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

org.jboss.weld.bootstrap.enablement.GlobalEnablementBuilder Maven / Gradle / Ivy

There is a newer version: 3.0.0.Alpha1
Show newest version
/*
 * JBoss, Home of Professional Open Source
 * Copyright 2013, 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.bootstrap.enablement;

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

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Set;

import javax.enterprise.inject.spi.Extension;

import org.jboss.weld.bootstrap.BeanDeployment;
import org.jboss.weld.bootstrap.api.helpers.AbstractBootstrapService;
import org.jboss.weld.bootstrap.spi.BeansXml;
import org.jboss.weld.bootstrap.spi.Metadata;
import org.jboss.weld.exceptions.DeploymentException;
import org.jboss.weld.logging.BootstrapLogger;
import org.jboss.weld.logging.LogMessageCallback;
import org.jboss.weld.logging.MessageCallback;
import org.jboss.weld.logging.ValidatorLogger;
import org.jboss.weld.resources.spi.ResourceLoader;
import org.jboss.weld.resources.spi.ResourceLoadingException;

import org.jboss.weld.util.Function;
import org.jboss.weld.util.collections.ImmutableList;
import org.jboss.weld.util.collections.ImmutableMap;
import org.jboss.weld.util.collections.ImmutableSet;
import org.jboss.weld.util.collections.Iterables;

/**
 * This service gathers globally enabled interceptors, decorators and alternatives and builds a list of each.
 *
 * @author Jozef Hartinger
 *
 */
public class GlobalEnablementBuilder extends AbstractBootstrapService {

    private final List alternatives = Collections.synchronizedList(new ArrayList());
    private final List interceptors = Collections.synchronizedList(new ArrayList());
    private final List decorators = Collections.synchronizedList(new ArrayList());

    private volatile Map, Integer> cachedAlternativeMap;
    private volatile boolean sorted;

    private void addItem(List list, Class javaClass, int priority) {
        list.add(new Item(javaClass, priority));
    }

    public void addAlternative(Class javaClass, int priority) {
        addItem(alternatives, javaClass, priority);
    }

    public void addInterceptor(Class javaClass, int priority) {
        addItem(interceptors, javaClass, priority);
    }

    public void addDecorator(Class javaClass, int priority) {
        addItem(decorators, javaClass, priority);
    }

    public List> getAlternativeList(final Extension extension) {
        initialize();
        return new EnablementListView() {

            @Override
            protected Extension getExtension() {
                return extension;
            }

            @Override
            protected ViewType getViewType() {
                return ViewType.ALTERNATIVES;
            }

            @Override
            protected List getDelegate() {
                return alternatives;
            }
        };
    }

    public List> getInterceptorList(final Extension extension) {
        initialize();
        return new EnablementListView() {

            @Override
            protected Extension getExtension() {
                return extension;
            }

            @Override
            protected ViewType getViewType() {
                return ViewType.INTERCEPTORS;
            }

            @Override
            protected List getDelegate() {
                return interceptors;
            }

        };
    }

    public List> getDecoratorList(final Extension extension) {
        initialize();
        return new EnablementListView() {

            @Override
            protected Extension getExtension() {
                return extension;
            }

            @Override
            protected ViewType getViewType() {
                return ViewType.DECORATORS;
            }

            @Override
            protected List getDelegate() {
                return decorators;
            }
        };
    }

    /*
     * cachedAlternativeMap is accessed from a single thread only and the result is safely propagated. Therefore, there is no need to synchronize access to
     * cachedAlternativeMap.
     */
    private Map, Integer> getGlobalAlternativeMap() {
        if (cachedAlternativeMap == null) {
            Map, Integer> map = new HashMap, Integer>();
            for (ListIterator iterator = alternatives.listIterator(); iterator.hasNext(); ) {
                Item item = iterator.next();
                map.put(item.getJavaClass(), iterator.previousIndex());
            }
            cachedAlternativeMap = ImmutableMap.copyOf(map);
        }
        return cachedAlternativeMap;
    }

    private void initialize() {
        if (!sorted) {
            Collections.sort(alternatives);
            Collections.sort(interceptors);
            Collections.sort(decorators);
            sorted = true;
        }
    }

