Bug 1411-5 #9: MDSAL Binding2 Java API Generator 99/46899/18
authorMartin Ciglan <mciglan@cisco.com>
Thu, 8 Dec 2016 09:43:24 +0000 (10:43 +0100)
committerMartin Ciglan <mciglan@cisco.com>
Thu, 12 Jan 2017 07:20:33 +0000 (07:20 +0000)
- interface generator, renderer, template TOgenerator
for generating union, union builder and class
- bit of cleanup
- review comments implemented

Change-Id: Iedbf069e629c6fb92b93046348c6a15fa3e77fd9
Signed-off-by: Filip Gregor <fgregor@cisco.com>
Signed-off-by: Martin Ciglan <mciglan@cisco.com>
binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/InterfaceGenerator.java [new file with mode: 0644]
binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/TOGenerator.java [new file with mode: 0644]
binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/renderers/InterfaceRenderer.java [new file with mode: 0644]
binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding2/interfaceTemplate.scala.txt [new file with mode: 0644]

diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/InterfaceGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/InterfaceGenerator.java
new file mode 100644 (file)
index 0000000..1ae9872
--- /dev/null
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.binding2.java.api.generator;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.mdsal.binding2.java.api.generator.renderers.InterfaceRenderer;
+import org.opendaylight.mdsal.binding2.model.api.CodeGenerator;
+import org.opendaylight.mdsal.binding2.model.api.Enumeration;
+import org.opendaylight.mdsal.binding2.model.api.GeneratedTransferObject;
+import org.opendaylight.mdsal.binding2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.UnitName;
+import org.opendaylight.yangtools.concepts.Identifier;
+
+/**
+ * Transforms data from virtual form to JAVA source code. Resulting source code represents JAVA
+ * interface. Source code generation process is supported by interface template written
+ * in Twirl (Scala based) language.
+ */
+@Beta
+public final class InterfaceGenerator implements CodeGenerator {
+
+    @Override
+    public String generate(Type type) {
+        if ((type instanceof GeneratedType) && !(type instanceof GeneratedTransferObject)) {
+            final GeneratedType genType = (GeneratedType) type;
+            return new InterfaceRenderer(genType).generateTemplate();
+        } else {
+            return "";
+        }
+    }
+
+    @Override
+    public boolean isAcceptable(Type type) {
+        return type instanceof GeneratedType && !(type instanceof GeneratedTransferObject)
+                && !(type instanceof Enumeration);
+    }
+
+    @Override
+    public Identifier getUnitName(Type type) {
+        return new UnitName(type.getName());
+    }
+}
diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/TOGenerator.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/TOGenerator.java
new file mode 100644 (file)
index 0000000..066c2f1
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.binding2.java.api.generator;
+
+import com.google.common.annotations.Beta;
+import org.opendaylight.mdsal.binding2.java.api.generator.renderers.ClassRenderer;
+import org.opendaylight.mdsal.binding2.java.api.generator.renderers.UnionBuilderRenderer;
+import org.opendaylight.mdsal.binding2.java.api.generator.renderers.UnionRenderer;
+import org.opendaylight.mdsal.binding2.model.api.CodeGenerator;
+import org.opendaylight.mdsal.binding2.model.api.GeneratedTransferObject;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.model.api.UnitName;
+import org.opendaylight.yangtools.concepts.Identifier;
+
+/**
+ * Transformer of the data from the virtual form to JAVA source code. The
+ * result source code represents JAVA class. For generating of the source code
+ * is used the template written in Twirl (Scala based) language.
+ */
+@Beta
+public class TOGenerator implements CodeGenerator {
+
+    @Override
+    public String generate(Type type) {
+        if (type instanceof GeneratedTransferObject) {
+            final GeneratedTransferObject genTO = (GeneratedTransferObject) type;
+            if(genTO.isUnionType()) {
+                return new UnionRenderer(genTO).generateTemplate();
+            } else if (genTO.isUnionTypeBuilder()) {
+                return new UnionBuilderRenderer(genTO).generateTemplate();
+            } else {
+                return new ClassRenderer(genTO).generateTemplate();
+            }
+        }
+        return "";
+    }
+
+    @Override
+    public boolean isAcceptable(Type type) {
+        return type instanceof GeneratedTransferObject;
+    }
+
+    @Override
+    public Identifier getUnitName(Type type) {
+        return new UnitName(type.getName());
+    }
+}
\ No newline at end of file
diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/renderers/InterfaceRenderer.java b/binding2/mdsal-binding2-java-api-generator/src/main/java/org/opendaylight/mdsal/binding2/java/api/generator/renderers/InterfaceRenderer.java
new file mode 100644 (file)
index 0000000..6234b61
--- /dev/null
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ */
+
+package org.opendaylight.mdsal.binding2.java.api.generator.renderers;
+
+import static org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.asJavadoc;
+import static org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.getJavaDocForInterface;
+
+import com.google.common.base.Preconditions;
+import java.util.ArrayList;
+import java.util.List;
+import org.opendaylight.mdsal.binding2.model.api.AnnotationType;
+import org.opendaylight.mdsal.binding2.model.api.Constant;
+import org.opendaylight.mdsal.binding2.model.api.Enumeration;
+import org.opendaylight.mdsal.binding2.model.api.GeneratedTransferObject;
+import org.opendaylight.mdsal.binding2.model.api.GeneratedType;
+import org.opendaylight.mdsal.binding2.model.api.MethodSignature;
+import org.opendaylight.mdsal.binding2.model.api.Type;
+import org.opendaylight.mdsal.binding2.txt.enumTemplate;
+import org.opendaylight.mdsal.binding2.txt.interfaceTemplate;
+
+public class InterfaceRenderer extends BaseRenderer {
+    /**
+     * Creates the instance of this class which is used for generating the interface file source
+     * code from <code>type</code>.
+     * @param type generated type
+     */
+    public InterfaceRenderer(final GeneratedType type) {
+        super(type);
+        Preconditions.checkNotNull(type, "Generated type reference cannot be NULL!");
+    }
+
+    @Override
+    protected String body() {
+        // mainAnnotations string with annotations for whole interface
+        final String mainAnnotations = generateAnnotations(getType().getAnnotations());
+        // StringBuilder string with the declaration of methods source code in JAVA format
+        final StringBuilder sb1 = new StringBuilder();
+        for (MethodSignature method : getType().getMethodDefinitions()) {
+            if (isAccessor(method)) {
+                sb1.append(asJavadoc(method.getComment()));
+            } else {
+                sb1.append(getJavaDocForInterface(method));
+            }
+            sb1.append(generateAnnotations(method.getAnnotations()))
+                .append(importedName(method.getReturnType()))
+                .append(' ')
+                .append(method.getName())
+                .append('(')
+                .append(generateParameters(method.getParameters()))
+                .append(");");
+        }
+        final String methodList = sb1.toString();
+
+        // enums string with rendered enums from template
+        final StringBuilder sb2 = new StringBuilder();
+        for (Enumeration enumeration : getType().getEnumerations()) {
+            final String importedName = importedName(String.class);
+            final String enumBody = enumTemplate.render(enumeration, importedName).body();
+            sb2.append(enumBody);
+        }
+        final String enums = sb2.toString();
+
+        final String generatedImports = generateImports(getType().getImplements());
+        // generatedConstants list of constants
+        final List<String> strings = new ArrayList<>(getType().getConstantDefinitions().size());
+        for (Constant constant : getType().getConstantDefinitions()) {
+            strings.add(emitConstant(constant));
+        }
+
+        final String generatedConstants = String.join("\n", strings);
+
+        final List<String> innerClassesBuilder = new ArrayList<>(getType().getEnclosedTypes().size());
+        for (GeneratedType innerClass : getType().getEnclosedTypes()) {
+            if (innerClass instanceof GeneratedTransferObject) {
+                if (((GeneratedTransferObject) innerClass).isUnionType()) {
+                    final UnionRenderer unionRenderer = new UnionRenderer((GeneratedTransferObject) innerClass);
+                    innerClassesBuilder.add(unionRenderer.body());
+                    this.getImportMap().putAll(unionRenderer.getImportMap());
+                } else {
+                    final ClassRenderer classRenderer = new ClassRenderer((GeneratedTransferObject) innerClass);
+                    innerClassesBuilder.add(classRenderer.generateAsInnerClass());
+                    this.getImportMap().putAll(classRenderer.getImportMap());
+                }
+            }
+        }
+        final String innerClasses = String.join("\n", strings);
+
+        return interfaceTemplate.render(getType(), enums, mainAnnotations, methodList, generatedImports,
+                generatedConstants, innerClasses).body();
+    }
+
+    private boolean isAccessor (final MethodSignature maybeGetter) {
+        return maybeGetter.getName().startsWith("is") || maybeGetter.getName().startsWith("get");
+    }
+
+    /**
+     * @param annotationTypeList list of annotations
+     * @return String of annotations in format:
+     * "@"annotation
+     * (parameterName1=ParameterSingleValue1,...)
+     *
+     */
+    private String generateAnnotations(final List<AnnotationType> annotationTypeList) {
+        final StringBuilder sb1 = new StringBuilder();
+        for (AnnotationType annotationType : annotationTypeList) {
+            sb1.append('@').append(importedName(annotationType));
+            if (!annotationType.getParameters().isEmpty()) {
+                sb1.append('(');
+            }
+            final List<String> parameterList = new ArrayList<>(annotationType.getParameters().size());
+            for (AnnotationType.Parameter parameter : annotationType.getParameters()) {
+                final StringBuilder sb2 = new StringBuilder();
+                sb2.append(parameter.getName())
+                   .append('=')
+                   .append(parameter.getSingleValue());
+                parameterList.add(sb2.toString());
+            }
+            sb1.append(String.join(",", parameterList))
+               .append(')');
+        }
+        return sb1.toString();
+    }
+
+    /**
+     * @param parameters list of parameters
+     * @return list of parameters separated with ","
+     */
+    private String generateImports(final List<Type> parameters) {
+        final List<String> strings = new ArrayList<>(parameters.size());
+        for (Type parameter : parameters) {
+            strings.add(importedName(parameter));
+        }
+
+        return String.join(",", strings);
+    }
+}
\ No newline at end of file
diff --git a/binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding2/interfaceTemplate.scala.txt b/binding2/mdsal-binding2-java-api-generator/src/main/twirl/org/opendaylight/mdsal/binding2/interfaceTemplate.scala.txt
new file mode 100644 (file)
index 0000000..e67cb1c
--- /dev/null
@@ -0,0 +1,32 @@
+@*
+ * Copyright (c) 2016 Cisco Systems, Inc. and others.  All rights reserved.
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License v1.0 which accompanies this distribution,
+ * and is available at http://www.eclipse.org/legal/epl-v10.html
+ *@
+
+@import org.opendaylight.mdsal.binding2.model.api.GeneratedTransferObject
+@import org.opendaylight.mdsal.binding2.model.api.GeneratedType
+@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.formatDataForJavaDoc
+@import org.opendaylight.mdsal.binding2.java.api.generator.util.TextTemplateUtil.wrapToDocumentation
+
+@(genType: GeneratedType, enums: String, annotations: String, generatedMethods: String, generatedImports: String,
+generatedConstants: String, innerClasses: String)
+@*
+ * Template method which generate the whole body of the interface.
+ *
+ * @return string with code for interface body in JAVA format
+ *@
+@if(genType != null) {
+@{wrapToDocumentation(formatDataForJavaDoc(genType))}
+@{annotations}
+public interface @{genType.getName}
+    @if(!generatedImports.isEmpty){extends @{generatedImports}}
+{
+    @{innerClasses}
+    @{enums}
+    @{generatedConstants}
+    @{generatedMethods}
+}
+}
\ No newline at end of file