Share RpcResult Type
[mdsal.git] / binding / mdsal-binding-generator-impl / src / main / java / org / opendaylight / mdsal / binding / generator / impl / AbstractTypeGenerator.java
index 047716a10f96d6fef14aff548a322357f7c4a2ed..691e541597c3bed516598a1ca948e573e65d18c1 100644 (file)
@@ -9,19 +9,26 @@ package org.opendaylight.mdsal.binding.generator.impl;
 
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
+import static com.google.common.base.Verify.verifyNotNull;
 import static java.util.Objects.requireNonNull;
 import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.computeDefaultSUID;
 import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForAugmentedGeneratedType;
 import static org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil.packageNameForGeneratedType;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.BASE_IDENTITY;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_OBJECT;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.DATA_ROOT;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.IDENTIFIABLE;
-import static org.opendaylight.mdsal.binding.model.util.BindingTypes.IDENTIFIER;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.NOTIFICATION;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.NOTIFICATION_LISTENER;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.ROUTING_CONTEXT;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.RPC_SERVICE;
 import static org.opendaylight.mdsal.binding.model.util.BindingTypes.augmentable;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.childOf;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.choiceIn;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.identifiable;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.identifier;
+import static org.opendaylight.mdsal.binding.model.util.BindingTypes.rpcResult;
 import static org.opendaylight.mdsal.binding.model.util.Types.BOOLEAN;
 import static org.opendaylight.mdsal.binding.model.util.Types.FUTURE;
-import static org.opendaylight.mdsal.binding.model.util.Types.VOID;
 import static org.opendaylight.mdsal.binding.model.util.Types.typeForClass;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findDataSchemaNode;
 import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findNodeInSchemaContext;
@@ -30,6 +37,7 @@ import static org.opendaylight.yangtools.yang.model.util.SchemaContextUtil.findP
 import com.google.common.base.Splitter;
 import com.google.common.collect.Iterables;
 import com.google.common.collect.Sets;
+import java.util.AbstractMap.SimpleImmutableEntry;
 import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Comparator;
@@ -47,6 +55,7 @@ import org.opendaylight.mdsal.binding.model.api.JavaTypeName;
 import org.opendaylight.mdsal.binding.model.api.ParameterizedType;
 import org.opendaylight.mdsal.binding.model.api.Restrictions;
 import org.opendaylight.mdsal.binding.model.api.Type;
+import org.opendaylight.mdsal.binding.model.api.type.builder.AnnotableTypeBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.AnnotationTypeBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.EnumBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedPropertyBuilder;
@@ -56,7 +65,6 @@ import org.opendaylight.mdsal.binding.model.api.type.builder.GeneratedTypeBuilde
 import org.opendaylight.mdsal.binding.model.api.type.builder.MethodSignatureBuilder;
 import org.opendaylight.mdsal.binding.model.api.type.builder.TypeMemberBuilder;
 import org.opendaylight.mdsal.binding.model.util.BindingGeneratorUtil;
-import org.opendaylight.mdsal.binding.model.util.BindingTypes;
 import org.opendaylight.mdsal.binding.model.util.ReferencedTypeImpl;
 import org.opendaylight.mdsal.binding.model.util.TypeConstants;
 import org.opendaylight.mdsal.binding.model.util.Types;
@@ -64,14 +72,9 @@ import org.opendaylight.mdsal.binding.model.util.generated.type.builder.Generate
 import org.opendaylight.mdsal.binding.yang.types.AbstractTypeProvider;
 import org.opendaylight.mdsal.binding.yang.types.BaseYangTypes;
 import org.opendaylight.mdsal.binding.yang.types.GroupingDefinitionDependencySort;
-import org.opendaylight.yangtools.yang.binding.BaseIdentity;
 import org.opendaylight.yangtools.yang.binding.BindingMapping;
-import org.opendaylight.yangtools.yang.binding.DataContainer;
-import org.opendaylight.yangtools.yang.binding.RpcService;
-import org.opendaylight.yangtools.yang.binding.annotations.RoutingContext;
 import org.opendaylight.yangtools.yang.common.QName;
 import org.opendaylight.yangtools.yang.common.QNameModule;
