2 * Copyright (c) 2014, 2015 Cisco Systems, Inc. and others. All rights reserved.
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
8 package org.opendaylight.mdsal.binding.generator.impl;
10 import com.google.common.base.Preconditions;
11 import java.util.HashSet;
12 import java.util.Iterator;
13 import java.util.Optional;
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.opendaylight.yangtools.yang.model.api.SchemaNode;
34 import org.opendaylight.yangtools.yang.model.util.SchemaNodeUtils;
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
38 public final class BindingSchemaContextUtils {
39 private static final Logger LOG = LoggerFactory.getLogger(BindingSchemaContextUtils.class);
41 private BindingSchemaContextUtils() {
42 throw new UnsupportedOperationException("Utility class should not be instantiated");
45 // FIXME: This method does not search in case augmentations.
46 public static Optional<DataNodeContainer> findDataNodeContainer(final SchemaContext ctx,
47 final InstanceIdentifier<?> path) {
48 Iterator<PathArgument> pathArguments = path.getPathArguments().iterator();
49 PathArgument currentArg = pathArguments.next();
50 Preconditions.checkArgument(currentArg != null);
51 QName currentQName = BindingReflections.findQName(currentArg.getType());
53 Optional<DataNodeContainer> currentContainer = Optional.empty();
54 if (BindingReflections.isNotification(currentArg.getType())) {
55 currentContainer = findNotification(ctx, currentQName);
56 } else if (BindingReflections.isRpcType(currentArg.getType())) {
57 currentContainer = findFirstDataNodeContainerInRpc(ctx, currentArg.getType());
58 if (currentQName == null && currentContainer.isPresent()) {
59 currentQName = ((DataSchemaNode) currentContainer.get()).getQName();
62 currentContainer = findDataNodeContainer(ctx, currentQName);
65 while (currentContainer.isPresent() && pathArguments.hasNext()) {
66 currentArg = pathArguments.next();
67 if (Augmentation.class.isAssignableFrom(currentArg.getType())) {
68 currentQName = BindingReflections.findQName(currentArg.getType());
69 if (pathArguments.hasNext()) {
70 currentArg = pathArguments.next();
72 return currentContainer;
75 if (ChildOf.class.isAssignableFrom(currentArg.getType())
76 && BindingReflections.isAugmentationChild(currentArg.getType())) {
77 currentQName = BindingReflections.findQName(currentArg.getType());
79 currentQName = BindingReflections.findQName(currentArg.getType()).withModule(currentQName.getModule());
81 Optional<DataNodeContainer> potential = findDataNodeContainer(currentContainer.get(), currentQName);
82 if (potential.isPresent()) {
83 currentContainer = potential;
85 return Optional.empty();
88 return currentContainer;
91 private static Optional<DataNodeContainer> findDataNodeContainer(final DataNodeContainer ctx,
92 final QName targetQName) {
94 for (DataSchemaNode child : ctx.getChildNodes()) {
95 if (child instanceof ChoiceSchemaNode) {
96 DataNodeContainer potential = findInCases((ChoiceSchemaNode) child, targetQName);
97 if (potential != null) {
98 return Optional.of(potential);
100 } else if (child instanceof DataNodeContainer) {
101 final QName qname = child.getQName();
102 if (qname.equals(targetQName)
103 || child.isAddedByUses() && qname.getLocalName().equals(targetQName.getLocalName())) {
104 return Optional.of((DataNodeContainer) child);
109 return Optional.empty();
112 private static Optional<DataNodeContainer> findNotification(final SchemaContext ctx,
113 final QName notificationQName) {
114 for (NotificationDefinition notification : ctx.getNotifications()) {
115 if (notification.getQName().equals(notificationQName)) {
116 return Optional.of(notification);
119 return Optional.empty();
122 private static DataNodeContainer findInCases(final ChoiceSchemaNode choiceNode, final QName targetQName) {
123 for (CaseSchemaNode caze : choiceNode.getCases().values()) {
124 Optional<DataNodeContainer> potential = findDataNodeContainer(caze, targetQName);
125 if (potential.isPresent()) {
126 return potential.get();
132 @SuppressWarnings("checkstyle:illegalCatch")
133 private static Optional<DataNodeContainer> findFirstDataNodeContainerInRpc(final SchemaContext ctx,
134 final Class<? extends DataObject> targetType) {
135 final QNameModule targetModule;
137 targetModule = BindingReflections.getModuleInfo(targetType).getName().getModule();
138 } catch (Exception e) {
139 throw new IllegalArgumentException(
140 String.format("Failed to load module information for class %s", targetType), e);
143 for (RpcDefinition rpc : ctx.getOperations()) {
144 if (targetModule.equals(rpc.getQName().getModule())) {
145 final Optional<DataNodeContainer> potential = findInputOutput(rpc,targetType.getSimpleName());
146 if (potential.isPresent()) {
151 return Optional.empty();
154 private static Optional<DataNodeContainer> findInputOutput(final RpcDefinition rpc, final String targetType) {
155 final String rpcName = BindingMapping.getClassName(rpc.getQName());
156 final String rpcInputName = rpcName + BindingMapping.RPC_INPUT_SUFFIX;
157 if (targetType.equals(rpcInputName)) {
158 return Optional.of(rpc.getInput());
160 final String rpcOutputName = rpcName + BindingMapping.RPC_OUTPUT_SUFFIX;
161 if (targetType.equals(rpcOutputName)) {
162 return Optional.of(rpc.getOutput());
164 return Optional.empty();
167 public static Set<AugmentationSchemaNode> collectAllAugmentationDefinitions(final SchemaContext currentSchema,
168 final AugmentationTarget ctxNode) {
169 HashSet<AugmentationSchemaNode> augmentations = new HashSet<>();
170 augmentations.addAll(ctxNode.getAvailableAugmentations());
171 if (ctxNode instanceof DataSchemaNode && ((DataSchemaNode) ctxNode).isAddedByUses()) {
172 LOG.info("DataSchemaNode target added by uses {}", ctxNode);
175 return augmentations;
178 public static Optional<ChoiceSchemaNode> findInstantiatedChoice(final DataNodeContainer parent,
179 final Class<?> choiceClass) {
180 return findInstantiatedChoice(parent, BindingReflections.findQName(choiceClass));
183 public static Optional<ChoiceSchemaNode> findInstantiatedChoice(final DataNodeContainer ctxNode,
184 final QName choiceName) {
185 DataSchemaNode potential = ctxNode.getDataChildByName(choiceName);
186 if (potential instanceof ChoiceSchemaNode) {
187 return Optional.of((ChoiceSchemaNode) potential);
190 return Optional.empty();
193 public static Optional<CaseSchemaNode> findInstantiatedCase(final ChoiceSchemaNode instantiatedChoice,
194 final CaseSchemaNode originalDefinition) {
195 CaseSchemaNode potential = instantiatedChoice.getCaseNodeByName(originalDefinition.getQName());
196 if (originalDefinition.equals(potential)) {
197 return Optional.of(potential);
199 if (potential != null) {
200 SchemaNode potentialRoot = SchemaNodeUtils.getRootOriginalIfPossible(potential);
201 if (originalDefinition.equals(potentialRoot)) {
202 return Optional.of(potential);
206 // We try to find case by name, then lookup its root definition
207 // and compare it with original definition
208 // This solves case, if choice was inside grouping
209 // which was used in different module and thus namespaces are
210 // different, but local names are still same.
212 // Still we need to check equality of definition, because local name is not
213 // sufficient to uniquelly determine equality of cases
215 for (CaseSchemaNode caze : instantiatedChoice.findCaseNodes(originalDefinition.getQName().getLocalName())) {
216 if (originalDefinition.equals(SchemaNodeUtils.getRootOriginalIfPossible(caze))) {
217 return Optional.of(caze);
220 return Optional.empty();