2 * Copyright (c) 2014 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.yangtools.yang.data.codec.gson;
10 import com.google.common.base.Preconditions;
11 import com.google.common.collect.ArrayListMultimap;
12 import com.google.common.collect.Multimap;
13 import java.io.IOException;
14 import java.util.ArrayList;
15 import java.util.Collection;
16 import java.util.Deque;
17 import java.util.List;
18 import java.util.Map.Entry;
19 import org.opendaylight.yangtools.yang.data.api.schema.stream.SchemaAwareNormalizedNodeStreamWriter;
20 import org.opendaylight.yangtools.yang.data.impl.schema.SchemaUtils;
21 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
22 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
23 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
24 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
32 * A node which is composed of multiple simpler nodes.
34 class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
37 * nodes which were added to schema via augmentation and are present in data input
39 private final Multimap<AugmentationSchema, AbstractNodeDataWithSchema> augmentationsToChild = ArrayListMultimap.create();
42 * remaining data nodes (which aren't added via augment). Every of one them should have the same QName.
44 private final List<AbstractNodeDataWithSchema> children = new ArrayList<>();
46 public CompositeNodeDataWithSchema(final DataSchemaNode schema) {
50 public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
51 Preconditions.checkArgument(!schemas.isEmpty(), "Expecting at least one schema");
53 // Pop the first node...
54 final DataSchemaNode schema = schemas.pop();
55 if (schemas.isEmpty()) {
56 // Simple, direct node
57 return addChild(schema);
60 // The choice/case mess, reuse what we already popped
61 final DataSchemaNode choiceCandidate = schema;
62 Preconditions.checkArgument(choiceCandidate instanceof ChoiceSchemaNode,
63 "Expected node of type ChoiceNode but was %s", choiceCandidate.getClass().getSimpleName());
64 final ChoiceSchemaNode choiceNode = (ChoiceSchemaNode) choiceCandidate;
66 final DataSchemaNode caseCandidate = schemas.pop();
67 Preconditions.checkArgument(caseCandidate instanceof ChoiceCaseNode,
68 "Expected node of type ChoiceCaseNode but was %s", caseCandidate.getClass().getSimpleName());
69 final ChoiceCaseNode caseNode = (ChoiceCaseNode) caseCandidate;
71 AugmentationSchema augSchema = null;
72 if (choiceCandidate.isAugmenting()) {
73 augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), choiceCandidate);
76 // looking for existing choice
77 final Collection<AbstractNodeDataWithSchema> childNodes;
78 if (augSchema != null) {
79 childNodes = augmentationsToChild.get(augSchema);
81 childNodes = children;
84 CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
85 if (caseNodeDataWithSchema == null) {
86 ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
87 childNodes.add(choiceNodeDataWithSchema);
88 caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
91 return caseNodeDataWithSchema.addChild(schemas);
94 private AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
95 SimpleNodeDataWithSchema newChild = null;
96 if (schema instanceof LeafSchemaNode) {
97 newChild = new LeafNodeDataWithSchema(schema);
98 } else if (schema instanceof AnyXmlSchemaNode) {
99 newChild = new AnyXmlNodeDataWithSchema(schema);
104 AugmentationSchema augSchema = null;
105 if (schema.isAugmenting()) {
106 augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), schema);
108 if (augSchema != null) {
109 augmentationsToChild.put(augSchema, newChild);
116 private static CaseNodeDataWithSchema findChoice(final Collection<AbstractNodeDataWithSchema> childNodes,
117 final DataSchemaNode choiceCandidate, final DataSchemaNode caseCandidate) {
118 if (childNodes != null) {
119 for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
120 if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
121 && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
122 CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
124 Preconditions.checkArgument(casePrevious.getSchema().getQName().equals(caseCandidate.getQName()),
125 "Data from case %s are specified but other data from case %s were specified erlier. Data aren't from the same case.",
126 caseCandidate.getQName(), casePrevious.getSchema().getQName());
135 AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
136 CompositeNodeDataWithSchema newChild;
137 if (schema instanceof ListSchemaNode) {
138 newChild = new ListNodeDataWithSchema(schema);
139 } else if (schema instanceof LeafListSchemaNode) {
140 newChild = new LeafListNodeDataWithSchema(schema);
141 } else if (schema instanceof ContainerSchemaNode) {
142 newChild = new ContainerNodeDataWithSchema(schema);
144 newChild = new CompositeNodeDataWithSchema(schema);
146 addCompositeChild(newChild);
150 void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
151 AugmentationSchema augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), newChild.getSchema());
152 if (augSchema != null) {
153 augmentationsToChild.put(augSchema, newChild);
159 private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema) {
160 AbstractNodeDataWithSchema newChild = addSimpleChild(schema);
161 return newChild == null ? addCompositeChild(schema) : newChild;
164 public void addChild(final AbstractNodeDataWithSchema newChild) {
165 children.add(newChild);
169 * Return a hint about how may children we are going to generate.
170 * @return Size of currently-present node list.
172 protected final int childSizeHint() {
173 return children.size();
177 public void write(final SchemaAwareNormalizedNodeStreamWriter writer) throws IOException {
178 for (AbstractNodeDataWithSchema child : children) {
181 for (Entry<AugmentationSchema, Collection<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.asMap().entrySet()) {
182 final Collection<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
183 if (!childsFromAgumentation.isEmpty()) {
184 // FIXME: can we get the augmentation schema?
185 writer.startAugmentationNode(SchemaUtils.getNodeIdentifierForAugmentation(augmentationToChild.getKey()));
187 for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
188 nodeDataWithSchema.write(writer);