package org.springframework.roo.addon.jpa.addon.dod.configuration; import java.lang.reflect.Modifier; import java.util.SortedSet; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.Validate; import org.apache.commons.lang3.builder.ToStringBuilder; import org.springframework.roo.addon.jpa.annotations.dod.RooJpaDataOnDemandConfiguration; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.ConstructorMetadataBuilder; import org.springframework.roo.classpath.details.FieldMetadataBuilder; import org.springframework.roo.classpath.details.MethodMetadata; import org.springframework.roo.classpath.details.MethodMetadataBuilder; import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder; import org.springframework.roo.classpath.itd.AbstractItdTypeDetailsProvidingMetadataItem; import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder; import org.springframework.roo.metadata.MetadataIdentificationUtils; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.model.JpaJavaType; import org.springframework.roo.model.SpringJavaType; import org.springframework.roo.project.LogicalPath; /** * Metadata for {@link RooJpaDataOnDemandConfiguration}. * * @author Sergio Clares * @since 2.0 */ public class JpaDataOnDemandConfigurationMetadata extends AbstractItdTypeDetailsProvidingMetadataItem { private static final String PROVIDES_TYPE_STRING = JpaDataOnDemandConfigurationMetadata.class .getName(); private static final String PROVIDES_TYPE = MetadataIdentificationUtils .create(PROVIDES_TYPE_STRING); private static final String ENTITY_MANAGER_FIELD_NAME = "entityManager"; public static String createIdentifier(final JavaType javaType, final LogicalPath path) { return PhysicalTypeIdentifierNamingUtils.createIdentifier(PROVIDES_TYPE_STRING, javaType, path); } public static String createIdentifier(ClassOrInterfaceTypeDetails details) { final LogicalPath logicalPath = PhysicalTypeIdentifier.getPath(details.getDeclaredByMetadataId()); return createIdentifier(details.getType(), logicalPath); } public static JavaType getJavaType(final String metadataIdentificationString) { return PhysicalTypeIdentifierNamingUtils.getJavaType(PROVIDES_TYPE_STRING, metadataIdentificationString); } public static String getMetadataIdentiferType() { return PROVIDES_TYPE; } public static LogicalPath getPath(final String metadataIdentificationString) { return PhysicalTypeIdentifierNamingUtils.getPath(PROVIDES_TYPE_STRING, metadataIdentificationString); } public static boolean isValid(final String metadataIdentificationString) { return PhysicalTypeIdentifierNamingUtils.isValid(PROVIDES_TYPE_STRING, metadataIdentificationString); } /** * Constructor * * @param identifier * @param aspectName * @param governorPhysicalTypeMetadata * @param dataOnDemandTypes */ public JpaDataOnDemandConfigurationMetadata(final String identifier, final JavaType aspectName, final PhysicalTypeMetadata governorPhysicalTypeMetadata, final SortedSet<JavaType> dataOnDemandTypes) { super(identifier, aspectName, governorPhysicalTypeMetadata); Validate.isTrue(isValid(identifier), "Metadata identification string '%s' does not appear to be a valid", identifier); // Add EntityManager field ensureGovernorHasField(getEntityManagerField()); // Add constructor ensureGovernorHasConstructor(getConstructor()); // Add @TestConfiguration ensureGovernorIsAnnotated(new AnnotationMetadataBuilder(SpringJavaType.TEST_CONFIGURATION)); // Add DoD bean creation method for (JavaType dodType : dataOnDemandTypes) { ensureGovernorHasMethod(new MethodMetadataBuilder(getDodTypeBeanCreationMethod(dodType))); } // Build the ITD itdTypeDetails = builder.build(); } /** * Builds and returns a class constructor which injects * {@link EntityManager} field. * * @return a ConstructorMetadataBuilder to add to ITD. */ private ConstructorMetadataBuilder getConstructor() { // Create instance and add parameters ConstructorMetadataBuilder constructorBuilder = new ConstructorMetadataBuilder(this.getId()); constructorBuilder.addParameter(ENTITY_MANAGER_FIELD_NAME, JpaJavaType.ENTITY_MANAGER); // Add body InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine("%1$s(%2$s);", getMutatorMethod(getEntityManagerField().build()) .getMethodName(), ENTITY_MANAGER_FIELD_NAME); constructorBuilder.setBodyBuilder(bodyBuilder); constructorBuilder.setModifier(Modifier.PUBLIC); // Add @Autowired constructorBuilder.addAnnotation(new AnnotationMetadataBuilder(SpringJavaType.AUTOWIRED)); return constructorBuilder; } /** * Builds and returns an {@link EntityManager} field type in the ITD. * * @return the FieldMetadataBuilder. */ private FieldMetadataBuilder getEntityManagerField() { FieldMetadataBuilder fieldBuilder = new FieldMetadataBuilder(this.getId(), Modifier.PRIVATE, new JavaSymbolName( ENTITY_MANAGER_FIELD_NAME), JpaJavaType.ENTITY_MANAGER, null); return fieldBuilder; } /** * Builds and returns a method used to instance a DataOnDemand class using * {@link EntityManager} and `@Bean` annotation. * * @param dodType * the class to inject in the Spring context. * @return the MethodMetadata to add to ITD. */ private MethodMetadata getDodTypeBeanCreationMethod(JavaType dodType) { // Define methodName final JavaSymbolName methodName = new JavaSymbolName(StringUtils.uncapitalize(dodType.getSimpleTypeName())); // Check if method exists MethodMetadata existingMethod = getGovernorMethod(methodName); if (existingMethod != null) { return existingMethod; } // Add body InvocableMemberBodyBuilder bodyBuilder = new InvocableMemberBodyBuilder(); bodyBuilder.appendFormalLine("return new %s(%s());", getNameOfJavaType(dodType), getAccessorMethod(getEntityManagerField().build()).getMethodName()); // Create method MethodMetadataBuilder method = new MethodMetadataBuilder(this.getId(), Modifier.PUBLIC, methodName, dodType, bodyBuilder); // Add annotation method.addAnnotation(new AnnotationMetadataBuilder(SpringJavaType.BEAN)); return method.build(); } @Override public String toString() { final ToStringBuilder builder = new ToStringBuilder(this); builder.append("identifier", getId()); builder.append("valid", valid); builder.append("aspectName", aspectName); builder.append("destinationType", destination); builder.append("governor", governorPhysicalTypeMetadata.getId()); builder.append("itdTypeDetails", itdTypeDetails); return builder.toString(); } }