Package org.springframework.roo.addon.test

Source Code of org.springframework.roo.addon.test.IntegrationTestMetadataProviderImpl

package org.springframework.roo.addon.test;

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.IDENTIFIER_ACCESSOR_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.MERGE_METHOD;
import static org.springframework.roo.classpath.customdata.CustomDataKeys.PERSISTENT_TYPE;
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.JavaType.INT_PRIMITIVE;
import static org.springframework.roo.model.RooJavaType.ROO_DATA_ON_DEMAND;
import static org.springframework.roo.model.RooJavaType.ROO_INTEGRATION_TEST;
import static org.springframework.roo.model.RooJavaType.ROO_JPA_ACTIVE_RECORD;

import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

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.dod.DataOnDemandMetadata;
import org.springframework.roo.classpath.PhysicalTypeDetails;
import org.springframework.roo.classpath.PhysicalTypeIdentifier;
import org.springframework.roo.classpath.PhysicalTypeIdentifierNamingUtils;
import org.springframework.roo.classpath.PhysicalTypeMetadata;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.MemberFindingUtils;
import org.springframework.roo.classpath.details.MemberHoldingTypeDetails;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.classpath.details.annotations.StringAttributeValue;
import org.springframework.roo.classpath.itd.AbstractItdMetadataProvider;
import org.springframework.roo.classpath.itd.ItdTypeDetailsProvidingMetadataItem;
import org.springframework.roo.classpath.layers.LayerService;
import org.springframework.roo.classpath.layers.LayerType;
import org.springframework.roo.classpath.layers.MemberTypeAdditions;
import org.springframework.roo.classpath.layers.MethodParameter;
import org.springframework.roo.classpath.scanner.MemberDetails;
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 IntegrationTestMetadataProvider}.
*
* @author Ben Alex
* @since 1.0
*/
@Component(immediate = true)
@Service
public class IntegrationTestMetadataProviderImpl extends
        AbstractItdMetadataProvider implements IntegrationTestMetadataProvider {

    private static final int LAYER_POSITION = LayerType.HIGHEST.getPosition();
    private static final JavaSymbolName TRANSACTION_MANAGER_ATTRIBUTE = new JavaSymbolName(
            "transactionManager");

    @Reference private ConfigurableMetadataProvider configurableMetadataProvider;
    @Reference private LayerService layerService;
    @Reference private ProjectOperations projectOperations;

    private final Map<JavaType, String> managedEntityTypes = new HashMap<JavaType, String>();
    private final Set<String> producedMids = new LinkedHashSet<String>();
    private Boolean wasGaeEnabled;

    protected void activate(final ComponentContext context) {
        metadataDependencyRegistry.addNotificationListener(this);
        metadataDependencyRegistry.registerDependency(
                PhysicalTypeIdentifier.getMetadataIdentiferType(),
                getProvidesType());
        // Integration test classes are @Configurable because they may need DI
        // of other DOD classes that provide M:1 relationships
        configurableMetadataProvider.addMetadataTrigger(ROO_INTEGRATION_TEST);
        addMetadataTrigger(ROO_INTEGRATION_TEST);
    }

    @Override
    protected String createLocalIdentifier(final JavaType javaType,
            final LogicalPath path) {
        return IntegrationTestMetadata.createIdentifier(javaType, path);
    }

    protected void deactivate(final ComponentContext context) {
        metadataDependencyRegistry.removeNotificationListener(this);
        metadataDependencyRegistry.deregisterDependency(
                PhysicalTypeIdentifier.getMetadataIdentiferType(),
                getProvidesType());
        configurableMetadataProvider
                .removeMetadataTrigger(ROO_INTEGRATION_TEST);
        removeMetadataTrigger(ROO_INTEGRATION_TEST);
    }

    /**
     * Returns the {@link JavaType} for the given entity's "data on demand"
     * class.
     *
     * @param entity the entity for which to get the DoD type
     * @return a non-<code>null</code> type (which may or may not exist yet)
     */
    private JavaType getDataOnDemandType(final JavaType entity) {
        // First check for an existing type with the standard DoD naming
        // convention
        final JavaType defaultDodType = new JavaType(
                entity.getFullyQualifiedTypeName() + "DataOnDemand");
        if (typeLocationService.getTypeDetails(defaultDodType) != null) {
            return defaultDodType;
        }

        // Otherwise we look through all DoD-annotated classes for this entity's
        // one
        for (final ClassOrInterfaceTypeDetails dodType : typeLocationService
                .findClassesOrInterfaceDetailsWithAnnotation(ROO_DATA_ON_DEMAND)) {
            final AnnotationMetadata dodAnnotation = MemberFindingUtils
                    .getFirstAnnotation(dodType, ROO_DATA_ON_DEMAND);
            if (dodAnnotation != null
                    && dodAnnotation.getAttribute("entity").getValue()
                            .equals(entity)) {
                return dodType.getName();
            }
        }

        // No existing DoD class was found for this entity, so use the default
        // name
        return defaultDodType;
    }

    private ClassOrInterfaceTypeDetails getEntitySuperclass(
            final JavaType entity) {
        final String physicalTypeIdentifier = PhysicalTypeIdentifier
                .createIdentifier(entity,
                        typeLocationService.getTypePath(entity));
        final PhysicalTypeMetadata ptm = (PhysicalTypeMetadata) metadataService
                .get(physicalTypeIdentifier);
        Validate.notNull(ptm, "Java source code unavailable for type %s",
                PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
        final PhysicalTypeDetails ptd = ptm.getMemberHoldingTypeDetails();
        Validate.notNull(ptd,
                "Java source code details unavailable for type %s",
                PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
        Validate.isInstanceOf(ClassOrInterfaceTypeDetails.class, ptd,
                "Java source code is immutable for type %s",
                PhysicalTypeIdentifier.getFriendlyName(physicalTypeIdentifier));
        final ClassOrInterfaceTypeDetails cid = (ClassOrInterfaceTypeDetails) ptd;
        return cid.getSuperclass();
    }

    @Override
    protected String getGovernorPhysicalTypeIdentifier(
            final String metadataIdentificationString) {
        final JavaType javaType = IntegrationTestMetadata
                .getJavaType(metadataIdentificationString);
        final LogicalPath path = IntegrationTestMetadata
                .getPath(metadataIdentificationString);
        return PhysicalTypeIdentifier.createIdentifier(javaType, path);
    }

    public String getItdUniquenessFilenameSuffix() {
        return "IntegrationTest";
    }

    @Override
    protected ItdTypeDetailsProvidingMetadataItem getMetadata(
            final String metadataIdentificationString,
            final JavaType aspectName,
            final PhysicalTypeMetadata governorPhysicalTypeMetadata,
            final String itdFilename) {
        // We need to parse the annotation, which we expect to be present
        final IntegrationTestAnnotationValues annotationValues = new IntegrationTestAnnotationValues(
                governorPhysicalTypeMetadata);
        final JavaType entity = annotationValues.getEntity();
        if (!annotationValues.isAnnotationFound() || entity == null) {
            return null;
        }

        final JavaType dataOnDemandType = getDataOnDemandType(entity);
        final String dataOnDemandMetadataKey = DataOnDemandMetadata
                .createIdentifier(dataOnDemandType,
                        typeLocationService.getTypePath(dataOnDemandType));
        final DataOnDemandMetadata dataOnDemandMetadata = (DataOnDemandMetadata) metadataService
                .get(dataOnDemandMetadataKey);

        // We need to be informed if our dependent metadata changes
        metadataDependencyRegistry.registerDependency(dataOnDemandMetadataKey,
                metadataIdentificationString);

        if (dataOnDemandMetadata == null || !dataOnDemandMetadata.isValid()) {
            return null;
        }

        final JavaType identifierType = persistenceMemberLocator
                .getIdentifierType(entity);
        if (identifierType == null) {
            return null;
        }

        final MemberDetails memberDetails = getMemberDetails(entity);
        if (memberDetails == null) {
            return null;
        }

        final MemberHoldingTypeDetails persistenceMemberHoldingTypeDetails = MemberFindingUtils
                .getMostConcreteMemberHoldingTypeDetailsWithTag(memberDetails,
                        PERSISTENT_TYPE);
        if (persistenceMemberHoldingTypeDetails == null) {
            return null;
        }

        // We need to be informed if our dependent metadata changes
        metadataDependencyRegistry.registerDependency(
                persistenceMemberHoldingTypeDetails.getDeclaredByMetadataId(),
                metadataIdentificationString);

        final MethodParameter firstResultParameter = new MethodParameter(
                INT_PRIMITIVE, "firstResult");
        final MethodParameter maxResultsParameter = new MethodParameter(
                INT_PRIMITIVE, "maxResults");

        final MethodMetadata identifierAccessorMethod = memberDetails
                .getMostConcreteMethodWithTag(IDENTIFIER_ACCESSOR_METHOD);
        final MethodMetadata versionAccessorMethod = persistenceMemberLocator
                .getVersionAccessor(entity);
        final MemberTypeAdditions countMethodAdditions = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        COUNT_ALL_METHOD.name(), entity, identifierType,
                        LAYER_POSITION);
        final MemberTypeAdditions findMethodAdditions = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        FIND_METHOD.name(), entity, identifierType,
                        LAYER_POSITION, new MethodParameter(identifierType,
                                "id"));
        final MemberTypeAdditions findAllMethodAdditions = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        FIND_ALL_METHOD.name(), entity, identifierType,
                        LAYER_POSITION);
        final MemberTypeAdditions findEntriesMethod = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        FIND_ENTRIES_METHOD.name(), entity, identifierType,
                        LAYER_POSITION, firstResultParameter,
                        maxResultsParameter);
        final MethodParameter entityParameter = new MethodParameter(entity,
                "obj");
        final MemberTypeAdditions flushMethodAdditions = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        FLUSH_METHOD.name(), entity, identifierType,
                        LAYER_POSITION, entityParameter);
        final MemberTypeAdditions mergeMethodAdditions = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        MERGE_METHOD.name(), entity, identifierType,
                        LAYER_POSITION, entityParameter);
        final MemberTypeAdditions persistMethodAdditions = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        PERSIST_METHOD.name(), entity, identifierType,
                        LAYER_POSITION, entityParameter);
        final MemberTypeAdditions removeMethodAdditions = layerService
                .getMemberTypeAdditions(metadataIdentificationString,
                        REMOVE_METHOD.name(), entity, identifierType,
                        LAYER_POSITION, entityParameter);
        if (persistMethodAdditions == null || findMethodAdditions == null
                || identifierAccessorMethod == null) {
            return null;
        }

        String transactionManager = null;
        final AnnotationMetadata jpaActiveRecordAnnotation = memberDetails
                .getAnnotation(ROO_JPA_ACTIVE_RECORD);
        if (jpaActiveRecordAnnotation != null) {
            final StringAttributeValue transactionManagerAttr = (StringAttributeValue) jpaActiveRecordAnnotation
                    .getAttribute(TRANSACTION_MANAGER_ATTRIBUTE);
            if (transactionManagerAttr != null) {
                transactionManager = transactionManagerAttr.getValue();
            }
        }

        final boolean hasEmbeddedIdentifier = dataOnDemandMetadata
                .hasEmbeddedIdentifier();
        final boolean entityHasSuperclass = getEntitySuperclass(entity) != null;

        // In order to handle switching between GAE and JPA produced MIDs need
        // to be remembered so they can be regenerated on JPA <-> GAE switch
        producedMids.add(metadataIdentificationString);

        // Maintain a list of entities that are being tested
        managedEntityTypes.put(entity, metadataIdentificationString);

        final String moduleName = PhysicalTypeIdentifierNamingUtils.getPath(
                metadataIdentificationString).getModule();
        final boolean isGaeEnabled = projectOperations
                .isProjectAvailable(moduleName)
                && projectOperations.isFeatureInstalledInModule(
                        FeatureNames.GAE, moduleName);

        return new IntegrationTestMetadata(metadataIdentificationString,
                aspectName, governorPhysicalTypeMetadata, annotationValues,
                dataOnDemandMetadata, identifierAccessorMethod,
                versionAccessorMethod, countMethodAdditions,
                findMethodAdditions, findAllMethodAdditions, findEntriesMethod,
                flushMethodAdditions, mergeMethodAdditions,
                persistMethodAdditions, removeMethodAdditions,
                transactionManager, hasEmbeddedIdentifier, entityHasSuperclass,
                isGaeEnabled);
    }

    public String getProvidesType() {
        return IntegrationTestMetadata.getMetadataIdentiferType();
    }

    private void handleChangesToLayeringForTestedEntities(
            final JavaType physicalType) {
        final MemberHoldingTypeDetails memberHoldingTypeDetails = typeLocationService
                .getTypeDetails(physicalType);
        if (memberHoldingTypeDetails != null) {
            for (final JavaType type : memberHoldingTypeDetails
                    .getLayerEntities()) {
                handleChangesToTestedEntities(type);
            }
        }
    }

    private void handleChangesToTestedEntities(final JavaType physicalType) {
        final String localMid = managedEntityTypes.get(physicalType);
        if (localMid != null) {
            // One of the entities for which we produce metadata has changed;
            // refresh that metadata
            metadataService.get(localMid);
        }
    }

    /**
     * Handles a generic change (i.e. with no explicit downstream dependency) to
     * the given physical type
     *
     * @param physicalType the type that changed (required)
     */
    private void handleGenericChangeToPhysicalType(final JavaType physicalType) {
        handleChangesToTestedEntities(physicalType);
        handleChangesToLayeringForTestedEntities(physicalType);
    }

    /**
     * Handles a generic change (i.e. with no explicit downstream dependency) to
     * the project metadata
     */
    private void handleGenericChangeToProject(final String moduleName) {
        final ProjectMetadata projectMetadata = projectOperations
                .getProjectMetadata(moduleName);
        if (projectMetadata != null && projectMetadata.isValid()) {
            final boolean isGaeEnabled = projectOperations
                    .isFeatureInstalledInModule(FeatureNames.GAE, moduleName);
            // We need to determine if the persistence state has changed, we do
            // this by comparing the last known state to the current state
            final boolean hasGaeStateChanged = wasGaeEnabled == null
                    || isGaeEnabled != wasGaeEnabled;
            if (hasGaeStateChanged) {
                wasGaeEnabled = isGaeEnabled;
                for (final String producedMid : producedMids) {
                    metadataService.evictAndGet(producedMid);
                }
            }
        }
    }

    @Override
    protected void notifyForGenericListener(final String upstreamDependency) {
        if (PhysicalTypeIdentifier.isValid(upstreamDependency)) {
            handleGenericChangeToPhysicalType(PhysicalTypeIdentifier
                    .getJavaType(upstreamDependency));
        }
        if (ProjectMetadata.isValid(upstreamDependency)) {
            handleGenericChangeToProject(ProjectMetadata
                    .getModuleName(upstreamDependency));
        }
    }
}
TOP

Related Classes of org.springframework.roo.addon.test.IntegrationTestMetadataProviderImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.