Update the ThreadLocal based scopes to use RequestContext.

Bound the ThreadLocalRequestContext module, which makes the CurrentUser
available in the Global module. Removed any binding in the scopes that
provided the CurrentUser. Updated all of the scopes to propagate the
RequestContext. The PerThreadRequestScope.Propagator allows scoping
callables to enter a request context.

Change-Id: Idf682ed1d7485cf8c9cdd22cd89bfe1ad5296880
This commit is contained in:
Colby Ranger
2012-05-09 10:39:48 -07:00
parent b3a402124f
commit cfd994548e
20 changed files with 222 additions and 258 deletions

View File

@@ -122,7 +122,7 @@ class CommandFactoryProvider implements Provider<CommandFactory> {
public void setSession(final ServerSession session) {
final SshSession s = session.getAttribute(SshSession.KEY);
this.ctx = new Context(s, commandLine);
this.ctx = sshScope.newContext(s, commandLine);
}
public void start(final Environment env) throws IOException {

View File

@@ -173,7 +173,7 @@ class DatabasePubKeyAuth implements PublickeyAuthenticator {
// session, record a login event in the log and add
// a close listener to record a logout event.
//
Context ctx = new Context(sd, null);
Context ctx = sshScope.newContext(sd, null);
Context old = sshScope.set(ctx);
try {
sshLog.onLogin();
@@ -185,7 +185,7 @@ class DatabasePubKeyAuth implements PublickeyAuthenticator {
new IoFutureListener<IoFuture>() {
@Override
public void operationComplete(IoFuture future) {
final Context ctx = new Context(sd, null);
final Context ctx = sshScope.newContext(sd, null);
final Context old = sshScope.set(ctx);
try {
sshLog.onLogout();

View File

@@ -89,7 +89,7 @@ class NoShell implements Factory<Command> {
}
public void setSession(final ServerSession session) {
this.context = new Context(session.getAttribute(SshSession.KEY), "");
this.context = sshScope.newContext(session.getAttribute(SshSession.KEY), "");
}
public void start(final Environment env) throws IOException {

View File

@@ -1,42 +0,0 @@
// Copyright (C) 2010 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.sshd;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.Singleton;
@Singleton
class SshCurrentUserProvider implements Provider<CurrentUser> {
private final Provider<SshSession> session;
private final Provider<IdentifiedUser> identifiedProvider;
@Inject
SshCurrentUserProvider(Provider<SshSession> s, Provider<IdentifiedUser> p) {
session = s;
identifiedProvider = p;
}
@Override
public CurrentUser get() {
final CurrentUser user = session.get().getCurrentUser();
if (user instanceof IdentifiedUser) {
return identifiedProvider.get();
}
return session.get().getCurrentUser();
}
}

View File

@@ -1,47 +0,0 @@
// Copyright (C) 2010 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.sshd;
import com.google.gerrit.common.errors.NotSignedInException;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.inject.Inject;
import com.google.inject.Provider;
import com.google.inject.ProvisionException;
import com.google.inject.Singleton;
@Singleton
class SshIdentifiedUserProvider implements Provider<IdentifiedUser> {
private final Provider<SshSession> session;
private final IdentifiedUser.RequestFactory factory;
@Inject
SshIdentifiedUserProvider(Provider<SshSession> s,
IdentifiedUser.RequestFactory f) {
session = s;
factory = f;
}
@Override
public IdentifiedUser get() {
final CurrentUser user = session.get().getCurrentUser();
if (user instanceof IdentifiedUser) {
return factory.create(user.getAccessPath(), //
((IdentifiedUser) user).getAccountId());
}
throw new ProvisionException(NotSignedInException.MESSAGE,
new NotSignedInException());
}
}

View File

@@ -152,11 +152,6 @@ public class SshModule extends FactoryModule {
bind(SocketAddress.class).annotatedWith(RemotePeer.class).toProvider(
SshRemotePeerProvider.class).in(SshScope.REQUEST);
bind(CurrentUser.class).toProvider(SshCurrentUserProvider.class).in(
SshScope.REQUEST);
bind(IdentifiedUser.class).toProvider(SshIdentifiedUserProvider.class).in(
SshScope.REQUEST);
bind(WorkQueue.Executor.class).annotatedWith(CommandExecutor.class)
.toProvider(CommandExecutorProvider.class).in(SshScope.REQUEST);

View File

@@ -14,8 +14,13 @@
package com.google.gerrit.sshd;
import com.google.gerrit.server.CurrentUser;
import com.google.gerrit.server.IdentifiedUser;
import com.google.gerrit.server.RequestCleanup;
import com.google.gerrit.server.util.RequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestContext;
import com.google.gerrit.server.util.ThreadLocalRequestScopePropagator;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.OutOfScopeException;
import com.google.inject.Provider;
@@ -26,10 +31,10 @@ import java.util.Map;
/** Guice scopes for state during an SSH connection. */
class SshScope {
static class Context {
private static final Key<RequestCleanup> RC_KEY =
Key.get(RequestCleanup.class);
private static final Key<RequestCleanup> RC_KEY =
Key.get(RequestCleanup.class);
class Context implements RequestContext {
private final RequestCleanup cleanup;
private final SshSession session;
private final String commandLine;
@@ -56,10 +61,6 @@ class SshScope {
finished = p.finished;
}
Context(final SshSession s, final String c) {
this(s, c, System.currentTimeMillis());
}
String getCommandLine() {
return commandLine;
}
@@ -68,6 +69,16 @@ class SshScope {
return session;
}
@Override
public CurrentUser getCurrentUser() {
final CurrentUser user = session.getCurrentUser();
if (user instanceof IdentifiedUser) {
return userFactory.create(user.getAccessPath(), //
((IdentifiedUser) user).getAccountId());
}
return user;
}
synchronized <T> T get(Key<T> key, Provider<T> creator) {
@SuppressWarnings("unchecked")
T t = (T) map.get(key);
@@ -100,15 +111,19 @@ class SshScope {
}
static class Propagator extends ThreadLocalRequestScopePropagator<Context> {
Propagator() {
super(REQUEST, current);
private final SshScope sshScope;
@Inject
Propagator(SshScope sshScope, ThreadLocalRequestContext local) {
super(REQUEST, current, local);
this.sshScope = sshScope;
}
@Override
protected Context continuingContext(Context ctx) {
// The cleanup is not chained, since the RequestScopePropagator executors
// the Context's cleanup when finished executing.
return new Context(ctx, ctx.getSession(), ctx.getCommandLine());
return sshScope.newContinuingContext(ctx);
}
}
@@ -123,9 +138,28 @@ class SshScope {
return ctx;
}
private final ThreadLocalRequestContext local;
private final IdentifiedUser.RequestFactory userFactory;
@Inject
SshScope(ThreadLocalRequestContext local,
IdentifiedUser.RequestFactory userFactory) {
this.local = local;
this.userFactory = userFactory;
}
Context newContext(SshSession session, String commandLine) {
return new Context(session, commandLine, System.currentTimeMillis());
}
private Context newContinuingContext(Context ctx) {
return new Context(ctx, ctx.getSession(), ctx.getCommandLine());
}
Context set(Context ctx) {
Context old = current.get();
current.set(ctx);
local.setContext(ctx);
return old;
}