This commit is contained in:
Sen 2025-07-12 16:48:23 +02:00
parent c126bdd8b0
commit 318a8885ba
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
53 changed files with 990 additions and 5887 deletions

View file

@ -1,392 +0,0 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 common.future;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
/**
* An abstract implementation of the {@link ListenableFuture} interface. This
* class is preferable to {@link java.util.concurrent.FutureTask} for two
* reasons: It implements {@code ListenableFuture}, and it does not implement
* {@code Runnable}. (If you want a {@code Runnable} implementation of {@code
* ListenableFuture}, create a {@link ListenableFutureTask}, or submit your
* tasks to a {@link ListeningExecutorService}.)
*
* <p>This class implements all methods in {@code ListenableFuture}.
* Subclasses should provide a way to set the result of the computation through
* the protected methods {@link #set(Object)} and
* {@link #setException(Throwable)}. Subclasses may also override {@link
* #interruptTask()}, which will be invoked automatically if a call to {@link
* #cancel(boolean) cancel(true)} succeeds in canceling the future.
*
* <p>{@code AbstractFuture} uses an {@link AbstractQueuedSynchronizer} to deal
* with concurrency issues and guarantee thread safety.
*
* <p>The state changing methods all return a boolean indicating success or
* failure in changing the future's state. Valid states are running,
* completed, failed, or cancelled.
*
* <p>This class uses an {@link ExecutionList} to guarantee that all registered
* listeners will be executed, either when the future finishes or, for listeners
* that are added after the future completes, immediately.
* {@code Runnable}-{@code Executor} pairs are stored in the execution list but
* are not necessarily executed in the order in which they were added. (If a
* listener is added after the Future is complete, it will be executed
* immediately, even if earlier listeners have not been executed. Additionally,
* executors need not guarantee FIFO execution, or different listeners may run
* in different executors.)
*
* @author Sven Mawson
* @since 1.0
*/
abstract class AbstractFuture<V> implements ListenableFuture<V> {
/** Synchronization control for AbstractFutures. */
private final Sync<V> sync = new Sync<V>();
// The execution list to hold our executors.
private final ExecutionList executionList = new ExecutionList();
/**
* Constructor for use by subclasses.
*/
protected AbstractFuture() {}
/*
* Improve the documentation of when InterruptedException is thrown. Our
* behavior matches the JDK's, but the JDK's documentation is misleading.
*/
/**
* {@inheritDoc}
*
* <p>The default {@link AbstractFuture} implementation throws {@code
* InterruptedException} if the current thread is interrupted before or during
* the call, even if the value is already available.
*
* @throws InterruptedException if the current thread was interrupted before
* or during the call (optional but recommended).
* @throws CancellationException {@inheritDoc}
*/
@Override
public V get(long timeout, TimeUnit unit) throws InterruptedException,
TimeoutException, ExecutionException {
return sync.get(unit.toNanos(timeout));
}
/*
* Improve the documentation of when InterruptedException is thrown. Our
* behavior matches the JDK's, but the JDK's documentation is misleading.
*/
/**
* {@inheritDoc}
*
* <p>The default {@link AbstractFuture} implementation throws {@code
* InterruptedException} if the current thread is interrupted before or during
* the call, even if the value is already available.
*
* @throws InterruptedException if the current thread was interrupted before
* or during the call (optional but recommended).
* @throws CancellationException {@inheritDoc}
*/
@Override
public V get() throws InterruptedException, ExecutionException {
return sync.get();
}
@Override
public boolean isDone() {
return sync.isDone();
}
@Override
public boolean isCancelled() {
return sync.isCancelled();
}
@Override
public boolean cancel(boolean mayInterruptIfRunning) {
if (!sync.cancel(mayInterruptIfRunning)) {
return false;
}
executionList.execute();
if (mayInterruptIfRunning) {
interruptTask();
}
return true;
}
/**
* Subclasses can override this method to implement interruption of the
* future's computation. The method is invoked automatically by a successful
* call to {@link #cancel(boolean) cancel(true)}.
*
* <p>The default implementation does nothing.
*
* @since 10.0
*/
protected void interruptTask() {
}
/**
* Returns true if this future was cancelled with {@code
* mayInterruptIfRunning} set to {@code true}.
*
* @since 14.0
*/
protected final boolean wasInterrupted() {
return sync.wasInterrupted();
}
/**
* {@inheritDoc}
*
* @since 10.0
*/
@Override
public void addListener(Runnable listener, Executor exec) {
executionList.add(listener, exec);
}
/**
* Subclasses should invoke this method to set the result of the computation
* to {@code value}. This will set the state of the future to
* {@link AbstractFuture.Sync#COMPLETED} and invoke the listeners if the
* state was successfully changed.
*
* @param value the value that was the result of the task.
* @return true if the state was successfully changed.
*/
protected boolean set(V value) {
boolean result = sync.set(value);
if (result) {
executionList.execute();
}
return result;
}
/**
* Subclasses should invoke this method to set the result of the computation
* to an error, {@code throwable}. This will set the state of the future to
* {@link AbstractFuture.Sync#COMPLETED} and invoke the listeners if the
* state was successfully changed.
*
* @param throwable the exception that the task failed with.
* @return true if the state was successfully changed.
*/
protected boolean setException(Throwable throwable) {
boolean result = sync.setException(throwable);
if (result) {
executionList.execute();
}
return result;
}
/**
* <p>Following the contract of {@link AbstractQueuedSynchronizer} we create a
* private subclass to hold the synchronizer. This synchronizer is used to
* implement the blocking and waiting calls as well as to handle state changes
* in a thread-safe manner. The current state of the future is held in the
* Sync state, and the lock is released whenever the state changes to
* {@link #COMPLETED}, {@link #CANCELLED}, or {@link #INTERRUPTED}
*
* <p>To avoid races between threads doing release and acquire, we transition
* to the final state in two steps. One thread will successfully CAS from
* RUNNING to COMPLETING, that thread will then set the result of the
* computation, and only then transition to COMPLETED, CANCELLED, or
* INTERRUPTED.
*
* <p>We don't use the integer argument passed between acquire methods so we
* pass around a -1 everywhere.
*/
static final class Sync<V> extends AbstractQueuedSynchronizer {
private static final long serialVersionUID = 0L;
/* Valid states. */
static final int RUNNING = 0;
static final int COMPLETING = 1;
static final int COMPLETED = 2;
static final int CANCELLED = 4;
static final int INTERRUPTED = 8;
private V value;
private Throwable exception;
/*
* Acquisition succeeds if the future is done, otherwise it fails.
*/
@Override
protected int tryAcquireShared(int ignored) {
if (isDone()) {
return 1;
}
return -1;
}
/*
* We always allow a release to go through, this means the state has been
* successfully changed and the result is available.
*/
@Override
protected boolean tryReleaseShared(int finalState) {
setState(finalState);
return true;
}
/**
* Blocks until the task is complete or the timeout expires. Throws a
* {@link TimeoutException} if the timer expires, otherwise behaves like
* {@link #get()}.
*/
V get(long nanos) throws TimeoutException, CancellationException,
ExecutionException, InterruptedException {
// Attempt to acquire the shared lock with a timeout.
if (!tryAcquireSharedNanos(-1, nanos)) {
throw new TimeoutException("Timeout waiting for task.");
}
return getValue();
}
/**
* Blocks until {@link #complete(Object, Throwable, int)} has been
* successfully called. Throws a {@link CancellationException} if the task
* was cancelled, or a {@link ExecutionException} if the task completed with
* an error.
*/
V get() throws CancellationException, ExecutionException,
InterruptedException {
// Acquire the shared lock allowing interruption.
acquireSharedInterruptibly(-1);
return getValue();
}
/**
* Implementation of the actual value retrieval. Will return the value
* on success, an exception on failure, a cancellation on cancellation, or
* an illegal state if the synchronizer is in an invalid state.
*/
private V getValue() throws CancellationException, ExecutionException {
int state = getState();
switch (state) {
case COMPLETED:
if (exception != null) {
throw new ExecutionException(exception);
} else {
return value;
}
case CANCELLED:
case INTERRUPTED:
throw cancellationExceptionWithCause(
"Task was cancelled.", exception);
default:
throw new IllegalStateException(
"Error, synchronizer in invalid state: " + state);
}
}
/**
* Checks if the state is {@link #COMPLETED}, {@link #CANCELLED}, or {@link
* INTERRUPTED}.
*/
boolean isDone() {
return (getState() & (COMPLETED | CANCELLED | INTERRUPTED)) != 0;
}
/**
* Checks if the state is {@link #CANCELLED} or {@link #INTERRUPTED}.
*/
boolean isCancelled() {
return (getState() & (CANCELLED | INTERRUPTED)) != 0;
}
/**
* Checks if the state is {@link #INTERRUPTED}.
*/
boolean wasInterrupted() {
return getState() == INTERRUPTED;
}
/**
* Transition to the COMPLETED state and set the value.
*/
boolean set(V v) {
return complete(v, null, COMPLETED);
}
/**
* Transition to the COMPLETED state and set the exception.
*/
boolean setException(Throwable t) {
return complete(null, t, COMPLETED);
}
/**
* Transition to the CANCELLED or INTERRUPTED state.
*/
boolean cancel(boolean interrupt) {
return complete(null, null, interrupt ? INTERRUPTED : CANCELLED);
}
/**
* Implementation of completing a task. Either {@code v} or {@code t} will
* be set but not both. The {@code finalState} is the state to change to
* from {@link #RUNNING}. If the state is not in the RUNNING state we
* return {@code false} after waiting for the state to be set to a valid
* final state ({@link #COMPLETED}, {@link #CANCELLED}, or {@link
* #INTERRUPTED}).
*
* @param v the value to set as the result of the computation.
* @param t the exception to set as the result of the computation.
* @param finalState the state to transition to.
*/
private boolean complete(V v, Throwable t,
int finalState) {
boolean doCompletion = compareAndSetState(RUNNING, COMPLETING);
if (doCompletion) {
// If this thread successfully transitioned to COMPLETING, set the value
// and exception and then release to the final state.
this.value = v;
// Don't actually construct a CancellationException until necessary.
this.exception = ((finalState & (CANCELLED | INTERRUPTED)) != 0)
? new CancellationException("Future.cancel() was called.") : t;
releaseShared(finalState);
} else if (getState() == COMPLETING) {
// If some other thread is currently completing the future, block until
// they are done so we can guarantee completion.
acquireShared(-1);
}
return doCompletion;
}
}
static final CancellationException cancellationExceptionWithCause(
String message, Throwable cause) {
CancellationException exception = new CancellationException(message);
exception.initCause(cause);
return exception;
}
}

View file

@ -1,60 +0,0 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* 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 common.future;
/**
* {@link Error} variant of {@link java.util.concurrent.ExecutionException}. As
* with {@code ExecutionException}, the error's {@linkplain #getCause() cause}
* comes from a failed task, possibly run in another thread. That cause should
* itself be an {@code Error}; if not, use {@code ExecutionException} or {@link
* UncheckedExecutionException}. This allows the client code to continue to
* distinguish between exceptions and errors, even when they come from other
* threads.
*
* @author Chris Povirk
* @since 10.0
*/
class ExecutionError extends Error {
/**
* Creates a new instance with {@code null} as its detail message.
*/
protected ExecutionError() {}
/**
* Creates a new instance with the given detail message.
*/
protected ExecutionError(String message) {
super(message);
}
/**
* Creates a new instance with the given detail message and cause.
*/
public ExecutionError(String message, Error cause) {
super(message, cause);
}
/**
* Creates a new instance with the given cause.
*/
public ExecutionError(Error cause) {
super(cause);
}
private static final long serialVersionUID = 0;
}

View file

