001/** 002 * Copyright 2014 The Kuali Foundation Licensed under the 003 * Educational Community License, Version 2.0 (the "License"); you may 004 * not use this file except in compliance with the License. You may 005 * obtain a copy of the License at 006 * 007 * http://www.osedu.org/licenses/ECL-2.0 008 * 009 * Unless required by applicable law or agreed to in writing, 010 * software distributed under the License is distributed on an "AS IS" 011 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express 012 * or implied. See the License for the specific language governing 013 * permissions and limitations under the License. 014 * 015 * Created by Charles on 8/5/2014 016 */ 017package org.kuali.student.poc.jsonparser.parser; 018 019import org.kuali.student.poc.jsonparser.json.BaseJsonObject; 020import org.kuali.student.poc.jsonparser.json.SimpleJsonBoolean; 021import org.kuali.student.poc.jsonparser.json.SimpleJsonList; 022import org.kuali.student.poc.jsonparser.json.SimpleJsonMap; 023import org.kuali.student.poc.jsonparser.json.SimpleJsonNull; 024import org.kuali.student.poc.jsonparser.json.SimpleJsonNumber; 025import org.kuali.student.poc.jsonparser.json.SimpleJsonString; 026import org.kuali.student.poc.jsonparser.tokenizer.SimpleJsonTokenizer; 027import org.kuali.student.poc.jsonparser.tokenizer.token.AtomToken; 028import org.kuali.student.poc.jsonparser.tokenizer.token.BaseToken; 029import org.kuali.student.poc.jsonparser.tokenizer.token.ConstantToken; 030import org.kuali.student.poc.jsonparser.tokenizer.token.NumberToken; 031import org.kuali.student.poc.jsonparser.tokenizer.token.StringToken; 032import org.kuali.student.poc.jsonparser.tokenizer.token.TokenConstants; 033 034import java.util.Iterator; 035import java.util.NoSuchElementException; 036 037/** 038 * Parses a simple JSON file 039 * 040 * @author Kuali Student Team 041 */ 042public class SimpleJsonParser implements Iterable<BaseJsonObject> { 043 SimpleJsonTokenizer tokenizer; 044 String resourcePath; 045 public SimpleJsonParser(String resourcePath) { 046 tokenizer = new SimpleJsonTokenizer(resourcePath); 047 this.resourcePath = resourcePath; 048 } 049 050// public List<BaseJsonObject> parse() throws MyJsonParseException { 051// List<BaseJsonObject> jsonObjects = new ArrayList<>(); 052// try { 053// Iterator<BaseToken> iterator = tokenizer.iterator(); 054// while (iterator.hasNext()) { 055// BaseJsonObject jsonObject = recursiveParse(iterator); 056// jsonObjects.add(jsonObject); 057// } 058// } catch (RuntimeException e) { 059// return null; 060// } 061// return jsonObjects; 062// } 063 064 private BaseJsonObject recursiveParse(Iterator<BaseToken> iterator) throws SimpleJsonParseException { 065 BaseToken token = iterator.next(); 066 if (token instanceof AtomToken) { 067 AtomToken aToken = (AtomToken) token; 068 if (aToken.getTokenType().equals(TokenConstants.START_MAP_TOKEN)) { 069 SimpleJsonMap map = new SimpleJsonMap(); 070 parseJsonMap(map, iterator); 071 return map; 072 } else if (aToken.getTokenType().equals(TokenConstants.START_LIST_TOKEN)) { 073 SimpleJsonList list = new SimpleJsonList(); 074 parseJsonList(list, iterator); 075 return list; 076 } 077 } else if (token instanceof StringToken) { 078 StringToken sToken = (StringToken) token; 079 return new SimpleJsonString(sToken.getString()); 080 } else if (token instanceof NumberToken) { 081 NumberToken nToken = (NumberToken) token; 082 return new SimpleJsonNumber(nToken.getValue()); 083 } else if (token instanceof ConstantToken) { 084 ConstantToken cToken = (ConstantToken) token; 085 if (cToken == ConstantToken.TRUE_TOKEN) { 086 return SimpleJsonBoolean.TRUE; 087 } else if (cToken == ConstantToken.FALSE_TOKEN) { 088 return SimpleJsonBoolean.FALSE; 089 } else { 090 // Assume it must be null 091 return SimpleJsonNull.NULL; 092 } 093 } 094 throw new SimpleJsonParseException("Unknown token found"); 095 } 096 097 private void parseJsonList(SimpleJsonList list, Iterator<BaseToken> iterator) throws SimpleJsonParseException { 098 BaseToken token = null; 099 while (!isEndListToken(token)) { 100 // Next token should be next element of list 101 BaseJsonObject element = recursiveParse(iterator); 102 list.add(element); 103 // Check for comma 104 token = iterator.next(); 105 if (!isEndListToken(token)) { 106 if (!isCommaToken(token)) { 107 throw new SimpleJsonParseException("Expecting a comma"); 108 } 109 } 110 } 111 } 112 113 private void parseJsonMap(SimpleJsonMap map, Iterator<BaseToken> iterator) throws SimpleJsonParseException { 114 // At this point, the start brace 115 BaseToken token = iterator.next(); 116 while (!isEndMapToken(token)) { 117 // Next token should be a key, which is a string token 118 StringToken sToken = (StringToken) token; // May class-cast 119 // Next token should be a colon 120 token = iterator.next(); 121 if (!isColonToken(token)) { 122 throw new SimpleJsonParseException("Expecting a colon"); 123 } 124 BaseJsonObject value = recursiveParse(iterator); 125 map.put(sToken.getString(), value); 126 // Check for comma 127 token = iterator.next(); 128 if (!isEndMapToken(token)) { 129 if (!isCommaToken(token)) { 130 throw new SimpleJsonParseException("Expecting a comma"); 131 } else { 132 // Get token after the comma 133 token = iterator.next(); 134 } 135 } 136 } 137 } 138 139 private boolean isEndMapToken(BaseToken token) { 140 if (token instanceof AtomToken) { 141 AtomToken aToken = (AtomToken) token; 142 return aToken.getTokenType().equals(TokenConstants.END_MAP_TOKEN); 143 } 144 return false; 145 } 146 147 private boolean isEndListToken(BaseToken token) { 148 if (token == null) { 149 return false; 150 } 151 if (token instanceof AtomToken) { 152 AtomToken aToken = (AtomToken) token; 153 return aToken.getTokenType().equals(TokenConstants.END_LIST_TOKEN); 154 } 155 return false; 156 } 157 158 private boolean isColonToken(BaseToken token) { 159 if (token instanceof AtomToken) { 160 AtomToken aToken = (AtomToken) token; 161 return aToken.getTokenType().equals(TokenConstants.COLON_TOKEN); 162 } 163 return false; 164 } 165 166 private boolean isCommaToken(BaseToken token) { 167 if (token instanceof AtomToken) { 168 AtomToken aToken = (AtomToken) token; 169 return aToken.getTokenType().equals(TokenConstants.COMMA_TOKEN); 170 } 171 return false; 172 } 173 174 @Override 175 public Iterator<BaseJsonObject> iterator() { 176 Iterator<BaseJsonObject> iter = 177 new Iterator<BaseJsonObject>() { 178 SimpleJsonTokenizer tokenizer; 179 Iterator<BaseToken> iterator; 180 BaseJsonObject nextJsonObject; 181 { 182 tokenizer = new SimpleJsonTokenizer(resourcePath); 183 iterator = tokenizer.iterator(); 184 nextJsonObject = getNextJsonObject(); 185 } 186 187 private BaseJsonObject getNextJsonObject() { 188 BaseJsonObject result = null; 189 try { 190 if (!iterator.hasNext()) { 191 return null; 192 } 193 result = recursiveParse(iterator); 194 } catch (SimpleJsonParseException e) { 195 throw new RuntimeException("MyJsonParseException", e); 196 } 197 return result; 198 } 199 200 @Override 201 public boolean hasNext() { 202 return nextJsonObject != null; 203 } 204 205 @Override 206 public BaseJsonObject next() { 207 BaseJsonObject saved = nextJsonObject; 208 if (saved == null) { 209 throw new NoSuchElementException(); 210 } else { 211 nextJsonObject = getNextJsonObject(); 212 } 213 214 return saved; 215 } 216 217 @Override 218 public void remove() { 219 throw new UnsupportedOperationException("remove not supported"); 220 } 221 }; 222 return iter; 223 } 224}