9e08fc2f39f1b8bd079ba6847d7aceed35dce02f
[yangtools.git] / yang / yang-data-impl / src / main / java / org / opendaylight / yangtools / yang / data / impl / schema / transform / base / SchemaUtils.java
1 /*
2  * Copyright (c) 2013 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8 package org.opendaylight.yangtools.yang.data.impl.schema.transform.base;
9
10
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.*;
22 import java.util.*;
23
24 public final class SchemaUtils {
25
26     private SchemaUtils() {
27     }
28
29     public static DataSchemaNode findSchemaForChild(DataNodeContainer schema, QName qname) {
30         Set<DataSchemaNode> childNodes = schema.getChildNodes();
31         return findSchemaForChild(schema, qname, childNodes);
32     }
33
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();
39     }
40
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",
44                 qNames, schema);
45         return schemaForAugment.get();
46     }
47
48     public static AugmentationSchema findSchemaForAugment(ChoiceNode schema, Set<QName> qNames) {
49         Optional<AugmentationSchema> schemaForAugment = Optional.absent();
50
51         for (ChoiceCaseNode choiceCaseNode : schema.getCases()) {
52             schemaForAugment = findAugment(choiceCaseNode, qNames);
53             if(schemaForAugment.isPresent()) {
54                 break;
55             }
56         }
57
58         Preconditions.checkState(schemaForAugment.isPresent(), "Unknown augmentation node detected, identified by: %s, in: %s",
59                 qNames, schema);
60         return schemaForAugment.get();
61     }
62
63     private static Optional<AugmentationSchema> findAugment(AugmentationTarget schema, Set<QName> qNames) {
64         for (AugmentationSchema augment : schema.getAvailableAugmentations()) {
65
66             HashSet<QName> qNamesFromAugment = Sets.newHashSet(Collections2.transform(augment.getChildNodes(), new Function<DataSchemaNode, QName>() {
67                 @Override
68                 public QName apply(DataSchemaNode input) {
69                     return input.getQName();
70                 }
71             }));
72
73             if(qNamesFromAugment.equals(qNames)) {
74                 return Optional.of(augment);
75             }
76         }
77
78         return Optional.absent();
79     }
80
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();
87             }
88         }
89
90
91         throw new IllegalStateException(String.format("Unknown child(ren) node(s) detected, identified by: %s, in: %s",
92                 childPartialQName, schema));
93     }
94
95     /**
96      * Recursively find all child nodes that come from choices in augment.
97      *
98      * @return Map with all child nodes, to their most top augmentation
99      */
100     public static Map<QName,ChoiceNode> mapChildElementsFromChoicesInAugment(AugmentationSchema schema, Set<DataSchemaNode> realChildSchemas) {
101         Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
102
103         for (DataSchemaNode realChildSchema : realChildSchemas) {
104             if(realChildSchema instanceof ChoiceNode)
105                 mappedChoices.putAll(mapChildElementsFromChoices(schema, realChildSchemas));
106         }
107
108         return mappedChoices;
109     }
110
111     /**
112      * Recursively find all child nodes that come from choices.
113      *
114      * @return Map with all child nodes, to their most top augmentation
115      */
116     public static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema) {
117         Set<DataSchemaNode> childNodes = schema.getChildNodes();
118
119         return mapChildElementsFromChoices(schema, childNodes);
120     }
121
122     private static Map<QName, ChoiceNode> mapChildElementsFromChoices(DataNodeContainer schema, Set<DataSchemaNode> childNodes) {
123         Map<QName, ChoiceNode> mappedChoices = Maps.newLinkedHashMap();
124
125         for (final DataSchemaNode childSchema : childNodes) {
126             if(childSchema instanceof ChoiceNode) {
127                 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
128
129                     for (QName qName : getChildNodes(choiceCaseNode)) {
130                         mappedChoices.put(qName, (ChoiceNode) childSchema);
131                     }
132                 }
133             }
134         }
135
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);
140
141             return Maps.filterKeys(mappedChoices, new Predicate<QName>() {
142                 @Override
143                 public boolean apply(QName input) {
144                     return augments.containsKey(input) == false;
145                 }
146             });
147         }
148
149         return mappedChoices;
150     }
151
152     /**
153      * Recursively find all child nodes that come from augmentations.
154      *
155      * @return Map with all child nodes, to their most top augmentation
156      */
157     public static Map<QName, AugmentationSchema> mapChildElementsFromAugments(AugmentationTarget schema) {
158
159         Map<QName, AugmentationSchema> childNodesToAugmentation = Maps.newLinkedHashMap();
160
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);
166             }
167         }
168
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) {
172
173             for (DataSchemaNode child : ((DataNodeContainer) schema).getChildNodes()) {
174                 // If is not augmented child, continue
175                 if (augments.containsKey(child.getQName()) == false)
176                     continue;
177
178                 AugmentationSchema mostTopAugmentation = augments.get(child.getQName());
179
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);
184                     }
185                 } else if (child instanceof ChoiceNode) {
186                     for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) child).getCases()) {
187                         for (QName qName : getChildNodes(choiceCaseNode)) {
188                             childNodesToAugmentation.put(qName, mostTopAugmentation);
189                         }
190                     }
191                 } else {
192                     childNodesToAugmentation.put(child.getQName(), mostTopAugmentation);
193                 }
194             }
195         }
196
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) {
201                     continue;
202                 }
203
204                 for (QName qName : getChildNodes(choiceCaseNode)) {
205                     childNodesToAugmentation.put(qName, augments.get(choiceCaseNode.getQName()));
206                 }
207             }
208         }
209
210         return childNodesToAugmentation;
211     }
212
213     /**
214      * Recursively list all child nodes.
215      *
216      * In case of choice, augment and cases, step in.
217      */
218     public static Set<QName> getChildNodes(DataNodeContainer nodeContainer) {
219         Set<QName> allChildNodes = Sets.newHashSet();
220
221         for (DataSchemaNode childSchema : nodeContainer.getChildNodes()) {
222             if(childSchema instanceof ChoiceNode) {
223                 for (ChoiceCaseNode choiceCaseNode : ((ChoiceNode) childSchema).getCases()) {
224                     allChildNodes.addAll(getChildNodes(choiceCaseNode));
225                 }
226             } else if(childSchema instanceof AugmentationSchema || childSchema instanceof ChoiceCaseNode) {
227                 allChildNodes.addAll(getChildNodes((DataNodeContainer) childSchema));
228             }
229             else {
230                 allChildNodes.add(childSchema.getQName());
231             }
232         }
233
234         return allChildNodes;
235     }
236
237     /**
238      * Retrieves real schemas for augmented child node.
239      *
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.
242      *
243      */
244     public static Set<DataSchemaNode> getRealSchemasForAugment(AugmentationTarget targetSchema, AugmentationSchema augmentSchema) {
245         if(targetSchema.getAvailableAugmentations().contains(augmentSchema) == false) {
246             return Collections.emptySet();
247         }
248
249         Set<DataSchemaNode> realChildNodes = Sets.newHashSet();
250
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()));
258                     }
259                 }
260             }
261         }
262
263         return realChildNodes;
264     }
265
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);
272         }
273         return realChildNodes;
274     }
275
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);
281                 }
282             }
283         }
284
285         return Optional.absent();
286     }
287 }