1 package org.opendaylight.controller.sal.rest.impl;
3 import static com.google.common.base.Preconditions.checkNotNull;
5 import java.io.IOException;
8 import javax.activation.UnsupportedDataTypeException;
10 import org.opendaylight.controller.sal.restconf.impl.ControllerContext;
11 import org.opendaylight.yangtools.yang.common.QName;
12 import org.opendaylight.yangtools.yang.data.api.*;
13 import org.opendaylight.yangtools.yang.model.api.*;
14 import org.opendaylight.yangtools.yang.model.api.type.*;
16 import com.google.common.base.Preconditions;
17 import com.google.gson.stream.JsonWriter;
21 private final Set<LeafListSchemaNode> foundLeafLists = new HashSet<>();
22 private final Set<ListSchemaNode> foundLists = new HashSet<>();
24 public void write(JsonWriter writer, CompositeNode data, DataNodeContainer schema) throws IOException {
25 Preconditions.checkNotNull(writer);
26 Preconditions.checkNotNull(data);
27 Preconditions.checkNotNull(schema);
31 if (schema instanceof ContainerSchemaNode) {
32 writeContainer(writer, data, (ContainerSchemaNode) schema);
33 } else if (schema instanceof ListSchemaNode) {
34 writeList(writer, null, data, (ListSchemaNode) schema);
36 throw new UnsupportedDataTypeException(
37 "Schema can be ContainerSchemaNode or ListSchemaNode. Other types are not supported yet.");
42 foundLeafLists.clear();
46 private void writeChildrenOfParent(JsonWriter writer, CompositeNode parent, DataNodeContainer parentSchema)
49 checkNotNull(parentSchema);
51 for (Node<?> child : parent.getChildren()) {
52 DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
54 if (childSchema == null) {
55 throw new UnsupportedDataTypeException("Probably the data node \"" + child.getNodeType().getLocalName()
56 + "\" is not conform to schema");
59 if (childSchema instanceof ContainerSchemaNode) {
60 Preconditions.checkState(child instanceof CompositeNode,
61 "Data representation of Container should be CompositeNode - " + child.getNodeType());
62 writeContainer(writer, (CompositeNode) child, (ContainerSchemaNode) childSchema);
63 } else if (childSchema instanceof ListSchemaNode) {
64 if (!foundLists.contains(childSchema)) {
65 Preconditions.checkState(child instanceof CompositeNode,
66 "Data representation of List should be CompositeNode - " + child.getNodeType());
67 foundLists.add((ListSchemaNode) childSchema);
68 writeList(writer, parent, (CompositeNode) child, (ListSchemaNode) childSchema);
70 } else if (childSchema instanceof LeafListSchemaNode) {
71 if (!foundLeafLists.contains(childSchema)) {
72 Preconditions.checkState(child instanceof SimpleNode<?>,
73 "Data representation of LeafList should be SimpleNode - " + child.getNodeType());
74 foundLeafLists.add((LeafListSchemaNode) childSchema);
75 writeLeafList(writer, parent, (SimpleNode<?>) child, (LeafListSchemaNode) childSchema);
77 } else if (childSchema instanceof LeafSchemaNode) {
78 Preconditions.checkState(child instanceof SimpleNode<?>,
79 "Data representation of LeafList should be SimpleNode - " + child.getNodeType());
80 writeLeaf(writer, (SimpleNode<?>) child, (LeafSchemaNode) childSchema);
82 throw new UnsupportedDataTypeException("Schema can be ContainerSchemaNode, ListSchemaNode, "
83 + "LeafListSchemaNode, or LeafSchemaNode. Other types are not supported yet.");
87 for (Node<?> child : parent.getChildren()) {
88 DataSchemaNode childSchema = findFirstSchemaForNode(child, parentSchema.getChildNodes());
89 if (childSchema instanceof LeafListSchemaNode) {
90 foundLeafLists.remove((LeafListSchemaNode) childSchema);
91 } else if (childSchema instanceof ListSchemaNode) {
92 foundLists.remove((ListSchemaNode) childSchema);
97 private DataSchemaNode findFirstSchemaForNode(Node<?> node, Set<DataSchemaNode> dataSchemaNode) {
98 for (DataSchemaNode dsn : dataSchemaNode) {
99 if (node.getNodeType().getLocalName().equals(dsn.getQName().getLocalName())) {
101 } else if (dsn instanceof ChoiceNode) {
102 for (ChoiceCaseNode choiceCase : ((ChoiceNode) dsn).getCases()) {
103 DataSchemaNode foundDsn = findFirstSchemaForNode(node, choiceCase.getChildNodes());
104 if (foundDsn != null) {
113 private void writeContainer(JsonWriter writer, CompositeNode node, ContainerSchemaNode schema) throws IOException {
114 writeName(node, schema, writer);
115 writer.beginObject();
116 writeChildrenOfParent(writer, node, schema);
120 private void writeList(JsonWriter writer, CompositeNode nodeParent, CompositeNode node, ListSchemaNode schema)
122 writeName(node, schema, writer);
125 if (nodeParent != null) {
126 List<CompositeNode> nodeLists = nodeParent.getCompositesByName(node.getNodeType());
127 for (CompositeNode nodeList : nodeLists) {
128 writer.beginObject();
129 writeChildrenOfParent(writer, nodeList, schema);
133 writer.beginObject();
134 writeChildrenOfParent(writer, node, schema);
141 private void writeLeafList(JsonWriter writer, CompositeNode nodeParent, SimpleNode<?> node,
142 LeafListSchemaNode schema) throws IOException {
143 writeName(node, schema, writer);
146 List<SimpleNode<?>> nodeLeafLists = nodeParent.getSimpleNodesByName(node.getNodeType());
147 for (SimpleNode<?> nodeLeafList : nodeLeafLists) {
148 writeValueOfNodeByType(writer, nodeLeafList, schema.getType(), schema);
153 private void writeLeaf(JsonWriter writer, SimpleNode<?> node, LeafSchemaNode schema) throws IOException {
154 writeName(node, schema, writer);
155 writeValueOfNodeByType(writer, node, schema.getType(), schema);
158 private void writeValueOfNodeByType(JsonWriter writer, SimpleNode<?> node, TypeDefinition<?> type,
159 DataSchemaNode schema) throws IOException {
161 String value = String.valueOf(node.getValue());
162 TypeDefinition<?> baseType = resolveBaseTypeFrom(type);
164 // TODO check InstanceIdentifierTypeDefinition,
165 // IdentityrefTypeDefinition
166 if (baseType instanceof IdentityrefTypeDefinition) {
167 if (node.getValue() instanceof QName) {
168 QName qName = (QName) node.getValue();
170 ControllerContext contContext = ControllerContext.getInstance();
171 String moduleName = contContext.findModuleByNamespace(qName.getNamespace());
173 writer.value(moduleName + ":" + qName.getLocalName());
176 } else if (baseType instanceof LeafrefTypeDefinition) {
177 ControllerContext contContext = ControllerContext.getInstance();
178 LeafSchemaNode lfSchemaNode = contContext.resolveTypeFromLeafref((LeafrefTypeDefinition) baseType, schema);
179 if (lfSchemaNode != null) {
180 writeValueOfNodeByType(writer, node, lfSchemaNode.getType(), lfSchemaNode);
184 } else if (baseType instanceof InstanceIdentifierTypeDefinition) {
185 writer.value(((InstanceIdentifierTypeDefinition) baseType).getPathStatement().toString());
186 } else if (baseType instanceof UnionTypeDefinition) {
187 processTypeIsUnionType(writer, (UnionTypeDefinition) baseType, value);
188 } else if (baseType instanceof DecimalTypeDefinition || baseType instanceof IntegerTypeDefinition
189 || baseType instanceof UnsignedIntegerTypeDefinition) {
190 writer.value(new NumberForJsonWriter(value));
191 } else if (baseType instanceof BooleanTypeDefinition) {
192 writer.value(Boolean.parseBoolean(value));
193 } else if (baseType instanceof EmptyTypeDefinition) {
194 writeEmptyDataTypeToJson(writer);
196 writer.value(value.equals("null") ? "" : value);
200 private void processTypeIsUnionType(JsonWriter writer, UnionTypeDefinition unionType, String value)
203 writeEmptyDataTypeToJson(writer);
204 } else if ((isNumber(value))
205 && containsType(unionType, UnsignedIntegerTypeDefinition.class, IntegerTypeDefinition.class,
206 DecimalTypeDefinition.class)) {
207 writer.value(new NumberForJsonWriter(value));
208 } else if (isBoolean(value) && containsType(unionType, BooleanTypeDefinition.class)) {
209 writer.value(Boolean.parseBoolean(value));
215 private boolean isBoolean(String value) {
216 if (value.equals("true") || value.equals("false")) {
222 private void writeEmptyDataTypeToJson(JsonWriter writer) throws IOException {
228 private boolean isNumber(String value) {
230 Double.valueOf(value);
231 } catch (NumberFormatException e) {
237 private boolean containsType(UnionTypeDefinition unionType, Class<?>... searchedTypes) {
238 List<TypeDefinition<?>> allUnionSubtypes = resolveAllUnionSubtypesFrom(unionType);
240 for (TypeDefinition<?> unionSubtype : allUnionSubtypes) {
241 for (Class<?> searchedType : searchedTypes) {
242 if (searchedType.isInstance(unionSubtype)) {
250 private List<TypeDefinition<?>> resolveAllUnionSubtypesFrom(UnionTypeDefinition inputType) {
251 List<TypeDefinition<?>> result = new ArrayList<>();
252 for (TypeDefinition<?> subtype : inputType.getTypes()) {
253 TypeDefinition<?> resolvedSubtype = subtype;
255 resolvedSubtype = resolveBaseTypeFrom(subtype);
257 if (resolvedSubtype instanceof UnionTypeDefinition) {
258 List<TypeDefinition<?>> subtypesFromRecursion = resolveAllUnionSubtypesFrom((UnionTypeDefinition) resolvedSubtype);
259 result.addAll(subtypesFromRecursion);
261 result.add(resolvedSubtype);
268 private TypeDefinition<?> resolveBaseTypeFrom(TypeDefinition<?> type) {
269 return type.getBaseType() != null ? resolveBaseTypeFrom(type.getBaseType()) : type;
272 private void writeName(Node<?> node, DataSchemaNode schema, JsonWriter writer) throws IOException {
273 String nameForOutput = node.getNodeType().getLocalName();
274 if (schema.isAugmenting()) {
275 ControllerContext contContext = ControllerContext.getInstance();
276 CharSequence moduleName;
277 moduleName = contContext.toRestconfIdentifier(schema.getQName());
278 if (moduleName != null) {
279 nameForOutput = moduleName.toString();
282 writer.name(nameForOutput);
285 private static final class NumberForJsonWriter extends Number {
287 private static final long serialVersionUID = -3147729419814417666L;
288 private final String value;
290 public NumberForJsonWriter(String value) {
295 public int intValue() {
296 throw new IllegalStateException("Should not be invoked");
300 public long longValue() {
301 throw new IllegalStateException("Should not be invoked");
305 public float floatValue() {
306 throw new IllegalStateException("Should not be invoked");
310 public double doubleValue() {
311 throw new IllegalStateException("Should not be invoked");
315 public String toString() {