Updated Json Stream Writer to use gson JsonWriter.
[yangtools.git] / yang / yang-data-codec-gson / src / main / java / org / opendaylight / yangtools / yang / data / codec / gson / JSONNormalizedNodeStreamWriter.java
1 /*
2  * Copyright (c) 2014 Cisco Systems, Inc. and others.  All rights reserved.
3  *
4  * This program and the accompanying materials are made available under the
5  * terms of the Eclipse Public License v1.0 which accompanies this distribution,
6  * and is available at http://www.eclipse.org/legal/epl-v10.html
7  */
8 package org.opendaylight.yangtools.yang.data.codec.gson;
9
10 import com.google.common.base.Preconditions;
11 import com.google.gson.stream.JsonWriter;
12 import java.io.IOException;
13 import java.io.Writer;
14 import java.net.URI;
15 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
16 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifier;
17 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.NodeIdentifierWithPredicates;
18 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
19 import org.opendaylight.yangtools.yang.data.impl.codec.SchemaTracker;
20 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
21 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
23 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
24 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.SchemaPath;
26
27 /**
28  * This implementation will create JSON output as output stream.
29  *
30  * Values of leaf and leaf-list are NOT translated according to codecs.
31  *
32  */
33 public class JSONNormalizedNodeStreamWriter implements NormalizedNodeStreamWriter {
34     /**
35      * RFC6020 deviation: we are not required to emit empty containers unless they
36      * are marked as 'presence'.
37      */
38     private static final boolean DEFAULT_EMIT_EMPTY_CONTAINERS = true;
39
40     private final SchemaTracker tracker;
41     private final JSONCodecFactory codecs;
42     private final JsonWriter writer;
43     private JSONStreamWriterContext context;
44
45     private JSONNormalizedNodeStreamWriter(final JSONCodecFactory codecFactory, final SchemaPath path, final URI initialNs, JsonWriter JsonWriter) {
46         this.writer = JsonWriter;
47         this.codecs = Preconditions.checkNotNull(codecFactory);
48         this.tracker = SchemaTracker.create(codecFactory.getSchemaContext(), path);
49         this.context = new JSONStreamWriterRootContext(initialNs);
50     }
51
52     /**
53      * Create a new stream writer, which writes to the specified {@link Writer}.
54      *
55      * @param schemaContext Schema context
56      * @param writer Output writer
57      * @return A stream writer instance
58      */
59     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer) {
60         return create(schemaContext, SchemaPath.ROOT, null, writer);
61     }
62
63     /**
64      * Create a new stream writer, which writes to the specified {@link Writer}.
65      *
66      * @param schemaContext Schema context
67      * @param path Root schemapath
68      * @param writer Output writer
69      * @return A stream writer instance
70      */
71     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path, final Writer writer) {
72         return create(schemaContext, path, null, writer);
73     }
74
75     /**
76      * Create a new stream writer, which writes to the specified {@link Writer}.
77      *
78      * @param schemaContext Schema context
79      * @param path Root schemapath
80      * @param writer Output writer
81      * @param initialNs Initial namespace
82      * @return A stream writer instance
83      */
84     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final SchemaPath path,
85             final URI initialNs, final Writer writer) {
86         return create(JSONCodecFactory.create(schemaContext), path, initialNs, JsonWriterFactory.createJsonWriter(writer));
87     }
88
89     /**
90      * Create a new stream writer, which writes to the specified output stream.
91      *
92      * @param schemaContext Schema context
93      * @param writer Output writer
94      * @param indentSize indentation size
95      * @return A stream writer instance
96      */
97     public static NormalizedNodeStreamWriter create(final SchemaContext schemaContext, final Writer writer, final int indentSize) {
98         return create(JSONCodecFactory.create(schemaContext), SchemaPath.ROOT, null,JsonWriterFactory.createJsonWriter(writer, indentSize));
99     }
100
101     /**
102      * Create a new stream writer, which writes to the specified output stream. The codec factory
103      * can be reused between multiple writers.
104      *
105      * @param codecFactory JSON codec factory
106      * @param writer Output writer
107      * @param indentSize indentation size
108      * @return A stream writer instance
109      */
110     public static NormalizedNodeStreamWriter create(final JSONCodecFactory codecFactory, final Writer writer, final int indentSize) {
111         return create(codecFactory, SchemaPath.ROOT, null, JsonWriterFactory.createJsonWriter(writer,indentSize));
112     }
113
114     /**
115      * Create a new stream writer, which writes to the specified output stream.
116      *
117      * @param schemaContext Schema context
118      * @param path Schema Path
119      * @param initialNs Initial namespace
120      * @param jsonWriter JsonWriter
121      * @return A stream writer instance
122      */
123     public static NormalizedNodeStreamWriter create(SchemaContext schemaContext, SchemaPath path, URI initialNs,
124             JsonWriter jsonWriter) {
125         return create(JSONCodecFactory.create(schemaContext), path, initialNs, jsonWriter);
126     }
127
128     /**
129      * Create a new stream writer, which writes to the specified output stream. The codec factory
130      * can be reused between multiple writers.
131      *
132      * @param codecFactory JSON codec factory
133      * @param path Schema Path
134      * @param initialNs Initial namespace
135      * @param jsonWriter JsonWriter
136      * @return A stream writer instance
137      */
138     public static NormalizedNodeStreamWriter create(JSONCodecFactory codecFactory, SchemaPath path, URI initialNs, JsonWriter jsonWriter) {
139         return new JSONNormalizedNodeStreamWriter(codecFactory, path, initialNs, jsonWriter);
140     }
141
142     @Override
143     public void leafNode(final NodeIdentifier name, final Object value) throws IOException {
144         final LeafSchemaNode schema = tracker.leafNode(name);
145         final JSONCodec<Object> codec = codecs.codecFor(schema.getType());
146
147         context.emittingChild(codecs.getSchemaContext(), writer);
148         context.writeChildJsonIdentifier(codecs.getSchemaContext(), writer, name.getNodeType());
149
150         writeValue(value, codec);
151     }
152
153     @Override
154     public void startLeafSet(final NodeIdentifier name, final int childSizeHint) throws IOException {
155         tracker.startLeafSet(name);
156         context = new JSONStreamWriterListContext(context, name);
157     }
158
159     @Override
160     public void leafSetEntryNode(final Object value) throws IOException {
161         final LeafListSchemaNode schema = tracker.leafSetEntryNode();
162         final JSONCodec<Object> codec = codecs.codecFor(schema.getType());
163
164         context.emittingChild(codecs.getSchemaContext(), writer);
165
166         writeValue(value, codec);
167     }
168
169     /*
170      * Warning suppressed due to static final constant which triggers a warning
171      * for the call to schema.isPresenceContainer().
172      */
173     @SuppressWarnings("unused")
174     @Override
175     public void startContainerNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
176         final SchemaNode schema = tracker.startContainerNode(name);
177
178         // FIXME this code ignores presence for containers
179         // but datastore does as well and it needs be fixed first (2399)
180         context = new JSONStreamWriterNamedObjectContext(context, name, DEFAULT_EMIT_EMPTY_CONTAINERS);
181     }
182
183     @Override
184     public void startUnkeyedList(final NodeIdentifier name, final int childSizeHint) throws IOException {
185         tracker.startList(name);
186         context = new JSONStreamWriterListContext(context, name);
187     }
188
189     @Override
190     public void startUnkeyedListItem(final NodeIdentifier name, final int childSizeHint) throws IOException {
191         tracker.startListItem(name);
192         context = new JSONStreamWriterObjectContext(context, name, DEFAULT_EMIT_EMPTY_CONTAINERS);
193     }
194
195     @Override
196     public void startMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
197         tracker.startList(name);
198         context = new JSONStreamWriterListContext(context, name);
199     }
200
201     @Override
202     public void startMapEntryNode(final NodeIdentifierWithPredicates identifier, final int childSizeHint)
203             throws IOException {
204         tracker.startListItem(identifier);
205         context = new JSONStreamWriterObjectContext(context, identifier, DEFAULT_EMIT_EMPTY_CONTAINERS);
206     }
207
208     @Override
209     public void startOrderedMapNode(final NodeIdentifier name, final int childSizeHint) throws IOException {
210         tracker.startList(name);
211         context = new JSONStreamWriterListContext(context, name);
212     }
213
214     @Override
215     public void startChoiceNode(final NodeIdentifier name, final int childSizeHint) {
216         tracker.startChoiceNode(name);
217         context = new JSONStreamWriterInvisibleContext(context);
218     }
219
220     @Override
221     public void startAugmentationNode(final AugmentationIdentifier identifier) {
222         tracker.startAugmentationNode(identifier);
223         context = new JSONStreamWriterInvisibleContext(context);
224     }
225
226     @Override
227     public void anyxmlNode(final NodeIdentifier name, final Object value) throws IOException {
228         @SuppressWarnings("unused")
229         final AnyXmlSchemaNode schema = tracker.anyxmlNode(name);
230         // FIXME: should have a codec based on this :)
231
232         context.emittingChild(codecs.getSchemaContext(), writer);
233         context.writeChildJsonIdentifier(codecs.getSchemaContext(), writer, name.getNodeType());
234         writer.value(String.valueOf(value));
235     }
236
237     @Override
238     public void endNode() throws IOException {
239         tracker.endNode();
240         context = context.endNode(codecs.getSchemaContext(), writer);
241         if(context instanceof JSONStreamWriterRootContext) {
242             context.emitEnd(writer);
243         }
244     }
245
246     private void writeValue(Object value, JSONCodec<Object> codec)
247             throws IOException {
248         codec.serializeToWriter(writer,value);
249     }
250
251     @Override
252     public void flush() throws IOException {
253         writer.flush();
254     }
255
256     @Override
257     public void close() throws IOException {
258         writer.flush();
259         writer.close();
260     }
261
262
263
264 }