package org.springframework.roo.addon.dto.addon; import static org.springframework.roo.model.RooJavaType.ROO_ENTITY_PROJECTION; import org.apache.commons.lang3.StringUtils; import org.apache.felix.scr.annotations.Component; import org.apache.felix.scr.annotations.Service; import org.osgi.service.component.ComponentContext; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.FieldMetadata; import org.springframework.roo.classpath.details.ItdTypeDetails; import org.springframework.roo.classpath.itd.AbstractMemberDiscoveringItdMetadataProvider; import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem; import org.springframework.roo.metadata.MetadataDependencyRegistry; import org.springframework.roo.metadata.internal.MetadataDependencyRegistryTracker; import org.springframework.roo.model.JavaType; import org.springframework.roo.model.RooJavaType; import org.springframework.roo.project.LogicalPath; import java.util.ArrayList; import java.util.List; /** * Implementation of {@link EntityProjectionMetadataProvider}. * <p/> * * @author Sergio Clares * @since 2.0 */ @Component @Service public class EntityProjectionMetadataProviderImpl extends AbstractMemberDiscoveringItdMetadataProvider implements EntityProjectionMetadataProvider { protected MetadataDependencyRegistryTracker registryTracker = null; /** * This service is being activated so setup it: * <ul> * <li>Create and open the {@link MetadataDependencyRegistryTracker}.</li> * <li>Registers {@link RooJavaType#ROO_ENTITY_PROJECTION} as additional * JavaType that will trigger metadata registration.</li> * <li>Set ensure the governor type details represent a class.</li> * </ul> */ @Override protected void activate(final ComponentContext cContext) { context = cContext.getBundleContext(); this.registryTracker = new MetadataDependencyRegistryTracker(context, this, PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); this.registryTracker.open(); addMetadataTrigger(ROO_ENTITY_PROJECTION); } /** * This service is being deactivated so unregister upstream-downstream * dependencies, triggers, matchers and listeners. * * @param context */ protected void deactivate(final ComponentContext context) { MetadataDependencyRegistry registry = this.registryTracker.getService(); registry.removeNotificationListener(this); registry.deregisterDependency(PhysicalTypeIdentifier.getMetadataIdentiferType(), getProvidesType()); this.registryTracker.close(); removeMetadataTrigger(ROO_ENTITY_PROJECTION); } @Override protected String createLocalIdentifier(final JavaType javaType, final LogicalPath path) { return EntityProjectionMetadata.createIdentifier(javaType, path); } @Override protected String getGovernorPhysicalTypeIdentifier(final String metadataIdentificationString) { final JavaType javaType = EntityProjectionMetadata.getJavaType(metadataIdentificationString); final LogicalPath path = EntityProjectionMetadata.getPath(metadataIdentificationString); return PhysicalTypeIdentifier.createIdentifier(javaType, path); } @Override protected String getLocalMidToRequest(final ItdTypeDetails itdTypeDetails) { return getLocalMid(itdTypeDetails); } @Override public String getItdUniquenessFilenameSuffix() { return "Projection"; } @Override protected ItdTypeDetailsProvidingMetadataItem getMetadata( final String metadataIdentificationString, final JavaType aspectName, final PhysicalTypeMetadata governorPhysicalTypeMetadata, final String itdFilename) { final EntityProjectionAnnotationValues annotationValues = new EntityProjectionAnnotationValues(governorPhysicalTypeMetadata); // Get CID from governor ClassOrInterfaceTypeDetails cid = governorPhysicalTypeMetadata.getMemberHoldingTypeDetails(); // Get all projection fields from annotation String[] fieldsString = annotationValues.getFields(); List<FieldMetadata> fields = buildFieldMetadataFromAnnotation(fieldsString, cid); // Add dependency between modules for (FieldMetadata field : fields) { getTypeLocationService().addModuleDependency(cid.getName().getModule(), field.getFieldType()); } return new EntityProjectionMetadata(metadataIdentificationString, aspectName, governorPhysicalTypeMetadata, annotationValues, fields); } /** * Builds FieldMetadata to provide {@link EntityProjectionMetadata} with the necessary * resources to create constructor. * * @param fields the String[] from 'fields' annotation parameter. * @param cid the governor ClassOrInterfaceTypeDetails, that is, the Projection physical type. * @return the List<FieldMetadata> with the fields to build the constructor. */ private List<FieldMetadata> buildFieldMetadataFromAnnotation(String[] fields, ClassOrInterfaceTypeDetails cid) { List<FieldMetadata> allFields = getMemberDetailsScanner().getMemberDetails(this.getClass().getName(), cid).getFields(); List<FieldMetadata> fieldsToAdd = new ArrayList<FieldMetadata>(); // Iterate over all specified fields for (int i = 0; i < fields.length; i++) { String fieldName = ""; boolean existsInGovernor = false; // Build field name following Java convention String[] splittedByDot = StringUtils.split(fields[i], "."); for (int t = 0; t < splittedByDot.length; t++) { if (t == 0) { fieldName = fieldName.concat(splittedByDot[t]); } else { fieldName = fieldName.concat(StringUtils.capitalize(splittedByDot[t])); } } // Check existence in governor for (FieldMetadata field : allFields) { if (field.getFieldName().getSymbolName().equals(fieldName)) { existsInGovernor = true; fieldsToAdd.add(field); } } if (!existsInGovernor) { throw new IllegalStateException( String .format( "Field %s couldn't be located in %s. Please, be sure that it is well written in 'fields' param of @RooEntityProjection.", fieldName, cid.getType().getFullyQualifiedTypeName())); } } return fieldsToAdd; } public String getProvidesType() { return EntityProjectionMetadata.getMetadataIdentiferType(); } }