
This is long overdue renaming step to manifest that SQL database is removed from gerrit core. Moreover, client/server package division was needed due to GWT UI that was removed as well in release 3.0. Bug: Issue 11678 Change-Id: Icfd83a309a6affac54141e7284e70f1255537dc4
189 lines
6.5 KiB
Java
189 lines
6.5 KiB
Java
// 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 static java.util.Objects.requireNonNull;
|
|
|
|
import com.google.common.base.Throwables;
|
|
import com.google.gerrit.entities.Project;
|
|
import com.google.gerrit.server.RequestCleanup;
|
|
import com.google.gerrit.server.git.ProjectRunnable;
|
|
import com.google.inject.Key;
|
|
import com.google.inject.Scope;
|
|
import com.google.inject.servlet.ServletScopes;
|
|
import java.util.concurrent.Callable;
|
|
import java.util.concurrent.Executors;
|
|
import java.util.concurrent.ScheduledThreadPoolExecutor;
|
|
|
|
/**
|
|
* Base class for propagating request-scoped data between threads.
|
|
*
|
|
* <p>Request scopes are typically linked to a {@link ThreadLocal}, which is only available to the
|
|
* current thread. In order to allow background work involving RequestScoped data, the ThreadLocal
|
|
* data must be copied from the request thread to the new background thread.
|
|
*
|
|
* <p>Every type of RequestScope must provide an implementation of RequestScopePropagator. See
|
|
* {@link #wrap(Callable)} for details on the implementation, usage, and restrictions.
|
|
*
|
|
* @see ThreadLocalRequestScopePropagator
|
|
*/
|
|
public abstract class RequestScopePropagator {
|
|
|
|
private final Scope scope;
|
|
private final ThreadLocalRequestContext local;
|
|
|
|
protected RequestScopePropagator(Scope scope, ThreadLocalRequestContext local) {
|
|
this.scope = scope;
|
|
this.local = local;
|
|
}
|
|
|
|
/**
|
|
* Ensures that the current request state is available when the passed in Callable is invoked.
|
|
*
|
|
* <p>If needed wraps the passed in Callable in a new {@link Callable} that propagates the current
|
|
* request state when the returned Callable is invoked. The method must be called in a request
|
|
* scope and the returned Callable may only be invoked in a thread that is not already in a
|
|
* request scope or is in the same request scope. The returned Callable will inherit toString()
|
|
* from the passed in Callable. A {@link ScheduledThreadPoolExecutor} does not accept a Callable,
|
|
* so there is no ProjectCallable implementation. Implementations of this method must be
|
|
* consistent with Guice's {@link ServletScopes#continueRequest(Callable, java.util.Map)}.
|
|
*
|
|
* <p>There are some limitations:
|
|
*
|
|
* <ul>
|
|
* <li>Derived objects (i.e. anything marked created in a request scope) will not be
|
|
* transported.
|
|
* <li>State changes to the request scoped context after this method is called will not be seen
|
|
* in the continued thread.
|
|
* </ul>
|
|
*
|
|
* @param callable the Callable to wrap.
|
|
* @return a new Callable which will execute in the current request scope.
|
|
*/
|
|
@SuppressWarnings("javadoc") // See GuiceRequestScopePropagator#wrapImpl
|
|
public final <T> Callable<T> wrap(Callable<T> callable) {
|
|
final RequestContext callerContext = requireNonNull(local.getContext());
|
|
final Callable<T> wrapped = wrapImpl(context(callerContext, cleanup(callable)));
|
|
return new Callable<T>() {
|
|
@Override
|
|
public T call() throws Exception {
|
|
if (callerContext == local.getContext()) {
|
|
return callable.call();
|
|
}
|
|
return wrapped.call();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return callable.toString();
|
|
}
|
|
};
|
|
}
|
|
|
|
/**
|
|
* Wraps runnable in a new {@link Runnable} that propagates the current request state when the
|
|
* runnable is invoked. The method must be called in a request scope and the returned Runnable may
|
|
* only be invoked in a thread that is not already in a request scope. The returned Runnable will
|
|
* inherit toString() from the passed in Runnable. Furthermore, if the passed runnable is of type
|
|
* {@link ProjectRunnable}, the returned runnable will be of the same type with the methods
|
|
* delegated.
|
|
*
|
|
* <p>See {@link #wrap(Callable)} for details on implementation and usage.
|
|
*
|
|
* @param runnable the Runnable to wrap.
|
|
* @return a new Runnable which will execute in the current request scope.
|
|
*/
|
|
public final Runnable wrap(Runnable runnable) {
|
|
final Callable<Object> wrapped = wrap(Executors.callable(runnable));
|
|
|
|
if (runnable instanceof ProjectRunnable) {
|
|
return new ProjectRunnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
wrapped.call();
|
|
} catch (Exception e) {
|
|
Throwables.throwIfUnchecked(e);
|
|
throw new RuntimeException(e); // Not possible.
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public Project.NameKey getProjectNameKey() {
|
|
return ((ProjectRunnable) runnable).getProjectNameKey();
|
|
}
|
|
|
|
@Override
|
|
public String getRemoteName() {
|
|
return ((ProjectRunnable) runnable).getRemoteName();
|
|
}
|
|
|
|
@Override
|
|
public boolean hasCustomizedPrint() {
|
|
return ((ProjectRunnable) runnable).hasCustomizedPrint();
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return runnable.toString();
|
|
}
|
|
};
|
|
}
|
|
return new Runnable() {
|
|
@Override
|
|
public void run() {
|
|
try {
|
|
wrapped.call();
|
|
} catch (RuntimeException e) {
|
|
throw e;
|
|
} catch (Exception e) {
|
|
throw new RuntimeException(e); // Not possible.
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public String toString() {
|
|
return runnable.toString();
|
|
}
|
|
};
|
|
}
|
|
|
|
/** @see #wrap(Callable) */
|
|
protected abstract <T> Callable<T> wrapImpl(Callable<T> callable);
|
|
|
|
protected <T> Callable<T> context(RequestContext context, Callable<T> callable) {
|
|
return () -> {
|
|
RequestContext old = local.setContext(context::getUser);
|
|
try {
|
|
return callable.call();
|
|
} finally {
|
|
local.setContext(old);
|
|
}
|
|
};
|
|
}
|
|
|
|
protected <T> Callable<T> cleanup(Callable<T> callable) {
|
|
return () -> {
|
|
RequestCleanup cleanup =
|
|
scope.scope(Key.get(RequestCleanup.class), RequestCleanup::new).get();
|
|
try {
|
|
return callable.call();
|
|
} finally {
|
|
cleanup.run();
|
|
}
|
|
};
|
|
}
|
|
}
|