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.reflection.Reflections.cast;

import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

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

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

    private class SpecializedBeanResolverForBeanManager implements Function {

        @Override
        public SpecializedBeanResolver apply(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 implements Function, Set>> {

        @Override
        public Set> apply(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)) {
                    for (AbstractBean specializedBean : result) {
                        AtomicLong value = specializedBeansMap.get(specializedBean);
                        if (value == null) {
                            value = new AtomicLong(0);
                            AtomicLong previous = specializedBeansMap.putIfAbsent(specializedBean, value);
                            if (previous != null) {
                                value = previous;
                            }
                        }
                        value.incrementAndGet();
                    }
                }
                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 specializedBeanResolvers.getValue(bean.getBeanManager());
        }
    }

    private final ComputingCache specializedBeanResolvers;
    private final Map environmentByManager = new ConcurrentHashMap();
    // maps specializing beans to the set of specialized beans
    private final ComputingCache, 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 ConcurrentHashMap, AtomicLong> specializedBeansMap = new ConcurrentHashMap, AtomicLong>();

    public SpecializationAndEnablementRegistry() {
        ComputingCacheBuilder cacheBuilder = ComputingCacheBuilder.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 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> noLongerSpecializedBeans = specializedBeans.getValueIfPresent(bean);
        if (noLongerSpecializedBeans != null) {
            specializedBeans.invalidate(bean);
            for (AbstractBean noLongerSpecializedBean : noLongerSpecializedBeans) {
                // We should never get null here but just to be sure
                AtomicLong count = specializedBeansMap.get(noLongerSpecializedBean);
                if (count != null) {
                    count.decrementAndGet();
                }
            }
        }
    }

    public boolean isSpecializedInAnyBeanDeployment(Bean bean) {
        AtomicLong count = specializedBeansMap.get(bean);
        return count != null && count.longValue() > 0;
    }

    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();
        specializedBeansMap.clear();
    }

    public Set> getBeansSpecializedInAnyDeployment() {
        return ImmutableSet.copyOf(specializedBeansMap.keySet());
    }

    public Map, Long> getBeansSpecializedInAnyDeploymentAsMap() {
        Set, AtomicLong>> entrySet = specializedBeansMap.entrySet();
        Map, Long> resultingMap = new HashMap<>();
        for (Entry, AtomicLong> entry : entrySet) {
            resultingMap.put(entry.getKey(), entry.getValue().longValue());
        }

        return ImmutableMap.copyOf(resultingMap);
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy