/*
* gvNIX is an open source tool for rapid application development (RAD).
* Copyright (C) 2010 Generalitat Valenciana
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.gvnix.addon.jpa.addon.audit.providers.envers;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import org.apache.commons.lang3.StringUtils;
import org.gvnix.addon.jpa.addon.audit.JpaAuditMetadata;
import org.gvnix.addon.jpa.addon.audit.JpaAuditRevisionEntityMetadata;
import org.gvnix.addon.jpa.addon.audit.providers.RevisionLogMetadataBuilder;
import org.gvnix.addon.jpa.annotations.audit.GvNIXJpaAudit;
import org.gvnix.support.ItdBuilderHelper;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.ConstructorMetadata;
import org.springframework.roo.classpath.details.ConstructorMetadataBuilder;
import org.springframework.roo.classpath.details.FieldMetadata;
import org.springframework.roo.classpath.details.FieldMetadataBuilder;
import org.springframework.roo.classpath.details.ItdTypeDetailsBuilder;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.model.DataType;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.model.JdkJavaType;
/**
* ITD builder of {@link EnversRevisionLogProvider} for audited entities
* (annotated with {@link GvNIXJpaAudit})
*
* @author <a href="http://www.disid.com">DISID Corporation S.L.</a> made for <a
* href="http://www.dgti.gva.es">General Directorate for Information
* Technologies (DGTI)</a>
* @since 1.3.0
*
*/
public class EnversRevisionLogMetadataBuilder implements
RevisionLogMetadataBuilder {
// Defined names
private static final JavaSymbolName AUDIT_READER_STATIC_METHOD = new JavaSymbolName(
"auditReader");
private static final JavaSymbolName GET_PROPERTY_METHOD = new JavaSymbolName(
"getProperty");
private static final JavaSymbolName CREATE_ITEM_LIST_METHOD = new JavaSymbolName(
"createList");
private static final JavaSymbolName REV_ITEM_REVISON_ENTITY_FIELD = new JavaSymbolName(
"revsionEntity");
private static final JavaSymbolName REV_ITEM_REVISON_TYPE_FIELD = new JavaSymbolName(
"revsionType");
// Defined java types
private static final JavaType AUDITED_ANNOTATION = new JavaType(
"org.hibernate.envers.Audited");
private static final JavaType AUDIT_READER = new JavaType(
"org.hibernate.envers.AuditReader");
private static final JavaType AUDIT_READER_FACTORY = new JavaType(
"org.hibernate.envers.AuditReaderFactory");
private static final JavaType REVISON_TYPE = new JavaType(
"org.hibernate.envers.RevisionType");
private static final JavaType AUDIT_ENTITY = new JavaType(
"org.hibernate.envers.query.AuditEntity");
private static final JavaType AUDIT_QUERY = new JavaType(
"org.hibernate.envers.query.AuditQuery");
private static final JavaType AUDIT_CONJUNTION = new JavaType(
"org.hibernate.envers.query.criteria.AuditConjunction");
private static final JavaType AUDIT_PROPERTY = new JavaType(
"org.hibernate.envers.query.criteria.AuditProperty");
private static final JavaType AUDIT_PROPERTY_GENERIC = new JavaType(
AUDIT_PROPERTY.getFullyQualifiedTypeName(), 0, DataType.TYPE, null,
null);
private static final JavaType AUDIT_PROPERTY_OBJECT = new JavaType(
AUDIT_PROPERTY.getFullyQualifiedTypeName(), 0, DataType.TYPE, null,
Arrays.asList(JavaType.OBJECT));
private static final JavaType MAP_STRING_OBJECT = new JavaType(
JdkJavaType.MAP.getFullyQualifiedTypeName(), 0, DataType.TYPE,
null, Arrays.asList(JavaType.STRING, JavaType.OBJECT));
private static final JavaType ENTRY_STRING_OBJECT = new JavaType(
JdkJavaType.MAP.getFullyQualifiedTypeName().concat(".Entry"), 0,
DataType.TYPE, null,
Arrays.asList(JavaType.STRING, JavaType.OBJECT));
private static final JavaType HASHMAP = new JavaType(HashMap.class);
private static final JavaType HASHMAP_STRING_OBJECT = new JavaType(
HASHMAP.getFullyQualifiedTypeName(), 0, DataType.TYPE, null,
Arrays.asList(JavaType.STRING, JavaType.OBJECT));
private static final JavaType OBJECT_ARRAY = new JavaType(
JavaType.OBJECT.getFullyQualifiedTypeName(), 1, DataType.TYPE,
null, null);
private static final JavaType LIST_OBJECT_ARRAY = new JavaType(
JdkJavaType.LIST.getFullyQualifiedTypeName(), 0, DataType.TYPE,
null, Arrays.asList(OBJECT_ARRAY));
private static final JavaType ARRAYLIST = new JavaType(ArrayList.class);
private static final JavaType AUDIT_ORDER = new JavaType(
"org.hibernate.envers.query.order.AuditOrder");
private static final JavaType STRING_UTILS = new JavaType(
"org.apache.commons.lang3.StringUtils");
private static final JavaType BEAN_WRAPPER_IMPL = new JavaType(
"org.springframework.beans.BeanWrapperImpl");
private static final JavaType COLLECTIONS = new JavaType(Collections.class);
// local properties
@SuppressWarnings("unused")
private final PhysicalTypeMetadata governorPhysicalTypeMetadata;
private ClassOrInterfaceTypeDetails governorTypeDetails;
private JavaSymbolName revisionItemFielName;
private final JpaAuditRevisionEntityMetadata revisionEntityMetadata;
private final EnversRevisionLogEntityMetadataBuilder revisionEntityBuilder;
private Context context;
private ItdBuilderHelper helper;
public EnversRevisionLogMetadataBuilder(
PhysicalTypeMetadata governorPhysicalTypeMetadata,
JpaAuditRevisionEntityMetadata revisionEntityMetada) {
this.governorPhysicalTypeMetadata = governorPhysicalTypeMetadata;
final Object physicalTypeDetails = governorPhysicalTypeMetadata
.getMemberHoldingTypeDetails();
if (physicalTypeDetails instanceof ClassOrInterfaceTypeDetails) {
// We have reliable physical type details
governorTypeDetails = (ClassOrInterfaceTypeDetails) physicalTypeDetails;
}
else {
throw new IllegalArgumentException(
"Invalid governorPhysicalTypeMetadata");
}
this.revisionEntityMetadata = revisionEntityMetada;
this.revisionEntityBuilder = (EnversRevisionLogEntityMetadataBuilder) revisionEntityMetada
.getRevisionLogBuilder();
}
/**
* {@inheritDoc}
*/
@Override
public void initialize(Context context) {
this.context = context;
this.helper = context.getHelper();
}
/**
* {@inheritDoc}
*/
@Override
public void done() {
this.context = null;
this.helper = null;
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyFindAllFromDate(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
// return findAllVisit(getRevisionNumberForDate(atDate));
body.appendFormalLine(String.format("return %s(%s(%s));",
context.getFindAllMethodName(),
context.getGetRevisionNumberForDate(), parameterNames.get(0)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyFindAllFromRevision(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
// return auditReader().createQuery().forEntitiesAtRevision(Visit.class,
// revision).getResultList();
body.appendFormalLine(String
.format("return %s().createQuery().forEntitiesAtRevision(%s.class, %s).getResultList();",
AUDIT_READER_STATIC_METHOD,
StringUtils.capitalize(context.getEntityName()),
parameterNames.get(0)));
}
/**
* {@inheritDoc}
*/
@Override
public void addCustomArtifact(ItdTypeDetailsBuilder builder) {
// Add @Audit if needed (includin in abstract class)
if (governorTypeDetails.getAnnotation(AUDITED_ANNOTATION) == null) {
builder.addAnnotation(new AnnotationMetadataBuilder(
AUDITED_ANNOTATION));
}
if (!context.isAbstractEntity()) {
builder.addMethod(getAuditReaderStaticMethod());
builder.addMethod(getPropertyMethod());
builder.addMethod(getPropertyMethodWithWrapper());
}
}
/**
* @return gets or creates getProperty(name) method
*/
private MethodMetadata getPropertyMethod() {
// Define method parameter types
List<AnnotatedJavaType> parameterTypes = helper
.toAnnotedJavaType(JavaType.STRING);
// Check if a method exist in type
final MethodMetadata method = helper.methodExists(GET_PROPERTY_METHOD,
parameterTypes);
if (method != null) {
// If it already exists, just return the method
return method;
}
// Define method annotations (none in this case)
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// Define method throws types (none in this case)
List<JavaType> throwsTypes = new ArrayList<JavaType>();
// Define method parameter names (none in this case)
List<JavaSymbolName> parameterNames = helper.toSymbolName("name");
// Create the method body
InvocableMemberBodyBuilder body = new InvocableMemberBodyBuilder();
// return getProperty(name, new BeanWrapperImpl(Visit.class));
body.appendFormalLine(String.format(
"return %s(name, new %s(%s.class));", GET_PROPERTY_METHOD,
helper.getFinalTypeName(BEAN_WRAPPER_IMPL),
StringUtils.capitalize(context.getEntityName())));
// Use the MethodMetadataBuilder for easy creation of MethodMetadata
MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
context.getMetadataId(), Modifier.PUBLIC + Modifier.STATIC,
GET_PROPERTY_METHOD, AUDIT_PROPERTY_GENERIC, parameterTypes,
parameterNames, body);
methodBuilder.setAnnotations(annotations);
methodBuilder.setThrowsTypes(throwsTypes);
return methodBuilder.build(); // Build and return a MethodMetadata
}
/**
* @return gets or creates getProperty(name,beanWrapper)
*/
private MethodMetadata getPropertyMethodWithWrapper() {
// Define method parameter types
List<AnnotatedJavaType> parameterTypes = helper.toAnnotedJavaType(
JavaType.STRING, BEAN_WRAPPER_IMPL);
// Check if a method exist in type
final MethodMetadata method = helper.methodExists(GET_PROPERTY_METHOD,
parameterTypes);
if (method != null) {
// If it already exists, just return the method
return method;
}
// Define method annotations (none in this case)
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// Define method throws types (none in this case)
List<JavaType> throwsTypes = new ArrayList<JavaType>();
// Define method parameter names (none in this case)
List<JavaSymbolName> parameterNames = helper.toSymbolName("name",
"beanWrapper");
// Create the method body
InvocableMemberBodyBuilder body = new InvocableMemberBodyBuilder();
buildGetPropertyMethodWithWrapper(body, helper, context.getEntity());
// Use the MethodMetadataBuilder for easy creation of MethodMetadata
MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
context.getMetadataId(), Modifier.PUBLIC + Modifier.STATIC,
GET_PROPERTY_METHOD, AUDIT_PROPERTY_GENERIC, parameterTypes,
parameterNames, body);
methodBuilder.setAnnotations(annotations);
methodBuilder.setThrowsTypes(throwsTypes);
return methodBuilder.build(); // Build and return a MethodMetadata
}
/**
* Builds method body (implementation) of getProperty(name,beanWrapper)
*
* @param body
* @param helper
*/
private void buildGetPropertyMethodWithWrapper(
InvocableMemberBodyBuilder body, ItdBuilderHelper helper,
JavaType entity) {
// String upperCase = name.toUpperCase();
body.appendFormalLine("String upperCase = name.toUpperCase();");
// if ("$ID$".equals(upperCase)) {
body.appendFormalLine("if (\"$ID$\".equals(upperCase)) {");
body.indent();
// return AuditEntity.id();
body.appendFormalLine(String.format("return %s.id();",
helper.getFinalTypeName(AUDIT_ENTITY)));
// } else if ("$REV$".equals(upperCase)) {
body.indentRemove();
body.appendFormalLine("} else if (\"$REV$\".equals(upperCase)) {");
body.indent();
// return AuditEntity.revisionNumber();
body.appendFormalLine(String.format("return %s.revisionNumber();",
helper.getFinalTypeName(AUDIT_ENTITY)));
// } else if ("$REV_TYPE$".equals(upperCase)) {
body.indentRemove();
body.appendFormalLine("} else if (\"$REV_TYPE$\".equals(upperCase)) {");
body.indent();
// return AuditEntity.revisionNumber();
body.appendFormalLine(String.format("return %s.revisionType();",
helper.getFinalTypeName(AUDIT_ENTITY)));
// } else if ("$REV_USER$".equals(upperCase)) {
body.indentRemove();
body.appendFormalLine("} else if (\"$REV_USER$\".equals(upperCase)) {");
body.indent();
// return AuditEntity.revisionProperty("userName");
body.appendFormalLine(String.format(
"return %s.revisionProperty(\"userName\");",
helper.getFinalTypeName(AUDIT_ENTITY)));
// } else {
body.indentRemove();
body.appendFormalLine("} else {");
body.indent();
// if (name.contains(".")) {
body.appendFormalLine("if (name.contains(\".\")) {");
body.indent();
// throw new
// IllegalArgumentException("Related object property not supported: ".concat(name));
body.appendFormalLine("throw new IllegalArgumentException(\"Related object property not supported: \".concat(name));");
// }
body.indentRemove();
body.appendFormalLine("}");
// if (beanWrapper.isReadableProperty(name)) {
body.appendFormalLine("if (beanWrapper.isReadableProperty(name)) {");
body.indent();
// return AuditEntity.property(name);
body.appendFormalLine(String.format("return %s.property(name);",
helper.getFinalTypeName(AUDIT_ENTITY)));
// }
body.indentRemove();
body.appendFormalLine("}");
// }
body.indentRemove();
body.appendFormalLine("}");
// throw new
// IllegalArgumentException("Property not found on: ".concat(name));
body.appendFormalLine(String
.format("throw new IllegalArgumentException(\"Property not found on %s: \".concat(name));",
entity));
}
/**
* @return creates getAuditReader() method
*/
private MethodMetadata getAuditReaderStaticMethod() {
return commonGetAuditReaderStaticMethod(context,
AUDIT_READER_STATIC_METHOD, Modifier.PUBLIC + Modifier.STATIC,
"return %s.get(entityManager());", null);
}
/**
* Generates a method on itd without parameters, annotation or throws
* declarations
*
* @param context
* @param methodName
* @param modifiers
* @param bodyStr
* @param annotations (optional)
* @return
*/
private MethodMetadata commonGetAuditReaderStaticMethod(Context context,
JavaSymbolName methodName, int modifiers, String bodyStr,
List<AnnotationMetadataBuilder> aAnnotations) {
// Define method parameter types
List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>(
0);
// Check if a method exist in type
final MethodMetadata method = helper.methodExists(methodName,
parameterTypes);
if (method != null) {
// If it already exists, just return the method
return method;
}
// Define method annotations (none in this case)
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
if (aAnnotations != null && !aAnnotations.isEmpty()) {
annotations.addAll(aAnnotations);
}
// Define method throws types (none in this case)
List<JavaType> throwsTypes = new ArrayList<JavaType>();
// Define method parameter names (none in this case)
List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>();
// Create the method body
InvocableMemberBodyBuilder body = new InvocableMemberBodyBuilder();
// return AuditReaderFactory.get(entityManager());
body.appendFormalLine(String.format(bodyStr,
helper.getFinalTypeName(AUDIT_READER_FACTORY)));
// Use the MethodMetadataBuilder for easy creation of MethodMetadata
MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
context.getMetadataId(), modifiers, methodName, AUDIT_READER,
parameterTypes, parameterNames, body);
methodBuilder.setAnnotations(annotations);
methodBuilder.setThrowsTypes(throwsTypes);
return methodBuilder.build(); // Build and return a MethodMetadata
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyGetRevisionNumberForDate(
InvocableMemberBodyBuilder body, List<JavaSymbolName> parameterNames) {
// return (Long) auditReader().getRevisionNumberForDate(aDate);
body.appendFormalLine(String.format(
"return (Long) %s().getRevisionNumberForDate(%s);",
AUDIT_READER_STATIC_METHOD, parameterNames.get(0)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyFindFromDate(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
// AuditReader reader = auditReader();
body.appendFormalLine(String.format("%s reader = %s();",
helper.getFinalTypeName(AUDIT_READER),
AUDIT_READER_STATIC_METHOD));
// Long revision = (Long) reader.getRevisionNumberForDate(atDate);
body.appendFormalLine(String.format(
"%s revision = (Long) reader.getRevisionNumberForDate(%s);",
helper.getFinalTypeName(JavaType.LONG_OBJECT),
parameterNames.get(1)));
// if (revision == null) {
body.appendFormalLine("if (revision == null) {");
body.indent();
// return null;
body.appendFormalLine("return null;");
// }
body.indentRemove();
body.appendFormalLine("}");
// return reader.find(Visit.class, id, revision);
body.appendFormalLine(String.format(
"return reader.find(%s.class, %s, revision);",
StringUtils.capitalize(context.getEntityName()),
parameterNames.get(0)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyFindFromRevision(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
// AuditReader reader = auditReader();
body.appendFormalLine(String.format("%s reader = %s();",
helper.getFinalTypeName(AUDIT_READER),
AUDIT_READER_STATIC_METHOD));
// return reader.find(Visit.class, id, revision);
body.appendFormalLine(String.format(
"return reader.find(%s.class, %s, %s);",
StringUtils.capitalize(context.getEntityName()),
parameterNames.get(0), parameterNames.get(1)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyGetRevisions(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
// Map<String, Object> criteria = new HashMap<String, Object>(1);
body.appendFormalLine(String.format("%s criteria = new %s(1);",
helper.getFinalTypeName(MAP_STRING_OBJECT),
helper.getFinalTypeName(HASHMAP_STRING_OBJECT)));
// criteria.put("$ID$", id);
body.appendFormalLine(String.format("criteria.put(\"$ID$\", %s);",
parameterNames.get(0)));
// return findVisitRevisionByDates(fromDate, toDate, criteria, null,
// start, limit);
body.appendFormalLine(String.format(
"return %s(%s, %s, criteria, null, %s, %s);",
context.getFindRevisionsByDatesMethodName(),
parameterNames.get(1), parameterNames.get(2),
parameterNames.get(3), parameterNames.get(4)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyGetRevisionsInstance(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
JavaSymbolName identifierGetter = helper
.getGetterMethodNameForField(context.getIdentifier()
.getFieldName());
JavaType arrayListRevisionItems = new JavaType(
JdkJavaType.ARRAY_LIST.getFullyQualifiedTypeName(), 0,
DataType.TYPE, null,
Arrays.asList(context.getRevisonItemType()));
// if (getId() == null) {
body.appendFormalLine(String.format("if (%s() == null) {",
identifierGetter));
body.indent();
// // No persistent visit --> No history
body.appendFormalLine("// No persistent visit --> No history");
// return Collections.unmodifiableList(new ArrayList<VisitRevision>(0));
body.appendFormalLine(String.format(
"return %s.unmodifiableList(new %s(0));",
helper.getFinalTypeName(COLLECTIONS),
helper.getFinalTypeName(arrayListRevisionItems)));
// }
body.indentRemove();
body.appendFormalLine("}");
// return getVisitRevisions(getId(), fromDate, toDate, start, limit);
body.appendFormalLine(String.format(
"return %s(%s(), fromDate, toDate, start, limit);",
context.getGetRevisionsMethodName(), identifierGetter,
parameterNames.get(0), parameterNames.get(1),
parameterNames.get(2), parameterNames.get(3),
helper.getFinalTypeName(arrayListRevisionItems)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyFindRevisionByDates(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
// if (fromDate != null && toDate != null) {
body.appendFormalLine(String.format("if (%s != null && %s != null) {",
parameterNames.get(0), parameterNames.get(1)));
body.indent();
// if (toDate.before(fromDate)) {
body.appendFormalLine(String.format("if (%s.before(%s)) {",
parameterNames.get(1), parameterNames.get(0)));
body.indent();
// throw new
// IllegalArgumentException("fromDate cannot be lower than toDate");
body.appendFormalLine(String
.format("throw new IllegalArgumentException(\"%s cannot be lower than %s\");",
parameterNames.get(0), parameterNames.get(1)));
// }
body.indentRemove();
body.appendFormalLine("}");
// }
body.indentRemove();
body.appendFormalLine("}");
// Long fromRevision = null;
body.appendFormalLine("Long fromRevision = null;");
// Long toRevision = null;
body.appendFormalLine("Long toRevision = null;");
// if (fromDate != null) {
body.appendFormalLine(String.format("if (%s != null) {",
parameterNames.get(0)));
body.indent();
// fromRevision = getRevisionNumberForDate(fromDate);
body.appendFormalLine(String.format("fromRevision = %s(%s);",
context.getGetRevisionNumberForDate(), parameterNames.get(0)));
// }
body.indentRemove();
body.appendFormalLine("}");
// if (toDate != null) {
body.appendFormalLine(String.format("if (%s != null) {",
parameterNames.get(1)));
body.indent();
// toRevision = getRevisionNumberForDate(fromDate);
body.appendFormalLine(String.format("toRevision = %s(%s);",
context.getGetRevisionNumberForDate(), parameterNames.get(1)));
// }
body.indentRemove();
body.appendFormalLine("}");
// return
// findVisitRevisions(fromRevision,toRevision,filterMap,order,start,limit);
body.appendFormalLine(String.format(
"return %s(fromRevision,toRevision,%s,%s,%s,%s);",
context.getFindRevisionsMethodName(), parameterNames.get(2),
parameterNames.get(3), parameterNames.get(4),
parameterNames.get(5)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyFindRevision(InvocableMemberBodyBuilder body,
List<JavaSymbolName> parameterNames) {
// AuditReader reader = auditReader();
body.appendFormalLine(String.format("%s reader = %s();",
helper.getFinalTypeName(AUDIT_READER),
AUDIT_READER_STATIC_METHOD));
// BeanWrapperImpl beanWrapper = new BeanWrapperImpl(Visit.class);
String capitalizeEntityName = StringUtils.capitalize(context
.getEntityName());
body.appendFormalLine(String.format(
"%s beanWrapper = new %s(%s.class);",
helper.getFinalTypeName(BEAN_WRAPPER_IMPL),
helper.getFinalTypeName(BEAN_WRAPPER_IMPL),
capitalizeEntityName));
body.appendFormalLine("");
body.appendFormalLine("// Get revisions list");
// AuditQuery query =
// reader.createQuery().forRevisionsOfEntity(Visit.class, false, true);
body.appendFormalLine(String
.format("%s query = reader.createQuery().forRevisionsOfEntity(%s.class, false, true);",
helper.getFinalTypeName(AUDIT_QUERY),
capitalizeEntityName));
// if (fromRevision != null && toRevision != null) {
body.appendFormalLine(String.format("if (%s != null && %s != null) {",
parameterNames.get(0), parameterNames.get(1)));
body.indent();
// query.add(AuditEntity.revisionNumber().between(fromRevision,
// toRevision));
body.appendFormalLine(String.format(
"query.add(%s.revisionNumber().between(%s, %s));",
helper.getFinalTypeName(AUDIT_ENTITY), parameterNames.get(0),
parameterNames.get(1)));
// } else if (fromRevision != null) {
body.indentRemove();
body.appendFormalLine(String.format("} else if (%s != null) {",
parameterNames.get(0)));
body.indent();
// query.add(AuditEntity.revisionNumber().ge(fromRevision));
body.appendFormalLine(String.format(
"query.add(%s.revisionNumber().ge(%s));",
helper.getFinalTypeName(AUDIT_ENTITY), parameterNames.get(0)));
// } else if (toRevision != null) {
body.indentRemove();
body.appendFormalLine(String.format("} else if (%s != null) {",
parameterNames.get(1)));
body.indent();
// query.add(AuditEntity.revisionNumber().le(toRevision));
body.appendFormalLine(String.format(
"query.add(%s.revisionNumber().le(%s));",
helper.getFinalTypeName(AUDIT_ENTITY), parameterNames.get(1)));
// } (else if)
body.indentRemove();
body.appendFormalLine("}");
body.appendFormalLine("");
// AuditConjunction criteria = null;
body.appendFormalLine(String.format("%s criteria = null;",
helper.getFinalTypeName(AUDIT_CONJUNTION)));
body.appendFormalLine("");
// if (filterMap != null && !filterMap.isEmpty()) {
body.appendFormalLine(String.format(
"if (%s != null && !%s.isEmpty()) {", parameterNames.get(2),
parameterNames.get(2)));
body.indent();
// criteria = AuditEntity.conjunction();
body.appendFormalLine(String.format("criteria = %s.conjunction();",
helper.getFinalTypeName(AUDIT_ENTITY)));
// for (Entry<String, Object> entry : filterMap.entrySet()) {
body.appendFormalLine(String.format("for (%s entry : %s.entrySet()) {",
helper.getFinalTypeName(ENTRY_STRING_OBJECT),
parameterNames.get(2)));
body.indent();
// criteria.add(((AuditProperty<Object>)
// getProperty(entry.getKey(),beanWrapper)).eq(entry.getValue()));
body.appendFormalLine(String
.format("criteria.add(((%s) %s(entry.getKey(),beanWrapper)).eq(entry.getValue()));",
helper.getFinalTypeName(AUDIT_PROPERTY_OBJECT),
GET_PROPERTY_METHOD));
// } (for)
body.indentRemove();
body.appendFormalLine("}");
// query.add(criteria);
body.appendFormalLine("query.add(criteria);");
// } (if)
body.indentRemove();
body.appendFormalLine("}");
body.appendFormalLine("");
// Prepare order
body.appendFormalLine("// Prepare order");
// AuditProperty<?> orderProp;
body.appendFormalLine(String.format("%s<?> orderProp;",
helper.getFinalTypeName(AUDIT_PROPERTY)));
// AuditOrder orderObj;
body.appendFormalLine(String.format("%s orderObj;",
helper.getFinalTypeName(AUDIT_ORDER)));
// if (order != null && !order.isEmpty()) {
body.appendFormalLine(String.format(
"if (%s != null && !%s.isEmpty()) {", parameterNames.get(3),
parameterNames.get(3)));
body.indent();
// for (String orderStr : %s) {
body.appendFormalLine(String.format("for (String orderStr : order) {",
parameterNames.get(3)));
body.indent();
// if (StringUtils.contains(orderStr, "|")) {
body.appendFormalLine(String.format(
"if (%s.contains(orderStr, \"|\")) {",
helper.getFinalTypeName(STRING_UTILS)));
body.indent();
// orderProp = getProperty(StringUtils.substringBefore(orderStr,
// "|"),beanWrapper);
body.appendFormalLine(String
.format("orderProp = %s(%s.substringBefore(orderStr, \"|\"),beanWrapper);",
GET_PROPERTY_METHOD,
helper.getFinalTypeName(STRING_UTILS)));
// if ("ASC".equals(StringUtils.substringAfter(orderStr,
// "|").toUpperCase())) {
body.appendFormalLine(String
.format("if (\"ASC\".equals(%s.substringAfter(orderStr, \"|\").toUpperCase())) {",
helper.getFinalTypeName(STRING_UTILS)));
body.indent();
// orderObj = orderProp.asc();
body.appendFormalLine("orderObj = orderProp.asc();");
// } else if ("DESC".equals(StringUtils.substringAfter(orderStr,
// "|").toUpperCase())) {
body.indentRemove();
body.appendFormalLine(String
.format("} else if (\"DESC\".equals(%s.substringAfter(orderStr, \"|\").toUpperCase())) {",
helper.getFinalTypeName(STRING_UTILS)));
body.indent();
// orderObj = orderProp.desc();
body.appendFormalLine("orderObj = orderProp.desc();");
// } else {
body.indentRemove();
body.appendFormalLine("} else {");
body.indent();
// throw new
// IllegalArgumentException("Invalid order '".concat(orderStr).concat("'"));
body.appendFormalLine("throw new IllegalArgumentException(\"Invalid order '\".concat(orderStr).concat(\"'\"));");
// } (if ("ASC".equals...
body.indentRemove();
body.appendFormalLine("}");
// } else { [if (SringUtils.contains...
body.indentRemove();
body.appendFormalLine("} else {");
body.indent();
// orderObj = AuditEntity.property(orderStr).asc();
body.appendFormalLine(String.format(
"orderObj = %s.property(orderStr).asc();",
helper.getFinalTypeName(AUDIT_ENTITY)));
// } (if [if (SringUtils.contains...
body.indentRemove();
body.appendFormalLine("}");
// query.addOrder(orderObj);
body.appendFormalLine("query.addOrder(orderObj);");
// } (for
body.indentRemove();
body.appendFormalLine("}");
// } (if order != null..
body.indentRemove();
body.appendFormalLine("}");
body.appendFormalLine("");
// // start modifier
body.appendFormalLine("// start modifier");
// if (start != null) {
body.appendFormalLine(String.format("if (%s != null) {",
parameterNames.get(4)));
body.indent();
// query.setFirstResult(start);
body.appendFormalLine(String.format("query.setFirstResult(%s);",
parameterNames.get(4)));
// }
body.indentRemove();
body.appendFormalLine("}");
// if (limit != null) {
body.appendFormalLine(String.format("if (%s != null) {",
parameterNames.get(5)));
body.indent();
// query.setMaxResults(limit);
body.appendFormalLine(String.format("query.setMaxResults(%s);",
parameterNames.get(5)));
// }
body.indentRemove();
body.appendFormalLine("}");
// List<Object[]> revisions = query.getResultList();
body.appendFormalLine(String.format(
"%s revisions = query.getResultList();",
helper.getFinalTypeName(LIST_OBJECT_ARRAY)));
// return VisitRevision.createList(revisions, reader);
body.appendFormalLine(String.format("return %s.%s(revisions, reader);",
context.getRevisonItemTypeName(), CREATE_ITEM_LIST_METHOD));
}
/**
* {@inheritDoc}
*/
@Override
public void addCustomArtifactToRevisionItem(
ClassOrInterfaceTypeDetailsBuilder classBuilder) {
classBuilder.addField(createRevisionItemField());
classBuilder.addField(createRevisionEntityRevisionField());
classBuilder.addField(createRevisionTypeField());
classBuilder.addConstructor(createRevisionItemConstructor());
classBuilder.addMethod(createRevisionItemCreateList());
}
/**
* @return Creates constructor for XXRevsion class
*/
private ConstructorMetadata createRevisionItemConstructor() {
// Define method parameter types
List<AnnotatedJavaType> parameterTypes = new ArrayList<AnnotatedJavaType>(
2);
parameterTypes.add(new AnnotatedJavaType(context.getEntity()));
parameterTypes.add(new AnnotatedJavaType(revisionEntityMetadata
.getType()));
parameterTypes.add(new AnnotatedJavaType(REVISON_TYPE));
// Define method annotations (none in this case)
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// Define method throws types (none in this case)
List<JavaType> throwsTypes = new ArrayList<JavaType>();
// Define method parameter names (none in this case)
List<JavaSymbolName> parameterNames = new ArrayList<JavaSymbolName>(3);
parameterNames.add(new JavaSymbolName(StringUtils.uncapitalize(context
.getEntityName())));
parameterNames.add(REV_ITEM_REVISON_ENTITY_FIELD);
parameterNames.add(REV_ITEM_REVISON_TYPE_FIELD);
// Create the method body
InvocableMemberBodyBuilder body = new InvocableMemberBodyBuilder();
helper.buildSetterMethodBody(body, parameterNames.get(0));
helper.buildSetterMethodBody(body, parameterNames.get(1));
helper.buildSetterMethodBody(body, parameterNames.get(2));
// Use the MethodMetadataBuilder for easy creation of MethodMetadata
ConstructorMetadataBuilder builder = new ConstructorMetadataBuilder(
context.getMetadataId());
builder.setParameterTypes(parameterTypes);
builder.setParameterNames(parameterNames);
builder.setModifier(Modifier.PUBLIC);
builder.setAnnotations(annotations);
builder.setThrowsTypes(throwsTypes);
builder.setBodyBuilder(body);
return builder.build(); // Build and return a MethodMetadata
}
/**
* @return Creates XXXRevision.createList(list,reader) static method
*/
private MethodMetadata createRevisionItemCreateList() {
// Define method parameter types
List<AnnotatedJavaType> parameterTypes = helper.toAnnotedJavaType(
LIST_OBJECT_ARRAY, AUDIT_READER);
// Define method annotations (none in this case)
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>();
// Define method throws types (none in this case)
List<JavaType> throwsTypes = new ArrayList<JavaType>();
// Define method parameter names (none in this case)
List<JavaSymbolName> parameterNames = helper.toSymbolName("list",
"reader");
// Create the method body
InvocableMemberBodyBuilder body = new InvocableMemberBodyBuilder();
buildRevisionItemCreateListMethodBody(body, parameterNames);
// Use the MethodMetadataBuilder for easy creation of MethodMetadata
MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
context.getMetadataId(), Modifier.PUBLIC + Modifier.STATIC,
CREATE_ITEM_LIST_METHOD, context.getRevisonItemListType(),
parameterTypes, parameterNames, body);
methodBuilder.setAnnotations(annotations);
methodBuilder.setThrowsTypes(throwsTypes);
return methodBuilder.build(); // Build and return a MethodMetadata
}
/**
* Builds method body (implementation) of
* XXXRevision.createList(list,reader)
*
* @param body
* @param context
* @param parameterNames
*/
private void buildRevisionItemCreateListMethodBody(
InvocableMemberBodyBuilder body, List<JavaSymbolName> parameterNames) {
JavaType arrayListRevison = new JavaType(
ARRAYLIST.getFullyQualifiedTypeName(), 0, DataType.TYPE, null,
Arrays.asList(context.getRevisonItemType()));
// ArrayList<VisitRevision> newList = new
// ArrayList<VisitRevision>(list.size());
body.appendFormalLine(String.format("%s newList = new %s(%s.size());",
helper.getFinalTypeName(arrayListRevison),
helper.getFinalTypeName(arrayListRevison),
parameterNames.get(0)));
// for (Object[] item : list) {
body.appendFormalLine(String.format("for (%s item : %s) {",
helper.getFinalTypeName(OBJECT_ARRAY), parameterNames.get(0)));
body.indent();
// newList.add(new VisitRevision((Visit) item[0],
// (HistoryRevisionEntity) item[1], (RevisionType) item[2]));
body.appendFormalLine(String
.format("newList.add(new %s((%s) item[0], (%s) item[1], (%s) item[2]));",
helper.getFinalTypeName(context.getRevisonItemType()),
StringUtils.capitalize(context.getEntityName()), helper
.getFinalTypeName(revisionEntityMetadata
.getType()), helper
.getFinalTypeName(REVISON_TYPE)));
// }
body.indentRemove();
body.appendFormalLine("}");
// return Collections.unmodifiableList(newList);
body.appendFormalLine(String.format(
"return %s.unmodifiableList(newList);",
helper.getFinalTypeName(COLLECTIONS)));
}
/**
* @return creates XXXRevsion.item field
*/
private FieldMetadata createRevisionItemField() {
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(
0);
return new FieldMetadataBuilder(context.getMetadataId(),
Modifier.PRIVATE, annotations, getRevisionItemFieldName(),
context.getEntity()).build();
}
/**
* @return creates XXXRevision.revision field
*/
private FieldMetadata createRevisionEntityRevisionField() {
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(
0);
return new FieldMetadataBuilder(context.getMetadataId(),
Modifier.PRIVATE, annotations, REV_ITEM_REVISON_ENTITY_FIELD,
revisionEntityMetadata.getType()).build();
}
/**
* @return creates XXXRevsion.type field
*/
private FieldMetadata createRevisionTypeField() {
List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(
0);
return new FieldMetadataBuilder(context.getMetadataId(),
Modifier.PRIVATE, annotations, REV_ITEM_REVISON_TYPE_FIELD,
REVISON_TYPE).build();
}
/**
* @param context
* @return XXXRevision.item field name
*/
private JavaSymbolName getRevisionItemFieldName() {
if (revisionItemFielName == null) {
revisionItemFielName = new JavaSymbolName(
StringUtils.uncapitalize(context.getEntityName()));
}
return revisionItemFielName;
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemGetItem(InvocableMemberBodyBuilder body) {
body.appendFormalLine(String.format("return %s;",
getRevisionItemFieldName()));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemGetRevisionNumber(
InvocableMemberBodyBuilder body) {
body.appendFormalLine(String.format("return this.%s.%s();",
REV_ITEM_REVISON_ENTITY_FIELD,
revisionEntityBuilder.getRevisionIdGetterName()));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemGetRevisionDate(
InvocableMemberBodyBuilder body) {
body.appendFormalLine(String.format("return this.%s.%s();",
REV_ITEM_REVISON_ENTITY_FIELD,
revisionEntityBuilder.getRevisionDateGetterName()));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemGetRevisionUser(
InvocableMemberBodyBuilder body) {
body.appendFormalLine(String.format("return this.%s.%s();",
REV_ITEM_REVISON_ENTITY_FIELD,
revisionEntityBuilder.getRevisonUserGetterName()));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemIsCreate(InvocableMemberBodyBuilder body) {
body.appendFormalLine(String.format("return this.%s == %s.ADD;",
REV_ITEM_REVISON_TYPE_FIELD, context.getHelper()
.getFinalTypeName(REVISON_TYPE)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemIsUpdate(InvocableMemberBodyBuilder body) {
body.appendFormalLine(String.format("return this.%s == %s.MOD;",
REV_ITEM_REVISON_TYPE_FIELD, context.getHelper()
.getFinalTypeName(REVISON_TYPE)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemIsDelete(InvocableMemberBodyBuilder body) {
body.appendFormalLine(String.format("return this.%s == %s.DEL;",
REV_ITEM_REVISON_TYPE_FIELD, context.getHelper()
.getFinalTypeName(REVISON_TYPE)));
}
/**
* {@inheritDoc}
*/
@Override
public void buildBodyRevisionItemGetType(InvocableMemberBodyBuilder body) {
// if (isCreate()) {
body.appendFormalLine(String.format("if (%s()) {",
JpaAuditMetadata.REV_ITEM_IS_CREATE_METHOD));
body.indent();
// return "CREATE";
body.appendFormalLine("return \"CREATE\";");
// }
body.indentRemove();
body.appendFormalLine("}");
// if (isUpdate()) {
body.appendFormalLine(String.format("if (%s()) {",
JpaAuditMetadata.REV_ITEM_IS_UPDATE_METHOD));
body.indent();
// return "UPDATE";
body.appendFormalLine("return \"UPDATE\";");
// }
body.indentRemove();
body.appendFormalLine("}");
// if (isDelete()) {
body.appendFormalLine(String.format("if (%s()) {",
JpaAuditMetadata.REV_ITEM_IS_DELETE_METHOD));
body.indent();
// return "DELETE";
body.appendFormalLine("return \"DELETE\";");
// }
body.indentRemove();
body.appendFormalLine("}");
// return null;
body.appendFormalLine("return null;");
}
}