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.base.Preconditions
11 import com.google.common.collect.ImmutableList
12 import com.google.common.collect.Lists
13 import com.google.common.io.BaseEncoding
14 import java.beans.ConstructorProperties
15 import java.util.ArrayList
16 import java.util.Arrays
17 import java.util.Collections
19 import java.util.Objects
20 import java.util.regex.Pattern
21 import org.opendaylight.yangtools.binding.generator.util.TypeConstants
22 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType
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
29 import org.opendaylight.yangtools.sal.binding.model.api.Type
30 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
33 * Template for generating JAVA class.
35 class ClassTemplate extends BaseTemplate {
37 protected val List<GeneratedProperty> properties
38 protected val List<GeneratedProperty> finalProperties
39 protected val List<GeneratedProperty> parentProperties
40 protected val Iterable<GeneratedProperty> allProperties;
41 protected val Restrictions restrictions
44 * List of enumeration which are generated as JAVA enum type.
46 protected val List<Enumeration> enums
49 * List of constant instances which are generated as JAVA public static final attributes.
51 protected val List<Constant> consts
54 * List of generated types which are enclosed inside <code>genType</code>
56 protected val List<GeneratedType> enclosedGeneratedTypes;
58 protected val GeneratedTransferObject genTO;
60 private val AbstractRangeGenerator<?> rangeGenerator
63 * Creates instance of this class with concrete <code>genType</code>.
65 * @param genType generated transfer object which will be transformed to JAVA class source code
67 new(GeneratedTransferObject genType) {
70 this.properties = genType.properties
71 this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)
72 this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)
73 this.restrictions = genType.restrictions
75 var List<GeneratedProperty> sorted = new ArrayList<GeneratedProperty>();
76 sorted.addAll(properties);
77 sorted.addAll(parentProperties);
78 Collections.sort(sorted, [p1, p2|
79 p1.name.compareTo(p2.name)
82 this.allProperties = sorted
83 this.enums = genType.enumerations
84 this.consts = genType.constantDefinitions
85 this.enclosedGeneratedTypes = genType.enclosedTypes
87 if (restrictions != null && !restrictions.rangeConstraints.nullOrEmpty) {
88 rangeGenerator = AbstractRangeGenerator.forType(findProperty(genType, "value").returnType)
89 Preconditions.checkNotNull(rangeGenerator)
96 * Generates JAVA class source code (class body only).
98 * @return string with JAVA class body source code
100 def CharSequence generateAsInnerClass() {
101 return generateBody(true)
104 override protected body() {
109 * Template method which generates class body.
111 * @param isInnerClass boolean value which specify if generated class is|isn't inner
112 * @return string with class source code in JAVA format
114 def protected generateBody(boolean isInnerClass) '''
115 «wrapToDocumentation(formatDataForJavaDoc(type))»
116 «annotationDeclaration»
117 «generateClassDeclaration(isInnerClass)» {
119 «innerClassesDeclarations»
121 «constantsDeclarations»
124 «IF restrictions != null»
125 «IF !restrictions.lengthConstraints.nullOrEmpty»
126 «LengthGenerator.generateLengthChecker("_value", findProperty(genTO, "value").returnType, restrictions.lengthConstraints)»
128 «IF !restrictions.rangeConstraints.nullOrEmpty»
129 «rangeGenerator.generateRangeChecker("_value", restrictions.rangeConstraints)»
137 «FOR field : properties SEPARATOR "\n"»
144 «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)»
145 «generateGetValueForBitsTypeDef»
152 «generateToString(genTO.toStringIdentifiers)»
158 * Template method which generates the method <code>getValue()</code> for typedef,
159 * which base type is BitsDefinition.
161 * @return string with the <code>getValue()</code> method definition in JAVA format
163 def protected generateGetValueForBitsTypeDef() '''
165 public boolean[] getValue() {
166 return new boolean[]{
167 «FOR property: genTO.properties SEPARATOR ','»
175 * Template method which generates inner classes inside this interface.
177 * @return string with the source code for inner classes in JAVA format
179 def protected innerClassesDeclarations() '''
180 «IF !enclosedGeneratedTypes.empty»
181 «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
182 «IF (innerClass instanceof GeneratedTransferObject)»
183 «val classTemplate = new ClassTemplate(innerClass)»
184 «classTemplate.generateAsInnerClass»
191 def protected constructors() '''
193 «genUnionConstructor»
195 «allValuesConstructor»
197 «IF !allProperties.empty»
200 «IF properties.empty && !parentProperties.empty »
205 def protected allValuesConstructor() '''
206 «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
207 @«ConstructorProperties.importedName»("value")
209 public «type.name»(«allProperties.asArgumentsDeclaration») {
210 «IF false == parentProperties.empty»
211 super(«parentProperties.asArguments»);
213 «FOR p : allProperties»
214 «generateRestrictions(type, p.fieldName.toString, p.returnType)»
218 * If we have patterns, we need to apply them to the value field. This is a sad
219 * consequence of how this code is structured.
221 IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
223 «Preconditions.importedName».checkNotNull(_value, "Supplied value may not be null");
226 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME && c.value instanceof List<?>»
227 for (Pattern p : patterns) {
228 «Preconditions.importedName».checkArgument(p.matcher(_value).matches(), "Supplied value \"%s\" does not match required pattern \"%s\"", _value, p);
235 «IF p.returnType.importedName.contains("[]")»
236 «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name
238 this.«p.fieldName» = «p.fieldName».clone();
240 this.«p.fieldName» = «p.fieldName» == null ? null : «p.fieldName».clone();
243 this.«p.fieldName» = «p.fieldName»;
250 def protected genUnionConstructor() '''
251 «FOR p : allProperties»
252 «val List<GeneratedProperty> other = new ArrayList(properties)»
254 «genConstructor(p, other)»
260 def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) '''
261 public «type.name»(«property.returnType.importedName + " " + property.name») {
262 «IF false == parentProperties.empty»
263 super(«parentProperties.asArguments»);
266 «generateRestrictions(type, property.fieldName.toString, property.returnType)»
268 this.«property.fieldName» = «property.name»;
270 this.«p.fieldName» = null;
275 def private static paramValue(Type returnType, String paramName) {
276 if (returnType instanceof ConcreteType) {
279 return paramName + ".getValue()"
283 def private generateRestrictions(Type type, String paramName, Type returnType) '''
284 «val restrictions = type.getRestrictions»
285 «IF restrictions !== null»
286 «IF !restrictions.lengthConstraints.empty || !restrictions.rangeConstraints.empty»
287 if («paramName» != null) {
288 «IF !restrictions.lengthConstraints.empty»
289 «LengthGenerator.generateLengthCheckerCall(paramName, paramValue(returnType, paramName))»
291 «IF !restrictions.rangeConstraints.empty»
292 «rangeGenerator.generateRangeCheckerCall(paramName, paramValue(returnType, paramName))»
299 def protected copyConstructor() '''
301 * Creates a copy from Source Object.
303 * @param source Source object
305 public «type.name»(«type.name» source) {
306 «IF false == parentProperties.empty»
310 this.«p.fieldName» = source.«p.fieldName»;
315 def protected parentConstructor() '''
317 * Creates a new instance from «genTO.superType.importedName»
319 * @param source Source object
321 public «type.name»(«genTO.superType.importedName» source) {
326 def protected defaultInstance() '''
327 «IF genTO.typedef && !allProperties.empty && !genTO.unionType»
328 «val prop = allProperties.get(0)»
329 «IF !("org.opendaylight.yangtools.yang.binding.InstanceIdentifier".equals(prop.returnType.fullyQualifiedName))»
330 public static «genTO.name» getDefaultInstance(String defaultValue) {
331 «IF "byte[]".equals(prop.returnType.name)»
332 «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64();
333 return new «genTO.name»(baseEncoding.decode(defaultValue));
334 «ELSEIF "java.lang.String".equals(prop.returnType.fullyQualifiedName)»
335 return new «genTO.name»(defaultValue);
336 «ELSEIF allProperties.size > 1»
338 «ELSEIF "java.lang.Boolean".equals(prop.returnType.fullyQualifiedName)»
339 return new «genTO.name»(Boolean.valueOf(defaultValue));
340 «ELSEIF "java.lang.Byte".equals(prop.returnType.fullyQualifiedName)»
341 return new «genTO.name»(Byte.valueOf(defaultValue));
342 «ELSEIF "java.lang.Short".equals(prop.returnType.fullyQualifiedName)»
343 return new «genTO.name»(Short.valueOf(defaultValue));
344 «ELSEIF "java.lang.Integer".equals(prop.returnType.fullyQualifiedName)»
345 return new «genTO.name»(Integer.valueOf(defaultValue));
346 «ELSEIF "java.lang.Long".equals(prop.returnType.fullyQualifiedName)»
347 return new «genTO.name»(Long.valueOf(defaultValue));
349 return new «genTO.name»(new «prop.returnType.importedName»(defaultValue));
356 def protected bitsArgs() '''
357 «List.importedName»<«String.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»);
358 if (!properties.contains(defaultValue)) {
359 throw new «IllegalArgumentException.importedName»("invalid default parameter");
362 return new «genTO.name»(
363 «FOR prop : allProperties SEPARATOR ","»
364 properties.get(i++).equals(defaultValue) ? «Boolean.importedName».TRUE : null
369 def protected propsAsArgs(Iterable<GeneratedProperty> properties) '''
370 «FOR prop : properties SEPARATOR ","»
376 * Template method which generates JAVA class declaration.
378 * @param isInnerClass boolean value which specify if generated class is|isn't inner
379 * @return string with class declaration in JAVA format
381 def protected generateClassDeclaration(boolean isInnerClass) '''
385 ELSEIF (type.abstract)»«
389 ENDIF»class «type.name»«
390 IF (genTO.superType != null)»«
391 " extends "»«genTO.superType.importedName»«
393 «IF (!type.implements.empty)»«
395 FOR type : type.implements SEPARATOR ", "»«
402 * Template method which generates JAVA enum type.
404 * @return string with inner enum source code in JAVA format
406 def protected enumDeclarations() '''
408 «FOR e : enums SEPARATOR "\n"»
409 «val enumTemplate = new EnumTemplate(e)»
410 «enumTemplate.generateAsInnerClass»
415 def protected suidDeclaration() '''
416 «IF genTO.SUID != null»
417 private static final long serialVersionUID = «genTO.SUID.value»L;
421 def protected annotationDeclaration() '''
422 «IF genTO.getAnnotations != null»
423 «FOR e : genTO.getAnnotations»
430 * Template method which generates JAVA constants.
432 * @return string with constants in JAVA format
434 def protected constantsDeclarations() '''
437 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
438 «val cValue = c.value»
439 «IF cValue instanceof List<?>»
440 private static final «Pattern.importedName»[] «Constants.MEMBER_PATTERN_LIST»;
441 public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(«
442 FOR v : cValue SEPARATOR ", "»«
443 IF v instanceof String»"«
448 «generateStaticInicializationBlock»
458 * Template method which generates JAVA static initialization block.
460 * @return string with static initialization block in JAVA format
462 def protected generateStaticInicializationBlock() '''
464 final «Pattern.importedName» a[] = new «Pattern.importedName»[«TypeConstants.PATTERN_CONSTANT_NAME».size()];
466 for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {
467 a[i++] = Pattern.compile(regEx);
470 «Constants.MEMBER_PATTERN_LIST» = a;
475 * Template method which generates JAVA class attributes.
477 * @return string with the class attributes in JAVA format
479 def protected generateFields() '''
480 «IF !properties.empty»
482 private«IF isReadOnly(f)» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
487 protected def isReadOnly(GeneratedProperty field) {
488 return field.readOnly
492 * Template method which generates the method <code>hashCode()</code>.
494 * @return string with the <code>hashCode()</code> method definition in JAVA format
496 def protected generateHashCode() '''
497 «IF !genTO.hashCodeIdentifiers.empty»
499 public int hashCode() {
500 final int prime = 31;
502 «FOR property : genTO.hashCodeIdentifiers»
503 «IF property.returnType.name.contains("[")»
504 result = prime * result + «Arrays.importedName».hashCode(«property.fieldName»);
506 result = prime * result + «Objects.importedName».hashCode(«property.fieldName»);
515 * Template method which generates the method <code>equals()</code>.
517 * @return string with the <code>equals()</code> method definition in JAVA format
519 def protected generateEquals() '''
520 «IF !genTO.equalsIdentifiers.empty»
522 public boolean equals(java.lang.Object obj) {
529 if (getClass() != obj.getClass()) {
532 «type.name» other = («type.name») obj;
533 «FOR property : genTO.equalsIdentifiers»
534 «val fieldName = property.fieldName»
535 «IF property.returnType.name.contains("[")»
536 if (!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {
538 if (!«Objects.importedName».equals(«fieldName», other.«fieldName»)) {
548 def GeneratedProperty getPropByName(String name) {
549 for (GeneratedProperty prop : allProperties) {
550 if (prop.name.equals(name)) {