package org.springframework.roo.addon.jpa.activerecord; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.CLEAR_METHOD_DEFAULT; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.COUNT_METHOD_DEFAULT; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.FIND_ALL_METHOD_DEFAULT; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.FIND_METHOD_DEFAULT; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.FLUSH_METHOD_DEFAULT; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.MERGE_METHOD_DEFAULT; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.PERSIST_METHOD_DEFAULT; import static org.springframework.roo.addon.jpa.activerecord.RooJpaActiveRecord.REMOVE_METHOD_DEFAULT; import static org.springframework.roo.classpath.customdata.CustomDataKeys.CLEAR_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.COUNT_ALL_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_ALL_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_ENTRIES_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FIND_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.FLUSH_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.MERGE_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.PERSIST_METHOD; import static org.springframework.roo.classpath.customdata.CustomDataKeys.REMOVE_METHOD; import static org.springframework.roo.model.RooJavaType.ROO_JPA_ACTIVE_RECORD; import static org.springframework.roo.model.RooJavaType.ROO_JPA_ENTITY; import java.util.List; import org.apache.commons.lang3.StringUtils; 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.osgi.service.component.ComponentContext; import org.springframework.roo.addon.configurable.ConfigurableMetadataProvider; import org.springframework.roo.addon.jpa.entity.JpaEntityAnnotationValues; import org.springframework.roo.addon.plural.PluralMetadata; import org.springframework.roo.addon.plural.PluralMetadataProvider; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.customdata.taggers.CustomDataKeyDecorator; import org.springframework.roo.classpath.customdata.taggers.MethodMatcher; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.MemberFindingUtils; import org.springframework.roo.classpath.itd.AbstractItdMetadataProvider; import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem; import org.springframework.roo.classpath.itd.MemberHoldingTypeDetailsMetadataItem; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.project.FeatureNames; import org.springframework.roo.project.LogicalPath; import org.springframework.roo.project.ProjectMetadata; import org.springframework.roo.project.ProjectOperations; /** * Implementation of {@link JpaActiveRecordMetadataProvider}. * * @author Ben Alex * @since 1.0 */ @Component(immediate = true) @Service public class JpaActiveRecordMetadataProviderImpl extends AbstractItdMetadataProvider implements JpaActiveRecordMetadataProvider { @Reference private ConfigurableMetadataProvider configurableMetadataProvider; @Reference private CustomDataKeyDecorator customDataKeyDecorator; @Reference private PluralMetadataProvider pluralMetadataProvider; @Reference private ProjectOperations projectOperations; protected void activate(final ComponentContext context) { metadataDependencyRegistry.registerDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); addMetadataTrigger(ROO_JPA_ACTIVE_RECORD); configurableMetadataProvider.addMetadataTrigger(ROO_JPA_ACTIVE_RECORD); pluralMetadataProvider.addMetadataTrigger(ROO_JPA_ACTIVE_RECORD); registerMatchers(); } @Override protected String createLocalIdentifier(final JavaType javaType, final LogicalPath path) { return JpaActiveRecordMetadata.createIdentifier(javaType, path); } protected void deactivate(final ComponentContext context) { metadataDependencyRegistry.deregisterDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); removeMetadataTrigger(ROO_JPA_ACTIVE_RECORD); configurableMetadataProvider .removeMetadataTrigger(ROO_JPA_ACTIVE_RECORD); pluralMetadataProvider.removeMetadataTrigger(ROO_JPA_ACTIVE_RECORD); customDataKeyDecorator.unregisterMatchers(getClass()); } public JpaCrudAnnotationValues getAnnotationValues(final JavaType javaType) { Validate.notNull(javaType, "JavaType required"); final String physicalTypeId = typeLocationService .getPhysicalTypeIdentifier(javaType); if (StringUtils.isBlank(physicalTypeId)) { return null; } final MemberHoldingTypeDetailsMetadataItem<?> governor = (MemberHoldingTypeDetailsMetadataItem<?>) metadataService .get(physicalTypeId); if (MemberFindingUtils.getAnnotationOfType(governor, ROO_JPA_ACTIVE_RECORD) == null) { // The type is not annotated with @RooJpaActiveRecord return null; } return new JpaCrudAnnotationValues(governor); } @Override protected String getGovernorPhysicalTypeIdentifier( final String metadataIdentificationString) { final JavaType javaType = JpaActiveRecordMetadata .getJavaType(metadataIdentificationString); final LogicalPath path = JpaActiveRecordMetadata .getPath(metadataIdentificationString); return PhysicalTypeIdentifier.createIdentifier(javaType, path); } public String getItdUniquenessFilenameSuffix() { return "Jpa_ActiveRecord"; } @Override protected ItdTypeDetailsProvidingMetadataItem getMetadata( final String metadataIdentificationString, final JavaType aspectName, final PhysicalTypeMetadata governorPhysicalType, final String itdFilename) { // Get the CRUD-related annotation values final JpaCrudAnnotationValues crudAnnotationValues = new JpaCrudAnnotationValues( governorPhysicalType); // Get the purely JPA-related annotation values, from @RooJpaEntity if // present, otherwise from @RooJpaActiveRecord JpaEntityAnnotationValues jpaEntityAnnotationValues = new JpaEntityAnnotationValues( governorPhysicalType, ROO_JPA_ENTITY); if (!jpaEntityAnnotationValues.isAnnotationFound()) { jpaEntityAnnotationValues = new JpaEntityAnnotationValues( governorPhysicalType, ROO_JPA_ACTIVE_RECORD); Validate.validState(jpaEntityAnnotationValues.isAnnotationFound(), "No @RooJpaEntity or @RooJpaActiveRecord on " + metadataIdentificationString); } // Look up the inheritance hierarchy for existing // JpaActiveRecordMetadata final JpaActiveRecordMetadata parent = getParentMetadata(governorPhysicalType .getMemberHoldingTypeDetails()); // If the parent is null, but the type has a super class it is likely // that the we don't have information to proceed if (parent == null && governorPhysicalType.getMemberHoldingTypeDetails() .getSuperclass() != null) { // If the superclass is not annotated with the Entity trigger // annotation then we can be pretty sure that we don't have enough // information to proceed if (MemberFindingUtils.getAnnotationOfType(governorPhysicalType .getMemberHoldingTypeDetails().getAnnotations(), ROO_JPA_ACTIVE_RECORD) != null) { return null; } } // We also need the plural final JavaType entity = JpaActiveRecordMetadata .getJavaType(metadataIdentificationString); final LogicalPath path = JpaActiveRecordMetadata .getPath(metadataIdentificationString); final String pluralId = PluralMetadata.createIdentifier(entity, path); final PluralMetadata pluralMetadata = (PluralMetadata) metadataService .get(pluralId); if (pluralMetadata == null) { // Can't acquire the plural return null; } metadataDependencyRegistry.registerDependency(pluralId, metadataIdentificationString); final List<FieldMetadata> idFields = persistenceMemberLocator .getIdentifierFields(entity); if (idFields.size() != 1) { // The ID field metadata is either unavailable or not stable yet return null; } final FieldMetadata idField = idFields.get(0); final String entityName = StringUtils.defaultIfEmpty( jpaEntityAnnotationValues.getEntityName(), entity.getSimpleTypeName()); boolean isGaeEnabled = false; final String moduleName = path.getModule(); if (projectOperations.isProjectAvailable(moduleName)) { // If the project itself changes, we want a chance to refresh this // item metadataDependencyRegistry.registerDependency( ProjectMetadata.getProjectIdentifier(moduleName), metadataIdentificationString); isGaeEnabled = projectOperations .isFeatureInstalledInModule(FeatureNames.GAE, moduleName); } return new JpaActiveRecordMetadata(metadataIdentificationString, aspectName, governorPhysicalType, parent, crudAnnotationValues, pluralMetadata.getPlural(), idField, entityName, isGaeEnabled); } public String getProvidesType() { return JpaActiveRecordMetadata.getMetadataIdentifierType(); } @SuppressWarnings("unchecked") private void registerMatchers() { customDataKeyDecorator .registerMatchers(getClass(), new MethodMatcher(CLEAR_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName("clearMethod"), CLEAR_METHOD_DEFAULT), new MethodMatcher( COUNT_ALL_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName("countMethod"), COUNT_METHOD_DEFAULT, true, false), new MethodMatcher(FIND_ALL_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName( "findAllMethod"), FIND_ALL_METHOD_DEFAULT, true, false), new MethodMatcher(FIND_ENTRIES_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName( "findEntriesMethod"), "find", false, true, "Entries"), new MethodMatcher( FIND_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName("findMethod"), FIND_METHOD_DEFAULT, false, true), new MethodMatcher(FLUSH_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName("flushMethod"), FLUSH_METHOD_DEFAULT), new MethodMatcher( MERGE_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName("mergeMethod"), MERGE_METHOD_DEFAULT), new MethodMatcher( PERSIST_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName("persistMethod"), PERSIST_METHOD_DEFAULT), new MethodMatcher( REMOVE_METHOD, ROO_JPA_ACTIVE_RECORD, new JavaSymbolName("removeMethod"), REMOVE_METHOD_DEFAULT)); } }