BUG-865: remove String-based getDataChildByName()
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / yangtools / sal / binding / generator / impl / BindingSchemaContextUtils.java
1 /*
2  * Copyright (c) 2014, 2015 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
9 package org.opendaylight.yangtools.sal.binding.generator.impl;
10
11 import com.google.common.base.Optional;
12 import com.google.common.base.Preconditions;
13 import java.util.HashSet;
14 import java.util.Iterator;
15 import java.util.Set;
16 import org.opendaylight.yangtools.yang.binding.Augmentation;
17 import org.opendaylight.yangtools.yang.binding.BindingMapping;
18 import org.opendaylight.yangtools.yang.binding.ChildOf;
19 import org.opendaylight.yangtools.yang.binding.DataObject;
20 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier;
21 import org.opendaylight.yangtools.yang.binding.InstanceIdentifier.PathArgument;
22 import org.opendaylight.yangtools.yang.binding.YangModuleInfo;
23 import org.opendaylight.yangtools.yang.binding.util.BindingReflections;
24 import org.opendaylight.yangtools.yang.common.QName;
25 import org.opendaylight.yangtools.yang.model.api.AugmentationSchema;
26 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
27 import org.opendaylight.yangtools.yang.model.api.ChoiceCaseNode;
28 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
29 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
30 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
31 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
32 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
33 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
34 import org.opendaylight.yangtools.yang.model.api.SchemaNode;
35 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
36
37 public final class BindingSchemaContextUtils {
38
39     private BindingSchemaContextUtils() {
40         throw new UnsupportedOperationException("Utility class should not be instantiated");
41     }
42
43     // FIXME: THis method does not search in case augmentations.
44     public static Optional<DataNodeContainer> findDataNodeContainer(final SchemaContext ctx,
45             final InstanceIdentifier<?> path) {
46         Iterator<PathArgument> pathArguments = path.getPathArguments().iterator();
47         PathArgument currentArg = pathArguments.next();
48         Preconditions.checkArgument(currentArg != null);
49         QName currentQName = BindingReflections.findQName(currentArg.getType());
50
51         Optional<DataNodeContainer> currentContainer = Optional.absent();
52         if (BindingReflections.isNotification(currentArg.getType())) {
53             currentContainer = findNotification(ctx, currentQName);
54         } else if (BindingReflections.isRpcType(currentArg.getType())) {
55             currentContainer = findFirstDataNodeContainerInRpc(ctx, currentArg.getType());
56             if(currentQName == null && currentContainer.isPresent()) {
57                 currentQName = ((DataSchemaNode) currentContainer.get()).getQName();
58             }
59         } else {
60             currentContainer = findDataNodeContainer(ctx, currentQName);
61         }
62
63         while (currentContainer.isPresent() && pathArguments.hasNext()) {
64             currentArg = pathArguments.next();
65             if (Augmentation.class.isAssignableFrom(currentArg.getType())) {
66                 currentQName = BindingReflections.findQName(currentArg.getType());
67                 if(pathArguments.hasNext()) {
68                     currentArg = pathArguments.next();
69                 } else {
70                     return currentContainer;
71                 }
72             }
73             if(ChildOf.class.isAssignableFrom(currentArg.getType()) && BindingReflections.isAugmentationChild(currentArg.getType())) {
74                 currentQName = BindingReflections.findQName(currentArg.getType());
75             } else {
76                 currentQName = QName.create(currentQName, BindingReflections.findQName(currentArg.getType()).getLocalName());
77             }
78             Optional<DataNodeContainer> potential = findDataNodeContainer(currentContainer.get(), currentQName);
79             if (potential.isPresent()) {
80                 currentContainer = potential;
81             } else {
82                 return Optional.absent();
83             }
84         }
85         return currentContainer;
86     }
87
88     private static Optional<DataNodeContainer> findNotification(final SchemaContext ctx, final QName notificationQName) {
89         for (NotificationDefinition notification : ctx.getNotifications()) {
90             if (notification.getQName().equals(notificationQName)) {
91                 return Optional.<DataNodeContainer> of(notification);
92             }
93         }
94         return Optional.absent();
95     }
96
97     private static Optional<DataNodeContainer> findDataNodeContainer(final DataNodeContainer ctx,
98             final QName targetQName) {
99
100         for (DataSchemaNode child : ctx.getChildNodes()) {
101             if (child instanceof ChoiceSchemaNode) {
102                 DataNodeContainer potential = findInCases(((ChoiceSchemaNode) child), targetQName);
103                 if (potential != null) {
104                     return Optional.of(potential);
105                 }
106             } else if (child instanceof DataNodeContainer && child.getQName().equals(targetQName)) {
107                 return Optional.of((DataNodeContainer) child);
108             } else if (child instanceof DataNodeContainer //
109                     && child.isAddedByUses() //
110                     && child.getQName().getLocalName().equals(targetQName.getLocalName())) {
111                 return Optional.of((DataNodeContainer) child);
112             }
113
114         }
115         return Optional.absent();
116     }
117
118     private static DataNodeContainer findInCases(final ChoiceSchemaNode choiceNode, final QName targetQName) {
119         for (ChoiceCaseNode caze : choiceNode.getCases()) {
120             Optional<DataNodeContainer> potential = findDataNodeContainer(caze, targetQName);
121             if (potential.isPresent()) {
122                 return potential.get();
123             }
124         }
125         return null;
126     }
127
128     private static Optional<DataNodeContainer> findFirstDataNodeContainerInRpc(final SchemaContext ctx,
129             final Class<? extends DataObject> targetType) {
130         final YangModuleInfo moduleInfo;
131         try {
132             moduleInfo = BindingReflections.getModuleInfo(targetType);
133         } catch (Exception e) {
134             throw new IllegalArgumentException(
135                     String.format("Failed to load module information for class %s", targetType), e);
136         }
137
138         for(RpcDefinition rpc : ctx.getOperations()) {
139             String rpcNamespace = rpc.getQName().getNamespace().toString();
140             String rpcRevision = rpc.getQName().getFormattedRevision();
141             if(moduleInfo.getNamespace().equals(rpcNamespace) && moduleInfo.getRevision().equals(rpcRevision)) {
142                 Optional<DataNodeContainer> potential = findInputOutput(rpc,targetType.getSimpleName());
143                 if(potential.isPresent()) {
144                     return potential;
145                 }
146             }
147         }
148         return Optional.absent();
149     }
150
151     private static Optional<DataNodeContainer> findInputOutput(final RpcDefinition rpc, final String targetType) {
152         String rpcName = BindingMapping.getClassName(rpc.getQName());
153         String rpcInputName = rpcName + BindingMapping.RPC_INPUT_SUFFIX;
154         String rpcOutputName = rpcName + BindingMapping.RPC_OUTPUT_SUFFIX;
155         if(targetType.equals(rpcInputName)) {
156             return Optional.<DataNodeContainer>of(rpc.getInput());
157         } else if (targetType.equals(rpcOutputName)) {
158             return Optional.<DataNodeContainer>of(rpc.getOutput());
159         }
160        return Optional.absent();
161     }
162
163     public static Set<AugmentationSchema> collectAllAugmentationDefinitions(final SchemaContext currentSchema, final AugmentationTarget ctxNode) {
164         HashSet<AugmentationSchema> augmentations = new HashSet<>();
165         augmentations.addAll(ctxNode.getAvailableAugmentations());
166         if(ctxNode instanceof DataSchemaNode && ((DataSchemaNode) ctxNode).isAddedByUses()) {
167
168             System.out.println(ctxNode);
169
170         }
171
172         return augmentations;
173     }
174
175     public static Optional<ChoiceSchemaNode> findInstantiatedChoice(final DataNodeContainer parent, final Class<?> choiceClass) {
176         return findInstantiatedChoice(parent, BindingReflections.findQName(choiceClass));
177     }
178
179     public static Optional<ChoiceSchemaNode> findInstantiatedChoice(final DataNodeContainer ctxNode, final QName choiceName) {
180         DataSchemaNode potential = ctxNode.getDataChildByName(choiceName);
181         if (potential instanceof ChoiceSchemaNode) {
182             return Optional.of((ChoiceSchemaNode) potential);
183         }
184
185         return Optional.absent();
186     }
187
188     public static Optional<ChoiceCaseNode> findInstantiatedCase(final ChoiceSchemaNode instantiatedChoice, final ChoiceCaseNode originalDefinition) {
189         ChoiceCaseNode potential = instantiatedChoice.getCaseNodeByName(originalDefinition.getQName());
190         if(originalDefinition.equals(potential)) {
191             return Optional.of(potential);
192         }
193         if (potential != null) {
194             SchemaNode potentialRoot = SchemaNodeUtils.getRootOriginalIfPossible(potential);
195             if (originalDefinition.equals(potentialRoot)) {
196                 return Optional.of(potential);
197             }
198         }
199         // We try to find case by name, then lookup its root definition
200         // and compare it with original definition
201         // This solves case, if choice was inside grouping
202         // which was used in different module and thus namespaces are
203         // different, but local names are still same.
204         //
205         // Still we need to check equality of definition, because local name is not
206         // sufficient to uniquelly determine equality of cases
207         //
208         potential = instantiatedChoice.getCaseNodeByName(originalDefinition.getQName().getLocalName());
209         if(potential != null && (originalDefinition.equals(SchemaNodeUtils.getRootOriginalIfPossible(potential)))) {
210             return Optional.of(potential);
211         }
212         return Optional.absent();
213     }
214
215 }