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

org.jboss.weld.bootstrap.SpecializationAndEnablementRegistry Maven / Gradle / Ivy

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

import static org.jboss.weld.util.cache.LoadingCacheUtils.getCacheValue;
import static org.jboss.weld.util.reflection.Reflections.cast;

import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

import javax.enterprise.inject.spi.Bean;

import org.jboss.weld.bean.AbstractBean;
import org.jboss.weld.bean.AbstractClassBean;
import org.jboss.weld.bean.AbstractProducerBean;
import org.jboss.weld.bean.ProducerMethod;
import org.jboss.weld.bean.RIBean;
import org.jboss.weld.bootstrap.api.helpers.AbstractBootstrapService;
import org.jboss.weld.manager.BeanManagerImpl;

import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ConcurrentHashMultiset;
import com.google.common.collect.Multiset;
import com.google.common.collect.Multisets;

/**
 * Holds information about specialized beans.
 *
 * @author Jozef Hartinger
 *
 */
public class SpecializationAndEnablementRegistry extends AbstractBootstrapService {

    private class SpecializedBeanResolverForBeanManager extends CacheLoader {

        @Override
        public SpecializedBeanResolver load(BeanManagerImpl manager) {
            return new SpecializedBeanResolver(buildAccessibleBeanDeployerEnvironments(manager));
        }

        private Set buildAccessibleBeanDeployerEnvironments(BeanManagerImpl manager) {
            Set result = new HashSet();
            result.add(environmentByManager.get(manager));
            buildAccessibleBeanDeployerEnvironments(manager, result);
            return result;
        }

        private void buildAccessibleBeanDeployerEnvironments(BeanManagerImpl manager, Collection result) {
            for (BeanManagerImpl accessibleManager : manager.getAccessibleManagers()) {
                BeanDeployerEnvironment environment = environmentByManager.get(accessibleManager);
                if (!result.contains(environment)) {
                    result.add(environment);
                    buildAccessibleBeanDeployerEnvironments(accessibleManager, result);
                }
            }
        }
    }

    private class BeansSpecializedByBean extends CacheLoader, Set>> {

        @Override
        public Set> load(Bean specializingBean) {
            Set> result = null;
            if (specializingBean instanceof AbstractClassBean) {
                result = apply((AbstractClassBean) specializingBean);
            }
            if (specializingBean instanceof ProducerMethod) {
                result = apply((ProducerMethod) specializingBean);
            }
            if (result != null) {
                if (isEnabledInAnyBeanDeployment(specializingBean)) {
                    specializedBeansSet.addAll(result);
                }
                return result;
            }
            throw new IllegalArgumentException("Unsupported bean type " + specializingBean);
        }

        private Set> apply(AbstractClassBean bean) {
            return getSpecializedBeanResolver(bean).resolveSpecializedBeans(bean);
        }

        private Set> apply(ProducerMethod bean) {
            return getSpecializedBeanResolver(bean).resolveSpecializedBeans(bean);
        }

        private SpecializedBeanResolver getSpecializedBeanResolver(RIBean bean) {
            return getCacheValue(specializedBeanResolvers, bean.getBeanManager());
        }
    }

    private final LoadingCache specializedBeanResolvers;
    private final Map environmentByManager = new ConcurrentHashMap();
    // maps specializing beans to the set of specialized beans
    private final LoadingCache, Set>> specializedBeans;
    // fast lookup structure that allows us to figure out if a given bean is specialized in any of the bean deployments
    private final Multiset> specializedBeansSet = ConcurrentHashMultiset.create();

    public SpecializationAndEnablementRegistry() {
        CacheBuilder cacheBuilder = CacheBuilder.newBuilder();
        this.specializedBeanResolvers = cacheBuilder.build(new SpecializedBeanResolverForBeanManager());
        this.specializedBeans = cacheBuilder.build(new BeansSpecializedByBean());
    }

    /**
     * Returns a set of beans specialized by this bean. An empty set is returned if this bean does not specialize another beans.
     */
    public Set> resolveSpecializedBeans(Bean specializingBean) {
        if (specializingBean instanceof AbstractClassBean) {
            AbstractClassBean abstractClassBean = (AbstractClassBean) specializingBean;
            if (abstractClassBean.isSpecializing()) {
                return getCacheValue(specializedBeans, specializingBean);
            }
        }
        if (specializingBean instanceof ProducerMethod) {
            ProducerMethod producerMethod = (ProducerMethod) specializingBean;
            if (producerMethod.isSpecializing()) {
                return getCacheValue(specializedBeans, specializingBean);
            }
        }
        return Collections.emptySet();
    }

    public void vetoSpecializingBean(Bean bean) {
        Set> noLongerSpecializedBeans = specializedBeans.getIfPresent(bean);
        if (noLongerSpecializedBeans != null) {
            specializedBeans.invalidate(bean);
            for (AbstractBean noLongerSpecializedBean : noLongerSpecializedBeans) {
                specializedBeansSet.remove(noLongerSpecializedBean);
            }
        }
    }

    public boolean isSpecializedInAnyBeanDeployment(Bean bean) {
        return specializedBeansSet.contains(bean);
    }

    public boolean isEnabledInAnyBeanDeployment(Bean bean) {
        for (BeanManagerImpl manager : environmentByManager.keySet()) {
            if (manager.isBeanEnabled(bean)) {
                return true;
            }
        }
        return false;
    }

    public boolean isCandidateForLifecycleEvent(Bean bean) {
        if (bean instanceof AbstractProducerBean) {
            AbstractProducerBean producer = cast(bean);
            if (!isCandidateForLifecycleEvent(producer.getDeclaringBean())) {
                return false;
            }
        }
        return isEnabledInAnyBeanDeployment(bean) && !isSpecializedInAnyBeanDeployment(bean);
    }

    public void registerEnvironment(BeanManagerImpl manager, BeanDeployerEnvironment environment, boolean additionalBeanArchive) {
        if ((specializedBeanResolvers.size() > 0) && !additionalBeanArchive) {
            /*
             * An environment should not be added after we started resolving specialized beans. However we cannot avoid that completely
             * in certain situations e.g. when a bean is added through AfterBeanDiscovery (otherwise a chicken-egg problem emerges between
             * determining which beans are enabled which is needed for firing ProcessBean events and resolving specialization of AfterBeanDiscovery-added beans)
             *
             * As a result beans added through AfterBeanDiscovery cannot be specialized.
             */
            throw new IllegalStateException(this.getClass().getName() + ".registerEnvironment() must not be called after specialization resolution begins");
        }
        if (environment == null) {
            throw new IllegalArgumentException("Environment must not be null");
        }
        this.environmentByManager.put(manager, environment);
    }

    @Override
    public void cleanupAfterBoot() {
        specializedBeanResolvers.invalidateAll();
        environmentByManager.clear();
        specializedBeans.invalidateAll();
        specializedBeansSet.clear();
    }

    public Set> getBeansSpecializedInAnyDeployment() {
        return specializedBeansSet.elementSet();
    }

    public Multiset> getBeansSpecializedInAnyDeploymentAsMultiset() {
        return Multisets.unmodifiableMultiset(specializedBeansSet);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy