/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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.apache.deltaspike.cdise.weld; import javax.enterprise.context.ApplicationScoped; import javax.enterprise.context.ConversationScoped; import javax.enterprise.context.Dependent; import javax.enterprise.context.RequestScoped; import javax.enterprise.context.SessionScoped; import javax.enterprise.inject.Instance; import javax.inject.Inject; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.Map; import org.apache.deltaspike.cdise.api.ContextControl; import org.jboss.weld.context.ApplicationContext; import org.jboss.weld.context.bound.BoundConversationContext; import org.jboss.weld.context.bound.BoundRequestContext; import org.jboss.weld.context.bound.BoundSessionContext; import org.jboss.weld.context.bound.MutableBoundRequest; /** * Weld specific impl of the {@link org.apache.deltaspike.cdise.api.ContextControl} */ @Dependent @SuppressWarnings("UnusedDeclaration") public class WeldContextControl implements ContextControl { private static ThreadLocal<RequestContextHolder> requestContexts = new ThreadLocal<RequestContextHolder>(); private static ThreadLocal<Map<String, Object>> sessionMaps = new ThreadLocal<Map<String, Object>>(); @Inject private ApplicationContext applicationContext; @Inject private BoundSessionContext sessionContext; @Inject private Instance<BoundRequestContext> requestContextFactory; @Inject private BoundConversationContext conversationContext; @Override public void startContexts() { startApplicationScope(); startSessionScope(); startRequestScope(); startConversationScope(null); } @Override public void startContext(Class<? extends Annotation> scopeClass) { if (scopeClass.isAssignableFrom(ApplicationScoped.class)) { startApplicationScope(); } else if (scopeClass.isAssignableFrom(SessionScoped.class)) { startSessionScope(); } else if (scopeClass.isAssignableFrom(RequestScoped.class)) { startRequestScope(); } else if (scopeClass.isAssignableFrom(ConversationScoped.class)) { startConversationScope(null); } } /** * Stops Conversation, Request and Session contexts. * Does NOT stop Application context, only invalidates * App scoped beans, as in Weld this context always active and clears * automatically on shutdown. * * {@inheritDoc} */ @Override public void stopContexts() { stopConversationScope(); stopRequestScope(); stopSessionScope(); stopApplicationScope(); } @Override public void stopContext(Class<? extends Annotation> scopeClass) { if (scopeClass.isAssignableFrom(ApplicationScoped.class)) { stopApplicationScope(); } else if (scopeClass.isAssignableFrom(SessionScoped.class)) { stopSessionScope(); } else if (scopeClass.isAssignableFrom(RequestScoped.class)) { stopRequestScope(); } else if (scopeClass.isAssignableFrom(ConversationScoped.class)) { stopConversationScope(); } } /* * This is a no-op method. In Weld Application Context is active as soon as the container starts */ private void startApplicationScope() { // No-op, in Weld Application context is always active } /** * Weld Application context is active from container start to its shutdown * This method merely clears out all ApplicationScoped beans BUT the context * will still be active which may result in immediate re-creation of some beans. */ private void stopApplicationScope() { // Welds ApplicationContext gets cleaned at shutdown. // Weld App context should be always active if (applicationContext.isActive()) { // destroys the bean instances, but the context stays active applicationContext.invalidate(); } } void startRequestScope() { RequestContextHolder rcHolder = requestContexts.get(); if (rcHolder == null) { rcHolder = new RequestContextHolder(requestContextFactory.get(), new HashMap<String, Object>()); requestContexts.set(rcHolder); rcHolder.getBoundRequestContext().associate(rcHolder.getRequestMap()); rcHolder.getBoundRequestContext().activate(); } } void stopRequestScope() { RequestContextHolder rcHolder = requestContexts.get(); if (rcHolder != null && rcHolder.getBoundRequestContext().isActive()) { rcHolder.getBoundRequestContext().invalidate(); rcHolder.getBoundRequestContext().deactivate(); rcHolder.getBoundRequestContext().dissociate(rcHolder.getRequestMap()); requestContexts.set(null); requestContexts.remove(); } } private void startSessionScope() { Map<String, Object> sessionMap = sessionMaps.get(); if (sessionMap == null) { sessionMap = new HashMap<String, Object>(); sessionMaps.set(sessionMap); } sessionContext.associate(sessionMap); sessionContext.activate(); } private void stopSessionScope() { if (sessionContext.isActive()) { sessionContext.invalidate(); sessionContext.deactivate(); sessionContext.dissociate(sessionMaps.get()); sessionMaps.set(null); sessionMaps.remove(); } } void startConversationScope(String cid) { RequestContextHolder rcHolder = requestContexts.get(); if (rcHolder == null) { startRequestScope(); rcHolder = requestContexts.get(); } conversationContext.associate(new MutableBoundRequest(rcHolder.requestMap, sessionMaps.get())); conversationContext.activate(cid); } void stopConversationScope() { RequestContextHolder rcHolder = requestContexts.get(); if (rcHolder == null) { startRequestScope(); rcHolder = requestContexts.get(); } if (conversationContext.isActive()) { conversationContext.invalidate(); conversationContext.deactivate(); conversationContext.dissociate(new MutableBoundRequest(rcHolder.getRequestMap(), sessionMaps.get())); } } private static class RequestContextHolder { private final BoundRequestContext boundRequestContext; private final Map<String, Object> requestMap; private RequestContextHolder(BoundRequestContext boundRequestContext, Map<String, Object> requestMap) { this.boundRequestContext = boundRequestContext; this.requestMap = requestMap; } public BoundRequestContext getBoundRequestContext() { return boundRequestContext; } public Map<String, Object> getRequestMap() { return requestMap; } } }