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.schema.DataContainerChild;
20 import org.opendaylight.yangtools.yang.data.impl.codec.xml.XmlDocumentUtils;
21 import org.opendaylight.yangtools.yang.model.api.*;
24 public final class SchemaUtils {
26 private SchemaUtils() {
29 public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname) {
30 Set<DataSchemaNode> childNodes = schema.getChildNodes();
31 return findSchemaForChild(schema, qname, childNodes);
34 public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname, Set<DataSchemaNode> childNodes) {
35 Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(qname, childNodes);
36 Preconditions.checkState(childSchema.isPresent(),
37 "Unknown child(ren) node(s) detected, identified by: %s, in: %s", qname, schema);
38 return childSchema.get();
41 public static AugmentationSchema findSchemaForAugment(AugmentationTarget schema, Set<QName> qNames) {
42 Optional<AugmentationSchema> schemaForAugment = findAugment(schema, qNames);
43 Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
45 return schemaForAugment.get();
48 public static AugmentationSchema findSchemaForAugment(ChoiceNode schema, Set<QName> qNames) {
49 Optional<AugmentationSchema> schemaForAugment = Optional.absent();
51 for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
52 schemaForAugment = findAugment(choiceCaseNode, qNames);
53 if(schemaForAugment.isPresent()) {
58 Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
60 return schemaForAugment.get();
63 private static Optional<AugmentationSchema> findAugment(AugmentationTarget schema, Set<QName> qNames) {
64 for (AugmentationSchema augment : schema.getAvailableAugmentations()) {
66 HashSet<QName> qNamesFromAugment = Sets.newHashSet(Collections2.transform(augment.getChildNodes(), new Function<DataSchemaNode, QName>() {
68 public QName apply(DataSchemaNode input) {
69 return input.getQName();
73 if(qNamesFromAugment.equals(qNames)) {
74 return Optional.of(augment);
78 return Optional.absent();
81 public static DataSchemaNode findSchemaForChild(ChoiceNode schema, QName childPartialQName) {
82 for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
83 Optional<DataSchemaNode> childSchema = XmlDocumentUtils.findFirstSchema(childPartialQName,
84 choiceCaseNode.getChildNodes());
85 if (childSchema.isPresent()) {
86 return childSchema.get();
91 throw new IllegalStateException(String.format("Unknown child(ren) node(s) detected, identified by: %s, in: %s",
92 childPartialQName, schema));
96 * Recursively find all child nodes that come from choices in augment.
98 * @return Map with all child nodes, to their most top augmentation
100 public static Map<QName,ChoiceNode> mapChildElementsFromChoicesInAugment(AugmentationSchema schema, Set<DataSchemaNode> realChildSchemas) {
101 Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
103 for (DataSchemaNode realChildSchema : realChildSchemas) {
104 if(realChildSchema instanceof ChoiceNode)
105 mappedChoices.putAll(mapChildElementsFromChoices(schema, realChildSchemas));
108 return mappedChoices;
112 * Recursively find all child nodes that come from choices.
114 * @return Map with all child nodes, to their most top augmentation
116 public static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema) {
117 Set<DataSchemaNode> childNodes = schema.getChildNodes();
119 return mapChildElementsFromChoices(schema, childNodes);
122 private static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema, Set<DataSchemaNode> childNodes) {
123 Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
125 for (final DataSchemaNode childSchema : childNodes) {
126 if(childSchema instanceof ChoiceNode) {
127 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
129 for (QName qName : getChildNodes(choiceCaseNode)) {
130 mappedChoices.put(qName, (ChoiceNode) childSchema);
136 // Remove augmented choices
137 // TODO ineffective, mapping augments one more time is not necessary, the map could be injected
138 if(schema instanceof AugmentationTarget) {
139 final Map<QName, AugmentationSchema> augments = mapChildElementsFromAugments((AugmentationTarget) schema);
141 return Maps.filterKeys(mappedChoices, new Predicate<QName>() {
143 public boolean apply(QName input) {
144 return augments.containsKey(input) == false;
149 return mappedChoices;
153 * Recursively find all child nodes that come from augmentations.
155 * @return Map with all child nodes, to their most top augmentation
157 public static Map<QName, AugmentationSchema> mapChildElementsFromAugments(AugmentationTarget schema) {
159 Map<QName, AugmentationSchema> childNodesToAugmentation = Maps.newLinkedHashMap();
161 // Find QNames of augmented child nodes
162 Map<QName, AugmentationSchema> augments = Maps.newHashMap();
163 for (final AugmentationSchema augmentationSchema : schema.getAvailableAugmentations()) {
164 for (DataSchemaNode dataSchemaNode : augmentationSchema.getChildNodes()) {
165 augments.put(dataSchemaNode.getQName(), augmentationSchema);
169 // Augmented nodes have to be looked up directly in augmentationTarget
170 // because nodes from augment do not contain nodes from other augmentations
171 if (schema instanceof DataNodeContainer) {
173 for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) {
174 // If is not augmented child, continue
175 if (augments.containsKey(child.getQName()) == false)
178 AugmentationSchema mostTopAugmentation = augments.get(child.getQName());
180 // recursively add all child nodes in case of augment, case and choice
181 if (child instanceof AugmentationSchema || child instanceof ChoiceCaseNode) {
182 for (QName qName : getChildNodes((DataNodeContainer) child)) {
183 childNodesToAugmentation.put(qName, mostTopAugmentation);
185 } else if (child instanceof ChoiceNode) {
186 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) child).getCases()) {
187 for (QName qName : getChildNodes(choiceCaseNode)) {
188 childNodesToAugmentation.put(qName, mostTopAugmentation);
192 childNodesToAugmentation.put(child.getQName(), mostTopAugmentation);
197 // Choice Node has to map child nodes from all its cases
198 if (schema instanceof ChoiceNode) {
199 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) schema).getCases()) {
200 if (augments.containsKey(choiceCaseNode.getQName()) == false) {
204 for (QName qName : getChildNodes(choiceCaseNode)) {
205 childNodesToAugmentation.put(qName, augments.get(choiceCaseNode.getQName()));
210 return childNodesToAugmentation;
214 * Recursively list all child nodes.
216 * In case of choice, augment and cases, step in.
218 public static Set<QName> getChildNodes(DataNodeContainer nodeContainer) {
219 Set<QName> allChildNodes = Sets.newHashSet();
221 for (DataSchemaNode childSchema : nodeContainer.getChildNodes()) {
222 if(childSchema instanceof ChoiceNode) {
223 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
224 allChildNodes.addAll(getChildNodes(choiceCaseNode));
226 } else if(childSchema instanceof AugmentationSchema || childSchema instanceof ChoiceCaseNode) {
227 allChildNodes.addAll(getChildNodes((DataNodeContainer) childSchema));
230 allChildNodes.add(childSchema.getQName());
234 return allChildNodes;
238 * Retrieves real schemas for augmented child node.
240 * Schema of the same child node from augment, and directly from target is not the same.
241 * Schema of child node from augment is incomplete, therefore its useless for xml <-> normalizedNode translation.
244 public static Set<DataSchemaNode> getRealSchemasForAugment(AugmentationTarget targetSchema, AugmentationSchema augmentSchema) {
245 if(targetSchema.getAvailableAugmentations().contains(augmentSchema) == false) {
246 return Collections.emptySet();
249 Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
251 if(targetSchema instanceof DataNodeContainer) {
252 realChildNodes = getRealSchemasForAugment((DataNodeContainer)targetSchema, augmentSchema);
253 } else if(targetSchema instanceof ChoiceNode) {
254 for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
255 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) targetSchema).getCases()) {
256 if(getChildNodes(choiceCaseNode).contains(dataSchemaNode.getQName())) {
257 realChildNodes.add(choiceCaseNode.getDataChildByName(dataSchemaNode.getQName()));
263 return realChildNodes;
266 public static Set<DataSchemaNode> getRealSchemasForAugment(DataNodeContainer targetSchema,
267 AugmentationSchema augmentSchema) {
268 Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
269 for (DataSchemaNode dataSchemaNode : augmentSchema.getChildNodes()) {
270 DataSchemaNode realChild = targetSchema.getDataChildByName(dataSchemaNode.getQName());
271 realChildNodes.add(realChild);
273 return realChildNodes;
276 public static Optional<ChoiceCaseNode> detectCase(ChoiceNode schema, DataContainerChild<?, ?> child) {
277 for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
278 for (DataSchemaNode childFromCase : choiceCaseNode.getChildNodes()) {
279 if (childFromCase.getQName().equals(child.getNodeType())) {
280 return Optional.of(choiceCaseNode);
285 return Optional.absent();