View Javadoc
1   /**
2    * Copyright 2014 The Kuali Foundation Licensed under the
3    * Educational Community License, Version 2.0 (the "License"); you may
4    * not use this file except in compliance with the License. You may
5    * obtain a copy of the License at
6    *
7    * http://www.osedu.org/licenses/ECL-2.0
8    *
9    * Unless required by applicable law or agreed to in writing,
10   * software distributed under the License is distributed on an "AS IS"
11   * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12   * or implied. See the License for the specific language governing
13   * permissions and limitations under the License.
14   *
15   * Created by Charles on 8/5/2014
16   */
17  package org.kuali.student.poc.jsonparser.parser;
18  
19  import org.kuali.student.poc.jsonparser.json.BaseJsonObject;
20  import org.kuali.student.poc.jsonparser.json.SimpleJsonBoolean;
21  import org.kuali.student.poc.jsonparser.json.SimpleJsonList;
22  import org.kuali.student.poc.jsonparser.json.SimpleJsonMap;
23  import org.kuali.student.poc.jsonparser.json.SimpleJsonNull;
24  import org.kuali.student.poc.jsonparser.json.SimpleJsonNumber;
25  import org.kuali.student.poc.jsonparser.json.SimpleJsonString;
26  import org.kuali.student.poc.jsonparser.tokenizer.SimpleJsonTokenizer;
27  import org.kuali.student.poc.jsonparser.tokenizer.token.AtomToken;
28  import org.kuali.student.poc.jsonparser.tokenizer.token.BaseToken;
29  import org.kuali.student.poc.jsonparser.tokenizer.token.ConstantToken;
30  import org.kuali.student.poc.jsonparser.tokenizer.token.NumberToken;
31  import org.kuali.student.poc.jsonparser.tokenizer.token.StringToken;
32  import org.kuali.student.poc.jsonparser.tokenizer.token.TokenConstants;
33  
34  import java.util.Iterator;
35  import java.util.NoSuchElementException;
36  
37  /**
38   * Parses a simple JSON file
39   *
40   * @author Kuali Student Team
41   */
42  public class SimpleJsonParser implements Iterable<BaseJsonObject> {
43      SimpleJsonTokenizer tokenizer;
44      String resourcePath;
45      public SimpleJsonParser(String resourcePath) {
46          tokenizer = new SimpleJsonTokenizer(resourcePath);
47          this.resourcePath = resourcePath;
48      }
49  
50  //    public List<BaseJsonObject> parse() throws MyJsonParseException {
51  //        List<BaseJsonObject> jsonObjects = new ArrayList<>();
52  //        try {
53  //            Iterator<BaseToken> iterator = tokenizer.iterator();
54  //            while (iterator.hasNext()) {
55  //                BaseJsonObject jsonObject = recursiveParse(iterator);
56  //                jsonObjects.add(jsonObject);
57  //            }
58  //        } catch (RuntimeException e) {
59  //            return null;
60  //        }
61  //        return jsonObjects;
62  //    }
63  
64      private BaseJsonObject recursiveParse(Iterator<BaseToken> iterator) throws SimpleJsonParseException {
65          BaseToken token = iterator.next();
66          if (token instanceof AtomToken) {
67              AtomToken aToken = (AtomToken) token;
68              if (aToken.getTokenType().equals(TokenConstants.START_MAP_TOKEN)) {
69                  SimpleJsonMap map = new SimpleJsonMap();
70                  parseJsonMap(map, iterator);
71                  return map;
72              } else if (aToken.getTokenType().equals(TokenConstants.START_LIST_TOKEN)) {
73                  SimpleJsonList list = new SimpleJsonList();
74                  parseJsonList(list, iterator);
75                  return list;
76              }
77          } else if (token instanceof StringToken) {
78              StringToken sToken = (StringToken) token;
79              return new SimpleJsonString(sToken.getString());
80          } else if (token instanceof NumberToken) {
81              NumberToken nToken = (NumberToken) token;
82              return new SimpleJsonNumber(nToken.getValue());
83          } else if (token instanceof ConstantToken) {
84              ConstantToken cToken = (ConstantToken) token;
85              if (cToken == ConstantToken.TRUE_TOKEN) {
86                  return SimpleJsonBoolean.TRUE;
87              } else if (cToken == ConstantToken.FALSE_TOKEN) {
88                  return SimpleJsonBoolean.FALSE;
89              } else {
90                  // Assume it must be null
91                  return SimpleJsonNull.NULL;
92              }
93          }
94          throw new SimpleJsonParseException("Unknown token found");
95      }
96  
97      private void parseJsonList(SimpleJsonList list, Iterator<BaseToken> iterator) throws SimpleJsonParseException {
98          BaseToken token = null;
99          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 }