diff --git a/client/src/main/java/client/Client.java b/client/src/main/java/client/Client.java index c24ad419..9c94223b 100755 --- a/client/src/main/java/client/Client.java +++ b/client/src/main/java/client/Client.java @@ -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 CLIENT_NIO_EVENTLOOP = new LazyLoader() { - protected NioEventLoopGroup load() { - return new NioEventLoopGroup(0, new ThreadFactoryBuilder().setNameFormat("Netty Client IO #%d").setDaemon(true).build()); - } - }; - - private final Queue> tasks = new ArrayDeque>(); + + private final Thread thread = Thread.currentThread(); + private final NioEventLoopGroup eventGroup = new NioEventLoopGroup(0, Util.getThreadFactory("Netty Client IO")); + private final Queue tasks = new ArrayDeque(); private final Map bars = Maps.newTreeMap(); - private final Thread clThread = Thread.currentThread(); private final Map cvars = Maps.newTreeMap(); private final Map synced = Maps.newTreeMap(); private final Map 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() { + new Bootstrap().group(this.eventGroup).handler(new ChannelInitializer() { 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 ListenableFuture addScheduledTask(Callable callableToSchedule) - { - if (!this.isMainThread()) - { - ListenableFutureTask listenablefuturetask = ListenableFutureTask.create(callableToSchedule); - - synchronized (this.tasks) - { - this.tasks.add(listenablefuturetask); - return listenablefuturetask; - } - } - else - { - try - { - return Futures.immediateFuture(callableToSchedule.call()); - } - catch (Exception exception) - { - Log.SYSTEM.error(exception, "Fehler beim sofortigen Ausführen von Render-Task " + callableToSchedule); - return Futures.immediateFailedFuture(exception); - } - } - } - - public ListenableFuture schedule(Runnable runnableToSchedule) - { - return this.addScheduledTask(Executors.callable(runnableToSchedule)); - } + public void schedule(Runnable task) { + if(!this.isMainThread()) { + synchronized(this.tasks) { + this.tasks.add(task); + } + } + else { + try { + task.run(); + } + catch(Throwable e) { + Log.SYSTEM.error(e, "Fehler beim sofortigen Ausführen von Render-Task " + task); + } + } + } public boolean isMainThread() { - return Thread.currentThread() == this.clThread; + return Thread.currentThread() == this.thread; } public BlockRenderer getBlockRendererDispatcher() diff --git a/client/src/main/java/client/gui/GuiInfo.java b/client/src/main/java/client/gui/GuiInfo.java index 98f1b943..bb7bc61d 100644 --- a/client/src/main/java/client/gui/GuiInfo.java +++ b/client/src/main/java/client/gui/GuiInfo.java @@ -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" }; diff --git a/client/src/main/java/client/renderer/chunk/ChunkBuilder.java b/client/src/main/java/client/renderer/chunk/ChunkBuilder.java new file mode 100644 index 00000000..b81da853 --- /dev/null +++ b/client/src/main/java/client/renderer/chunk/ChunkBuilder.java @@ -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 extends Future { + void addListener(Runnable listener, Executor executor); + } + + public static class ImmediateFuture implements ListenableFuture { + 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 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 ListenableFutureTask newTaskFor(Runnable runnable, T value) { + return ListenableFutureTask.create(runnable, value); + } + + protected final ListenableFutureTask newTaskFor(Callable callable) { + return ListenableFutureTask.create(callable); + } + + public ListenableFuture submit(Runnable task) { + return (ListenableFuture)super.submit(task); + } + + public ListenableFuture submit(Runnable task, T result) { + return (ListenableFuture)super.submit(task, result); + } + + public ListenableFuture submit(Callable task) { + return (ListenableFuture)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 extends FutureTask implements ListenableFuture { + private final ExecutionList executionList = new ExecutionList(); + + public static ListenableFutureTask create(Callable callable) { + return new ListenableFutureTask(callable); + } + + public static ListenableFutureTask create(Runnable runnable, V result) { + return new ListenableFutureTask(runnable, result); + } + + ListenableFutureTask(Callable 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> 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 getUninterruptibly(Future 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> futures; + final AtomicInteger remaining; + final Object seenExceptionsLock = new Object(); + boolean active = true; + Set seenExceptions; + + CombinedFuture(ImmutableList> 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 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 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); + } + } +} diff --git a/client/src/main/java/client/renderer/chunk/ChunkRenderDispatcher.java b/client/src/main/java/client/renderer/chunk/ChunkRenderDispatcher.java index 735cadbc..e75f1a7c 100755 --- a/client/src/main/java/client/renderer/chunk/ChunkRenderDispatcher.java +++ b/client/src/main/java/client/renderer/chunk/ChunkRenderDispatcher.java @@ -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 listThreadedWorkers = Lists.newArrayList(); private final BlockingQueue queueChunkUpdates = new ArrayBlockingQueue(100); private final BlockingQueue queueFreeRenderBuilders = new ArrayBlockingQueue(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 uploadChunk(final BlockLayer player, final RenderBuffer p_178503_2_, final RenderChunk chunkRenderer, final CompiledChunk compiledChunkIn) + public ListenableFuture 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.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); diff --git a/client/src/main/java/client/renderer/chunk/ChunkRenderWorker.java b/client/src/main/java/client/renderer/chunk/ChunkRenderWorker.java index 0fe9a2b5..55906107 100755 --- a/client/src/main/java/client/renderer/chunk/ChunkRenderWorker.java +++ b/client/src/main/java/client/renderer/chunk/ChunkRenderWorker.java @@ -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,72 +115,25 @@ 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> 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> listenablefuture = Futures.allAsList(lvt_8_1_); - generator.addFinishRunnable(new Runnable() - { - public void run() - { - listenablefuture.cancel(false); - } - }); - Futures.addCallback(listenablefuture, new FutureCallback>() - { - public void onSuccess(List p_onSuccess_1_) - { - ChunkRenderWorker.this.freeRenderBuilder(generator); - generator.getLock().lock(); - label21: - { - try - { - if (generator.getStatus() == ChunkCompileTaskGenerator.Status.UPLOADING) - { - generator.setStatus(ChunkCompileTaskGenerator.Status.DONE); - break label21; - } - - if (!generator.isFinished()) - { - Log.RENDER.warn("Chunk-Rendering-Aufgabe war " + generator.getStatus() + " wenn UPLOADING erwartet war; breche Aufgabe ab"); - } - } - finally - { - generator.getLock().unlock(); - } - - 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"); - } - } - }); + ChunkBuilder.addCallback(list, generator, compiled, this); } } @@ -194,11 +142,40 @@ public class ChunkRenderWorker implements Runnable return this.regionRenderCacheBuilder != null ? this.regionRenderCacheBuilder : this.chunkRenderDispatcher.allocateRenderBuilder(); } - private void freeRenderBuilder(ChunkCompileTaskGenerator taskGenerator) + 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(); + label21: + { + try + { + if (generator.getStatus() == ChunkCompileTaskGenerator.Status.UPLOADING) + { + generator.setStatus(ChunkCompileTaskGenerator.Status.DONE); + break label21; + } + + if (!generator.isFinished()) + { + Log.RENDER.warn("Chunk-Rendering-Aufgabe war " + generator.getStatus() + " wenn UPLOADING erwartet war; breche Aufgabe ab"); + } + } + finally + { + generator.getLock().unlock(); + } + + return; + } + generator.getRenderChunk().setCompiledChunk(compiled); + } } diff --git a/common/src/main/java/common/future/AbstractFuture.java b/common/src/main/java/common/future/AbstractFuture.java deleted file mode 100644 index 280f3afd..00000000 --- a/common/src/main/java/common/future/AbstractFuture.java +++ /dev/null @@ -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}.) - * - *

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. - * - *

