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.");
254 GeneratedTypeBuilder parentType = genCtx.get(module).getChildNode(parent.getPath());
255 checkState(parentType != null, "Parent generated type for " + parent
256 + " data schema node must have been generated already");
257 annotateDeprecatedIfNecessary(parent.getStatus(), parentType);
259 if (parent instanceof ListSchemaNode) {
261 GeneratedTransferObject keyType = null;
262 for (MethodSignatureBuilder method : parentType.getMethodDefinitions()) {
263 if (method.getName().equals("getIdentifier")) {
264 keyType = (GeneratedTransferObject) method.toInstance(parentType).getReturnType();
268 operationMethod.addParameter(parameterizedTypeFor(KEYED_INSTANCE_IDENTIFIER, parentType, keyType),
270 interfaceBuilder.addImplementsType(parameterizedTypeFor(LIST_ACTION, parentType, keyType, inType,
274 operationMethod.addParameter(parameterizedTypeFor(INSTANCE_IDENTIFIER, parentType), "ii");
275 interfaceBuilder.addImplementsType(parameterizedTypeFor(ACTION, parentType,
276 parameterizedTypeFor(INSTANCE_IDENTIFIER, parentType) ,inType, outType));
280 interfaceBuilder.addImplementsType(parameterizedTypeFor(RPC, inType, outType));
283 interfaceBuilder.addImplementsType(TREE_NODE);
284 operationMethod.addParameter(parameterizedTypeFor(RPC_CALLBACK, outType), "callback");
286 operationMethod.setComment(operationComment);
287 operationMethod.setReturnType(VOID);
289 return interfaceBuilder;
292 private static GeneratedTypeBuilder resolveOperationNode(final GeneratedTypeBuilder parent, final Module module, final
293 ContainerSchemaNode operationNode, final String basePackageName, final SchemaContext schemaContext, final String
294 operationName, final boolean verboseClassComments, final TypeProvider typeProvider, final Map<String, Map<String,
295 GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx, final boolean isInput,
296 final BindingNamespaceType namespaceType) {
297 final GeneratedTypeBuilder nodeType = addRawInterfaceDefinition(basePackageName, operationNode, schemaContext,
298 operationName, "", verboseClassComments, genTypeBuilders, namespaceType, genCtx.get(module));
299 addImplementedInterfaceFromUses(operationNode, nodeType, genCtx);
300 nodeType.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
301 (BindingTypes.ITEM, nodeType)));
303 nodeType.addImplementsType(parameterizedTypeFor(INPUT, nodeType));
305 nodeType.addImplementsType(parameterizedTypeFor(OUTPUT, nodeType));
307 nodeType.addImplementsType(parameterizedTypeFor(INSTANTIABLE, nodeType));
308 nodeType.addImplementsType(augmentable(nodeType));
309 GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, nodeType, nodeType, operationNode.getChildNodes(), genCtx,
310 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
312 final MethodSignatureBuilder nodeMethod = nodeType.addMethod("implementedInterface");
313 nodeMethod.setReturnType(parameterizedTypeFor(CLASS, nodeType));
314 nodeMethod.addAnnotation("", "Override");
316 processUsesImplements(operationNode, module, schemaContext, genCtx, namespaceType);