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