cleanup
This commit is contained in:
parent
c126bdd8b0
commit
318a8885ba
53 changed files with 990 additions and 5887 deletions
|
@ -23,10 +23,6 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.function.Function;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
|
@ -120,10 +116,6 @@ import common.entity.npc.EntityNPC;
|
|||
import common.entity.npc.EntityWaterNPC;
|
||||
import common.entity.npc.PlayerCharacter;
|
||||
import common.entity.types.EntityLiving;
|
||||
import common.future.Futures;
|
||||
import common.future.ListenableFuture;
|
||||
import common.future.ListenableFutureTask;
|
||||
import common.future.ThreadFactoryBuilder;
|
||||
import common.init.BlockRegistry;
|
||||
import common.init.Blocks;
|
||||
import common.init.EntityRegistry;
|
||||
|
@ -171,7 +163,6 @@ import common.util.CharValidator;
|
|||
import common.util.ExtMath;
|
||||
import common.util.Facing;
|
||||
import common.util.HitPosition;
|
||||
import common.util.LazyLoader;
|
||||
import common.util.Util;
|
||||
import common.util.Var;
|
||||
import common.util.HitPosition.ObjectType;
|
||||
|
@ -281,15 +272,11 @@ public class Client implements IThreadListener {
|
|||
public static final int LOG_BUFFER = 32768;
|
||||
public static final int MIN_WIDTH = 800;
|
||||
public static final int MIN_HEIGHT = 450;
|
||||
private static final LazyLoader<NioEventLoopGroup> CLIENT_NIO_EVENTLOOP = new LazyLoader<NioEventLoopGroup>() {
|
||||
protected NioEventLoopGroup load() {
|
||||
return new NioEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Client IO #%d").setDaemon(true).build());
|
||||
}
|
||||
};
|
||||
|
||||
private final Queue<FutureTask<?>> tasks = new ArrayDeque<FutureTask<?>>();
|
||||
private final Thread thread = Thread.currentThread();
|
||||
private final NioEventLoopGroup eventGroup = new NioEventLoopGroup(0, Util.getThreadFactory("Netty Client IO"));
|
||||
private final Queue<Runnable> tasks = new ArrayDeque<Runnable>();
|
||||
private final Map<Integer, Long> bars = Maps.newTreeMap();
|
||||
private final Thread clThread = Thread.currentThread();
|
||||
private final Map<String, CVar> cvars = Maps.newTreeMap();
|
||||
private final Map<String, Field> synced = Maps.newTreeMap();
|
||||
private final Map<Keysym, DebugFunction> debug = Maps.newTreeMap();
|
||||
|
@ -537,7 +524,7 @@ public class Client implements IThreadListener {
|
|||
|
||||
private NetConnection connect(InetAddress address, int port) {
|
||||
final NetConnection connection = new NetConnection();
|
||||
new Bootstrap().group(CLIENT_NIO_EVENTLOOP.getValue()).handler(new ChannelInitializer<Channel>() {
|
||||
new Bootstrap().group(this.eventGroup).handler(new ChannelInitializer<Channel>() {
|
||||
protected void initChannel(Channel channel) throws Exception {
|
||||
try {
|
||||
channel.config().setOption(ChannelOption.TCP_NODELAY, true);
|
||||
|
@ -708,17 +695,13 @@ public class Client implements IThreadListener {
|
|||
{
|
||||
while (!this.tasks.isEmpty())
|
||||
{
|
||||
FutureTask<?> task = this.tasks.poll();
|
||||
Runnable task = this.tasks.poll();
|
||||
try {
|
||||
task.run();
|
||||
task.get();
|
||||
}
|
||||
catch(ExecutionException e1) {
|
||||
if(!(e1.getCause() instanceof ThreadQuickExitException))
|
||||
Log.SYSTEM.error(e1, "Fehler beim Ausführen von Render-Task " + task);
|
||||
}
|
||||
catch(InterruptedException e2) {
|
||||
Log.SYSTEM.error(e2, "Fehler beim Ausführen von Render-Task " + task);
|
||||
catch(Throwable e) {
|
||||
if(!(e instanceof ThreadQuickExitException))
|
||||
Log.SYSTEM.error(e, "Fehler beim Ausführen von Render-Task " + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1605,40 +1588,25 @@ public class Client implements IThreadListener {
|
|||
this.viewEntity = viewingEntity;
|
||||
}
|
||||
|
||||
private <V> ListenableFuture<V> addScheduledTask(Callable<V> callableToSchedule)
|
||||
{
|
||||
if (!this.isMainThread())
|
||||
{
|
||||
ListenableFutureTask<V> listenablefuturetask = ListenableFutureTask.<V>create(callableToSchedule);
|
||||
|
||||
synchronized (this.tasks)
|
||||
{
|
||||
this.tasks.add(listenablefuturetask);
|
||||
return listenablefuturetask;
|
||||
public void schedule(Runnable task) {
|
||||
if(!this.isMainThread()) {
|
||||
synchronized(this.tasks) {
|
||||
this.tasks.add(task);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
return Futures.<V>immediateFuture(callableToSchedule.call());
|
||||
else {
|
||||
try {
|
||||
task.run();
|
||||
}
|
||||
catch (Exception exception)
|
||||
{
|
||||
Log.SYSTEM.error(exception, "Fehler beim sofortigen Ausführen von Render-Task " + callableToSchedule);
|
||||
return Futures.immediateFailedFuture(exception);
|
||||
catch(Throwable e) {
|
||||
Log.SYSTEM.error(e, "Fehler beim sofortigen Ausführen von Render-Task " + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ListenableFuture<Object> schedule(Runnable runnableToSchedule)
|
||||
{
|
||||
return this.<Object>addScheduledTask(Executors.callable(runnableToSchedule));
|
||||
}
|
||||
|
||||
public boolean isMainThread()
|
||||
{
|
||||
return Thread.currentThread() == this.clThread;
|
||||
return Thread.currentThread() == this.thread;
|
||||
}
|
||||
|
||||
public BlockRenderer getBlockRendererDispatcher()
|
||||
|
|
|
@ -27,7 +27,7 @@ public class GuiInfo extends Gui {
|
|||
"Albert Pham - WorldEdit (Snippets)",
|
||||
"Joonas Vali - NameGenerator",
|
||||
"LWJGL 2.9.4-nightly-20150209 - Project, Vector*, Matrix*",
|
||||
"Guava 17.0 - collect, future, Predicates",
|
||||
"Guava 17.0 - collect, Predicates",
|
||||
"Netty 4.0.23-Final - net.*",
|
||||
"JOrbis 20101023 (JCraft) - jogg, jorbis, CodecJOrbis"
|
||||
};
|
||||
|
|
595
client/src/main/java/client/renderer/chunk/ChunkBuilder.java
Normal file
595
client/src/main/java/client/renderer/chunk/ChunkBuilder.java
Normal file
|
@ -0,0 +1,595 @@
|
|||
package client.renderer.chunk;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.AbstractExecutorService;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executor;
|
||||
import java.util.concurrent.ExecutorService;
|
||||
import java.util.concurrent.Future;
|
||||
import java.util.concurrent.FutureTask;
|
||||
import java.util.concurrent.RejectedExecutionException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.TimeoutException;
|
||||
import java.util.concurrent.atomic.AtomicInteger;
|
||||
import java.util.concurrent.locks.AbstractQueuedSynchronizer;
|
||||
import java.util.concurrent.locks.Condition;
|
||||
import java.util.concurrent.locks.Lock;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import common.collect.ImmutableList;
|
||||
import common.collect.Sets;
|
||||
import common.log.Log;
|
||||
|
||||
public abstract class ChunkBuilder {
|
||||
public static interface ListenableFuture<V> extends Future<V> {
|
||||
void addListener(Runnable listener, Executor executor);
|
||||
}
|
||||
|
||||
public static class ImmediateFuture implements ListenableFuture<Object> {
|
||||
public void addListener(Runnable listener, Executor executor) {
|
||||
try {
|
||||
executor.execute(listener);
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
Log.SYSTEM.error(e, "Fehler beim Ausführen von " + listener + " mit " + executor);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public Object get() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Object get(long timeout, TimeUnit unit) throws ExecutionException {
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
private static class SameThreadExecutorService extends AbstractExecutorService implements ExecutorService {
|
||||
private final Lock lock = new ReentrantLock();
|
||||
private final Condition termination = lock.newCondition();
|
||||
|
||||
private int runningTasks = 0;
|
||||
private boolean shutdown = false;
|
||||
|
||||
public void execute(Runnable command) {
|
||||
startTask();
|
||||
try {
|
||||
command.run();
|
||||
}
|
||||
finally {
|
||||
endTask();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isShutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
return shutdown;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
lock.lock();
|
||||
try {
|
||||
shutdown = true;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
public List<Runnable> shutdownNow() {
|
||||
shutdown();
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
public boolean isTerminated() {
|
||||
lock.lock();
|
||||
try {
|
||||
return shutdown && runningTasks == 0;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
private void startTask() {
|
||||
lock.lock();
|
||||
try {
|
||||
if(isShutdown()) {
|
||||
throw new RejectedExecutionException("Executor already shutdown");
|
||||
}
|
||||
runningTasks++;
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
private void endTask() {
|
||||
lock.lock();
|
||||
try {
|
||||
runningTasks--;
|
||||
if(isTerminated()) {
|
||||
termination.signalAll();
|
||||
}
|
||||
}
|
||||
finally {
|
||||
lock.unlock();
|
||||
}
|
||||
}
|
||||
|
||||
protected final <T> ListenableFutureTask<T> newTaskFor(Runnable runnable, T value) {
|
||||
return ListenableFutureTask.create(runnable, value);
|
||||
}
|
||||
|
||||
protected final <T> ListenableFutureTask<T> newTaskFor(Callable<T> callable) {
|
||||
return ListenableFutureTask.create(callable);
|
||||
}
|
||||
|
||||
public ListenableFuture<?> submit(Runnable task) {
|
||||
return (ListenableFuture<?>)super.submit(task);
|
||||
}
|
||||
|
||||
public <T> ListenableFuture<T> submit(Runnable task, T result) {
|
||||
return (ListenableFuture<T>)super.submit(task, result);
|
||||
}
|
||||
|
||||
public <T> ListenableFuture<T> submit(Callable<T> task) {
|
||||
return (ListenableFuture<T>)super.submit(task);
|
||||
}
|
||||
}
|
||||
|
||||
private static final class ExecutionList {
|
||||
private RunnableExecutorPair runnables;
|
||||
private boolean executed;
|
||||
|
||||
public void add(Runnable runnable, Executor executor) {
|
||||
synchronized(this) {
|
||||
if(!executed) {
|
||||
runnables = new RunnableExecutorPair(runnable, executor, runnables);
|
||||
return;
|
||||
}
|
||||
}
|
||||
executeListener(runnable, executor);
|
||||
}
|
||||
|
||||
public void execute() {
|
||||
RunnableExecutorPair list;
|
||||
synchronized(this) {
|
||||
if(executed) {
|
||||
return;
|
||||
}
|
||||
executed = true;
|
||||
list = runnables;
|
||||
runnables = null;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
private static void executeListener(Runnable runnable, Executor executor) {
|
||||
try {
|
||||
executor.execute(runnable);
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
Log.SYSTEM.error(e, "Fehler beim Ausführen von " + runnable + " mit " + executor);
|
||||
}
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class ListenableFutureTask<V> extends FutureTask<V> implements ListenableFuture<V> {
|
||||
private final ExecutionList executionList = new ExecutionList();
|
||||
|
||||
public static <V> ListenableFutureTask<V> create(Callable<V> callable) {
|
||||
return new ListenableFutureTask<V>(callable);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
public void addListener(Runnable listener, Executor exec) {
|
||||
executionList.add(listener, exec);
|
||||
}
|
||||
|
||||
protected void done() {
|
||||
executionList.execute();
|
||||
}
|
||||
}
|
||||
|
||||
public static void addCallback(List<ListenableFuture<Object>> futures, final ChunkCompileTaskGenerator generator, final CompiledChunk compiled, final ChunkRenderWorker worker) {
|
||||
final CombinedFuture future = new CombinedFuture(ImmutableList.copyOf(futures));
|
||||
generator.addFinishRunnable(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
future.cancel(false);
|
||||
}
|
||||
});
|
||||
Runnable listener = new Runnable() {
|
||||
public void run() {
|
||||
try {
|
||||
boolean interrupted = false;
|
||||
try {
|
||||
while(true) {
|
||||
try {
|
||||
future.get();
|
||||
break;
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if(interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(ExecutionException e) {
|
||||
if (!(e.getCause() instanceof CancellationException) && !(e.getCause() instanceof InterruptedException))
|
||||
Log.RENDER.error(e.getCause(), "Fehler beim Rendern des Chunks");
|
||||
worker.freeRenderBuilder(generator);
|
||||
return;
|
||||
}
|
||||
catch(RuntimeException e) {
|
||||
if (!(e instanceof CancellationException))
|
||||
Log.RENDER.error(e, "Fehler beim Rendern des Chunks");
|
||||
worker.freeRenderBuilder(generator);
|
||||
return;
|
||||
}
|
||||
catch(Error e) {
|
||||
Log.RENDER.error(e, "Fehler beim Rendern des Chunks");
|
||||
worker.freeRenderBuilder(generator);
|
||||
return;
|
||||
}
|
||||
worker.setRenderBuilderChunk(generator, compiled);
|
||||
}
|
||||
};
|
||||
future.addListener(listener, new SameThreadExecutorService());
|
||||
}
|
||||
|
||||
private static <V> V getUninterruptibly(Future<V> future) throws ExecutionException {
|
||||
boolean interrupted = false;
|
||||
try {
|
||||
while(true) {
|
||||
try {
|
||||
return future.get();
|
||||
}
|
||||
catch(InterruptedException e) {
|
||||
interrupted = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if(interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class CombinedFuture {
|
||||
private final Sync sync = new Sync();
|
||||
private final ExecutionList executionList = new ExecutionList();
|
||||
ImmutableList<? extends ListenableFuture<Object>> futures;
|
||||
final AtomicInteger remaining;
|
||||
final Object seenExceptionsLock = new Object();
|
||||
boolean active = true;
|
||||
Set<Throwable> seenExceptions;
|
||||
|
||||
CombinedFuture(ImmutableList<ListenableFuture<Object>> futures) {
|
||||
this.futures = futures;
|
||||
this.remaining = new AtomicInteger(futures.size());
|
||||
init();
|
||||
}
|
||||
|
||||
protected void init() {
|
||||
addListener(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if(CombinedFuture.this.isCancelled()) {
|
||||
for(ListenableFuture<?> future : CombinedFuture.this.futures) {
|
||||
future.cancel(CombinedFuture.this.wasInterrupted());
|
||||
}
|
||||
}
|
||||
|
||||
CombinedFuture.this.futures = null;
|
||||
CombinedFuture.this.active = false;
|
||||
}
|
||||
}, new SameThreadExecutorService());
|
||||
|
||||
if(futures.isEmpty()) {
|
||||
set();
|
||||
return;
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
for(final ListenableFuture<Object> listenable : futures) {
|
||||
final int index = i++;
|
||||
listenable.addListener(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setOneValue(index, listenable);
|
||||
}
|
||||
}, new SameThreadExecutorService());
|
||||
}
|
||||
}
|
||||
|
||||
private void setExceptionAndMaybeLog(Throwable throwable) {
|
||||
boolean visibleFromOutputFuture = false;
|
||||
boolean firstTimeSeeingThisException = true;
|
||||
if(true) {
|
||||
visibleFromOutputFuture = this.setException(throwable);
|
||||
|
||||
synchronized(seenExceptionsLock) {
|
||||
if(seenExceptions == null) {
|
||||
seenExceptions = Sets.newHashSet();
|
||||
}
|
||||
firstTimeSeeingThisException = seenExceptions.add(throwable);
|
||||
}
|
||||
}
|
||||
|
||||
if(throwable instanceof Error || (true && !visibleFromOutputFuture && firstTimeSeeingThisException)) {
|
||||
Log.SYSTEM.error(throwable, "Aufgabe fehlgeschlagen");
|
||||
}
|
||||
}
|
||||
|
||||
private void setOneValue(int index, Future<Object> future) {
|
||||
boolean wasActive = active;
|
||||
if(isDone() || !wasActive)
|
||||
checkState(true, "Future was done before all dependencies completed");
|
||||
|
||||
try {
|
||||
checkState(future.isDone(), "Tried to set value from future which is not done");
|
||||
Object returnValue = getUninterruptibly(future);
|
||||
}
|
||||
catch(CancellationException e) {
|
||||
if(true) {
|
||||
cancel(false);
|
||||
}
|
||||
}
|
||||
catch(ExecutionException e) {
|
||||
setExceptionAndMaybeLog(e.getCause());
|
||||
}
|
||||
catch(Throwable t) {
|
||||
setExceptionAndMaybeLog(t);
|
||||
}
|
||||
finally {
|
||||
int newRemaining = remaining.decrementAndGet();
|
||||
checkState(newRemaining >= 0, "Less than 0 remaining futures");
|
||||
if(newRemaining == 0) {
|
||||
if(wasActive) {
|
||||
set();
|
||||
}
|
||||
else {
|
||||
checkState(isDone(), "Future is not done");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void get() throws InterruptedException, ExecutionException {
|
||||
sync.get();
|
||||
}
|
||||
|
||||
public boolean isDone() {
|
||||
return sync.isDone();
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return sync.isCancelled();
|
||||
}
|
||||
|
||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
||||
if(!sync.cancel(mayInterruptIfRunning)) {
|
||||
return false;
|
||||
}
|
||||
executionList.execute();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected final boolean wasInterrupted() {
|
||||
return sync.wasInterrupted();
|
||||
}
|
||||
|
||||
public void addListener(Runnable listener, Executor exec) {
|
||||
executionList.add(listener, exec);
|
||||
}
|
||||
|
||||
protected boolean set() {
|
||||
boolean result = sync.set();
|
||||
if(result) {
|
||||
executionList.execute();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
protected boolean setException(Throwable throwable) {
|
||||
boolean result = sync.setException(throwable);
|
||||
if(result) {
|
||||
executionList.execute();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static final class Sync extends AbstractQueuedSynchronizer {
|
||||
|
||||
private static final long serialVersionUID = 0L;
|
||||
|
||||
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 Throwable exception;
|
||||
|
||||
protected int tryAcquireShared(int ignored) {
|
||||
if(isDone()) {
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
protected boolean tryReleaseShared(int finalState) {
|
||||
setState(finalState);
|
||||
return true;
|
||||
}
|
||||
|
||||
void get(long nanos) throws TimeoutException, CancellationException, ExecutionException, InterruptedException {
|
||||
|
||||
if(!tryAcquireSharedNanos(-1, nanos)) {
|
||||
throw new TimeoutException("Timeout waiting for task.");
|
||||
}
|
||||
|
||||
getValue();
|
||||
}
|
||||
|
||||
void get() throws CancellationException, ExecutionException, InterruptedException {
|
||||
|
||||
acquireSharedInterruptibly(-1);
|
||||
getValue();
|
||||
}
|
||||
|
||||
private void getValue() throws CancellationException, ExecutionException {
|
||||
int state = getState();
|
||||
switch(state) {
|
||||
case COMPLETED:
|
||||
if(exception != null) {
|
||||
throw new ExecutionException(exception);
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
case CANCELLED:
|
||||
case INTERRUPTED:
|
||||
throw cancellationExceptionWithCause("Task was cancelled.", exception);
|
||||
|
||||
default:
|
||||
throw new IllegalStateException("Error, synchronizer in invalid state: " + state);
|
||||
}
|
||||
}
|
||||
|
||||
boolean isDone() {
|
||||
return (getState() & (COMPLETED | CANCELLED | INTERRUPTED)) != 0;
|
||||
}
|
||||
|
||||
boolean isCancelled() {
|
||||
return (getState() & (CANCELLED | INTERRUPTED)) != 0;
|
||||
}
|
||||
|
||||
boolean wasInterrupted() {
|
||||
return getState() == INTERRUPTED;
|
||||
}
|
||||
|
||||
boolean set() {
|
||||
return complete(null, COMPLETED);
|
||||
}
|
||||
|
||||
boolean setException(Throwable t) {
|
||||
return complete(t, COMPLETED);
|
||||
}
|
||||
|
||||
boolean cancel(boolean interrupt) {
|
||||
return complete(null, interrupt ? INTERRUPTED : CANCELLED);
|
||||
}
|
||||
|
||||
private boolean complete(Throwable t, int finalState) {
|
||||
boolean doCompletion = compareAndSetState(RUNNING, COMPLETING);
|
||||
if(doCompletion) {
|
||||
this.exception = ((finalState & (CANCELLED | INTERRUPTED)) != 0) ? new CancellationException("Future.cancel() was called.") : t;
|
||||
releaseShared(finalState);
|
||||
}
|
||||
else if(getState() == COMPLETING) {
|
||||
acquireShared(-1);
|
||||
}
|
||||
return doCompletion;
|
||||
}
|
||||
}
|
||||
|
||||
static final CancellationException cancellationExceptionWithCause(String message, Throwable cause) {
|
||||
CancellationException exception = new CancellationException(message);
|
||||
exception.initCause(cause);
|
||||
return exception;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static void checkState(boolean expression, String errorMessage) {
|
||||
if(!expression) {
|
||||
throw new IllegalStateException(errorMessage);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -5,22 +5,18 @@ import java.util.List;
|
|||
import java.util.Queue;
|
||||
import java.util.concurrent.ArrayBlockingQueue;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.ThreadFactory;
|
||||
|
||||
import client.Client;
|
||||
import client.renderer.RegionRenderCacheBuilder;
|
||||
import client.renderer.RenderBuffer;
|
||||
import client.renderer.VertexBuffer;
|
||||
import client.renderer.chunk.ChunkBuilder.ImmediateFuture;
|
||||
import client.renderer.chunk.ChunkBuilder.ListenableFuture;
|
||||
import client.renderer.chunk.ChunkBuilder.ListenableFutureTask;
|
||||
import common.collect.Lists;
|
||||
import common.future.Futures;
|
||||
import common.future.ListenableFuture;
|
||||
import common.future.ListenableFutureTask;
|
||||
import common.future.ThreadFactoryBuilder;
|
||||
import common.model.BlockLayer;
|
||||
|
||||
public class ChunkRenderDispatcher
|
||||
{
|
||||
private static final ThreadFactory threadFactory = (new ThreadFactoryBuilder()).setNameFormat("Chunk Batcher %d").setDaemon(true).build();
|
||||
private final List<ChunkRenderWorker> listThreadedWorkers = Lists.<ChunkRenderWorker>newArrayList();
|
||||
private final BlockingQueue<ChunkCompileTaskGenerator> queueChunkUpdates = new ArrayBlockingQueue<ChunkCompileTaskGenerator>(100);
|
||||
private final BlockingQueue<RegionRenderCacheBuilder> queueFreeRenderBuilders = new ArrayBlockingQueue<RegionRenderCacheBuilder>(5);
|
||||
|
@ -34,7 +30,8 @@ public class ChunkRenderDispatcher
|
|||
for (int i = 0; i < 2; ++i)
|
||||
{
|
||||
ChunkRenderWorker chunkrenderworker = new ChunkRenderWorker(this);
|
||||
Thread thread = threadFactory.newThread(chunkrenderworker);
|
||||
Thread thread = new Thread(chunkrenderworker, "Chunk Batcher #" + (i + 1));
|
||||
thread.setDaemon(true);
|
||||
thread.start();
|
||||
this.listThreadedWorkers.add(chunkrenderworker);
|
||||
}
|
||||
|
@ -225,15 +222,15 @@ public class ChunkRenderDispatcher
|
|||
return flag;
|
||||
}
|
||||
|
||||
public ListenableFuture<Object> uploadChunk(final BlockLayer player, final RenderBuffer p_178503_2_, final RenderChunk chunkRenderer, final CompiledChunk compiledChunkIn)
|
||||
public ListenableFuture<Object> uploadChunk(final BlockLayer layer, final RenderBuffer buf, final RenderChunk renderer, final CompiledChunk compiled)
|
||||
{
|
||||
if (Client.CLIENT.isMainThread())
|
||||
{
|
||||
p_178503_2_.reset();
|
||||
chunkRenderer.getVertexBufferByLayer(player.ordinal()).bufferData(p_178503_2_.getByteBuffer());
|
||||
buf.reset();
|
||||
renderer.getVertexBufferByLayer(layer.ordinal()).bufferData(buf.getByteBuffer());
|
||||
|
||||
p_178503_2_.setTranslation(0.0D, 0.0D, 0.0D);
|
||||
return Futures.<Object>immediateFuture((Object)null);
|
||||
buf.setTranslation(0.0D, 0.0D, 0.0D);
|
||||
return new ImmediateFuture();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -241,7 +238,7 @@ public class ChunkRenderDispatcher
|
|||
{
|
||||
public void run()
|
||||
{
|
||||
ChunkRenderDispatcher.this.uploadChunk(player, p_178503_2_, chunkRenderer, compiledChunkIn);
|
||||
ChunkRenderDispatcher.this.uploadChunk(layer, buf, renderer, compiled);
|
||||
}
|
||||
}, (Object)null);
|
||||
|
||||
|
|
|
@ -1,16 +1,11 @@
|
|||
package client.renderer.chunk;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CancellationException;
|
||||
|
||||
import client.Client;
|
||||
import client.renderer.RegionRenderCacheBuilder;
|
||||
import client.renderer.chunk.ChunkBuilder.ListenableFuture;
|
||||
import common.collect.Lists;
|
||||
import common.entity.Entity;
|
||||
import common.future.FutureCallback;
|
||||
import common.future.Futures;
|
||||
import common.future.ListenableFuture;
|
||||
import common.log.Log;
|
||||
import common.model.BlockLayer;
|
||||
|
||||
|
@ -120,35 +115,42 @@ public class ChunkRenderWorker implements Runnable
|
|||
generator.getLock().unlock();
|
||||
}
|
||||
|
||||
final CompiledChunk lvt_7_1_ = generator.getCompiledChunk();
|
||||
ArrayList lvt_8_1_ = Lists.newArrayList();
|
||||
final CompiledChunk compiled = generator.getCompiledChunk();
|
||||
List<ListenableFuture<Object>> list = Lists.newArrayList();
|
||||
|
||||
if (chunkcompiletaskgenerator$type == ChunkCompileTaskGenerator.Type.REBUILD_CHUNK)
|
||||
{
|
||||
for (BlockLayer enumworldblocklayer : BlockLayer.values())
|
||||
{
|
||||
if (lvt_7_1_.isLayerStarted(enumworldblocklayer))
|
||||
if (compiled.isLayerStarted(enumworldblocklayer))
|
||||
{
|
||||
lvt_8_1_.add(this.chunkRenderDispatcher.uploadChunk(enumworldblocklayer, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(enumworldblocklayer), generator.getRenderChunk(), lvt_7_1_));
|
||||
list.add(this.chunkRenderDispatcher.uploadChunk(enumworldblocklayer, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(enumworldblocklayer), generator.getRenderChunk(), compiled));
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (chunkcompiletaskgenerator$type == ChunkCompileTaskGenerator.Type.RESORT_TRANSPARENCY)
|
||||
{
|
||||
lvt_8_1_.add(this.chunkRenderDispatcher.uploadChunk(BlockLayer.TRANSLUCENT, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(BlockLayer.TRANSLUCENT), generator.getRenderChunk(), lvt_7_1_));
|
||||
list.add(this.chunkRenderDispatcher.uploadChunk(BlockLayer.TRANSLUCENT, generator.getRegionRenderCacheBuilder().getWorldRendererByLayer(BlockLayer.TRANSLUCENT), generator.getRenderChunk(), compiled));
|
||||
}
|
||||
|
||||
final ListenableFuture<List<Object>> listenablefuture = Futures.allAsList(lvt_8_1_);
|
||||
generator.addFinishRunnable(new Runnable()
|
||||
{
|
||||
public void run()
|
||||
{
|
||||
listenablefuture.cancel(false);
|
||||
ChunkBuilder.addCallback(list, generator, compiled, this);
|
||||
}
|
||||
});
|
||||
Futures.addCallback(listenablefuture, new FutureCallback<List<Object>>()
|
||||
}
|
||||
|
||||
private RegionRenderCacheBuilder getRegionRenderCacheBuilder() throws InterruptedException
|
||||
{
|
||||
public void onSuccess(List<Object> p_onSuccess_1_)
|
||||
return this.regionRenderCacheBuilder != null ? this.regionRenderCacheBuilder : this.chunkRenderDispatcher.allocateRenderBuilder();
|
||||
}
|
||||
|
||||
public void freeRenderBuilder(ChunkCompileTaskGenerator taskGenerator)
|
||||
{
|
||||
if (this.regionRenderCacheBuilder == null)
|
||||
{
|
||||
this.chunkRenderDispatcher.freeRenderBuilder(taskGenerator.getRegionRenderCacheBuilder());
|
||||
}
|
||||
}
|
||||
|
||||
public void setRenderBuilderChunk(ChunkCompileTaskGenerator generator, CompiledChunk compiled)
|
||||
{
|
||||
ChunkRenderWorker.this.freeRenderBuilder(generator);
|
||||
generator.getLock().lock();
|
||||
|
@ -174,31 +176,6 @@ public class ChunkRenderWorker implements Runnable
|
|||
|
||||
return;
|
||||
}
|
||||
generator.getRenderChunk().setCompiledChunk(lvt_7_1_);
|
||||
}
|
||||
public void onFailure(Throwable p_onFailure_1_)
|
||||
{
|
||||
ChunkRenderWorker.this.freeRenderBuilder(generator);
|
||||
|
||||
if (!(p_onFailure_1_ instanceof CancellationException) && !(p_onFailure_1_ instanceof InterruptedException))
|
||||
{
|
||||
Log.RENDER.error(p_onFailure_1_, "Fehler beim Rendern des Chunks");
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private RegionRenderCacheBuilder getRegionRenderCacheBuilder() throws InterruptedException
|
||||
{
|
||||
return this.regionRenderCacheBuilder != null ? this.regionRenderCacheBuilder : this.chunkRenderDispatcher.allocateRenderBuilder();
|
||||
}
|
||||
|
||||
private void freeRenderBuilder(ChunkCompileTaskGenerator taskGenerator)
|
||||
{
|
||||
if (this.regionRenderCacheBuilder == null)
|
||||
{
|
||||
this.chunkRenderDispatcher.freeRenderBuilder(taskGenerator.getRegionRenderCacheBuilder());
|
||||
}
|
||||
generator.getRenderChunk().setCompiledChunk(compiled);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
@ -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);
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
// }
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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 ++;
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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("Hi {}.", "there")
|
||||
* </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("Set {1,2,3} is not equal to {}.", "1,2");
|
||||
* </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("Set \\{} is not equal to {}.", "1,2");
|
||||
* </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("File name is C:\\\\{}.", "file.zip");
|
||||
* </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("Hi {}.", "there");
|
||||
* </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("Hi {}. My name is {}.", "Alice", "Bob");
|
||||
* </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;
|
||||
}
|
||||
|
@ -422,6 +274,125 @@ final class MessageFormatter {
|
|||
sbuf.append(']');
|
||||
}
|
||||
|
||||
private MessageFormatter() {
|
||||
public static boolean isDebugEnabled() {
|
||||
return Log.getLevel().ordinal() >= LogLevel.DEBUG.ordinal();
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -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() {
|
||||
|
|
|
@ -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)));
|
||||
}
|
||||
|
|
|
@ -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() + ')';
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,11 +23,6 @@ import java.util.Locale;
|
|||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Queue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.ExecutionException;
|
||||
import java.util.concurrent.Executors;
|
||||
import java.util.concurrent.FutureTask;
|
||||
|
||||
import common.Version;
|
||||
import common.collect.Lists;
|
||||
import common.collect.Maps;
|
||||
|
@ -38,10 +33,6 @@ import common.effect.StatusEffect;
|
|||
import common.entity.Entity;
|
||||
import common.entity.npc.EntityHuman;
|
||||
import common.entity.npc.EntityNPC;
|
||||
import common.future.Futures;
|
||||
import common.future.ListenableFuture;
|
||||
import common.future.ListenableFutureTask;
|
||||
import common.future.ThreadFactoryBuilder;
|
||||
import common.init.EntityRegistry;
|
||||
import common.init.Registry;
|
||||
import common.init.UniverseRegistry;
|
||||
|
@ -86,7 +77,6 @@ import common.tags.TagObject;
|
|||
import common.util.BlockPos;
|
||||
import common.util.EncryptUtil;
|
||||
import common.util.ExtMath;
|
||||
import common.util.LazyLoader;
|
||||
import common.util.Pair;
|
||||
import common.util.PortalType;
|
||||
import common.util.Position;
|
||||
|
@ -109,19 +99,14 @@ import server.world.Region;
|
|||
import server.world.WorldServer;
|
||||
|
||||
public final class Server implements IThreadListener, Executor {
|
||||
private static final LazyLoader<NioEventLoopGroup> SERVER_NIO_EVENTLOOP = new LazyLoader<NioEventLoopGroup>() {
|
||||
protected NioEventLoopGroup load() {
|
||||
return new NioEventLoopGroup(0, (new ThreadFactoryBuilder()).setNameFormat("Netty Server IO #%d").setDaemon(true).build());
|
||||
}
|
||||
};
|
||||
|
||||
private final Thread serverThread = Thread.currentThread();
|
||||
private final Thread thread = Thread.currentThread();
|
||||
private final NioEventLoopGroup eventGroup = new NioEventLoopGroup(0, Util.getThreadFactory("Netty Server IO"));
|
||||
private final Map<String, SVar> variables = Maps.newTreeMap();
|
||||
private final List<NetConnection> clients = Collections.<NetConnection>synchronizedList(Lists.<NetConnection>newArrayList());
|
||||
private final List<Player> players = Lists.<Player>newArrayList();
|
||||
private final Map<String, Player> online = Maps.<String, Player>newHashMap();
|
||||
private final Map<String, User> users = Maps.newTreeMap();
|
||||
private final Queue<FutureTask<?>> queue = new ArrayDeque<FutureTask<?>>();
|
||||
private final Queue<Runnable> queue = new ArrayDeque<Runnable>();
|
||||
private final long[] tickTimes = new long[100];
|
||||
private final Map<Integer, WorldServer> dimensions = Maps.newTreeMap();
|
||||
private final List<WorldServer> worlds = Lists.<WorldServer>newArrayList();
|
||||
|
@ -512,17 +497,13 @@ public final class Server implements IThreadListener, Executor {
|
|||
long now = System.currentTimeMillis();
|
||||
synchronized(this.queue) {
|
||||
while(!this.queue.isEmpty()) {
|
||||
FutureTask<?> task = this.queue.poll();
|
||||
Runnable task = this.queue.poll();
|
||||
try {
|
||||
task.run();
|
||||
task.get();
|
||||
}
|
||||
catch(ExecutionException e1) {
|
||||
if(!(e1.getCause() instanceof ThreadQuickExitException))
|
||||
Log.SYSTEM.error(e1, "Fehler beim Ausführen von Server-Task " + task); // throw new RuntimeException(e1);
|
||||
}
|
||||
catch(InterruptedException e2) {
|
||||
Log.SYSTEM.error(e2, "Fehler beim Ausführen von Server-Task " + task);
|
||||
catch(Throwable e) {
|
||||
if(!(e instanceof ThreadQuickExitException))
|
||||
Log.SYSTEM.error(e, "Fehler beim Ausführen von Server-Task " + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -650,31 +631,24 @@ public final class Server implements IThreadListener, Executor {
|
|||
return this.users.get(user);
|
||||
}
|
||||
|
||||
private <V> ListenableFuture<V> callFromMainThread(Callable<V> callable) {
|
||||
public void schedule(Runnable task) {
|
||||
if(!this.isMainThread() && !this.stopped) {
|
||||
ListenableFutureTask<V> task = ListenableFutureTask.<V>create(callable);
|
||||
synchronized(this.queue) {
|
||||
this.queue.add(task);
|
||||
return task;
|
||||
}
|
||||
}
|
||||
else {
|
||||
try {
|
||||
return Futures.<V>immediateFuture(callable.call());
|
||||
task.run();
|
||||
}
|
||||
catch(Exception exception) {
|
||||
Log.SYSTEM.error(exception, "Fehler beim sofortigen Ausführen von Server-Task " + callable);
|
||||
return Futures.immediateFailedFuture(exception);
|
||||
catch(Throwable e) {
|
||||
Log.SYSTEM.error(e, "Fehler beim sofortigen Ausführen von Server-Task " + task);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ListenableFuture<Object> schedule(Runnable run) {
|
||||
return this.<Object>callFromMainThread(Executors.callable(run));
|
||||
}
|
||||
|
||||
public boolean isMainThread() {
|
||||
return Thread.currentThread() == this.serverThread;
|
||||
return Thread.currentThread() == this.thread;
|
||||
}
|
||||
|
||||
public Position getRandomSpawnPosition(WorldPos origin) {
|
||||
|
@ -1024,7 +998,7 @@ public final class Server implements IThreadListener, Executor {
|
|||
for(Player conn : Lists.newArrayList(this.players)) {
|
||||
conn.disconnect(message);
|
||||
}
|
||||
synchronized(this.serverThread) {
|
||||
synchronized(this.thread) {
|
||||
if(this.endpoint != null) {
|
||||
Log.NETWORK.info("Schließe Port");
|
||||
try {
|
||||
|
@ -1084,7 +1058,7 @@ public final class Server implements IThreadListener, Executor {
|
|||
}
|
||||
|
||||
public void bind(int port) {
|
||||
synchronized(this.serverThread) {
|
||||
synchronized(this.thread) {
|
||||
if(port >= 0) {
|
||||
try {
|
||||
if(this.endpoint != null)
|
||||
|
@ -1107,7 +1081,7 @@ public final class Server implements IThreadListener, Executor {
|
|||
channel.pipeline().addLast((String)"packet_handler", (ChannelHandler)manager);
|
||||
manager.setNetHandler(new HandshakeHandler(Server.this, manager));
|
||||
}
|
||||
}).group(SERVER_NIO_EVENTLOOP.getValue()).localAddress((InetAddress)null, port)).bind().syncUninterruptibly();
|
||||
}).group(this.eventGroup).localAddress((InetAddress)null, port)).bind().syncUninterruptibly();
|
||||
}
|
||||
catch(Throwable e) {
|
||||
Log.NETWORK.error(e, "**** KONNTE NICHT AN PORT " + port + " ANBINDEN!");
|
||||
|
|
|
@ -26,7 +26,6 @@ import common.entity.npc.EntityNPC;
|
|||
import common.entity.npc.PlayerCharacter;
|
||||
import common.entity.projectile.EntityArrow;
|
||||
import common.entity.types.EntityLiving;
|
||||
import common.future.Futures;
|
||||
import common.init.BlockRegistry;
|
||||
import common.init.Blocks;
|
||||
import common.init.EntityRegistry;
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue