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.regex.Pattern
20 import org.opendaylight.yangtools.binding.generator.util.TypeConstants
21 import org.opendaylight.yangtools.sal.binding.model.api.ConcreteType
22 import org.opendaylight.yangtools.sal.binding.model.api.Constant
23 import org.opendaylight.yangtools.sal.binding.model.api.Enumeration
24 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedProperty
25 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedTransferObject
26 import org.opendaylight.yangtools.sal.binding.model.api.GeneratedType
27 import org.opendaylight.yangtools.sal.binding.model.api.Restrictions
28 import org.opendaylight.yangtools.sal.binding.model.api.Type
29 import org.opendaylight.yangtools.yang.model.api.type.BitsTypeDefinition
32 * Template for generating JAVA class.
34 class ClassTemplate extends BaseTemplate {
36 protected val List<GeneratedProperty> properties
37 protected val List<GeneratedProperty> finalProperties
38 protected val List<GeneratedProperty> parentProperties
39 protected val Iterable<GeneratedProperty> allProperties;
40 protected val Restrictions restrictions
43 * List of enumeration which are generated as JAVA enum type.
45 protected val List<Enumeration> enums
48 * List of constant instances which are generated as JAVA public static final attributes.
50 protected val List<Constant> consts
53 * List of generated types which are enclosed inside <code>genType</code>
55 protected val List<GeneratedType> enclosedGeneratedTypes;
57 protected val GeneratedTransferObject genTO;
59 private val AbstractRangeGenerator<?> rangeGenerator
62 * Creates instance of this class with concrete <code>genType</code>.
64 * @param genType generated transfer object which will be transformed to JAVA class source code
66 new(GeneratedTransferObject genType) {
69 this.properties = genType.properties
70 this.finalProperties = GeneratorUtil.resolveReadOnlyPropertiesFromTO(genTO.properties)
71 this.parentProperties = GeneratorUtil.getPropertiesOfAllParents(genTO)
72 this.restrictions = genType.restrictions
74 var List<GeneratedProperty> sorted = new ArrayList<GeneratedProperty>();
75 sorted.addAll(properties);
76 sorted.addAll(parentProperties);
77 Collections.sort(sorted, [p1, p2|
78 p1.name.compareTo(p2.name)
81 this.allProperties = sorted
82 this.enums = genType.enumerations
83 this.consts = genType.constantDefinitions
84 this.enclosedGeneratedTypes = genType.enclosedTypes
86 if (restrictions != null && !restrictions.rangeConstraints.nullOrEmpty) {
87 rangeGenerator = AbstractRangeGenerator.forType(findProperty(genType, "value").returnType)
88 Preconditions.checkNotNull(rangeGenerator)
95 * Generates JAVA class source code (class body only).
97 * @return string with JAVA class body source code
99 def CharSequence generateAsInnerClass() {
100 return generateBody(true)
103 override protected body() {
108 * Template method which generates class body.
110 * @param isInnerClass boolean value which specify if generated class is|isn't inner
111 * @return string with class source code in JAVA format
113 def protected generateBody(boolean isInnerClass) '''
114 «wrapToDocumentation(formatDataForJavaDoc(type))»
115 «generateClassDeclaration(isInnerClass)» {
117 «innerClassesDeclarations»
119 «constantsDeclarations»
122 «IF restrictions != null»
123 «IF !restrictions.lengthConstraints.nullOrEmpty»
124 «LengthGenerator.generateLengthChecker("_value", findProperty(genTO, "value").returnType, restrictions.lengthConstraints)»
126 «IF !restrictions.rangeConstraints.nullOrEmpty»
127 «rangeGenerator.generateRangeChecker("_value", restrictions.rangeConstraints)»
135 «FOR field : properties SEPARATOR "\n"»
142 «IF (genTO.isTypedef() && genTO.getBaseType instanceof BitsTypeDefinition)»
143 «generateGetValueForBitsTypeDef»
150 «generateToString(genTO.toStringIdentifiers)»
156 * Template method which generates the method <code>getValue()</code> for typedef,
157 * which base type is BitsDefinition.
159 * @return string with the <code>getValue()</code> method definition in JAVA format
161 def protected generateGetValueForBitsTypeDef() '''
163 public boolean[] getValue() {
164 return new boolean[]{
165 «FOR property: genTO.properties SEPARATOR ','»
173 * Template method which generates inner classes inside this interface.
175 * @return string with the source code for inner classes in JAVA format
177 def protected innerClassesDeclarations() '''
178 «IF !enclosedGeneratedTypes.empty»
179 «FOR innerClass : enclosedGeneratedTypes SEPARATOR "\n"»
180 «IF (innerClass instanceof GeneratedTransferObject)»
181 «val classTemplate = new ClassTemplate(innerClass)»
182 «classTemplate.generateAsInnerClass»
189 def protected constructors() '''
191 «genUnionConstructor»
193 «allValuesConstructor»
195 «IF !allProperties.empty»
198 «IF properties.empty && !parentProperties.empty »
203 def protected allValuesConstructor() '''
204 «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
205 @«ConstructorProperties.importedName»("value")
207 public «type.name»(«allProperties.asArgumentsDeclaration») {
208 «IF false == parentProperties.empty»
209 super(«parentProperties.asArguments»);
211 «FOR p : allProperties»
212 «generateRestrictions(type, p.fieldName.toString, p.returnType)»
216 * If we have patterns, we need to apply them to the value field. This is a sad
217 * consequence of how this code is structured.
219 IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name.equals("value")»
221 «Preconditions.importedName».checkNotNull(_value, "Supplied value may not be null");
224 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME && c.value instanceof List<?>»
225 for (Pattern p : patterns) {
226 «Preconditions.importedName».checkArgument(p.matcher(_value).matches(), "Supplied value \"%s\" does not match required pattern \"%s\"", _value, p);
233 «IF p.returnType.importedName.contains("[]")»
234 «IF genTO.typedef && !allProperties.empty && allProperties.size == 1 && allProperties.get(0).name
236 this.«p.fieldName» = «p.fieldName».clone();
238 this.«p.fieldName» = «p.fieldName» == null ? null : «p.fieldName».clone();
241 this.«p.fieldName» = «p.fieldName»;
248 def protected genUnionConstructor() '''
249 «FOR p : allProperties»
250 «val List<GeneratedProperty> other = new ArrayList(properties)»
252 «genConstructor(p, other)»
258 def protected genConstructor(GeneratedProperty property, GeneratedProperty... other) '''
259 public «type.name»(«property.returnType.importedName + " " + property.name») {
260 «IF false == parentProperties.empty»
261 super(«parentProperties.asArguments»);
264 «generateRestrictions(type, property.fieldName.toString, property.returnType)»
266 this.«property.fieldName» = «property.name»;
268 this.«p.fieldName» = null;
273 def private static paramValue(Type returnType, String paramName) {
274 if (returnType instanceof ConcreteType) {
277 return paramName + ".getValue()"
281 def private generateRestrictions(Type type, String paramName, Type returnType) '''
282 «val restrictions = type.getRestrictions»
283 «IF restrictions !== null»
284 «IF !restrictions.lengthConstraints.empty || !restrictions.rangeConstraints.empty»
285 if («paramName» != null) {
286 «IF !restrictions.lengthConstraints.empty»
287 «LengthGenerator.generateLengthCheckerCall(paramName, paramValue(returnType, paramName))»
289 «IF !restrictions.rangeConstraints.empty»
290 «rangeGenerator.generateRangeCheckerCall(paramName, paramValue(returnType, paramName))»
297 def protected copyConstructor() '''
299 * Creates a copy from Source Object.
301 * @param source Source object
303 public «type.name»(«type.name» source) {
304 «IF false == parentProperties.empty»
308 this.«p.fieldName» = source.«p.fieldName»;
313 def protected parentConstructor() '''
315 * Creates a new instance from «genTO.superType.importedName»
317 * @param source Source object
319 public «type.name»(«genTO.superType.importedName» source) {
324 def protected defaultInstance() '''
325 «IF genTO.typedef && !allProperties.empty && !genTO.unionType»
326 «val prop = allProperties.get(0)»
327 «IF !("org.opendaylight.yangtools.yang.binding.InstanceIdentifier".equals(prop.returnType.fullyQualifiedName))»
328 public static «genTO.name» getDefaultInstance(String defaultValue) {
329 «IF "byte[]".equals(prop.returnType.name)»
330 «BaseEncoding.importedName» baseEncoding = «BaseEncoding.importedName».base64();
331 return new «genTO.name»(baseEncoding.decode(defaultValue));
332 «ELSEIF "java.lang.String".equals(prop.returnType.fullyQualifiedName)»
333 return new «genTO.name»(defaultValue);
334 «ELSEIF allProperties.size > 1»
336 «ELSEIF "java.lang.Boolean".equals(prop.returnType.fullyQualifiedName)»
337 return new «genTO.name»(Boolean.valueOf(defaultValue));
338 «ELSEIF "java.lang.Byte".equals(prop.returnType.fullyQualifiedName)»
339 return new «genTO.name»(Byte.valueOf(defaultValue));
340 «ELSEIF "java.lang.Short".equals(prop.returnType.fullyQualifiedName)»
341 return new «genTO.name»(Short.valueOf(defaultValue));
342 «ELSEIF "java.lang.Integer".equals(prop.returnType.fullyQualifiedName)»
343 return new «genTO.name»(Integer.valueOf(defaultValue));
344 «ELSEIF "java.lang.Long".equals(prop.returnType.fullyQualifiedName)»
345 return new «genTO.name»(Long.valueOf(defaultValue));
347 return new «genTO.name»(new «prop.returnType.importedName»(defaultValue));
354 def protected bitsArgs() '''
355 «List.importedName»<«String.importedName»> properties = «Lists.importedName».newArrayList(«allProperties.propsAsArgs»);
356 if (!properties.contains(defaultValue)) {
357 throw new «IllegalArgumentException.importedName»("invalid default parameter");
360 return new «genTO.name»(
361 «FOR prop : allProperties SEPARATOR ","»
362 properties.get(i++).equals(defaultValue) ? «Boolean.importedName».TRUE : null
367 def protected propsAsArgs(Iterable<GeneratedProperty> properties) '''
368 «FOR prop : properties SEPARATOR ","»
374 * Template method which generates JAVA class declaration.
376 * @param isInnerClass boolean value which specify if generated class is|isn't inner
377 * @return string with class declaration in JAVA format
379 def protected generateClassDeclaration(boolean isInnerClass) '''
383 ELSEIF (type.abstract)»«
387 ENDIF»class «type.name»«
388 IF (genTO.superType != null)»«
389 " extends "»«genTO.superType.importedName»«
391 «IF (!type.implements.empty)»«
393 FOR type : type.implements SEPARATOR ", "»«
400 * Template method which generates JAVA enum type.
402 * @return string with inner enum source code in JAVA format
404 def protected enumDeclarations() '''
406 «FOR e : enums SEPARATOR "\n"»
407 «val enumTemplate = new EnumTemplate(e)»
408 «enumTemplate.generateAsInnerClass»
413 def protected suidDeclaration() '''
414 «IF genTO.SUID != null»
415 private static final long serialVersionUID = «genTO.SUID.value»L;
420 * Template method which generates JAVA constants.
422 * @return string with constants in JAVA format
424 def protected constantsDeclarations() '''
427 «IF c.name == TypeConstants.PATTERN_CONSTANT_NAME»
428 «val cValue = c.value»
429 «IF cValue instanceof List<?>»
430 private static final «Pattern.importedName»[] «Constants.MEMBER_PATTERN_LIST»;
431 public static final «List.importedName»<String> «TypeConstants.PATTERN_CONSTANT_NAME» = «ImmutableList.importedName».of(«
432 FOR v : cValue SEPARATOR ", "»«
433 IF v instanceof String»"«
438 «generateStaticInicializationBlock»
441 public static final «c.type.importedName» «c.name» = «c.value»;
448 * Template method which generates JAVA static initialization block.
450 * @return string with static initialization block in JAVA format
452 def protected generateStaticInicializationBlock() '''
454 final «Pattern.importedName» a[] = new «Pattern.importedName»[«TypeConstants.PATTERN_CONSTANT_NAME».size()];
456 for (String regEx : «TypeConstants.PATTERN_CONSTANT_NAME») {
457 a[i++] = Pattern.compile(regEx);
460 «Constants.MEMBER_PATTERN_LIST» = a;
465 * Template method which generates JAVA class attributes.
467 * @return string with the class attributes in JAVA format
469 def protected generateFields() '''
470 «IF !properties.empty»
472 private«IF f.readOnly» final«ENDIF» «f.returnType.importedName» «f.fieldName»;
478 * Template method which generates the method <code>hashCode()</code>.
480 * @return string with the <code>hashCode()</code> method definition in JAVA format
482 def protected generateHashCode() '''
483 «IF !genTO.hashCodeIdentifiers.empty»
485 public int hashCode() {
486 final int prime = 31;
488 «FOR property : genTO.hashCodeIdentifiers»
489 «IF property.returnType.name.contains("[")»
490 result = prime * result + ((«property.fieldName» == null) ? 0 : «Arrays.importedName».hashCode(«property.fieldName»));
492 result = prime * result + ((«property.fieldName» == null) ? 0 : «property.fieldName».hashCode());
501 * Template method which generates the method <code>equals()</code>.
503 * @return string with the <code>equals()</code> method definition in JAVA format
505 def protected generateEquals() '''
506 «IF !genTO.equalsIdentifiers.empty»
508 public boolean equals(java.lang.Object obj) {
515 if (getClass() != obj.getClass()) {
518 «type.name» other = («type.name») obj;
519 «FOR property : genTO.equalsIdentifiers»
520 «val fieldName = property.fieldName»
521 if («fieldName» == null) {
522 if (other.«fieldName» != null) {
525 «IF property.returnType.name.contains("[")»
526 } else if(!«Arrays.importedName».equals(«fieldName», other.«fieldName»)) {
528 } else if(!«fieldName».equals(other.«fieldName»)) {
538 def GeneratedProperty getPropByName(String name) {
539 for (GeneratedProperty prop : allProperties) {
540 if (prop.name.equals(name)) {