-import org.opendaylight.yangtools.yang.common.RpcResult;
 import org.opendaylight.yangtools.yang.model.api.AugmentationSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.CaseSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.ChoiceSchemaNode;
@@ -96,8 +99,6 @@ import org.opendaylight.yangtools.yang.model.api.Status;
 import org.opendaylight.yangtools.yang.model.api.TypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.UnknownSchemaNode;
 import org.opendaylight.yangtools.yang.model.api.UsesNode;
-import org.opendaylight.yangtools.yang.model.api.meta.EffectiveStatement;
-import org.opendaylight.yangtools.yang.model.api.meta.StatementSource;
 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.EnumTypeDefinition;
 import org.opendaylight.yangtools.yang.model.api.type.PatternConstraint;
@@ -112,6 +113,8 @@ import org.slf4j.LoggerFactory;
 abstract class AbstractTypeGenerator {
     private static final Logger LOG = LoggerFactory.getLogger(BindingGeneratorImpl.class);
     private static final Splitter COLON_SPLITTER = Splitter.on(':');
+    private static final JavaTypeName DEPRECATED_ANNOTATION = JavaTypeName.create(Deprecated.class);
+    private static final JavaTypeName OVERRIDE_ANNOTATION = JavaTypeName.create(Override.class);
 
     /**
      * Comparator based on augment target path.
@@ -286,8 +289,8 @@ abstract class AbstractTypeGenerator {
             final List<String> listKeys = listKeys(node);
             final GeneratedTOBuilder genTOBuilder = resolveListKeyTOBuilder(context, node);
             if (genTOBuilder != null) {
-                final Type identifierMarker = Types.parameterizedTypeFor(IDENTIFIER, genType);
-                final Type identifiableMarker = Types.parameterizedTypeFor(IDENTIFIABLE, genTOBuilder);
+                final Type identifierMarker = identifier(genType);
+                final Type identifiableMarker = identifiable(genTOBuilder);
                 genTOBuilder.addImplementsType(identifierMarker);
                 genType.addImplementsType(identifiableMarker);
             }
@@ -415,7 +418,7 @@ abstract class AbstractTypeGenerator {
         }
 
         final GeneratedTypeBuilder interfaceBuilder = moduleTypeBuilder(context, "Service");
-        interfaceBuilder.addImplementsType(Types.typeForClass(RpcService.class));
+        interfaceBuilder.addImplementsType(RPC_SERVICE);
 
         addCodegenInformation(interfaceBuilder, module, "RPCs", rpcDefinitions);
 
@@ -424,42 +427,20 @@ abstract class AbstractTypeGenerator {
                 final String rpcName = BindingMapping.getClassName(rpc.getQName());
                 final String rpcMethodName = BindingMapping.getPropertyName(rpcName);
                 final MethodSignatureBuilder method = interfaceBuilder.addMethod(rpcMethodName);
-                final ContainerSchemaNode input = rpc.getInput();
-                final ContainerSchemaNode output = rpc.getOutput();
 
                 // Do not refer to annotation class, as it may not be available at runtime
                 method.addAnnotation("javax.annotation", "CheckReturnValue");
-
-                //in case of implicit RPC input (StatementSource.CONTEXT),
-                // stay compatible (no input argument generated)
-                if (input != null && isExplicitStatement(input)) {
-                    final Type inTypeInstance = createRpcContainer(context, rpcName, rpc, input);
-                    method.addParameter(inTypeInstance, "input");
-                }
-
-                final Type outTypeInstance;
-                //in case of implicit RPC output (StatementSource.CONTEXT),
-                //stay compatible (Future<RpcResult<Void>> return type generated)
-                if (output != null && isExplicitStatement(output)) {
-                    outTypeInstance = createRpcContainer(context, rpcName, rpc, output);
-                } else {
-                    outTypeInstance = VOID;
-                }
-
-                final Type rpcRes = Types.parameterizedTypeFor(Types.typeForClass(RpcResult.class), outTypeInstance);
                 addComment(method, rpc);
-                method.setReturnType(Types.parameterizedTypeFor(FUTURE, rpcRes));
+                method.addParameter(
+                    createRpcContainer(context, rpcName, rpc, verifyNotNull(rpc.getInput())), "input");
+                method.setReturnType(Types.parameterizedTypeFor(FUTURE,
+                    rpcResult(createRpcContainer(context, rpcName, rpc, verifyNotNull(rpc.getOutput())))));
             }
         }
 
         context.addTopLevelNodeType(interfaceBuilder);
     }
 
-    private static boolean isExplicitStatement(final ContainerSchemaNode node) {
-        return node instanceof EffectiveStatement
-                && ((EffectiveStatement<?, ?>) node).getDeclared().getStatementSource() == StatementSource.DECLARATION;
-    }
-
     private Type createRpcContainer(final ModuleContext context, final String rpcName, final RpcDefinition rpc,
             final ContainerSchemaNode schema) {
         processUsesAugments(schema, context);
@@ -500,7 +481,7 @@ abstract class AbstractTypeGenerator {
         }
 
         final GeneratedTypeBuilder listenerInterface = moduleTypeBuilder(context, "Listener");
-        listenerInterface.addImplementsType(BindingTypes.NOTIFICATION_LISTENER);
+        listenerInterface.addImplementsType(NOTIFICATION_LISTENER);
 
         for (final NotificationDefinition notification : notifications) {
             if (notification != null) {
@@ -571,16 +552,15 @@ abstract class AbstractTypeGenerator {
             packageNameForGeneratedType(context.modulePackageName(), identity.getPath()),
             BindingMapping.getClassName(identity.getQName())));
         final Set<IdentitySchemaNode> baseIdentities = identity.getBaseIdentities();
-        if (baseIdentities.isEmpty()) {
-            final GeneratedTOBuilder gto = typeProvider.newGeneratedTOBuilder(JavaTypeName.create(BaseIdentity.class));
-            newType.addImplementsType(gto.build());
-        } else {
+        if (!baseIdentities.isEmpty()) {
             for (IdentitySchemaNode baseIdentity : baseIdentities) {
                 final QName qname = baseIdentity.getQName();
                 final GeneratedTransferObject gto = typeProvider.newGeneratedTOBuilder(JavaTypeName.create(
                     BindingMapping.getRootPackageName(qname.getModule()), BindingMapping.getClassName(qname))).build();
                 newType.addImplementsType(gto);
             }
+        } else {
+            newType.addImplementsType(BASE_IDENTITY);
         }
 
         final Module module = context.module();
@@ -588,15 +568,16 @@ abstract class AbstractTypeGenerator {
         newType.setModuleName(module.getName());
         newType.setSchemaPath(identity.getPath());
 
-        qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, identity.getQName());
+        qnameConstant(newType, JavaTypeName.create(context.modulePackageName(), BindingMapping.MODULE_INFO_CLASS_NAME),
+            identity.getQName().getLocalName());
 
         context.addIdentityType(identity.getQName(), newType);
     }
 
-
-    private static Constant qnameConstant(final GeneratedTypeBuilderBase<?> toBuilder, final String constantName,
-            final QName name) {
-        return toBuilder.addConstant(typeForClass(QName.class), constantName, name);
+    private static Constant qnameConstant(final GeneratedTypeBuilderBase<?> toBuilder,
+            final JavaTypeName yangModuleInfo, final String localName) {
+        return toBuilder.addConstant(typeForClass(QName.class), BindingMapping.QNAME_STATIC_FIELD_NAME,
+            new SimpleImmutableEntry<>(yangModuleInfo, localName));
     }
 
     /**
@@ -1070,11 +1051,14 @@ abstract class AbstractTypeGenerator {
             final GeneratedTypeBuilder choiceTypeBuilder = addRawInterfaceDefinition(
                 JavaTypeName.create(packageNameForGeneratedType(context.modulePackageName(), choiceNode.getPath()),
                 BindingMapping.getClassName(choiceNode.getQName())), choiceNode);
-            constructGetter(parent, choiceTypeBuilder, choiceNode);
-            choiceTypeBuilder.addImplementsType(typeForClass(DataContainer.class));
+            choiceTypeBuilder.addImplementsType(choiceIn(parent));
             annotateDeprecatedIfNecessary(choiceNode.getStatus(), choiceTypeBuilder);
             context.addChildNodeType(choiceNode, choiceTypeBuilder);
-            generateTypesFromChoiceCases(context, choiceTypeBuilder.build(), choiceNode);
+
+            final GeneratedType choiceType = choiceTypeBuilder.build();
+            generateTypesFromChoiceCases(context, choiceType, choiceNode);
+
+            constructGetter(parent, choiceType, choiceNode);
         }
     }
 
@@ -1187,25 +1171,7 @@ abstract class AbstractTypeGenerator {
                 final GeneratedTypeBuilder caseTypeBuilder = addDefaultInterfaceDefinition(context, caseNode);
                 caseTypeBuilder.addImplementsType(targetType);
 
-                SchemaNode parent;
-                final SchemaPath nodeSp = targetNode.getPath();
-                parent = findDataSchemaNode(schemaContext, nodeSp.getParent());
-
-                GeneratedTypeBuilder childOfType = null;
-                if (parent instanceof Module) {
-                    childOfType = moduleContext(((Module) parent).getQNameModule()).getModuleNode();
-                } else if (parent instanceof CaseSchemaNode) {
-                    childOfType = findCaseByPath(parent.getPath());
-                } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
-                    childOfType = findChildNodeByPath(parent.getPath());
-                } else if (parent instanceof GroupingDefinition) {
-                    childOfType = findGroupingByPath(parent.getPath());
-                }
-
-                if (childOfType == null) {
-                    throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
-                }
-
+                GeneratedTypeBuilder childOfType = findChildOfType(targetNode);
                 CaseSchemaNode node = null;
                 final String caseLocalName = caseNode.getQName().getLocalName();
                 if (caseNode instanceof CaseSchemaNode) {
@@ -1232,6 +1198,30 @@ abstract class AbstractTypeGenerator {
         }
     }
 
+    private GeneratedTypeBuilder findChildOfType(final ChoiceSchemaNode targetNode) {
+        final SchemaPath nodePath = targetNode.getPath();
+        final SchemaPath parentSp = nodePath.getParent();
+        if (parentSp.getParent() == null) {
+            return moduleContext(nodePath.getLastComponent().getModule()).getModuleNode();
+        }
+
+        final SchemaNode parent = findDataSchemaNode(schemaContext, parentSp);
+        GeneratedTypeBuilder childOfType = null;
+        if (parent instanceof CaseSchemaNode) {
+            childOfType = findCaseByPath(parent.getPath());
+        } else if (parent instanceof DataSchemaNode || parent instanceof NotificationDefinition) {
+            childOfType = findChildNodeByPath(parent.getPath());
+        } else if (parent instanceof GroupingDefinition) {
+            childOfType = findGroupingByPath(parent.getPath());
+        }
+
+        if (childOfType == null) {
+            throw new IllegalArgumentException("Failed to find parent type of choice " + targetNode);
+        }
+
+        return childOfType;
+    }
+
     private static CaseSchemaNode findNamedCase(final ChoiceSchemaNode choice, final String caseName) {
         final List<CaseSchemaNode> cases = choice.findCaseNodes(caseName);
         return cases.isEmpty() ? null : cases.get(0);
@@ -1381,7 +1371,7 @@ abstract class AbstractTypeGenerator {
                             + nodeParam);
                 }
 
-                final AnnotationTypeBuilder rc = getter.addAnnotation(JavaTypeName.create(RoutingContext.class));
+                final AnnotationTypeBuilder rc = getter.addAnnotation(ROUTING_CONTEXT);
                 final String packageName = packageNameForGeneratedType(basePackageName, identity.getPath());
                 final String genTypeName = BindingMapping.getClassName(identity.getQName().getLocalName());
                 rc.addParameter("value", packageName + "." + genTypeName + ".class");
@@ -1618,18 +1608,15 @@ abstract class AbstractTypeGenerator {
             final Type parent, final ModuleContext context) {
         final GeneratedTypeBuilder it = addRawInterfaceDefinition(
             JavaTypeName.create(packageName, BindingMapping.getClassName(schemaNode.getQName())), schemaNode);
-        if (parent == null) {
-            it.addImplementsType(DATA_OBJECT);
-        } else {
-            it.addImplementsType(BindingTypes.childOf(parent));
-        }
+
+        it.addImplementsType(parent == null ? DATA_OBJECT : childOf(parent));
         if (!(schemaNode instanceof GroupingDefinition)) {
             it.addImplementsType(augmentable(it));
         }
-
         if (schemaNode instanceof DataNodeContainer) {
-            groupingsToGenTypes(context, ((DataNodeContainer) schemaNode).getGroupings());
-            addImplementedInterfaceFromUses((DataNodeContainer) schemaNode, it);
+            final DataNodeContainer containerSchema = (DataNodeContainer) schemaNode;
+            groupingsToGenTypes(context, containerSchema.getGroupings());
+            addImplementedInterfaceFromUses(containerSchema, it);
         }
 
         return it;
@@ -1686,7 +1673,8 @@ abstract class AbstractTypeGenerator {
         // FIXME: Validation of name conflict
         final GeneratedTypeBuilder newType = typeProvider.newGeneratedTypeBuilder(identifier);
         final Module module = findParentModule(schemaContext, schemaNode);
-        qnameConstant(newType, BindingMapping.QNAME_STATIC_FIELD_NAME, schemaNode.getQName());
+        qnameConstant(newType, JavaTypeName.create(BindingMapping.getRootPackageName(module.getQNameModule()),
+            BindingMapping.MODULE_INFO_CLASS_NAME), schemaNode.getQName().getLocalName());
 
         addCodegenInformation(newType, module, schemaNode);
         newType.setSchemaPath(schemaNode.getPath());
@@ -1748,8 +1736,10 @@ abstract class AbstractTypeGenerator {
             getterMethodName(node.getQName().getLocalName(), returnType));
         getMethod.setReturnType(returnType);
 
-        if (node.getStatus() == Status.DEPRECATED) {
-            getMethod.addAnnotation("java.lang", "Deprecated");
+        annotateDeprecatedIfNecessary(node.getStatus(), getMethod);
+        if (!returnType.getPackageName().isEmpty()) {
+            // The return type has a package, so it's not a primitive type
+            getMethod.addAnnotation("javax.annotation", "Nullable");
         }
         addComment(getMethod, node);
 
@@ -1816,11 +1806,9 @@ abstract class AbstractTypeGenerator {
 
         if (genTOBuilder != null) {
             final GeneratedTransferObject genTO = genTOBuilder.build();
-
-            // Fake the 'getKey()' for items, this is equivalent to constructGetter()
-            final MethodSignatureBuilder getMethod = typeBuilder.addMethod(getterMethodName("key", genTO));
-            getMethod.setReturnType(genTO);
-            getMethod.setComment("Returns Primary Key of Yang List Type");
+            // Add Identifiable.getKey() for items
+            typeBuilder.addMethod(BindingMapping.IDENTIFIABLE_KEY_NAME).setReturnType(genTO)
+                .addAnnotation(OVERRIDE_ANNOTATION);
             context.addGeneratedTOBuilder(genTOBuilder);
         }
     }
@@ -2007,9 +1995,9 @@ abstract class AbstractTypeGenerator {
         return null;
     }
 
-    private static void annotateDeprecatedIfNecessary(final Status status, final GeneratedTypeBuilder builder) {
+    private static void annotateDeprecatedIfNecessary(final Status status, final AnnotableTypeBuilder builder) {
         if (status == Status.DEPRECATED) {
-            builder.addAnnotation("java.lang", "Deprecated");
+            builder.addAnnotation(DEPRECATED_ANNOTATION);
         }
     }
 }