Fix checkstyle in mdsal-binding2-java-api-generator
[mdsal.git] / binding2 / mdsal-binding2-java-api-generator / src / main / java / org / opendaylight / mdsal / binding / javav2 / java / api / generator / renderers / ClassRenderer.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 static org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.fieldName;
12 import static org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.setterMethod;
13
14 import com.google.common.base.Preconditions;
15 import com.google.common.collect.Collections2;
16 import com.google.common.collect.ImmutableList;
17 import com.google.common.collect.Lists;
18 import com.google.common.io.BaseEncoding;
19
20 import java.beans.ConstructorProperties;
21 import java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.Collection;
24 import java.util.Comparator;
25 import java.util.LinkedList;
26 import java.util.List;
27 import java.util.Objects;
28
29 import org.opendaylight.mdsal.binding.javav2.java.api.generator.range_generators.AbstractRangeGenerator;
30 import org.opendaylight.mdsal.binding.javav2.java.api.generator.range_generators.LengthGenerator;
31 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplate;
32 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateConstructors;
33 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateRestrictions;
34 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateUnionConstr;
35 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.constantsTemplate;
36 import org.opendaylight.mdsal.binding.javav2.model.api.Constant;
37 import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration;
38 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty;
39 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
40 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
41 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
42 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
43 import org.opendaylight.yangtools.yang.common.QName;
44 import org.opendaylight.yangtools.yang.common.Uint16;
45 import org.opendaylight.yangtools.yang.common.Uint32;
46 import org.opendaylight.yangtools.yang.common.Uint64;
47 import org.opendaylight.yangtools.yang.common.Uint8;
48
49 public class ClassRenderer extends BaseRenderer {
50     protected final GeneratedTransferObject genTO;
51     protected final Restrictions restrictions;
52     private final List<GeneratedProperty> properties;
53     private final List<GeneratedProperty> finalProperties;
54     private final List<GeneratedProperty> parentProperties;
55     private final List<Enumeration> enums;
56     private final List<Constant> consts;
57     private final List<GeneratedType> enclosedGeneratedTypes;
58     private final List<GeneratedProperty> allProperties;
59
60     private final AbstractRangeGenerator<?> rangeGenerator;
61
62     public ClassRenderer(final GeneratedTransferObject genType) {
63         super(genType);
64         genTO = genType;
65         properties = ImmutableList.copyOf(genTO.getProperties());
66         finalProperties = ImmutableList.copyOf(resolveReadOnlyPropertiesFromTO(genTO.getProperties()));
67         parentProperties = ImmutableList.copyOf(getPropertiesOfAllParents(genTO));
68         enums = ImmutableList.copyOf(genTO.getEnumerations());
69         consts = ImmutableList.copyOf(genTO.getConstantDefinitions());
70         enclosedGeneratedTypes = ImmutableList.copyOf(genTO.getEnclosedTypes());
71         restrictions = genTO.getRestrictions();
72
73         final List<GeneratedProperty> sorted = new ArrayList<>();
74         sorted.addAll(properties);
75         sorted.addAll(parentProperties);
76         final Comparator<GeneratedProperty> function = (GeneratedProperty p1, GeneratedProperty p2) -> {
77             final String name = p1.getName();
78             final String name1 = p2.getName();
79             return name.compareTo(name1);
80         };
81         sorted.sort(function);
82         allProperties = ImmutableList.copyOf(sorted);
83
84         if (restrictions != null && restrictions.getRangeConstraint().isPresent()) {
85             rangeGenerator = AbstractRangeGenerator.forType(findProperty(genType, "value").getReturnType());
86             Preconditions.checkNotNull(rangeGenerator);
87         } else {
88             rangeGenerator = null;
89         }
90     }
91
92     protected List<GeneratedProperty> getProperties() {
93         return properties;
94     }
95
96     protected List<GeneratedProperty> getFinalProperties() {
97         return finalProperties;
98     }
99
100     protected List<GeneratedProperty> getParentProperties() {
101         return parentProperties;
102     }
103
104     protected List<Enumeration> getEnums() {
105         return enums;
106     }
107
108     protected List<Constant> getConsts() {
109         return consts;
110     }
111
112     protected List<GeneratedType> getEnclosedGeneratedTypes() {
113         return enclosedGeneratedTypes;
114     }
115
116     protected Collection<GeneratedProperty> getAllProperties() {
117         return allProperties;
118     }
119
120     protected String generateAsInnerClass() {
121         return generateBody(true);
122     }
123
124     @Override
125     protected String body() {
126         return generateBody(false);
127     }
128
129     protected String generateInnerClassBody(final GeneratedTransferObject innerClass) {
130         final ClassRenderer classRenderer = new ClassRenderer(innerClass);
131         final String body = classRenderer.generateAsInnerClass();
132         this.putAllToImportMap(classRenderer.getImportMap());
133         return body;
134     }
135
136     protected String generateBody(final boolean isInnerClass) {
137         getImportedNames().put("type", importedName(getType()));
138         getImportedNames().put("arrays", importedName(Arrays.class));
139         getImportedNames().put("objects", importedName(Objects.class));
140         getImportedNames().put("string", importedName(String.class));
141         getImportedNames().put("byte", importedName(Byte.class));
142         getImportedNames().put("short", importedName(Short.class));
143         getImportedNames().put("integer", importedName(Integer.class));
144         getImportedNames().put("long", importedName(Long.class));
145         getImportedNames().put("uint8", importedName(Uint8.class));
146         getImportedNames().put("uint16", importedName(Uint16.class));
147         getImportedNames().put("uint32", importedName(Uint32.class));
148         getImportedNames().put("uint64", importedName(Uint64.class));
149         getImportedNames().put("stringBuilder", importedName(StringBuilder.class));
150         getImportedNames().put("list", importedName(List.class));
151         getImportedNames().put("lists", importedName(Lists.class));
152         getImportedNames().put("illegalArgumentException", importedName(IllegalArgumentException.class));
153         getImportedNames().put("boolean", importedName(Boolean.class));
154         getImportedNames().put("qname", importedName(QName.class));
155
156         final List<String> implementsListBuilder = new LinkedList<>();
157         if (!getType().getImplements().isEmpty()) {
158             for (Type impl : getType().getImplements()) {
159                 implementsListBuilder.add((importedName(impl)));
160             }
161         }
162         final String implementsList = String.join(", ", implementsListBuilder);
163
164         final List<String> classTemplateBuilder = new LinkedList<>();
165         if (!enclosedGeneratedTypes.isEmpty()) {
166             for (GeneratedType innerClass : enclosedGeneratedTypes) {
167                 if (innerClass instanceof GeneratedTransferObject) {
168                     classTemplateBuilder.add(generateInnerClassBody((GeneratedTransferObject) innerClass));
169                 }
170             }
171         }
172         final String innerClasses = String.join("\n", classTemplateBuilder);
173
174         final List<String> enumList = new LinkedList<>();
175         if (!enums.isEmpty()) {
176             for (Enumeration enumeration : enums) {
177                 enumList.add(new EnumRenderer(enumeration).body());
178             }
179         }
180         final String enumerations = String.join("\n", enumList);
181
182         final String constants = constantsTemplate.render(getType(), getImportedNames(), this::importedName, false)
183                 .body();
184
185         if (genTO.getSuperType() != null) {
186             getImportedNames().put("superType", importedName(genTO.getSuperType()));
187         }
188
189         for (GeneratedProperty property : properties) {
190             getImportedNames().put(property.getReturnType().toString(), importedName(property.getReturnType()));
191         }
192
193         final String constructors = generateConstructors();
194
195         final StringBuilder lengthRangeCheckerBuilder = new StringBuilder();
196         if (restrictions != null) {
197             if (restrictions.getLengthConstraint().isPresent()) {
198                 lengthRangeCheckerBuilder.append(LengthGenerator.generateLengthChecker("_value", findProperty(genTO,
199                         "value").getReturnType(), restrictions.getLengthConstraint().get()))
200                         .append("\n");
201             }
202             if (restrictions.getRangeConstraint().isPresent()) {
203                 lengthRangeCheckerBuilder.append(rangeGenerator.generateRangeChecker("_value", restrictions
204                         .getRangeConstraint().get()))
205                         .append("\n");
206             }
207         }
208         final String lengthRangeChecker = lengthRangeCheckerBuilder.toString();
209
210         final StringBuilder sb2 = new StringBuilder();
211         if (!properties.isEmpty()) {
212             for (GeneratedProperty property : properties) {
213                 final String isFinal = property.isReadOnly() ? " final " : " ";
214                 sb2.append("private")
215                         .append(isFinal)
216                         .append(importedName(property.getReturnType()))
217                         .append(' ')
218                         .append(fieldName(property))
219                         .append(";\n");
220             }
221         }
222         final String fields = sb2.toString();
223         getImportedNames().put("baseEncoding", importedName(BaseEncoding.class));
224         if (!allProperties.isEmpty()) {
225             getImportedNames().put("defProp", importedName(((GeneratedProperty) ((List) allProperties).get(0))
226                     .getReturnType()));
227         }
228
229         final StringBuilder sb3 = new StringBuilder();
230         for (GeneratedProperty property : properties) {
231             sb3.append(getterMethod(property));
232             if (!property.isReadOnly()) {
233                 sb3.append(setterMethod(property, getType().getName(), importedName(property
234                         .getReturnType())));
235             }
236         }
237         final String propertyMethod = sb3.toString();
238
239         return classTemplate.render(getType(), genTO, getImportedNames(), implementsList, innerClasses, enumerations,
240                 constants, constructors, lengthRangeChecker, fields, allProperties, propertyMethod,
241                 isInnerClass).body();
242     }
243
244     protected String generateConstructors() {
245         getImportedNames().put("constructorProperties", importedName(ConstructorProperties.class));
246         getImportedNames().put("preconditions", importedName(Preconditions.class));
247
248         final StringBuilder sb1 = new StringBuilder();
249         for (GeneratedProperty allProperty : allProperties) {
250             sb1.append(classTemplateRestrictions.render(getType(), fieldName(allProperty), allProperty
251                     .getReturnType(), rangeGenerator).body());
252         }
253         final String genRestrictions = sb1.toString();
254
255         final StringBuilder sb2 = new StringBuilder();
256         if (genTO.isUnionType()) {
257             for (GeneratedProperty allProperty : allProperties) {
258                 final List other = new ArrayList<>(properties);
259                 if (other.remove(allProperty)) {
260                     sb2.append(classTemplateUnionConstr.render(getType(), parentProperties, allProperty,
261                             other, importedName(allProperty.getReturnType()), genRestrictions).body());
262                 }
263             }
264         }
265         final String unionConstructor = sb2.toString();
266
267         final String argumentsDeclaration = asArgumentsDeclaration(allProperties);
268         return classTemplateConstructors.render(genTO, allProperties, properties, parentProperties,
269                 getImportedNames(), argumentsDeclaration, unionConstructor, genRestrictions).body();
270     }
271
272     /**
273      * Selects from input list of properties only those which have read only
274      * attribute set to true.
275      *
276      * @param props list of properties of generated transfer object
277      * @return subset of <code>properties</code> which have read only attribute
278      *      set to true
279      */
280     private List<GeneratedProperty> resolveReadOnlyPropertiesFromTO(final List<GeneratedProperty> props) {
281         return new ArrayList<>(Collections2.filter(props, GeneratedProperty::isReadOnly));
282     }
283
284     /**
285      * Returns the list of the read only properties of all extending generated
286      * transfer object from <code>genTO</code> to highest parent generated
287      * transfer object.
288      *
289      * @param transferObject generated transfer object for which is the list of read only
290      *                       properties generated
291      * @return list of all read only properties from actual to highest parent
292      *      generated transfer object. In case when extension exists the
293      *      method is recursive called.
294      */
295     private List<GeneratedProperty> getPropertiesOfAllParents(final GeneratedTransferObject transferObject) {
296         final List<GeneratedProperty> propertiesOfAllParents = new ArrayList<>();
297         if (transferObject.getSuperType() != null) {
298             final List<GeneratedProperty> allPropertiesOfTO = transferObject.getSuperType().getProperties();
299             List<GeneratedProperty> readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO);
300             propertiesOfAllParents.addAll(readOnlyPropertiesOfTO);
301             propertiesOfAllParents.addAll(getPropertiesOfAllParents(transferObject.getSuperType()));
302         }
303         return propertiesOfAllParents;
304     }
305 }