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