package org.springframework.roo.addon.gwt.request; import static org.springframework.roo.model.RooJavaType.ROO_GWT_REQUEST; 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.osgi.service.component.ComponentContext; import org.springframework.roo.addon.gwt.GwtTypeService; import org.springframework.roo.addon.gwt.GwtUtils; import org.springframework.roo.classpath.PhysicalTypeIdentifier; import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils; import org.springframework.roo.classpath.PhysicalTypeMetadata; import org.springframework.roo.classpath.TypeLocationService; import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails; import org.springframework.roo.classpath.details.MemberHoldingTypeDetails; import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue; import org.springframework.roo.classpath.details.annotations.AnnotationMetadata; import org.springframework.roo.metadata.MetadataDependencyRegistry; import org.springframework.roo.metadata.MetadataIdentificationUtils; import org.springframework.roo.metadata.MetadataNotificationListener; import org.springframework.roo.metadata.MetadataService; import org.springframework.roo.model.JavaType; import org.springframework.roo.project.LogicalPath; /** * Triggers the generation of {@link GwtRequestMetadata} upon being notified of * changes to {@link PhysicalTypeMetadata} within the user project. * * @author Andrew Swan * @since 1.2.0 */ @Component(immediate = true) @Service public class GwtRequestMetadataNotificationListener implements MetadataNotificationListener { @Reference GwtTypeService gwtTypeService; @Reference MetadataDependencyRegistry metadataDependencyRegistry; @Reference MetadataService metadataService; @Reference TypeLocationService typeLocationService; protected void activate(final ComponentContext context) { metadataDependencyRegistry.addNotificationListener(this); } protected void deactivate(final ComponentContext context) { metadataDependencyRegistry.removeNotificationListener(this); } private String getDownstreamInstanceId(final String upstreamDependency) { final ClassOrInterfaceTypeDetails upstreamType = typeLocationService .getTypeDetails(upstreamDependency); if (upstreamType == null) { return null; } final String downstreamOfGwtEntityLayerComponent = getDownstreamOfGwtEntityLayerComponent(upstreamType); if (downstreamOfGwtEntityLayerComponent != null) { return downstreamOfGwtEntityLayerComponent; } if (upstreamType.getAnnotation(ROO_GWT_REQUEST) == null) { final String downstreamOfGwtEntity = getDownstreamOfGwtEntity(upstreamType .getType()); if (downstreamOfGwtEntity != null) { return downstreamOfGwtEntity; } } return null; } private String getDownstreamOfGwtEntity(final JavaType upstreamType) { for (final ClassOrInterfaceTypeDetails request : typeLocationService .findClassesOrInterfaceDetailsWithAnnotation(ROO_GWT_REQUEST)) { final AnnotationMetadata gwtRequestAnnotation = request .getAnnotation(ROO_GWT_REQUEST); if (gwtRequestAnnotation != null) { final AnnotationAttributeValue<?> attributeValue = gwtRequestAnnotation .getAttribute("value"); Validate.validState(attributeValue != null, "The x annotation should have a '" + "value" + "' attribute"); final String entityClass = GwtUtils .getStringValue(attributeValue); if (upstreamType.getFullyQualifiedTypeName() .equals(entityClass)) { // The upstream type is an entity with an associated GWT // request; make that request the downstream return getLocalMid(request.getDeclaredByMetadataId()); } } } return null; } private String getDownstreamOfGwtEntityLayerComponent( final MemberHoldingTypeDetails upstreamType) { final List<JavaType> layerEntities = upstreamType.getLayerEntities(); if (!layerEntities.isEmpty()) { // Look for a GWT request that manages one of these entities for (final ClassOrInterfaceTypeDetails request : typeLocationService .findClassesOrInterfaceDetailsWithAnnotation(ROO_GWT_REQUEST)) { final ClassOrInterfaceTypeDetails entity = gwtTypeService .lookupEntityFromRequest(request); if (entity != null && layerEntities.contains(entity.getType())) { // This layer component has an associated GWT request; make // that request the downstream return getLocalMid(request.getDeclaredByMetadataId()); } } } return null; } private String getLocalMid(final String physicalTypeId) { final JavaType typeName = PhysicalTypeIdentifier .getJavaType(physicalTypeId); final LogicalPath typePath = PhysicalTypeIdentifier .getPath(physicalTypeId); return GwtRequestMetadata.createIdentifier(typeName, typePath); } public void notify(final String upstreamMID, final String downstreamMID) { if (!PhysicalTypeIdentifier.isValid(upstreamMID)) { return; } final String downstreamInstanceId; if (MetadataIdentificationUtils.isIdentifyingInstance(downstreamMID)) { downstreamInstanceId = downstreamMID; } else { downstreamInstanceId = getDownstreamInstanceId(upstreamMID); if (downstreamInstanceId == null) { return; } } // We should now have an instance-specific "downstream dependency" that // can be processed by this class Validate.isTrue(PhysicalTypeIdentifierNamingUtils.isValid( GwtRequestMetadata.class.getName(), downstreamInstanceId)); metadataService.evictAndGet(downstreamInstanceId); } }