{@code AbstractFuture} uses an {@link AbstractQueuedSynchronizer} to deal - * with concurrency issues and guarantee thread safety. - * - *

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. - * - *

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 implements ListenableFuture { - - /** Synchronization control for AbstractFutures. */ - private final Sync sync = new Sync(); - - // 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} - * - *

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} - * - *

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)}. - * - *

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; - } - - /** - *

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} - * - *

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. - * - *

We don't use the integer argument passed between acquire methods so we - * pass around a -1 everywhere. - */ - static final class Sync 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; - } -} diff --git a/common/src/main/java/common/future/ExecutionError.java b/common/src/main/java/common/future/ExecutionError.java deleted file mode 100644 index 73fe3f15..00000000 --- a/common/src/main/java/common/future/ExecutionError.java +++ /dev/null @@ -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; -} diff --git a/common/src/main/java/common/future/ExecutionList.java b/common/src/main/java/common/future/ExecutionList.java deleted file mode 100644 index 46a757cb..00000000 --- a/common/src/main/java/common/future/ExecutionList.java +++ /dev/null @@ -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; - -/** - *

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. - * - *

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. - * - *

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. - * - *

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; - } - } -} diff --git a/common/src/main/java/common/future/FutureCallback.java b/common/src/main/java/common/future/FutureCallback.java deleted file mode 100644 index 6e5b5292..00000000 --- a/common/src/main/java/common/future/FutureCallback.java +++ /dev/null @@ -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. - * - *

To attach to a {@link ListenableFuture} use {@link Futures#addCallback}. - * - * @author Anthony Zana - * @since 10.0 - */ -public interface FutureCallback { - /** - * 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. - * - *

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); -} diff --git a/common/src/main/java/common/future/Futures.java b/common/src/main/java/common/future/Futures.java deleted file mode 100644 index 6dbce5f7..00000000 --- a/common/src/main/java/common/future/Futures.java +++ /dev/null @@ -1,1723 +0,0 @@ -/* - * Copyright (C) 2006 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.ArrayList; -import java.util.List; -import java.util.Set; -import java.util.concurrent.CancellationException; -import java.util.concurrent.ExecutionException; -import java.util.concurrent.Executor; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.atomic.AtomicInteger; -import java.util.logging.Level; -import java.util.logging.Logger; - -import common.collect.ImmutableList; -import common.collect.Sets; - -/** - * Static utility methods pertaining to the {@link Future} interface. - * - *

Many of these methods use the {@link ListenableFuture} API; consult the - * Guava User Guide article on - * {@code ListenableFuture}. - * - * @author Kevin Bourrillion - * @author Nishant Thakkar - * @author Sven Mawson - * @since 1.0 - */ -//@Beta -public final class Futures { - private Futures() {} - - /** - * Creates a {@link CheckedFuture} out of a normal {@link ListenableFuture} - * and a {@link Function} that maps from {@link Exception} instances into the - * appropriate checked type. - * - *

The given mapping function will be applied to an - * {@link InterruptedException}, a {@link CancellationException}, or an - * {@link ExecutionException}. - * See {@link Future#get()} for details on the exceptions thrown. - * - * @since 9.0 (source-compatible since 1.0) - */ -// public static CheckedFuture makeChecked( -// ListenableFuture future, Function mapper) { -// return new MappingCheckedFuture(checkNotNull(future), mapper); -// } - - private abstract static class ImmediateFuture - implements ListenableFuture { - - private static final Logger log = - Logger.getLogger(ImmediateFuture.class.getName()); - - @Override - public void addListener(Runnable listener, Executor executor) { -// checkNotNull(listener, "Runnable was null."); -// checkNotNull(executor, "Executor was null."); - try { - executor.execute(listener); - } catch (RuntimeException e) { - // ListenableFuture's contract is that it will not throw unchecked - // exceptions, so log the bad runnable and/or executor and swallow it. - log.log(Level.SEVERE, "RuntimeException while executing runnable " - + listener + " with executor " + executor, e); - } - } - - @Override - public boolean cancel(boolean mayInterruptIfRunning) { - return false; - } - - @Override - public abstract V get() throws ExecutionException; - - @Override - public V get(long timeout, TimeUnit unit) throws ExecutionException { -// checkNotNull(unit); - return get(); - } - - @Override - public boolean isCancelled() { - return false; - } - - @Override - public boolean isDone() { - return true; - } - } - - private static class ImmediateSuccessfulFuture extends ImmediateFuture { - - private final V value; - - ImmediateSuccessfulFuture(V value) { - this.value = value; - } - - @Override - public V get() { - return value; - } - } - -// private static class ImmediateSuccessfulCheckedFuture -// extends ImmediateFuture implements CheckedFuture { -// -// private final V value; -// -// ImmediateSuccessfulCheckedFuture(V value) { -// this.value = value; -// } -// -// @Override -// public V get() { -// return value; -// } -// -// @Override -// public V checkedGet() { -// return value; -// } -// -// @Override -// public V checkedGet(long timeout, TimeUnit unit) { -// checkNotNull(unit); -// return value; -// } -// } - - private static class ImmediateFailedFuture extends ImmediateFuture { - - private final Throwable thrown; - - ImmediateFailedFuture(Throwable thrown) { - this.thrown = thrown; - } - - @Override - public V get() throws ExecutionException { - throw new ExecutionException(thrown); - } - } - -// private static class ImmediateCancelledFuture extends ImmediateFuture { -// -// private final CancellationException thrown; -// -// ImmediateCancelledFuture() { -// this.thrown = new CancellationException("Immediate cancelled future."); -// } -// -// @Override -// public boolean isCancelled() { -// return true; -// } -// -// @Override -// public V get() { -// throw AbstractFuture.cancellationExceptionWithCause( -// "Task was cancelled.", thrown); -// } -// } - -// private static class ImmediateFailedFuture -// extends ImmediateFuture implements ListenableFuture { -// -//// private final X thrown; -// -// ImmediateFailedCheckedFuture(X thrown) { -// this.thrown = thrown; -// } -// -// @Override -// public V get() throws ExecutionException { -// throw new ExecutionException(thrown); -// } -// -// @Override -// public V checkedGet() throws X { -// throw thrown; -// } -// -// @Override -// public V checkedGet(long timeout, TimeUnit unit) throws X { -// checkNotNull(unit); -// throw thrown; -// } -// } - - /** - * Creates a {@code ListenableFuture} which has its value set immediately upon - * construction. The getters just return the value. This {@code Future} can't - * be canceled or timed out and its {@code isDone()} method always returns - * {@code true}. - */ - public static ListenableFuture immediateFuture(V value) { - return new ImmediateSuccessfulFuture(value); - } - - /** - * Returns a {@code CheckedFuture} which has its value set immediately upon - * construction. - * - *

The returned {@code Future} can't be cancelled, and its {@code isDone()} - * method always returns {@code true}. Calling {@code get()} or {@code - * checkedGet()} will immediately return the provided value. - */ -// public static CheckedFuture -// immediateCheckedFuture(V value) { -// return new ImmediateSuccessfulCheckedFuture(value); -// } - - /** - * Returns a {@code ListenableFuture} which has an exception set immediately - * upon construction. - * - *

The returned {@code Future} can't be cancelled, and its {@code isDone()} - * method always returns {@code true}. Calling {@code get()} will immediately - * throw the provided {@code Throwable} wrapped in an {@code - * ExecutionException}. - */ - public static ListenableFuture immediateFailedFuture( - Throwable throwable) { -// checkNotNull(throwable); - return new ImmediateFailedFuture(throwable); - } - - /** - * Creates a {@code ListenableFuture} which is cancelled immediately upon - * construction, so that {@code isCancelled()} always returns {@code true}. - * - * @since 14.0 - */ -// public static ListenableFuture immediateCancelledFuture() { -// return new ImmediateCancelledFuture(); -// } - - /** - * Returns a {@code CheckedFuture} which has an exception set immediately upon - * construction. - * - *

The returned {@code Future} can't be cancelled, and its {@code isDone()} - * method always returns {@code true}. Calling {@code get()} will immediately - * throw the provided {@code Exception} wrapped in an {@code - * ExecutionException}, and calling {@code checkedGet()} will throw the - * provided exception itself. - */ -// public static ListenableFuture -// immediateFailedCheckedFuture(X exception) { -// checkNotNull(exception); -// return new ImmediateFailedCheckedFuture(exception); -// } - - /** - * Returns a {@code Future} whose result is taken from the given primary - * {@code input} or, if the primary input fails, from the {@code Future} - * provided by the {@code fallback}. {@link FutureFallback#create} is not - * invoked until the primary input has failed, so if the primary input - * succeeds, it is never invoked. If, during the invocation of {@code - * fallback}, an exception is thrown, this exception is used as the result of - * the output {@code Future}. - * - *

Below is an example of a fallback that returns a default value if an - * exception occurs: - * - *

   {@code
-   *   ListenableFuture fetchCounterFuture = ...;
-   *
-   *   // Falling back to a zero counter in case an exception happens when
-   *   // processing the RPC to fetch counters.
-   *   ListenableFuture faultTolerantFuture = Futures.withFallback(
-   *       fetchCounterFuture, new FutureFallback() {
-   *         public ListenableFuture create(Throwable t) {
-   *           // Returning "0" as the default for the counter when the
-   *           // exception happens.
-   *           return immediateFuture(0);
-   *         }
-   *       });}
- * - *

The fallback can also choose to propagate the original exception when - * desired: - * - *

   {@code
-   *   ListenableFuture fetchCounterFuture = ...;
-   *
-   *   // Falling back to a zero counter only in case the exception was a
-   *   // TimeoutException.
-   *   ListenableFuture faultTolerantFuture = Futures.withFallback(
-   *       fetchCounterFuture, new FutureFallback() {
-   *         public ListenableFuture create(Throwable t) {
-   *           if (t instanceof TimeoutException) {
-   *             return immediateFuture(0);
-   *           }
-   *           return immediateFailedFuture(t);
-   *         }
-   *       });}
- * - *

Note: If the derived {@code Future} is slow or heavyweight to create - * (whether the {@code Future} itself is slow or heavyweight to complete is - * irrelevant), consider {@linkplain #withFallback(ListenableFuture, - * FutureFallback, Executor) supplying an executor}. If you do not supply an - * executor, {@code withFallback} will use {@link - * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some - * caveats for heavier operations. For example, the call to {@code - * fallback.create} may run on an unpredictable or undesirable thread: - * - *

    - *
  • If the input {@code Future} is done at the time {@code withFallback} - * is called, {@code withFallback} will call {@code fallback.create} inline. - *
  • If the input {@code Future} is not yet done, {@code withFallback} will - * schedule {@code fallback.create} to be run by the thread that completes - * the input {@code Future}, which may be an internal system thread such as - * an RPC network thread. - *
- * - *

Also note that, regardless of which thread executes the {@code - * sameThreadExecutor} {@code fallback.create}, all other registered but - * unexecuted listeners are prevented from running during its execution, even - * if those listeners are to run in other executors. - * - * @param input the primary input {@code Future} - * @param fallback the {@link FutureFallback} implementation to be called if - * {@code input} fails - * @since 14.0 - */ -// public static ListenableFuture withFallback( -// ListenableFuture input, -// FutureFallback fallback) { -// return withFallback(input, fallback, sameThreadExecutor()); -// } - - /** - * Returns a {@code Future} whose result is taken from the given primary - * {@code input} or, if the primary input fails, from the {@code Future} - * provided by the {@code fallback}. {@link FutureFallback#create} is not - * invoked until the primary input has failed, so if the primary input - * succeeds, it is never invoked. If, during the invocation of {@code - * fallback}, an exception is thrown, this exception is used as the result of - * the output {@code Future}. - * - *

Below is an example of a fallback that returns a default value if an - * exception occurs: - * - *

   {@code
-   *   ListenableFuture fetchCounterFuture = ...;
-   *
-   *   // Falling back to a zero counter in case an exception happens when
-   *   // processing the RPC to fetch counters.
-   *   ListenableFuture faultTolerantFuture = Futures.withFallback(
-   *       fetchCounterFuture, new FutureFallback() {
-   *         public ListenableFuture create(Throwable t) {
-   *           // Returning "0" as the default for the counter when the
-   *           // exception happens.
-   *           return immediateFuture(0);
-   *         }
-   *       }, sameThreadExecutor());}
- * - *

The fallback can also choose to propagate the original exception when - * desired: - * - *

   {@code
-   *   ListenableFuture fetchCounterFuture = ...;
-   *
-   *   // Falling back to a zero counter only in case the exception was a
-   *   // TimeoutException.
-   *   ListenableFuture faultTolerantFuture = Futures.withFallback(
-   *       fetchCounterFuture, new FutureFallback() {
-   *         public ListenableFuture create(Throwable t) {
-   *           if (t instanceof TimeoutException) {
-   *             return immediateFuture(0);
-   *           }
-   *           return immediateFailedFuture(t);
-   *         }
-   *       }, sameThreadExecutor());}
- * - *

When the execution of {@code fallback.create} is fast and lightweight - * (though the {@code Future} it returns need not meet these criteria), - * consider {@linkplain #withFallback(ListenableFuture, FutureFallback) - * omitting the executor} or explicitly specifying {@code - * sameThreadExecutor}. However, be aware of the caveats documented in the - * link above. - * - * @param input the primary input {@code Future} - * @param fallback the {@link FutureFallback} implementation to be called if - * {@code input} fails - * @param executor the executor that runs {@code fallback} if {@code input} - * fails - * @since 14.0 - */ -// public static ListenableFuture withFallback( -// ListenableFuture input, -// FutureFallback fallback, Executor executor) { -// checkNotNull(fallback); -// return new FallbackFuture(input, fallback, executor); -// } - - /** - * A future that falls back on a second, generated future, in case its - * original future fails. - */ -// private static class FallbackFuture extends AbstractFuture { -// -// private volatile ListenableFuture running; -// -// FallbackFuture(ListenableFuture input, -// final FutureFallback fallback, -// final Executor executor) { -// running = input; -// addCallback(running, new FutureCallback() { -// @Override -// public void onSuccess(V value) { -// set(value); -// } -// -// @Override -// public void onFailure(Throwable t) { -// if (isCancelled()) { -// return; -// } -// try { -// running = fallback.create(t); -// if (isCancelled()) { // in case cancel called in the meantime -// running.cancel(wasInterrupted()); -// return; -// } -// addCallback(running, new FutureCallback() { -// @Override -// public void onSuccess(V value) { -// set(value); -// } -// -// @Override -// public void onFailure(Throwable t) { -// if (running.isCancelled()) { -// cancel(false); -// } else { -// setException(t); -// } -// } -// }, sameThreadExecutor()); -// } catch (Throwable e) { -// setException(e); -// } -// } -// }, executor); -// } -// -// @Override -// public boolean cancel(boolean mayInterruptIfRunning) { -// if (super.cancel(mayInterruptIfRunning)) { -// running.cancel(mayInterruptIfRunning); -// return true; -// } -// return false; -// } -// } - - /** - * Returns a new {@code ListenableFuture} whose result is asynchronously - * derived from the result of the given {@code Future}. More precisely, the - * returned {@code Future} takes its result from a {@code Future} produced by - * applying the given {@code AsyncFunction} to the result of the original - * {@code Future}. Example: - * - *

   {@code
-   *   ListenableFuture rowKeyFuture = indexService.lookUp(query);
-   *   AsyncFunction queryFunction =
-   *       new AsyncFunction() {
-   *         public ListenableFuture apply(RowKey rowKey) {
-   *           return dataService.read(rowKey);
-   *         }
-   *       };
-   *   ListenableFuture queryFuture =
-   *       transform(rowKeyFuture, queryFunction);}
- * - *

Note: If the derived {@code Future} is slow or heavyweight to create - * (whether the {@code Future} itself is slow or heavyweight to complete is - * irrelevant), consider {@linkplain #transform(ListenableFuture, - * AsyncFunction, Executor) supplying an executor}. If you do not supply an - * executor, {@code transform} will use {@link - * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some - * caveats for heavier operations. For example, the call to {@code - * function.apply} may run on an unpredictable or undesirable thread: - * - *

    - *
  • If the input {@code Future} is done at the time {@code transform} is - * called, {@code transform} will call {@code function.apply} inline. - *
  • If the input {@code Future} is not yet done, {@code transform} will - * schedule {@code function.apply} to be run by the thread that completes the - * input {@code Future}, which may be an internal system thread such as an - * RPC network thread. - *
- * - *

Also note that, regardless of which thread executes the {@code - * sameThreadExecutor} {@code function.apply}, all other registered but - * unexecuted listeners are prevented from running during its execution, even - * if those listeners are to run in other executors. - * - *

The returned {@code Future} attempts to keep its cancellation state in - * sync with that of the input future and that of the future returned by the - * function. That is, if the returned {@code Future} is cancelled, it will - * attempt to cancel the other two, and if either of the other two is - * cancelled, the returned {@code Future} will receive a callback in which it - * will attempt to cancel itself. - * - * @param input The future to transform - * @param function A function to transform the result of the input future - * to the result of the output future - * @return A future that holds result of the function (if the input succeeded) - * or the original input's failure (if not) - * @since 11.0 - */ -// public static ListenableFuture transform(ListenableFuture input, -// AsyncFunction function) { -// return transform(input, function, MoreExecutors.sameThreadExecutor()); -// } - - /** - * Returns a new {@code ListenableFuture} whose result is asynchronously - * derived from the result of the given {@code Future}. More precisely, the - * returned {@code Future} takes its result from a {@code Future} produced by - * applying the given {@code AsyncFunction} to the result of the original - * {@code Future}. Example: - * - *

   {@code
-   *   ListenableFuture rowKeyFuture = indexService.lookUp(query);
-   *   AsyncFunction queryFunction =
-   *       new AsyncFunction() {
-   *         public ListenableFuture apply(RowKey rowKey) {
-   *           return dataService.read(rowKey);
-   *         }
-   *       };
-   *   ListenableFuture queryFuture =
-   *       transform(rowKeyFuture, queryFunction, executor);}
- * - *

The returned {@code Future} attempts to keep its cancellation state in - * sync with that of the input future and that of the future returned by the - * chain function. That is, if the returned {@code Future} is cancelled, it - * will attempt to cancel the other two, and if either of the other two is - * cancelled, the returned {@code Future} will receive a callback in which it - * will attempt to cancel itself. - * - *

When the execution of {@code function.apply} is fast and lightweight - * (though the {@code Future} it returns need not meet these criteria), - * consider {@linkplain #transform(ListenableFuture, AsyncFunction) omitting - * the executor} or explicitly specifying {@code sameThreadExecutor}. - * However, be aware of the caveats documented in the link above. - * - * @param input The future to transform - * @param function A function to transform the result of the input future - * to the result of the output future - * @param executor Executor to run the function in. - * @return A future that holds result of the function (if the input succeeded) - * or the original input's failure (if not) - * @since 11.0 - */ -// public static ListenableFuture transform(ListenableFuture input, -// AsyncFunction function, -// Executor executor) { -// ChainingListenableFuture output = -// new ChainingListenableFuture(function, input); -// input.addListener(output, executor); -// return output; -// } - - /** - * Returns a new {@code ListenableFuture} whose result is the product of - * applying the given {@code Function} to the result of the given {@code - * Future}. Example: - * - *

   {@code
-   *   ListenableFuture queryFuture = ...;
-   *   Function> rowsFunction =
-   *       new Function>() {
-   *         public List apply(QueryResult queryResult) {
-   *           return queryResult.getRows();
-   *         }
-   *       };
-   *   ListenableFuture> rowsFuture =
-   *       transform(queryFuture, rowsFunction);}
- * - *

Note: If the transformation is slow or heavyweight, consider {@linkplain - * #transform(ListenableFuture, Function, Executor) supplying an executor}. - * If you do not supply an executor, {@code transform} will use {@link - * MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries some - * caveats for heavier operations. For example, the call to {@code - * function.apply} may run on an unpredictable or undesirable thread: - * - *

    - *
  • If the input {@code Future} is done at the time {@code transform} is - * called, {@code transform} will call {@code function.apply} inline. - *
  • If the input {@code Future} is not yet done, {@code transform} will - * schedule {@code function.apply} to be run by the thread that completes the - * input {@code Future}, which may be an internal system thread such as an - * RPC network thread. - *
- * - *

Also note that, regardless of which thread executes the {@code - * sameThreadExecutor} {@code function.apply}, all other registered but - * unexecuted listeners are prevented from running during its execution, even - * if those listeners are to run in other executors. - * - *

The returned {@code Future} attempts to keep its cancellation state in - * sync with that of the input future. That is, if the returned {@code Future} - * is cancelled, it will attempt to cancel the input, and if the input is - * cancelled, the returned {@code Future} will receive a callback in which it - * will attempt to cancel itself. - * - *

An example use of this method is to convert a serializable object - * returned from an RPC into a POJO. - * - * @param input The future to transform - * @param function A Function to transform the results of the provided future - * to the results of the returned future. This will be run in the thread - * that notifies input it is complete. - * @return A future that holds result of the transformation. - * @since 9.0 (in 1.0 as {@code compose}) - */ -// public static ListenableFuture transform(ListenableFuture input, -// final Function function) { -// return transform(input, function, MoreExecutors.sameThreadExecutor()); -// } - - /** - * Returns a new {@code ListenableFuture} whose result is the product of - * applying the given {@code Function} to the result of the given {@code - * Future}. Example: - * - *

   {@code
-   *   ListenableFuture queryFuture = ...;
-   *   Function> rowsFunction =
-   *       new Function>() {
-   *         public List apply(QueryResult queryResult) {
-   *           return queryResult.getRows();
-   *         }
-   *       };
-   *   ListenableFuture> rowsFuture =
-   *       transform(queryFuture, rowsFunction, executor);}
- * - *

The returned {@code Future} attempts to keep its cancellation state in - * sync with that of the input future. That is, if the returned {@code Future} - * is cancelled, it will attempt to cancel the input, and if the input is - * cancelled, the returned {@code Future} will receive a callback in which it - * will attempt to cancel itself. - * - *

An example use of this method is to convert a serializable object - * returned from an RPC into a POJO. - * - *

When the transformation is fast and lightweight, consider {@linkplain - * #transform(ListenableFuture, Function) omitting the executor} or - * explicitly specifying {@code sameThreadExecutor}. However, be aware of the - * caveats documented in the link above. - * - * @param input The future to transform - * @param function A Function to transform the results of the provided future - * to the results of the returned future. - * @param executor Executor to run the function in. - * @return A future that holds result of the transformation. - * @since 9.0 (in 2.0 as {@code compose}) - */ -// public static ListenableFuture transform(ListenableFuture input, -// final Function function, Executor executor) { -// checkNotNull(function); -// AsyncFunction wrapperFunction -// = new AsyncFunction() { -// @Override public ListenableFuture apply(I input) { -// O output = function.apply(input); -// return immediateFuture(output); -// } -// }; -// return transform(input, wrapperFunction, executor); -// } - - /** - * Like {@link #transform(ListenableFuture, Function)} except that the - * transformation {@code function} is invoked on each call to - * {@link Future#get() get()} on the returned future. - * - *

The returned {@code Future} reflects the input's cancellation - * state directly, and any attempt to cancel the returned Future is likewise - * passed through to the input Future. - * - *

Note that calls to {@linkplain Future#get(long, TimeUnit) timed get} - * only apply the timeout to the execution of the underlying {@code Future}, - * not to the execution of the transformation function. - * - *

The primary audience of this method is callers of {@code transform} - * who don't have a {@code ListenableFuture} available and - * do not mind repeated, lazy function evaluation. - * - * @param input The future to transform - * @param function A Function to transform the results of the provided future - * to the results of the returned future. - * @return A future that returns the result of the transformation. - * @since 10.0 - */ -// public static Future lazyTransform(final Future input, -// final Function function) { -// checkNotNull(input); -// checkNotNull(function); -// return new Future() { -// -// @Override -// public boolean cancel(boolean mayInterruptIfRunning) { -// return input.cancel(mayInterruptIfRunning); -// } -// -// @Override -// public boolean isCancelled() { -// return input.isCancelled(); -// } -// -// @Override -// public boolean isDone() { -// return input.isDone(); -// } -// -// @Override -// public O get() throws InterruptedException, ExecutionException { -// return applyTransformation(input.get()); -// } -// -// @Override -// public O get(long timeout, TimeUnit unit) -// throws InterruptedException, ExecutionException, TimeoutException { -// return applyTransformation(input.get(timeout, unit)); -// } -// -// private O applyTransformation(I input) throws ExecutionException { -// try { -// return function.apply(input); -// } catch (Throwable t) { -// throw new ExecutionException(t); -// } -// } -// }; -// } - - /** - * An implementation of {@code ListenableFuture} that also implements - * {@code Runnable} so that it can be used to nest ListenableFutures. - * Once the passed-in {@code ListenableFuture} is complete, it calls the - * passed-in {@code Function} to generate the result. - * - *

For historical reasons, this class has a special case in its exception - * handling: If the given {@code AsyncFunction} throws an {@code - * UndeclaredThrowableException}, {@code ChainingListenableFuture} unwraps it - * and uses its cause as the output future's exception, rather than - * using the {@code UndeclaredThrowableException} itself as it would for other - * exception types. The reason for this is that {@code Futures.transform} used - * to require a {@code Function}, whose {@code apply} method is not allowed to - * throw checked exceptions. Nowadays, {@code Futures.transform} has an - * overload that accepts an {@code AsyncFunction}, whose {@code apply} method - * is allowed to throw checked exception. Users who wish to throw - * checked exceptions should use that overload instead, and we - * should remove the {@code UndeclaredThrowableException} special case. - */ -// private static class ChainingListenableFuture -// extends AbstractFuture implements Runnable { -// -// private AsyncFunction function; -// private ListenableFuture inputFuture; -// private volatile ListenableFuture outputFuture; -// private final CountDownLatch outputCreated = new CountDownLatch(1); -// -// private ChainingListenableFuture( -// AsyncFunction function, -// ListenableFuture inputFuture) { -// this.function = checkNotNull(function); -// this.inputFuture = checkNotNull(inputFuture); -// } -// -// @Override -// public boolean cancel(boolean mayInterruptIfRunning) { -// /* -// * Our additional cancellation work needs to occur even if -// * !mayInterruptIfRunning, so we can't move it into interruptTask(). -// */ -// if (super.cancel(mayInterruptIfRunning)) { -// // This should never block since only one thread is allowed to cancel -// // this Future. -// cancel(inputFuture, mayInterruptIfRunning); -// cancel(outputFuture, mayInterruptIfRunning); -// return true; -// } -// return false; -// } -// -// private void cancel(Future future, -// boolean mayInterruptIfRunning) { -// if (future != null) { -// future.cancel(mayInterruptIfRunning); -// } -// } -// -// @Override -// public void run() { -// try { -// I sourceResult; -// try { -// sourceResult = getUninterruptibly(inputFuture); -// } catch (CancellationException e) { -// // Cancel this future and return. -// // At this point, inputFuture is cancelled and outputFuture doesn't -// // exist, so the value of mayInterruptIfRunning is irrelevant. -// cancel(false); -// return; -// } catch (ExecutionException e) { -// // Set the cause of the exception as this future's exception -// setException(e.getCause()); -// return; -// } -// -// final ListenableFuture outputFuture = this.outputFuture = -// Preconditions.checkNotNull(function.apply(sourceResult), -// "AsyncFunction may not return null."); -// if (isCancelled()) { -// outputFuture.cancel(wasInterrupted()); -// this.outputFuture = null; -// return; -// } -// outputFuture.addListener(new Runnable() { -// @Override -// public void run() { -// try { -// set(getUninterruptibly(outputFuture)); -// } catch (CancellationException e) { -// // Cancel this future and return. -// // At this point, inputFuture and outputFuture are done, so the -// // value of mayInterruptIfRunning is irrelevant. -// cancel(false); -// return; -// } catch (ExecutionException e) { -// // Set the cause of the exception as this future's exception -// setException(e.getCause()); -// } finally { -// // Don't pin inputs beyond completion -// ChainingListenableFuture.this.outputFuture = null; -// } -// } -// }, MoreExecutors.sameThreadExecutor()); -// } catch (UndeclaredThrowableException e) { -// // Set the cause of the exception as this future's exception -// setException(e.getCause()); -// } catch (Throwable t) { -// // This exception is irrelevant in this thread, but useful for the -// // client -// setException(t); -// } finally { -// // Don't pin inputs beyond completion -// function = null; -// inputFuture = null; -// // Allow our get routines to examine outputFuture now. -// outputCreated.countDown(); -// } -// } -// } - - /** - * Returns a new {@code ListenableFuture} whose result is the product of - * calling {@code get()} on the {@code Future} nested within the given {@code - * Future}, effectively chaining the futures one after the other. Example: - * - *

   {@code
-   *   SettableFuture> nested = SettableFuture.create();
-   *   ListenableFuture dereferenced = dereference(nested);}
- * - *

This call has the same cancellation and execution semantics as {@link - * #transform(ListenableFuture, AsyncFunction)}, in that the returned {@code - * Future} attempts to keep its cancellation state in sync with both the - * input {@code Future} and the nested {@code Future}. The transformation - * is very lightweight and therefore takes place in the same thread (either - * the thread that called {@code dereference}, or the thread in which the - * dereferenced future completes). - * - * @param nested The nested future to transform. - * @return A future that holds result of the inner future. - * @since 13.0 - */ -// -// public static ListenableFuture dereference( -// ListenableFuture> nested) { -// return Futures.transform((ListenableFuture) nested, (AsyncFunction) DEREFERENCER); -// } - - /** - * Helper {@code Function} for {@link #dereference}. - */ -// private static final AsyncFunction, Object> DEREFERENCER = -// new AsyncFunction, Object>() { -// @Override public ListenableFuture apply(ListenableFuture input) { -// return input; -// } -// }; - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the - * values of all its input futures, if all succeed. If any input fails, the - * returned future fails. - * - *

The list of results is in the same order as the input list. - * - *

Canceling this future will attempt to cancel all the component futures, - * and if any of the provided futures fails or is canceled, this one is, - * too. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component - * futures - * @since 10.0 - */ -// @Beta -// public static ListenableFuture> allAsList( -// ListenableFuture... futures) { -// return listFuture(ImmutableList.copyOf(futures), true, -// MoreExecutors.sameThreadExecutor()); -// } - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the - * values of all its input futures, if all succeed. If any input fails, the - * returned future fails. - * - *

The list of results is in the same order as the input list. - * - *

Canceling this future will attempt to cancel all the component futures, - * and if any of the provided futures fails or is canceled, this one is, - * too. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component - * futures - * @since 10.0 - */ -// @Beta - public static ListenableFuture> allAsList( - Iterable> futures) { - return listFuture(ImmutableList.copyOf(futures), true, - MoreExecutors.sameThreadExecutor()); - } - - /** - * Creates a new {@code ListenableFuture} whose result is set from the - * supplied future when it completes. Cancelling the supplied future - * will also cancel the returned future, but cancelling the returned - * future will have no effect on the supplied future. - * - * @since 15.0 - */ -// public static ListenableFuture nonCancellationPropagating( -// ListenableFuture future) { -// return new NonCancellationPropagatingFuture(future); -// } - - /** - * A wrapped future that does not propagate cancellation to its delegate. - */ -// private static class NonCancellationPropagatingFuture -// extends AbstractFuture { -// NonCancellationPropagatingFuture(final ListenableFuture delegate) { -// checkNotNull(delegate); -// addCallback(delegate, new FutureCallback() { -// @Override -// public void onSuccess(V result) { -// set(result); -// } -// -// @Override -// public void onFailure(Throwable t) { -// if (delegate.isCancelled()) { -// cancel(false); -// } else { -// setException(t); -// } -// } -// }, sameThreadExecutor()); -// } -// } - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the - * values of all its successful input futures. The list of results is in the - * same order as the input list, and if any of the provided futures fails or - * is canceled, its corresponding position will contain {@code null} (which is - * indistinguishable from the future having a successful value of - * {@code null}). - * - *

Canceling this future will attempt to cancel all the component futures. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component - * futures - * @since 10.0 - */ -// @Beta -// public static ListenableFuture> successfulAsList( -// ListenableFuture... futures) { -// return listFuture(ImmutableList.copyOf(futures), false, -// MoreExecutors.sameThreadExecutor()); -// } - - /** - * Creates a new {@code ListenableFuture} whose value is a list containing the - * values of all its successful input futures. The list of results is in the - * same order as the input list, and if any of the provided futures fails or - * is canceled, its corresponding position will contain {@code null} (which is - * indistinguishable from the future having a successful value of - * {@code null}). - * - *

Canceling this future will attempt to cancel all the component futures. - * - * @param futures futures to combine - * @return a future that provides a list of the results of the component - * futures - * @since 10.0 - */ -// @Beta -// public static ListenableFuture> successfulAsList( -// Iterable> futures) { -// return listFuture(ImmutableList.copyOf(futures), false, -// MoreExecutors.sameThreadExecutor()); -// } - - /** - * Returns a list of delegate futures that correspond to the futures received in the order - * that they complete. Delegate futures return the same value or throw the same exception - * as the corresponding input future returns/throws. - * - *

Cancelling a delegate future has no effect on any input future, since the delegate future - * does not correspond to a specific input future until the appropriate number of input - * futures have completed. At that point, it is too late to cancel the input future. - * The input future's result, which cannot be stored into the cancelled delegate future, - * is ignored. - * - * @since 17.0 - */ -// @Beta -// public static ImmutableList> inCompletionOrder( -// Iterable> futures) { -// // A CLQ may be overkill here. We could save some pointers/memory by synchronizing on an -// // ArrayDeque -// final ConcurrentLinkedQueue> delegates = -// Queues.newConcurrentLinkedQueue(); -// ImmutableList.Builder> listBuilder = ImmutableList.builder(); -// // Using SerializingExecutor here will ensure that each CompletionOrderListener executes -// // atomically and therefore that each returned future is guaranteed to be in completion order. -// // N.B. there are some cases where the use of this executor could have possibly surprising -// // effects when input futures finish at approximately the same time _and_ the output futures -// // have sameThreadExecutor listeners. In this situation, the listeners may end up running on a -// // different thread than if they were attached to the corresponding input future. We believe -// // this to be a negligible cost since: -// // 1. Using the sameThreadExecutor implies that your callback is safe to run on any thread. -// // 2. This would likely only be noticeable if you were doing something expensive or blocking on -// // a sameThreadExecutor listener on one of the output futures which is an antipattern anyway. -// SerializingExecutor executor = new SerializingExecutor(MoreExecutors.sameThreadExecutor()); -// for (final ListenableFuture future : futures) { -// AsyncSettableFuture delegate = AsyncSettableFuture.create(); -// // Must make sure to add the delegate to the queue first in case the future is already done -// delegates.add(delegate); -// future.addListener(new Runnable() { -// @Override public void run() { -// delegates.remove().setFuture(future); -// } -// }, executor); -// listBuilder.add(delegate); -// } -// return listBuilder.build(); -// } - - /** - * Registers separate success and failure callbacks to be run when the {@code - * Future}'s computation is {@linkplain java.util.concurrent.Future#isDone() - * complete} or, if the computation is already complete, immediately. - * - *

There is no guaranteed ordering of execution of callbacks, but any - * callback added through this method is guaranteed to be called once the - * computation is complete. - * - * Example:

 {@code
-   * ListenableFuture future = ...;
-   * addCallback(future,
-   *     new FutureCallback {
-   *       public void onSuccess(QueryResult result) {
-   *         storeInCache(result);
-   *       }
-   *       public void onFailure(Throwable t) {
-   *         reportError(t);
-   *       }
-   *     });}
- * - *

Note: If the callback is slow or heavyweight, consider {@linkplain - * #addCallback(ListenableFuture, FutureCallback, Executor) supplying an - * executor}. If you do not supply an executor, {@code addCallback} will use - * {@link MoreExecutors#sameThreadExecutor sameThreadExecutor}, which carries - * some caveats for heavier operations. For example, the callback may run on - * an unpredictable or undesirable thread: - * - *

    - *
  • If the input {@code Future} is done at the time {@code addCallback} is - * called, {@code addCallback} will execute the callback inline. - *
  • If the input {@code Future} is not yet done, {@code addCallback} will - * schedule the callback to be run by the thread that completes the input - * {@code Future}, which may be an internal system thread such as an RPC - * network thread. - *
- * - *

Also note that, regardless of which thread executes the {@code - * sameThreadExecutor} callback, all other registered but unexecuted listeners - * are prevented from running during its execution, even if those listeners - * are to run in other executors. - * - *

For a more general interface to attach a completion listener to a - * {@code Future}, see {@link ListenableFuture#addListener addListener}. - * - * @param future The future attach the callback to. - * @param callback The callback to invoke when {@code future} is completed. - * @since 10.0 - */ - public static void addCallback(ListenableFuture future, - FutureCallback callback) { - addCallback(future, callback, MoreExecutors.sameThreadExecutor()); - } - - /** - * Registers separate success and failure callbacks to be run when the {@code - * Future}'s computation is {@linkplain java.util.concurrent.Future#isDone() - * complete} or, if the computation is already complete, immediately. - * - *

The callback is run in {@code executor}. - * There is no guaranteed ordering of execution of callbacks, but any - * callback added through this method is guaranteed to be called once the - * computation is complete. - * - * Example:

 {@code
-   * ListenableFuture future = ...;
-   * Executor e = ...
-   * addCallback(future,
-   *     new FutureCallback {
-   *       public void onSuccess(QueryResult result) {
-   *         storeInCache(result);
-   *       }
-   *       public void onFailure(Throwable t) {
-   *         reportError(t);
-   *       }
-   *     }, e);}
- * - *

When the callback is fast and lightweight, consider {@linkplain - * #addCallback(ListenableFuture, FutureCallback) omitting the executor} or - * explicitly specifying {@code sameThreadExecutor}. However, be aware of the - * caveats documented in the link above. - * - *

For a more general interface to attach a completion listener to a - * {@code Future}, see {@link ListenableFuture#addListener addListener}. - * - * @param future The future attach the callback to. - * @param callback The callback to invoke when {@code future} is completed. - * @param executor The executor to run {@code callback} when the future - * completes. - * @since 10.0 - */ - public static void addCallback(final ListenableFuture future, - final FutureCallback callback, Executor executor) { - Runnable callbackListener = new Runnable() { - @Override - public void run() { - final V value; - try { - // TODO(user): (Before Guava release), validate that this - // is the thing for IE. - value = getUninterruptibly(future); - } catch (ExecutionException e) { - callback.onFailure(e.getCause()); - return; - } catch (RuntimeException e) { - callback.onFailure(e); - return; - } catch (Error e) { - callback.onFailure(e); - return; - } - callback.onSuccess(value); - } - }; - future.addListener(callbackListener, executor); - } - - /** - * Returns the result of {@link Future#get()}, converting most exceptions to a - * new instance of the given checked exception type. This reduces boilerplate - * for a common use of {@code Future} in which it is unnecessary to - * programmatically distinguish between exception types or to extract other - * information from the exception instance. - * - *

Exceptions from {@code Future.get} are treated as follows: - *

    - *
  • Any {@link ExecutionException} has its cause wrapped in an - * {@code X} if the cause is a checked exception, an {@link - * UncheckedExecutionException} if the cause is a {@code - * RuntimeException}, or an {@link ExecutionError} if the cause is an - * {@code Error}. - *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after - * restoring the interrupt). - *
  • Any {@link CancellationException} is propagated untouched, as is any - * other {@link RuntimeException} (though {@code get} implementations are - * discouraged from throwing such exceptions). - *
- * - *

The overall principle is to continue to treat every checked exception as a - * checked exception, every unchecked exception as an unchecked exception, and - * every error as an error. In addition, the cause of any {@code - * ExecutionException} is wrapped in order to ensure that the new stack trace - * matches that of the current thread. - * - *

Instances of {@code exceptionClass} are created by choosing an arbitrary - * public constructor that accepts zero or more arguments, all of type {@code - * String} or {@code Throwable} (preferring constructors with at least one - * {@code String}) and calling the constructor via reflection. If the - * exception did not already have a cause, one is set by calling {@link - * Throwable#initCause(Throwable)} on it. If no such constructor exists, an - * {@code IllegalArgumentException} is thrown. - * - * @throws X if {@code get} throws any checked exception except for an {@code - * ExecutionException} whose cause is not itself a checked exception - * @throws UncheckedExecutionException if {@code get} throws an {@code - * ExecutionException} with a {@code RuntimeException} as its cause - * @throws ExecutionError if {@code get} throws an {@code ExecutionException} - * with an {@code Error} as its cause - * @throws CancellationException if {@code get} throws a {@code - * CancellationException} - * @throws IllegalArgumentException if {@code exceptionClass} extends {@code - * RuntimeException} or does not have a suitable constructor - * @since 10.0 - */ -// public static V get( -// Future future, Class exceptionClass) throws X { -// checkNotNull(future); -// checkArgument(!RuntimeException.class.isAssignableFrom(exceptionClass), -// "Futures.get exception type (%s) must not be a RuntimeException", -// exceptionClass); -// try { -// return future.get(); -// } catch (InterruptedException e) { -// currentThread().interrupt(); -// throw newWithCause(exceptionClass, e); -// } catch (ExecutionException e) { -// wrapAndThrowExceptionOrError(e.getCause(), exceptionClass); -// throw new AssertionError(); -// } -// } - - /** - * Returns the result of {@link Future#get(long, TimeUnit)}, converting most - * exceptions to a new instance of the given checked exception type. This - * reduces boilerplate for a common use of {@code Future} in which it is - * unnecessary to programmatically distinguish between exception types or to - * extract other information from the exception instance. - * - *

Exceptions from {@code Future.get} are treated as follows: - *

    - *
  • Any {@link ExecutionException} has its cause wrapped in an - * {@code X} if the cause is a checked exception, an {@link - * UncheckedExecutionException} if the cause is a {@code - * RuntimeException}, or an {@link ExecutionError} if the cause is an - * {@code Error}. - *
  • Any {@link InterruptedException} is wrapped in an {@code X} (after - * restoring the interrupt). - *
  • Any {@link TimeoutException} is wrapped in an {@code X}. - *
  • Any {@link CancellationException} is propagated untouched, as is any - * other {@link RuntimeException} (though {@code get} implementations are - * discouraged from throwing such exceptions). - *
- * - *

The overall principle is to continue to treat every checked exception as a - * checked exception, every unchecked exception as an unchecked exception, and - * every error as an error. In addition, the cause of any {@code - * ExecutionException} is wrapped in order to ensure that the new stack trace - * matches that of the current thread. - * - *

Instances of {@code exceptionClass} are created by choosing an arbitrary - * public constructor that accepts zero or more arguments, all of type {@code - * String} or {@code Throwable} (preferring constructors with at least one - * {@code String}) and calling the constructor via reflection. If the - * exception did not already have a cause, one is set by calling {@link - * Throwable#initCause(Throwable)} on it. If no such constructor exists, an - * {@code IllegalArgumentException} is thrown. - * - * @throws X if {@code get} throws any checked exception except for an {@code - * ExecutionException} whose cause is not itself a checked exception - * @throws UncheckedExecutionException if {@code get} throws an {@code - * ExecutionException} with a {@code RuntimeException} as its cause - * @throws ExecutionError if {@code get} throws an {@code ExecutionException} - * with an {@code Error} as its cause - * @throws CancellationException if {@code get} throws a {@code - * CancellationException} - * @throws IllegalArgumentException if {@code exceptionClass} extends {@code - * RuntimeException} or does not have a suitable constructor - * @since 10.0 - */ -// public static V get( -// Future future, long timeout, TimeUnit unit, Class exceptionClass) -// throws X { -// checkNotNull(future); -// checkNotNull(unit); -// checkArgument(!RuntimeException.class.isAssignableFrom(exceptionClass), -// "Futures.get exception type (%s) must not be a RuntimeException", -// exceptionClass); -// try { -// return future.get(timeout, unit); -// } catch (InterruptedException e) { -// currentThread().interrupt(); -// throw newWithCause(exceptionClass, e); -// } catch (TimeoutException e) { -// throw newWithCause(exceptionClass, e); -// } catch (ExecutionException e) { -// wrapAndThrowExceptionOrError(e.getCause(), exceptionClass); -// throw new AssertionError(); -// } -// } - -// private static void wrapAndThrowExceptionOrError( -// Throwable cause, Class exceptionClass) throws X { -// if (cause instanceof Error) { -// throw new ExecutionError((Error) cause); -// } -// if (cause instanceof RuntimeException) { -// throw new UncheckedExecutionException(cause); -// } -// throw newWithCause(exceptionClass, cause); -// } - - /** - * Returns the result of calling {@link Future#get()} uninterruptibly on a - * task known not to throw a checked exception. This makes {@code Future} more - * suitable for lightweight, fast-running tasks that, barring bugs in the - * code, will not fail. This gives it exception-handling behavior similar to - * that of {@code ForkJoinTask.join}. - * - *

Exceptions from {@code Future.get} are treated as follows: - *

    - *
  • Any {@link ExecutionException} has its cause wrapped in an - * {@link UncheckedExecutionException} (if the cause is an {@code - * Exception}) or {@link ExecutionError} (if the cause is an {@code - * Error}). - *
  • Any {@link InterruptedException} causes a retry of the {@code get} - * call. The interrupt is restored before {@code getUnchecked} returns. - *
  • Any {@link CancellationException} is propagated untouched. So is any - * other {@link RuntimeException} ({@code get} implementations are - * discouraged from throwing such exceptions). - *
- * - *

The overall principle is to eliminate all checked exceptions: to loop to - * avoid {@code InterruptedException}, to pass through {@code - * CancellationException}, and to wrap any exception from the underlying - * computation in an {@code UncheckedExecutionException} or {@code - * ExecutionError}. - * - *

For an uninterruptible {@code get} that preserves other exceptions, see - * {@link Uninterruptibles#getUninterruptibly(Future)}. - * - * @throws UncheckedExecutionException if {@code get} throws an {@code - * ExecutionException} with an {@code Exception} as its cause - * @throws ExecutionError if {@code get} throws an {@code ExecutionException} - * with an {@code Error} as its cause - * @throws CancellationException if {@code get} throws a {@code - * CancellationException} - * @since 10.0 - */ - public static V getUnchecked(Future future) { -// checkNotNull(future); - try { - return getUninterruptibly(future); - } catch (ExecutionException e) { - wrapAndThrowUnchecked(e.getCause()); - throw new AssertionError(); - } - } - - public static V getUninterruptibly(Future future) - throws ExecutionException { - boolean interrupted = false; - try { - while (true) { - try { - return future.get(); - } catch (InterruptedException e) { - interrupted = true; - } - } - } finally { - if (interrupted) { - Thread.currentThread().interrupt(); - } - } - } - - private static void wrapAndThrowUnchecked(Throwable cause) { - if (cause instanceof Error) { - throw new ExecutionError((Error) cause); - } - /* - * It's a non-Error, non-Exception Throwable. From my survey of such - * classes, I believe that most users intended to extend Exception, so we'll - * treat it like an Exception. - */ - throw new UncheckedExecutionException(cause); - } - - /* - * TODO(user): FutureChecker interface for these to be static methods on? If - * so, refer to it in the (static-method) Futures.get documentation - */ - - /* - * Arguably we don't need a timed getUnchecked because any operation slow - * enough to require a timeout is heavyweight enough to throw a checked - * exception and therefore be inappropriate to use with getUnchecked. Further, - * it's not clear that converting the checked TimeoutException to a - * RuntimeException -- especially to an UncheckedExecutionException, since it - * wasn't thrown by the computation -- makes sense, and if we don't convert - * it, the user still has to write a try-catch block. - * - * If you think you would use this method, let us know. - */ - -// private static X newWithCause( -// Class exceptionClass, Throwable cause) { -// // getConstructors() guarantees this as long as we don't modify the array. -// -// List> constructors = -// (List) Arrays.asList(exceptionClass.getConstructors()); -// for (Constructor constructor : preferringStrings(constructors)) { -// X instance = newFromConstructor(constructor, cause); -// if (instance != null) { -// if (instance.getCause() == null) { -// instance.initCause(cause); -// } -// return instance; -// } -// } -// throw new IllegalArgumentException( -// "No appropriate constructor for exception of type " + exceptionClass -// + " in response to chained exception", cause); -// } - -// private static List> -// preferringStrings(List> constructors) { -// return WITH_STRING_PARAM_FIRST.sortedCopy(constructors); -// } -// -// private static final Ordering> WITH_STRING_PARAM_FIRST = -// Ordering.natural().onResultOf(new Function, Boolean>() { -// @Override public boolean test(Constructor input) { -// return asList(input.getParameterTypes()).contains(String.class); -// } -// }).reverse(); - -// private static X newFromConstructor( -// Constructor constructor, Throwable cause) { -// Class[] paramTypes = constructor.getParameterTypes(); -// Object[] params = new Object[paramTypes.length]; -// for (int i = 0; i < paramTypes.length; i++) { -// Class paramType = paramTypes[i]; -// if (paramType.equals(String.class)) { -// params[i] = cause.toString(); -// } else if (paramType.equals(Throwable.class)) { -// params[i] = cause; -// } else { -// return null; -// } -// } -// try { -// return constructor.newInstance(params); -// } catch (IllegalArgumentException e) { -// return null; -// } catch (InstantiationException e) { -// return null; -// } catch (IllegalAccessException e) { -// return null; -// } catch (InvocationTargetException e) { -// return null; -// } -// } - - private interface FutureCombiner { - C combine(List values); - } - - private static class CombinedFuture extends AbstractFuture> { - private static final Logger logger = - Logger.getLogger(CombinedFuture.class.getName()); - - ImmutableList> futures; - final boolean allMustSucceed; - final AtomicInteger remaining; -// FutureCombiner combiner; - List values; - final Object seenExceptionsLock = new Object(); - Set seenExceptions; - - CombinedFuture( - ImmutableList> futures, - boolean allMustSucceed, Executor listenerExecutor // , -// FutureCombiner combiner - ) { - this.futures = futures; - this.allMustSucceed = allMustSucceed; - this.remaining = new AtomicInteger(futures.size()); -// this.combiner = combiner; - this.values = new ArrayList(futures.size()); - init(listenerExecutor); - } - - /** - * Must be called at the end of the constructor. - */ - protected void init(final Executor listenerExecutor) { - // First, schedule cleanup to execute when the Future is done. - addListener(new Runnable() { - @Override - public void run() { - // Cancel all the component futures. - if (CombinedFuture.this.isCancelled()) { - for (ListenableFuture future : CombinedFuture.this.futures) { - future.cancel(CombinedFuture.this.wasInterrupted()); - } - } - - // Let go of the memory held by other futures - CombinedFuture.this.futures = null; - - // By now the values array has either been set as the Future's value, - // or (in case of failure) is no longer useful. - CombinedFuture.this.values = null; - - // The combiner may also hold state, so free that as well -// CombinedFuture.this.combiner = null; - } - }, MoreExecutors.sameThreadExecutor()); - - // Now begin the "real" initialization. - - // Corner case: List is empty. - if (futures.isEmpty()) { - set(ImmutableList.of()); - return; - } - - // Populate the results list with null initially. - for (int i = 0; i < futures.size(); ++i) { - values.add(null); - } - - // Register a listener on each Future in the list to update - // the state of this future. - // Note that if all the futures on the list are done prior to completing - // this loop, the last call to addListener() will callback to - // setOneValue(), transitively call our cleanup listener, and set - // this.futures to null. - // This is not actually a problem, since the foreach only needs - // this.futures to be non-null at the beginning of the loop. - int i = 0; - for (final ListenableFuture listenable : futures) { - final int index = i++; - listenable.addListener(new Runnable() { - @Override - public void run() { - setOneValue(index, listenable); - } - }, listenerExecutor); - } - } - - /** - * Fails this future with the given Throwable if {@link #allMustSucceed} is - * true. Also, logs the throwable if it is an {@link Error} or if - * {@link #allMustSucceed} is {@code true}, the throwable did not cause - * this future to fail, and it is the first time we've seen that particular Throwable. - */ - private void setExceptionAndMaybeLog(Throwable throwable) { - boolean visibleFromOutputFuture = false; - boolean firstTimeSeeingThisException = true; - if (allMustSucceed) { - // As soon as the first one fails, throw the exception up. - // The result of all other inputs is then ignored. - visibleFromOutputFuture = super.setException(throwable); - - synchronized (seenExceptionsLock) { - if (seenExceptions == null) { - seenExceptions = Sets.newHashSet(); - } - firstTimeSeeingThisException = seenExceptions.add(throwable); - } - } - - if (throwable instanceof Error - || (allMustSucceed && !visibleFromOutputFuture && firstTimeSeeingThisException)) { - logger.log(Level.SEVERE, "input future failed.", throwable); - } - } - - /** - * Sets the value at the given index to that of the given future. - */ - private void setOneValue(int index, Future future) { - List localValues = values; - // TODO(user): This check appears to be redundant since values is - // assigned null only after the future completes. However, values - // is not volatile so it may be possible for us to observe the changes - // to these two values in a different order... which I think is why - // we need to check both. Clear up this craziness either by making - // values volatile or proving that it doesn't need to be for some other - // reason. - if (isDone() || localValues == null) { - // Some other future failed or has been cancelled, causing this one to - // also be cancelled or have an exception set. This should only happen - // if allMustSucceed is true or if the output itself has been - // cancelled. - checkState(allMustSucceed || isCancelled(), - "Future was done before all dependencies completed"); - } - - try { - checkState(future.isDone(), - "Tried to set value from future which is not done"); - V returnValue = getUninterruptibly(future); - if (localValues != null) { - localValues.set(index, returnValue); - } - } catch (CancellationException e) { - if (allMustSucceed) { - // Set ourselves as cancelled. Let the input futures keep running - // as some of them may be used elsewhere. - 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) { -// FutureCombiner localCombiner = combiner; - if (/* localCombiner != null && */ localValues != null) { - set(localValues); - } else { - checkState(isDone(), "Future is not done"); - } - } - } - } - - } - - /** Used for {@link #allAsList} and {@link #successfulAsList}. */ - private static ListenableFuture> listFuture( - ImmutableList> futures, - boolean allMustSucceed, Executor listenerExecutor) { - return new CombinedFuture( - futures, allMustSucceed, listenerExecutor); -// new FutureCombiner>() { -// @Override -// public List combine(List values) { -//// List result = Lists.newArrayList(); -//// for (V element : values) { -//// result.add(element); -//// } -// return Collections.unmodifiableList(values); -// } -// }); - } - - /** - * A checked future that uses a function to map from exceptions to the - * appropriate checked type. - */ -// private static class MappingCheckedFuture extends -// AbstractCheckedFuture { -// -// final Function mapper; -// -// MappingCheckedFuture(ListenableFuture delegate, -// Function mapper) { -// super(delegate); -// -// this.mapper = checkNotNull(mapper); -// } -// -// @Override -// protected X mapException(Exception e) { -// return mapper.apply(e); -// } -// } - private static void checkState(boolean expression, String errorMessage) { - if (!expression) { - throw new IllegalStateException(errorMessage); - } - } -} diff --git a/common/src/main/java/common/future/ListenableFuture.java b/common/src/main/java/common/future/ListenableFuture.java deleted file mode 100644 index c8417947..00000000 --- a/common/src/main/java/common/future/ListenableFuture.java +++ /dev/null @@ -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. - * - *

See the Guava User Guide article on - * {@code ListenableFuture}. - * - *

Purpose

- * - *

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. - * - *

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:

   {@code
- *   final String name = ...;
- *   inFlight.add(name);
- *   ListenableFuture 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);}
- * - *

How to get an instance

- * - *

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: - *

    - *
  • 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.) - *
  • 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}.) - *
- * - *

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 extends Future { - /** - * 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. - * - *

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. - * - *

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. - * - *

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: - * - *

    - *
  • If this {@code Future} is done at the time {@code addListener} is - * called, {@code addListener} will execute the listener inline. - *
  • 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. - *
- * - *

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. - * - *

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); -} diff --git a/common/src/main/java/common/future/ListenableFutureTask.java b/common/src/main/java/common/future/ListenableFutureTask.java deleted file mode 100644 index e2b9450b..00000000 --- a/common/src/main/java/common/future/ListenableFutureTask.java +++ /dev/null @@ -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}. - * - *

- * - * @author Sven Mawson - * @since 1.0 - */ -public class ListenableFutureTask extends FutureTask - implements ListenableFuture { - // 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 ListenableFutureTask create(Callable callable) { - return new ListenableFutureTask(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 ListenableFutureTask create( - Runnable runnable, V result) { - return new ListenableFutureTask(runnable, result); - } - - ListenableFutureTask(Callable 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(); - } -} diff --git a/common/src/main/java/common/future/MoreExecutors.java b/common/src/main/java/common/future/MoreExecutors.java deleted file mode 100644 index ad8b8f14..00000000 --- a/common/src/main/java/common/future/MoreExecutors.java +++ /dev/null @@ -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. - * - *

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. - * - *

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. - * - *

This method waits 120 seconds before continuing with JVM termination, - * even if the executor has not finished its work. - * - *

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. - * - *

This method waits 120 seconds before continuing with JVM termination, - * even if the executor has not finished its work. - * - *

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). - * - *

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. - * - *

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 (mostly source-compatible 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 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 ListenableFutureTask newTaskFor(Runnable runnable, T value) { - return ListenableFutureTask.create(runnable, value); - } - - @Override protected final ListenableFutureTask newTaskFor(Callable callable) { - return ListenableFutureTask.create(callable); - } - - @Override public ListenableFuture submit(Runnable task) { - return (ListenableFuture) super.submit(task); - } - - @Override public ListenableFuture submit(Runnable task, T result) { - return (ListenableFuture) super.submit(task, result); - } - - @Override public ListenableFuture submit(Callable task) { - return (ListenableFuture) 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}. - * - *

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}. - * - *

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 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 task = -// ListenableFutureTask.create(command, null); -// ScheduledFuture scheduled = delegate.schedule(task, delay, unit); -// return new ListenableScheduledTask(task, scheduled); -// } -// -// @Override -// public ListenableScheduledFuture schedule( -// Callable callable, long delay, TimeUnit unit) { -// ListenableFutureTask task = ListenableFutureTask.create(callable); -// ScheduledFuture scheduled = delegate.schedule(task, delay, unit); -// return new ListenableScheduledTask(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(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(task, scheduled); -// } -// -// private static final class ListenableScheduledTask -// extends SimpleForwardingListenableFuture -// implements ListenableScheduledFuture { -// -// private final ScheduledFuture scheduledDelegate; -// -// public ListenableScheduledTask( -// ListenableFuture 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 -// 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 invokeAnyImpl(ListeningExecutorService executorService, -// Collection> tasks, boolean timed, long nanos) -// throws InterruptedException, ExecutionException, TimeoutException { -// checkNotNull(executorService); -// int ntasks = tasks.size(); -// checkArgument(ntasks > 0); -// List> futures = Lists.newArrayListWithCapacity(ntasks); -// BlockingQueue> 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> it = tasks.iterator(); -// -// futures.add(submitAndAddQueueListener(executorService, it.next(), futureQueue)); -// --ntasks; -// int active = 1; -// -// for (;;) { -// Future 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 f : futures) { -// f.cancel(true); -// } -// } -// } - - /** - * Submits the task and adds a listener that adds the future to {@code queue} when it completes. - */ -// private static ListenableFuture submitAndAddQueueListener( -// ListeningExecutorService executorService, Callable task, -// final BlockingQueue> queue) { -// final ListenableFuture 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. - * - *

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? Functions to - // calculate names? - - /** - * Creates an {@link Executor} that renames the {@link Thread threads} that its tasks run in. - * - *

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 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. - * - *

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 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 Callable wrapTask(Callable 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. - * - *

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 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 Callable wrapTask(Callable 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. - * - *

The method takes the following steps: - *

    - *
  1. calls {@link ExecutorService#shutdown()}, disabling acceptance of new submitted tasks. - *
  2. waits for half of the specified timeout. - *
  3. if the timeout expires, it calls {@link ExecutorService#shutdownNow()}, cancelling - * pending tasks and interrupting running tasks. - *
  4. waits for the other half of the specified timeout. - *
- * - *

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 or 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(); -// } -} diff --git a/common/src/main/java/common/future/ThreadFactoryBuilder.java b/common/src/main/java/common/future/ThreadFactoryBuilder.java deleted file mode 100644 index a115d0fa..00000000 --- a/common/src/main/java/common/future/ThreadFactoryBuilder.java +++ /dev/null @@ -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: - *

    - *
  • whether threads should be marked as {@linkplain Thread#setDaemon daemon} - * threads - *
  • a {@linkplain ThreadFactoryBuilder#setNameFormat naming format} - *
  • a {@linkplain Thread#setPriority thread priority} - *
  • an {@linkplain Thread#setUncaughtExceptionHandler uncaught exception - * handler} - *
  • a {@linkplain ThreadFactory#newThread backing thread factory} - *
- *

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; - } - }; - } -} diff --git a/common/src/main/java/common/future/UncheckedExecutionException.java b/common/src/main/java/common/future/UncheckedExecutionException.java deleted file mode 100644 index b0808676..00000000 --- a/common/src/main/java/common/future/UncheckedExecutionException.java +++ /dev/null @@ -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. - * - *

{@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. - * - *

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; -} diff --git a/common/src/main/java/common/log/Log.java b/common/src/main/java/common/log/Log.java index ea68b873..657e0ed7 100644 --- a/common/src/main/java/common/log/Log.java +++ b/common/src/main/java/common/log/Log.java @@ -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 schedule(Runnable run) { - return null; + public void schedule(Runnable run) { } public boolean isMainThread() { diff --git a/common/src/main/java/common/net/bootstrap/Bootstrap.java b/common/src/main/java/common/net/bootstrap/Bootstrap.java index dd59fb0d..1629ce28 100644 --- a/common/src/main/java/common/net/bootstrap/Bootstrap.java +++ b/common/src/main/java/common/net/bootstrap/Bootstrap.java @@ -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 { - 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 { for (Entry, Object> e: options.entrySet()) { try { if (!channel.config().setOption((ChannelOption) 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); } } } diff --git a/common/src/main/java/common/net/bootstrap/ServerBootstrap.java b/common/src/main/java/common/net/bootstrap/ServerBootstrap.java index 96144f92..82d71bfd 100644 --- a/common/src/main/java/common/net/bootstrap/ServerBootstrap.java +++ b/common/src/main/java/common/net/bootstrap/ServerBootstrap.java @@ -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 { - private static final InternalLogger logger = InternalLoggerFactory.getInstance(ServerBootstrap.class); - private final Map, Object> childOptions = new LinkedHashMap, Object>(); private final Map, Object> childAttrs = new LinkedHashMap, Object>(); private volatile EventLoopGroup childGroup; @@ -193,7 +190,7 @@ public final class ServerBootstrap extends AbstractBootstrap, Object> e: childOptions) { try { if (!child.config().setOption((ChannelOption) 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 heapArena; final PoolArena 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()); } } diff --git a/common/src/main/java/common/net/buffer/PooledByteBufAllocator.java b/common/src/main/java/common/net/buffer/PooledByteBufAllocator.java index a0b0ca4e..3202a0e9 100644 --- a/common/src/main/java/common/net/buffer/PooledByteBufAllocator.java +++ b/common/src/main/java/common/net/buffer/PooledByteBufAllocator.java @@ -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); } } diff --git a/common/src/main/java/common/net/channel/AbstractChannel.java b/common/src/main/java/common/net/channel/AbstractChannel.java index 2330ef86..d3336f86 100644 --- a/common/src/main/java/common/net/channel/AbstractChannel.java +++ b/common/src/main/java/common/net/channel/AbstractChannel.java @@ -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); } } } diff --git a/common/src/main/java/common/net/channel/AbstractChannelHandlerContext.java b/common/src/main/java/common/net/channel/AbstractChannelHandlerContext.java index 204bd7ab..506055ad 100644 --- a/common/src/main/java/common/net/channel/AbstractChannelHandlerContext.java +++ b/common/src/main/java/common/net/channel/AbstractChannelHandlerContext.java @@ -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); } diff --git a/common/src/main/java/common/net/channel/ChannelInitializer.java b/common/src/main/java/common/net/channel/ChannelInitializer.java index 31ad3abd..9fe6e61e 100644 --- a/common/src/main/java/common/net/channel/ChannelInitializer.java +++ b/common/src/main/java/common/net/channel/ChannelInitializer.java @@ -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 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 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); diff --git a/common/src/main/java/common/net/channel/ChannelOutboundBuffer.java b/common/src/main/java/common/net/channel/ChannelOutboundBuffer.java index e3621143..df425939 100644 --- a/common/src/main/java/common/net/channel/ChannelOutboundBuffer.java +++ b/common/src/main/java/common/net/channel/ChannelOutboundBuffer.java @@ -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 NIO_BUFFERS = new FastThreadLocal() { @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); } } diff --git a/common/src/main/java/common/net/channel/DefaultChannelPipeline.java b/common/src/main/java/common/net/channel/DefaultChannelPipeline.java index 86d549c1..f469f444 100644 --- a/common/src/main/java/common/net/channel/DefaultChannelPipeline.java +++ b/common/src/main/java/common/net/channel/DefaultChannelPipeline.java @@ -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, 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 { diff --git a/common/src/main/java/common/net/channel/MultithreadEventLoopGroup.java b/common/src/main/java/common/net/channel/MultithreadEventLoopGroup.java index 0a5f4e1e..dfb72375 100644 --- a/common/src/main/java/common/net/channel/MultithreadEventLoopGroup.java +++ b/common/src/main/java/common/net/channel/MultithreadEventLoopGroup.java @@ -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); } } diff --git a/common/src/main/java/common/net/channel/nio/AbstractNioChannel.java b/common/src/main/java/common/net/channel/nio/AbstractNioChannel.java index 214f1de2..3679de13 100644 --- a/common/src/main/java/common/net/channel/nio/AbstractNioChannel.java +++ b/common/src/main/java/common/net/channel/nio/AbstractNioChannel.java @@ -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); } } diff --git a/common/src/main/java/common/net/channel/nio/NioEventLoop.java b/common/src/main/java/common/net/channel/nio/NioEventLoop.java index dcb46d02..48258c7a 100644 --- a/common/src/main/java/common/net/channel/nio/NioEventLoop.java +++ b/common/src/main/java/common/net/channel/nio/NioEventLoop.java @@ -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); } } } diff --git a/common/src/main/java/common/net/channel/socket/nio/NioServerSocketChannel.java b/common/src/main/java/common/net/channel/socket/nio/NioServerSocketChannel.java index b006e1fd..b49ddf56 100644 --- a/common/src/main/java/common/net/channel/socket/nio/NioServerSocketChannel.java +++ b/common/src/main/java/common/net/channel/socket/nio/NioServerSocketChannel.java @@ -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); } } diff --git a/common/src/main/java/common/net/util/NetUtil.java b/common/src/main/java/common/net/util/NetUtil.java index 99e420a2..12f1f760 100644 --- a/common/src/main/java/common/net/util/NetUtil.java +++ b/common/src/main/java/common/net/util/NetUtil.java @@ -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); } } diff --git a/common/src/main/java/common/net/util/Recycler.java b/common/src/main/java/common/net/util/Recycler.java index 9fb120d3..b897ebed 100644 --- a/common/src/main/java/common/net/util/Recycler.java +++ b/common/src/main/java/common/net/util/Recycler.java @@ -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 { - 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 { } 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); diff --git a/common/src/main/java/common/net/util/ReferenceCountUtil.java b/common/src/main/java/common/net/util/ReferenceCountUtil.java index 7c55c48b..7af4b793 100644 --- a/common/src/main/java/common/net/util/ReferenceCountUtil.java +++ b/common/src/main/java/common/net/util/ReferenceCountUtil.java @@ -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); } } diff --git a/common/src/main/java/common/net/util/ResourceLeakDetector.java b/common/src/main/java/common/net/util/ResourceLeakDetector.java index 0159efd3..9c7ed3f9 100644 --- a/common/src/main/java/common/net/util/ResourceLeakDetector.java +++ b/common/src/main/java/common/net/util/ResourceLeakDetector.java @@ -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 { @@ -64,14 +63,12 @@ public final class ResourceLeakDetector { 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 { } 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 { } 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 { // 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 { 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); } diff --git a/common/src/main/java/common/net/util/ThreadDeathWatcher.java b/common/src/main/java/common/net/util/ThreadDeathWatcher.java index 10205967..09fcf6de 100644 --- a/common/src/main/java/common/net/util/ThreadDeathWatcher.java +++ b/common/src/main/java/common/net/util/ThreadDeathWatcher.java @@ -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 ++; diff --git a/common/src/main/java/common/net/util/concurrent/DefaultPromise.java b/common/src/main/java/common/net/util/concurrent/DefaultPromise.java index f7cad80a..db5b7928 100644 --- a/common/src/main/java/common/net/util/concurrent/DefaultPromise.java +++ b/common/src/main/java/common/net/util/concurrent/DefaultPromise.java @@ -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 extends AbstractFuture implements Promise { - 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 extends AbstractFuture implements Promise { 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 extends AbstractFuture implements Promise { 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 extends AbstractFuture implements Promise { 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); } } } diff --git a/common/src/main/java/common/net/util/concurrent/GlobalEventExecutor.java b/common/src/main/java/common/net/util/concurrent/GlobalEventExecutor.java index 103143b6..306acd3a 100644 --- a/common/src/main/java/common/net/util/concurrent/GlobalEventExecutor.java +++ b/common/src/main/java/common/net/util/concurrent/GlobalEventExecutor.java @@ -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) { diff --git a/common/src/main/java/common/net/util/concurrent/SingleThreadEventExecutor.java b/common/src/main/java/common/net/util/concurrent/SingleThreadEventExecutor.java index 044f794f..721577b6 100644 --- a/common/src/main/java/common/net/util/concurrent/SingleThreadEventExecutor.java +++ b/common/src/main/java/common/net/util/concurrent/SingleThreadEventExecutor.java @@ -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; } diff --git a/common/src/main/java/common/net/util/internal/logging/MessageFormatter.java b/common/src/main/java/common/net/util/internal/NetLog.java similarity index 53% rename from common/src/main/java/common/net/util/internal/logging/MessageFormatter.java rename to common/src/main/java/common/net/util/internal/NetLog.java index a1e956ad..59c64109 100644 --- a/common/src/main/java/common/net/util/internal/logging/MessageFormatter.java +++ b/common/src/main/java/common/net/util/internal/NetLog.java @@ -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. - *

- *

- * For example, - *

- *

- * MessageFormatter.format("Hi {}.", "there")
- * 
- *

- * will return the string "Hi there.". - *

- * The {} pair is called the formatting anchor. It serves to designate - * the location where arguments need to be substituted within the message - * pattern. - *

- * In case your message contains the '{' or the '}' character, you do not have - * to do anything special unless the '}' character immediately follows '{'. For - * example, - *

- *

- * MessageFormatter.format("Set {1,2,3} is not equal to {}.", "1,2");
- * 
- *

- * will return the string "Set {1,2,3} is not equal to 1,2.". - *

- *

- * If for whatever reason you need to place the string "{}" in the message - * without its formatting anchor 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, - *

- *

- * MessageFormatter.format("Set \\{} is not equal to {}.", "1,2");
- * 
- *

- * will return the string "Set {} is not equal to 1,2.". - *

- *

- * The escaping behavior just described can be overridden by escaping the escape - * character '\'. Calling - *

- *

- * MessageFormatter.format("File name is C:\\\\{}.", "file.zip");
- * 
- *

- * will return the string "File name is C:\file.zip". - *

- *

- * 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. - *

- *

- * 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. - *

- * For example, - *

- *

-     * MessageFormatter.format("Hi {}.", "there");
-     * 
- *

- * will return the string "Hi there.". - *

- * - * @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 format(String messagePattern, Object arg) { return arrayFormat(messagePattern, new Object[]{arg}); } - /** - * Performs a two argument substitution for the 'messagePattern' passed as - * parameter. - *

- * For example, - *

- *

-     * MessageFormatter.format("Hi {}. My name is {}.", "Alice", "Bob");
-     * 
- *

- * 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 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 arrayFormat(final String messagePattern, final Object[] argArray) { Throwable throwableCandidate = getThrowableCandidate(argArray); if (messagePattern == null) { - return new FormattingTuple(null, argArray, throwableCandidate); + return new Pair("Error:", throwableCandidate); } if (argArray == null) { - return new FormattingTuple(messagePattern); + return new Pair(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(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(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(sbuf.toString(), throwableCandidate); } else { - return new FormattingTuple(sbuf.toString(), argArray, null); + return new Pair(sbuf.toString(), null); } } - static boolean isEscapedDelimeter(String messagePattern, + private static boolean isEscapedDelimeter(String messagePattern, int delimeterStartIndex) { if (delimeterStartIndex == 0) { @@ -254,7 +106,7 @@ final class MessageFormatter { return messagePattern.charAt(delimeterStartIndex - 1) == ESCAPE_CHAR; } - static boolean isDoubleEscaped(String messagePattern, + private static boolean isDoubleEscaped(String messagePattern, int delimeterStartIndex) { return delimeterStartIndex >= 2 && messagePattern.charAt(delimeterStartIndex - 2) == ESCAPE_CHAR; } @@ -421,7 +273,126 @@ final class MessageFormatter { } sbuf.append(']'); } + + public static boolean isDebugEnabled() { + return Log.getLevel().ordinal() >= LogLevel.DEBUG.ordinal(); + } - private MessageFormatter() { - } + public static boolean isWarnEnabled() { + return Log.getLevel().ordinal() >= LogLevel.WARN.ordinal(); + } + + public static boolean isErrorEnabled() { + return Log.getLevel().ordinal() >= LogLevel.ERROR.ordinal(); + } + + public static void trace(String format, Object arg) { + Pair 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 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 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 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 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 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 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 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 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 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); + } } diff --git a/common/src/main/java/common/net/util/internal/SystemPropertyUtil.java b/common/src/main/java/common/net/util/internal/SystemPropertyUtil.java index 1788bdbe..c1d0a9d6 100644 --- a/common/src/main/java/common/net/util/internal/SystemPropertyUtil.java +++ b/common/src/main/java/common/net/util/internal/SystemPropertyUtil.java @@ -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() { diff --git a/common/src/main/java/common/net/util/internal/ThreadLocalRandom.java b/common/src/main/java/common/net/util/internal/ThreadLocalRandom.java index 0ad7360b..17a5764b 100644 --- a/common/src/main/java/common/net/util/internal/ThreadLocalRandom.java +++ b/common/src/main/java/common/net/util/internal/ThreadLocalRandom.java @@ -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))); } diff --git a/common/src/main/java/common/net/util/internal/logging/AbstractInternalLogger.java b/common/src/main/java/common/net/util/internal/logging/AbstractInternalLogger.java deleted file mode 100644 index 2ebbf8a6..00000000 --- a/common/src/main/java/common/net/util/internal/logging/AbstractInternalLogger.java +++ /dev/null @@ -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() + ')'; - } -} diff --git a/common/src/main/java/common/net/util/internal/logging/FormattingTuple.java b/common/src/main/java/common/net/util/internal/logging/FormattingTuple.java deleted file mode 100644 index c87a8e74..00000000 --- a/common/src/main/java/common/net/util/internal/logging/FormattingTuple.java +++ /dev/null @@ -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; - } -} diff --git a/common/src/main/java/common/net/util/internal/logging/InternalLogLevel.java b/common/src/main/java/common/net/util/internal/logging/InternalLogLevel.java deleted file mode 100644 index 108c2f50..00000000 --- a/common/src/main/java/common/net/util/internal/logging/InternalLogLevel.java +++ /dev/null @@ -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 -} diff --git a/common/src/main/java/common/net/util/internal/logging/InternalLogger.java b/common/src/main/java/common/net/util/internal/logging/InternalLogger.java deleted file mode 100644 index 1c2b953a..00000000 --- a/common/src/main/java/common/net/util/internal/logging/InternalLogger.java +++ /dev/null @@ -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; - -/** - * Internal-use-only logger used by Netty. DO NOT - * 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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the TRACE level.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the TRACE level.

- * - * @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. - *

- *

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.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the DEBUG level.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the DEBUG level.

- * - * @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. - *

- *

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.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the INFO level.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the INFO level.

- * - * @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. - *

- *

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.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the WARN level.

- * - * @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. - *

- *

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.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the WARN level.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the ERROR level.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the ERROR level.

- * - * @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. - *

- *

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.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the specified {@code level}.

- * - * @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. - *

- *

This form avoids superfluous object creation when the logger - * is disabled for the specified {@code level}.

- * - * @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. - *

- *

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.

- * - * @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); -} diff --git a/common/src/main/java/common/net/util/internal/logging/InternalLoggerFactory.java b/common/src/main/java/common/net/util/internal/logging/InternalLoggerFactory.java deleted file mode 100644 index e6d10fff..00000000 --- a/common/src/main/java/common/net/util/internal/logging/InternalLoggerFactory.java +++ /dev/null @@ -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: - *
- * {@link InternalLoggerFactory}.setDefaultFactory(new {@link Log4JLoggerFactory}());
- * 
- * 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); -} diff --git a/common/src/main/java/common/net/util/internal/logging/JdkLogger.java b/common/src/main/java/common/net/util/internal/logging/JdkLogger.java deleted file mode 100644 index a0e69f61..00000000 --- a/common/src/main/java/common/net/util/internal/logging/JdkLogger.java +++ /dev/null @@ -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; - -/** - * java.util.logging - * 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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for level FINEST. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the FINEST level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the FINEST level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for level FINE. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the FINE level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the FINE level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the INFO level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the INFO level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the INFO level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the WARNING level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the WARNING level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the WARNING level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the SEVERE level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the SEVERE level. - *

- * - * @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. - * - *

- * This form avoids superfluous object creation when the logger is disabled - * for the SEVERE level. - *

- * - * @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()); - } - } -} diff --git a/common/src/main/java/common/net/util/internal/logging/JdkLoggerFactory.java b/common/src/main/java/common/net/util/internal/logging/JdkLoggerFactory.java deleted file mode 100644 index a1e88dd2..00000000 --- a/common/src/main/java/common/net/util/internal/logging/JdkLoggerFactory.java +++ /dev/null @@ -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 - * java.util.logging - * logger. - */ -public class JdkLoggerFactory extends InternalLoggerFactory { - - @Override - public InternalLogger newInstance(String name) { - return new JdkLogger(Logger.getLogger(name)); - } -} diff --git a/common/src/main/java/common/network/IThreadListener.java b/common/src/main/java/common/network/IThreadListener.java index 646777aa..0062d71f 100755 --- a/common/src/main/java/common/network/IThreadListener.java +++ b/common/src/main/java/common/network/IThreadListener.java @@ -1,9 +1,7 @@ package common.network; -import common.future.ListenableFuture; - public interface IThreadListener { - ListenableFuture schedule(Runnable run); + void schedule(Runnable run); boolean isMainThread(); default void log(String prefixed, String line) { } diff --git a/common/src/main/java/common/util/LazyLoader.java b/common/src/main/java/common/util/LazyLoader.java deleted file mode 100755 index 2e6801ef..00000000 --- a/common/src/main/java/common/util/LazyLoader.java +++ /dev/null @@ -1,20 +0,0 @@ -package common.util; - -public abstract class LazyLoader -{ - 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(); -} diff --git a/common/src/main/java/common/util/Util.java b/common/src/main/java/common/util/Util.java index 47f70cab..64800bfa 100644 --- a/common/src/main/java/common/util/Util.java +++ b/common/src/main/java/common/util/Util.java @@ -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; + } + }; + } } diff --git a/server/src/main/java/server/Server.java b/server/src/main/java/server/Server.java index b2b02707..2e76e4be 100755 --- a/server/src/main/java/server/Server.java +++ b/server/src/main/java/server/Server.java @@ -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 SERVER_NIO_EVENTLOOP = new LazyLoader() { - 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 variables = Maps.newTreeMap(); private final List clients = Collections.synchronizedList(Lists.newArrayList()); private final List players = Lists.newArrayList(); private final Map online = Maps.newHashMap(); private final Map users = Maps.newTreeMap(); - private final Queue> queue = new ArrayDeque>(); + private final Queue queue = new ArrayDeque(); private final long[] tickTimes = new long[100]; private final Map dimensions = Maps.newTreeMap(); private final List worlds = Lists.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); } } } @@ -649,32 +630,25 @@ public final class Server implements IThreadListener, Executor { public User getUser(String user) { return this.users.get(user); } - - private ListenableFuture callFromMainThread(Callable callable) { + + public void schedule(Runnable task) { if(!this.isMainThread() && !this.stopped) { - ListenableFutureTask task = ListenableFutureTask.create(callable); synchronized(this.queue) { this.queue.add(task); - return task; } } else { try { - return Futures.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 schedule(Runnable run) { - return this.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!"); diff --git a/server/src/main/java/server/network/Player.java b/server/src/main/java/server/network/Player.java index 246d945f..1f27f343 100755 --- a/server/src/main/java/server/network/Player.java +++ b/server/src/main/java/server/network/Player.java @@ -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;