@*
* Copyright (c) 2016 Cisco Systems, Inc. and others. All rights reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v1.0 which accompanies this distribution,
* and is available at http://www.eclipse.org/legal/epl-v10.html
*@
@import java.util.List
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.fieldName
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.formatDataForJavaDocBuilder
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.getSimpleNameForBuilder
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.getterMethodName
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.getRestrictions
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.propertyNameFromGetter
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.toFirstUpper
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.util.TextTemplateUtil.wrapToDocumentation
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers.BuilderRenderer.getAllIfcs
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers.BuilderRenderer.hasImplementsFromUses
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.renderers.BuilderRenderer.toListOfNames
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.AbstractRangeGenerator
@import org.opendaylight.mdsal.binding.javav2.java.api.generator.rangeGenerators.LengthGenerator
@import org.opendaylight.mdsal.binding.javav2.model.api.ConcreteType
@import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedType
@import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedTransferObject
@import org.opendaylight.mdsal.binding.javav2.model.api.GeneratedProperty
@import org.opendaylight.mdsal.binding.javav2.model.api.Type
@import org.opendaylight.yangtools.concepts.Builder
@(genType: GeneratedType, properties: Set[GeneratedProperty], importedNames: Map[String, String],
ImportedNamesWithProperties: Map[GeneratedProperty, String], augmentField: GeneratedProperty, copyConstructorHelper: String,
getterMethods: List[String], parentTypeForBuilderName: String)
@if(genType != null) {
@{wrapToDocumentation(formatDataForJavaDocBuilder(importedNames.get("genType")))}
public class @{genType.getName}Builder implements @{getSimpleNameForBuilder} <@{importedNames.get("genType")}> {
@generateFields(false)
@generateAugmentField(false)
@generateConstructorsFromIfcs()
@generateCopyConstructor(false)
@generateMethodFieldsFrom()
@generateGetters(false)
@generateSetters()
@@Override
public @{genType.getName} build() {
return new @{genType.getName}Impl(this);
}
private static final class @{genType.getName}Impl implements @{genType.getName} {
@implementedInterfaceGetter()
@generateFields(true)
@generateAugmentField(true)
@generateCopyConstructor(true)
@generateGetters(true)
@generateHashCode()
@generateEquals()
@generateToString()
@generateImplementedMethods()
}
}
}
@**
* Template method which generates class attributes.
*
* @param isFinal value which specify whether field is|isn't final
* @param genType is genType
* @return string with class attributes and their types
*@
@generateFields(isFinal: Boolean) = {
@if(ImportedNamesWithProperties != null) {
@for((key, value) <- ImportedNamesWithProperties) {
private @if(isFinal) { final}
@{value} @{fieldName(key)};
}
}
}
@**
* Template method which generates class attributes.
*
* @param boolean value which specify whether field is|isn't final
* @return string with class attributes and their types
*@
@generateAugmentField(isPrivate: Boolean) = {
@if(augmentField != null) {
@if(isPrivate) {private }
@{importedNames.get("map")}<@{importedNames.get("class")} extends @{importedNames.get("augmentFieldReturnType")}>,
@{importedNames.get("augmentFieldReturnType")}> @{augmentField.getName} = @{importedNames.get("collections")}.emptyMap();
}
}
@implementedInterfaceGetter() = {
@@Override
public @{importedNames.get("class")}<@{importedNames.get("genType")}> implementedInterface() {
return @{importedNames.get("genType")}.class;
}
}
@**
* Generate default constructor and constructor for every implemented interface from uses statements.
*@
@generateConstructorsFromIfcs() = {
public @{genType.getName}Builder() {
}
@if(genType.isInstanceOf[GeneratedType] && !genType.isInstanceOf[GeneratedTransferObject]) {
@for(impl <- genType.asInstanceOf[GeneratedType].getImplements) {
@generateConstructorFromIfc(impl)
}
}
}
@generateMethodFieldsFrom() = {
@if(genType.isInstanceOf[GeneratedType] && !genType.isInstanceOf[GeneratedTransferObject]) {
@if(hasImplementsFromUses(genType.asInstanceOf[GeneratedType])) {
/**
*Set fields from given grouping argument. Valid argument is instance of one of following types:
*
@for(impl <- getAllIfcs(genType.asInstanceOf[GeneratedType])) {
* - @{impl.getFullyQualifiedName}
}
*
*
* @@param arg grouping object
* @@throws IllegalArgumentException if given argument is none of valid types
*/
public void fieldsFrom(@{importedNames.get("treeNode")} arg) {
boolean isValidArg = false;
@for(impl <- getAllIfcs(genType.asInstanceOf[GeneratedType])) {
@if(impl.isInstanceOf[GeneratedType] && !impl.asInstanceOf[GeneratedType].getMethodDefinitions.isEmpty) {
if (arg instanceof @{impl.asInstanceOf[GeneratedType].getFullyQualifiedName}) {
@if(!impl.isInstanceOf[GeneratedTransferObject]) {
@for(getter <- genType.asInstanceOf[GeneratedType].getMethodDefinitions) {
this._@{propertyNameFromGetter(getter)} = ((@{impl.asInstanceOf[GeneratedType].getFullyQualifiedName})arg).@{getter.getName}();
}
}
isValidArg = true;
}
}
}
if (!isValidArg) {
throw new IllegalArgumentException(
"expected one of: @{toListOfNames(getAllIfcs(genType.asInstanceOf[GeneratedType]))} \n" +
"but was: " + arg
);
}
}
}
}
}
@**
* Generate constructor with argument of given type.
*@
@generateConstructorFromIfc(impl: Type) = {
@if(impl.isInstanceOf[GeneratedType]) {
@if(!impl.asInstanceOf[GeneratedType].getMethodDefinitions.isEmpty) {
public @{genType.getName}Builder(
@{impl.getFullyQualifiedName} arg) {
@{printConstructorPropertySetter(impl)}
}
}
@for(implTypeImplement <- impl.asInstanceOf[GeneratedType].getImplements) {
@generateConstructorFromIfc(implTypeImplement)
}
}
}
@printConstructorPropertySetter(implementedIfc: Type) = {
@if(implementedIfc.isInstanceOf[GeneratedType] && !implementedIfc.isInstanceOf[GeneratedTransferObject]) {
@for(getter <- implementedIfc.asInstanceOf[GeneratedType].getMethodDefinitions) {
this._@{propertyNameFromGetter(getter)} = arg.@{getter.getName}();
}
@for(impl <- implementedIfc.asInstanceOf[GeneratedType].getImplements) {
@{printConstructorPropertySetter(impl)}
}
}
}
@generateImplType() = {
@defining(genType.getName + "Impl") {typeImpl => @typeImpl}
}
@generateBuilderType() = {
@defining(genType.getName + "Builder") {typeBuilder => @typeBuilder}
}
@generateInnerBuilderType() = {
@defining("(" + genType.getName + "Builder base)") {typeInnerBuilder => @typeInnerBuilder}
}
@generateInnerType() = {
@defining("(" + genType.getName + " base)") {innerType => @innerType}
}
@generateCopyConstructor(impl: Boolean) = {
@if(impl) {private} else {public}
@if(impl) {@generateImplType()} else {@generateBuilderType()}
@if(impl) {@generateInnerBuilderType()} else {@generateInnerType()}
{
@{copyConstructorHelper}
@if(augmentField != null) {
@if(impl) {
switch (base.@{augmentField.getName}.size()) {
case 0:
this.@{augmentField.getName} = @{importedNames.get("collections")}.emptyMap();
break;
case 1:
final @{importedNames.get("map")}.Entry<@{importedNames.get("class")} extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e = base.@{augmentField.getName}.entrySet().iterator().next();
this.@{augmentField.getName} = @{importedNames.get("collections")}.<@{importedNames.get("class")} extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> singletonMap(e.getKey(), e.getValue());
break;
default :
this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(base.@{augmentField.getName});
}
} else {
if (base instanceof @{genType.getName}Impl) {
@{genType.getName}Impl impl = (@{genType.getName}Impl) base;
if (!impl.@{augmentField.getName}.isEmpty()) {
this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(impl.@{augmentField.getName});
}
} @{"else"} if (base instanceof @{importedNames.get("augmentationHolder")}) {
@@SuppressWarnings("unchecked")
@{importedNames.get("augmentationHolder")}<@{importedNames.get("genType")}> casted =(@{importedNames.get("augmentationHolder")}<@{importedNames.get("genType")}>) base;
if (!casted.augmentations().isEmpty()) {
this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>(casted.augmentations());
}
}
}
}
}
}
@generateSetters() = {
@for(field <- properties) {
@if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
@if(getRestrictions(field.getReturnType).getRangeConstraints != null && !getRestrictions(field.getReturnType).getRangeConstraints.isEmpty) {
@{AbstractRangeGenerator.forType(field.getReturnType).generateRangeChecker(toFirstUpper(field.getName),
getRestrictions(field.getReturnType).getRangeConstraints)}
}
@if(getRestrictions(field.getReturnType).getLengthConstraints != null && !getRestrictions(field.getReturnType).getLengthConstraints.isEmpty) {
@{LengthGenerator.generateLengthChecker(fieldName(field), field.getReturnType,
getRestrictions(field.getReturnType).getLengthConstraints)}
}
}
public @{genType.getName}Builder set@{toFirstUpper(field.getName)}(final @{toFirstUpper(field.getReturnType.getName)} value) {
@if(!field.getReturnType.isInstanceOf[GeneratedType] && getRestrictions(field.getReturnType) != null) {
if (value != null) {
@if(getRestrictions(field.getReturnType).getRangeConstraints != null && !getRestrictions(field.getReturnType).getRangeConstraints.isEmpty) {
@if(field.getReturnType.isInstanceOf[ConcreteType]) {
@{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value")}
} else {
@{AbstractRangeGenerator.forType(field.getReturnType).generateRangeCheckerCall(toFirstUpper(field.getName), "value.getValue()")}
}
}
@if(getRestrictions(field.getReturnType).getLengthConstraints != null && !getRestrictions(field.getReturnType).getLengthConstraints.isEmpty) {
@if(field.getReturnType.isInstanceOf[ConcreteType]) {
@{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value")}
} else {
@{LengthGenerator.generateLengthCheckerCall(fieldName(field), "value.getValue()")}
}
}
}
}
this.@{fieldName(field)} = value;
return this;
}
}
@if(augmentField != null) {
public @{genType.getName}Builder add@{toFirstUpper(augmentField.getName)}(@{importedNames.get("class")} extends @{importedNames.get("augmentFieldReturnType")}> augmentationType, @{importedNames.get("augmentFieldReturnType")} augmentation) {
if (augmentation == null) {
return remove@{toFirstUpper(augmentField.getName)}(augmentationType);
}
if (!(this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")})) {
this.@{augmentField.getName} = new @{importedNames.get("hashMap")}<>();
}
this.@{augmentField.getName}.put(augmentationType, augmentation);
return this;
}
public @{genType.getName}Builder remove@{toFirstUpper(augmentField.getName)}
(@{importedNames.get("class")} extends @{importedNames.get("augmentFieldReturnType")}> augmentationType) {
if (this.@{augmentField.getName} instanceof @{importedNames.get("hashMap")}) {
this.@{augmentField.getName}.remove(augmentationType);
}
return this;
}
}
}
@generateGetters(addOverride: Boolean) = {
@if(!getterMethods.isEmpty) {
@for(property <- getterMethods) {
@if(addOverride) {@@Override}
@{property}
}
}
@if(augmentField != null) {
@@SuppressWarnings("unchecked")
@if(addOverride) {@@Override}
public > E get@{toFirstUpper(augmentField.getName)}
(@{importedNames.get("class")} augmentationType) {
if (augmentationType == null) {
throw new IllegalArgumentException("Augmentation Type reference cannot be NULL!");
}
return (E) @{augmentField.getName}.get(augmentationType);
}
}
}
@generateHashCode() = {
@if(!properties.isEmpty || augmentField != null) {
private int hash = 0;
private volatile boolean hashValid = false;
@@Override
public int hashCode() {
if (hashValid) {
return hash;
}
final int prime = 31;
int result = 1;
@for(property <- properties) {
@if(property.getReturnType.getName.contains("[")) {
result = prime * result + @{importedNames.get("arrays")}.hashCode(@{fieldName(property)});
} else {
result = prime * result + @{importedNames.get("objects")}.hashCode(@{fieldName(property)});
}
}
@if(augmentField != null) {
result = prime * result + @{importedNames.get("objects")}.hashCode(@{augmentField.getName});
}
hash = result;
hashValid = true;
return result;
}
}
}
@generateToString() = {
@if(properties != null) {
@@Override
public @{importedNames.get("string")} toString() {
@{importedNames.get("string")} name = "@{genType.getName} [";
@{importedNames.get("stringBuilder")} builder = new @{importedNames.get("stringBuilder")}(name);
@for((property, index) <- properties.zipWithIndex) {
if (@{fieldName(property)} != null) {
builder.append("@{fieldName(property)}=");
@if(property.getReturnType.getName.contains("[")) {
builder.append(@{importedNames.get("arrays")}.toString(@{fieldName(property)}));
} else {
builder.append(@{fieldName(property)});
}
@if(properties.size() > 1 && index < properties.size()-1){
builder.append(", ");
}
}
}
@if(augmentField != null) {
@if(!properties.isEmpty()){
final int builderLength = builder.length();
final int builderAdditionalLength = builder.substring(name.length(), builderLength).length();
if (builderAdditionalLength > 2 && !builder.substring(builderLength - 2, builderLength).equals(", ")) {
builder.append(", ");
}
}
builder.append("@{augmentField.getName}=");
builder.append(@{augmentField.getName}.values());
return builder.append(']').toString();
} else {
@if(properties.isEmpty()){
return builder.append(']').toString();
} else {
return builder.append(']').toString();
}
}
}
}
}
@generateImplementedMethods() = {
@@Override
public @{importedNames.get("item")}<@{parentTypeForBuilderName}> treeIdentifier() {
//TODO implement
return null;
}
@@Override
public @{importedNames.get("classInstMap")}<@{importedNames.get("augmentation")} super @{genType.getName}>>
augments() {
//TODO implement
return null;
}
}
@generateEquals() = {
@if(!properties.isEmpty || augmentField != null) {
@@Override
public boolean equals(@{importedNames.get("object")} obj) {
if (this == obj) {
return true;
}
if (!(obj instanceof @{importedNames.get("treeNode")})) {
return false;
}
if (!(obj instanceof @{importedNames.get("instantiable")})) {
return false;
}
if (!@{importedNames.get("genType")}.class.equals(((@{importedNames.get("instantiable")})obj)
.implementedInterface())) {
return false;
}
@{importedNames.get("genType")} other = (@{importedNames.get("genType")})obj;
@for(property <- properties) {
@if(property.getReturnType.getName.contains("[")) {
if (!@{importedNames.get("arrays")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
} else {
if (!@{importedNames.get("objects")}.equals(@{fieldName(property)}, other.@{getterMethodName(property)}()))
}
{
return false;
}
}
@if(augmentField != null) {
if (getClass() == obj.getClass()) {
// Simple case: we are comparing against self
@{genType.getName}Impl otherImpl = (@{genType.getName}Impl) obj;
if (!@{importedNames.get("objects")}.equals(@{augmentField.getName}, otherImpl.@{augmentField.getName})) {
return false;
}
} @{"else"} {
// Hard case: compare our augments with presence there...
for (@{importedNames.get("map")}.Entry<@{importedNames.get("class")} extends @{importedNames.get("augmentFieldReturnType")}>, @{importedNames.get("augmentFieldReturnType")}> e : @{augmentField.getName}.entrySet()) {
if (!e.getValue().equals(other.getAugmentation(e.getKey()))) {
return false;
}
}
// .. and give the other one the chance to do the same
if (!obj.equals(this)) {
return false;
}
}
}
return true;
}
}
}