/*
 * 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 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 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 request scope context was suspended and retrieved which also informs requestScope that it should not automatically release the instance once the running task is finished. The 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 requestScopeContext must be manually released. Not releasing the instance could cause memory leaks. Please note that calling suspendCurrent does not retrieve an immutable snapshot of the current request scope but a live reference to the internal 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, Miroslav Fuksa
/** * Scopes a single request/response processing execution on a single thread. * <p> * 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. * </p> * <p> * Example: * </p> * <pre> * &#064;Inject * RequestScope requestScope; * * ... * * requestScope.runInScope(new Runnable() { * &#064;Override * public void run() { * System.out.println("This is executed in the request scope..."); * } * }); * </pre> * <p> * 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: * </p> * <pre> * RequestContext requestScopeContext = * requestScope.runInScope(new Callable&lt;Instance&gt;() { * &#064;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() { * * &#064;Override * public void run() { * // This is executed in the same request scope as code above. * } * }); * * // The scope context must be explicitly released. * requestScopeContext.release(); * </pre> * <p> * 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. * </p> * * @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.
/** * A thread local copy of the current scope context. */
private final ThreadLocal<RequestContext> 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 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 #runInScope(RequestContext, ...) methods.

Note that the returned context must be released manually once not needed anymore to prevent memory leaks.

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 Also:
Returns:currently active request scope context.
/** * 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. * <p> * 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. * </p> * <p> * Note that the returned context must be {@link RequestContext#release() * released} manually once not needed anymore to prevent memory leaks. * </p> * * @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 RequestContext which has to be active on the given thread.
Returns:current active request context.
/** * 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 request scope context and mark it as suspended. This call prevents automatic 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 #runInScope(RequestContext, ...) methods.

Note that the returned context must be released manually once not needed anymore to prevent memory leaks.

See Also:
Returns:currently active request scope context that was suspended or null if the thread is not currently running in an active request scope.
/** * 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. * <p> * 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. * </p> * <p> * Note that the returned context must be {@link RequestContext#release() * released} manually once not needed anymore to prevent memory leaks. * </p> * * @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.
Params:
  • context – current request context to be suspended.
/** * 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 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();
Returns:New suspended request scope 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: * <pre> * RequestContext context = requestScope.createContext(); * requestScope.runInScope(context, someRunnableTask); * context.release(); * </pre> * * @return New suspended request scope context. */
public abstract RequestContext createContext();
Stores the provided RequestContext to thread-local variable belonging to current request scope.
Params:
  • context – storage with request scoped objects.
/** * 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 RequestContext to thread-local variable belonging to current request scope.
Params:
  • context – storage with request scoped objects.
/** * 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 RequestContext to thread-local variable belonging to current request scope.
Params:
  • context – storage with request scoped objects.
/** * 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 task in the request scope initialized from the scope context. The 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 scope instance. At the end of the method the request scope is returned to its original state.
Params:
  • context – The request scope context from which the request scope will be initialized.
  • task – Task to be executed.
/** * 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 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 scope context. At the end of the method the request scope is returned to its original state. The newly created scope context will be implicitly released at the end of the method call except the task will call suspendCurrent.
Params:
  • task – Task to be executed.
/** * 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 task in the request scope initialized from the scope context. The 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 scope instance. At the end of the method the request scope is returned to its original state.
Params:
  • context – The request scope context from which the request scope will be initialized.
  • task – Task to be executed.
Type parameters:
  • <T> – task result type.
Throws:
Returns:result returned by the task.
/** * 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 <T> {@code task} result type. * @return result returned by the {@code task}. * @throws Exception Exception thrown by the {@code task}. */
public <T> T runInScope(RequestContext context, Callable<T> task) throws Exception { final RequestContext oldContext = retrieveCurrent(); try { activate(context.getReference(), oldContext); return Errors.process(task); } finally { release(context); resume(oldContext); } }
Runs the 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 scope context. At the end of the method the request scope is returned to its original state. The newly created scope context will be implicitly released at the end of the method call except the task will call suspendCurrent.
Params:
  • task – Task to be executed.
Type parameters:
  • <T> – task result type.
Throws:
Returns:result returned by the task.
/** * 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 <T> {@code task} result type. * @return result returned by the {@code task}. * @throws Exception Exception thrown by the {@code task}. */
public <T> T runInScope(Callable<T> 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 task in the request scope initialized from the scope context. The 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 scope context. At the end of the method the request scope is returned to its original state.
Params:
  • context – The request scope context from which the request scope will be initialized.
  • task – Task to be executed.
Type parameters:
  • <T> – task result type.
Returns:result returned by the task
/** * 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 <T> {@code task} result type. * @return result returned by the {@code task} */
public <T> T runInScope(RequestContext context, Producer<T> task) { final RequestContext oldContext = retrieveCurrent(); try { activate(context.getReference(), oldContext); return Errors.process(task); } finally { release(context); resume(oldContext); } }
Runs the 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 scope instance. At the end of the method the request scope is returned to its original state. The newly created scope context will be implicitly released at the end of the method call except the task will call suspendCurrent.
Params:
  • task – Task to be executed.
Type parameters:
  • <T> – task result type.
Returns:result returned by the task.
/** * 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 <T> {@code task} result type. * @return result returned by the {@code task}. */
public <T> T runInScope(Producer<T> 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 RequestScope instance int InjectionManager and BootstrapBag.
Author:Petr Bouda
/** * 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); } } }