Specialize ModuleInfoBackedContext for no fallback
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / mdsal / 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 package org.opendaylight.mdsal.binding.generator.impl;
9
10 import com.google.common.base.Preconditions;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.Optional;
14 import java.util.Set;
15 import org.opendaylight.mdsal.binding.spec.naming.BindingMapping;
16 import org.opendaylight.mdsal.binding.spec.reflect.BindingReflections;
17 import org.opendaylight.yangtools.yang.binding.Augmentation;
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.common.QName;
23 import org.opendaylight.yangtools.yang.common.QNameModule;
24 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
25 import org.opendaylight.yangtools.yang.model.api.AugmentationTarget;
26 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
27 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
28 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
29 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
30 import org.opendaylight.yangtools.yang.model.api.NotificationDefinition;
31 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
32 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
33 import org.slf4j.Logger;
34 import org.slf4j.LoggerFactory;
35
36 public final class BindingSchemaContextUtils {
37     private static final Logger LOG = LoggerFactory.getLogger(BindingSchemaContextUtils.class);
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.empty();
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())
74                     && BindingReflections.isAugmentationChild(currentArg.getType())) {
75                 currentQName = BindingReflections.findQName(currentArg.getType());
76             } else {
77                 currentQName = BindingReflections.findQName(currentArg.getType()).withModule(currentQName.getModule());
78             }
79             Optional<DataNodeContainer> potential = findDataNodeContainer(currentContainer.get(), currentQName);
80             if (potential.isPresent()) {
81                 currentContainer = potential;
82             } else {
83                 return Optional.empty();
84             }
85         }
86         return currentContainer;
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) {
99                 final QName qname = child.getQName();
100                 if (qname.equals(targetQName)
101                         || child.isAddedByUses() && qname.getLocalName().equals(targetQName.getLocalName())) {
102                     return Optional.of((DataNodeContainer) child);
103                 }
104             }
105
106         }
107         return Optional.empty();
108     }
109
110     private static Optional<DataNodeContainer> findNotification(final SchemaContext ctx,
111             final QName notificationQName) {
112         for (NotificationDefinition notification : ctx.getNotifications()) {
113             if (notification.getQName().equals(notificationQName)) {
114                 return Optional.of(notification);
115             }
116         }
117         return Optional.empty();
118     }
119
120     private static DataNodeContainer findInCases(final ChoiceSchemaNode choiceNode, final QName targetQName) {
121         for (CaseSchemaNode caze : choiceNode.getCases().values()) {
122             Optional<DataNodeContainer> potential = findDataNodeContainer(caze, targetQName);
123             if (potential.isPresent()) {
124                 return potential.get();
125             }
126         }
127         return null;
128     }
129
130     @SuppressWarnings("checkstyle:illegalCatch")
131     private static Optional<DataNodeContainer> findFirstDataNodeContainerInRpc(final SchemaContext ctx,
132             final Class<? extends DataObject> targetType) {
133         final QNameModule targetModule;
134         try {
135             targetModule = BindingReflections.getModuleInfo(targetType).getName().getModule();
136         } catch (Exception e) {
137             throw new IllegalArgumentException(
138                     String.format("Failed to load module information for class %s", targetType), e);
139         }
140
141         for (RpcDefinition rpc : ctx.getOperations()) {
142             if (targetModule.equals(rpc.getQName().getModule())) {
143                 final Optional<DataNodeContainer> potential = findInputOutput(rpc,targetType.getSimpleName());
144                 if (potential.isPresent()) {
145                     return potential;
146                 }
147             }
148         }
149         return Optional.empty();
150     }
151
152     private static Optional<DataNodeContainer> findInputOutput(final RpcDefinition rpc, final String targetType) {
153         final String rpcName = BindingMapping.getClassName(rpc.getQName());
154         final String rpcInputName = rpcName + BindingMapping.RPC_INPUT_SUFFIX;
155         if (targetType.equals(rpcInputName)) {
156             return Optional.of(rpc.getInput());
157         }
158         final String rpcOutputName = rpcName + BindingMapping.RPC_OUTPUT_SUFFIX;
159         if (targetType.equals(rpcOutputName)) {
160             return Optional.of(rpc.getOutput());
161         }
162         return Optional.empty();
163     }
164
165     public static Set<AugmentationSchemaNode> collectAllAugmentationDefinitions(final SchemaContext currentSchema,
166             final AugmentationTarget ctxNode) {
167         HashSet<AugmentationSchemaNode> augmentations = new HashSet<>();
168         augmentations.addAll(ctxNode.getAvailableAugmentations());
169         if (ctxNode instanceof DataSchemaNode && ((DataSchemaNode) ctxNode).isAddedByUses()) {
170             LOG.info("DataSchemaNode target added by uses {}", ctxNode);
171         }
172
173         return augmentations;
174     }
175
176     public static Optional<ChoiceSchemaNode> findInstantiatedChoice(final DataNodeContainer parent,
177             final Class<?> choiceClass) {
178         return findInstantiatedChoice(parent, BindingReflections.findQName(choiceClass));
179     }
180
181     public static Optional<ChoiceSchemaNode> findInstantiatedChoice(final DataNodeContainer ctxNode,
182             final QName choiceName) {
183         DataSchemaNode potential = ctxNode.getDataChildByName(choiceName);
184         if (potential instanceof ChoiceSchemaNode) {
185             return Optional.of((ChoiceSchemaNode) potential);
186         }
187
188         return Optional.empty();
189     }
190 }