2 * Copyright (c) 2017 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
9 package org.opendaylight.mdsal.binding.javav2.generator.impl;
11 import static com.google.common.base.Preconditions.checkState;
12 import static java.util.Objects.requireNonNull;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.checkModuleAndModuleName;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.addImplementedInterfaceFromUses;
16 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.addRawInterfaceDefinition;
17 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.moduleTypeBuilder;
18 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.processUsesImplements;
19 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.resolveDataSchemaNodesCheck;
20 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
21 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.ACTION;
22 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.INPUT;
23 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.INSTANCE_IDENTIFIER;
24 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.INSTANTIABLE;
25 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.KEYED_INSTANCE_IDENTIFIER;
26 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.LIST_ACTION;
27 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.OUTPUT;
28 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.RPC;
29 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.RPC_CALLBACK;
30 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.TREE_NODE;
31 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.augmentable;
32 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.CLASS;
33 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.VOID;
34 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor;
36 import com.google.common.annotations.Beta;
37 import com.google.common.annotations.VisibleForTesting;
38 import com.google.common.base.Preconditions;
39 import java.util.Collection;
41 import java.util.Optional;
43 import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
44 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
45 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
46 import org.opendaylight.mdsal.binding.javav2.generator.util.TypeComments;
47 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
48 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
49 import org.opendaylight.mdsal.binding.javav2.model.api.YangSourceDefinition;
50 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
51 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder;
52 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
53 import org.opendaylight.yangtools.yang.common.QName;
54 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
55 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
56 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
57 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
58 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
59 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
60 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
61 import org.opendaylight.yangtools.yang.model.api.Module;
62 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
63 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
64 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
65 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
68 * Util class used for generation of types for RPCs, routedRPCs and Actions (YANG 1.1 only)
69 * in Binding spec. v2. In case of routed RPC detected in input YANG, RPC is turned to Action.
72 final class RpcActionGenHelper {
74 static final QName CONTEXT_REFERENCE =
75 QName.create("urn:opendaylight:yang:extension:yang-ext", "2013-07-09", "context-reference").intern();
77 private RpcActionGenHelper() {
78 throw new UnsupportedOperationException("Util class");
82 * Let's find out what context we are talking about
86 * In 1st case, we need Binding Generator behave like YANG 1.1 Action
88 * @param schemaNode RPC input node
89 * @return presence optional
92 static Optional<QName> getRoutingContext(final DataSchemaNode schemaNode) {
93 for (UnknownSchemaNode extension : schemaNode.getUnknownSchemaNodes()) {
94 if (CONTEXT_REFERENCE.equals(extension.getNodeType())) {
95 return Optional.ofNullable(extension.getQName());
98 return Optional.empty();
101 private static void resolveActions(final DataNodeContainer parent, final Module module,
102 final SchemaContext schemaContext, final boolean verboseClassComments,
103 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
104 final TypeProvider typeProvider, final BindingNamespaceType namespaceType) {
105 Preconditions.checkNotNull(parent, "Parent should not be NULL.");
106 final Collection<DataSchemaNode> potentials = parent.getChildNodes();
107 for (DataSchemaNode potential : potentials) {
108 if (resolveDataSchemaNodesCheck(module, schemaContext,potential)) {
109 BindingNamespaceType namespaceType1 = namespaceType;
110 if (namespaceType.equals(BindingNamespaceType.Data)) {
111 if (potential instanceof GroupingDefinition) {
112 namespaceType1 = BindingNamespaceType.Grouping;
116 if (potential instanceof ActionNodeContainer) {
117 final Set<ActionDefinition> actions = ((ActionNodeContainer) potential).getActions();
118 for (ActionDefinition action : actions) {
119 final GeneratedTypeBuilder typeBuilder = resolveOperation(potential, action, module,
120 schemaContext, verboseClassComments, genTypeBuilders, genCtx, typeProvider, true,
122 genCtx.get(module).addTopLevelNodeType(typeBuilder);
123 genCtx.get(module).addTypeToSchema(typeBuilder, action);
127 if (potential instanceof DataNodeContainer) {
128 resolveActions((DataNodeContainer) potential, module, schemaContext, verboseClassComments,
129 genTypeBuilders, genCtx, typeProvider, namespaceType1);
136 * Converts Yang 1.1 <b>Actions</b> to list of <code>Type</code> objects.
137 * @param module module from which is obtained set of all Action objects to
139 * @param genCtx input, generated context
140 * @param verboseClassComments verbosity switch
141 * @return generated context
143 static Map<Module, ModuleContext> actionMethodsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
144 final SchemaContext schemaContext, final boolean verboseClassComments,
145 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
147 checkModuleAndModuleName(module);
148 resolveActions(module, module, schemaContext, verboseClassComments, genTypeBuilders, genCtx, typeProvider,
149 BindingNamespaceType.Data);
154 * Converts global <b>RPCs</b> inputs and outputs sub-statements of the module
155 * to the list of <code>Type</code> objects. In addition, containers
156 * and lists which belong to input or output are also part of returning list.
157 * Detected routed RPCs are turned to Yang 1.1 Actions
160 * module from which is obtained set of all RPC objects to
162 * @param genCtx input, generated context
163 * @param verboseClassComments verbosity switch
165 * @throws IllegalArgumentException
167 * <li>if the module is null</li>
168 * <li>if the name of module is null</li>
170 * @throws IllegalStateException
171 * if set of RPCs from module is null
173 * @return generated context
175 static Map<Module, ModuleContext> rpcMethodsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
176 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String,
177 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
179 checkModuleAndModuleName(module);
180 final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
181 checkState(rpcDefinitions != null, "Set of RPCs from module " + module.getName() + " cannot be NULL.");
182 if (rpcDefinitions.isEmpty()) {
186 for (final RpcDefinition rpc : rpcDefinitions) {
187 final GeneratedTypeBuilder typeBuilder = resolveOperation(null, rpc, module, schemaContext,
188 verboseClassComments, genTypeBuilders, genCtx, typeProvider, false,
189 BindingNamespaceType.Data);
190 genCtx.get(module).addTopLevelNodeType(typeBuilder);
191 genCtx.get(module).addTypeToSchema(typeBuilder, rpc);
198 * Converts RPC, Action or routed RPC into generated type
199 * @return generated type
201 private static GeneratedTypeBuilder resolveOperation(final DataSchemaNode parent, final OperationDefinition operation,
202 final Module module, final SchemaContext schemaContext, final boolean verboseClassComments,
203 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
204 final TypeProvider typeProvider, final boolean isAction, final BindingNamespaceType namespaceType) {
207 final String operationName = operation.getQName().getLocalName();
208 //concrete operation name
209 final StringBuilder sb = new StringBuilder(operationName).append('_');
215 final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, sb.toString(),
216 verboseClassComments, genCtx.get(module));
218 final String basePackageName = interfaceBuilder.getPackageName();
220 if (verboseClassComments) {
221 interfaceBuilder.addComment(TypeComments.javadoc(
222 "Interface for implementing the following YANG Operation defined in module <b>" + module.getName() + "</b>")
224 YangSourceDefinition.of(module, operation).ifPresent(interfaceBuilder::setYangSourceDefinition);
227 final String operationComment = encodeAngleBrackets(operation.getDescription().orElse(null));
228 final MethodSignatureBuilder operationMethod = interfaceBuilder.addMethod("invoke");
231 final ContainerSchemaNode input = operation.getInput();
232 final GeneratedTypeBuilder inType = resolveOperationNode(interfaceBuilder, module, operation.getInput(),
233 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders,
234 genCtx, true, namespaceType);
235 annotateDeprecatedIfNecessary(operation.getStatus(), inType);
236 inType.setParentTypeForBuilder(interfaceBuilder);
237 genCtx.get(module).addChildNodeType(input, inType);
240 final ContainerSchemaNode output = operation.getOutput();
241 final GeneratedTypeBuilder outType = resolveOperationNode(interfaceBuilder, module, operation.getOutput(),
242 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders,
243 genCtx, false, namespaceType);
244 annotateDeprecatedIfNecessary(operation.getStatus(), outType);
245 outType.setParentTypeForBuilder(interfaceBuilder);
246 genCtx.get(module).addChildNodeType(output, outType);
248 final GeneratedType inTypeInstance = inType.toInstance();
249 operationMethod.addParameter(inTypeInstance, "input");
252 requireNonNull(parent, "Parent must be specified for action.");
253 GeneratedTypeBuilder parentType = genCtx.get(module).getChildNode(parent.getPath());
254 checkState(parentType != null, "Parent generated type for " + parent
255 + " data schema node must have been generated already");
256 annotateDeprecatedIfNecessary(parent.getStatus(), parentType);
258 if (parent instanceof ListSchemaNode) {
260 GeneratedTransferObject keyType = null;
261 for (MethodSignatureBuilder method : parentType.getMethodDefinitions()) {
262 if (method.getName().equals("getKey")) {
263 keyType = (GeneratedTransferObject) method.toInstance(parentType).getReturnType();
267 operationMethod.addParameter(
268 parameterizedTypeFor(KEYED_INSTANCE_IDENTIFIER, parentType, keyType), "kii");
269 interfaceBuilder.addImplementsType(parameterizedTypeFor(LIST_ACTION, parentType, inType, outType));
272 operationMethod.addParameter(parameterizedTypeFor(INSTANCE_IDENTIFIER, parentType), "ii");
273 interfaceBuilder.addImplementsType(parameterizedTypeFor(ACTION, parentType, inType, outType));
277 interfaceBuilder.addImplementsType(parameterizedTypeFor(RPC, inType, outType));
280 interfaceBuilder.addImplementsType(TREE_NODE);
281 operationMethod.addParameter(parameterizedTypeFor(RPC_CALLBACK, outType), "callback");
283 operationMethod.setComment(operationComment);
284 operationMethod.setReturnType(VOID);
286 return interfaceBuilder;
289 private static GeneratedTypeBuilder resolveOperationNode(final GeneratedTypeBuilder parent, final Module module, final
290 ContainerSchemaNode operationNode, final String basePackageName, final SchemaContext schemaContext, final String
291 operationName, final boolean verboseClassComments, final TypeProvider typeProvider, final Map<String, Map<String,
292 GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx, final boolean isInput,
293 final BindingNamespaceType namespaceType) {
294 final GeneratedTypeBuilder nodeType = addRawInterfaceDefinition(basePackageName, operationNode, schemaContext,
295 operationName, "", verboseClassComments, genTypeBuilders, namespaceType, genCtx.get(module));
296 addImplementedInterfaceFromUses(operationNode, nodeType, genCtx);
297 nodeType.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
298 (BindingTypes.ITEM, nodeType)));
300 nodeType.addImplementsType(parameterizedTypeFor(INPUT, nodeType));
302 nodeType.addImplementsType(parameterizedTypeFor(OUTPUT, nodeType));
304 nodeType.addImplementsType(parameterizedTypeFor(INSTANTIABLE, nodeType));
305 nodeType.addImplementsType(augmentable(nodeType));
306 GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, nodeType, nodeType, operationNode.getChildNodes(), genCtx,
307 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
309 final MethodSignatureBuilder nodeMethod = nodeType.addMethod("implementedInterface");
310 nodeMethod.setReturnType(parameterizedTypeFor(CLASS, nodeType));
311 nodeMethod.addAnnotation("", "Override");
313 processUsesImplements(operationNode, module, schemaContext, genCtx, namespaceType);