    public ModuleEnablement createModuleEnablement(BeanDeployment deployment) {

        ClassLoader loader = new ClassLoader(deployment.getBeanManager().getServices().get(ResourceLoader.class));

        BeansXml beansXml = deployment.getBeanDeploymentArchive().getBeansXml();

        Set> alternativeClasses = null;
        Set> alternativeStereotypes = null;

        List> globallyEnabledInterceptors = getInterceptorList(null);
        List> globallyEnabledDecorators = getDecoratorList(null);

        ImmutableList.Builder> moduleInterceptorsBuilder = ImmutableList.>builder();
        moduleInterceptorsBuilder.addAll(globallyEnabledInterceptors);

        ImmutableList.Builder> moduleDecoratorsBuilder = ImmutableList.>builder();
        moduleDecoratorsBuilder.addAll(globallyEnabledDecorators);

        if (beansXml != null) {

            checkForDuplicates(beansXml.getEnabledInterceptors(), ValidatorLogger.INTERCEPTOR_SPECIFIED_TWICE);
            checkForDuplicates(beansXml.getEnabledDecorators(), ValidatorLogger.DECORATOR_SPECIFIED_TWICE);
            checkForDuplicates(beansXml.getEnabledAlternativeClasses(), ValidatorLogger.ALTERNATIVE_CLASS_SPECIFIED_MULTIPLE_TIMES);
            checkForDuplicates(beansXml.getEnabledAlternativeStereotypes(), ValidatorLogger.ALTERNATIVE_STEREOTYPE_SPECIFIED_MULTIPLE_TIMES);

            List> interceptorClasses = new ArrayList<>();
            for (Metadata stringMetadata : beansXml.getEnabledInterceptors()) {
                interceptorClasses.add(loader.apply(stringMetadata));
            }
            moduleInterceptorsBuilder.addAll(filter(interceptorClasses, globallyEnabledInterceptors, ValidatorLogger.INTERCEPTOR_ENABLED_FOR_APP_AND_ARCHIVE,
                    deployment));

            List> decoratorClasses = new ArrayList<>();
            for (Metadata stringMetadata : beansXml.getEnabledDecorators()) {
                decoratorClasses.add(loader.apply(stringMetadata));
            }
            moduleDecoratorsBuilder.addAll(filter(decoratorClasses, globallyEnabledDecorators, ValidatorLogger.DECORATOR_ENABLED_FOR_APP_AND_ARCHIVE,
                    deployment));

            alternativeClasses = ImmutableSet.copyOf(Iterables.transform(beansXml.getEnabledAlternativeClasses(), loader));
            alternativeStereotypes = cast(ImmutableSet.copyOf(Iterables.transform(beansXml.getEnabledAlternativeStereotypes(), loader)));
        } else {
            alternativeClasses = Collections.emptySet();
            alternativeStereotypes = Collections.emptySet();
        }

        Map, Integer> globalAlternatives = getGlobalAlternativeMap();

        return new ModuleEnablement(moduleInterceptorsBuilder.build(), moduleDecoratorsBuilder.build(), globalAlternatives, alternativeClasses,
                alternativeStereotypes);
    }

    @Override
    public void cleanupAfterBoot() {
        alternatives.clear();
        interceptors.clear();
        decorators.clear();
    }

    @Override
    public String toString() {
        return "GlobalEnablementBuilder [alternatives=" + alternatives + ", interceptors=" + interceptors + ", decorators=" + decorators + "]";
    }

    private  void checkForDuplicates(List> list, MessageCallback messageCallback) {
        Map> map = new HashMap>();
        for (Metadata item : list) {
            Metadata previousOccurrence = map.put(item.getValue(), item);
            if (previousOccurrence != null) {
                throw messageCallback.construct(item.getValue(), item, previousOccurrence);
            }
        }
    }

    /**
     * Filter out interceptors and decorators which are also enabled globally.
     *
     * @param enabledClasses
     * @param globallyEnabledClasses
     * @param logMessageCallback
     * @param deployment
     * @return the filtered list
     */
    private  List> filter(List> enabledClasses, List> globallyEnabledClasses, LogMessageCallback logMessageCallback,
            BeanDeployment deployment) {
        for (Iterator> iterator = enabledClasses.iterator(); iterator.hasNext(); ) {
            Class enabledClass = iterator.next();
            if (globallyEnabledClasses.contains(enabledClass)) {
                logMessageCallback.log(enabledClass, deployment.getBeanDeploymentArchive().getId());
                iterator.remove();
            }
        }
        return enabledClasses;
    }

    private static class ClassLoader implements Function, Class> {

        private final ResourceLoader resourceLoader;

        public ClassLoader(ResourceLoader resourceLoader) {
            this.resourceLoader = resourceLoader;
        }

        @Override
        public Class apply(Metadata from) {
            try {
                return resourceLoader.classForName(from.getValue());
            } catch (ResourceLoadingException e) {
                throw BootstrapLogger.LOG.errorLoadingBeansXmlEntry(from.getValue(), from.getLocation(), e.getCause());
            } catch (Exception e) {
                throw BootstrapLogger.LOG.errorLoadingBeansXmlEntry(from.getValue(), from.getLocation(), e);
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy