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

org.jboss.weld.bean.ContextualInstanceStrategy Maven / Gradle / Ivy

Go to download

This jar bundles all the bits of Weld and CDI required for running in a Servlet container.

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

import java.lang.annotation.Annotation;
import java.util.Set;

import javax.enterprise.context.ApplicationScoped;
import javax.enterprise.context.ConversationScoped;
import javax.enterprise.context.RequestScoped;
import javax.enterprise.context.SessionScoped;
import javax.enterprise.context.spi.AlterableContext;
import javax.enterprise.context.spi.Context;
import javax.enterprise.context.spi.CreationalContext;
import javax.enterprise.inject.spi.Bean;
import javax.enterprise.inject.spi.BeanAttributes;
import javax.inject.Singleton;

import org.jboss.weld.contexts.cache.RequestScopedCache;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.util.collections.ImmutableSet;
import org.jboss.weld.util.reflection.Reflections;

/**
 * This component allows optimized strategies for obtaining contextual instances of a given bean to be plugged in.
 *
 * By default a contextual instance of a bean is obtained by first obtaining the context for bean's scope and then by
 * calling {@link Context#get(javax.enterprise.context.spi.Contextual)} or {@link Context#get(javax.enterprise.context.spi.Contextual, CreationalContext)}
 * on the given context. This algorithm matches the {@link #defaultStrategy()} implementation.
 *
 * In addition, specialized implementations are provided.
 *
 * For {@link ApplicationScoped} beans a special strategy is used which caches application-scoped bean instances in a volatile field. This implementation respects
 * the possibility of an instance being destroyed via {@link AlterableContext} and the cached instance is flushed in such case.
 *
 * For {@link SessionScoped}, {@link ConversationScoped} and {@link RequestScoped} beans a special strategy is used which caches contextual bean instances in
 * a {@link ThreadLocal}. This implementation respects the possibility of an instance being destroyed via {@link AlterableContext} and the cached instance is
 * flushed in such case. This is done indirectly by {@link RequestScopedCache}.
 *
 * @author Jozef Hartinger
 *
 * @param 
 */
public abstract class ContextualInstanceStrategy {

    @SuppressWarnings("unchecked")
    public static  ContextualInstanceStrategy defaultStrategy() {
        return (ContextualInstanceStrategy) DefaultContextualInstanceStrategy.INSTANCE;
    }

    public static  ContextualInstanceStrategy create(BeanAttributes bean, BeanManagerImpl manager) {
        if (ApplicationScoped.class == bean.getScope() || Singleton.class == bean.getScope()) {
            return new ApplicationScopedContextualInstanceStrategy();
        } else if (CachingContextualInstanceStrategy.CACHEABLE_SCOPES.contains(bean.getScope())) {
            return new CachingContextualInstanceStrategy();
        }
        return defaultStrategy();
    }

    ContextualInstanceStrategy() {
    }

    abstract T get(Bean bean, BeanManagerImpl manager, CreationalContext ctx);

    abstract T getIfExists(Bean bean, BeanManagerImpl manager);

    abstract void destroy(Bean bean);

    private static class DefaultContextualInstanceStrategy extends ContextualInstanceStrategy {

        static final ContextualInstanceStrategy INSTANCE = new DefaultContextualInstanceStrategy();

        @Override
        T getIfExists(Bean bean, BeanManagerImpl manager) {
            return manager.getContext(bean.getScope()).get(bean);
        }

        @Override
        T get(Bean bean, BeanManagerImpl manager, CreationalContext ctx) {
            Context context = manager.getContext(bean.getScope());
            T instance = context.get(bean);
            if (instance == null) {
                if (ctx == null) {
                    ctx = manager.createCreationalContext(bean);
                }
                instance = context.get(bean, Reflections.> cast(ctx));
            }
            return instance;
        }

        @Override
        void destroy(Bean bean) {
            // noop
        }
    }

    private static class ApplicationScopedContextualInstanceStrategy extends DefaultContextualInstanceStrategy {

        private volatile T value;

        @Override
        T getIfExists(Bean bean, BeanManagerImpl manager) {
            T instance = value;
            if (instance != null) {
                return instance;
            }
            synchronized (this) {
                if (value == null) {
                    instance = super.getIfExists(bean, manager);
                    if (instance != null) {
                        this.value = instance;
                    }
                }
                return instance;
            }
        }

        @Override
        T get(Bean bean, BeanManagerImpl manager, CreationalContext ctx) {
            T instance = value;
            if (instance != null) {
                return instance;
            }
            synchronized (this) {
                if ((instance = value) == null) {
                    this.value = instance = super.get(bean, manager, ctx);
                }
                return instance;
            }
        }

        @Override
        void destroy(Bean bean) {
            value = null;
        }
    }

    private static class CachingContextualInstanceStrategy extends DefaultContextualInstanceStrategy {

        private static final Set> CACHEABLE_SCOPES = ImmutableSet.of(RequestScoped.class, ConversationScoped.class,
                SessionScoped.class);
        private final ThreadLocal cache = new ThreadLocal();

        @Override
        T getIfExists(Bean bean, BeanManagerImpl manager) {
            T cached = cache.get();
            if (cached != null) {
                return cached;
            }
            cached = super.getIfExists(bean, manager);
            if (cached != null && RequestScopedCache.addItemIfActive(cache)) {
                cache.set(cached);
            }
            return cached;
        }

        @Override
        T get(Bean bean, BeanManagerImpl manager, CreationalContext ctx) {
            T cached = cache.get();
            if (cached != null) {
                return cached;
            }
            cached = super.get(bean, manager, ctx);
            if (RequestScopedCache.addItemIfActive(cache)) {
                cache.set(cached);
            }
            return cached;
        }
    }
}