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;
30 import org.opendaylight.yangtools.yang.model.api.YangModeledAnyXmlSchemaNode;
33 * A node which is composed of multiple simpler nodes.
35 class CompositeNodeDataWithSchema extends AbstractNodeDataWithSchema {
38 * nodes which were added to schema via augmentation and are present in data input
40 private final Multimap<AugmentationSchema, AbstractNodeDataWithSchema> augmentationsToChild = ArrayListMultimap.create();
43 * remaining data nodes (which aren't added via augment). Every of one them should have the same QName.
45 private final List<AbstractNodeDataWithSchema> children = new ArrayList<>();
47 public CompositeNodeDataWithSchema(final DataSchemaNode schema) {
51 public AbstractNodeDataWithSchema addChild(final Deque<DataSchemaNode> schemas) {
52 Preconditions.checkArgument(!schemas.isEmpty(), "Expecting at least one schema");
54 // Pop the first node...
55 final DataSchemaNode schema = schemas.pop();
56 if (schemas.isEmpty()) {
57 // Simple, direct node
58 return addChild(schema);
61 // The choice/case mess, reuse what we already popped
62 final DataSchemaNode choiceCandidate = schema;
63 Preconditions.checkArgument(choiceCandidate instanceof ChoiceSchemaNode,
64 "Expected node of type ChoiceNode but was %s", choiceCandidate.getClass().getSimpleName());
65 final ChoiceSchemaNode choiceNode = (ChoiceSchemaNode) choiceCandidate;
67 final DataSchemaNode caseCandidate = schemas.pop();
68 Preconditions.checkArgument(caseCandidate instanceof ChoiceCaseNode,
69 "Expected node of type ChoiceCaseNode but was %s", caseCandidate.getClass().getSimpleName());
70 final ChoiceCaseNode caseNode = (ChoiceCaseNode) caseCandidate;
72 AugmentationSchema augSchema = null;
73 if (choiceCandidate.isAugmenting()) {
74 augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), choiceCandidate);
77 // looking for existing choice
78 final Collection<AbstractNodeDataWithSchema> childNodes;
79 if (augSchema != null) {
80 childNodes = augmentationsToChild.get(augSchema);
82 childNodes = children;
85 CompositeNodeDataWithSchema caseNodeDataWithSchema = findChoice(childNodes, choiceCandidate, caseCandidate);
86 if (caseNodeDataWithSchema == null) {
87 ChoiceNodeDataWithSchema choiceNodeDataWithSchema = new ChoiceNodeDataWithSchema(choiceNode);
88 childNodes.add(choiceNodeDataWithSchema);
89 caseNodeDataWithSchema = choiceNodeDataWithSchema.addCompositeChild(caseNode);
92 return caseNodeDataWithSchema.addChild(schemas);
95 private AbstractNodeDataWithSchema addSimpleChild(final DataSchemaNode schema) {
96 SimpleNodeDataWithSchema newChild = null;
97 if (schema instanceof LeafSchemaNode) {
98 newChild = new LeafNodeDataWithSchema(schema);
99 } else if (schema instanceof AnyXmlSchemaNode) {
100 // YangModeledAnyXmlSchemaNode is handled by addCompositeChild method.
101 if (schema instanceof YangModeledAnyXmlSchemaNode) {
104 newChild = new AnyXmlNodeDataWithSchema(schema);
109 AugmentationSchema augSchema = null;
110 if (schema.isAugmenting()) {
111 augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), schema);
113 if (augSchema != null) {
114 augmentationsToChild.put(augSchema, newChild);
121 private static CaseNodeDataWithSchema findChoice(final Collection<AbstractNodeDataWithSchema> childNodes,
122 final DataSchemaNode choiceCandidate, final DataSchemaNode caseCandidate) {
123 if (childNodes != null) {
124 for (AbstractNodeDataWithSchema nodeDataWithSchema : childNodes) {
125 if (nodeDataWithSchema instanceof ChoiceNodeDataWithSchema
126 && nodeDataWithSchema.getSchema().getQName().equals(choiceCandidate.getQName())) {
127 CaseNodeDataWithSchema casePrevious = ((ChoiceNodeDataWithSchema) nodeDataWithSchema).getCase();
129 Preconditions.checkArgument(casePrevious.getSchema().getQName().equals(caseCandidate.getQName()),
130 "Data from case %s are specified but other data from case %s were specified erlier. Data aren't from the same case.",
131 caseCandidate.getQName(), casePrevious.getSchema().getQName());
140 AbstractNodeDataWithSchema addCompositeChild(final DataSchemaNode schema) {
141 final CompositeNodeDataWithSchema newChild;
143 if (schema instanceof ListSchemaNode) {
144 newChild = new ListNodeDataWithSchema(schema);
145 } else if (schema instanceof LeafListSchemaNode) {
146 newChild = new LeafListNodeDataWithSchema(schema);
147 } else if (schema instanceof ContainerSchemaNode) {
148 newChild = new ContainerNodeDataWithSchema(schema);
149 } else if (schema instanceof YangModeledAnyXmlSchemaNode) {
150 newChild = new YangModeledAnyXmlNodeDataWithSchema((YangModeledAnyXmlSchemaNode)schema);
152 newChild = new CompositeNodeDataWithSchema(schema);
155 addCompositeChild(newChild);
159 void addCompositeChild(final CompositeNodeDataWithSchema newChild) {
160 AugmentationSchema augSchema = SchemaUtils.findCorrespondingAugment(getSchema(), newChild.getSchema());
161 if (augSchema != null) {
162 augmentationsToChild.put(augSchema, newChild);
168 private AbstractNodeDataWithSchema addChild(final DataSchemaNode schema) {
169 AbstractNodeDataWithSchema newChild = addSimpleChild(schema);
170 return newChild == null ? addCompositeChild(schema) : newChild;
173 public void addChild(final AbstractNodeDataWithSchema newChild) {
174 children.add(newChild);
178 * Return a hint about how may children we are going to generate.
179 * @return Size of currently-present node list.
181 protected final int childSizeHint() {
182 return children.size();
186 public void write(final SchemaAwareNormalizedNodeStreamWriter writer) throws IOException {
187 for (AbstractNodeDataWithSchema child : children) {
190 for (Entry<AugmentationSchema, Collection<AbstractNodeDataWithSchema>> augmentationToChild : augmentationsToChild.asMap().entrySet()) {
191 final Collection<AbstractNodeDataWithSchema> childsFromAgumentation = augmentationToChild.getValue();
192 if (!childsFromAgumentation.isEmpty()) {
193 // FIXME: can we get the augmentation schema?
194 writer.startAugmentationNode(SchemaUtils.getNodeIdentifierForAugmentation(augmentationToChild.getKey()));
196 for (AbstractNodeDataWithSchema nodeDataWithSchema : childsFromAgumentation) {
197 nodeDataWithSchema.write(writer);