@ -1,170 +0,0 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 common.future;
import java.util.concurrent.Executor;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* <p>A list of listeners, each with an associated {@code Executor}, that
* guarantees that every {@code Runnable} that is {@linkplain #add added} will
* be executed after {@link #execute()} is called. Any {@code Runnable} added
* after the call to {@code execute} is still guaranteed to execute. There is no
* guarantee, however, that listeners will be executed in the order that they
* are added.
*
* <p>Exceptions thrown by a listener will be propagated up to the executor.
* Any exception thrown during {@code Executor.execute} (e.g., a {@code
* RejectedExecutionException} or an exception thrown by {@linkplain
* MoreExecutors#sameThreadExecutor inline execution}) will be caught and
* logged.
*
* @author Nishant Thakkar
* @author Sven Mawson
* @since 1.0
*/
final class ExecutionList {
// Logger to log exceptions caught when running runnables.
// @VisibleForTesting
static final Logger log = Logger.getLogger(ExecutionList.class.getName());
/**
* The runnable, executor pairs to execute. This acts as a stack threaded through the
* {@link RunnableExecutorPair#next} field.
*/
// @GuardedBy("this")
private RunnableExecutorPair runnables;
// @GuardedBy("this")
private boolean executed;
/** Creates a new, empty {@link ExecutionList}. */
public ExecutionList() {}
/**
* Adds the {@code Runnable} and accompanying {@code Executor} to the list of
* listeners to execute. If execution has already begun, the listener is
* executed immediately.
*
* <p>Note: For fast, lightweight listeners that would be safe to execute in
* any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier
* listeners, {@code sameThreadExecutor()} carries some caveats: First, the
* thread that the listener runs in depends on whether the {@code
* ExecutionList} has been executed at the time it is added. In particular,
* listeners may run in the thread that calls {@code add}. Second, the thread
* that calls {@link #execute} may be an internal implementation thread, such
* as an RPC network thread, and {@code sameThreadExecutor()} listeners may
* run in this thread. Finally, during the execution of a {@code
* sameThreadExecutor} listener, all other registered but unexecuted
* listeners are prevented from running, even if those listeners are to run
* in other executors.
*/
public void add(Runnable runnable, Executor executor) {
// Fail fast on a null. We throw NPE here because the contract of
// Executor states that it throws NPE on null listener, so we propagate
// that contract up into the add method as well.
// Lock while we check state. We must maintain the lock while adding the
// new pair so that another thread can't run the list out from under us.
// We only add to the list if we have not yet started execution.
synchronized (this) {
if (!executed) {
runnables = new RunnableExecutorPair(runnable, executor, runnables);
return;
}
}
// Execute the runnable immediately. Because of scheduling this may end up
// getting called before some of the previously added runnables, but we're
// OK with that. If we want to change the contract to guarantee ordering
// among runnables we'd have to modify the logic here to allow it.
executeListener(runnable, executor);
}
/**
* Runs this execution list, executing all existing pairs in the order they
* were added. However, note that listeners added after this point may be
* executed before those previously added, and note that the execution order
* of all listeners is ultimately chosen by the implementations of the
* supplied executors.
*
* <p>This method is idempotent. Calling it several times in parallel is
* semantically equivalent to calling it exactly once.
*
* @since 10.0 (present in 1.0 as {@code run})
*/
public void execute() {
// Lock while we update our state so the add method above will finish adding
// any listeners before we start to run them.
RunnableExecutorPair list;
synchronized (this) {
if (executed) {
return;
}
executed = true;
list = runnables;
runnables = null; // allow GC to free listeners even if this stays around for a while.
}
// If we succeeded then list holds all the runnables we to execute. The pairs in the stack are
// in the opposite order from how they were added so we need to reverse the list to fulfill our
// contract.
// This is somewhat annoying, but turns out to be very fast in practice. Alternatively, we
// could drop the contract on the method that enforces this queue like behavior since depending
// on it is likely to be a bug anyway.
// N.B. All writes to the list and the next pointers must have happened before the above
// synchronized block, so we can iterate the list without the lock held here.
RunnableExecutorPair reversedList = null;
while (list != null) {
RunnableExecutorPair tmp = list;
list = list.next;
tmp.next = reversedList;
reversedList = tmp;
}
while (reversedList != null) {
executeListener(reversedList.runnable, reversedList.executor);
reversedList = reversedList.next;
}
}
/**
* Submits the given runnable to the given {@link Executor} catching and logging all
* {@linkplain RuntimeException runtime exceptions} thrown by the executor.
*/
private static void executeListener(Runnable runnable, Executor executor) {
try {
executor.execute(runnable);
} catch (RuntimeException e) {
// Log it and keep going, bad runnable and/or executor. Don't
// punish the other runnables if we're given a bad one. We only
// catch RuntimeException because we want Errors to propagate up.
log.log(Level.SEVERE, "RuntimeException while executing runnable "
+ runnable + " with executor " + executor, e);
}
}
private static final class RunnableExecutorPair {
final Runnable runnable;
final Executor executor;
RunnableExecutorPair next;
RunnableExecutorPair(Runnable runnable, Executor executor, RunnableExecutorPair next) {
this.runnable = runnable;
this.executor = executor;
this.next = next;
}
}
}

View file

@ -1,43 +0,0 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* 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 common.future;
/**
* A callback for accepting the results of a {@link java.util.concurrent.Future}
* computation asynchronously.
*
* <p>To attach to a {@link ListenableFuture} use {@link Futures#addCallback}.
*
* @author Anthony Zana
* @since 10.0
*/
public interface FutureCallback<V> {
/**
* Invoked with the result of the {@code Future} computation when it is
* successful.
*/
void onSuccess(V result);
/**
* Invoked when a {@code Future} computation fails or is canceled.
*
* <p>If the future's {@link Future#get() get} method throws an {@link
* ExecutionException}, then the cause is passed to this method. Any other
* thrown object is passed unaltered.
*/
void onFailure(Throwable t);
}

File diff suppressed because it is too large Load diff

View file

@ -1,132 +0,0 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 common.future;
import java.util.concurrent.Executor;
import java.util.concurrent.Future;
/**
* A {@link Future} that accepts completion listeners. Each listener has an
* associated executor, and it is invoked using this executor once the future's
* computation is {@linkplain Future#isDone() complete}. If the computation has
* already completed when the listener is added, the listener will execute
* immediately.
*
* <p>See the Guava User Guide article on <a href=
* "http://code.google.com/p/guava-libraries/wiki/ListenableFutureExplained">
* {@code ListenableFuture}</a>.
*
* <h3>Purpose</h3>
*
* <p>Most commonly, {@code ListenableFuture} is used as an input to another
* derived {@code Future}, as in {@link Futures#allAsList(Iterable)
* Futures.allAsList}. Many such methods are impossible to implement efficiently
* without listener support.
*
* <p>It is possible to call {@link #addListener addListener} directly, but this
* is uncommon because the {@code Runnable} interface does not provide direct
* access to the {@code Future} result. (Users who want such access may prefer
* {@link Futures#addCallback Futures.addCallback}.) Still, direct {@code
* addListener} calls are occasionally useful:<pre> {@code
* final String name = ...;
* inFlight.add(name);
* ListenableFuture<Result> future = service.query(name);
* future.addListener(new Runnable() {
* public void run() {
* processedCount.incrementAndGet();
* inFlight.remove(name);
* lastProcessed.set(name);
* logger.info("Done with {0}", name);
* }
* }, executor);}</pre>
*
* <h3>How to get an instance</h3>
*
* <p>Developers are encouraged to return {@code ListenableFuture} from their
* methods so that users can take advantages of the utilities built atop the
* class. The way that they will create {@code ListenableFuture} instances
* depends on how they currently create {@code Future} instances:
* <ul>
* <li>If they are returned from an {@code ExecutorService}, convert that
* service to a {@link ListeningExecutorService}, usually by calling {@link
* MoreExecutors#listeningDecorator(ExecutorService)
* MoreExecutors.listeningDecorator}. (Custom executors may find it more
* convenient to use {@link ListenableFutureTask} directly.)
* <li>If they are manually filled in by a call to {@link FutureTask#set} or a
* similar method, create a {@link SettableFuture} instead. (Users with more
* complex needs may prefer {@link AbstractFuture}.)
* </ul>
*
* <p>Occasionally, an API will return a plain {@code Future} and it will be
* impossible to change the return type. For this case, we provide a more
* expensive workaround in {@code JdkFutureAdapters}. However, when possible, it
* is more efficient and reliable to create a {@code ListenableFuture} directly.
*
* @author Sven Mawson
* @author Nishant Thakkar
* @since 1.0
*/
public interface ListenableFuture<V> extends Future<V> {
/**
* Registers a listener to be {@linkplain Executor#execute(Runnable) run} on
* the given executor. The listener will run when the {@code Future}'s
* computation is {@linkplain Future#isDone() complete} or, if the computation
* is already complete, immediately.
*
* <p>There is no guaranteed ordering of execution of listeners, but any
* listener added through this method is guaranteed to be called once the
* computation is complete.
*
* <p>Exceptions thrown by a listener will be propagated up to the executor.
* Any exception thrown during {@code Executor.execute} (e.g., a {@code
* RejectedExecutionException} or an exception thrown by {@linkplain
* MoreExecutors#sameThreadExecutor inline execution}) will be caught and
* logged.
*
* <p>Note: For fast, lightweight listeners that would be safe to execute in
* any thread, consider {@link MoreExecutors#sameThreadExecutor}. For heavier
* listeners, {@code sameThreadExecutor()} carries some caveats. For
* example, the listener may run on an unpredictable or undesirable thread:
*
* <ul>
* <li>If this {@code Future} is done at the time {@code addListener} is
* called, {@code addListener} will execute the listener inline.
* <li>If this {@code Future} is not yet done, {@code addListener} will
* schedule the listener to be run by the thread that completes this {@code
* Future}, which may be an internal system thread such as an RPC network
* thread.
* </ul>
*
* <p>Also note that, regardless of which thread executes the
* {@code sameThreadExecutor()} listener, all other registered but unexecuted
* listeners are prevented from running during its execution, even if those
* listeners are to run in other executors.
*
* <p>This is the most general listener interface. For common operations
* performed using listeners, see {@link
* game.future.Futures}. For a simplified but general
* listener interface, see {@link
* game.future.Futures#addCallback addCallback()}.
*
* @param listener the listener to run when the computation is complete
* @param executor the executor to run the listener in
* @throws NullPointerException if the executor or listener was null
* @throws RejectedExecutionException if we tried to execute the listener
* immediately but the executor rejected it.
*/
void addListener(Runnable listener, Executor executor);
}

View file

@ -1,91 +0,0 @@
/*
* Copyright (C) 2008 The Guava Authors
*
* 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 common.future;
import java.util.concurrent.Callable;
import java.util.concurrent.Executor;
import java.util.concurrent.FutureTask;
/**
* A {@link FutureTask} that also implements the {@link ListenableFuture}
* interface. Unlike {@code FutureTask}, {@code ListenableFutureTask} does not
* provide an overrideable {@link FutureTask#done() done()} method. For similar
* functionality, call {@link #addListener}.
*
* <p>
*
* @author Sven Mawson
* @since 1.0
*/
public class ListenableFutureTask<V> extends FutureTask<V>
implements ListenableFuture<V> {
// TODO(cpovirk): explore ways of making ListenableFutureTask final. There are
// some valid reasons such as BoundedQueueExecutorService to allow extends but it
// would be nice to make it final to avoid unintended usage.
// The execution list to hold our listeners.
private final ExecutionList executionList = new ExecutionList();
/**
* Creates a {@code ListenableFutureTask} that will upon running, execute the
* given {@code Callable}.
*
* @param callable the callable task
* @since 10.0
*/
public static <V> ListenableFutureTask<V> create(Callable<V> callable) {
return new ListenableFutureTask<V>(callable);
}
/**
* Creates a {@code ListenableFutureTask} that will upon running, execute the
* given {@code Runnable}, and arrange that {@code get} will return the
* given result on successful completion.
*
* @param runnable the runnable task
* @param result the result to return on successful completion. If you don't
* need a particular result, consider using constructions of the form:
* {@code ListenableFuture<?> f = ListenableFutureTask.create(runnable,
* null)}
* @since 10.0
*/
public static <V> ListenableFutureTask<V> create(
Runnable runnable, V result) {
return new ListenableFutureTask<V>(runnable, result);
}
ListenableFutureTask(Callable<V> callable) {
super(callable);
}
ListenableFutureTask(Runnable runnable, V result) {
super(runnable, result);
}
@Override
public void addListener(Runnable listener, Executor exec) {
executionList.add(listener, exec);
}
/**
* Internal implementation detail used to invoke the listeners.
*/
@Override
protected void done() {
executionList.execute();
}
}

View file

@ -1,889 +0,0 @@
/*
* Copyright (C) 2007 The Guava Authors
*
* 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 common.future;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.AbstractExecutorService;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.RejectedExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Factory and utility methods for {@link java.util.concurrent.Executor}, {@link
* ExecutorService}, and {@link ThreadFactory}.
*
* @author Eric Fellheimer
* @author Kyle Littlefield
* @author Justin Mahoney
* @since 3.0
*/
final class MoreExecutors {
private MoreExecutors() {}
/**
* Converts the given ThreadPoolExecutor into an ExecutorService that exits
* when the application is complete. It does so by using daemon threads and
* adding a shutdown hook to wait for their completion.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newFixedThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @param terminationTimeout how long to wait for the executor to
* finish before terminating the JVM
* @param timeUnit unit of time for the time parameter
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ExecutorService getExitingExecutorService(
// ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// return new Application()
// .getExitingExecutorService(executor, terminationTimeout, timeUnit);
// }
/**
* Converts the given ScheduledThreadPoolExecutor into a
* ScheduledExecutorService that exits when the application is complete. It
* does so by using daemon threads and adding a shutdown hook to wait for
* their completion.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newScheduledThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @param terminationTimeout how long to wait for the executor to
* finish before terminating the JVM
* @param timeUnit unit of time for the time parameter
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// return new Application()
// .getExitingScheduledExecutorService(executor, terminationTimeout, timeUnit);
// }
/**
* Add a shutdown hook to wait for thread completion in the given
* {@link ExecutorService service}. This is useful if the given service uses
* daemon threads, and we want to keep the JVM from exiting immediately on
* shutdown, instead giving these daemon threads a chance to terminate
* normally.
* @param service ExecutorService which uses daemon threads
* @param terminationTimeout how long to wait for the executor to finish
* before terminating the JVM
* @param timeUnit unit of time for the time parameter
*/
// @Beta
// public static void addDelayedShutdownHook(
// ExecutorService service, long terminationTimeout, TimeUnit timeUnit) {
// new Application()
// .addDelayedShutdownHook(service, terminationTimeout, timeUnit);
// }
/**
* Converts the given ThreadPoolExecutor into an ExecutorService that exits
* when the application is complete. It does so by using daemon threads and
* adding a shutdown hook to wait for their completion.
*
* <p>This method waits 120 seconds before continuing with JVM termination,
* even if the executor has not finished its work.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newFixedThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) {
// return new Application().getExitingExecutorService(executor);
// }
/**
* Converts the given ThreadPoolExecutor into a ScheduledExecutorService that
* exits when the application is complete. It does so by using daemon threads
* and adding a shutdown hook to wait for their completion.
*
* <p>This method waits 120 seconds before continuing with JVM termination,
* even if the executor has not finished its work.
*
* <p>This is mainly for fixed thread pools.
* See {@link Executors#newScheduledThreadPool(int)}.
*
* @param executor the executor to modify to make sure it exits when the
* application is finished
* @return an unmodifiable version of the input which will not hang the JVM
*/
// @Beta
// public static ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor) {
// return new Application().getExitingScheduledExecutorService(executor);
// }
/** Represents the current application to register shutdown hooks. */
// @VisibleForTesting static class Application {
//
// final ExecutorService getExitingExecutorService(
// ThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// useDaemonThreadFactory(executor);
// ExecutorService service = Executors.unconfigurableExecutorService(executor);
// addDelayedShutdownHook(service, terminationTimeout, timeUnit);
// return service;
// }
//
// final ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor, long terminationTimeout, TimeUnit timeUnit) {
// useDaemonThreadFactory(executor);
// ScheduledExecutorService service = Executors.unconfigurableScheduledExecutorService(executor);
// addDelayedShutdownHook(service, terminationTimeout, timeUnit);
// return service;
// }
//
// final void addDelayedShutdownHook(
// final ExecutorService service, final long terminationTimeout, final TimeUnit timeUnit) {
// checkNotNull(service);
// checkNotNull(timeUnit);
// addShutdownHook(MoreExecutors.newThread("DelayedShutdownHook-for-" + service, new Runnable() {
// @Override
// public void run() {
// try {
// // We'd like to log progress and failures that may arise in the
// // following code, but unfortunately the behavior of logging
// // is undefined in shutdown hooks.
// // This is because the logging code installs a shutdown hook of its
// // own. See Cleaner class inside {@link LogManager}.
// service.shutdown();
// service.awaitTermination(terminationTimeout, timeUnit);
// } catch (InterruptedException ignored) {
// // We're shutting down anyway, so just ignore.
// }
// }
// }));
// }
//
// final ExecutorService getExitingExecutorService(ThreadPoolExecutor executor) {
// return getExitingExecutorService(executor, 120, TimeUnit.SECONDS);
// }
//
// final ScheduledExecutorService getExitingScheduledExecutorService(
// ScheduledThreadPoolExecutor executor) {
// return getExitingScheduledExecutorService(executor, 120, TimeUnit.SECONDS);
// }
//
// @VisibleForTesting void addShutdownHook(Thread hook) {
// Runtime.getRuntime().addShutdownHook(hook);
// }
// }
//
// private static void useDaemonThreadFactory(ThreadPoolExecutor executor) {
// executor.setThreadFactory(new ThreadFactoryBuilder()
// .setDaemon(true)
// .setThreadFactory(executor.getThreadFactory())
// .build());
// }
/**
* Creates an executor service that runs each task in the thread
* that invokes {@code execute/submit}, as in {@link CallerRunsPolicy} This
* applies both to individually submitted tasks and to collections of tasks
* submitted via {@code invokeAll} or {@code invokeAny}. In the latter case,
* tasks will run serially on the calling thread. Tasks are run to
* completion before a {@code Future} is returned to the caller (unless the
* executor has been shutdown).
*
* <p>Although all tasks are immediately executed in the thread that
* submitted the task, this {@code ExecutorService} imposes a small
* locking overhead on each task submission in order to implement shutdown
* and termination behavior.
*
* <p>The implementation deviates from the {@code ExecutorService}
* specification with regards to the {@code shutdownNow} method. First,
* "best-effort" with regards to canceling running tasks is implemented
* as "no-effort". No interrupts or other attempts are made to stop
* threads executing tasks. Second, the returned list will always be empty,
* as any submitted task is considered to have started execution.
* This applies also to tasks given to {@code invokeAll} or {@code invokeAny}
* which are pending serial execution, even the subset of the tasks that
* have not yet started execution. It is unclear from the
* {@code ExecutorService} specification if these should be included, and
* it's much easier to implement the interpretation that they not be.
* Finally, a call to {@code shutdown} or {@code shutdownNow} may result
* in concurrent calls to {@code invokeAll/invokeAny} throwing
* RejectedExecutionException, although a subset of the tasks may already
* have been executed.
*
* @since 10.0 (<a href="http://code.google.com/p/guava-libraries/wiki/Compatibility"
* >mostly source-compatible</a> since 3.0)
*/
public static SameThreadExecutorService sameThreadExecutor() {
return new SameThreadExecutorService();
}
// See sameThreadExecutor javadoc for behavioral notes.
private static class SameThreadExecutorService
extends AbstractExecutorService implements ExecutorService {
/**
* Lock used whenever accessing the state variables
* (runningTasks, shutdown, terminationCondition) of the executor
*/
private final Lock lock = new ReentrantLock();
/** Signaled after the executor is shutdown and running tasks are done */
private final Condition termination = lock.newCondition();
/*
* Conceptually, these two variables describe the executor being in
* one of three states:
* - Active: shutdown == false
* - Shutdown: runningTasks > 0 and shutdown == true
* - Terminated: runningTasks == 0 and shutdown == true
*/
private int runningTasks = 0;
private boolean shutdown = false;
@Override
public void execute(Runnable command) {
startTask();
try {
command.run();
} finally {
endTask();
}
}
@Override
public boolean isShutdown() {
lock.lock();
try {
return shutdown;
} finally {
lock.unlock();
}
}
@Override
public void shutdown() {
lock.lock();
try {
shutdown = true;
} finally {
lock.unlock();
}
}
// See sameThreadExecutor javadoc for unusual behavior of this method.
@Override
public List<Runnable> shutdownNow() {
shutdown();
return Collections.emptyList();
}
@Override
public boolean isTerminated() {
lock.lock();
try {
return shutdown && runningTasks == 0;
} finally {
lock.unlock();
}
}
@Override
public boolean awaitTermination(long timeout, TimeUnit unit)
throws InterruptedException {
long nanos = unit.toNanos(timeout);
lock.lock();
try {
for (;;) {
if (isTerminated()) {
return true;
} else if (nanos <= 0) {
return false;
} else {
nanos = termination.awaitNanos(nanos);
}
}
} finally {
lock.unlock();
}
}
/**
* Checks if the executor has been shut down and increments the running
* task count.
*
* @throws RejectedExecutionException if the executor has been previously
* shutdown
*/
private void startTask() {
lock.lock();
try {
if (isShutdown()) {
throw new RejectedExecutionException("Executor already shutdown");
}
runningTasks++;
} finally {
lock.unlock();
}
}
/**
* Decrements the running task count.
*/
private void endTask() {
lock.lock();
try {
runningTasks--;
if (isTerminated()) {
termination.signalAll();
}
} finally {
lock.unlock();
}
}
@Override protected final <T> ListenableFutureTask<T> newTaskFor(Runnable runnable, T value) {
return ListenableFutureTask.create(runnable, value);
}
@Override protected final <T> ListenableFutureTask<T> newTaskFor(Callable<T> callable) {
return ListenableFutureTask.create(callable);
}
@Override public ListenableFuture<?> submit(Runnable task) {
return (ListenableFuture<?>) super.submit(task);
}
@Override public <T> ListenableFuture<T> submit(Runnable task, T result) {
return (ListenableFuture<T>) super.submit(task, result);
}
@Override public <T> ListenableFuture<T> submit(Callable<T> task) {
return (ListenableFuture<T>) super.submit(task);
}
}
/**
* Creates an {@link ExecutorService} whose {@code submit} and {@code
* invokeAll} methods submit {@link ListenableFutureTask} instances to the
* given delegate executor. Those methods, as well as {@code execute} and
* {@code invokeAny}, are implemented in terms of calls to {@code
* delegate.execute}. All other methods are forwarded unchanged to the
* delegate. This implies that the returned {@code ListeningExecutorService}
* never calls the delegate's {@code submit}, {@code invokeAll}, and {@code
* invokeAny} methods, so any special handling of tasks must be implemented in
* the delegate's {@code execute} method or by wrapping the returned {@code
* ListeningExecutorService}.
*
* <p>If the delegate executor was already an instance of {@code
* ListeningExecutorService}, it is returned untouched, and the rest of this
* documentation does not apply.
*
* @since 10.0
*/
// public static ListeningExecutorService listeningDecorator(
// ExecutorService delegate) {
// return (delegate instanceof ListeningExecutorService)
// ? (ListeningExecutorService) delegate
// : (delegate instanceof ScheduledExecutorService)
// ? new ScheduledListeningDecorator((ScheduledExecutorService) delegate)
// : new ListeningDecorator(delegate);
// }
/**
* Creates a {@link ScheduledExecutorService} whose {@code submit} and {@code
* invokeAll} methods submit {@link ListenableFutureTask} instances to the
* given delegate executor. Those methods, as well as {@code execute} and
* {@code invokeAny}, are implemented in terms of calls to {@code
* delegate.execute}. All other methods are forwarded unchanged to the
* delegate. This implies that the returned {@code
* ListeningScheduledExecutorService} never calls the delegate's {@code
* submit}, {@code invokeAll}, and {@code invokeAny} methods, so any special
* handling of tasks must be implemented in the delegate's {@code execute}
* method or by wrapping the returned {@code
* ListeningScheduledExecutorService}.
*
* <p>If the delegate executor was already an instance of {@code
* ListeningScheduledExecutorService}, it is returned untouched, and the rest
* of this documentation does not apply.
*
* @since 10.0
*/
// public static ListeningScheduledExecutorService listeningDecorator(
// ScheduledExecutorService delegate) {
// return (delegate instanceof ListeningScheduledExecutorService)
// ? (ListeningScheduledExecutorService) delegate
// : new ScheduledListeningDecorator(delegate);
// }
// private static class ListeningDecorator
// extends AbstractListeningExecutorService {
// private final ExecutorService delegate;
//
// ListeningDecorator(ExecutorService delegate) {
// this.delegate = checkNotNull(delegate);
// }
//
// @Override
// public boolean awaitTermination(long timeout, TimeUnit unit)
// throws InterruptedException {
// return delegate.awaitTermination(timeout, unit);
// }
//
// @Override
// public boolean isShutdown() {
// return delegate.isShutdown();
// }
//
// @Override
// public boolean isTerminated() {
// return delegate.isTerminated();
// }
//
// @Override
// public void shutdown() {
// delegate.shutdown();
// }
//
// @Override
// public List<Runnable> shutdownNow() {
// return delegate.shutdownNow();
// }
//
// @Override
// public void execute(Runnable command) {
// delegate.execute(command);
// }
// }
//
// private static class ScheduledListeningDecorator
// extends ListeningDecorator implements ListeningScheduledExecutorService {
//
// final ScheduledExecutorService delegate;
//
// ScheduledListeningDecorator(ScheduledExecutorService delegate) {
// super(delegate);
// this.delegate = checkNotNull(delegate);
// }
//
// @Override
// public ListenableScheduledFuture<?> schedule(
// Runnable command, long delay, TimeUnit unit) {
// ListenableFutureTask<Void> task =
// ListenableFutureTask.create(command, null);
// ScheduledFuture<?> scheduled = delegate.schedule(task, delay, unit);
// return new ListenableScheduledTask<Void>(task, scheduled);
// }
//
// @Override
// public <V> ListenableScheduledFuture<V> schedule(
// Callable<V> callable, long delay, TimeUnit unit) {
// ListenableFutureTask<V> task = ListenableFutureTask.create(callable);
// ScheduledFuture<?> scheduled = delegate.schedule(task, delay, unit);
// return new ListenableScheduledTask<V>(task, scheduled);
// }
//
// @Override
// public ListenableScheduledFuture<?> scheduleAtFixedRate(
// Runnable command, long initialDelay, long period, TimeUnit unit) {
// NeverSuccessfulListenableFutureTask task =
// new NeverSuccessfulListenableFutureTask(command);
// ScheduledFuture<?> scheduled =
// delegate.scheduleAtFixedRate(task, initialDelay, period, unit);
// return new ListenableScheduledTask<Void>(task, scheduled);
// }
//
// @Override
// public ListenableScheduledFuture<?> scheduleWithFixedDelay(
// Runnable command, long initialDelay, long delay, TimeUnit unit) {
// NeverSuccessfulListenableFutureTask task =
// new NeverSuccessfulListenableFutureTask(command);
// ScheduledFuture<?> scheduled =
// delegate.scheduleWithFixedDelay(task, initialDelay, delay, unit);
// return new ListenableScheduledTask<Void>(task, scheduled);
// }
//
// private static final class ListenableScheduledTask<V>
// extends SimpleForwardingListenableFuture<V>
// implements ListenableScheduledFuture<V> {
//
// private final ScheduledFuture<?> scheduledDelegate;
//
// public ListenableScheduledTask(
// ListenableFuture<V> listenableDelegate,
// ScheduledFuture<?> scheduledDelegate) {
// super(listenableDelegate);
// this.scheduledDelegate = scheduledDelegate;
// }
//
// @Override
// public boolean cancel(boolean mayInterruptIfRunning) {
// boolean cancelled = super.cancel(mayInterruptIfRunning);
// if (cancelled) {
// // Unless it is cancelled, the delegate may continue being scheduled
// scheduledDelegate.cancel(mayInterruptIfRunning);
//
// // TODO(user): Cancel "this" if "scheduledDelegate" is cancelled.
// }
// return cancelled;
// }
//
// @Override
// public long getDelay(TimeUnit unit) {
// return scheduledDelegate.getDelay(unit);
// }
//
// @Override
// public int compareTo(Delayed other) {
// return scheduledDelegate.compareTo(other);
// }
// }
//
// private static final class NeverSuccessfulListenableFutureTask
// extends AbstractFuture<Void>
// implements Runnable {
// private final Runnable delegate;
//
// public NeverSuccessfulListenableFutureTask(Runnable delegate) {
// this.delegate = checkNotNull(delegate);
// }
//
// @Override public void run() {
// try {
// delegate.run();
// } catch (Throwable t) {
// setException(t);
// throw Throwables.propagate(t);
// }
// }
// }
// }
/*
* This following method is a modified version of one found in
* http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/test/tck/AbstractExecutorServiceTest.java?revision=1.30
* which contained the following notice:
*
* Written by Doug Lea with assistance from members of JCP JSR-166
* Expert Group and released to the public domain, as explained at
* http://creativecommons.org/publicdomain/zero/1.0/
* Other contributors include Andrew Wright, Jeffrey Hayes,
* Pat Fisher, Mike Judd.
*/
/**
* An implementation of {@link ExecutorService#invokeAny} for {@link ListeningExecutorService}
* implementations.
*/ // static <T> T invokeAnyImpl(ListeningExecutorService executorService,
// Collection<? extends Callable<T>> tasks, boolean timed, long nanos)
// throws InterruptedException, ExecutionException, TimeoutException {
// checkNotNull(executorService);
// int ntasks = tasks.size();
// checkArgument(ntasks > 0);
// List<Future<T>> futures = Lists.newArrayListWithCapacity(ntasks);
// BlockingQueue<Future<T>> futureQueue = Queues.newLinkedBlockingQueue();
//
// // For efficiency, especially in executors with limited
// // parallelism, check to see if previously submitted tasks are
// // done before submitting more of them. This interleaving
// // plus the exception mechanics account for messiness of main
// // loop.
//
// try {
// // Record exceptions so that if we fail to obtain any
// // result, we can throw the last exception we got.
// ExecutionException ee = null;
// long lastTime = timed ? System.nanoTime() : 0;
// Iterator<? extends Callable<T>> it = tasks.iterator();
//
// futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue));
// --ntasks;
// int active = 1;
//
// for (;;) {
// Future<T> f = futureQueue.poll();
// if (f == null) {
// if (ntasks > 0) {
// --ntasks;
// futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue));
// ++active;
// } else if (active == 0) {
// break;
// } else if (timed) {
// f = futureQueue.poll(nanos, TimeUnit.NANOSECONDS);
// if (f == null) {
// throw new TimeoutException();
// }
// long now = System.nanoTime();
// nanos -= now - lastTime;
// lastTime = now;
// } else {
// f = futureQueue.take();
// }
// }
// if (f != null) {
// --active;
// try {
// return f.get();
// } catch (ExecutionException eex) {
// ee = eex;
// } catch (RuntimeException rex) {
// ee = new ExecutionException(rex);
// }
// }
// }
//
// if (ee == null) {
// ee = new ExecutionException(null);
// }
// throw ee;
// } finally {
// for (Future<T> f : futures) {
// f.cancel(true);
// }
// }
// }
/**
* Submits the task and adds a listener that adds the future to {@code queue} when it completes.
*/
// private static <T> ListenableFuture<T> submitAndAddQueueListener(
// ListeningExecutorService executorService, Callable<T> task,
// final BlockingQueue<Future<T>> queue) {
// final ListenableFuture<T> future = executorService.submit(task);
// future.addListener(new Runnable() {
// @Override public void run() {
// queue.add(future);
// }
// }, MoreExecutors.sameThreadExecutor());
// return future;
// }
/**
* Returns a default thread factory used to create new threads.
*
* <p>On AppEngine, returns {@code ThreadManager.currentRequestThreadFactory()}.
* Otherwise, returns {@link Executors#defaultThreadFactory()}.
*
* @since 14.0
*/
// @Beta
// public static ThreadFactory platformThreadFactory() {
// if (!isAppEngine()) {
// return Executors.defaultThreadFactory();
// }
// try {
// return (ThreadFactory) Class.forName("com.google.appengine.api.ThreadManager")
// .getMethod("currentRequestThreadFactory")
// .invoke(null);
// } catch (IllegalAccessException e) {
// throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
// } catch (ClassNotFoundException e) {
// throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
// } catch (NoSuchMethodException e) {
// throw new RuntimeException("Couldn't invoke ThreadManager.currentRequestThreadFactory", e);
// } catch (InvocationTargetException e) {
// throw Throwables.propagate(e.getCause());
// }
// }
// private static boolean isAppEngine() {
// if (System.getProperty("com.google.appengine.runtime.environment") == null) {
// return false;
// }
// try {
// // If the current environment is null, we're not inside AppEngine.
// return Class.forName("com.google.apphosting.api.ApiProxy")
// .getMethod("getCurrentEnvironment")
// .invoke(null) != null;
// } catch (ClassNotFoundException e) {
// // If ApiProxy doesn't exist, we're not on AppEngine at all.
// return false;
// } catch (InvocationTargetException e) {
// // If ApiProxy throws an exception, we're not in a proper AppEngine environment.
// return false;
// } catch (IllegalAccessException e) {
// // If the method isn't accessible, we're not on a supported version of AppEngine;
// return false;
// } catch (NoSuchMethodException e) {
// // If the method doesn't exist, we're not on a supported version of AppEngine;
// return false;
// }
// }
/**
* Creates a thread using {@link #platformThreadFactory}, and sets its name to {@code name}
* unless changing the name is forbidden by the security manager.
*/
// static Thread newThread(String name, Runnable runnable) {
// checkNotNull(name);
// checkNotNull(runnable);
// Thread result = platformThreadFactory().newThread(runnable);
// try {
// result.setName(name);
// } catch (SecurityException e) {
// // OK if we can't set the name in this environment.
// }
// return result;
// }
// TODO(user): provide overloads for ListeningExecutorService? ListeningScheduledExecutorService?
// TODO(user): provide overloads that take constant strings? Function<Runnable, String>s to
// calculate names?
/**
* Creates an {@link Executor} that renames the {@link Thread threads} that its tasks run in.
*
* <p>The names are retrieved from the {@code nameSupplier} on the thread that is being renamed
* right before each task is run. The renaming is best effort, if a {@link SecurityManager}
* prevents the renaming then it will be skipped but the tasks will still execute.
*
*
* @param executor The executor to decorate
* @param nameSupplier The source of names for each task
*/
// static Executor renamingDecorator(final Executor executor, final Supplier<String> nameSupplier) {
// checkNotNull(executor);
// checkNotNull(nameSupplier);
// if (isAppEngine()) {
// // AppEngine doesn't support thread renaming, so don't even try
// return executor;
// }
// return new Executor() {
// @Override public void execute(Runnable command) {
// executor.execute(Callables.threadRenaming(command, nameSupplier));
// }
// };
// }
/**
* Creates an {@link ExecutorService} that renames the {@link Thread threads} that its tasks run
* in.
*
* <p>The names are retrieved from the {@code nameSupplier} on the thread that is being renamed
* right before each task is run. The renaming is best effort, if a {@link SecurityManager}
* prevents the renaming then it will be skipped but the tasks will still execute.
*
*
* @param service The executor to decorate
* @param nameSupplier The source of names for each task
*/
// static ExecutorService renamingDecorator(final ExecutorService service,
// final Supplier<String> nameSupplier) {
// checkNotNull(service);
// checkNotNull(nameSupplier);
// if (isAppEngine()) {
// // AppEngine doesn't support thread renaming, so don't even try.
// return service;
// }
// return new WrappingExecutorService(service) {
// @Override protected <T> Callable<T> wrapTask(Callable<T> callable) {
// return Callables.threadRenaming(callable, nameSupplier);
// }
// @Override protected Runnable wrapTask(Runnable command) {
// return Callables.threadRenaming(command, nameSupplier);
// }
// };
// }
/**
* Creates a {@link ScheduledExecutorService} that renames the {@link Thread threads} that its
* tasks run in.
*
* <p>The names are retrieved from the {@code nameSupplier} on the thread that is being renamed
* right before each task is run. The renaming is best effort, if a {@link SecurityManager}
* prevents the renaming then it will be skipped but the tasks will still execute.
*
*
* @param service The executor to decorate
* @param nameSupplier The source of names for each task
*/
// static ScheduledExecutorService renamingDecorator(final ScheduledExecutorService service,
// final Supplier<String> nameSupplier) {
// checkNotNull(service);
// checkNotNull(nameSupplier);
// if (isAppEngine()) {
// // AppEngine doesn't support thread renaming, so don't even try.
// return service;
// }
// return new WrappingScheduledExecutorService(service) {
// @Override protected <T> Callable<T> wrapTask(Callable<T> callable) {
// return Callables.threadRenaming(callable, nameSupplier);
// }
// @Override protected Runnable wrapTask(Runnable command) {
// return Callables.threadRenaming(command, nameSupplier);
// }
// };
// }
/**
* Shuts down the given executor gradually, first disabling new submissions and later cancelling
* existing tasks.
*
* <p>The method takes the following steps:
* <ol>
* <li>calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks.
* <li>waits for half of the specified timeout.
* <li>if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling
* pending tasks and interrupting running tasks.
* <li>waits for the other half of the specified timeout.
* </ol>
*
* <p>If, at any step of the process, the given executor is terminated or the calling thread is
* interrupted, the method may return without executing any remaining steps.
*
* @param service the {@code ExecutorService} to shut down
* @param timeout the maximum time to wait for the {@code ExecutorService} to terminate
* @param unit the time unit of the timeout argument
* @return {@code true) if the pool was terminated successfully, {@code false} if the
* {@code ExecutorService} could not terminate <b>or</b> the thread running this method
* is interrupted while waiting for the {@code ExecutorService} to terminate
* @since 17.0
*/
// @Beta
// public static boolean shutdownAndAwaitTermination(
// ExecutorService service, long timeout, TimeUnit unit) {
// checkNotNull(unit);
// // Disable new tasks from being submitted
// service.shutdown();
// try {
// long halfTimeoutNanos = TimeUnit.NANOSECONDS.convert(timeout, unit) / 2;
// // Wait for half the duration of the timeout for existing tasks to terminate
// if (!service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS)) {
// // Cancel currently executing tasks
// service.shutdownNow();
// // Wait the other half of the timeout for tasks to respond to being cancelled
// service.awaitTermination(halfTimeoutNanos, TimeUnit.NANOSECONDS);
// }
// } catch (InterruptedException ie) {
// // Preserve interrupt status
// Thread.currentThread().interrupt();
// // (Re-)Cancel if current thread also interrupted
// service.shutdownNow();
// }
// return service.isTerminated();
// }
}

View file

@ -1,176 +0,0 @@
/*
* Copyright (C) 2010 The Guava Authors
*
* 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 common.future;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
/**
* A ThreadFactory builder, providing any combination of these features:
* <ul>
* <li> whether threads should be marked as {@linkplain Thread#setDaemon daemon}
* threads
* <li> a {@linkplain ThreadFactoryBuilder#setNameFormat naming format}
* <li> a {@linkplain Thread#setPriority thread priority}
* <li> an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception
* handler}
* <li> a {@linkplain ThreadFactory#newThread backing thread factory}
* </ul>
* <p>If no backing thread factory is provided, a default backing thread factory is
* used as if by calling {@code setThreadFactory(}{@link
* Executors#defaultThreadFactory()}{@code )}.
*
* @author Kurt Alfred Kluever
* @since 4.0
*/
public final class ThreadFactoryBuilder {
private String nameFormat = null;
private Boolean daemon = null;
private Integer priority = null;
private UncaughtExceptionHandler uncaughtExceptionHandler = null;
private ThreadFactory backingThreadFactory = null;
/**
* Creates a new {@link ThreadFactory} builder.
*/
public ThreadFactoryBuilder() {}
/**
* Sets the naming format to use when naming threads ({@link Thread#setName})
* which are created with this ThreadFactory.
*
* @param nameFormat a {@link String#format(String, Object...)}-compatible
* format String, to which a unique integer (0, 1, etc.) will be supplied
* as the single parameter. This integer will be unique to the built
* instance of the ThreadFactory and will be assigned sequentially. For
* example, {@code "rpc-pool-%d"} will generate thread names like
* {@code "rpc-pool-0"}, {@code "rpc-pool-1"}, {@code "rpc-pool-2"}, etc.
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setNameFormat(String nameFormat) {
String.format(nameFormat, 0); // fail fast if the format is bad or null
this.nameFormat = nameFormat;
return this;
}
/**
* Sets daemon or not for new threads created with this ThreadFactory.
*
* @param daemon whether or not new Threads created with this ThreadFactory
* will be daemon threads
* @return this for the builder pattern
*/
public ThreadFactoryBuilder setDaemon(boolean daemon) {
this.daemon = daemon;
return this;
}
/**
* Sets the priority for new threads created with this ThreadFactory.
*
* @param priority the priority for new Threads created with this
* ThreadFactory
* @return this for the builder pattern
*/
// public ThreadFactoryBuilder setPriority(int priority) {
// Thread#setPriority() already checks for validity. These error messages
// are nicer though and will fail-fast.
// checkArgument(priority >= Thread.MIN_PRIORITY,
// "Thread priority (%s) must be >= %s", priority, Thread.MIN_PRIORITY);
// checkArgument(priority <= Thread.MAX_PRIORITY,
// "Thread priority (%s) must be <= %s", priority, Thread.MAX_PRIORITY);
// this.priority = priority;
// return this;
// }
/**
* Sets the {@link UncaughtExceptionHandler} for new threads created with this
* ThreadFactory.
*
* @param uncaughtExceptionHandler the uncaught exception handler for new
* Threads created with this ThreadFactory
* @return this for the builder pattern
*/
// public ThreadFactoryBuilder setUncaughtExceptionHandler(
// UncaughtExceptionHandler uncaughtExceptionHandler) {
// this.uncaughtExceptionHandler = checkNotNull(uncaughtExceptionHandler);
// return this;
// }
/**
* Sets the backing {@link ThreadFactory} for new threads created with this
* ThreadFactory. Threads will be created by invoking #newThread(Runnable) on
* this backing {@link ThreadFactory}.
*
* @param backingThreadFactory the backing {@link ThreadFactory} which will
* be delegated to during thread creation.
* @return this for the builder pattern
*
* @see MoreExecutors
*/
// public ThreadFactoryBuilder setThreadFactory(
// ThreadFactory backingThreadFactory) {
// this.backingThreadFactory = checkNotNull(backingThreadFactory);
// return this;
// }
/**
* Returns a new thread factory using the options supplied during the building
* process. After building, it is still possible to change the options used to
* build the ThreadFactory and/or build again. State is not shared amongst
* built instances.
*
* @return the fully constructed {@link ThreadFactory}
*/
public ThreadFactory build() {
return build(this);
}
private static ThreadFactory build(ThreadFactoryBuilder builder) {
final String nameFormat = builder.nameFormat;
final Boolean daemon = builder.daemon;
final Integer priority = builder.priority;
final UncaughtExceptionHandler uncaughtExceptionHandler =
builder.uncaughtExceptionHandler;
final ThreadFactory backingThreadFactory =
(builder.backingThreadFactory != null)
? builder.backingThreadFactory
: Executors.defaultThreadFactory();
final AtomicLong count = (nameFormat != null) ? new AtomicLong(0) : null;
return new ThreadFactory() {
@Override public Thread newThread(Runnable runnable) {
Thread thread = backingThreadFactory.newThread(runnable);
if (nameFormat != null) {
thread.setName(String.format(nameFormat, count.getAndIncrement()));
}
if (daemon != null) {
thread.setDaemon(daemon);
}
if (priority != null) {
thread.setPriority(priority);
}
if (uncaughtExceptionHandler != null) {
thread.setUncaughtExceptionHandler(uncaughtExceptionHandler);
}
return thread;
}
};
}
}

View file

@ -1,65 +0,0 @@
/*
* Copyright (C) 2011 The Guava Authors
*
* 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 common.future;
/**
* Unchecked variant of {@link java.util.concurrent.ExecutionException}. As with
* {@code ExecutionException}, the exception's {@linkplain #getCause() cause}
* comes from a failed task, possibly run in another thread.
*
* <p>{@code UncheckedExecutionException} is intended as an alternative to
* {@code ExecutionException} when the exception thrown by a task is an
* unchecked exception. However, it may also wrap a checked exception in some
* cases.
*
* <p>When wrapping an {@code Error} from another thread, prefer {@link
* ExecutionError}. When wrapping a checked exception, prefer {@code
* ExecutionException}.
*
* @author Charles Fry
* @since 10.0
*/
class UncheckedExecutionException extends RuntimeException {
/**
* Creates a new instance with {@code null} as its detail message.
*/
protected UncheckedExecutionException() {}
/**
* Creates a new instance with the given detail message.
*/
protected UncheckedExecutionException(String message) {
super(message);
}
/**
* Creates a new instance with the given detail message and cause.
*/
public UncheckedExecutionException(String message, Throwable cause) {
super(message, cause);
}
/**
* Creates a new instance with the given cause.
*/
public UncheckedExecutionException(Throwable cause) {
super(cause);
}
private static final long serialVersionUID = 0;
}

View file

@ -6,7 +6,6 @@ import java.util.List;
import common.collect.Lists;
import common.color.TextColor;
import common.future.ListenableFuture;
import common.network.IThreadListener;
import common.util.Util;
@ -45,8 +44,7 @@ public enum Log {
private static LogLevel level = LogLevel.INFO;
private static boolean colors = true;
private static IThreadListener sync = new IThreadListener() {
public ListenableFuture<Object> schedule(Runnable run) {
return null;
public void schedule(Runnable run) {
}
public boolean isMainThread() {

View file

@ -28,8 +28,7 @@ import common.net.channel.ChannelOption;
import common.net.channel.ChannelPipeline;
import common.net.channel.ChannelPromise;
import common.net.util.AttributeKey;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* A {@link Bootstrap} that makes it easy to bootstrap a {@link Channel} to use
@ -40,8 +39,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public final class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Bootstrap.class);
private volatile SocketAddress remoteAddress;
public Bootstrap() { }
@ -185,10 +182,10 @@ public final class Bootstrap extends AbstractBootstrap<Bootstrap, Channel> {
for (Entry<ChannelOption<?>, Object> e: options.entrySet()) {
try {
if (!channel.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {
logger.warn("Unknown channel option: " + e);
NetLog.warn("Unknown channel option: " + e);
}
} catch (Throwable t) {
logger.warn("Failed to set a channel option: " + channel, t);
NetLog.warn("Failed to set a channel option: " + channel, t);
}
}
}

View file

@ -33,9 +33,8 @@ import common.net.channel.ChannelPipeline;
import common.net.channel.EventLoopGroup;
import common.net.channel.ServerChannel;
import common.net.util.AttributeKey;
import common.net.util.internal.NetLog;
import common.net.util.internal.StringUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* {@link Bootstrap} sub-class which allows easy bootstrap of {@link ServerChannel}
@ -43,8 +42,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public final class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, ServerChannel> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class);
private final Map<ChannelOption<?>, Object> childOptions = new LinkedHashMap<ChannelOption<?>, Object>();
private final Map<AttributeKey<?>, Object> childAttrs = new LinkedHashMap<AttributeKey<?>, Object>();
private volatile EventLoopGroup childGroup;
@ -193,7 +190,7 @@ public final class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, Se
throw new IllegalStateException("childHandler not set");
}
if (childGroup == null) {
logger.warn("childGroup is not set. Using parentGroup instead.");
NetLog.warn("childGroup is not set. Using parentGroup instead.");
childGroup = group();
}
return this;
@ -235,10 +232,10 @@ public final class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, Se
for (Entry<ChannelOption<?>, Object> e: childOptions) {
try {
if (!child.config().setOption((ChannelOption<Object>) e.getKey(), e.getValue())) {
logger.warn("Unknown channel option: " + e);
NetLog.warn("Unknown channel option: " + e);
}
} catch (Throwable t) {
logger.warn("Failed to set a channel option: " + child, t);
NetLog.warn("Failed to set a channel option: " + child, t);
}
}
@ -262,7 +259,7 @@ public final class ServerBootstrap extends AbstractBootstrap<ServerBootstrap, Se
private static void forceClose(Channel child, Throwable t) {
child.unsafe().closeForcibly();
logger.warn("Failed to register an accepted channel: " + child, t);
NetLog.warn("Failed to register an accepted channel: " + child, t);
}
@Override

View file

@ -28,17 +28,14 @@ import java.util.Locale;
import common.net.util.CharsetUtil;
import common.net.util.Recycler;
import common.net.util.Recycler.Handle;
import common.net.util.internal.NetLog;
import common.net.util.internal.SystemPropertyUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* A collection of utility methods that is related with handling {@link ByteBuf}.
*/
public final class ByteBufUtil {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ByteBufUtil.class);
private static final char[] HEXDUMP_TABLE = new char[256 * 4];
static final ByteBufAllocator DEFAULT_ALLOCATOR;
@ -56,19 +53,19 @@ public final class ByteBufUtil {
ByteBufAllocator alloc;
if ("unpooled".equals(allocType)) {
alloc = UnpooledByteBufAllocator.DEFAULT;
logger.debug("-Dgame.net.allocator.type: {}", allocType);
NetLog.debug("-Dgame.net.allocator.type: {}", allocType);
} else if ("pooled".equals(allocType)) {
alloc = PooledByteBufAllocator.DEFAULT;
logger.debug("-Dgame.net.allocator.type: {}", allocType);
NetLog.debug("-Dgame.net.allocator.type: {}", allocType);
} else {
alloc = UnpooledByteBufAllocator.DEFAULT;
logger.debug("-Dgame.net.allocator.type: unpooled (unknown: {})", allocType);
NetLog.debug("-Dgame.net.allocator.type: unpooled (unknown: {})", allocType);
}
DEFAULT_ALLOCATOR = alloc;
THREAD_LOCAL_BUFFER_SIZE = SystemPropertyUtil.getInt("game.net.threadLocalDirectBufferSize", 64 * 1024);
logger.debug("-Dgame.net.threadLocalDirectBufferSize: {}", THREAD_LOCAL_BUFFER_SIZE);
NetLog.debug("-Dgame.net.threadLocalDirectBufferSize: {}", THREAD_LOCAL_BUFFER_SIZE);
}
/**

View file

@ -20,8 +20,7 @@ package common.net.buffer;
import java.nio.ByteBuffer;
import common.net.util.ThreadDeathWatcher;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* Acts a Thread cache for allocations. This implementation is moduled after
@ -31,8 +30,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
final class PoolThreadCache {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PoolThreadCache.class);
final PoolArena<byte[]> heapArena;
final PoolArena<ByteBuffer> directArena;
@ -224,8 +221,8 @@ final class PoolThreadCache {
free(smallSubPageHeapCaches) +
free(normalHeapCaches);
if (numFreed > 0 && logger.isDebugEnabled()) {
logger.debug("Freed {} thread-local buffer(s) from thread: {}", numFreed, thread.getName());
if (numFreed > 0 && NetLog.isDebugEnabled()) {
NetLog.debug("Freed {} thread-local buffer(s) from thread: {}", numFreed, thread.getName());
}
}

View file

@ -20,13 +20,11 @@ import java.nio.ByteBuffer;
import java.util.concurrent.atomic.AtomicInteger;
import common.net.util.concurrent.FastThreadLocal;
import common.net.util.internal.NetLog;
import common.net.util.internal.SystemPropertyUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
public class PooledByteBufAllocator extends AbstractByteBufAllocator {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(PooledByteBufAllocator.class);
private static final int DEFAULT_NUM_HEAP_ARENA;
private static final int DEFAULT_NUM_DIRECT_ARENA;
@ -93,25 +91,25 @@ public class PooledByteBufAllocator extends AbstractByteBufAllocator {
DEFAULT_CACHE_TRIM_INTERVAL = SystemPropertyUtil.getInt(
"game.net.allocator.cacheTrimInterval", 8192);
if (logger.isDebugEnabled()) {
logger.debug("-Dgame.net.allocator.numHeapArenas: {}", DEFAULT_NUM_HEAP_ARENA);
logger.debug("-Dgame.net.allocator.numDirectArenas: {}", DEFAULT_NUM_DIRECT_ARENA);
if (NetLog.isDebugEnabled()) {
NetLog.debug("-Dgame.net.allocator.numHeapArenas: {}", DEFAULT_NUM_HEAP_ARENA);
NetLog.debug("-Dgame.net.allocator.numDirectArenas: {}", DEFAULT_NUM_DIRECT_ARENA);
if (pageSizeFallbackCause == null) {
logger.debug("-Dgame.net.allocator.pageSize: {}", DEFAULT_PAGE_SIZE);
NetLog.debug("-Dgame.net.allocator.pageSize: {}", DEFAULT_PAGE_SIZE);
} else {
logger.debug("-Dgame.net.allocator.pageSize: {}", DEFAULT_PAGE_SIZE, pageSizeFallbackCause);
NetLog.debug("-Dgame.net.allocator.pageSize: {}", DEFAULT_PAGE_SIZE, pageSizeFallbackCause);
}
if (maxOrderFallbackCause == null) {
logger.debug("-Dgame.net.allocator.maxOrder: {}", DEFAULT_MAX_ORDER);
NetLog.debug("-Dgame.net.allocator.maxOrder: {}", DEFAULT_MAX_ORDER);
} else {
logger.debug("-Dgame.net.allocator.maxOrder: {}", DEFAULT_MAX_ORDER, maxOrderFallbackCause);
NetLog.debug("-Dgame.net.allocator.maxOrder: {}", DEFAULT_MAX_ORDER, maxOrderFallbackCause);
}
logger.debug("-Dgame.net.allocator.chunkSize: {}", DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER);
logger.debug("-Dgame.net.allocator.tinyCacheSize: {}", DEFAULT_TINY_CACHE_SIZE);
logger.debug("-Dgame.net.allocator.smallCacheSize: {}", DEFAULT_SMALL_CACHE_SIZE);
logger.debug("-Dgame.net.allocator.normalCacheSize: {}", DEFAULT_NORMAL_CACHE_SIZE);
logger.debug("-Dgame.net.allocator.maxCachedBufferCapacity: {}", DEFAULT_MAX_CACHED_BUFFER_CAPACITY);
logger.debug("-Dgame.net.allocator.cacheTrimInterval: {}", DEFAULT_CACHE_TRIM_INTERVAL);
NetLog.debug("-Dgame.net.allocator.chunkSize: {}", DEFAULT_PAGE_SIZE << DEFAULT_MAX_ORDER);
NetLog.debug("-Dgame.net.allocator.tinyCacheSize: {}", DEFAULT_TINY_CACHE_SIZE);
NetLog.debug("-Dgame.net.allocator.smallCacheSize: {}", DEFAULT_SMALL_CACHE_SIZE);
NetLog.debug("-Dgame.net.allocator.normalCacheSize: {}", DEFAULT_NORMAL_CACHE_SIZE);
NetLog.debug("-Dgame.net.allocator.maxCachedBufferCapacity: {}", DEFAULT_MAX_CACHED_BUFFER_CAPACITY);
NetLog.debug("-Dgame.net.allocator.cacheTrimInterval: {}", DEFAULT_CACHE_TRIM_INTERVAL);
}
}

View file

@ -25,18 +25,15 @@ import common.net.buffer.ByteBufAllocator;
import common.net.util.DefaultAttributeMap;
import common.net.util.ReferenceCountUtil;
import common.net.util.internal.EmptyArrays;
import common.net.util.internal.NetLog;
import common.net.util.internal.OneTimeTask;
import common.net.util.internal.ThreadLocalRandom;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* A skeletal {@link Channel} implementation.
*/
public abstract class AbstractChannel extends DefaultAttributeMap implements Channel {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(AbstractChannel.class);
static final ClosedChannelException CLOSED_CHANNEL_EXCEPTION = new ClosedChannelException();
static final NotYetConnectedException NOT_YET_CONNECTED_EXCEPTION = new NotYetConnectedException();
@ -417,7 +414,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
}
});
} catch (Throwable t) {
logger.warn(
NetLog.warn(
"Force-closing a channel whose registration task was not accepted by an event loop: {}",
AbstractChannel.this, t);
closeForcibly();
@ -563,7 +560,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
try {
doClose();
} catch (Exception e) {
logger.warn("Failed to close a channel.", e);
NetLog.warn("Failed to close a channel.", e);
}
}
@ -581,7 +578,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
try {
doDeregister();
} catch (Throwable t) {
logger.warn("Unexpected exception occurred while deregistering a channel.", t);
NetLog.warn("Unexpected exception occurred while deregistering a channel.", t);
} finally {
if (registered) {
registered = false;
@ -719,7 +716,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
*/
protected final void safeSetSuccess(ChannelPromise promise) {
if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
NetLog.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
@ -728,7 +725,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
*/
protected final void safeSetFailure(ChannelPromise promise, Throwable cause) {
if (!(promise instanceof VoidChannelPromise) && !promise.tryFailure(cause)) {
logger.warn("Failed to mark a promise as failure because it's done already: {}", promise, cause);
NetLog.warn("Failed to mark a promise as failure because it's done already: {}", promise, cause);
}
}
@ -754,7 +751,7 @@ public abstract class AbstractChannel extends DefaultAttributeMap implements Cha
// which means the execution of two inbound handler methods of the same handler overlap undesirably.
eventLoop().execute(task);
} catch (RejectedExecutionException e) {
logger.warn("Can't invoke task later as EventLoop rejected it", e);
NetLog.warn("Can't invoke task later as EventLoop rejected it", e);
}
}
}

View file

@ -15,8 +15,6 @@
*/
package common.net.channel;
import static common.net.channel.DefaultChannelPipeline.logger;
import java.net.SocketAddress;
import common.net.buffer.ByteBufAllocator;
@ -25,6 +23,7 @@ import common.net.util.Recycler;
import common.net.util.ReferenceCountUtil;
import common.net.util.concurrent.EventExecutor;
import common.net.util.concurrent.EventExecutorGroup;
import common.net.util.internal.NetLog;
import common.net.util.internal.OneTimeTask;
import common.net.util.internal.RecyclableMpscLinkedQueueNode;
import common.net.util.internal.StringUtil;
@ -256,9 +255,9 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap impleme
}
});
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to submit an exceptionCaught() event.", t);
logger.warn("The exceptionCaught() event that was failed to submit was:", cause);
if (NetLog.isWarnEnabled()) {
NetLog.warn("Failed to submit an exceptionCaught() event.", t);
NetLog.warn("The exceptionCaught() event that was failed to submit was:", cause);
}
}
}
@ -270,8 +269,8 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap impleme
try {
handler().exceptionCaught(this, cause);
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn(
if (NetLog.isWarnEnabled()) {
NetLog.warn(
"An exception was thrown by a user handler's " +
"exceptionCaught() method while handling the following exception:", cause);
}
@ -749,16 +748,16 @@ abstract class AbstractChannelHandlerContext extends DefaultAttributeMap impleme
}
if (!promise.tryFailure(cause)) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to fail the promise because it's done already: {}", promise, cause);
if (NetLog.isWarnEnabled()) {
NetLog.warn("Failed to fail the promise because it's done already: {}", promise, cause);
}
}
}
private void notifyHandlerException(Throwable cause) {
if (inExceptionCaught(cause)) {
if (logger.isWarnEnabled()) {
logger.warn(
if (NetLog.isWarnEnabled()) {
NetLog.warn(
"An exception was thrown by a user handler " +
"while handling an exceptionCaught event", cause);
}

View file

@ -16,8 +16,7 @@
package common.net.channel;
import common.net.channel.ChannelHandler.Sharable;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* A special {@link ChannelInboundHandler} which offers an easy way to initialize a {@link Channel} once it was
@ -47,8 +46,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
@Sharable
public abstract class ChannelInitializer<C extends Channel> extends ChannelInboundHandlerAdapter {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelInitializer.class);
/**
* This method will be called once the {@link Channel} was registered. After the method returns this instance
* will be removed from the {@link ChannelPipeline} of the {@link Channel}.
@ -69,7 +66,7 @@ public abstract class ChannelInitializer<C extends Channel> extends ChannelInbou
ctx.fireChannelRegistered();
success = true;
} catch (Throwable t) {
logger.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);
NetLog.warn("Failed to initialize a channel. Closing: " + ctx.channel(), t);
} finally {
if (pipeline.context(this) != null) {
pipeline.remove(this);

View file

@ -27,8 +27,7 @@ import common.net.util.ReferenceCountUtil;
import common.net.util.Recycler.Handle;
import common.net.util.concurrent.FastThreadLocal;
import common.net.util.internal.InternalThreadLocalMap;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* (Transport implementors only) an internal data structure used by {@link AbstractChannel} to store its pending
@ -38,8 +37,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public final class ChannelOutboundBuffer {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ChannelOutboundBuffer.class);
private static final FastThreadLocal<ByteBuffer[]> NIO_BUFFERS = new FastThreadLocal<ByteBuffer[]>() {
@Override
protected ByteBuffer[] initialValue() throws Exception {
@ -518,13 +515,13 @@ public final class ChannelOutboundBuffer {
private static void safeSuccess(ChannelPromise promise) {
if (!(promise instanceof VoidChannelPromise) && !promise.trySuccess()) {
logger.warn("Failed to mark a promise as success because it is done already: {}", promise);
NetLog.warn("Failed to mark a promise as success because it is done already: {}", promise);
}
}
private static void safeFail(ChannelPromise promise, Throwable cause) {
if (!(promise instanceof VoidChannelPromise) && !promise.tryFailure(cause)) {
logger.warn("Failed to mark a promise as failure because it's done already: {}", promise, cause);
NetLog.warn("Failed to mark a promise as failure because it's done already: {}", promise, cause);
}
}

View file

@ -32,9 +32,8 @@ import common.net.channel.Channel.Unsafe;
import common.net.util.ReferenceCountUtil;
import common.net.util.concurrent.EventExecutor;
import common.net.util.concurrent.EventExecutorGroup;
import common.net.util.internal.NetLog;
import common.net.util.internal.StringUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.util.Util;
/**
@ -43,8 +42,6 @@ import common.util.Util;
*/
final class DefaultChannelPipeline implements ChannelPipeline {
static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultChannelPipeline.class);
private static final WeakHashMap<Class<?>, String>[] nameCaches =
new WeakHashMap[Runtime.getRuntime().availableProcessors()];
@ -490,8 +487,8 @@ final class DefaultChannelPipeline implements ChannelPipeline {
remove((AbstractChannelHandlerContext) ctx);
removed = true;
} catch (Throwable t2) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to remove a handler: " + ctx.name(), t2);
if (NetLog.isWarnEnabled()) {
NetLog.warn("Failed to remove a handler: " + ctx.name(), t2);
}
}
@ -968,7 +965,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception {
logger.warn(
NetLog.warn(
"An exceptionCaught() event was fired, and it reached at the tail of the pipeline. " +
"It usually means the last handler in the pipeline did not handle the exception.", cause);
}
@ -976,7 +973,7 @@ final class DefaultChannelPipeline implements ChannelPipeline {
@Override
public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
try {
logger.debug(
NetLog.debug(
"Discarded inbound message {} that reached at the tail of the pipeline. " +
"Please check your pipeline configuration.", msg);
} finally {

View file

@ -19,9 +19,8 @@ import java.util.concurrent.ThreadFactory;
import common.net.util.concurrent.DefaultThreadFactory;
import common.net.util.concurrent.MultithreadEventExecutorGroup;
import common.net.util.internal.NetLog;
import common.net.util.internal.SystemPropertyUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* Abstract base class for {@link EventLoopGroup} implementations that handles their tasks with multiple threads at
@ -29,16 +28,14 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public abstract class MultithreadEventLoopGroup extends MultithreadEventExecutorGroup implements EventLoopGroup {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(MultithreadEventLoopGroup.class);
private static final int DEFAULT_EVENT_LOOP_THREADS;
static {
DEFAULT_EVENT_LOOP_THREADS = Math.max(1, SystemPropertyUtil.getInt(
"game.net.eventLoopThreads", Runtime.getRuntime().availableProcessors() * 2));
if (logger.isDebugEnabled()) {
logger.debug("-Dgame.net.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
if (NetLog.isDebugEnabled()) {
NetLog.debug("-Dgame.net.eventLoopThreads: {}", DEFAULT_EVENT_LOOP_THREADS);
}
}

View file

@ -38,18 +38,14 @@ import common.net.channel.ConnectTimeoutException;
import common.net.channel.EventLoop;
import common.net.util.ReferenceCountUtil;
import common.net.util.ReferenceCounted;
import common.net.util.internal.NetLog;
import common.net.util.internal.OneTimeTask;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* Abstract base class for {@link Channel} implementations which use a Selector based approach.
*/
public abstract class AbstractNioChannel extends AbstractChannel {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(AbstractNioChannel.class);
private final SelectableChannel ch;
protected final int readInterestOp;
volatile SelectionKey selectionKey;
@ -81,8 +77,8 @@ public abstract class AbstractNioChannel extends AbstractChannel {
try {
ch.close();
} catch (IOException e2) {
if (logger.isWarnEnabled()) {
logger.warn(
if (NetLog.isWarnEnabled()) {
NetLog.warn(
"Failed to close a partially initialized socket.", e2);
}
}

View file

@ -38,9 +38,8 @@ import common.net.channel.EventLoopException;
import common.net.channel.SingleThreadEventLoop;
import common.net.channel.nio.AbstractNioChannel.NioUnsafe;
import common.net.util.internal.MpscLinkedQueue;
import common.net.util.internal.NetLog;
import common.net.util.internal.SystemPropertyUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* {@link SingleThreadEventLoop} implementation which register the {@link Channel}'s to a
@ -49,8 +48,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public final class NioEventLoop extends SingleThreadEventLoop {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioEventLoop.class);
private static final int CLEANUP_INTERVAL = 256; // XXX Hard-coded value, but won't need customization.
private static final boolean DISABLE_KEYSET_OPTIMIZATION =
@ -72,8 +69,8 @@ public final class NioEventLoop extends SingleThreadEventLoop {
System.setProperty(key, "");
}
} catch (SecurityException e) {
if (logger.isDebugEnabled()) {
logger.debug("Unable to get/set System Property: {}", key, e);
if (NetLog.isDebugEnabled()) {
NetLog.debug("Unable to get/set System Property: {}", key, e);
}
}
@ -84,9 +81,9 @@ public final class NioEventLoop extends SingleThreadEventLoop {
SELECTOR_AUTO_REBUILD_THRESHOLD = selectorAutoRebuildThreshold;
if (logger.isDebugEnabled()) {
logger.debug("-Dgame.net.noKeySetOptimization: {}", DISABLE_KEYSET_OPTIMIZATION);
logger.debug("-Dgame.net.selectorAutoRebuildThreshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD);
if (NetLog.isDebugEnabled()) {
NetLog.debug("-Dgame.net.noKeySetOptimization: {}", DISABLE_KEYSET_OPTIMIZATION);
NetLog.debug("-Dgame.net.selectorAutoRebuildThreshold: {}", SELECTOR_AUTO_REBUILD_THRESHOLD);
}
}
@ -152,10 +149,10 @@ public final class NioEventLoop extends SingleThreadEventLoop {
publicSelectedKeysField.set(selector, selectedKeySet);
selectedKeys = selectedKeySet;
logger.trace("Instrumented an optimized java.util.Set into: {}", selector);
NetLog.trace("Instrumented an optimized java.util.Set into: {}", selector);
} catch (Throwable t) {
selectedKeys = null;
logger.trace("Failed to instrument an optimized java.util.Set into: {}", selector, t);
NetLog.trace("Failed to instrument an optimized java.util.Set into: {}", selector, t);
}
return selector;
@ -241,7 +238,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
try {
newSelector = openSelector();
} catch (Exception e) {
logger.warn("Failed to create a new Selector.", e);
NetLog.warn("Failed to create a new Selector.", e);
return;
}
@ -265,7 +262,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
}
nChannels ++;
} catch (Exception e) {
logger.warn("Failed to re-register a Channel to the new Selector.", e);
NetLog.warn("Failed to re-register a Channel to the new Selector.", e);
if (a instanceof AbstractNioChannel) {
AbstractNioChannel ch = (AbstractNioChannel) a;
ch.unsafe().close(ch.unsafe().voidPromise());
@ -290,12 +287,12 @@ public final class NioEventLoop extends SingleThreadEventLoop {
// time to close the old selector as everything else is registered to the new one
oldSelector.close();
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to close the old Selector.", t);
if (NetLog.isWarnEnabled()) {
NetLog.warn("Failed to close the old Selector.", t);
}
}
logger.info("Migrated " + nChannels + " channel(s) to the new Selector.");
NetLog.info("Migrated " + nChannels + " channel(s) to the new Selector.");
}
@Override
@ -363,7 +360,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
}
}
} catch (Throwable t) {
logger.warn("Unexpected exception in the selector loop.", t);
NetLog.warn("Unexpected exception in the selector loop.", t);
// Prevent possible consecutive immediate failures that lead to
// excessive CPU consumption.
@ -389,7 +386,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
try {
selector.close();
} catch (IOException e) {
logger.warn("Failed to close a selector.", e);
NetLog.warn("Failed to close a selector.", e);
}
}
@ -580,7 +577,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
try {
task.channelUnregistered(k.channel(), cause);
} catch (Exception e) {
logger.warn("Unexpected exception while running NioTask.channelUnregistered()", e);
NetLog.warn("Unexpected exception while running NioTask.channelUnregistered()", e);
}
}
@ -634,8 +631,8 @@ public final class NioEventLoop extends SingleThreadEventLoop {
// also log it.
//
// See https://github.com/netty/netty/issues/2426
if (logger.isDebugEnabled()) {
logger.debug("Selector.select() returned prematurely because " +
if (NetLog.isDebugEnabled()) {
NetLog.debug("Selector.select() returned prematurely because " +
"Thread.currentThread().interrupt() was called. Use " +
"NioEventLoop.shutdownGracefully() to shutdown the NioEventLoop.");
}
@ -651,7 +648,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
selectCnt >= SELECTOR_AUTO_REBUILD_THRESHOLD) {
// The selector returned prematurely many times in a row.
// Rebuild the selector to work around the problem.
logger.warn(
NetLog.warn(
"Selector.select() returned prematurely {} times in a row; rebuilding selector.",
selectCnt);
@ -668,13 +665,13 @@ public final class NioEventLoop extends SingleThreadEventLoop {
}
if (selectCnt > MIN_PREMATURE_SELECTOR_RETURNS) {
if (logger.isDebugEnabled()) {
logger.debug("Selector.select() returned prematurely {} times in a row.", selectCnt - 1);
if (NetLog.isDebugEnabled()) {
NetLog.debug("Selector.select() returned prematurely {} times in a row.", selectCnt - 1);
}
}
} catch (CancelledKeyException e) {
if (logger.isDebugEnabled()) {
logger.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector - JDK bug?", e);
if (NetLog.isDebugEnabled()) {
NetLog.debug(CancelledKeyException.class.getSimpleName() + " raised by a Selector - JDK bug?", e);
}
// Harmless exception - log anyway
}
@ -685,7 +682,7 @@ public final class NioEventLoop extends SingleThreadEventLoop {
try {
selector.selectNow();
} catch (Throwable t) {
logger.warn("Failed to update SelectionKeys.", t);
NetLog.warn("Failed to update SelectionKeys.", t);
}
}
}

View file

@ -31,8 +31,7 @@ import common.net.channel.ChannelOutboundBuffer;
import common.net.channel.nio.AbstractNioMessageChannel;
import common.net.channel.socket.DefaultServerSocketChannelConfig;
import common.net.channel.socket.ServerSocketChannelConfig;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* A {@link game.net.channel.socket.ServerSocketChannel} implementation which uses
@ -44,8 +43,6 @@ public class NioServerSocketChannel extends AbstractNioMessageChannel
private static final ChannelMetadata METADATA = new ChannelMetadata(false);
private static final SelectorProvider DEFAULT_SELECTOR_PROVIDER = SelectorProvider.provider();
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NioServerSocketChannel.class);
private static ServerSocketChannel newSocket(SelectorProvider provider) {
try {
/**
@ -140,12 +137,12 @@ public class NioServerSocketChannel extends AbstractNioMessageChannel
return 1;
}
} catch (Throwable t) {
logger.warn("Failed to create a new channel from an accepted socket.", t);
NetLog.warn("Failed to create a new channel from an accepted socket.", t);
try {
ch.close();
} catch (Throwable t2) {
logger.warn("Failed to close a socket.", t2);
NetLog.warn("Failed to close a socket.", t2);
}
}

View file

@ -28,8 +28,7 @@ import java.util.Enumeration;
import java.util.List;
import java.util.StringTokenizer;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
import common.util.Util;
/**
@ -68,11 +67,6 @@ public final class NetUtil {
*/
public static final int SOMAXCONN;
/**
* The logger being used by this class
*/
private static final InternalLogger logger = InternalLoggerFactory.getInstance(NetUtil.class);
static {
byte[] LOCALHOST4_BYTES = {127, 0, 0, 1};
byte[] LOCALHOST6_BYTES = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1};
@ -108,7 +102,7 @@ public final class NetUtil {
}
}
} catch (SocketException e) {
logger.warn("Failed to retrieve the list of available network interfaces", e);
NetLog.warn("Failed to retrieve the list of available network interfaces", e);
}
// Find the first loopback interface available from its INET address (127.0.0.1 or ::1)
@ -144,16 +138,16 @@ public final class NetUtil {
}
if (loopbackIface == null) {
logger.warn("Failed to find the loopback interface");
NetLog.warn("Failed to find the loopback interface");
}
} catch (SocketException e) {
logger.warn("Failed to find the loopback interface", e);
NetLog.warn("Failed to find the loopback interface", e);
}
}
if (loopbackIface != null) {
// Found the loopback interface with an INET address.
logger.debug(
NetLog.debug(
"Loopback interface: {} ({}, {})",
loopbackIface.getName(), loopbackIface.getDisplayName(), loopbackAddr.getHostAddress());
} else {
@ -162,14 +156,14 @@ public final class NetUtil {
if (loopbackAddr == null) {
try {
if (NetworkInterface.getByInetAddress(LOCALHOST6) != null) {
logger.debug("Using hard-coded IPv6 localhost address: {}", localhost6);
NetLog.debug("Using hard-coded IPv6 localhost address: {}", localhost6);
loopbackAddr = localhost6;
}
} catch (Exception e) {
// Ignore
} finally {
if (loopbackAddr == null) {
logger.debug("Using hard-coded IPv4 localhost address: {}", localhost4);
NetLog.debug("Using hard-coded IPv4 localhost address: {}", localhost4);
loopbackAddr = localhost4;
}
}
@ -190,11 +184,11 @@ public final class NetUtil {
try {
in = new BufferedReader(new FileReader(file));
somaxconn = Integer.parseInt(in.readLine());
if (logger.isDebugEnabled()) {
logger.debug("{}: {}", file, somaxconn);
if (NetLog.isDebugEnabled()) {
NetLog.debug("{}: {}", file, somaxconn);
}
} catch (Exception e) {
logger.debug("Failed to get SOMAXCONN from: {}", file, e);
NetLog.debug("Failed to get SOMAXCONN from: {}", file, e);
} finally {
if (in != null) {
try {
@ -205,8 +199,8 @@ public final class NetUtil {
}
}
} else {
if (logger.isDebugEnabled()) {
logger.debug("{}: {} (non-existent)", file, somaxconn);
if (NetLog.isDebugEnabled()) {
NetLog.debug("{}: {} (non-existent)", file, somaxconn);
}
}

View file

@ -23,9 +23,8 @@ import java.util.WeakHashMap;
import java.util.concurrent.atomic.AtomicInteger;
import common.net.util.concurrent.FastThreadLocal;
import common.net.util.internal.NetLog;
import common.net.util.internal.SystemPropertyUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* Light-weight object pool based on a thread-local stack.
@ -34,8 +33,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public abstract class Recycler<T> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(Recycler.class);
private static final AtomicInteger ID_GENERATOR = new AtomicInteger(Integer.MIN_VALUE);
private static final int OWN_THREAD_ID = ID_GENERATOR.getAndIncrement();
private static final int DEFAULT_MAX_CAPACITY;
@ -52,8 +49,8 @@ public abstract class Recycler<T> {
}
DEFAULT_MAX_CAPACITY = maxCapacity;
if (logger.isDebugEnabled()) {
logger.debug("-Dgame.net.recycler.maxCapacity.default: {}", DEFAULT_MAX_CAPACITY);
if (NetLog.isDebugEnabled()) {
NetLog.debug("-Dgame.net.recycler.maxCapacity.default: {}", DEFAULT_MAX_CAPACITY);
}
INITIAL_CAPACITY = Math.min(DEFAULT_MAX_CAPACITY, 256);

View file

@ -15,17 +15,14 @@
*/
package common.net.util;
import common.net.util.internal.NetLog;
import common.net.util.internal.StringUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* Collection of method to handle objects that may implement {@link ReferenceCounted}.
*/
public final class ReferenceCountUtil {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ReferenceCountUtil.class);
/**
* Try to call {@link ReferenceCounted#retain()} if the specified message implements {@link ReferenceCounted}.
* If the specified message doesn't implement {@link ReferenceCounted}, this method does nothing.
@ -83,7 +80,7 @@ public final class ReferenceCountUtil {
try {
release(msg);
} catch (Throwable t) {
logger.warn("Failed to release a message: {}", msg, t);
NetLog.warn("Failed to release a message: {}", msg, t);
}
}
@ -98,8 +95,8 @@ public final class ReferenceCountUtil {
try {
release(msg, decrement);
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("Failed to release a message: {} (decrement: {})", msg, decrement, t);
if (NetLog.isWarnEnabled()) {
NetLog.warn("Failed to release a message: {} (decrement: {})", msg, decrement, t);
}
}
}
@ -142,12 +139,12 @@ public final class ReferenceCountUtil {
public void run() {
try {
if (!obj.release(decrement)) {
logger.warn("Non-zero refCnt: {}", this);
NetLog.warn("Non-zero refCnt: {}", this);
} else {
logger.debug("Released: {}", this);
NetLog.debug("Released: {}", this);
}
} catch (Exception ex) {
logger.warn("Failed to release an object: {}", obj, ex);
NetLog.warn("Failed to release an object: {}", obj, ex);
}
}

View file

@ -28,9 +28,8 @@ import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.atomic.AtomicBoolean;
import common.net.util.internal.NetLog;
import common.net.util.internal.SystemPropertyUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
public final class ResourceLeakDetector<T> {
@ -64,14 +63,12 @@ public final class ResourceLeakDetector<T> {
private static Level level;
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ResourceLeakDetector.class);
static {
final boolean disabled;
if (SystemPropertyUtil.get("game.net.noResourceLeakDetection") != null) {
disabled = SystemPropertyUtil.getBoolean("game.net.noResourceLeakDetection", false);
logger.debug("-Dgame.net.noResourceLeakDetection: {}", disabled);
logger.warn(
NetLog.debug("-Dgame.net.noResourceLeakDetection: {}", disabled);
NetLog.warn(
"-Dgame.net.noResourceLeakDetection is deprecated. Use '-D{}={}' instead.",
PROP_LEVEL, DEFAULT_LEVEL.name().toLowerCase());
} else {
@ -88,8 +85,8 @@ public final class ResourceLeakDetector<T> {
}
ResourceLeakDetector.level = level;
if (logger.isDebugEnabled()) {
logger.debug("-D{}: {}", PROP_LEVEL, level.name().toLowerCase());
if (NetLog.isDebugEnabled()) {
NetLog.debug("-D{}: {}", PROP_LEVEL, level.name().toLowerCase());
}
}
@ -191,7 +188,7 @@ public final class ResourceLeakDetector<T> {
}
private void reportLeak(Level level) {
if (!logger.isErrorEnabled()) {
if (!NetLog.isErrorEnabled()) {
for (;;) {
DefaultResourceLeak ref = (DefaultResourceLeak) refQueue.poll();
@ -206,7 +203,7 @@ public final class ResourceLeakDetector<T> {
// Report too many instances.
int samplingInterval = level == Level.PARANOID? 1 : this.samplingInterval;
if (active * samplingInterval > maxActive && loggedTooManyActive.compareAndSet(false, true)) {
logger.error("LEAK: You are creating too many " + resourceType + " instances. " +
NetLog.error("LEAK: You are creating too many " + resourceType + " instances. " +
resourceType + " is a shared resource that must be reused across the JVM," +
"so that only a few instances are created.");
}
@ -228,13 +225,13 @@ public final class ResourceLeakDetector<T> {
String records = ref.toString();
if (reportedLeaks.putIfAbsent(records, Boolean.TRUE) == null) {
if (records.isEmpty()) {
logger.error("LEAK: {}.release() was not called before it's garbage-collected. " +
NetLog.error("LEAK: {}.release() was not called before it's garbage-collected. " +
"Enable advanced leak reporting to find out where the leak occurred. " +
"To enable advanced leak reporting, " +
"specify the JVM option '-D{}={}' or call {}.setLevel()",
resourceType, PROP_LEVEL, Level.ADVANCED.name().toLowerCase(), simpleClassName(this));
} else {
logger.error(
NetLog.error(
"LEAK: {}.release() was not called before it's garbage-collected.{}",
resourceType, records);
}

View file

@ -26,8 +26,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import common.net.util.concurrent.DefaultThreadFactory;
import common.net.util.internal.MpscLinkedQueue;
import common.net.util.internal.MpscLinkedQueueNode;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* Checks if a thread is alive periodically and runs a task when a thread dies.
@ -39,7 +38,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public final class ThreadDeathWatcher {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ThreadDeathWatcher.class);
private static final ThreadFactory threadFactory =
new DefaultThreadFactory(ThreadDeathWatcher.class, true, Thread.MIN_PRIORITY);
@ -194,7 +192,7 @@ public final class ThreadDeathWatcher {
try {
e.task.run();
} catch (Throwable t) {
logger.warn("Thread death watcher task raised an exception:", t);
NetLog.warn("Thread death watcher task raised an exception:", t);
}
} else {
i ++;

View file

@ -24,17 +24,12 @@ import java.util.concurrent.TimeUnit;
import common.net.util.Signal;
import common.net.util.internal.EmptyArrays;
import common.net.util.internal.InternalThreadLocalMap;
import common.net.util.internal.NetLog;
import common.net.util.internal.StringUtil;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.util.Util;
public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(DefaultPromise.class);
private static final InternalLogger rejectedExecutionLogger =
InternalLoggerFactory.getInstance(DefaultPromise.class.getName() + ".rejectedExecution");
private static final int MAX_LISTENER_STACK_DEPTH = 8;
private static final Signal SUCCESS = Signal.valueOf(DefaultPromise.class.getName() + ".SUCCESS");
private static final Signal UNCANCELLABLE = Signal.valueOf(DefaultPromise.class.getName() + ".UNCANCELLABLE");
@ -670,7 +665,7 @@ public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
try {
executor.execute(task);
} catch (Throwable t) {
rejectedExecutionLogger.error("Failed to submit a listener notification task. Event loop shut down?", t);
NetLog.error("Failed to submit a listener notification task. Event loop shut down?", t);
}
}
@ -679,8 +674,8 @@ public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
try {
l.operationComplete(future);
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", t);
if (NetLog.isWarnEnabled()) {
NetLog.warn("An exception was thrown by " + l.getClass().getName() + ".operationComplete()", t);
}
}
}
@ -787,8 +782,8 @@ public class DefaultPromise<V> extends AbstractFuture<V> implements Promise<V> {
try {
l.operationProgressed(future, progress, total);
} catch (Throwable t) {
if (logger.isWarnEnabled()) {
logger.warn("An exception was thrown by " + l.getClass().getName() + ".operationProgressed()", t);
if (NetLog.isWarnEnabled()) {
NetLog.warn("An exception was thrown by " + l.getClass().getName() + ".operationProgressed()", t);
}
}
}

View file

@ -26,8 +26,7 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* Single-thread singleton {@link EventExecutor}. It starts the thread automatically and stops it when there is no
@ -36,8 +35,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public final class GlobalEventExecutor extends AbstractEventExecutor {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(GlobalEventExecutor.class);
private static final long SCHEDULE_PURGE_INTERVAL = TimeUnit.SECONDS.toNanos(1);
public static final GlobalEventExecutor INSTANCE = new GlobalEventExecutor();
@ -336,7 +333,7 @@ public final class GlobalEventExecutor extends AbstractEventExecutor {
try {
task.run();
} catch (Throwable t) {
logger.warn("Unexpected exception from the global event executor: ", t);
NetLog.warn("Unexpected exception from the global event executor: ", t);
}
if (task != purgeTask) {

View file

@ -32,8 +32,7 @@ import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.net.util.internal.NetLog;
/**
* Abstract base class for {@link EventExecutor}'s that execute all its submitted tasks in a single thread.
@ -41,9 +40,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
*/
public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
private static final InternalLogger logger =
InternalLoggerFactory.getInstance(SingleThreadEventExecutor.class);
private static final int ST_NOT_STARTED = 1;
private static final int ST_STARTED = 2;
private static final int ST_SHUTTING_DOWN = 3;
@ -115,7 +111,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
SingleThreadEventExecutor.this.run();
success = true;
} catch (Throwable t) {
logger.warn("Unexpected exception from an event executor: ", t);
NetLog.warn("Unexpected exception from an event executor: ", t);
} finally {
for (;;) {
int oldState = STATE_UPDATER.get(SingleThreadEventExecutor.this);
@ -126,7 +122,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
}
// Check if confirmShutdown() was called at the end of the loop.
if (success && gracefulShutdownStartTime == 0) {
logger.error(
NetLog.error(
"Buggy " + EventExecutor.class.getSimpleName() + " implementation; " +
SingleThreadEventExecutor.class.getSimpleName() + ".confirmShutdown() must be called " +
"before run() implementation terminates.");
@ -146,7 +142,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
STATE_UPDATER.set(SingleThreadEventExecutor.this, ST_TERMINATED);
threadLock.release();
if (!taskQueue.isEmpty()) {
logger.warn(
NetLog.warn(
"An event executor terminated with " +
"non-empty task queue (" + taskQueue.size() + ')');
}
@ -349,7 +345,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
try {
task.run();
} catch (Throwable t) {
logger.warn("A task raised an exception.", t);
NetLog.warn("A task raised an exception.", t);
}
task = pollTask();
@ -378,7 +374,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
try {
task.run();
} catch (Throwable t) {
logger.warn("A task raised an exception.", t);
NetLog.warn("A task raised an exception.", t);
}
runTasks ++;
@ -491,7 +487,7 @@ public abstract class SingleThreadEventExecutor extends AbstractEventExecutor {
try {
task.run();
} catch (Throwable t) {
logger.warn("Shutdown hook raised an exception.", t);
NetLog.warn("Shutdown hook raised an exception.", t);
} finally {
ran = true;
}

View file

@ -1,164 +1,28 @@
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
/**
* Copyright (c) 2004-2011 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package common.net.util.internal.logging;
package common.net.util.internal;
import java.util.HashMap;
import java.util.Map;
// contributors: lizongbo: proposed special treatment of array parameter values
// Joern Huxhorn: pointed out double[] omission, suggested deep array copy
import common.log.Log;
import common.log.LogLevel;
import common.util.Pair;
/**
* Formats messages according to very simple substitution rules. Substitutions
* can be made 1, 2 or more arguments.
* <p/>
* <p/>
* For example,
* <p/>
* <pre>
* MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;)
* </pre>
* <p/>
* will return the string "Hi there.".
* <p/>
* The {} pair is called the <em>formatting anchor</em>. It serves to designate
* the location where arguments need to be substituted within the message
* pattern.
* <p/>
* In case your message contains the '{' or the '}' character, you do not have
* to do anything special unless the '}' character immediately follows '{'. For
* example,
* <p/>
* <pre>
* MessageFormatter.format(&quot;Set {1,2,3} is not equal to {}.&quot;, &quot;1,2&quot;);
* </pre>
* <p/>
* will return the string "Set {1,2,3} is not equal to 1,2.".
* <p/>
* <p/>
* If for whatever reason you need to place the string "{}" in the message
* without its <em>formatting anchor</em> meaning, then you need to escape the
* '{' character with '\', that is the backslash character. Only the '{'
* character should be escaped. There is no need to escape the '}' character.
* For example,
* <p/>
* <pre>
* MessageFormatter.format(&quot;Set \\{} is not equal to {}.&quot;, &quot;1,2&quot;);
* </pre>
* <p/>
* will return the string "Set {} is not equal to 1,2.".
* <p/>
* <p/>
* The escaping behavior just described can be overridden by escaping the escape
* character '\'. Calling
* <p/>
* <pre>
* MessageFormatter.format(&quot;File name is C:\\\\{}.&quot;, &quot;file.zip&quot;);
* </pre>
* <p/>
* will return the string "File name is C:\file.zip".
* <p/>
* <p/>
* The formatting conventions are different than those of {@link MessageFormat}
* which ships with the Java platform. This is justified by the fact that
* SLF4J's implementation is 10 times faster than that of {@link MessageFormat}.
* This local performance difference is both measurable and significant in the
* larger context of the complete logging processing chain.
* <p/>
* <p/>
* See also {@link #format(String, Object)},
* {@link #format(String, Object, Object)} and
* {@link #arrayFormat(String, Object[])} methods for more details.
*/
final class MessageFormatter {
static final char DELIM_START = '{';
static final char DELIM_STOP = '}';
static final String DELIM_STR = "{}";
public abstract class NetLog {
private static final char DELIM_START = '{';
private static final char DELIM_STOP = '}';
private static final String DELIM_STR = "{}";
private static final char ESCAPE_CHAR = '\\';
/**
* Performs single argument substitution for the 'messagePattern' passed as
* parameter.
* <p/>
* For example,
* <p/>
* <pre>
* MessageFormatter.format(&quot;Hi {}.&quot;, &quot;there&quot;);
* </pre>
* <p/>
* will return the string "Hi there.".
* <p/>
*
* @param messagePattern The message pattern which will be parsed and formatted
* @param arg The argument to be substituted in place of the formatting anchor
* @return The formatted message
*/
static FormattingTuple format(String messagePattern, Object arg) {
private static Pair<String, Throwable> format(String messagePattern, Object arg) {
return arrayFormat(messagePattern, new Object[]{arg});
}
/**
* Performs a two argument substitution for the 'messagePattern' passed as
* parameter.
* <p/>
* For example,
* <p/>
* <pre>
* MessageFormatter.format(&quot;Hi {}. My name is {}.&quot;, &quot;Alice&quot;, &quot;Bob&quot;);
* </pre>
* <p/>
* will return the string "Hi Alice. My name is Bob.".
*
* @param messagePattern The message pattern which will be parsed and formatted
* @param argA The argument to be substituted in place of the first formatting
* anchor
* @param argB The argument to be substituted in place of the second formatting
* anchor
* @return The formatted message
*/
static FormattingTuple format(final String messagePattern,
private static Pair<String, Throwable> format(final String messagePattern,
Object argA, Object argB) {
return arrayFormat(messagePattern, new Object[]{argA, argB});
}
static Throwable getThrowableCandidate(Object[] argArray) {
private static Throwable getThrowableCandidate(Object[] argArray) {
if (argArray == null || argArray.length == 0) {
return null;
}
@ -170,27 +34,17 @@ final class MessageFormatter {
return null;
}
/**
* Same principle as the {@link #format(String, Object)} and
* {@link #format(String, Object, Object)} methods except that any number of
* arguments can be passed in an array.
*
* @param messagePattern The message pattern which will be parsed and formatted
* @param argArray An array of arguments to be substituted in place of formatting
* anchors
* @return The formatted message
*/
static FormattingTuple arrayFormat(final String messagePattern,
private static Pair<String, Throwable> arrayFormat(final String messagePattern,
final Object[] argArray) {
Throwable throwableCandidate = getThrowableCandidate(argArray);
if (messagePattern == null) {
return new FormattingTuple(null, argArray, throwableCandidate);
return new Pair<String, Throwable>("Error:", throwableCandidate);
}
if (argArray == null) {
return new FormattingTuple(messagePattern);
return new Pair<String, Throwable>(messagePattern, null);
}
int i = 0;
@ -205,13 +59,11 @@ final class MessageFormatter {
if (j == -1) {
// no more variables
if (i == 0) { // this is a simple string
return new FormattingTuple(messagePattern, argArray,
throwableCandidate);
return new Pair<String, Throwable>(messagePattern, throwableCandidate);
} else { // add the tail string which contains no variables and return
// the result.
sbuf.append(messagePattern.substring(i, messagePattern.length()));
return new FormattingTuple(sbuf.toString(), argArray,
throwableCandidate);
return new Pair<String, Throwable>(sbuf.toString(), throwableCandidate);
}
} else {
if (isEscapedDelimeter(messagePattern, j)) {
@ -239,13 +91,13 @@ final class MessageFormatter {
// append the characters following the last {} pair.
sbuf.append(messagePattern.substring(i, messagePattern.length()));
if (L < argArray.length - 1) {
return new FormattingTuple(sbuf.toString(), argArray, throwableCandidate);
return new Pair<String, Throwable>(sbuf.toString(), throwableCandidate);
} else {
return new FormattingTuple(sbuf.toString(), argArray, null);
return new Pair<String, Throwable>(sbuf.toString(), null);
}
}
static boolean isEscapedDelimeter(String messagePattern,
private static boolean isEscapedDelimeter(String messagePattern,
int delimeterStartIndex) {
if (delimeterStartIndex == 0) {
@ -254,7 +106,7 @@ final class MessageFormatter {
return messagePattern.charAt(delimeterStartIndex - 1) == ESCAPE_CHAR;
}
static boolean isDoubleEscaped(String messagePattern,
private static boolean isDoubleEscaped(String messagePattern,
int delimeterStartIndex) {
return delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR;
}
@ -421,7 +273,126 @@ final class MessageFormatter {
}
sbuf.append(']');
}
public static boolean isDebugEnabled() {
return Log.getLevel().ordinal() >= LogLevel.DEBUG.ordinal();
}
private MessageFormatter() {
}
public static boolean isWarnEnabled() {
return Log.getLevel().ordinal() >= LogLevel.WARN.ordinal();
}
public static boolean isErrorEnabled() {
return Log.getLevel().ordinal() >= LogLevel.ERROR.ordinal();
}
public static void trace(String format, Object arg) {
Pair<String, Throwable> ft = format(format, arg);
if(ft.second() == null)
Log.NETWORK.trace(ft.first());
else if(Log.getLevel().ordinal() >= LogLevel.TRACE.ordinal())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void trace(String format, Object argA, Object argB) {
Pair<String, Throwable> ft = format(format, argA, argB);
if(ft.second() == null)
Log.NETWORK.trace(ft.first());
else if(Log.getLevel().ordinal() >= LogLevel.TRACE.ordinal())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void debug(String msg) {
Log.NETWORK.debug(msg);
}
public static void debug(String format, Object arg) {
Pair<String, Throwable> ft = format(format, arg);
if(ft.second() == null)
Log.NETWORK.debug(ft.first());
else if(isDebugEnabled())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void debug(String format, Object argA, Object argB) {
Pair<String, Throwable> ft = format(format, argA, argB);
if(ft.second() == null)
Log.NETWORK.debug(ft.first());
else if(isDebugEnabled())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void debug(String format, Object... argArray) {
Pair<String, Throwable> ft = arrayFormat(format, argArray);
if(ft.second() == null)
Log.NETWORK.debug(ft.first());
else if(isDebugEnabled())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void debug(String msg, Throwable t) {
if(isDebugEnabled())
Log.NETWORK.error(t, msg);
}
public static void info(String msg) {
Log.NETWORK.info(msg);
}
public static void warn(String msg) {
Log.NETWORK.warn(msg);
}
public static void warn(String format, Object arg) {
Pair<String, Throwable> ft = format(format, arg);
if(ft.second() == null)
Log.NETWORK.warn(ft.first());
else if(isWarnEnabled())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void warn(String format, Object argA, Object argB) {
Pair<String, Throwable> ft = format(format, argA, argB);
if(ft.second() == null)
Log.NETWORK.warn(ft.first());
else if(isWarnEnabled())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void warn(String format, Object... argArray) {
Pair<String, Throwable> ft = arrayFormat(format, argArray);
if(ft.second() == null)
Log.NETWORK.warn(ft.first());
else if(isWarnEnabled())
Log.NETWORK.error(ft.second(), ft.first());
}
public static void warn(String msg, Throwable t) {
if(isWarnEnabled())
Log.NETWORK.error(t, msg);
}
public static void error(String msg) {
Log.NETWORK.error(msg);
}
public static void error(String format, Object argA, Object argB) {
Pair<String, Throwable> ft = format(format, argA, argB);
if(ft.second() == null)
Log.NETWORK.error(ft.first());
else
Log.NETWORK.error(ft.second(), ft.first());
}
public static void error(String format, Object... arguments) {
Pair<String, Throwable> ft = arrayFormat(format, arguments);
if(ft.second() == null)
Log.NETWORK.error(ft.first());
else
Log.NETWORK.error(ft.second(), ft.first());
}
public static void error(String msg, Throwable t) {
Log.NETWORK.error(t, msg);
}
}

View file

@ -15,28 +15,17 @@
*/
package common.net.util.internal;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.regex.Pattern;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
import common.log.Log;
/**
* A collection of utility methods to retrieve and parse the values of the Java system properties.
*/
public final class SystemPropertyUtil {
private static boolean initializedLogger;
private static final InternalLogger logger;
private static boolean loggedException;
static {
initializedLogger = false;
logger = InternalLoggerFactory.getInstance(SystemPropertyUtil.class);
initializedLogger = true;
}
/**
* Returns {@code true} if and only if the system property with the specified {@code key}
* exists.
@ -189,21 +178,11 @@ public final class SystemPropertyUtil {
}
private static void log(String msg) {
if (initializedLogger) {
logger.warn(msg);
} else {
// Use JDK logging if logger was not initialized yet.
Logger.getLogger(SystemPropertyUtil.class.getName()).log(Level.WARNING, msg);
}
Log.NETWORK.warn(msg);
}
private static void log(String msg, Exception e) {
if (initializedLogger) {
logger.warn(msg, e);
} else {
// Use JDK logging if logger was not initialized yet.
Logger.getLogger(SystemPropertyUtil.class.getName()).log(Level.WARNING, msg, e);
}
Log.NETWORK.error(e, msg);
}
private SystemPropertyUtil() {

View file

@ -30,9 +30,6 @@ import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicLong;
import common.net.util.internal.logging.InternalLogger;
import common.net.util.internal.logging.InternalLoggerFactory;
/**
* A random number generator isolated to the current thread. Like the
* global {@link java.util.Random} generator used by the {@link
@ -60,8 +57,6 @@ import common.net.util.internal.logging.InternalLoggerFactory;
public final class ThreadLocalRandom extends Random {
private static final InternalLogger logger = InternalLoggerFactory.getInstance(ThreadLocalRandom.class);
private static final AtomicLong seedUniquifier = new AtomicLong();
private static volatile long initialSeedUniquifier;
@ -96,7 +91,7 @@ public final class ThreadLocalRandom extends Random {
generatorThread.setUncaughtExceptionHandler(new UncaughtExceptionHandler() {
@Override
public void uncaughtException(Thread t, Throwable e) {
logger.debug("An exception has been raised by {}", t.getName(), e);
NetLog.debug("An exception has been raised by {}", t.getName(), e);
}
});
@ -108,7 +103,7 @@ public final class ThreadLocalRandom extends Random {
long waitTime = deadLine - System.nanoTime();
if (waitTime <= 0) {
generatorThread.interrupt();
logger.warn(
NetLog.warn(
"Failed to generate a seed from SecureRandom within {} seconds. " +
"Not enough entrophy?", timeoutSeconds
);
@ -131,7 +126,7 @@ public final class ThreadLocalRandom extends Random {
}
} catch (InterruptedException e) {
interrupted = true;
logger.warn("Failed to generate a seed from SecureRandom due to an InterruptedException.");
NetLog.warn("Failed to generate a seed from SecureRandom due to an InterruptedException.");
break;
}
}
@ -165,8 +160,8 @@ public final class ThreadLocalRandom extends Random {
final long next = actualCurrent * 181783497276652981L;
if (seedUniquifier.compareAndSet(current, next)) {
if (current == 0 && logger.isDebugEnabled()) {
logger.debug(String.format(
if (current == 0 && NetLog.isDebugEnabled()) {
NetLog.debug(String.format(
"-Dgame.net.initialSeedUniquifier: 0x%016x (took %d ms)",
actualCurrent, TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime)));
}

View file

@ -1,190 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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 common.net.util.internal.logging;
import java.io.ObjectStreamException;
import java.io.Serializable;
import common.net.util.internal.StringUtil;
/**
* A skeletal implementation of {@link InternalLogger}. This class implements
* all methods that have a {@link InternalLogLevel} parameter by default to call
* specific logger methods such as {@link #info(String)} or {@link #isInfoEnabled()}.
*/
public abstract class AbstractInternalLogger implements InternalLogger, Serializable {
private static final long serialVersionUID = -6382972526573193470L;
private final String name;
/**
* Creates a new instance.
*/
protected AbstractInternalLogger(String name) {
if (name == null) {
throw new NullPointerException("name");
}
this.name = name;
}
@Override
public String name() {
return name;
}
@Override
public boolean isEnabled(InternalLogLevel level) {
switch (level) {
case TRACE:
return isTraceEnabled();
case DEBUG:
return isDebugEnabled();
case INFO:
return isInfoEnabled();
case WARN:
return isWarnEnabled();
case ERROR:
return isErrorEnabled();
default:
throw new Error();
}
}
@Override
public void log(InternalLogLevel level, String msg, Throwable cause) {
switch (level) {
case TRACE:
trace(msg, cause);
break;
case DEBUG:
debug(msg, cause);
break;
case INFO:
info(msg, cause);
break;
case WARN:
warn(msg, cause);
break;
case ERROR:
error(msg, cause);
break;
default:
throw new Error();
}
}
@Override
public void log(InternalLogLevel level, String msg) {
switch (level) {
case TRACE:
trace(msg);
break;
case DEBUG:
debug(msg);
break;
case INFO:
info(msg);
break;
case WARN:
warn(msg);
break;
case ERROR:
error(msg);
break;
default:
throw new Error();
}
}
@Override
public void log(InternalLogLevel level, String format, Object arg) {
switch (level) {
case TRACE:
trace(format, arg);
break;
case DEBUG:
debug(format, arg);
break;
case INFO:
info(format, arg);
break;
case WARN:
warn(format, arg);
break;
case ERROR:
error(format, arg);
break;
default:
throw new Error();
}
}
@Override
public void log(InternalLogLevel level, String format, Object argA, Object argB) {
switch (level) {
case TRACE:
trace(format, argA, argB);
break;
case DEBUG:
debug(format, argA, argB);
break;
case INFO:
info(format, argA, argB);
break;
case WARN:
warn(format, argA, argB);
break;
case ERROR:
error(format, argA, argB);
break;
default:
throw new Error();
}
}
@Override
public void log(InternalLogLevel level, String format, Object... arguments) {
switch (level) {
case TRACE:
trace(format, arguments);
break;
case DEBUG:
debug(format, arguments);
break;
case INFO:
info(format, arguments);
break;
case WARN:
warn(format, arguments);
break;
case ERROR:
error(format, arguments);
break;
default:
throw new Error();
}
}
protected Object readResolve() throws ObjectStreamException {
return InternalLoggerFactory.getInstance(name());
}
@Override
public String toString() {
return StringUtil.simpleClassName(this) + '(' + name() + ')';
}
}

View file

@ -1,88 +0,0 @@
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
/**
* Copyright (c) 2004-2011 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package common.net.util.internal.logging;
/**
* Holds the results of formatting done by {@link MessageFormatter}.
*/
class FormattingTuple {
static final FormattingTuple NULL = new FormattingTuple(null);
private final String message;
private final Throwable throwable;
private final Object[] argArray;
FormattingTuple(String message) {
this(message, null, null);
}
FormattingTuple(String message, Object[] argArray, Throwable throwable) {
this.message = message;
this.throwable = throwable;
if (throwable == null) {
this.argArray = argArray;
} else {
this.argArray = trimmedCopy(argArray);
}
}
static Object[] trimmedCopy(Object[] argArray) {
if (argArray == null || argArray.length == 0) {
throw new IllegalStateException("non-sensical empty or null argument array");
}
final int trimemdLen = argArray.length - 1;
Object[] trimmed = new Object[trimemdLen];
System.arraycopy(argArray, 0, trimmed, 0, trimemdLen);
return trimmed;
}
public String getMessage() {
return message;
}
public Object[] getArgArray() {
return argArray;
}
public Throwable getThrowable() {
return throwable;
}
}

View file

@ -1,42 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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 common.net.util.internal.logging;
/**
* The log level that {@link InternalLogger} can log at.
*/
public enum InternalLogLevel {
/**
* 'TRACE' log level.
*/
TRACE,
/**
* 'DEBUG' log level.
*/
DEBUG,
/**
* 'INFO' log level.
*/
INFO,
/**
* 'WARN' log level.
*/
WARN,
/**
* 'ERROR' log level.
*/
ERROR
}

View file

@ -1,444 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
/**
* Copyright (c) 2004-2011 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package common.net.util.internal.logging;
/**
* <em>Internal-use-only</em> logger used by Netty. <strong>DO NOT</strong>
* access this class outside of Netty.
*/
public interface InternalLogger {
/**
* Return the name of this {@link InternalLogger} instance.
*
* @return name of this logger instance
*/
String name();
/**
* Is the logger instance enabled for the TRACE level?
*
* @return True if this Logger is enabled for the TRACE level,
* false otherwise.
*/
boolean isTraceEnabled();
/**
* Log a message at the TRACE level.
*
* @param msg the message string to be logged
*/
void trace(String msg);
/**
* Log a message at the TRACE level according to the specified format
* and argument.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the TRACE level. </p>
*
* @param format the format string
* @param arg the argument
*/
void trace(String format, Object arg);
/**
* Log a message at the TRACE level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the TRACE level. </p>
*
* @param format the format string
* @param argA the first argument
* @param argB the second argument
*/
void trace(String format, Object argA, Object argB);
/**
* Log a message at the TRACE level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the TRACE level. However, this variant incurs the hidden
* (and relatively small) cost of creating an {@code Object[]} before invoking the method,
* even if this logger is disabled for TRACE. The variants taking {@link #trace(String, Object) one} and
* {@link #trace(String, Object, Object) two} arguments exist solely in order to avoid this hidden cost.</p>
*
* @param format the format string
* @param arguments a list of 3 or more arguments
*/
void trace(String format, Object... arguments);
/**
* Log an exception (throwable) at the TRACE level with an
* accompanying message.
*
* @param msg the message accompanying the exception
* @param t the exception (throwable) to log
*/
void trace(String msg, Throwable t);
/**
* Is the logger instance enabled for the DEBUG level?
*
* @return True if this Logger is enabled for the DEBUG level,
* false otherwise.
*/
boolean isDebugEnabled();
/**
* Log a message at the DEBUG level.
*
* @param msg the message string to be logged
*/
void debug(String msg);
/**
* Log a message at the DEBUG level according to the specified format
* and argument.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the DEBUG level. </p>
*
* @param format the format string
* @param arg the argument
*/
void debug(String format, Object arg);
/**
* Log a message at the DEBUG level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the DEBUG level. </p>
*
* @param format the format string
* @param argA the first argument
* @param argB the second argument
*/
void debug(String format, Object argA, Object argB);
/**
* Log a message at the DEBUG level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the DEBUG level. However, this variant incurs the hidden
* (and relatively small) cost of creating an {@code Object[]} before invoking the method,
* even if this logger is disabled for DEBUG. The variants taking
* {@link #debug(String, Object) one} and {@link #debug(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*
* @param format the format string
* @param arguments a list of 3 or more arguments
*/
void debug(String format, Object... arguments);
/**
* Log an exception (throwable) at the DEBUG level with an
* accompanying message.
*
* @param msg the message accompanying the exception
* @param t the exception (throwable) to log
*/
void debug(String msg, Throwable t);
/**
* Is the logger instance enabled for the INFO level?
*
* @return True if this Logger is enabled for the INFO level,
* false otherwise.
*/
boolean isInfoEnabled();
/**
* Log a message at the INFO level.
*
* @param msg the message string to be logged
*/
void info(String msg);
/**
* Log a message at the INFO level according to the specified format
* and argument.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the INFO level. </p>
*
* @param format the format string
* @param arg the argument
*/
void info(String format, Object arg);
/**
* Log a message at the INFO level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the INFO level. </p>
*
* @param format the format string
* @param argA the first argument
* @param argB the second argument
*/
void info(String format, Object argA, Object argB);
/**
* Log a message at the INFO level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the INFO level. However, this variant incurs the hidden
* (and relatively small) cost of creating an {@code Object[]} before invoking the method,
* even if this logger is disabled for INFO. The variants taking
* {@link #info(String, Object) one} and {@link #info(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*
* @param format the format string
* @param arguments a list of 3 or more arguments
*/
void info(String format, Object... arguments);
/**
* Log an exception (throwable) at the INFO level with an
* accompanying message.
*
* @param msg the message accompanying the exception
* @param t the exception (throwable) to log
*/
void info(String msg, Throwable t);
/**
* Is the logger instance enabled for the WARN level?
*
* @return True if this Logger is enabled for the WARN level,
* false otherwise.
*/
boolean isWarnEnabled();
/**
* Log a message at the WARN level.
*
* @param msg the message string to be logged
*/
void warn(String msg);
/**
* Log a message at the WARN level according to the specified format
* and argument.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the WARN level. </p>
*
* @param format the format string
* @param arg the argument
*/
void warn(String format, Object arg);
/**
* Log a message at the WARN level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the WARN level. However, this variant incurs the hidden
* (and relatively small) cost of creating an {@code Object[]} before invoking the method,
* even if this logger is disabled for WARN. The variants taking
* {@link #warn(String, Object) one} and {@link #warn(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*
* @param format the format string
* @param arguments a list of 3 or more arguments
*/
void warn(String format, Object... arguments);
/**
* Log a message at the WARN level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the WARN level. </p>
*
* @param format the format string
* @param argA the first argument
* @param argB the second argument
*/
void warn(String format, Object argA, Object argB);
/**
* Log an exception (throwable) at the WARN level with an
* accompanying message.
*
* @param msg the message accompanying the exception
* @param t the exception (throwable) to log
*/
void warn(String msg, Throwable t);
/**
* Is the logger instance enabled for the ERROR level?
*
* @return True if this Logger is enabled for the ERROR level,
* false otherwise.
*/
boolean isErrorEnabled();
/**
* Log a message at the ERROR level.
*
* @param msg the message string to be logged
*/
void error(String msg);
/**
* Log a message at the ERROR level according to the specified format
* and argument.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the ERROR level. </p>
*
* @param format the format string
* @param arg the argument
*/
void error(String format, Object arg);
/**
* Log a message at the ERROR level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the ERROR level. </p>
*
* @param format the format string
* @param argA the first argument
* @param argB the second argument
*/
void error(String format, Object argA, Object argB);
/**
* Log a message at the ERROR level according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the ERROR level. However, this variant incurs the hidden
* (and relatively small) cost of creating an {@code Object[]} before invoking the method,
* even if this logger is disabled for ERROR. The variants taking
* {@link #error(String, Object) one} and {@link #error(String, Object, Object) two}
* arguments exist solely in order to avoid this hidden cost.</p>
*
* @param format the format string
* @param arguments a list of 3 or more arguments
*/
void error(String format, Object... arguments);
/**
* Log an exception (throwable) at the ERROR level with an
* accompanying message.
*
* @param msg the message accompanying the exception
* @param t the exception (throwable) to log
*/
void error(String msg, Throwable t);
/**
* Is the logger instance enabled for the specified {@code level}?
*
* @return True if this Logger is enabled for the specified {@code level},
* false otherwise.
*/
boolean isEnabled(InternalLogLevel level);
/**
* Log a message at the specified {@code level}.
*
* @param msg the message string to be logged
*/
void log(InternalLogLevel level, String msg);
/**
* Log a message at the specified {@code level} according to the specified format
* and argument.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the specified {@code level}. </p>
*
* @param format the format string
* @param arg the argument
*/
void log(InternalLogLevel level, String format, Object arg);
/**
* Log a message at the specified {@code level} according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous object creation when the logger
* is disabled for the specified {@code level}. </p>
*
* @param format the format string
* @param argA the first argument
* @param argB the second argument
*/
void log(InternalLogLevel level, String format, Object argA, Object argB);
/**
* Log a message at the specified {@code level} according to the specified format
* and arguments.
* <p/>
* <p>This form avoids superfluous string concatenation when the logger
* is disabled for the specified {@code level}. However, this variant incurs the hidden
* (and relatively small) cost of creating an {@code Object[]} before invoking the method,
* even if this logger is disabled for the specified {@code level}. The variants taking
* {@link #log(InternalLogLevel, String, Object) one} and
* {@link #log(InternalLogLevel, String, Object, Object) two} arguments exist solely
* in order to avoid this hidden cost.</p>
*
* @param format the format string
* @param arguments a list of 3 or more arguments
*/
void log(InternalLogLevel level, String format, Object... arguments);
/**
* Log an exception (throwable) at the specified {@code level} with an
* accompanying message.
*
* @param msg the message accompanying the exception
* @param t the exception (throwable) to log
*/
void log(InternalLogLevel level, String msg, Throwable t);
}

View file

@ -1,91 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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 common.net.util.internal.logging;
/**
* Creates an {@link InternalLogger} or changes the default factory
* implementation. This factory allows you to choose what logging framework
* Netty should use. The default factory is {@link Slf4JLoggerFactory}. If SLF4J
* is not available, {@link Log4JLoggerFactory} is used. If Log4J is not available,
* {@link JdkLoggerFactory} is used. You can change it to your preferred
* logging framework before other Netty classes are loaded:
* <pre>
* {@link InternalLoggerFactory}.setDefaultFactory(new {@link Log4JLoggerFactory}());
* </pre>
* Please note that the new default factory is effective only for the classes
* which were loaded after the default factory is changed. Therefore,
* {@link #setDefaultFactory(InternalLoggerFactory)} should be called as early
* as possible and shouldn't be called more than once.
*/
public abstract class InternalLoggerFactory {
private static volatile InternalLoggerFactory defaultFactory =
newDefaultFactory(InternalLoggerFactory.class.getName());
//
private static InternalLoggerFactory newDefaultFactory(String name) {
InternalLoggerFactory f;
// try {
// f = new Slf4JLoggerFactory(true);
// f.newInstance(name).debug("Using SLF4J as the default logging framework");
// } catch (Throwable t1) {
// try {
// f = new Log4JLoggerFactory();
// f.newInstance(name).debug("Using Log4J as the default logging framework");
// } catch (Throwable t2) {
f = new JdkLoggerFactory();
f.newInstance(name).debug("Using java.util.logging as the default logging framework");
// }
// }
return f;
}
/**
* Returns the default factory. The initial default factory is
* {@link JdkLoggerFactory}.
*/
public static InternalLoggerFactory getDefaultFactory() {
return defaultFactory;
}
/**
* Changes the default factory.
*/
public static void setDefaultFactory(InternalLoggerFactory defaultFactory) {
if (defaultFactory == null) {
throw new NullPointerException("defaultFactory");
}
InternalLoggerFactory.defaultFactory = defaultFactory;
}
/**
* Creates a new logger instance with the name of the specified class.
*/
public static InternalLogger getInstance(Class<?> clazz) {
return getInstance(clazz.getName());
}
/**
* Creates a new logger instance with the specified name.
*/
public static InternalLogger getInstance(String name) {
return getDefaultFactory().newInstance(name);
}
/**
* Creates a new logger instance with the specified name.
*/
protected abstract InternalLogger newInstance(String name);
}

View file

@ -1,647 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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.
*/
/**
* Copyright (c) 2004-2011 QOS.ch
* All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice shall be
* included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
* LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
* OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
* WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
*
*/
package common.net.util.internal.logging;
import java.util.logging.Level;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
/**
* <a href="http://java.sun.com/javase/6/docs/technotes/guides/logging/index.html">java.util.logging</a>
* logger.
*/
class JdkLogger extends AbstractInternalLogger {
private static final long serialVersionUID = -1767272577989225979L;
final transient Logger logger;
JdkLogger(Logger logger) {
super(logger.getName());
this.logger = logger;
}
/**
* Is this logger instance enabled for the FINEST level?
*
* @return True if this Logger is enabled for level FINEST, false otherwise.
*/
@Override
public boolean isTraceEnabled() {
return logger.isLoggable(Level.FINEST);
}
/**
* Log a message object at level FINEST.
*
* @param msg
* - the message object to be logged
*/
@Override
public void trace(String msg) {
if (logger.isLoggable(Level.FINEST)) {
log(SELF, Level.FINEST, msg, null);
}
}
/**
* Log a message at level FINEST according to the specified format and
* argument.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for level FINEST.
* </p>
*
* @param format
* the format string
* @param arg
* the argument
*/
@Override
public void trace(String format, Object arg) {
if (logger.isLoggable(Level.FINEST)) {
FormattingTuple ft = MessageFormatter.format(format, arg);
log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at level FINEST according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the FINEST level.
* </p>
*
* @param format
* the format string
* @param argA
* the first argument
* @param argB
* the second argument
*/
@Override
public void trace(String format, Object argA, Object argB) {
if (logger.isLoggable(Level.FINEST)) {
FormattingTuple ft = MessageFormatter.format(format, argA, argB);
log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at level FINEST according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the FINEST level.
* </p>
*
* @param format
* the format string
* @param argArray
* an array of arguments
*/
@Override
public void trace(String format, Object... argArray) {
if (logger.isLoggable(Level.FINEST)) {
FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
log(SELF, Level.FINEST, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log an exception (throwable) at level FINEST with an accompanying message.
*
* @param msg
* the message accompanying the exception
* @param t
* the exception (throwable) to log
*/
@Override
public void trace(String msg, Throwable t) {
if (logger.isLoggable(Level.FINEST)) {
log(SELF, Level.FINEST, msg, t);
}
}
/**
* Is this logger instance enabled for the FINE level?
*
* @return True if this Logger is enabled for level FINE, false otherwise.
*/
@Override
public boolean isDebugEnabled() {
return logger.isLoggable(Level.FINE);
}
/**
* Log a message object at level FINE.
*
* @param msg
* - the message object to be logged
*/
@Override
public void debug(String msg) {
if (logger.isLoggable(Level.FINE)) {
log(SELF, Level.FINE, msg, null);
}
}
/**
* Log a message at level FINE according to the specified format and argument.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for level FINE.
* </p>
*
* @param format
* the format string
* @param arg
* the argument
*/
@Override
public void debug(String format, Object arg) {
if (logger.isLoggable(Level.FINE)) {
FormattingTuple ft = MessageFormatter.format(format, arg);
log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at level FINE according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the FINE level.
* </p>
*
* @param format
* the format string
* @param argA
* the first argument
* @param argB
* the second argument
*/
@Override
public void debug(String format, Object argA, Object argB) {
if (logger.isLoggable(Level.FINE)) {
FormattingTuple ft = MessageFormatter.format(format, argA, argB);
log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at level FINE according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the FINE level.
* </p>
*
* @param format
* the format string
* @param argArray
* an array of arguments
*/
@Override
public void debug(String format, Object... argArray) {
if (logger.isLoggable(Level.FINE)) {
FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
log(SELF, Level.FINE, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log an exception (throwable) at level FINE with an accompanying message.
*
* @param msg
* the message accompanying the exception
* @param t
* the exception (throwable) to log
*/
@Override
public void debug(String msg, Throwable t) {
if (logger.isLoggable(Level.FINE)) {
log(SELF, Level.FINE, msg, t);
}
}
/**
* Is this logger instance enabled for the INFO level?
*
* @return True if this Logger is enabled for the INFO level, false otherwise.
*/
@Override
public boolean isInfoEnabled() {
return logger.isLoggable(Level.INFO);
}
/**
* Log a message object at the INFO level.
*
* @param msg
* - the message object to be logged
*/
@Override
public void info(String msg) {
if (logger.isLoggable(Level.INFO)) {
log(SELF, Level.INFO, msg, null);
}
}
/**
* Log a message at level INFO according to the specified format and argument.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the INFO level.
* </p>
*
* @param format
* the format string
* @param arg
* the argument
*/
@Override
public void info(String format, Object arg) {
if (logger.isLoggable(Level.INFO)) {
FormattingTuple ft = MessageFormatter.format(format, arg);
log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at the INFO level according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the INFO level.
* </p>
*
* @param format
* the format string
* @param argA
* the first argument
* @param argB
* the second argument
*/
@Override
public void info(String format, Object argA, Object argB) {
if (logger.isLoggable(Level.INFO)) {
FormattingTuple ft = MessageFormatter.format(format, argA, argB);
log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at level INFO according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the INFO level.
* </p>
*
* @param format
* the format string
* @param argArray
* an array of arguments
*/
@Override
public void info(String format, Object... argArray) {
if (logger.isLoggable(Level.INFO)) {
FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
log(SELF, Level.INFO, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log an exception (throwable) at the INFO level with an accompanying
* message.
*
* @param msg
* the message accompanying the exception
* @param t
* the exception (throwable) to log
*/
@Override
public void info(String msg, Throwable t) {
if (logger.isLoggable(Level.INFO)) {
log(SELF, Level.INFO, msg, t);
}
}
/**
* Is this logger instance enabled for the WARNING level?
*
* @return True if this Logger is enabled for the WARNING level, false
* otherwise.
*/
@Override
public boolean isWarnEnabled() {
return logger.isLoggable(Level.WARNING);
}
/**
* Log a message object at the WARNING level.
*
* @param msg
* - the message object to be logged
*/
@Override
public void warn(String msg) {
if (logger.isLoggable(Level.WARNING)) {
log(SELF, Level.WARNING, msg, null);
}
}
/**
* Log a message at the WARNING level according to the specified format and
* argument.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the WARNING level.
* </p>
*
* @param format
* the format string
* @param arg
* the argument
*/
@Override
public void warn(String format, Object arg) {
if (logger.isLoggable(Level.WARNING)) {
FormattingTuple ft = MessageFormatter.format(format, arg);
log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at the WARNING level according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the WARNING level.
* </p>
*
* @param format
* the format string
* @param argA
* the first argument
* @param argB
* the second argument
*/
@Override
public void warn(String format, Object argA, Object argB) {
if (logger.isLoggable(Level.WARNING)) {
FormattingTuple ft = MessageFormatter.format(format, argA, argB);
log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at level WARNING according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the WARNING level.
* </p>
*
* @param format
* the format string
* @param argArray
* an array of arguments
*/
@Override
public void warn(String format, Object... argArray) {
if (logger.isLoggable(Level.WARNING)) {
FormattingTuple ft = MessageFormatter.arrayFormat(format, argArray);
log(SELF, Level.WARNING, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log an exception (throwable) at the WARNING level with an accompanying
* message.
*
* @param msg
* the message accompanying the exception
* @param t
* the exception (throwable) to log
*/
@Override
public void warn(String msg, Throwable t) {
if (logger.isLoggable(Level.WARNING)) {
log(SELF, Level.WARNING, msg, t);
}
}
/**
* Is this logger instance enabled for level SEVERE?
*
* @return True if this Logger is enabled for level SEVERE, false otherwise.
*/
@Override
public boolean isErrorEnabled() {
return logger.isLoggable(Level.SEVERE);
}
/**
* Log a message object at the SEVERE level.
*
* @param msg
* - the message object to be logged
*/
@Override
public void error(String msg) {
if (logger.isLoggable(Level.SEVERE)) {
log(SELF, Level.SEVERE, msg, null);
}
}
/**
* Log a message at the SEVERE level according to the specified format and
* argument.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the SEVERE level.
* </p>
*
* @param format
* the format string
* @param arg
* the argument
*/
@Override
public void error(String format, Object arg) {
if (logger.isLoggable(Level.SEVERE)) {
FormattingTuple ft = MessageFormatter.format(format, arg);
log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at the SEVERE level according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the SEVERE level.
* </p>
*
* @param format
* the format string
* @param argA
* the first argument
* @param argB
* the second argument
*/
@Override
public void error(String format, Object argA, Object argB) {
if (logger.isLoggable(Level.SEVERE)) {
FormattingTuple ft = MessageFormatter.format(format, argA, argB);
log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log a message at level SEVERE according to the specified format and
* arguments.
*
* <p>
* This form avoids superfluous object creation when the logger is disabled
* for the SEVERE level.
* </p>
*
* @param format
* the format string
* @param arguments
* an array of arguments
*/
@Override
public void error(String format, Object... arguments) {
if (logger.isLoggable(Level.SEVERE)) {
FormattingTuple ft = MessageFormatter.arrayFormat(format, arguments);
log(SELF, Level.SEVERE, ft.getMessage(), ft.getThrowable());
}
}
/**
* Log an exception (throwable) at the SEVERE level with an accompanying
* message.
*
* @param msg
* the message accompanying the exception
* @param t
* the exception (throwable) to log
*/
@Override
public void error(String msg, Throwable t) {
if (logger.isLoggable(Level.SEVERE)) {
log(SELF, Level.SEVERE, msg, t);
}
}
/**
* Log the message at the specified level with the specified throwable if any.
* This method creates a LogRecord and fills in caller date before calling
* this instance's JDK14 logger.
*
* See bug report #13 for more details.
*/
private void log(String callerFQCN, Level level, String msg, Throwable t) {
// millis and thread are filled by the constructor
LogRecord record = new LogRecord(level, msg);
record.setLoggerName(name());
record.setThrown(t);
fillCallerData(callerFQCN, record);
logger.log(record);
}
static final String SELF = JdkLogger.class.getName();
static final String SUPER = AbstractInternalLogger.class.getName();
/**
* Fill in caller data if possible.
*
* @param record
* The record to update
*/
private static void fillCallerData(String callerFQCN, LogRecord record) {
StackTraceElement[] steArray = new Throwable().getStackTrace();
int selfIndex = -1;
for (int i = 0; i < steArray.length; i++) {
final String className = steArray[i].getClassName();
if (className.equals(callerFQCN) || className.equals(SUPER)) {
selfIndex = i;
break;
}
}
int found = -1;
for (int i = selfIndex + 1; i < steArray.length; i++) {
final String className = steArray[i].getClassName();
if (!(className.equals(callerFQCN) || className.equals(SUPER))) {
found = i;
break;
}
}
if (found != -1) {
StackTraceElement ste = steArray[found];
// setting the class name has the side effect of setting
// the needToInferCaller variable to false.
record.setSourceClassName(ste.getClassName());
record.setSourceMethodName(ste.getMethodName());
}
}
}

View file

@ -1,32 +0,0 @@
/*
* Copyright 2012 The Netty Project
*
* The Netty Project licenses this file to you 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 common.net.util.internal.logging;
import java.util.logging.Logger;
/**
* Logger factory which creates a
* <a href="http://docs.oracle.com/javase/7/docs/technotes/guides/logging/">java.util.logging</a>
* logger.
*/
public class JdkLoggerFactory extends InternalLoggerFactory {
@Override
public InternalLogger newInstance(String name) {
return new JdkLogger(Logger.getLogger(name));
}
}

View file

@ -1,9 +1,7 @@
package common.network;
import common.future.ListenableFuture;
public interface IThreadListener {
ListenableFuture<Object> schedule(Runnable run);
void schedule(Runnable run);
boolean isMainThread();
default void log(String prefixed, String line) {
}

View file

@ -1,20 +0,0 @@
package common.util;
public abstract class LazyLoader<T>
{
private T value;
private boolean isLoaded = false;
public T getValue()
{
if (!this.isLoaded)
{
this.isLoaded = true;
this.value = this.load();
}
return this.value;
}
protected abstract T load();
}

View file

@ -14,6 +14,9 @@ import java.util.Date;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.atomic.AtomicLong;
import java.util.function.Function;
import javax.imageio.ImageIO;
@ -534,4 +537,17 @@ public abstract class Util {
public static String getTierSuffix(int tier) {
return tier <= 0 ? "" : " " + (tier > TIERS.length ? (tier + 1) : TIERS[tier - 1]);
}
public static ThreadFactory getThreadFactory(String name) {
final String format = name + " #%d";
final ThreadFactory factory = Executors.defaultThreadFactory();
final AtomicLong count = new AtomicLong(0);
return new ThreadFactory() {
public Thread newThread(Runnable runnable) {
Thread thread = new Thread(runnable, String.format(format, count.incrementAndGet()));
thread.setDaemon(true);
return thread;
}
};
}
}