Package org.jboss.weld.bootstrap

Source Code of org.jboss.weld.bootstrap.SpecializationAndEnablementRegistry$BeansSpecializedByBean

/*
* 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.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 java.util.function.Function;

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 org.jboss.weld.util.cache.ComputingCache;
import org.jboss.weld.util.cache.ComputingCacheBuilder;

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 implements Function<BeanManagerImpl, SpecializedBeanResolver> {

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

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

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

    private class BeansSpecializedByBean implements Function<Bean<?>, Set<? extends AbstractBean<?, ?>>> {

        @Override
        public Set<? extends AbstractBean<?, ?>> apply(Bean<?> specializingBean) {
            Set<? extends AbstractBean<?, ?>> 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<AbstractClassBean<?>> apply(AbstractClassBean<?> bean) {
            return getSpecializedBeanResolver(bean).resolveSpecializedBeans(bean);
        }

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

        private SpecializedBeanResolver getSpecializedBeanResolver(RIBean<?> bean) {
            return specializedBeanResolvers.getValue(bean.getBeanManager());
        }
    }

    private final ComputingCache<BeanManagerImpl, SpecializedBeanResolver> specializedBeanResolvers;
    private final Map<BeanManagerImpl, BeanDeployerEnvironment> environmentByManager = new ConcurrentHashMap<BeanManagerImpl, BeanDeployerEnvironment>();
    // maps specializing beans to the set of specialized beans
    private final ComputingCache<Bean<?>, Set<? extends AbstractBean<?, ?>>> 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<AbstractBean<?, ?>> specializedBeansSet = ConcurrentHashMultiset.create();

    public SpecializationAndEnablementRegistry() {
        ComputingCacheBuilder cacheBuilder = ComputingCacheBuilder.newBuilder();
        this.specializedBeanResolvers = cacheBuilder.build(new SpecializedBeanResolverForBeanManager());
        this.specializedBeans = ComputingCacheBuilder.newBuilder().buildReentrant(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<? extends AbstractBean<?, ?>> resolveSpecializedBeans(Bean<?> specializingBean) {
        if (specializingBean instanceof AbstractClassBean<?>) {
            AbstractClassBean<?> abstractClassBean = (AbstractClassBean<?>) specializingBean;
            if (abstractClassBean.isSpecializing()) {
                return specializedBeans.getValue(specializingBean);
            }
        }
        if (specializingBean instanceof ProducerMethod<?, ?>) {
            ProducerMethod<?, ?> producerMethod = (ProducerMethod<?, ?>) specializingBean;
            if (producerMethod.isSpecializing()) {
                return specializedBeans.getValue(specializingBean);
            }
        }
        return Collections.emptySet();
    }

    public void vetoSpecializingBean(Bean<?> bean) {
        Set<? extends AbstractBean<?, ?>> noLongerSpecializedBeans = specializedBeans.getValueIfPresent(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.clear();
        environmentByManager.clear();
        specializedBeans.clear();
        specializedBeansSet.clear();
    }

    public Set<AbstractBean<?, ?>> getBeansSpecializedInAnyDeployment() {
        return specializedBeansSet.elementSet();
    }

    public Multiset<AbstractBean<?, ?>> getBeansSpecializedInAnyDeploymentAsMultiset() {
        return Multisets.unmodifiableMultiset(specializedBeansSet);
    }
}
TOP

Related Classes of org.jboss.weld.bootstrap.SpecializationAndEnablementRegistry$BeansSpecializedByBean

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.