Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* JBoss, Home of Professional Open Source
* Copyright 2013, 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.servlet;
import java.lang.annotation.Annotation;
import java.util.Collections;
import javax.enterprise.inject.spi.EventMetadata;
import javax.servlet.ServletContext;
import javax.servlet.ServletRequestListener;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import org.jboss.weld.Container;
import org.jboss.weld.bootstrap.BeanDeploymentModule;
import org.jboss.weld.bootstrap.BeanDeploymentModules;
import org.jboss.weld.bootstrap.api.Service;
import org.jboss.weld.context.BoundContext;
import org.jboss.weld.context.ManagedContext;
import org.jboss.weld.context.cache.RequestScopedCache;
import org.jboss.weld.context.http.HttpRequestContext;
import org.jboss.weld.context.http.HttpRequestContextImpl;
import org.jboss.weld.context.http.HttpSessionContext;
import org.jboss.weld.context.http.HttpSessionDestructionContext;
import org.jboss.weld.event.EventMetadataImpl;
import org.jboss.weld.event.FastEvent;
import org.jboss.weld.literal.DestroyedLiteral;
import org.jboss.weld.literal.InitializedLiteral;
import org.jboss.weld.logging.ServletLogger;
import org.jboss.weld.manager.BeanManagerImpl;
import org.jboss.weld.servlet.spi.HttpContextActivationFilter;
import org.jboss.weld.util.reflection.Reflections;
/**
* Takes care of setting up and tearing down CDI contexts around an HTTP request and dispatching context lifecycle events.
*
* @author Jozef Hartinger
* @author Marko Luksa
*
*/
public class HttpContextLifecycle implements Service {
public static final String ASYNC_STARTED_ATTR_NAME = "org.jboss.weld.context.asyncStarted";
private static final String HTTP_SESSION = "org.jboss.weld." + HttpSession.class.getName();
private static final String INCLUDE_HEADER = "javax.servlet.include.request_uri";
private static final String FORWARD_HEADER = "javax.servlet.forward.request_uri";
private static final String REQUEST_DESTROYED = HttpContextLifecycle.class.getName() + ".request.destroyed";
private static final String GUARD_PARAMETER_NAME = "org.jboss.weld.context.ignore.guard.marker";
private static final Object GUARD_PARAMETER_VALUE = new Object();
private HttpSessionDestructionContext sessionDestructionContextCache;
private HttpSessionContext sessionContextCache;
private HttpRequestContext requestContextCache;
private volatile Boolean conversationActivationEnabled;
private final boolean ignoreForwards;
private final boolean ignoreIncludes;
private final BeanManagerImpl beanManager;
private final ConversationContextActivator conversationContextActivator;
private final HttpContextActivationFilter contextActivationFilter;
private final FastEvent requestInitializedEvent;
private final FastEvent requestDestroyedEvent;
private final FastEvent sessionInitializedEvent;
private final FastEvent sessionDestroyedEvent;
private final ServletApiAbstraction servletApi;
private final ServletContextService servletContextService;
private final Container container;
private final BeanDeploymentModule module;
private static final ThreadLocal nestedInvocationGuard = new ThreadLocal();
private final boolean nestedInvocationGuardEnabled;
private static class Counter {
private int value = 1;
}
public HttpContextLifecycle(BeanManagerImpl beanManager, HttpContextActivationFilter contextActivationFilter, boolean ignoreForwards,
boolean ignoreIncludes, boolean lazyConversationContext, boolean nestedInvocationGuardEnabled) {
this.beanManager = beanManager;
this.conversationContextActivator = new ConversationContextActivator(beanManager, lazyConversationContext);
this.conversationActivationEnabled = null;
this.ignoreForwards = ignoreForwards;
this.ignoreIncludes = ignoreIncludes;
this.contextActivationFilter = contextActivationFilter;
this.requestInitializedEvent = FastEvent.of(HttpServletRequest.class, beanManager, InitializedLiteral.REQUEST);
this.requestDestroyedEvent = FastEvent.of(HttpServletRequest.class, beanManager, DestroyedLiteral.REQUEST);
this.sessionInitializedEvent = FastEvent.of(HttpSession.class, beanManager, InitializedLiteral.SESSION);
this.sessionDestroyedEvent = FastEvent.of(HttpSession.class, beanManager, DestroyedLiteral.SESSION);
this.servletApi = beanManager.getServices().get(ServletApiAbstraction.class);
this.servletContextService = beanManager.getServices().get(ServletContextService.class);
this.nestedInvocationGuardEnabled = nestedInvocationGuardEnabled;
this.container = Container.instance(beanManager);
BeanDeploymentModules beanDeploymentModules = beanManager.getServices().get(BeanDeploymentModules.class);
this.module = beanDeploymentModules != null ? beanDeploymentModules.getModule(beanManager) : null;
}
private HttpSessionDestructionContext getSessionDestructionContext() {
if (sessionDestructionContextCache == null) {
this.sessionDestructionContextCache = beanManager.instance().select(HttpSessionDestructionContext.class).get();
}
return sessionDestructionContextCache;
}
private HttpSessionContext getSessionContext() {
if (sessionContextCache == null) {
this.sessionContextCache = beanManager.instance().select(HttpSessionContext.class).get();
}
return sessionContextCache;
}
public HttpRequestContext getRequestContext() {
if (requestContextCache == null) {
this.requestContextCache = beanManager.instance().select(HttpRequestContext.class).get();
}
return requestContextCache;
}
public void contextInitialized(ServletContext ctx) {
servletContextService.contextInitialized(ctx);
fireEventForApplicationScope(ctx, InitializedLiteral.APPLICATION);
}
public void contextDestroyed(ServletContext ctx) {
fireEventForApplicationScope(ctx, DestroyedLiteral.APPLICATION);
}
private void fireEventForApplicationScope(ServletContext ctx, Annotation qualifier) {
if (module != null) {
// Deliver events sequentially
synchronized (container) {
if (module.isWebModule()) {
module.fireEvent(ServletContext.class, ctx, qualifier);
} else {
// fallback for backward compatibility
final EventMetadata metadata = new EventMetadataImpl(ServletContext.class, null, Collections.singleton(qualifier));
beanManager.getAccessibleLenientObserverNotifier().fireEvent(ServletContext.class, ctx, metadata, qualifier);
}
}
}
}
public void sessionCreated(HttpSession session) {
SessionHolder.sessionCreated(session);
conversationContextActivator.sessionCreated(session);
sessionInitializedEvent.fire(session);
}
public void sessionDestroyed(HttpSession session) {
// Mark the session context and conversation contexts to destroy
// instances when appropriate
deactivateSessionDestructionContext(session);
boolean destroyed = getSessionContext().destroy(session);
SessionHolder.clear();
RequestScopedCache.endRequest();
if (destroyed) {
// we are outside of a request (the session timed out) and therefore the session was destroyed immediately
// we can fire the @Destroyed(SessionScoped.class) event immediately
sessionDestroyedEvent.fire(session);
} else {
// the old session won't be available at the time we destroy this request
// let's store its reference until then
if (getRequestContext() instanceof HttpRequestContextImpl) {
HttpServletRequest request = Reflections. cast(getRequestContext()).getHttpServletRequest();
request.setAttribute(HTTP_SESSION, session);
}
}
}
private void deactivateSessionDestructionContext(HttpSession session) {
HttpSessionDestructionContext context = getSessionDestructionContext();
if (context.isActive()) {
context.deactivate();
context.dissociate(session);
}
}
public void requestInitialized(HttpServletRequest request, ServletContext ctx) {
if (nestedInvocationGuardEnabled) {
Counter counter = nestedInvocationGuard.get();
Object marker = request.getAttribute(GUARD_PARAMETER_NAME);
if (counter != null && marker != null) {
// this is a nested invocation, increment the counter and ignore this invocation
counter.value++;
return;
} else {
if (counter != null && marker == null) {
/*
* This request has not been processed yet but the guard is set already. That indicates, that the guard leaked from a previous request
* processing - most likely the Servlet container did not invoke listener methods symmetrically. Log a warning and recover by
* re-initializing the guard
*/
ServletLogger.LOG.guardLeak(counter.value);
}
// this is the initial (outer) invocation
nestedInvocationGuard.set(new Counter());
request.setAttribute(GUARD_PARAMETER_NAME, GUARD_PARAMETER_VALUE);
}
}
if (ignoreForwards && isForwardedRequest(request)) {
return;
}
if (ignoreIncludes && isIncludedRequest(request)) {
return;
}
if (!contextActivationFilter.accepts(request)) {
return;
}
ServletLogger.LOG.requestInitialized(request);
SessionHolder.requestInitialized(request);
getRequestContext().associate(request);
getSessionContext().associate(request);
if (conversationActivationEnabled) {
conversationContextActivator.associateConversationContext(request);
}
getRequestContext().activate();
getSessionContext().activate();
try {
if (conversationActivationEnabled) {
conversationContextActivator.activateConversationContext(request);
}
requestInitializedEvent.fire(request);
} catch (RuntimeException e) {
try {
requestDestroyed(request);
} catch (Exception ignored) {
// ignored in order to let the original exception be thrown
}
/*
* If the servlet container happens to call the destroyed callback again, ignore it.
*/
request.setAttribute(REQUEST_DESTROYED, Boolean.TRUE);
throw e;
}
}
public void requestDestroyed(HttpServletRequest request) {
if (isRequestDestroyed(request)) {
return;
}
if (nestedInvocationGuardEnabled) {
Counter counter = nestedInvocationGuard.get();
if (counter != null) {
counter.value--;
if (counter.value > 0) {
return; // this is a nested invocation, ignore it
} else {
nestedInvocationGuard.remove(); // this is the outer invocation
request.removeAttribute(GUARD_PARAMETER_NAME);
}
} else {
ServletLogger.LOG.guardNotSet();
return;
}
}
if (ignoreForwards && isForwardedRequest(request)) {
return;
}
if (ignoreIncludes && isIncludedRequest(request)) {
return;
}
if (!contextActivationFilter.accepts(request)) {
return;
}
ServletLogger.LOG.requestDestroyed(request);
try {
conversationContextActivator.deactivateConversationContext(request);
/*
* If this request has been switched to async then do not invalidate the context now as it will be invalidated at the end of the async operation.
*/
if (servletApi.isAsyncSupported() && servletApi.isAsyncStarted(request)) {
// Note that we can't use isAsyncStarted() because it may return false after dispatch
request.setAttribute(ASYNC_STARTED_ATTR_NAME, true);
} else {
getRequestContext().invalidate();
}
safelyDeactivate(getRequestContext(), request);
// fire @Destroyed(RequestScoped.class)
requestDestroyedEvent.fire(request);
safelyDeactivate(getSessionContext(), request);
// fire @Destroyed(SessionScoped.class)
Object destroyedHttpSession = request.getAttribute(HTTP_SESSION);
if (destroyedHttpSession != null) {
sessionDestroyedEvent.fire((HttpSession) destroyedHttpSession);
}
} finally {
safelyDissociate(getRequestContext(), request);
// WFLY-1533 Underlying HTTP session may be invalid
safelyDissociate(getSessionContext(), request);
// Catch block is inside the activator method so that we're able to log the context
conversationContextActivator.disassociateConversationContext(request);
SessionHolder.clear();
}
}
public boolean isConversationActivationSet() {
return conversationActivationEnabled != null;
}
public void setConversationActivationEnabled(boolean conversationActivationEnabled) {
this.conversationActivationEnabled = conversationActivationEnabled;
}
@Override
public void cleanup() {
}
/**
* Some Servlet containers fire HttpServletListeners for include requests (inner requests caused by calling the include method of RequestDispatcher). This
* causes problems with context shut down as context manipulation is not reentrant. This method detects if this request is an included request or not.
*/
private boolean isIncludedRequest(HttpServletRequest request) {
return request.getAttribute(INCLUDE_HEADER) != null;
}
/**
* Some Servlet containers fire HttpServletListeners for forward requests (inner requests caused by calling the forward method of RequestDispatcher). This
* causes problems with context shut down as context manipulation is not reentrant. This method detects if this request is an forwarded request or not.
*/
private boolean isForwardedRequest(HttpServletRequest request) {
return request.getAttribute(FORWARD_HEADER) != null;
}
/**
* The way servlet containers react to an exception that occurs in a {@link ServletRequestListener} differs among servlet listeners. In certain containers
* the destroyed callback may be invoked multiple times, causing the latter invocations to fail as thread locals have already been unset. We use the
* {@link #REQUEST_DESTROYED} flag to indicate that all further invocations of the
* {@link ServletRequestListener#requestDestroyed(javax.servlet.ServletRequestEvent)} should be ignored by Weld.
*/
private boolean isRequestDestroyed(HttpServletRequest request) {
return request.getAttribute(REQUEST_DESTROYED) != null;
}
private void safelyDissociate(BoundContext context, T storage) {
try {
context.dissociate(storage);
} catch (Exception e) {
ServletLogger.LOG.unableToDissociateContext(context, storage);
ServletLogger.LOG.catchingDebug(e);
}
}
private void safelyDeactivate(ManagedContext context, HttpServletRequest request) {
try {
context.deactivate();
} catch (Exception e) {
ServletLogger.LOG.unableToDeactivateContext(context, request);
ServletLogger.LOG.catchingDebug(e);
}
}
}