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.AuxiliaryGenUtils.createDescription;
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.Optional;
39 import com.google.common.base.Preconditions;
40 import java.util.Collection;
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.model.api.GeneratedTransferObject;
47 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
48 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
49 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder;
50 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
51 import org.opendaylight.yangtools.yang.common.QName;
52 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
53 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
54 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
55 import org.opendaylight.yangtools.yang.model.api.DataNodeContainer;
56 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
57 import org.opendaylight.yangtools.yang.model.api.GroupingDefinition;
58 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
59 import org.opendaylight.yangtools.yang.model.api.Module;
60 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
61 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
62 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
63 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
66 * Util class used for generation of types for RPCs, routedRPCs and Actions (YANG 1.1 only)
67 * in Binding spec. v2. In case of routed RPC detected in input YANG, RPC is turned to Action.
70 final class RpcActionGenHelper {
72 static final QName CONTEXT_REFERENCE =
73 QName.create("urn:opendaylight:yang:extension:yang-ext", "2013-07-09", "context-reference").intern();
75 private RpcActionGenHelper() {
76 throw new UnsupportedOperationException("Util class");
80 * Let's find out what context we are talking about
84 * In 1st case, we need Binding Generator behave like YANG 1.1 Action
86 * @param schemaNode RPC input node
87 * @return presence optional
90 static Optional<QName> getRoutingContext(final DataSchemaNode schemaNode) {
91 for (UnknownSchemaNode extension : schemaNode.getUnknownSchemaNodes()) {
92 if (CONTEXT_REFERENCE.equals(extension.getNodeType())) {
93 return Optional.fromNullable(extension.getQName());
96 return Optional.absent();
99 private static void resolveActions(final DataNodeContainer parent, final Module module,
100 final SchemaContext schemaContext, final boolean verboseClassComments,
101 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
102 final TypeProvider typeProvider, final BindingNamespaceType namespaceType) {
103 Preconditions.checkNotNull(parent, "Parent should not be NULL.");
104 final Collection<DataSchemaNode> potentials = parent.getChildNodes();
105 for (DataSchemaNode potential : potentials) {
106 if (resolveDataSchemaNodesCheck(module, schemaContext,potential)) {
107 BindingNamespaceType namespaceType1 = namespaceType;
108 if (namespaceType.equals(BindingNamespaceType.Data)) {
109 if (potential instanceof GroupingDefinition) {
110 namespaceType1 = BindingNamespaceType.Grouping;
114 if (potential instanceof ActionNodeContainer) {
115 final Set<ActionDefinition> actions = ((ActionNodeContainer) potential).getActions();
116 for (ActionDefinition action : actions) {
117 genCtx.get(module).addTopLevelNodeType(resolveOperation(potential, action, module,
118 schemaContext, verboseClassComments, genTypeBuilders, genCtx, typeProvider, true,
123 if (potential instanceof DataNodeContainer) {
124 resolveActions((DataNodeContainer) potential, module, schemaContext, verboseClassComments,
125 genTypeBuilders, genCtx, typeProvider, namespaceType1);
132 * Converts Yang 1.1 <b>Actions</b> to list of <code>Type</code> objects.
133 * @param module module from which is obtained set of all Action objects to
135 * @param genCtx input, generated context
136 * @param verboseClassComments verbosity switch
137 * @return generated context
139 static Map<Module, ModuleContext> actionMethodsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
140 final SchemaContext schemaContext, final boolean verboseClassComments,
141 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
143 checkModuleAndModuleName(module);
144 resolveActions(module, module, schemaContext, verboseClassComments, genTypeBuilders, genCtx, typeProvider,
145 BindingNamespaceType.Data);
150 * Converts global <b>RPCs</b> inputs and outputs sub-statements of the module
151 * to the list of <code>Type</code> objects. In addition, containers
152 * and lists which belong to input or output are also part of returning list.
153 * Detected routed RPCs are turned to Yang 1.1 Actions
156 * module from which is obtained set of all RPC objects to
158 * @param genCtx input, generated context
159 * @param verboseClassComments verbosity switch
161 * @throws IllegalArgumentException
163 * <li>if the module is null</li>
164 * <li>if the name of module is null</li>
166 * @throws IllegalStateException
167 * if set of RPCs from module is null
169 * @return generated context
171 static Map<Module, ModuleContext> rpcMethodsToGenType(final Module module, final Map<Module, ModuleContext> genCtx,
172 final SchemaContext schemaContext, final boolean verboseClassComments, final Map<String, Map<String,
173 GeneratedTypeBuilder>> genTypeBuilders, final TypeProvider typeProvider) {
175 checkModuleAndModuleName(module);
176 final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
177 checkState(rpcDefinitions != null, "Set of RPCs from module " + module.getName() + " cannot be NULL.");
178 if (rpcDefinitions.isEmpty()) {
182 for (final RpcDefinition rpc : rpcDefinitions) {
183 //FIXME: get correct parent for routed RPCs only
184 DataSchemaNode parent = null;
186 ContainerSchemaNode input = rpc.getInput();
187 boolean isAction = false;
189 for (DataSchemaNode schemaNode : input.getChildNodes()) {
190 if (getRoutingContext(schemaNode).isPresent()) {
199 genCtx.get(module).addTopLevelNodeType(resolveOperation(parent, rpc, module, schemaContext,
200 verboseClassComments, genTypeBuilders, genCtx, typeProvider, true,
201 BindingNamespaceType.Data));
204 genCtx.get(module).addTopLevelNodeType(resolveOperation(parent, rpc, module, schemaContext,
205 verboseClassComments, genTypeBuilders, genCtx, typeProvider, false,
206 BindingNamespaceType.Data));
214 * Converts RPC, Action or routed RPC into generated type
215 * @return generated type
217 private static GeneratedTypeBuilder resolveOperation(final DataSchemaNode parent, final OperationDefinition operation,
218 final Module module, final SchemaContext schemaContext, final boolean verboseClassComments,
219 final Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
220 final TypeProvider typeProvider, final boolean isAction, final BindingNamespaceType namespaceType) {
223 final String operationName = operation.getQName().getLocalName();
224 //concrete operation name
225 final StringBuilder sb = new StringBuilder(operationName).append('_');
231 final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, sb.toString(),
232 verboseClassComments, genCtx.get(module));
234 final String basePackageName = interfaceBuilder.getPackageName();
236 interfaceBuilder.setDescription(createDescription(operation, interfaceBuilder.getFullyQualifiedName(),
237 schemaContext, verboseClassComments, namespaceType));
238 final String operationComment = encodeAngleBrackets(operation.getDescription().orElse(null));
239 final MethodSignatureBuilder operationMethod = interfaceBuilder.addMethod("invoke");
242 final ContainerSchemaNode input = operation.getInput();
243 final GeneratedTypeBuilder inType = resolveOperationNode(interfaceBuilder, module, operation.getInput(),
244 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders,
245 genCtx, true, namespaceType);
246 annotateDeprecatedIfNecessary(operation.getStatus(), inType);
247 inType.setParentTypeForBuilder(interfaceBuilder);
248 genCtx.get(module).addChildNodeType(input, inType);
251 final ContainerSchemaNode output = operation.getOutput();
252 final GeneratedTypeBuilder outType = resolveOperationNode(interfaceBuilder, module, operation.getOutput(),
253 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders,
254 genCtx, false, namespaceType);
255 annotateDeprecatedIfNecessary(operation.getStatus(), outType);
256 outType.setParentTypeForBuilder(interfaceBuilder);
257 genCtx.get(module).addChildNodeType(output, outType);
259 final GeneratedType inTypeInstance = inType.toInstance();
260 operationMethod.addParameter(inTypeInstance, "input");
263 if (parent != null) {
265 GeneratedTypeBuilder parentType = genCtx.get(module).getChildNode(parent.getPath());
266 checkState(parentType != null, "Parent generated type for " + parent
267 + " data schema node must have been generated already");
268 annotateDeprecatedIfNecessary(parent.getStatus(), parentType);
270 if (parent instanceof ListSchemaNode) {
272 GeneratedTransferObject keyType = null;
273 for (MethodSignatureBuilder method : parentType.getMethodDefinitions()) {
274 if (method.getName().equals("getKey")) {
275 keyType = (GeneratedTransferObject) method.toInstance(parentType).getReturnType();
279 operationMethod.addParameter(
280 parameterizedTypeFor(KEYED_INSTANCE_IDENTIFIER, parentType, keyType), "kii");
281 interfaceBuilder.addImplementsType(parameterizedTypeFor(LIST_ACTION, parentType, inType, outType));
284 operationMethod.addParameter(parameterizedTypeFor(INSTANCE_IDENTIFIER, parentType), "ii");
285 interfaceBuilder.addImplementsType(parameterizedTypeFor(ACTION, parentType, inType, outType));
289 throw new UnsupportedOperationException("Not implemented yet.");
293 interfaceBuilder.addImplementsType(parameterizedTypeFor(RPC, inType, outType));
296 interfaceBuilder.addImplementsType(TREE_NODE);
297 operationMethod.addParameter(parameterizedTypeFor(RPC_CALLBACK, outType), "callback");
299 operationMethod.setComment(operationComment);
300 operationMethod.setReturnType(VOID);
302 return interfaceBuilder;
305 private static GeneratedTypeBuilder resolveOperationNode(final GeneratedTypeBuilder parent, final Module module, final
306 ContainerSchemaNode operationNode, final String basePackageName, final SchemaContext schemaContext, final String
307 operationName, final boolean verboseClassComments, final TypeProvider typeProvider, final Map<String, Map<String,
308 GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx, final boolean isInput,
309 final BindingNamespaceType namespaceType) {
310 final GeneratedTypeBuilder nodeType = addRawInterfaceDefinition(basePackageName, operationNode, schemaContext,
311 operationName, "", verboseClassComments, genTypeBuilders, namespaceType, genCtx.get(module));
312 addImplementedInterfaceFromUses(operationNode, nodeType, genCtx);
313 nodeType.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
314 (BindingTypes.ITEM, nodeType)));
316 nodeType.addImplementsType(parameterizedTypeFor(INPUT, nodeType));
318 nodeType.addImplementsType(parameterizedTypeFor(OUTPUT, nodeType));
320 nodeType.addImplementsType(parameterizedTypeFor(INSTANTIABLE, nodeType));
321 nodeType.addImplementsType(augmentable(nodeType));
322 GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, nodeType, nodeType, operationNode.getChildNodes(), genCtx,
323 schemaContext, verboseClassComments, genTypeBuilders, typeProvider, namespaceType);
325 final MethodSignatureBuilder nodeMethod = nodeType.addMethod("implementedInterface");
326 nodeMethod.setReturnType(parameterizedTypeFor(CLASS, nodeType));
327 nodeMethod.addAnnotation("", "Override");
329 processUsesImplements(operationNode, module, schemaContext, genCtx, namespaceType);