Package org.springframework.roo.addon.gwt.proxy

Source Code of org.springframework.roo.addon.gwt.proxy.GwtProxyMetadataProviderImpl

package org.springframework.roo.addon.gwt.proxy;

import static org.springframework.roo.addon.gwt.GwtJavaType.ENTITY_PROXY;
import static org.springframework.roo.addon.gwt.GwtJavaType.OLD_ENTITY_PROXY;

import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
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.gwt.GwtFileManager;
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.TypeLocationService;
import org.springframework.roo.classpath.details.BeanInfoUtils;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetails;
import org.springframework.roo.classpath.details.ClassOrInterfaceTypeDetailsBuilder;
import org.springframework.roo.classpath.details.MemberFindingUtils;
import org.springframework.roo.classpath.details.MethodMetadata;
import org.springframework.roo.classpath.details.MethodMetadataBuilder;
import org.springframework.roo.classpath.details.annotations.AnnotatedJavaType;
import org.springframework.roo.classpath.details.annotations.AnnotationAttributeValue;
import org.springframework.roo.classpath.details.annotations.AnnotationMetadata;
import org.springframework.roo.classpath.details.annotations.ArrayAttributeValue;
import org.springframework.roo.classpath.details.annotations.StringAttributeValue;
import org.springframework.roo.classpath.itd.InvocableMemberBodyBuilder;
import org.springframework.roo.metadata.AbstractHashCodeTrackingMetadataNotifier;
import org.springframework.roo.metadata.MetadataIdentificationUtils;
import org.springframework.roo.metadata.MetadataItem;
import org.springframework.roo.model.JavaPackage;
import org.springframework.roo.model.JavaSymbolName;
import org.springframework.roo.model.JavaType;
import org.springframework.roo.model.RooJavaType;
import org.springframework.roo.project.LogicalPath;
import org.springframework.roo.project.ProjectOperations;

