Add a class for propagating request scoping to different threads
Request scopes are all implemented with ThreadLocals, which meant that RequestScoped data would not be available in any new threads created from the main request thread. Add a class to wrap Runnables and Callables so tasks that depend on request scoped objects can be inserted in a WorkQueue. Include ScopePropagator implementations for all request scope types. The GuiceRequestScopePropagator will forward materialized instances of CurrentUser, RemotePeer SocketAddress, and the CannonicalWebUrl. To support this, CanonicalWebUrlModule is not bound as a SINGLETON anymore and HttpIdentifiedUserProvider implementation now relies on CurrentUser, instead of the WebSession. This was needed because some fields in the HttpRequest object are cleared after the request is finished, but possibly before the propagated request context has been processed. The non guice request scopes do not have this problem, so they can reconstruct the needed objects in the propagated context. Change-Id: I586cd1c91727e2cb8abb166f23fc504e9949a944
This commit is contained in:

committed by
Colby Ranger

parent
2e66220190
commit
3e7ef3cc5f
@@ -0,0 +1,84 @@
|
||||
// Copyright (C) 2012 The Android Open Source Project
|
||||
//
|
||||
// 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 com.google.gerrit.server.util;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gerrit.server.CurrentUser;
|
||||
import com.google.gerrit.server.RemotePeer;
|
||||
import com.google.gerrit.server.config.CanonicalWebUrl;
|
||||
import com.google.inject.Inject;
|
||||
import com.google.inject.Key;
|
||||
import com.google.inject.Provider;
|
||||
import com.google.inject.servlet.ServletScopes;
|
||||
import com.google.inject.util.Providers;
|
||||
import com.google.inject.util.Types;
|
||||
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.net.SocketAddress;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.Callable;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
/** Propagator for Guice's built-in servlet scope. */
|
||||
public class GuiceRequestScopePropagator extends RequestScopePropagator {
|
||||
|
||||
private final Provider<String> urlProvider;
|
||||
private final Provider<SocketAddress> remotePeerProvider;
|
||||
private final Provider<CurrentUser> currentUserProvider;
|
||||
|
||||
@Inject
|
||||
GuiceRequestScopePropagator(
|
||||
@CanonicalWebUrl @Nullable Provider<String> urlProvider,
|
||||
@RemotePeer Provider<SocketAddress> remotePeerProvider,
|
||||
Provider<CurrentUser> currentUserProvider) {
|
||||
super(ServletScopes.REQUEST);
|
||||
this.urlProvider = urlProvider;
|
||||
this.remotePeerProvider = remotePeerProvider;
|
||||
this.currentUserProvider = currentUserProvider;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see RequestScopePropagator#wrap(Callable)
|
||||
*/
|
||||
@Override
|
||||
protected <T> Callable<T> wrapImpl(Callable<T> callable) {
|
||||
Map<Key<?>, Object> seedMap = Maps.newHashMap();
|
||||
|
||||
// Request scopes appear to use specific keys in their map, instead of only
|
||||
// providers. Add bindings for both the key to the instance directly and the
|
||||
// provider to the instance to be safe.
|
||||
String url = urlProvider.get();
|
||||
seedMap.put(Key.get(typeOfProvider(String.class), CanonicalWebUrl.class),
|
||||
Providers.of(url));
|
||||
seedMap.put(Key.get(String.class, CanonicalWebUrl.class), url);
|
||||
|
||||
SocketAddress peer = remotePeerProvider.get();
|
||||
seedMap.put(Key.get(typeOfProvider(SocketAddress.class), RemotePeer.class),
|
||||
Providers.of(peer));
|
||||
seedMap.put(Key.get(SocketAddress.class, RemotePeer.class), peer);
|
||||
|
||||
CurrentUser user = currentUserProvider.get();
|
||||
seedMap.put(Key.get(typeOfProvider(CurrentUser.class)), Providers.of(user));
|
||||
seedMap.put(Key.get(CurrentUser.class), user);
|
||||
|
||||
return ServletScopes.continueRequest(callable, seedMap);
|
||||
}
|
||||
|
||||
private ParameterizedType typeOfProvider(Type type) {
|
||||
return Types.newParameterizedType(Provider.class, type);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user