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.java.api.generator.renderers;
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;
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 import java.beans.ConstructorProperties;
20 import java.util.ArrayList;
21 import java.util.Arrays;
22 import java.util.Collection;
23 import java.util.Collections;
24 import java.util.Comparator;
25 import java.util.HashMap;
26 import java.util.LinkedList;
27 import java.util.List;
29 import java.util.Objects;
30 import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.AbstractRangeGenerator;
31 import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.LengthGenerator;
32 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplate;
33 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateConstructors;
34 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateRestrictions;
35 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.classTemplateUnionConstr;
36 import org.opendaylight.mdsal.binding.javav2.java.api.generator.txt.constantsTemplate;
37 import org.opendaylight.mdsal.binding.javav2.model.api.Constant;
38 import org.opendaylight.mdsal.binding.javav2.model.api.Enumeration;
39 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty;
40 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject;
41 import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType;
42 import org.opendaylight.mdsal.binding.javav2.model.api.Restrictions;
43 import org.opendaylight.mdsal.binding.javav2.model.api.Type;
44 import org.opendaylight.yangtools.yang.common.QName;
46 public class ClassRenderer extends BaseRenderer {
47 protected final GeneratedTransferObject genTO;
48 protected final Restrictions restrictions;
49 private final List<GeneratedProperty> properties;
50 private final List<GeneratedProperty> finalProperties;
51 private final List<GeneratedProperty> parentProperties;
52 private final List<Enumeration> enums;
53 private final List<Constant> consts;
54 private final List<GeneratedType> enclosedGeneratedTypes;
55 private final List<GeneratedProperty> allProperties;
57 private final AbstractRangeGenerator<?> rangeGenerator;
59 public ClassRenderer(final GeneratedTransferObject genType) {
62 properties = ImmutableList.copyOf(genTO.getProperties());
63 finalProperties = ImmutableList.copyOf(resolveReadOnlyPropertiesFromTO(genTO.getProperties()));
64 parentProperties = ImmutableList.copyOf(getPropertiesOfAllParents(genTO));
65 enums = ImmutableList.copyOf(genTO.getEnumerations());
66 consts = ImmutableList.copyOf(genTO.getConstantDefinitions());
67 enclosedGeneratedTypes = ImmutableList.copyOf(genTO.getEnclosedTypes());
68 restrictions = genTO.getRestrictions();
70 final List<GeneratedProperty> sorted = new ArrayList<>();
71 sorted.addAll(properties);
72 sorted.addAll(parentProperties);
73 final Comparator<GeneratedProperty> function = (GeneratedProperty p1, GeneratedProperty p2) -> {
74 final String name = p1.getName();
75 final String name1 = p2.getName();
76 return name.compareTo(name1);
78 Collections.sort(sorted, function);
79 allProperties = ImmutableList.copyOf(sorted);
81 if (restrictions != null && restrictions.getRangeConstraint().isPresent()) {
82 rangeGenerator = AbstractRangeGenerator.forType(findProperty(genType, "value").getReturnType());
83 Preconditions.checkNotNull(rangeGenerator);
85 rangeGenerator = null;
89 protected List<GeneratedProperty> getProperties() {
93 protected List<GeneratedProperty> getFinalProperties() {
94 return finalProperties;
97 protected List<GeneratedProperty> getParentProperties() {
98 return parentProperties;
101 protected List<Enumeration> getEnums() {
105 protected List<Constant> getConsts() {
109 protected List<GeneratedType> getEnclosedGeneratedTypes() {
110 return enclosedGeneratedTypes;
113 protected Collection<GeneratedProperty> getAllProperties() {
114 return allProperties;
117 protected String generateAsInnerClass() {
118 return generateBody(true);
122 protected String body() {
123 return generateBody(false);
126 protected String generateInnerClassBody(final GeneratedTransferObject innerClass) {
127 final ClassRenderer classRenderer = new ClassRenderer(innerClass);
128 final String body = classRenderer.generateAsInnerClass();
129 this.putAllToImportMap(classRenderer.getImportMap());
133 protected String generateBody(final boolean isInnerClass) {
134 getImportedNames().put("type", importedName(getType()));
135 getImportedNames().put("arrays", importedName(Arrays.class));
136 getImportedNames().put("objects", importedName(Objects.class));
137 getImportedNames().put("string", importedName(String.class));
138 getImportedNames().put("byte", importedName(Byte.class));
139 getImportedNames().put("short", importedName(Short.class));
140 getImportedNames().put("integer", importedName(Integer.class));
141 getImportedNames().put("long", importedName(Long.class));
142 getImportedNames().put("stringBuilder", importedName(StringBuilder.class));
143 getImportedNames().put("list", importedName(List.class));
144 getImportedNames().put("lists", importedName(Lists.class));
145 getImportedNames().put("illegalArgumentException", importedName(IllegalArgumentException.class));
146 getImportedNames().put("boolean", importedName(Boolean.class));
147 getImportedNames().put("qname", importedName(QName.class));
149 final List<String> implementsListBuilder = new LinkedList<>();
150 if (!getType().getImplements().isEmpty()) {
151 for (Type impl : getType().getImplements()) {
152 implementsListBuilder.add((importedName(impl)));
155 final String implementsList = String.join(", ", implementsListBuilder);
157 final List<String> classTemplateBuilder = new LinkedList<>();
158 if (!enclosedGeneratedTypes.isEmpty()) {
159 for (GeneratedType innerClass : enclosedGeneratedTypes) {
160 if (innerClass instanceof GeneratedTransferObject) {
161 classTemplateBuilder.add(generateInnerClassBody((GeneratedTransferObject)innerClass));
165 final String innerClasses = String.join("\n", classTemplateBuilder);
167 final List<String> enumList = new LinkedList<>();
168 if (!enums.isEmpty()) {
169 for (Enumeration enumeration : enums) {
170 enumList.add(new EnumRenderer(enumeration).body());
173 final String enumerations = String.join("\n", enumList);
175 final String constants = constantsTemplate.render(getType(), getImportedNames(), this::importedName, false).body();
177 if (genTO.getSuperType() != null) {
178 getImportedNames().put("superType", importedName(genTO.getSuperType()));
181 for (GeneratedProperty property : properties) {
182 getImportedNames().put(property.getReturnType().toString(), importedName(property.getReturnType()));
185 final String constructors = generateConstructors();
187 final StringBuilder lengthRangeCheckerBuilder = new StringBuilder();
188 if (restrictions != null) {
189 if (restrictions.getLengthConstraint().isPresent()) {
190 lengthRangeCheckerBuilder.append(LengthGenerator.generateLengthChecker("_value", findProperty(genTO,
191 "value").getReturnType(), restrictions.getLengthConstraint().get()))
194 if (restrictions.getRangeConstraint().isPresent()) {
195 lengthRangeCheckerBuilder.append(rangeGenerator.generateRangeChecker("_value", restrictions
196 .getRangeConstraint().get()))
200 final String lengthRangeChecker = lengthRangeCheckerBuilder.toString();
202 final StringBuilder sb2 = new StringBuilder();
203 if (!properties.isEmpty()) {
204 for (GeneratedProperty property : properties) {
205 final String isFinal = property.isReadOnly() ? " final " : " ";
206 sb2.append("private")
208 .append(importedName(property.getReturnType()))
210 .append(fieldName(property))
214 final String fields = sb2.toString();
215 getImportedNames().put("baseEncoding", importedName(BaseEncoding.class));
216 if (!allProperties.isEmpty()) {
217 getImportedNames().put("defProp", importedName(((GeneratedProperty)((List) allProperties).get(0)).getReturnType()));
220 final StringBuilder sb3 = new StringBuilder();
221 for (GeneratedProperty property : properties) {
222 sb3.append(getterMethod(property));
223 if (!property.isReadOnly()) {
224 sb3.append(setterMethod(property, getType().getName(), importedName(property
228 final String propertyMethod = sb3.toString();
230 return classTemplate.render(getType(), genTO, getImportedNames(), implementsList, innerClasses, enumerations,
231 constants, constructors, lengthRangeChecker, fields, allProperties, propertyMethod,
232 isInnerClass).body();
235 protected String generateConstructors() {
236 getImportedNames().put("constructorProperties", importedName(ConstructorProperties.class));
237 getImportedNames().put("preconditions", importedName(Preconditions.class));
239 final StringBuilder sb1 = new StringBuilder();
240 for (GeneratedProperty allProperty : allProperties) {
241 sb1.append(classTemplateRestrictions.render(getType(), fieldName(allProperty), allProperty
242 .getReturnType(), rangeGenerator).body());
244 final String genRestrictions = sb1.toString();
246 final StringBuilder sb2 = new StringBuilder();
247 if (genTO.isUnionType()) {
248 for (GeneratedProperty allProperty : allProperties) {
249 final List other = new ArrayList<>(properties);
250 if (other.remove(allProperty)) {
251 sb2.append(classTemplateUnionConstr.render(getType(), parentProperties, allProperty,
252 other, importedName(allProperty.getReturnType()), genRestrictions).body());
256 final String unionConstructor = sb2.toString();
258 final String argumentsDeclaration = asArgumentsDeclaration(allProperties);
259 return classTemplateConstructors.render(genTO, allProperties, properties, parentProperties,
260 getImportedNames(), argumentsDeclaration, unionConstructor, genRestrictions).body();
264 * Selects from input list of properties only those which have read only
265 * attribute set to true.
268 * list of properties of generated transfer object
269 * @return subset of <code>properties</code> which have read only attribute
272 private List<GeneratedProperty> resolveReadOnlyPropertiesFromTO(final List<GeneratedProperty> properties) {
273 return new ArrayList<>(Collections2.filter(properties, GeneratedProperty::isReadOnly));
277 * Returns the list of the read only properties of all extending generated
278 * transfer object from <code>genTO</code> to highest parent generated
282 * generated transfer object for which is the list of read only
283 * properties generated
284 * @return list of all read only properties from actual to highest parent
285 * generated transfer object. In case when extension exists the
286 * method is recursive called.
288 private List<GeneratedProperty> getPropertiesOfAllParents(final GeneratedTransferObject genTO) {
289 final List<GeneratedProperty> propertiesOfAllParents = new ArrayList<>();
290 if (genTO.getSuperType() != null) {
291 final List<GeneratedProperty> allPropertiesOfTO = genTO.getSuperType().getProperties();
292 List<GeneratedProperty> readOnlyPropertiesOfTO = resolveReadOnlyPropertiesFromTO(allPropertiesOfTO);
293 propertiesOfAllParents.addAll(readOnlyPropertiesOfTO);
294 propertiesOfAllParents.addAll(getPropertiesOfAllParents(genTO.getSuperType()));
296 return propertiesOfAllParents;