package org.springframework.roo.addon.finder; import java.util.Collections; import java.util.SortedMap; import java.util.TreeMap; 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.jpa.activerecord.JpaActiveRecordMetadata; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.details.ItdTypeDetails; import org.springframework.roo.classpath.details.MethodMetadata; import org.springframework.roo.classpath.itd.AbstractMemberDiscoveringItdMetadataProvider; import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem; import org.springframework.roo.classpath.scanner.MemberDetails; import org.springframework.roo.model.JavaSymbolName; import org.springframework.roo.model.JavaType; import org.springframework.roo.project.LogicalPath; /** * Implementation of {@link FinderMetadataProvider}. * * @author Stefan Schmidt * @author Ben Alex * @author Alan Stewart * @since 1.0 */ @Component(immediate = true) @Service public class FinderMetadataProviderImpl extends AbstractMemberDiscoveringItdMetadataProvider implements FinderMetadataProvider { @Reference private DynamicFinderServices dynamicFinderServices; protected void activate(final ComponentContext context) { metadataDependencyRegistry.addNotificationListener(this); metadataDependencyRegistry.registerDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); // Ignoring trigger annotations means that other MD providers that want // to discover whether a type has finders can do so. setIgnoreTriggerAnnotations(true); } @Override protected String createLocalIdentifier(final JavaType javaType, final LogicalPath path) { return FinderMetadata.createIdentifier(javaType, path); } protected void deactivate(final ComponentContext context) { metadataDependencyRegistry.removeNotificationListener(this); metadataDependencyRegistry.deregisterDependency( PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); } @Override protected String getGovernorPhysicalTypeIdentifier( final String metadataIdentificationString) { final JavaType javaType = FinderMetadata .getJavaType(metadataIdentificationString); final LogicalPath path = FinderMetadata .getPath(metadataIdentificationString); return PhysicalTypeIdentifier.createIdentifier(javaType, path); } public String getItdUniquenessFilenameSuffix() { return "Finder"; } @Override protected String getLocalMidToRequest(final ItdTypeDetails itdTypeDetails) { return getLocalMid(itdTypeDetails); } @Override protected ItdTypeDetailsProvidingMetadataItem getMetadata( final String metadataIdentificationString, final JavaType aspectName, final PhysicalTypeMetadata governorPhysicalTypeMetadata, final String itdFilename) { // We know governor type details are non-null and can be safely cast // Work out the MIDs of the other metadata we depend on final JavaType javaType = FinderMetadata .getJavaType(metadataIdentificationString); final LogicalPath path = FinderMetadata .getPath(metadataIdentificationString); final String jpaActiveRecordMetadataKey = JpaActiveRecordMetadata .createIdentifier(javaType, path); // We need to lookup the metadata we depend on final JpaActiveRecordMetadata jpaActiveRecordMetadata = (JpaActiveRecordMetadata) metadataService .get(jpaActiveRecordMetadataKey); if (jpaActiveRecordMetadata == null || !jpaActiveRecordMetadata.isValid()) { return new FinderMetadata(metadataIdentificationString, aspectName, governorPhysicalTypeMetadata, null, Collections.<JavaSymbolName, QueryHolder> emptyMap()); } final MethodMetadata entityManagerMethod = jpaActiveRecordMetadata .getEntityManagerMethod(); if (entityManagerMethod == null) { return null; } final MemberDetails memberDetails = getMemberDetails(governorPhysicalTypeMetadata); if (memberDetails == null) { return null; } final String plural = jpaActiveRecordMetadata.getPlural(); final String entityName = jpaActiveRecordMetadata.getEntityName(); // Using SortedMap to ensure that the ITD emits finders in the same // order each time final SortedMap<JavaSymbolName, QueryHolder> queryHolders = new TreeMap<JavaSymbolName, QueryHolder>(); for (final String methodName : jpaActiveRecordMetadata .getDynamicFinders()) { final JavaSymbolName finderName = new JavaSymbolName(methodName); final QueryHolder queryHolder = dynamicFinderServices .getQueryHolder(memberDetails, finderName, plural, entityName); if (queryHolder != null) { queryHolders.put(finderName, queryHolder); } } // Now determine all the ITDs we're relying on to ensure we are notified // if they change for (final QueryHolder queryHolder : queryHolders.values()) { for (final Token token : queryHolder.getTokens()) { if (token instanceof FieldToken) { final FieldToken fieldToken = (FieldToken) token; final String declaredByMid = fieldToken.getField() .getDeclaredByMetadataId(); metadataDependencyRegistry.registerDependency( declaredByMid, metadataIdentificationString); } } } // We need to be informed if our dependent metadata changes metadataDependencyRegistry.registerDependency( jpaActiveRecordMetadataKey, metadataIdentificationString); // We make the queryHolders immutable in case FinderMetadata in the // future makes it available through an accessor etc return new FinderMetadata(metadataIdentificationString, aspectName, governorPhysicalTypeMetadata, entityManagerMethod, Collections.unmodifiableSortedMap(queryHolders)); } public String getProvidesType() { return FinderMetadata.getMetadataIdentiferType(); } }