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 java.io.IOException;
11 import java.util.ArrayList;
12 import java.util.Collection;
13 import java.util.Collections;
14 import java.util.Deque;
15 import java.util.HashMap;
16 import java.util.HashSet;
17 import java.util.List;
19 import java.util.Map.Entry;
22 import org.opendaylight.yangtools.yang.common.QName;
23 import org.opendaylight.yangtools.yang.data.api.YangInstanceIdentifier.AugmentationIdentifier;
24 import org.opendaylight.yangtools.yang.data.api.schema.stream.NormalizedNodeStreamWriter;
25 import org.opendaylight.yangtools.yang.model.api.AnyXmlSchemaNode;
26 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
27 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
28 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
29 import org.opendaylight.yangtools.yang.model.api.ChoiceNode;
30 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
32 import org.opendaylight.yangtools.yang.model.api.LeafListSchemaNode;
33 import org.opendaylight.yangtools.yang.model.api.LeafSchemaNode;
34 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
36 class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
39 * nodes which were added to schema via augmentation and are present in data input
41 protected Map<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationsToChild = new HashMap<>();
44 * remaining data nodes (which aren't added via augment). Every of them should have the same QName
46 protected List<AbstractNodeDataWithSchema> childs = new ArrayList<>();
48 public CompositeNodeDataWithSchema(final DataSchemaNode schema) {
52 public AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
53 SimpleNodeDataWithSchema newChild = null;
54 if (schema instanceof LeafSchemaNode) {
55 newChild = new LeafNodeDataWithSchema(schema);
56 } else if (schema instanceof AnyXmlSchemaNode) {
57 newChild = new AnyXmlNodeDataWithSchema(schema);
60 if (newChild != null) {
62 AugmentationSchema augSchema = null;
63 if (schema.isAugmenting()) {
64 augSchema = findCorrespondingAugment(getSchema(), schema);
66 if (augSchema != null) {
67 addChildToAugmentation(augSchema, newChild);
76 private void addChildToAugmentation(final AugmentationSchema augSchema, final AbstractNodeDataWithSchema newChild) {
77 List<AbstractNodeDataWithSchema> childsInAugment = augmentationsToChild.get(augSchema);
78 if (childsInAugment == null) {
79 childsInAugment = new ArrayList<>();
80 augmentationsToChild.put(augSchema, childsInAugment);
82 childsInAugment.add(newChild);
85 public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
86 if (schemas.size() == 1) {
87 final DataSchemaNode childDataSchemaNode = schemas.pop();
88 return addChild(childDataSchemaNode);
90 DataSchemaNode choiceCandidate = schemas.pop();
91 DataSchemaNode caseCandidate = schemas.pop();
92 ChoiceNode choiceNode = null;
93 ChoiceCaseNode caseNode = null;
94 if (choiceCandidate instanceof ChoiceNode) {
95 choiceNode = (ChoiceNode) choiceCandidate;
97 throw new IllegalArgumentException("Awaited node of type ChoiceNode but was "
98 + choiceCandidate.getClass().getSimpleName());
101 if (caseCandidate instanceof ChoiceCaseNode) {
102 caseNode = (ChoiceCaseNode) caseCandidate;
104 throw new IllegalArgumentException("Awaited node of type ChoiceCaseNode but was "
105 + caseCandidate.getClass().getSimpleName());
108 AugmentationSchema augSchema = null;
109 if (choiceCandidate.isAugmenting()) {
110 augSchema = findCorrespondingAugment(getSchema(), choiceCandidate);
113 // looking for existing choice
114 List<AbstractNodeDataWithSchema> childNodes = Collections.emptyList();
115 if (augSchema != null) {
116 childNodes = augmentationsToChild.get(augSchema);
121 CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
122 if (caseNodeDataWithSchema == null) {
123 ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
124 addChild(choiceNodeDataWithSchema);
125 caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
128 return caseNodeDataWithSchema.addChild(schemas);
133 private CaseNodeDataWithSchema findChoice(final List<AbstractNodeDataWithSchema> childNodes, final DataSchemaNode choiceCandidate,
134 final DataSchemaNode caseCandidate) {
135 if (childNodes == null) {
138 for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
139 if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
140 && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
141 CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
142 if (casePrevious.getSchema().getQName() != caseCandidate.getQName()) {
143 throw new IllegalArgumentException("Data from case " + caseCandidate.getQName()
144 + " are specified but other data from case " + casePrevious.getSchema().getQName()
145 + " were specified erlier. Data aren't from the same case.");
153 public AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
154 CompositeNodeDataWithSchema newChild;
155 if (schema instanceof ListSchemaNode) {
156 newChild = new ListNodeDataWithSchema(schema);
157 } else if (schema instanceof LeafListSchemaNode) {
158 newChild = new LeafListNodeDataWithSchema(schema);
159 } else if (schema instanceof ContainerSchemaNode) {
160 newChild = new ContainerNodeDataWithSchema(schema);
162 newChild = new CompositeNodeDataWithSchema(schema);
164 addCompositeChild(newChild);
168 public void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
169 AugmentationSchema augSchema = findCorrespondingAugment(getSchema(), newChild.getSchema());
170 if (augSchema != null) {
171 addChildToAugmentation(augSchema, newChild);
177 private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema) {
178 AbstractNodeDataWithSchema newChild = addSimpleChild(schema);
179 return newChild == null ? addCompositeChild(schema) : newChild;
182 public void addChild(final AbstractNodeDataWithSchema newChild) {
183 childs.add(newChild);
187 * Tries to find in {@code parent} which is dealed as augmentation target node with QName as {@code child}. If such
188 * node is found then it is returned, else null.
190 protected AugmentationSchema findCorrespondingAugment(final DataSchemaNode parent, final DataSchemaNode child) {
191 if (parent instanceof AugmentationTarget) {
192 for (AugmentationSchema augmentation : ((AugmentationTarget) parent).getAvailableAugmentations()) {
193 DataSchemaNode childInAugmentation = augmentation.getDataChildByName(child.getQName());
194 if (childInAugmentation != null) {
203 protected void writeToStream(final NormalizedNodeStreamWriter nnStreamWriter) throws IOException {
204 for (AbstractNodeDataWithSchema child : childs) {
205 child.writeToStream(nnStreamWriter);
207 for (Entry<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.entrySet()) {
209 final List<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
211 if (!childsFromAgumentation.isEmpty()) {
212 nnStreamWriter.startAugmentationNode(toAugmentationIdentifier(augmentationToChild));
214 for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
215 nodeDataWithSchema.writeToStream(nnStreamWriter);
218 nnStreamWriter.endNode();
223 private static AugmentationIdentifier toAugmentationIdentifier(
224 final Entry<AugmentationSchema, List<AbstractNodeDataWithSchema>> augmentationToChild) {
225 Collection<DataSchemaNode> nodes = augmentationToChild.getKey().getChildNodes();
226 Set<QName> nodesQNames = new HashSet<>();
227 for (DataSchemaNode node : nodes) {
228 nodesQNames.add(node.getQName());
231 return new AugmentationIdentifier(nodesQNames);