@Component(immediate = true)
@Service
public class GwtProxyMetadataProviderImpl extends
        AbstractHashCodeTrackingMetadataNotifier implements
        GwtProxyMetadataProvider {

    @Reference protected GwtFileManager gwtFileManager;
    @Reference protected GwtTypeService gwtTypeService;
    @Reference protected ProjectOperations projectOperations;
    @Reference protected TypeLocationService typeLocationService;

    protected void activate(final ComponentContext context) {
        metadataDependencyRegistry.registerDependency(
                PhysicalTypeIdentifier.getMetadataIdentiferType(),
                getProvidesType());
    }

    protected void deactivate(final ComponentContext context) {
        metadataDependencyRegistry.deregisterDependency(
                PhysicalTypeIdentifier.getMetadataIdentiferType(),
                getProvidesType());
    }

    public MetadataItem get(final String metadataIdentificationString) {
        final ClassOrInterfaceTypeDetails proxy = getGovernor(metadataIdentificationString);
        if (proxy == null) {
            return null;
        }

        final AnnotationMetadata mirrorAnnotation = MemberFindingUtils
                .getAnnotationOfType(proxy.getAnnotations(),
                        RooJavaType.ROO_GWT_PROXY);
        if (mirrorAnnotation == null) {
            return null;
        }

        final JavaType mirroredType = GwtUtils.lookupProxyTargetType(proxy);
        if (mirroredType == null) {
            return null;
        }

        final List<String> exclusionList = new ArrayList<String>();
        final AnnotationAttributeValue<?> excludeAttribute = mirrorAnnotation
                .getAttribute("exclude");
        if (excludeAttribute != null
                && excludeAttribute instanceof ArrayAttributeValue) {
            @SuppressWarnings("unchecked")
            final ArrayAttributeValue<StringAttributeValue> excludeArrayAttribute = (ArrayAttributeValue<StringAttributeValue>) excludeAttribute;
            for (final StringAttributeValue attributeValue : excludeArrayAttribute
                    .getValue()) {
                exclusionList.add(attributeValue.getValue());
            }
        }
        else if (excludeAttribute != null
                && excludeAttribute instanceof StringAttributeValue) {
            final StringAttributeValue excludeStringAttribute = (StringAttributeValue) excludeAttribute;
            exclusionList.add(excludeStringAttribute.getValue());
        }

        final List<String> readOnlyList = new ArrayList<String>();
        final AnnotationAttributeValue<?> readOnlyAttribute = mirrorAnnotation
                .getAttribute("readOnly");
        if (readOnlyAttribute != null
                && readOnlyAttribute instanceof ArrayAttributeValue) {
            @SuppressWarnings("unchecked")
            final ArrayAttributeValue<StringAttributeValue> readOnlyArrayAttribute = (ArrayAttributeValue<StringAttributeValue>) readOnlyAttribute;
            for (final StringAttributeValue attributeValue : readOnlyArrayAttribute
                    .getValue()) {
                readOnlyList.add(attributeValue.getValue());
            }
        }
        else if (readOnlyAttribute != null
                && readOnlyAttribute instanceof StringAttributeValue) {
            final StringAttributeValue readOnlyStringAttribute = (StringAttributeValue) readOnlyAttribute;
            readOnlyList.add(readOnlyStringAttribute.getValue());
        }

        final ClassOrInterfaceTypeDetails mirroredDetails = typeLocationService
                .getTypeDetails(mirroredType);
        if (mirroredDetails == null
                || Modifier.isAbstract(mirroredDetails.getModifier())) {
            return null;
        }

        final String moduleName = PhysicalTypeIdentifier.getPath(
                proxy.getDeclaredByMetadataId()).getModule();
        final List<MethodMetadata> proxyMethods = gwtTypeService
                .getProxyMethods(mirroredDetails);
        final List<MethodMetadata> convertedProxyMethods = new ArrayList<MethodMetadata>();
        final Collection<JavaPackage> sourcePackages = gwtTypeService
                .getSourcePackages(moduleName);
        for (final MethodMetadata method : proxyMethods) {
            final JavaType gwtType = gwtTypeService.getGwtSideLeafType(
                    method.getReturnType(), mirroredDetails.getName(), false,
                    true);
            final MethodMetadataBuilder methodBuilder = new MethodMetadataBuilder(
                    method);
            // Remove all annotations from proxy method
            methodBuilder.setAnnotations(new ArrayList<AnnotationMetadata>());
            methodBuilder.setReturnType(gwtType);
            final MethodMetadata convertedMethod = methodBuilder.build();
            if (gwtTypeService.isMethodReturnTypeInSourcePath(convertedMethod,
                    mirroredDetails, sourcePackages)) {
                convertedProxyMethods.add(methodBuilder.build());
            }
        }
        final GwtProxyMetadata metadata = new GwtProxyMetadata(
                metadataIdentificationString, updateProxy(proxy,
                        convertedProxyMethods, exclusionList, readOnlyList));
        notifyIfRequired(metadata);
        return metadata;
    }

    private ClassOrInterfaceTypeDetails getGovernor(
            final String metadataIdentificationString) {
        final JavaType governorTypeName = GwtProxyMetadata
                .getJavaType(metadataIdentificationString);
        final LogicalPath governorTypePath = GwtProxyMetadata
                .getPath(metadataIdentificationString);

        final String physicalTypeId = PhysicalTypeIdentifier.createIdentifier(
                governorTypeName, governorTypePath);
        return typeLocationService.getTypeDetails(physicalTypeId);
    }

    public String getProvidesType() {
        return GwtProxyMetadata.getMetadataIdentifierType();
    }

    public void notify(final String upstreamDependency,
            String downstreamDependency) {
        if (MetadataIdentificationUtils
                .isIdentifyingClass(downstreamDependency)) {
            Validate.isTrue(
                    MetadataIdentificationUtils.getMetadataClass(
                            upstreamDependency).equals(
                            MetadataIdentificationUtils
                                    .getMetadataClass(PhysicalTypeIdentifier
                                            .getMetadataIdentiferType())),
                    "Expected class-level notifications only for PhysicalTypeIdentifier (not '%s')",
                    upstreamDependency);

            final ClassOrInterfaceTypeDetails cid = typeLocationService
                    .getTypeDetails(upstreamDependency);
            if (cid == null) {
                return;
            }
            if (MemberFindingUtils.getAnnotationOfType(cid.getAnnotations(),
                    RooJavaType.ROO_GWT_PROXY) == null) {
                boolean found = false;
                for (final ClassOrInterfaceTypeDetails proxyCid : typeLocationService
                        .findClassesOrInterfaceDetailsWithAnnotation(RooJavaType.ROO_GWT_PROXY)) {
                    final AnnotationMetadata annotationMetadata = GwtUtils
                            .getFirstAnnotation(proxyCid,
                                    GwtUtils.ROO_PROXY_REQUEST_ANNOTATIONS);
                    if (annotationMetadata != null) {
                        final AnnotationAttributeValue<?> attributeValue = annotationMetadata
                                .getAttribute("value");
                        if (attributeValue != null) {
                            final String mirrorName = GwtUtils
                                    .getStringValue(attributeValue);
                            if (mirrorName != null
                                    && cid.getName()
                                            .getFullyQualifiedTypeName()
                                            .equals(attributeValue.getValue())) {
                                found = true;
                                final JavaType typeName = PhysicalTypeIdentifier
                                        .getJavaType(proxyCid
                                                .getDeclaredByMetadataId());
                                final LogicalPath typePath = PhysicalTypeIdentifier
                                        .getPath(proxyCid
                                                .getDeclaredByMetadataId());
                                downstreamDependency = GwtProxyMetadata
                                        .createIdentifier(typeName, typePath);
                                break;
                            }
                        }
                    }
                }
                if (!found) {
                    return;
                }
            }
            else {
                // A physical Java type has changed, and determine what the
                // corresponding local metadata identification string would have
                // been
                final JavaType typeName = PhysicalTypeIdentifier
                        .getJavaType(upstreamDependency);
                final LogicalPath typePath = PhysicalTypeIdentifier
                        .getPath(upstreamDependency);
                downstreamDependency = GwtProxyMetadata.createIdentifier(
                        typeName, typePath);
            }

            // We only need to proceed if the downstream dependency relationship
            // is not already registered
            // (if it's already registered, the event will be delivered directly
            // later on)
            if (metadataDependencyRegistry.getDownstream(upstreamDependency)
                    .contains(downstreamDependency)) {
                return;
            }
        }

        // We should now have an instance-specific "downstream dependency" that
        // can be processed by this class
        Validate.isTrue(
                MetadataIdentificationUtils.getMetadataClass(
                        downstreamDependency).equals(
                        MetadataIdentificationUtils
                                .getMetadataClass(getProvidesType())),
                "Unexpected downstream notification for '%s' to this provider (which uses '%s')",
                downstreamDependency, getProvidesType());

        metadataService.evictAndGet(downstreamDependency);
    }

    private String updateProxy(final ClassOrInterfaceTypeDetails proxy,
            final List<MethodMetadata> proxyMethods,
            final List<String> exclusionList, final List<String> readOnlyList) {
        // Create a new ClassOrInterfaceTypeDetailsBuilder for the Proxy, will
        // be overridden if the Proxy has already been created
        final ClassOrInterfaceTypeDetailsBuilder cidBuilder = new ClassOrInterfaceTypeDetailsBuilder(
                proxy);

        // Only inherit from EntityProxy if extension is not already defined
        if (!cidBuilder.getExtendsTypes().contains(OLD_ENTITY_PROXY)
                && !cidBuilder.getExtendsTypes().contains(ENTITY_PROXY)) {
            cidBuilder.addExtendsTypes(ENTITY_PROXY);
        }

        if (!cidBuilder.getExtendsTypes().contains(ENTITY_PROXY)) {
            cidBuilder.addExtendsTypes(ENTITY_PROXY);
        }

        final String destinationMetadataId = proxy.getDeclaredByMetadataId();
        final List<MethodMetadataBuilder> methods = new ArrayList<MethodMetadataBuilder>();
        for (final MethodMetadata method : proxyMethods) {
            if (exclusionList.contains(method.getMethodName().getSymbolName())) {
                continue;
            }
            final String propertyName = StringUtils.uncapitalize(BeanInfoUtils
                    .getPropertyNameForJavaBeanMethod(method).getSymbolName());
            if (exclusionList.contains(propertyName)) {
                continue;
            }

            final MethodMetadataBuilder abstractAccessorMethodBuilder = new MethodMetadataBuilder(
                    destinationMetadataId, method);
            abstractAccessorMethodBuilder
                    .setBodyBuilder(new InvocableMemberBodyBuilder());
            abstractAccessorMethodBuilder.setModifier(Modifier.ABSTRACT);
            methods.add(abstractAccessorMethodBuilder);

            if (readOnlyList.contains(propertyName)) {
                continue;
            }
            final MethodMetadataBuilder abstractMutatorMethodBuilder = new MethodMetadataBuilder(
                    destinationMetadataId, method);
            abstractMutatorMethodBuilder
                    .setBodyBuilder(new InvocableMemberBodyBuilder());
            abstractMutatorMethodBuilder.setModifier(Modifier.ABSTRACT);
            abstractMutatorMethodBuilder.setReturnType(JavaType.VOID_PRIMITIVE);
            abstractMutatorMethodBuilder
                    .setParameterTypes(AnnotatedJavaType
                            .convertFromJavaTypes(Arrays.asList(method
                                    .getReturnType())));
            abstractMutatorMethodBuilder.setParameterNames(Arrays
                    .asList(new JavaSymbolName(StringUtils
                            .uncapitalize(propertyName))));
            abstractMutatorMethodBuilder.setMethodName(new JavaSymbolName(
                    method.getMethodName().getSymbolName()
                            .replaceFirst("get", "set")));
            methods.add(abstractMutatorMethodBuilder);
        }

        cidBuilder.setDeclaredMethods(methods);
        return gwtFileManager.write(cidBuilder.build(),
                GwtUtils.PROXY_REQUEST_WARNING);
    }
}
TOP

Related Classes of org.springframework.roo.addon.gwt.proxy.GwtProxyMetadataProviderImpl

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.