| package org.codehaus.jackson.util; |
| |
| import java.io.IOException; |
| import java.util.*; |
| |
| import org.codehaus.jackson.*; |
| |
| /** |
| * Helper class that can be used to sequence multiple physical |
| * {@link JsonParser}s to create a single logical sequence of |
| * tokens, as a single {@link JsonParser}. |
| *<p> |
| * Fairly simple use of {@link JsonParserDelegate}: only need |
| * to override {@link #nextToken} to handle transition |
| * |
| * @author tatu |
| * @since 1.5 |
| */ |
| public class JsonParserSequence extends JsonParserDelegate |
| { |
| /** |
| * Parsers other than the first one (which is initially assigned |
| * as delegate) |
| */ |
| protected final JsonParser[] _parsers; |
| |
| /** |
| * Index of the next parser in {@link #_parsers}. |
| */ |
| protected int _nextParser; |
| |
| /* |
| ******************************************************* |
| * Construction |
| ******************************************************* |
| */ |
| |
| protected JsonParserSequence(JsonParser[] parsers) |
| { |
| super(parsers[0]); |
| _parsers = parsers; |
| _nextParser = 1; |
| } |
| |
| /** |
| * Method that will construct a parser (possibly a sequence) that |
| * contains all given sub-parsers. |
| * All parsers given are checked to see if they are sequences: and |
| * if so, they will be "flattened", that is, contained parsers are |
| * directly added in a new sequence instead of adding sequences |
| * within sequences. This is done to minimize delegation depth, |
| * ideally only having just a single level of delegation. |
| */ |
| public static JsonParserSequence createFlattened(JsonParser first, JsonParser second) |
| { |
| if (!(first instanceof JsonParserSequence || second instanceof JsonParserSequence)) { |
| // simple: |
| return new JsonParserSequence(new JsonParser[] { first, second }); |
| } |
| ArrayList<JsonParser> p = new ArrayList<JsonParser>(); |
| if (first instanceof JsonParserSequence) { |
| ((JsonParserSequence) first).addFlattenedActiveParsers(p); |
| } else { |
| p.add(first); |
| } |
| if (second instanceof JsonParserSequence) { |
| ((JsonParserSequence) second).addFlattenedActiveParsers(p); |
| } else { |
| p.add(second); |
| } |
| return new JsonParserSequence(p.toArray(new JsonParser[p.size()])); |
| } |
| |
| protected void addFlattenedActiveParsers(List<JsonParser> result) |
| { |
| for (int i = _nextParser-1, len = _parsers.length; i < len; ++i) { |
| JsonParser p = _parsers[i]; |
| if (p instanceof JsonParserSequence) { |
| ((JsonParserSequence) p).addFlattenedActiveParsers(result); |
| } else { |
| result.add(p); |
| } |
| } |
| } |
| |
| /* |
| ******************************************************* |
| * Overridden methods, needed: cases where default |
| * delegation does not work |
| ******************************************************* |
| */ |
| |
| @Override |
| public void close() throws IOException |
| { |
| do { |
| delegate.close(); |
| } while (switchToNext()); |
| } |
| |
| @Override |
| public JsonToken nextToken() throws IOException, JsonParseException |
| { |
| JsonToken t = delegate.nextToken(); |
| if (t != null) return t; |
| while (switchToNext()) { |
| t = delegate.nextToken(); |
| if (t != null) return t; |
| } |
| return null; |
| } |
| |
| /* |
| /******************************************************* |
| /* Additional extended API |
| /******************************************************* |
| */ |
| |
| /** |
| * Method that is most useful for debugging or testing; |
| * returns actual number of underlying parsers sequence |
| * was constructed with (nor just ones remaining active) |
| */ |
| public int containedParsersCount() { |
| return _parsers.length; |
| } |
| |
| /* |
| /******************************************************* |
| /* Helper methods |
| /******************************************************* |
| */ |
| |
| /** |
| * Method that will switch active parser from the current one |
| * to next parser in sequence, if there is another parser left, |
| * making this the new delegate. Old delegate is returned if |
| * switch succeeds. |
| * |
| * @return True if switch succeeded; false otherwise |
| */ |
| protected boolean switchToNext() |
| { |
| if (_nextParser >= _parsers.length) { |
| return false; |
| } |
| delegate = _parsers[_nextParser++]; |
| return true; |
| } |
| } |