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

org.glassfish.jersey.process.internal.RequestScope Maven / Gradle / Ivy

/*
 * Copyright (c) 2010, 2019 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package org.glassfish.jersey.process.internal;

import java.util.concurrent.Callable;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.glassfish.jersey.internal.BootstrapBag;
import org.glassfish.jersey.internal.BootstrapConfigurator;
import org.glassfish.jersey.internal.Errors;
import org.glassfish.jersey.internal.inject.InjectionManager;
import org.glassfish.jersey.internal.util.ExtendedLogger;
import org.glassfish.jersey.internal.util.Producer;

import static org.glassfish.jersey.internal.guava.Preconditions.checkState;

/**
 * Scopes a single request/response processing execution on a single thread.
 * 

* To execute a code inside of the request scope use one of the {@code runInScope(...)} * methods and supply the task encapsulating the code that should be executed in the scope. *

*

* Example: *

*
 * @Inject
 * RequestScope requestScope;
 *
 * ...
 *
 * requestScope.runInScope(new Runnable() {
 *     @Override
 *     public void run() {
 *          System.out.println("This is executed in the request scope...");
 *     }
 * });
 * 
*

* An instance of the request scope can be suspended and retrieved via a call to * {@link RequestScope#suspendCurrent} method. This instance can be later * used to resume the same request scope and run another task in the same scope: *

*
 *  RequestContext requestScopeContext =
 *      requestScope.runInScope(new Callable<Instance>() {
 *          @Override
 *          public RequestContext call() {
 *              // This is executed in the new request scope.
 *
 *              // The following call will cause that the
 *              // RequestContext will not be released
 *              // automatically and we will have to release
 *              // it explicitly at the end.
 *              return requestScope.suspendCurrent();
 *          }
 *      });
 *
 *  requestScope.runInScope(requestScopeContext, new Runnable() {
 *
 *      @Override
 *      public void run() {
 *          // This is executed in the same request scope as code above.
 *      }
 *  });
 *
 *  // The scope context must be explicitly released.
 *  requestScopeContext.release();
 * 
*

* In the previous example the {@link RequestContext request scope context} * was suspended and retrieved which also informs {@code requestScope} that it * should not automatically release the instance once the running task is finished. * The {@code requestScopeContext} is then used to initialize the next * request-scoped execution. The second task will run in the same request scope as the * first task. At the end the suspended {@code requestScopeContext} must be * manually {@link RequestContext#release released}. Not releasing the instance * could cause memory leaks. Please note that calling {@link RequestScope#suspendCurrent} * does not retrieve an immutable snapshot of the current request scope but * a live reference to the internal {@link RequestContext request scope context} * which may change it's state during each request-scoped task execution for * which this scope context is used. *

* * @author Marek Potociar * @author Miroslav Fuksa */ public abstract class RequestScope { private static final ExtendedLogger logger = new ExtendedLogger(Logger.getLogger(RequestScope.class.getName()), Level.FINEST); /** * A thread local copy of the current scope context. */ private final ThreadLocal currentRequestContext = new ThreadLocal<>(); private volatile boolean isActive = true; public boolean isActive() { return isActive; } public void shutdown() { isActive = false; } /** * Get a new reference for to currently running request scope context. This call * prevents automatic {@link RequestContext#release() release} of the scope * context once the task that runs in the scope has finished. *

* The returned scope context may be used to run additional task(s) in the * same request scope using one of the {@code #runInScope(RequestContext, ...)} methods. *

*

* Note that the returned context must be {@link RequestContext#release() * released} manually once not needed anymore to prevent memory leaks. *

* * @return currently active {@link RequestContext request scope context}. * @throws IllegalStateException in case there is no active request scope associated * with the current thread or if the request scope has * been already shut down. * @see #suspendCurrent() */ public RequestContext referenceCurrent() throws IllegalStateException { return current().getReference(); } /** * Returns the current {@link RequestContext} which has to be active on the given thread. * * @return current active request context. */ public RequestContext current() { checkState(isActive, "Request scope has been already shut down."); final RequestContext scopeInstance = currentRequestContext.get(); checkState(scopeInstance != null, "Not inside a request scope."); return scopeInstance; } private RequestContext retrieveCurrent() { checkState(isActive, "Request scope has been already shut down."); return currentRequestContext.get(); } /** * Get the current {@link RequestContext request scope context} * and mark it as suspended. This call prevents automatic * {@link RequestContext#release() release} of the scope context * once the task that runs in the scope has finished. *

* The returned scope context may be used to run additional task(s) in the * same request scope using one of the {@code #runInScope(RequestContext, ...)} * methods. *

*

* Note that the returned context must be {@link RequestContext#release() * released} manually once not needed anymore to prevent memory leaks. *

* * @return currently active {@link RequestContext request scope context} * that was suspended or {@code null} if the thread is not currently running * in an active request scope. * @see #referenceCurrent() */ public RequestContext suspendCurrent() { final RequestContext context = retrieveCurrent(); if (context == null) { return null; } try { RequestContext referencedContext = context.getReference(); suspend(referencedContext); return referencedContext; } finally { logger.debugLog("Returned a new reference of the request scope context {0}", context); } } /** * Executes the action when the request scope comes into suspended state. For example, implementation can call deactivation * of the underlying request scope storage. * * @param context current request context to be suspended. */ protected void suspend(RequestContext context) { } /** * Creates a new instance of the {@link RequestContext request scope context}. * This instance can be then used to run task in the request scope. Returned context * is suspended by default and must therefore be closed explicitly as it is shown in * the following example: *
     * RequestContext context = requestScope.createContext();
     * requestScope.runInScope(context, someRunnableTask);
     * context.release();
     * 
* * @return New suspended request scope context. */ public abstract RequestContext createContext(); /** * Stores the provided {@link RequestContext} to thread-local variable belonging to current request scope. * * @param context storage with request scoped objects. */ protected void activate(RequestContext context, RequestContext oldContext) { checkState(isActive, "Request scope has been already shut down."); currentRequestContext.set(context); } /** * Resumes the provided {@link RequestContext} to thread-local variable belonging to current request scope. * * @param context storage with request scoped objects. */ protected void resume(RequestContext context) { currentRequestContext.set(context); } /** * Releases the provided {@link RequestContext} to thread-local variable belonging to current request scope. * * @param context storage with request scoped objects. */ protected void release(RequestContext context) { context.release(); } /** * Runs the {@link Runnable task} in the request scope initialized from the * {@link RequestContext scope context}. The {@link RequestContext * scope context} is NOT released by the method (this must be done explicitly). The * current thread might be already in any request scope and in that case the scope * will be changed to the scope defined by the {@link RequestContext scope * instance}. At the end of the method the request scope is returned to its original * state. * * @param context The request scope context from which the request scope will be initialized. * @param task Task to be executed. */ public void runInScope(RequestContext context, Runnable task) { final RequestContext oldContext = retrieveCurrent(); try { activate(context.getReference(), oldContext); Errors.process(task); } finally { release(context); resume(oldContext); } } /** * Runs the {@link Runnable task} in the new request scope. The current thread might * be already in any request scope and in that case the scope will be changed to the * scope defined by the {@link RequestContext scope context}. At the end of * the method the request scope is returned to its original state. The newly created * {@link RequestContext scope context} will be implicitly released at the end * of the method call except the task will call * {@link RequestScope#suspendCurrent}. * * @param task Task to be executed. */ public void runInScope(Runnable task) { final RequestContext oldContext = retrieveCurrent(); final RequestContext context = createContext(); try { activate(context, oldContext); Errors.process(task); } finally { release(context); resume(oldContext); } } /** * Runs the {@link Callable task} in the request scope initialized from the * {@link RequestContext scope context}. The {@link RequestContext * scope context} is NOT released by the method (this must be done explicitly). The * current thread might be already in any request scope and in that case the scope * will be changed to the scope defined by the {@link RequestContext scope * instance}. At the end of the method the request scope is returned to its original * state. * * @param context The request scope context from which the request scope will be initialized. * @param task Task to be executed. * @param {@code task} result type. * @return result returned by the {@code task}. * @throws Exception Exception thrown by the {@code task}. */ public T runInScope(RequestContext context, Callable task) throws Exception { final RequestContext oldContext = retrieveCurrent(); try { activate(context.getReference(), oldContext); return Errors.process(task); } finally { release(context); resume(oldContext); } } /** * Runs the {@link Callable task} in the new request scope. The current thread might * be already in any request scope and in that case the scope will be changed to the * scope defined by the {@link RequestContext scope context}. At the end of * the method the request scope is returned to its original state. The newly created * {@link RequestContext scope context} will be implicitly released at the end * of the method call except the task will call * {@link RequestScope#suspendCurrent}. * * @param task Task to be executed. * @param {@code task} result type. * @return result returned by the {@code task}. * @throws Exception Exception thrown by the {@code task}. */ public T runInScope(Callable task) throws Exception { final RequestContext oldContext = retrieveCurrent(); final RequestContext context = createContext(); try { activate(context, oldContext); return Errors.process(task); } finally { release(context); resume(oldContext); } } /** * Runs the {@link org.glassfish.jersey.internal.util.Producer task} in the request scope initialized * from the {@link RequestContext scope context}. * The {@link RequestContext scope context} is NOT released by the method (this * must be done explicitly). The current thread might be already in any request scope * and in that case the scope will be changed to the scope defined by the * {@link RequestContext scope context}. At the end of the method the request * scope is returned to its original state. * * @param context The request scope context from which the request scope will be initialized. * @param task Task to be executed. * @param {@code task} result type. * @return result returned by the {@code task} */ public T runInScope(RequestContext context, Producer task) { final RequestContext oldContext = retrieveCurrent(); try { activate(context.getReference(), oldContext); return Errors.process(task); } finally { release(context); resume(oldContext); } } /** * Runs the {@link org.glassfish.jersey.internal.util.Producer task} in the new request scope. The * current thread might be already in any request scope and in that case the scope * will be changed to the scope defined by the {@link RequestContext scope * instance}. At the end of the method the request scope is returned to its original * state. The newly created {@link RequestContext scope context} will be * implicitly released at the end of the method call except the task will call * {@link RequestScope#suspendCurrent}. * * @param task Task to be executed. * @param {@code task} result type. * @return result returned by the {@code task}. */ public T runInScope(Producer task) { final RequestContext oldContext = retrieveCurrent(); final RequestContext context = createContext(); try { activate(context, oldContext); return Errors.process(task); } finally { release(context); resume(oldContext); } } /** * Configurator which initializes and register {@link RequestScope} instance int {@link InjectionManager} and * {@link BootstrapBag}. * * @author Petr Bouda */ public static class RequestScopeConfigurator implements BootstrapConfigurator { @Override public void init(InjectionManager injectionManagerFactory, BootstrapBag bootstrapBag) { } @Override public void postInit(InjectionManager injectionManager, BootstrapBag bootstrapBag) { RequestScope requestScope = injectionManager.getInstance(RequestScope.class); bootstrapBag.setRequestScope(requestScope); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy