2 * Copyright (c) 2013 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.impl.schema.transform.base;
11 import com.google.common.base.Function;
12 import com.google.common.base.Optional;
13 import com.google.common.base.Preconditions;
14 import com.google.common.base.Predicate;
15 import com.google.common.collect.Collections2;
16 import com.google.common.collect.Maps;
17 import com.google.common.collect.Sets;
18 import org.opendaylight.yangtools.yang.common.QName;
19 import org.opendaylight.yangtools.yang.data.api.InstanceIdentifier;
20 import org.opendaylight.yangtools.yang.data.api.schema.AugmentationNode;
21 import org.opendaylight.yangtools.yang.data.api.schema.DataContainerChild;
22 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
23 import org.opendaylight.yangtools.yang.model.api.*;
26 public final class SchemaUtils {
28 private SchemaUtils() {
31 public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname) {
32 Set<DataSchemaNode> childNodes = schema.getChildNodes();
33 return findSchemaForChild(schema, qname, childNodes);
36 public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname, Set<DataSchemaNode> childNodes) {
37 Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(qname, childNodes);
38 Preconditions.checkState(childSchema.isPresent(),
39 "Unknown child(ren) node(s) detected, identified by: %s, in: %s", qname, schema);
40 return childSchema.get();
43 public static AugmentationSchema findSchemaForAugment(AugmentationTarget schema, Set<QName> qNames) {
44 Optional<AugmentationSchema> schemaForAugment = findAugment(schema, qNames);
45 Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
47 return schemaForAugment.get();
50 public static AugmentationSchema findSchemaForAugment(ChoiceNode schema, Set<QName> qNames) {
51 Optional<AugmentationSchema> schemaForAugment = Optional.absent();
53 for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
54 schemaForAugment = findAugment(choiceCaseNode, qNames);
55 if(schemaForAugment.isPresent()) {
60 Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
62 return schemaForAugment.get();
65 private static Optional<AugmentationSchema> findAugment(AugmentationTarget schema, Set<QName> qNames) {
66 for (AugmentationSchema augment : schema.getAvailableAugmentations()) {
68 HashSet<QName> qNamesFromAugment = Sets.newHashSet(Collections2.transform(augment.getChildNodes(), new Function<DataSchemaNode, QName>() {
70 public QName apply(DataSchemaNode input) {
71 return input.getQName();
75 if(qNamesFromAugment.equals(qNames)) {
76 return Optional.of(augment);
80 return Optional.absent();
83 public static DataSchemaNode findSchemaForChild(ChoiceNode schema, QName childPartialQName) {
84 for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
85 Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(childPartialQName,
86 choiceCaseNode.getChildNodes());
87 if (childSchema.isPresent()) {
88 return childSchema.get();
93 throw new IllegalStateException(String.format("Unknown child(ren) node(s) detected, identified by: %s, in: %s",
94 childPartialQName, schema));
98 * Recursively find all child nodes that come from choices in augment.
100 * @return Map with all child nodes, to their most top augmentation
102 public static Map<QName,ChoiceNode> mapChildElementsFromChoicesInAugment(AugmentationSchema schema, Set<DataSchemaNode> realChildSchemas) {
103 Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
105 for (DataSchemaNode realChildSchema : realChildSchemas) {
106 if(realChildSchema instanceof ChoiceNode)
107 mappedChoices.putAll(mapChildElementsFromChoices(schema, realChildSchemas));
110 return mappedChoices;
114 * Recursively find all child nodes that come from choices.
116 * @return Map with all child nodes, to their most top augmentation
118 public static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema) {
119 Set<DataSchemaNode> childNodes = schema.getChildNodes();
121 return mapChildElementsFromChoices(schema, childNodes);
124 private static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema, Set<DataSchemaNode> childNodes) {
125 Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
127 for (final DataSchemaNode childSchema : childNodes) {
128 if(childSchema instanceof ChoiceNode) {
129 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
131 for (QName qName : getChildNodes(choiceCaseNode)) {
132 mappedChoices.put(qName, (ChoiceNode) childSchema);
138 // Remove augmented choices
139 // TODO ineffective, mapping augments one more time is not necessary, the map could be injected
140 if(schema instanceof AugmentationTarget) {
141 final Map<QName, AugmentationSchema> augments = mapChildElementsFromAugments((AugmentationTarget) schema);
143 return Maps.filterKeys(mappedChoices, new Predicate<QName>() {
145 public boolean apply(QName input) {
146 return augments.containsKey(input) == false;
151 return mappedChoices;
155 * Recursively find all child nodes that come from augmentations.
157 * @return Map with all child nodes, to their most top augmentation
159 public static Map<QName, AugmentationSchema> mapChildElementsFromAugments(AugmentationTarget schema) {
161 Map<QName, AugmentationSchema> childNodesToAugmentation = Maps.newLinkedHashMap();
163 // Find QNames of augmented child nodes
164 Map<QName, AugmentationSchema> augments = Maps.newHashMap();
165 for (final AugmentationSchema augmentationSchema : schema.getAvailableAugmentations()) {
166 for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) {
167 augments.put(dataSchemaNode.getQName(), augmentationSchema);
171 // Augmented nodes have to be looked up directly in augmentationTarget
172 // because nodes from augment do not contain nodes from other augmentations
173 if (schema instanceof DataNodeContainer) {
175 for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) {
176 // If is not augmented child, continue
177 if (augments.containsKey(child.getQName()) == false)
180 AugmentationSchema mostTopAugmentation = augments.get(child.getQName());
182 // recursively add all child nodes in case of augment, case and choice
183 if (child instanceof AugmentationSchema || child instanceof ChoiceCaseNode) {
184 for (QName qName : getChildNodes((DataNodeContainer) child)) {
185 childNodesToAugmentation.put(qName, mostTopAugmentation);
187 } else if (child instanceof ChoiceNode) {
188 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) child).getCases()) {
189 for (QName qName : getChildNodes(choiceCaseNode)) {
190 childNodesToAugmentation.put(qName, mostTopAugmentation);
194 childNodesToAugmentation.put(child.getQName(), mostTopAugmentation);
199 // Choice Node has to map child nodes from all its cases
200 if (schema instanceof ChoiceNode) {
201 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) schema).getCases()) {
202 if (augments.containsKey(choiceCaseNode.getQName()) == false) {
206 for (QName qName : getChildNodes(choiceCaseNode)) {
207 childNodesToAugmentation.put(qName, augments.get(choiceCaseNode.getQName()));
212 return childNodesToAugmentation;
216 * Recursively list all child nodes.
218 * In case of choice, augment and cases, step in.
220 public static Set<QName> getChildNodes(DataNodeContainer nodeContainer) {
221 Set<QName> allChildNodes = Sets.newHashSet();
223 for (DataSchemaNode childSchema : nodeContainer.getChildNodes()) {
224 if(childSchema instanceof ChoiceNode) {
225 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
226 allChildNodes.addAll(getChildNodes(choiceCaseNode));
228 } else if(childSchema instanceof AugmentationSchema || childSchema instanceof ChoiceCaseNode) {
229 allChildNodes.addAll(getChildNodes((DataNodeContainer) childSchema));
232 allChildNodes.add(childSchema.getQName());
236 return allChildNodes;
240 * Retrieves real schemas for augmented child node.
242 * Schema of the same child node from augment, and directly from target is not the same.
243 * Schema of child node from augment is incomplete, therefore its useless for xml <-> normalizedNode translation.
246 public static Set<DataSchemaNode> getRealSchemasForAugment(AugmentationTarget targetSchema, AugmentationSchema augmentSchema) {
247 if(targetSchema.getAvailableAugmentations().contains(augmentSchema) == false) {
248 return Collections.emptySet();
251 Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
253 if(targetSchema instanceof DataNodeContainer) {
254 realChildNodes = getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema);
255 } else if(targetSchema instanceof ChoiceNode) {
256 for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
257 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) targetSchema).getCases()) {
258 if(getChildNodes(choiceCaseNode).contains(dataSchemaNode.getQName())) {
259 realChildNodes.add(choiceCaseNode.getDataChildByName(dataSchemaNode.getQName()));
265 return realChildNodes;
268 public static Set<DataSchemaNode> getRealSchemasForAugment(DataNodeContainer targetSchema,
269 AugmentationSchema augmentSchema) {
270 Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
271 for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
272 DataSchemaNode realChild = targetSchema.getDataChildByName(dataSchemaNode.getQName());
273 realChildNodes.add(realChild);
275 return realChildNodes;
278 public static Optional<ChoiceCaseNode> detectCase(ChoiceNode schema, DataContainerChild<?, ?> child) {
279 for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
280 if (child instanceof AugmentationNode
281 && belongsToCaseAugment(choiceCaseNode,
282 (InstanceIdentifier.AugmentationIdentifier) child.getIdentifier())) {
283 return Optional.of(choiceCaseNode);
284 } else if (choiceCaseNode.getDataChildByName(child.getNodeType()) != null) {
285 return Optional.of(choiceCaseNode);
289 return Optional.absent();
292 public static boolean belongsToCaseAugment(ChoiceCaseNode caseNode, InstanceIdentifier.AugmentationIdentifier childToProcess) {
293 for (AugmentationSchema augmentationSchema : caseNode.getAvailableAugmentations()) {
295 Set<QName> currentAugmentChildNodes = Sets.newHashSet();
296 for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) {
297 currentAugmentChildNodes.add(dataSchemaNode.getQName());
300 if(childToProcess.getPossibleChildNames().equals(currentAugmentChildNodes)){