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.AuxiliaryGenUtils.resolveListKeyTOBuilder;
16 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.addImplementedInterfaceFromUses;
17 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.addRawInterfaceDefinition;
18 import static org.opendaylight.mdsal.binding.javav2.generator.impl.GenHelperUtil.moduleTypeBuilder;
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.base.Optional;
37 import java.util.Collection;
40 import org.opendaylight.mdsal.binding.javav2.generator.spi.TypeProvider;
41 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingGeneratorUtil;
42 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
43 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
44 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTOBuilder;
45 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
46 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.MethodSignatureBuilder;
47 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
48 import org.opendaylight.yangtools.yang.common.QName;
49 import org.opendaylight.yangtools.yang.model.api.ActionDefinition;
50 import org.opendaylight.yangtools.yang.model.api.ActionNodeContainer;
51 import org.opendaylight.yangtools.yang.model.api.ContainerSchemaNode;
52 import org.opendaylight.yangtools.yang.model.api.DataSchemaNode;
53 import org.opendaylight.yangtools.yang.model.api.ListSchemaNode;
54 import org.opendaylight.yangtools.yang.model.api.Module;
55 import org.opendaylight.yangtools.yang.model.api.OperationDefinition;
56 import org.opendaylight.yangtools.yang.model.api.RpcDefinition;
57 import org.opendaylight.yangtools.yang.model.api.SchemaContext;
58 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
62 * Util class used for generation of types for RPCs, routedRPCs and Actions (YANG 1.1 only)
63 * in Binding spec. v2. In case of routed RPC detected in input YANG, RPC is turned to Action.
67 public final class RpcActionGenHelper {
69 private static final QName CONTEXT_REFERENCE =
70 QName.create("urn:opendaylight:yang:extension:yang-ext", "2013-07-09", "context-reference").intern();
72 private RpcActionGenHelper() {
73 throw new UnsupportedOperationException("Util class");
77 * Let's find out what context we are talking about
81 * In 1st case, we need Binding Generator behave like YANG 1.1 Action
83 * @param schemaNode RPC input node
84 * @return presence optional
86 private static Optional<QName> getRoutingContext(final DataSchemaNode schemaNode) {
87 for (UnknownSchemaNode extension : schemaNode.getUnknownSchemaNodes()) {
88 if (CONTEXT_REFERENCE.equals(extension.getNodeType())) {
89 return Optional.fromNullable(extension.getQName());
92 return Optional.absent();
96 * Converts Yang 1.1 <b>Actions</b> to list of <code>Type</code> objects.
97 * @param module module from which is obtained set of all Action objects to
99 * @param genCtx input, generated context
100 * @param verboseClassComments verbosity switch
101 * @return generated context
103 static Map<Module, ModuleContext> actionMethodsToGenType(final Module module, Map<Module, ModuleContext> genCtx,
104 final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String,
105 GeneratedTypeBuilder>> genTypeBuilders, TypeProvider typeProvider) {
107 checkModuleAndModuleName(module);
108 final Collection<DataSchemaNode> potentials = module.getChildNodes();
109 for (DataSchemaNode potential : potentials) {
110 if (potential instanceof ActionNodeContainer) {
111 final Set<ActionDefinition> actions = ((ActionNodeContainer) potential).getActions();
112 for (ActionDefinition action: actions) {
113 genCtx.get(module).addChildNodeType(potential, resolveOperation(potential, action, module,
114 schemaContext, verboseClassComments, genTypeBuilders, genCtx, typeProvider, true));
122 * Converts global <b>RPCs</b> inputs and outputs sub-statements of the module
123 * to the list of <code>Type</code> objects. In addition, containers
124 * and lists which belong to input or output are also part of returning list.
125 * Detected routed RPCs are turned to Yang 1.1 Actions
128 * module from which is obtained set of all RPC objects to
130 * @param genCtx input, generated context
131 * @param verboseClassComments verbosity switch
133 * @throws IllegalArgumentException
135 * <li>if the module is null</li>
136 * <li>if the name of module is null</li>
138 * @throws IllegalStateException
139 * if set of RPCs from module is null
141 * @return generated context
143 static Map<Module, ModuleContext> rpcMethodsToGenType(final Module module, Map<Module, ModuleContext> genCtx,
144 final SchemaContext schemaContext, final boolean verboseClassComments, Map<String, Map<String,
145 GeneratedTypeBuilder>> genTypeBuilders, TypeProvider typeProvider) {
147 checkModuleAndModuleName(module);
148 final Set<RpcDefinition> rpcDefinitions = module.getRpcs();
149 checkState(rpcDefinitions != null, "Set of RPCs from module " + module.getName() + " cannot be NULL.");
150 if (rpcDefinitions.isEmpty()) {
154 for (final RpcDefinition rpc : rpcDefinitions) {
155 //FIXME: get correct parent for routed RPCs only
156 DataSchemaNode parent = null;
158 ContainerSchemaNode input = rpc.getInput();
159 boolean isAction = false;
161 for (DataSchemaNode schemaNode : input.getChildNodes()) {
162 if (getRoutingContext(schemaNode).isPresent()) {
171 genCtx.get(module).addChildNodeType(parent, resolveOperation(parent, rpc, module, schemaContext,
172 verboseClassComments, genTypeBuilders, genCtx, typeProvider, true));
175 genCtx.get(module).addTopLevelNodeType(resolveOperation(parent, rpc, module, schemaContext,
176 verboseClassComments, genTypeBuilders, genCtx, typeProvider, false));
184 * Converts RPC, Action or routed RPC into generated type
185 * @return generated type
187 private static GeneratedTypeBuilder resolveOperation(final DataSchemaNode parent, final OperationDefinition operation,
188 final Module module, final SchemaContext schemaContext, final boolean verboseClassComments,
189 Map<String, Map<String, GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx,
190 TypeProvider typeProvider, final boolean isAction) {
193 final String operationName = operation.getQName().getLocalName();
194 //concrete operation name
195 final StringBuilder sb = new StringBuilder(operationName).append('_');
201 final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(module, sb.toString(),
202 verboseClassComments);
204 final String basePackageName = interfaceBuilder.getPackageName();
206 interfaceBuilder.setDescription(createDescription(operation, interfaceBuilder.getFullyQualifiedName(),
207 schemaContext, verboseClassComments));
208 final String operationComment = encodeAngleBrackets(operation.getDescription());
209 final MethodSignatureBuilder operationMethod = interfaceBuilder.addMethod("invoke");
212 final ContainerSchemaNode input = operation.getInput();
213 final GeneratedTypeBuilder inType = resolveOperationNode(interfaceBuilder, module, operation.getInput(),
214 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders, genCtx, true);
215 annotateDeprecatedIfNecessary(operation.getStatus(), inType);
216 inType.setParentTypeForBuilder(interfaceBuilder);
217 genCtx.get(module).addChildNodeType(input, inType);
220 final ContainerSchemaNode output = operation.getOutput();
221 final GeneratedTypeBuilder outType = resolveOperationNode(interfaceBuilder, module, operation.getOutput(),
222 basePackageName, schemaContext, operationName, verboseClassComments, typeProvider, genTypeBuilders, genCtx, false);
223 annotateDeprecatedIfNecessary(operation.getStatus(), outType);
224 outType.setParentTypeForBuilder(interfaceBuilder);
225 genCtx.get(module).addChildNodeType(output, outType);
227 final GeneratedType inTypeInstance = inType.toInstance();
228 operationMethod.addParameter(inTypeInstance, "input");
232 String packageName = BindingGeneratorUtil.packageNameForGeneratedType(basePackageName, parent.getPath(),
233 BindingNamespaceType.Data);
234 GeneratedTypeBuilder parentType = addRawInterfaceDefinition(packageName, parent, schemaContext,
235 parent.getQName().getLocalName(), verboseClassComments, genTypeBuilders);
236 parentType.addImplementsType(TREE_NODE);
237 parentType.addImplementsType(augmentable(parentType));
238 annotateDeprecatedIfNecessary(parent.getStatus(), parentType);
240 operationMethod.addParameter(parameterizedTypeFor(INSTANCE_IDENTIFIER, parentType), "ii");
242 if (parent instanceof ListSchemaNode) {
244 final GeneratedTOBuilder keyType = resolveListKeyTOBuilder(basePackageName, (ListSchemaNode) parent);
245 operationMethod.addParameter(
246 parameterizedTypeFor(KEYED_INSTANCE_IDENTIFIER, parentType, keyType), "kii");
247 operationMethod.setReturnType(keyType);
248 interfaceBuilder.addImplementsType(parameterizedTypeFor(LIST_ACTION, parentType, inType, outType));
251 GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, parentType, parentType,
252 ((ContainerSchemaNode) parent).getChildNodes(), genCtx, schemaContext, verboseClassComments,
253 genTypeBuilders, typeProvider);
254 operationMethod.addParameter(parameterizedTypeFor(INSTANCE_IDENTIFIER, parentType), "ii");
255 interfaceBuilder.addImplementsType(parameterizedTypeFor(ACTION, parentType, inType, outType));
259 interfaceBuilder.addImplementsType(parameterizedTypeFor(RPC, inType, outType));
260 interfaceBuilder.addImplementsType(TREE_NODE);
263 operationMethod.addParameter(parameterizedTypeFor(RPC_CALLBACK, outType), "callback");
265 operationMethod.setComment(operationComment);
266 operationMethod.setReturnType(VOID);
268 return interfaceBuilder;
271 private static GeneratedTypeBuilder resolveOperationNode(GeneratedTypeBuilder parent, final Module module, final
272 ContainerSchemaNode operationNode, final String basePackageName, final SchemaContext schemaContext, final String
273 operationName, final boolean verboseClassComments, TypeProvider typeProvider, Map<String, Map<String,
274 GeneratedTypeBuilder>> genTypeBuilders, final Map<Module, ModuleContext> genCtx, final boolean isInput) {
276 final GeneratedTypeBuilder nodeType = addRawInterfaceDefinition(basePackageName, operationNode, schemaContext,
277 operationName, verboseClassComments, genTypeBuilders);
278 addImplementedInterfaceFromUses(operationNode, nodeType, genCtx);
279 nodeType.addImplementsType(parameterizedTypeFor(BindingTypes.TREE_CHILD_NODE, parent, parameterizedTypeFor
280 (BindingTypes.ITEM, parent)));
282 nodeType.addImplementsType(parameterizedTypeFor(INPUT, nodeType));
284 nodeType.addImplementsType(parameterizedTypeFor(OUTPUT, nodeType));
286 nodeType.addImplementsType(parameterizedTypeFor(INSTANTIABLE, nodeType));
287 nodeType.addImplementsType(augmentable(nodeType));
288 GenHelperUtil.resolveDataSchemaNodes(module, basePackageName, nodeType, nodeType, operationNode.getChildNodes(), genCtx,
289 schemaContext, verboseClassComments, genTypeBuilders, typeProvider);
291 final MethodSignatureBuilder nodeMethod = nodeType.addMethod("implementedInterface");
292 nodeMethod.setReturnType(parameterizedTypeFor(CLASS, nodeType));
293 nodeMethod.addAnnotation("", "Override");