001/*
002 * (C) Copyright 2012-2013 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 */
017package org.nuxeo.connect.tools.report.client;
018
019import java.util.Stack;
020
021import javax.json.Json;
022import javax.json.JsonArrayBuilder;
023import javax.json.JsonException;
024import javax.json.JsonObjectBuilder;
025import javax.json.stream.JsonParser;
026import javax.json.stream.JsonParser.Event;
027
028/**
029 *
030 *
031 */
032public class ObjectFeeder {
033    interface Handler {
034        void handle(JsonArrayBuilder builder);
035
036        void handle(JsonObjectBuilder builder);
037
038        void handle(Event current, JsonParser parser);
039    }
040
041    class ArrayHandler implements Handler {
042        final JsonArrayBuilder builder;
043
044        ArrayHandler(JsonArrayBuilder aBuilder) {
045            builder = aBuilder;
046        }
047
048        @Override
049        public void handle(Event event, JsonParser parser) {
050            switch (event) {
051            case START_ARRAY:
052                stack.push(new ArrayHandler(Json.createArrayBuilder()));
053                break;
054            case START_OBJECT:
055                stack.push(new ObjectHandler(Json.createObjectBuilder()));
056                break;
057            case END_ARRAY:
058                stack.pop();
059                stack.peek().handle(builder);
060                break;
061            case END_OBJECT:
062                stack.pop();
063                stack.peek().handle(builder);
064                break;
065            case VALUE_FALSE:
066                builder.add(false);
067                break;
068            case VALUE_TRUE:
069                builder.add(true);
070                break;
071            case VALUE_STRING:
072                builder.add(parser.getString());
073                break;
074            case VALUE_NULL:
075                builder.addNull();
076                break;
077            case VALUE_NUMBER:
078                if (parser.isIntegralNumber()) {
079                    builder.add(parser.getLong());
080                } else {
081                    builder.add(parser.getBigDecimal());
082                }
083                break;
084            default:
085                throw new IllegalStateException("Cannot handle " + event + " while parsing object");
086            }
087        }
088
089        @Override
090        public void handle(JsonArrayBuilder builder) {
091            this.builder.add(builder);
092        }
093
094        @Override
095        public void handle(JsonObjectBuilder builder) {
096            this.builder.add(builder);
097        }
098    }
099
100    class ObjectHandler implements Handler {
101        final JsonObjectBuilder builder;
102
103        ObjectHandler(JsonObjectBuilder aBuilder) {
104            builder = aBuilder;
105        }
106
107        String name;
108
109        @Override
110        public void handle(Event anEvent, JsonParser aParser) {
111            switch (anEvent) {
112            case END_OBJECT:
113                stack.pop();
114                if (!stack.isEmpty()) {
115                    stack.peek().handle(builder);
116                }
117                break;
118            case KEY_NAME:
119                name = aParser.getString();
120                switch (aParser.next()) {
121                case START_ARRAY:
122                    stack.push(new ArrayHandler(Json.createArrayBuilder()));
123                    break;
124                case START_OBJECT:
125                    stack.push(new ObjectHandler(Json.createObjectBuilder()));
126                    break;
127                case VALUE_FALSE:
128                    builder.add(name, false);
129                    break;
130                case VALUE_TRUE:
131                    builder.add(name, true);
132                    break;
133                case VALUE_NULL:
134                    builder.addNull(name);
135                    break;
136                case VALUE_STRING:
137                    builder.add(name, aParser.getString());
138                    break;
139                case VALUE_NUMBER:
140                    if (aParser.isIntegralNumber()) {
141                        builder.add(name, aParser.getLong());
142                    } else {
143                        builder.add(name, aParser.getBigDecimal());
144                    }
145                    break;
146                default:
147                    throw new IllegalStateException("Cannot handle " + anEvent + " while parsing object");
148                }
149                break;
150            default:
151                throw new IllegalStateException("Cannot handle " + anEvent + " while parsing object");
152            }
153        }
154
155        @Override
156        public void handle(JsonArrayBuilder builder) {
157            this.builder.add(name, builder);
158        }
159
160        @Override
161        public void handle(JsonObjectBuilder builder) {
162            this.builder.add(name, builder);
163        }
164
165    }
166
167    final Stack<Handler> stack = new Stack<>();
168
169    public JsonArrayBuilder buildArray(JsonArrayBuilder builder, JsonParser parser) {
170        if (!parser.hasNext()) {
171            throw new JsonException("not an array");
172        }
173        if (parser.next() != Event.START_ARRAY) {
174            throw new IllegalStateException("Not an array");
175        }
176        stack.push(new ArrayHandler(builder));
177        try {
178            dofeed(parser);
179        } finally {
180            stack.clear();
181        }
182        return builder;
183    }
184
185    public JsonObjectBuilder feed(JsonObjectBuilder builder, JsonParser parser) {
186        if (!parser.hasNext()) {
187            throw new JsonException("not an array");
188        }
189        if (parser.next() != Event.START_OBJECT) {
190            throw new IllegalStateException("Not an array");
191        }
192        stack.push(new ObjectHandler(builder));
193        try {
194            dofeed(parser);
195        } finally {
196            stack.clear();
197        }
198        return builder;
199    }
200
201    void dofeed(JsonParser parser) {
202        while (parser.hasNext()) {
203            stack.peek().handle(parser.next(), parser);
204        }
205    }
206}