Cleanup use of Guava library
[yangtools.git] / yang / yang-data-codec-gson / src / main / java / org / opendaylight / yangtools / yang / data / codec / gson / JSONStreamWriterContext.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 static com.google.common.base.Preconditions.checkArgument;
11
12 import com.google.gson.stream.JsonWriter;
13 import java.io.IOException;
14 import java.net.URI;
15 import javax.annotation.Nonnull;
16 import org.opendaylight.yangtools.yang.common.QName;
17 import org.opendaylight.yangtools.yang.model.api.Module;
18 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
19
20 /**
21  * Abstract base class for a single level of {@link JSONNormalizedNodeStreamWriter} recursion. Provides the base API
22  * towards the writer, which is then specialized by subclasses.
23  */
24 abstract class JSONStreamWriterContext {
25     private final JSONStreamWriterContext parent;
26     private final boolean mandatory;
27     private final int depth;
28     private boolean emittedMyself = false;
29
30     /**
31      * Construct a new context.
32      *
33      * @param parent Parent context, usually non-null.
34      * @param mandatory Mandatory flag. If set to true, the corresponding node
35      *                  will be emitted even if it has no children.
36      */
37     protected JSONStreamWriterContext(final JSONStreamWriterContext parent, final boolean mandatory) {
38         this.mandatory = mandatory;
39         this.parent = parent;
40
41         if (parent != null) {
42             depth = parent.depth + 1;
43         } else {
44             depth = 0;
45         }
46     }
47
48     /**
49      * Write a child JSON node identifier, optionally prefixing it with the module name corresponding to its namespace.
50      *
51      * @param schema Schema context
52      * @param writer Output writer
53      * @param qname Namespace/name tuple
54      * @throws IOException when the writer reports it
55      */
56     final void writeChildJsonIdentifier(final SchemaContext schema, final JsonWriter writer, final QName qname)
57             throws IOException {
58
59         final StringBuilder sb = new StringBuilder();
60         // Prepend module name if namespaces do not match
61         final URI ns = qname.getNamespace();
62         if (!ns.equals(getNamespace())) {
63             final Module module = schema.findModuleByNamespaceAndRevision(ns, null);
64             checkArgument(module != null, "Could not find module for namespace {}", ns);
65
66             sb.append(module.getName());
67             sb.append(':');
68         }
69         sb.append(qname.getLocalName());
70
71         writer.name(sb.toString());
72     }
73
74     /**
75      * Write our JSON node identifier, optionally prefixing it with the module name corresponding to its namespace.
76      *
77      * @param schema Schema context
78      * @param writer Output writer
79      * @param qname Namespace/name tuple
80      * @throws IOException when the writer reports it
81      */
82     protected final void writeMyJsonIdentifier(final SchemaContext schema, final JsonWriter writer, final QName qname)
83             throws IOException {
84         parent.writeChildJsonIdentifier(schema, writer, qname);
85     }
86
87     /**
88      * Return the namespace associated with current node.
89      *
90      * @return Namespace as URI
91      */
92     protected abstract @Nonnull URI getNamespace();
93
94     /**
95      * Emit the start of an element.
96      *
97      * @param schema Schema context
98      * @param writer Output writer
99      * @throws IOException when the writer reports it
100      */
101     protected abstract void emitStart(SchemaContext schema, JsonWriter writer) throws IOException;
102
103     /**
104      * Emit the end of an element.
105      *
106      * @param schema Schema context
107      * @param writer Output writer
108      * @throws IOException when writer reports it
109      */
110     protected abstract void emitEnd(JsonWriter writer) throws IOException;
111
112     private void emitMyself(final SchemaContext schema, final JsonWriter writer) throws IOException {
113         if (!emittedMyself) {
114             if (parent != null) {
115                 parent.emittingChild(schema, writer);
116             }
117
118             emitStart(schema, writer);
119             emittedMyself = true;
120         }
121     }
122
123     /**
124      * Invoked whenever a child node is being emitted. Checks whether this node has
125      * been emitted, and takes care of that if necessary. Also makes sure separator
126      * is emitted before a second and subsequent child.
127      *
128      * @param schema Schema context
129      * @param writer Output writer
130      * @throws IOException when writer reports it
131      */
132     final void emittingChild(final SchemaContext schema, final JsonWriter writer) throws IOException {
133         emitMyself(schema, writer);
134     }
135
136     /**
137      * Invoked by the writer when it is leaving this node. Checks whether this node
138      * needs to be emitted and takes of that if necessary.
139      *
140      * @param schema Schema context
141      * @param writer Output writer
142      * @return Parent node context
143      * @throws IOException when writer reports it
144      * @throws IllegalArgumentException if this node cannot be ended (e.g. root)
145      */
146     final JSONStreamWriterContext endNode(final SchemaContext schema, final JsonWriter writer) throws IOException {
147         if (!emittedMyself && mandatory) {
148             emitMyself(schema, writer);
149         }
150
151         if (emittedMyself) {
152             emitEnd(writer);
153         }
154         return parent;
155     }
156 }