Line data Source code
1 : // Copyright (C) 2012 The Android Open Source Project 2 : // 3 : // Licensed under the Apache License, Version 2.0 (the "License"); 4 : // you may not use this file except in compliance with the License. 5 : // You may obtain a copy of the License at 6 : // 7 : // http://www.apache.org/licenses/LICENSE-2.0 8 : // 9 : // Unless required by applicable law or agreed to in writing, software 10 : // distributed under the License is distributed on an "AS IS" BASIS, 11 : // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 : // See the License for the specific language governing permissions and 13 : // limitations under the License. 14 : 15 : package com.google.gerrit.server.util; 16 : 17 : import com.google.inject.OutOfScopeException; 18 : import com.google.inject.Scope; 19 : import java.util.concurrent.Callable; 20 : 21 : /** 22 : * {@link RequestScopePropagator} implementation for request scopes based on a {@link ThreadLocal} 23 : * context. 24 : * 25 : * @param <C> "context" type stored in the {@link ThreadLocal}. 26 : */ 27 : public abstract class ThreadLocalRequestScopePropagator<C> extends RequestScopePropagator { 28 : 29 : private final ThreadLocal<C> threadLocal; 30 : 31 : protected ThreadLocalRequestScopePropagator( 32 : Scope scope, ThreadLocal<C> threadLocal, ThreadLocalRequestContext local) { 33 92 : super(scope, local); 34 92 : this.threadLocal = threadLocal; 35 92 : } 36 : 37 : /** @see RequestScopePropagator#wrap(Callable) */ 38 : @Override 39 : protected final <T> Callable<T> wrapImpl(Callable<T> callable) { 40 91 : C ctx = continuingContext(requireContext()); 41 91 : return () -> { 42 91 : C old = threadLocal.get(); 43 91 : threadLocal.set(ctx); 44 : try { 45 91 : return callable.call(); 46 : } finally { 47 91 : if (old != null) { 48 0 : threadLocal.set(old); 49 : } else { 50 91 : threadLocal.remove(); 51 : } 52 : } 53 : }; 54 : } 55 : 56 : private C requireContext() { 57 91 : C context = threadLocal.get(); 58 91 : if (context == null) { 59 0 : throw new OutOfScopeException("Cannot access scoped object"); 60 : } 61 91 : return context; 62 : } 63 : 64 : /** 65 : * Returns a new context object based on the passed in context that has no request scoped objects 66 : * initialized. 67 : * 68 : * <p>Note that some code paths expect request-scoped objects like {@code CurrentUser} to be 69 : * constructible starting from just the context object returned by this method. For example, in 70 : * the SSH scope, the context includes the {@code SshSession}, which is used by {@code 71 : * SshCurrentUserProvider} to construct a new {@code CurrentUser} in the new thread. 72 : * 73 : * @param ctx the context to continue. 74 : * @return a new context. 75 : */ 76 : protected abstract C continuingContext(C ctx); 77 : }