2 * Copyright (c) 2014 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
8 package org.opendaylight.yangtools.sal.java.api.generator
10 import com.google.common.collect.ImmutableList
11 import com.google.common.collect.Lists
12 import com.google.common.collect.Range
13 import com.google.common.io.BaseEncoding
14 import java.beans.ConstructorProperties
15 import java.math.BigDecimal
16 import java.math.BigInteger
17 import java.util.ArrayList
18 import java.util.Arrays
19 import java.util.Collections
21 import java.util.regex.Pattern
22 import org.opendaylight.yangtools.binding.generator.util.TypeConstants
23 import org.opendaylight.yangtools.sal.binding.model.api.Constant
24 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
25 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
26 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
27 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
28 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
31 * Template for generating JAVA class.
33 class ClassTemplate extends BaseTemplate {
35 protected val List<GeneratedProperty> properties
36 protected val List<GeneratedProperty> finalProperties
37 protected val List<GeneratedProperty> parentProperties
38 protected val Iterable<GeneratedProperty> allProperties;
39 protected val Restrictions restrictions
42 * List of enumeration which are generated as JAVA enum type.
44 protected val List<Enumeration> enums
47 * List of constant instances which are generated as JAVA public static final attributes.
49 protected val List<Constant> consts
52 * List of generated types which are enclosed inside <code>genType</code>
54 protected val List<GeneratedType> enclosedGeneratedTypes;
56 protected val GeneratedTransferObject genTO;
59 * Creates instance of this class with concrete <code>genType</code>.
61 * @param genType generated transfer object which will be transformed to JAVA class source code
63 new(GeneratedTransferObject genType) {
66 this.properties = genType.properties
67 this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)
68 this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)
69 this.restrictions = genType.restrictions
71 var List<GeneratedProperty> sorted = new ArrayList<GeneratedProperty>();
72 sorted.addAll(properties);
73 sorted.addAll(parentProperties);
74 Collections.sort(sorted, [p1, p2|
75 p1.name.compareTo(p2.name)
78 this.allProperties = sorted
79 this.enums = genType.enumerations
80 this.consts = genType.constantDefinitions
81 this.enclosedGeneratedTypes = genType.enclosedTypes
85 * Generates JAVA class source code (class body only).
87 * @return string with JAVA class body source code
89 def CharSequence generateAsInnerClass() {
90 return generateBody(true)
93 override protected body() {
98 * Template method which generates class body.
100 * @param isInnerClass boolean value which specify if generated class is|isn't inner
101 * @return string with class source code in JAVA format
103 def protected generateBody(boolean isInnerClass) '''
104 «wrapToDocumentation(formatDataForJavaDoc(type))»
105 «generateClassDeclaration(isInnerClass)» {
107 «innerClassesDeclarations»
109 «constantsDeclarations»
112 «IF restrictions != null && (!restrictions.rangeConstraints.nullOrEmpty ||
113 !restrictions.lengthConstraints.nullOrEmpty)»
114 «generateConstraints»
121 «FOR field : properties SEPARATOR "\n"»
132 «generateToString(genTO.toStringIdentifiers)»
134 «generateLengthMethod("length", "_length")»
136 «generateRangeMethod("range", "_range")»
141 def private generateLengthMethod(String methodName, String varName) '''
142 «IF restrictions != null && !(restrictions.lengthConstraints.empty)»
143 «val numberClass = restrictions.lengthConstraints.iterator.next.min.class»
144 public static «List.importedName»<«Range.importedName»<«numberClass.importedNumber»>> «methodName»() {
150 def private generateRangeMethod(String methodName, String varName) '''
151 «IF restrictions != null && !(restrictions.rangeConstraints.empty)»
152 «val returnType = allProperties.iterator.next.returnType»
153 public static «List.importedName»<«Range.importedName»<«returnType.importedNumber»>> «methodName»() {
160 * Template method which generates inner classes inside this interface.
162 * @return string with the source code for inner classes in JAVA format
164 def protected innerClassesDeclarations() '''
165 «IF !enclosedGeneratedTypes.empty»
166 «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
167 «IF (innerClass instanceof GeneratedTransferObject)»
168 «val classTemplate = new ClassTemplate(innerClass as GeneratedTransferObject)»
169 «classTemplate.generateAsInnerClass»
176 def protected constructors() '''
178 «genUnionConstructor»
180 «allValuesConstructor»
182 «IF !allProperties.empty»
185 «IF properties.empty && !parentProperties.empty »
190 def private generateConstraints() '''
192 «IF !restrictions.rangeConstraints.nullOrEmpty»
193 «generateRangeConstraints»
195 «IF !restrictions.lengthConstraints.nullOrEmpty»
196 «generateLengthConstraints»
201 private def generateRangeConstraints() '''
202 «IF !allProperties.nullOrEmpty»
203 «val returnType = allProperties.iterator.next.returnType»
204 «IF returnType.fullyQualifiedName.equals(BigDecimal.canonicalName)»
205 «rangeBody(restrictions, BigDecimal, genTO.importedName, "_range")»
207 «rangeBody(restrictions, BigInteger, genTO.importedName, "_range")»
212 private def rangeBody(Restrictions restrictions, Class<? extends Number> numberClass, String className, String varName) '''
213 «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder();
214 «FOR r : restrictions.rangeConstraints»
215 builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»));
217 «varName» = builder.build();
220 private def lengthBody(Restrictions restrictions, Class<? extends Number> numberClass, String className, String varName) '''
221 «ImmutableList.importedName».Builder<«Range.importedName»<«numberClass.importedName»>> builder = «ImmutableList.importedName».builder();
222 «FOR r : restrictions.lengthConstraints»
223 builder.add(«Range.importedName».closed(«numericValue(numberClass, r.min)», «numericValue(numberClass, r.max)»));
225 «varName» = builder.build();
228 private def generateLengthConstraints() '''
229 «IF restrictions != null && !(restrictions.lengthConstraints.empty)»
230 «val numberClass = restrictions.lengthConstraints.iterator.next.min.class»
231 «IF numberClass.equals(typeof(BigDecimal))»
232 «lengthBody(restrictions, numberClass, genTO.importedName, "_length")»
234 «lengthBody(restrictions, typeof(BigInteger), genTO.importedName, "_length")»
239 def protected allValuesConstructor() '''
240 «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
241 @«ConstructorProperties.importedName»("value")
243 public «type.name»(«allProperties.asArgumentsDeclaration») {
244 «IF false == parentProperties.empty»
245 super(«parentProperties.asArguments»);
247 «FOR p : allProperties»
248 «generateRestrictions(type, p.fieldName.toString, p.returnType)»
251 this.«p.fieldName» = «p.fieldName»;
257 def protected genUnionConstructor() '''
258 «FOR p : allProperties»
259 «val List<GeneratedProperty> other = new ArrayList(properties)»
261 «genConstructor(p, other)»
267 def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) '''
268 public «type.name»(«property.returnType.importedName + " " + property.name») {
269 «IF false == parentProperties.empty»
270 super(«parentProperties.asArguments»);
272 «generateRestrictions(type, property.fieldName.toString, property.returnType)»
273 this.«property.fieldName» = «property.name»;
275 this.«p.fieldName» = null;
280 def protected copyConstructor() '''
282 * Creates a copy from Source Object.
284 * @param source Source object
286 public «type.name»(«type.name» source) {
287 «IF false == parentProperties.empty»
291 this.«p.fieldName» = source.«p.fieldName»;
296 def protected parentConstructor() '''
298 * Creates a new instance from «genTO.superType.importedName»
300 * @param source Source object
302 public «type.name»(«genTO.superType.importedName» source) {
307 def protected defaultInstance() '''
308 «IF genTO.typedef && !allProperties.empty && !genTO.unionType»
309 «val prop = allProperties.get(0)»
310 «IF !("org.opendaylight.yangtools.yang.binding.InstanceIdentifier".equals(prop.returnType.fullyQualifiedName))»
311 public static «genTO.name» getDefaultInstance(String defaultValue) {
312 «IF "byte[]".equals(prop.returnType.name)»
313 «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64();
314 return new «genTO.name»(baseEncoding.decode(defaultValue));
315 «ELSEIF "java.lang.String".equals(prop.returnType.fullyQualifiedName)»
316 return new «genTO.name»(defaultValue);
317 «ELSEIF allProperties.size > 1»
319 «ELSEIF "java.lang.Boolean".equals(prop.returnType.fullyQualifiedName)»
320 return new «genTO.name»(Boolean.valueOf(defaultValue));
321 «ELSEIF "java.lang.Byte".equals(prop.returnType.fullyQualifiedName)»
322 return new «genTO.name»(Byte.valueOf(defaultValue));
323 «ELSEIF "java.lang.Short".equals(prop.returnType.fullyQualifiedName)»
324 return new «genTO.name»(Short.valueOf(defaultValue));
325 «ELSEIF "java.lang.Integer".equals(prop.returnType.fullyQualifiedName)»
326 return new «genTO.name»(Integer.valueOf(defaultValue));
327 «ELSEIF "java.lang.Long".equals(prop.returnType.fullyQualifiedName)»
328 return new «genTO.name»(Long.valueOf(defaultValue));
330 return new «genTO.name»(new «prop.returnType.importedName»(defaultValue));
337 def protected bitsArgs() '''
338 «List.importedName»<«String.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»);
339 if (!properties.contains(defaultValue)) {
340 throw new «IllegalArgumentException.importedName»("invalid default parameter");
343 return new «genTO.name»(
344 «FOR prop : allProperties SEPARATOR ","»
345 properties.get(i++).equals(defaultValue) ? «Boolean.importedName».TRUE : null
350 def protected propsAsArgs(Iterable<GeneratedProperty> properties) '''
351 «FOR prop : properties SEPARATOR ","»
357 * Template method which generates JAVA class declaration.
359 * @param isInnerClass boolean value which specify if generated class is|isn't inner
360 * @return string with class declaration in JAVA format
362 def protected generateClassDeclaration(boolean isInnerClass) '''
366 ELSEIF (type.abstract)»«
370 ENDIF»class «type.name»«
371 IF (genTO.superType != null)»«
372 " extends "»«genTO.superType.importedName»«
374 «IF (!type.implements.empty)»«
376 FOR type : type.implements SEPARATOR ", "»«
383 * Template method which generates JAVA enum type.
385 * @return string with inner enum source code in JAVA format
387 def protected enumDeclarations() '''
389 «FOR e : enums SEPARATOR "\n"»
390 «val enumTemplate = new EnumTemplate(e)»
391 «enumTemplate.generateAsInnerClass»
396 def protected suidDeclaration() '''
397 «IF genTO.SUID != null»
398 private static final long serialVersionUID = «genTO.SUID.value»L;
403 * Template method wich generates JAVA constants.
405 * @return string with constants in JAVA format
407 def protected constantsDeclarations() '''
410 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
411 «val cValue = c.value»
412 «IF cValue instanceof List<?>»
413 «val cValues = cValue as List<?>»
414 private static final «List.importedName»<«Pattern.importedName»> «Constants.MEMBER_PATTERN_LIST» = new «ArrayList.importedName»<«Pattern.importedName»>();
415 public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «Arrays.importedName».asList(«
416 FOR v : cValues SEPARATOR ", "»«
417 IF v instanceof String»"«
422 «generateStaticInicializationBlock»
425 public static final «c.type.importedName» «c.name» = «c.value»;
432 * Template method which generates JAVA static initialization block.
434 * @return string with static initialization block in JAVA format
436 def protected generateStaticInicializationBlock() '''
438 for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {
439 «Constants.MEMBER_PATTERN_LIST».add(Pattern.compile(regEx));
445 * Template method which generates JAVA class attributes.
447 * @return string with the class attributes in JAVA format
449 def protected generateFields() '''
450 «IF restrictions != null»
451 «val prop = getPropByName("value")»
453 «IF !(restrictions.lengthConstraints.empty)»
454 private static final «List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _length;
456 «IF !(restrictions.rangeConstraints.empty)»
457 private static final «List.importedName»<«Range.importedName»<«prop.returnType.importedNumber»>> _range;
461 «IF !properties.empty»
463 «IF f.readOnly»final«ENDIF» private «f.returnType.importedName» «f.fieldName»;
469 * Template method which generates the method <code>hashCode()</code>.
471 * @return string with the <code>hashCode()</code> method definition in JAVA format
473 def protected generateHashCode() '''
474 «IF !genTO.hashCodeIdentifiers.empty»
476 public int hashCode() {
477 final int prime = 31;
479 «FOR property : genTO.hashCodeIdentifiers»
480 «IF property.returnType.name.contains("[")»
481 result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));
483 result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());
492 * Template method which generates the method <code>equals()</code>.
494 * @return string with the <code>equals()</code> method definition in JAVA format
496 def protected generateEquals() '''
497 «IF !genTO.equalsIdentifiers.empty»
499 public boolean equals(java.lang.Object obj) {
506 if (getClass() != obj.getClass()) {
509 «type.name» other = («type.name») obj;
510 «FOR property : genTO.equalsIdentifiers»
511 «val fieldName = property.fieldName»
512 if («fieldName» == null) {
513 if (other.«fieldName» != null) {
516 «IF property.returnType.name.contains("[")»
517 } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {
519 } else if(!«fieldName».equals(other.«fieldName»)) {
529 def GeneratedProperty getPropByName(String name) {
530 for (GeneratedProperty prop : allProperties) {
531 if (prop.name.equals(name)) {