470632bd204dd3e5f1049f5001200dd14b5e8e99
[mdsal.git] / binding2 / mdsal-binding2-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / javav2 / java / api / generator / renderers / InterfaceRenderer.java
1 /*
2  * Copyright (c) 2017 Cisco Systems, Inc. and others.  All rights reserved.
3  *
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
7  */
8
9 package org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers;
10
11 import com.google.common.base.Preconditions;
12 import java.util.AbstractMap.SimpleEntry;
13 import java.util.ArrayDeque;
14 import java.util.ArrayList;
15 import java.util.Deque;
16 import java.util.List;
17 import java.util.Map.Entry;
18 import java.util.Optional;
19 import org.opendaylight.mdsal.binding.javav2.generator.util.BindingTypes;
20 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifier;
21 import org.opendaylight.mdsal.binding.javav2.generator.util.JavaIdentifierNormalizer;
22 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.constantsTemplate;
23 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.enumTemplate;
24 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.interfaceTemplate;
25 import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil;
26 import org.opendaylight.mdsal.binding.javav2.model.api.AnnotationType;
27 import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration;
28 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
29 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
30 import org.opendaylight.mdsal.binding.javav2.model.api.MethodSignature;
31 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
32 import org.opendaylight.mdsal.binding.javav2.model.api.type.builder.GeneratedTypeBuilder;
33 import org.opendaylight.mdsal.binding.javav2.spec.base.InstanceIdentifier;
34 import org.opendaylight.mdsal.binding.javav2.spec.runtime.BindingNamespaceType;
35 import org.opendaylight.yangtools.yang.common.QName;
36
37 public class InterfaceRenderer extends BaseRenderer {
38
39     private static final char NEW_LINE = '\n';
40
41     /**
42      * Creates the instance of this class which is used for generating the interface file source
43      * code from <code>type</code>.
44      * @param type generated type
45      */
46     public InterfaceRenderer(final GeneratedType type) {
47         super(type);
48         Preconditions.checkNotNull(type, "Generated type reference cannot be NULL!");
49     }
50
51     @Override
52     protected String body() {
53         // mainAnnotations string with annotations for whole interface
54         final String mainAnnotations = generateAnnotations(getType().getAnnotations());
55         // StringBuilder string with the declaration of methods source code in JAVA format
56         final StringBuilder sb1 = new StringBuilder();
57         for (MethodSignature method : getType().getMethodDefinitions()) {
58             if (isAccessor(method)) {
59                 sb1.append(TextTemplateUtil.asJavadoc(method.getComment()));
60             } else {
61                 sb1.append(TextTemplateUtil.getJavaDocForInterface(method));
62             }
63             sb1.append(generateAnnotations(method.getAnnotations()))
64                 .append(importedName(method.getReturnType()))
65                 .append(' ')
66                 .append(method.getName())
67                 .append('(')
68                 .append(generateParameters(method.getParameters()))
69                 .append(");")
70                 .append(NEW_LINE);
71         }
72         final String methodList = sb1.toString();
73
74         // enums string with rendered enums from template
75         final StringBuilder sb2 = new StringBuilder();
76         for (Enumeration enumeration : getType().getEnumerations()) {
77             final String importedName = importedName(String.class);
78             final String enumBody = enumTemplate.render(enumeration, importedName).body();
79             sb2.append(enumBody);
80         }
81         final String enums = sb2.toString();
82
83         final String generatedImports = generateImports(getType().getImplements());
84
85         getImportedNames().put("qname", importedName(QName.class));
86         final String generatedConstants = constantsTemplate.render(getType(), getImportedNames(),
87             this::importedName, true).body();
88
89         final Entry<String, String> identifier = generateInstanceIdentifier();
90
91         final List<String> innerClasses = new ArrayList<>(getType().getEnclosedTypes().size());
92         for (GeneratedType innerClass : getType().getEnclosedTypes()) {
93             if (innerClass instanceof GeneratedTransferObject) {
94                 if (((GeneratedTransferObject) innerClass).isUnionType()) {
95                     final UnionRenderer unionRenderer = new UnionRenderer((GeneratedTransferObject) innerClass);
96                     innerClasses.add(unionRenderer.generateAsInnerClass());
97                     this.putAllToImportMap(unionRenderer.getImportMap());
98                 } else {
99                     final ClassRenderer classRenderer = new ClassRenderer((GeneratedTransferObject) innerClass);
100                     innerClasses.add(classRenderer.generateAsInnerClass());
101                     this.putAllToImportMap(classRenderer.getImportMap());
102                 }
103             }
104         }
105         final String generatedInnerClasses = String.join("\n", innerClasses);
106
107         return interfaceTemplate.render(getType(), enums, mainAnnotations, methodList, generatedImports,
108                 generatedConstants, generatedInnerClasses, identifier.getKey(), identifier.getValue()).body();
109     }
110
111     private static boolean isAccessor(final MethodSignature maybeGetter) {
112         return maybeGetter.getName().startsWith("is") || maybeGetter.getName().startsWith("get");
113     }
114
115     /**
116      * @param annotationTypeList list of annotations
117      * @return String of annotations in format:
118      * "@"annotation
119      * (parameterName1=ParameterSingleValue1,...)
120      *
121      */
122     private String generateAnnotations(final List<AnnotationType> annotationTypeList) {
123         final StringBuilder sb1 = new StringBuilder();
124         for (AnnotationType annotationType : annotationTypeList) {
125             sb1.append('@').append(importedName(annotationType));
126             if (!annotationType.getParameters().isEmpty()) {
127                 sb1.append('(');
128             }
129             final List<String> parameterList = new ArrayList<>(annotationType.getParameters().size());
130             for (AnnotationType.Parameter parameter : annotationType.getParameters()) {
131                 final StringBuilder sb2 = new StringBuilder();
132                 sb2.append(parameter.getName())
133                    .append('=')
134                    .append(parameter.getSingleValue());
135                 parameterList.add(sb2.toString());
136             }
137             sb1.append(String.join(",", parameterList));
138             if (!annotationType.getParameters().isEmpty()) {
139                 sb1.append(')');
140             }
141             sb1.append(NEW_LINE);
142         }
143         return sb1.toString();
144     }
145
146     /**
147      * Generate default method getInstanceIdentifier.
148      * @return  string pair of instance identifier and key parameters
149      */
150     private Entry<String, String> generateInstanceIdentifier() {
151         //Only tree data nodes need to generate the method.
152         if (null == getType().getBindingNamespaceType() ||
153             !BindingNamespaceType.isTreeData(getType().getBindingNamespaceType()) ||
154             !getType().getImplements().contains(BindingTypes.TREE_CHILD_NODE) ) {
155             return new SimpleEntry<>(null, null);
156         }
157
158         final Deque<GeneratedType> dataPath = new ArrayDeque<>();
159         GeneratedType type = getType();
160         GeneratedTypeBuilder parentTypeBuilder;
161
162         while (type != null) {
163             dataPath.push(type);
164             importedName(type);
165             parentTypeBuilder = (GeneratedTypeBuilder) type.getParentTypeForBuilder();
166             type = parentTypeBuilder != null ? parentTypeBuilder.toInstance() : null;
167         }
168
169         dataPath.pop();
170
171         final StringBuilder iiBuidler = new StringBuilder();
172         type = dataPath.pop();
173         iiBuidler.append("InstanceIdentifier.builder(").append(type.getName()).append(".class)");
174         importedName(InstanceIdentifier.class);
175         final List<String> keys = new ArrayList<>();
176         while (dataPath.peek() != null) {
177             type = dataPath.pop();
178             if (type.getImplements().contains(BindingTypes.AUGMENTATION)) {
179                 iiBuidler.append(".augmentation(").append(type.getName()).append(".class)");
180             } else {
181                 Optional<MethodSignature> method = type.getMethodDefinitions().stream().filter(m ->
182                     m.getName().equals("getIdentifier")).findFirst();
183                 if (method.isPresent()) {
184                     importedName(method.get().getReturnType());
185                     final String keyName = method.get().getReturnType().getName();
186                     final String normalizedKeyName = JavaIdentifierNormalizer.normalizeSpecificIdentifier(keyName,
187                         JavaIdentifier.METHOD);
188                     keys.add(new StringBuilder().append("final ").append(keyName).append(" _")
189                         .append(normalizedKeyName).toString());
190                     iiBuidler.append(".child(").append(type.getFullyQualifiedName()).append(".class, _")
191                         .append(normalizedKeyName).append(")");
192                 } else {
193                     iiBuidler.append(".child(").append(type.getFullyQualifiedName()).append(".class)");
194                 }
195             }
196         }
197         iiBuidler.append(".build()");
198         return new SimpleEntry<>(iiBuidler.toString(), String.join(", ", keys));
199     }
200
201
202     /**
203      * @param parameters list of parameters
204      * @return list of parameters separated with ","
205      */
206     private String generateImports(final List<Type> parameters) {
207         final List<String> strings = new ArrayList<>(parameters.size());
208         for (Type parameter : parameters) {
209             strings.add(importedName(parameter));
210         }
211
212         return String.join(", ", strings);
213     }
214 }