package org.springframework.roo.addon.dod; import static org.springframework.roo.model.JpaJavaType.ENTITY; import static org.springframework.roo.model.SpringJavaType.PERSISTENT; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.List; import org.apache.commons.lang3.Validate; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Reference; import org.apache.felix.scr.annotations.Service; import org.springframework.roo.classpath.PhysicalTypeCategory; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.TypeLocationService; import org.springframework.roo.classpath.TypeManagementService; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder; import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.classpath.details.annotations.AnnotationMetadataBuilder; import org.springframework.roo.classpath.details.annotations.ClassAttributeValue; import org.springframework.roo.classpath.scanner.MemberDetails; import org.springframework.roo.classpath.scanner.MemberDetailsScanner; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.model.RooJavaType; import org.springframework.roo.project.FeatureNames; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.Path; import org.springframework.roo.project.ProjectOperations; /** * Implementation of {@link DataOnDemandOperations}. * * @author Alan Stewart * @since 1.1.3 */ @Component @Service public class DataOnDemandOperationsImpl implements DataOnDemandOperations { @Reference private MemberDetailsScanner memberDetailsScanner; @Reference private MetadataService metadataService; @Reference private ProjectOperations projectOperations; @Reference private TypeLocationService typeLocationService; @Reference private TypeManagementService typeManagementService; /** * @param entity the entity to lookup required * @return the type details (never null; throws an exception if it cannot be * obtained or parsed) */ private ClassOrInterfaceTypeDetails getEntity(final JavaType entity) { final ClassOrInterfaceTypeDetails cid = typeLocationService .getTypeDetails(entity); Validate.notNull(cid, "Java source code details unavailable for type '" + entity + "'"); return cid; } public boolean isDataOnDemandInstallationPossible() { return projectOperations.isFocusedProjectAvailable() && projectOperations.isFeatureInstalledInFocusedModule( FeatureNames.JPA, FeatureNames.MONGO); } public void newDod(final JavaType entity, final JavaType name) { Validate.notNull(entity, "Entity to produce a data on demand provider for is required"); Validate.notNull(name, "Name of the new data on demand provider is required"); final LogicalPath path = LogicalPath.getInstance(Path.SRC_TEST_JAVA, projectOperations.getFocusedModuleName()); Validate.notNull(path, "Location of the new data on demand provider is required"); // Verify the requested entity actually exists as a class and is not // abstract final ClassOrInterfaceTypeDetails cid = getEntity(entity); Validate.isTrue( cid.getPhysicalTypeCategory() == PhysicalTypeCategory.CLASS, "Type " + entity.getFullyQualifiedTypeName() + " is not a class"); Validate.isTrue(!Modifier.isAbstract(cid.getModifier()), "Type " + entity.getFullyQualifiedTypeName() + " is abstract"); // Check if the requested entity is a JPA @Entity final MemberDetails memberDetails = memberDetailsScanner .getMemberDetails(DataOnDemandOperationsImpl.class.getName(), cid); final AnnotationMetadata entityAnnotation = memberDetails .getAnnotation(ENTITY); final AnnotationMetadata persistentAnnotation = memberDetails .getAnnotation(PERSISTENT); Validate.isTrue(entityAnnotation != null || persistentAnnotation != null, "Type " + entity.getFullyQualifiedTypeName() + " must be a persistent type"); // Everything is OK to proceed final String declaredByMetadataId = PhysicalTypeIdentifier .createIdentifier(name, path); if (metadataService.get(declaredByMetadataId) != null) { // The file already exists return; } final List<AnnotationMetadataBuilder> annotations = new ArrayList<AnnotationMetadataBuilder>(); final List<AnnotationAttributeValue<?>> dodConfig = new ArrayList<AnnotationAttributeValue<?>>(); dodConfig.add(new ClassAttributeValue(new JavaSymbolName("entity"), entity)); annotations.add(new AnnotationMetadataBuilder( RooJavaType.ROO_DATA_ON_DEMAND, dodConfig)); final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder( declaredByMetadataId, Modifier.PUBLIC, name, PhysicalTypeCategory.CLASS); cidBuilder.setAnnotations(annotations); typeManagementService.createOrUpdateTypeOnDisk(cidBuilder.build()); } }