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 org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.annotateDeprecatedIfNecessary;
13 import static org.opendaylight.mdsal.binding.javav2.generator.impl.AuxiliaryGenUtils.checkModuleAndModuleName;
14 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.addImplementedInterfaceFromUses;
15 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.addRawInterfaceDefinition;
16 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.moduleTypeBuilder;
17 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.processUsesImplements;
18 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.resolveDataSchemaNodesCheck;
19 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil.encodeAngleBrackets;
20 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.ACTION;
21 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.INPUT;
22 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.INSTANCE_IDENTIFIER;
23 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.INSTANTIABLE;
24 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.KEYED_INSTANCE_IDENTIFIER;
25 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.LIST_ACTION;
26 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.OUTPUT;
27 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.RPC;
28 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.RPC_CALLBACK;
29 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.TREE_NODE;
30 import static org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes.augmentable;
31 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.CLASS;
32 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.VOID;
33 import static org.opendaylight.mdsal.binding.javav2.generator.util.Types.parameterizedTypeFor;
35 import com.google.common.annotations.Beta;
36 import com.google.common.annotations.VisibleForTesting;
37 import com.google.common.base.Preconditions;
38 import java.util.Collection;
40 import java.util.Optional;
42 import org.opendaylight.mdsal.binding.javav2.generator.context.ModuleContext;
43 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
44 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
45 import org.opendaylight.mdsal.binding.javav2.generator.util.TypeComments;
46 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
47 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
48 import org.opendaylight.mdsal.binding.javav2.model.api.YangSourceDefinition;
49 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
50 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder;
51 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
52 import org.opendaylight.yangtools.yang.common.QName;
53 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
54 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
55 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
56 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
57 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
58 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
59 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
60 import org.opendaylight.yangtools.yang.model.api.Module;
61 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
62 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
63 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
64 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
67 * Util class used for generation of types for RPCs, routedRPCs and Actions (YANG 1.1 only)
68 * in Binding spec. v2. In case of routed RPC detected in input YANG, RPC is turned to Action.
71 final class RpcActionGenHelper {
73 static final QName CONTEXT_REFERENCE =
74 QName.create("urn:opendaylight:yang:extension:yang-ext", "2013-07-09", "context-reference").intern();
76 private RpcActionGenHelper() {
77 throw new UnsupportedOperationException("Util class");
81 * Let's find out what context we are talking about
85 * In 1st case, we need Binding Generator behave like YANG 1.1 Action
87 * @param schemaNode RPC input node
88 * @return presence optional
91 static Optional<QName> getRoutingContext(final DataSchemaNode schemaNode) {
92 for (UnknownSchemaNode extension : schemaNode.getUnknownSchemaNodes()) {
93 if (CONTEXT_REFERENCE.equals(extension.getNodeType())) {
94 return Optional.ofNullable(extension.getQName());
97 return Optional.empty();
100 private static void resolveActions(final DataNodeContainer parent, final Module module,
101 final SchemaContext schemaContext, final boolean verboseClassComments,
102 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
103 final TypeProvider typeProvider, final BindingNamespaceType namespaceType) {
104 Preconditions.checkNotNull(parent, "Parent should not be NULL.");
105 final Collection<DataSchemaNode> potentials = parent.getChildNodes();
106 for (DataSchemaNode potential : potentials) {
107 if (resolveDataSchemaNodesCheck(module, schemaContext,potential)) {
108 BindingNamespaceType namespaceType1 = namespaceType;
109 if (namespaceType.equals(BindingNamespaceType.Data)) {
110 if (potential instanceof GroupingDefinition) {
111 namespaceType1 = BindingNamespaceType.Grouping;
115 if (potential instanceof ActionNodeContainer) {
116 final Set<ActionDefinition> actions = ((ActionNodeContainer) potential).getActions();
117 for (ActionDefinition action : actions) {
118 genCtx.get(module).addTopLevelNodeType(resolveOperation(potential, action, module,
119 schemaContext, verboseClassComments, genTypeBuilders, genCtx, typeProvider, true,
124 if (potential instanceof DataNodeContainer) {
125 resolveActions((DataNodeContainer) potential, module, schemaContext, verboseClassComments,
126 genTypeBuilders, genCtx, typeProvider, namespaceType1);
133 * Converts Yang 1.1 <b>Actions</b> to list of <code>Type</code> objects.
134 * @param module module from which is obtained set of all Action objects to
136 * @param genCtx input, generated context
137 * @param verboseClassComments verbosity switch
138 * @return generated context
140 static Map<Module, ModuleContext> actionMethodsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
141 final SchemaContext schemaContext, final boolean verboseClassComments,
142 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
144 checkModuleAndModuleName(module);
145 resolveActions(module, module, schemaContext, verboseClassComments, genTypeBuilders, genCtx, typeProvider,
146 BindingNamespaceType.Data);
151 * Converts global <b>RPCs</b> inputs and outputs sub-statements of the module
152 * to the list of <code>Type</code> objects. In addition, containers
153 * and lists which belong to input or output are also part of returning list.
154 * Detected routed RPCs are turned to Yang 1.1 Actions
157 * module from which is obtained set of all RPC objects to
159 * @param genCtx input, generated context
160 * @param verboseClassComments verbosity switch
162 * @throws IllegalArgumentException
164 * <li>if the module is null</li>
165 * <li>if the name of module is null</li>
167 * @throws IllegalStateException
168 * if set of RPCs from module is null
170 * @return generated context
172 static Map<Module, ModuleContext> rpcMethodsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
173 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String,
174 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
176 checkModuleAndModuleName(module);
177 final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
178 checkState(rpcDefinitions != null, "Set of RPCs from module " + module.getName() + " cannot be NULL.");
179 if (rpcDefinitions.isEmpty()) {
183 for (final RpcDefinition rpc : rpcDefinitions) {
184 //FIXME: get correct parent for routed RPCs only
185 DataSchemaNode parent = null;
187 ContainerSchemaNode input = rpc.getInput();
188 boolean isAction = false;
190 for (DataSchemaNode schemaNode : input.getChildNodes()) {
191 if (getRoutingContext(schemaNode).isPresent()) {
200 genCtx.get(module).addTopLevelNodeType(resolveOperation(parent, rpc, module, schemaContext,
201 verboseClassComments, genTypeBuilders, genCtx, typeProvider, true,
202 BindingNamespaceType.Data));
205 genCtx.get(module).addTopLevelNodeType(resolveOperation(parent, rpc, module, schemaContext,
206 verboseClassComments, genTypeBuilders, genCtx, typeProvider, false,
207 BindingNamespaceType.Data));
215 * Converts RPC, Action or routed RPC into generated type
216 * @return generated type
218 private static GeneratedTypeBuilder resolveOperation(final DataSchemaNode parent, final OperationDefinition operation,
219 final Module module, final SchemaContext schemaContext, final boolean verboseClassComments,
220 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
221 final TypeProvider typeProvider, final boolean isAction, final BindingNamespaceType namespaceType) {
224 final String operationName = operation.getQName().getLocalName();
225 //concrete operation name
226 final StringBuilder sb = new StringBuilder(operationName).append('_');
232 final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, sb.toString(),
233 verboseClassComments, genCtx.get(module));
235 final String basePackageName = interfaceBuilder.getPackageName();
237 if (verboseClassComments) {
238 interfaceBuilder.addComment(TypeComments.javadoc(
239 "Interface for implementing the following YANG Operation defined in module <b>" + module.getName() + "</b>")
241 YangSourceDefinition.of(module, operation).ifPresent(interfaceBuilder::setYangSourceDefinition);
244 final String operationComment = encodeAngleBrackets(operation.getDescription().orElse(null));
245 final MethodSignatureBuilder operationMethod = interfaceBuilder.addMethod("invoke");
248 final ContainerSchemaNode input = operation.getInput();
249 final GeneratedTypeBuilder inType = resolveOperationNode(interfaceBuilder, module, operation.getInput(),
250 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders,
251 genCtx, true, namespaceType);
252 annotateDeprecatedIfNecessary(operation.getStatus(), inType);
253 inType.setParentTypeForBuilder(interfaceBuilder);
254 genCtx.get(module).addChildNodeType(input, inType);
257 final ContainerSchemaNode output = operation.getOutput();
258 final GeneratedTypeBuilder outType = resolveOperationNode(interfaceBuilder, module, operation.getOutput(),
259 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders,
260 genCtx, false, namespaceType);
261 annotateDeprecatedIfNecessary(operation.getStatus(), outType);
262 outType.setParentTypeForBuilder(interfaceBuilder);
263 genCtx.get(module).addChildNodeType(output, outType);
265 final GeneratedType inTypeInstance = inType.toInstance();
266 operationMethod.addParameter(inTypeInstance, "input");
269 if (parent != null) {
271 GeneratedTypeBuilder parentType = genCtx.get(module).getChildNode(parent.getPath());
272 checkState(parentType != null, "Parent generated type for " + parent
273 + " data schema node must have been generated already");
274 annotateDeprecatedIfNecessary(parent.getStatus(), parentType);
276 if (parent instanceof ListSchemaNode) {
278 GeneratedTransferObject keyType = null;
279 for (MethodSignatureBuilder method : parentType.getMethodDefinitions()) {
280 if (method.getName().equals("getKey")) {
281 keyType = (GeneratedTransferObject) method.toInstance(parentType).getReturnType();
285 operationMethod.addParameter(
286 parameterizedTypeFor(KEYED_INSTANCE_IDENTIFIER, parentType, keyType), "kii");
287 interfaceBuilder.addImplementsType(parameterizedTypeFor(LIST_ACTION, parentType, inType, outType));
290 operationMethod.addParameter(parameterizedTypeFor(INSTANCE_IDENTIFIER, parentType), "ii");
291 interfaceBuilder.addImplementsType(parameterizedTypeFor(ACTION, parentType, inType, outType));
295 throw new UnsupportedOperationException("Not implemented yet.");
299 interfaceBuilder.addImplementsType(parameterizedTypeFor(RPC, inType, outType));
302 interfaceBuilder.addImplementsType(TREE_NODE);
303 operationMethod.addParameter(parameterizedTypeFor(RPC_CALLBACK, outType), "callback");
305 operationMethod.setComment(operationComment);
306 operationMethod.setReturnType(VOID);
308 return interfaceBuilder;
311 private static GeneratedTypeBuilder resolveOperationNode(final GeneratedTypeBuilder parent, final Module module, final
312 ContainerSchemaNode operationNode, final String basePackageName, final SchemaContext schemaContext, final String
313 operationName, final boolean verboseClassComments, final TypeProvider typeProvider, final Map<String, Map<String,
314 GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx, final boolean isInput,
315 final BindingNamespaceType namespaceType) {
316 final GeneratedTypeBuilder nodeType = addRawInterfaceDefinition(basePackageName, operationNode, schemaContext,
317 operationName, "", verboseClassComments, genTypeBuilders, namespaceType, genCtx.get(module));
318 addImplementedInterfaceFromUses(operationNode, nodeType, genCtx);
319 nodeType.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
320 (BindingTypes.ITEM, nodeType)));
322 nodeType.addImplementsType(parameterizedTypeFor(INPUT, nodeType));
324 nodeType.addImplementsType(parameterizedTypeFor(OUTPUT, nodeType));
326 nodeType.addImplementsType(parameterizedTypeFor(INSTANTIABLE, nodeType));
327 nodeType.addImplementsType(augmentable(nodeType));
328 GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, nodeType, nodeType, operationNode.getChildNodes(), genCtx,
329 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
331 final MethodSignatureBuilder nodeMethod = nodeType.addMethod("implementedInterface");
332 nodeMethod.setReturnType(parameterizedTypeFor(CLASS, nodeType));
333 nodeMethod.addAnnotation("", "Override");
335 processUsesImplements(operationNode, module, schemaContext, genCtx, namespaceType);