All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jboss.weld.resources.ClassTransformer Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2008, Red Hat, Inc., and individual contributors
 * by the @authors tag. See the copyright.txt in the distribution for a
 * full listing of individual contributors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * http://www.apache.org/licenses/LICENSE-2.0
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.jboss.weld.resources;

import static org.jboss.weld.util.reflection.Reflections.cast;

import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import javax.enterprise.inject.spi.AnnotatedType;

import org.jboss.weld.annotated.enhanced.EnhancedAnnotatedType;
import org.jboss.weld.annotated.enhanced.EnhancedAnnotation;
import org.jboss.weld.annotated.enhanced.jlr.EnhancedAnnotatedTypeImpl;
import org.jboss.weld.annotated.enhanced.jlr.EnhancedAnnotationImpl;
import org.jboss.weld.annotated.slim.AnnotatedTypeIdentifier;
import org.jboss.weld.annotated.slim.SlimAnnotatedType;
import org.jboss.weld.annotated.slim.backed.BackedAnnotatedType;
import org.jboss.weld.annotated.slim.unbacked.UnbackedAnnotatedType;
import org.jboss.weld.bootstrap.api.BootstrapService;
import org.jboss.weld.logging.BootstrapLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.metadata.TypeStore;
import org.jboss.weld.resources.spi.ResourceLoadingException;
import org.jboss.weld.util.AnnotatedTypes;
import org.jboss.weld.util.Function;
import org.jboss.weld.util.cache.ComputingCache;
import org.jboss.weld.util.cache.ComputingCacheBuilder;

/**
 * @author Pete Muir
 * @author Stuart Douglas
 * @author JBoss Weld Community
 * @author Ales Justin
 */
public class ClassTransformer implements BootstrapService {

    public static ClassTransformer instance(BeanManagerImpl manager) {
        return manager.getServices().get(ClassTransformer.class);
    }

    private class TransformClassToWeldAnnotation implements Function, EnhancedAnnotation> {
        @Override
        public EnhancedAnnotation apply(Class from) {

            SlimAnnotatedType slimAnnotatedType = syntheticAnnotationsAnnotatedTypes.get(from);

            if (slimAnnotatedType == null) {
                /*
                 * TODO: we do not recognize the BDA that defined the annotation This could in theory cause problem is two
                 * annotations with the same name but different definition are defined within the same application (different
                 * BDAs)
                 */
                slimAnnotatedType = getBackedAnnotatedType(from, AnnotatedTypeIdentifier.NULL_BDA_ID);
            }
            return EnhancedAnnotationImpl.create(slimAnnotatedType, ClassTransformer.this);
        }
    }

    private class TransformClassToBackedAnnotatedType implements Function, BackedAnnotatedType> {
        @Override
        public BackedAnnotatedType apply(TypeHolder typeHolder) {
            BackedAnnotatedType type = BackedAnnotatedType.of(typeHolder.getRawType(), typeHolder.getBaseType(), cache,
                    reflectionCache, contextId, typeHolder.getBdaId(), typeHolder.getSuffix());
            return updateLookupTable(type);
        }
    }

    private class TransformSlimAnnotatedTypeToEnhancedAnnotatedType implements
            Function, EnhancedAnnotatedType> {
        @Override
        public EnhancedAnnotatedType apply(SlimAnnotatedType annotatedType) {
            return EnhancedAnnotatedTypeImpl.of(annotatedType, ClassTransformer.this);
        }
    }

    private static final class TypeHolder {

        private final String bdaId;
        private final Class rawType;
        private final Type baseType;
        private final String suffix;

        private TypeHolder(Class rawType, Type baseType, String bdaId, String suffix) {
            this.rawType = rawType;
            this.baseType = baseType;
            this.bdaId = bdaId;
            this.suffix = suffix;
        }

        Type getBaseType() {
            return baseType;
        }

        Class getRawType() {
            return rawType;
        }

        String getBdaId() {
            return bdaId;
        }

        String getSuffix() {
            return suffix;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj instanceof TypeHolder) {
                TypeHolder that = (TypeHolder) obj;
                return Objects.equals(this.getBaseType(), that.getBaseType()) && Objects.equals(this.getBdaId(), that.getBdaId()) && Objects.equals(this.getSuffix(), that.getSuffix());
            }
            return false;
        }

        @Override
        public int hashCode() {
            return Objects.hash(this.getBaseType(), this.getBdaId(), this.getSuffix());
        }

        @Override
        public String toString() {
            return "TypeHolder [bdaId=" + bdaId + ", rawType=" + rawType + ", baseType=" + baseType + ", suffix=" + suffix + "]";
        }

    }

    // The synthetic annotations map (annotation type -> annotated type)
    private final ConcurrentMap, UnbackedAnnotatedType> syntheticAnnotationsAnnotatedTypes = new ConcurrentHashMap, UnbackedAnnotatedType>();

    private final ConcurrentMap> slimAnnotatedTypesById;

    private final ComputingCache, BackedAnnotatedType> backedAnnotatedTypes;
    private final ComputingCache, EnhancedAnnotatedType> enhancedAnnotatedTypes;
    private final ComputingCache, EnhancedAnnotation> annotations;

    private final TypeStore typeStore;
    private final SharedObjectCache cache;
    private final ReflectionCache reflectionCache;

    private final String contextId;

    public ClassTransformer(TypeStore typeStore, SharedObjectCache cache, ReflectionCache reflectionCache, String contextId) {
        this.contextId = contextId;
        this.backedAnnotatedTypes = ComputingCacheBuilder.newBuilder().setWeakValues().build(new TransformClassToBackedAnnotatedType());
        this.enhancedAnnotatedTypes = ComputingCacheBuilder.newBuilder().build(new TransformSlimAnnotatedTypeToEnhancedAnnotatedType());
        this.annotations = ComputingCacheBuilder.newBuilder().build(new TransformClassToWeldAnnotation());
        this.typeStore = typeStore;
        this.cache = cache;
        this.reflectionCache = reflectionCache;
        this.slimAnnotatedTypesById = new ConcurrentHashMap>();
    }

    // Slim AnnotatedTypes

    public  BackedAnnotatedType getBackedAnnotatedType(final Class rawType, final Type baseType, final String bdaId, final String suffix) {
        try {
            return backedAnnotatedTypes.getCastValue(new TypeHolder(rawType, baseType, bdaId, suffix));
        } catch (RuntimeException e) {
            if (e instanceof TypeNotPresentException || e instanceof ResourceLoadingException) {
                BootstrapLogger.LOG.exceptionWhileLoadingClass(rawType.getName(), e);
                throw new ResourceLoadingException("Exception while loading class " + rawType.getName(), e);
            }
            throw e;
        } catch (Error e) {
            if(e instanceof NoClassDefFoundError || e instanceof LinkageError) {
                throw new ResourceLoadingException("Error while loading class " + rawType.getName(), e);
            }
            BootstrapLogger.LOG.errorWhileLoadingClass(rawType.getName(), e);
            throw e;
        }
    }

    public  BackedAnnotatedType getBackedAnnotatedType(Class rawType, String bdaId) {
        return getBackedAnnotatedType(rawType, rawType, bdaId, null);
    }

    public  BackedAnnotatedType getBackedAnnotatedType(Class rawType, String bdaId, String suffix) {
        return getBackedAnnotatedType(rawType, rawType, bdaId, suffix);
    }

    public  SlimAnnotatedType getSlimAnnotatedTypeById(AnnotatedTypeIdentifier id) {
        return cast(slimAnnotatedTypesById.get(id));
    }

    public  UnbackedAnnotatedType getUnbackedAnnotatedType(AnnotatedType source, String bdaId, String suffix) {
        UnbackedAnnotatedType type = UnbackedAnnotatedType.additionalAnnotatedType(contextId, source, bdaId, suffix, cache);
        return updateLookupTable(type);
    }

    public  UnbackedAnnotatedType getUnbackedAnnotatedType(SlimAnnotatedType originalType, AnnotatedType source) {
        UnbackedAnnotatedType type = UnbackedAnnotatedType.modifiedAnnotatedType(originalType, source, cache);
        return updateLookupTable(type);
    }

    public UnbackedAnnotatedType getSyntheticAnnotationAnnotatedType(
            Class annotationType) {
        return syntheticAnnotationsAnnotatedTypes.get(annotationType);
    }

    private > S updateLookupTable(S annotatedType) {
        SlimAnnotatedType previousValue = slimAnnotatedTypesById.putIfAbsent(annotatedType.getIdentifier(), annotatedType);
        if (previousValue == null) {
            return annotatedType;
        } else {
            return cast(previousValue);
        }
    }

    // Enhanced AnnotatedTypes

    public  EnhancedAnnotatedType getEnhancedAnnotatedType(Class rawType, String bdaId) {
        return getEnhancedAnnotatedType(getBackedAnnotatedType(rawType, bdaId));
    }

    public  EnhancedAnnotatedType getEnhancedAnnotatedType(Class rawType, Type baseType, String bdaId) {
        return getEnhancedAnnotatedType(getBackedAnnotatedType(rawType, baseType, bdaId, null));
    }

    public  EnhancedAnnotatedType getEnhancedAnnotatedType(AnnotatedType annotatedType, String bdaId) {
        if (annotatedType instanceof EnhancedAnnotatedType) {
            return cast(annotatedType);
        }
        if (annotatedType instanceof SlimAnnotatedType) {
            return cast(getEnhancedAnnotatedType((SlimAnnotatedType) annotatedType));
        }
        return getEnhancedAnnotatedType(getUnbackedAnnotatedType(annotatedType, bdaId,
                AnnotatedTypes.createTypeId(annotatedType)));
    }

    public  EnhancedAnnotatedType getEnhancedAnnotatedType(SlimAnnotatedType annotatedType) {
        return enhancedAnnotatedTypes.getCastValue(annotatedType);
    }

    public  EnhancedAnnotation getEnhancedAnnotation(final Class clazz) {
        return annotations.getCastValue(clazz);
    }

    public void clearAnnotationData(Class annotationClass) {
        annotations.invalidate(annotationClass);
    }

    public TypeStore getTypeStore() {
        return typeStore;
    }

    public SharedObjectCache getSharedObjectCache() {
        return cache;
    }

    public ReflectionCache getReflectionCache() {
        return reflectionCache;
    }

    /**
     *
     * @param annotation
     */
    public void addSyntheticAnnotation(AnnotatedType annotation, String bdaId) {
        syntheticAnnotationsAnnotatedTypes.put(annotation.getJavaClass(),
                getUnbackedAnnotatedType(annotation, bdaId, AnnotatedTypeIdentifier.SYNTHETIC_ANNOTATION_SUFFIX));
        clearAnnotationData(annotation.getJavaClass());
    }

    public  void disposeBackedAnnotatedType(Class rawType, String bdaId, String suffix) {
        TypeHolder typeHolder = new TypeHolder<>(rawType, rawType, bdaId, suffix);
        BackedAnnotatedType annotatedType = cast(this.backedAnnotatedTypes.getValueIfPresent(typeHolder));
        if (annotatedType != null) {
            this.backedAnnotatedTypes.invalidate(typeHolder);
            this.slimAnnotatedTypesById.remove(annotatedType.getIdentifier());
            this.enhancedAnnotatedTypes.invalidate(annotatedType);
        }
    }

    @Override
    public void cleanupAfterBoot() {
        this.enhancedAnnotatedTypes.clear();
        this.annotations.clear();
        for (BackedAnnotatedType annotatedType : backedAnnotatedTypes.getAllPresentValues()) {
            annotatedType.clear();
        }
        this.backedAnnotatedTypes.clear();
    }

    @Override
    public void cleanup() {
        cleanupAfterBoot();
        slimAnnotatedTypesById.clear();
        syntheticAnnotationsAnnotatedTypes.clear();
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy