Java tutorial
/* * Copyright (c) 2011-2013 The original author or authors * ------------------------------------------------------ * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * and Apache License v2.0 which accompanies this distribution. * * The Eclipse Public License is available at * http://www.eclipse.org/legal/epl-v10.html * * The Apache License v2.0 is available at * http://www.opensource.org/licenses/apache2.0.php * * You may elect to redistribute this code under either of these licenses. */ package io.jsync.impl; import io.jsync.AsyncResult; import io.jsync.AsyncResultHandler; import io.jsync.Context; import io.jsync.Handler; import io.jsync.file.impl.PathResolver; import io.jsync.logging.Logger; import io.jsync.logging.impl.LoggerFactory; import io.netty.channel.EventLoop; import io.netty.channel.EventLoopGroup; import java.util.HashSet; import java.util.Set; import java.util.concurrent.Executor; /** * @author <a href="http://tfox.org">Tim Fox</a> */ public abstract class DefaultContext implements Context { private static final Logger log = LoggerFactory.getLogger(DefaultContext.class); protected final AsyncInternal async; protected final Executor orderedBgExec; private final ClassLoader tccl; private final EventLoop eventLoop; private DeploymentHandle deploymentContext; private PathResolver pathResolver; private Set<Closeable> closeHooks; private boolean closed; protected DefaultContext(AsyncInternal async, Executor orderedBgExec) { this.async = async; this.orderedBgExec = orderedBgExec; EventLoopGroup group = async.getEventLoopGroup(); if (group != null) { this.eventLoop = group.next(); this.tccl = Thread.currentThread().getContextClassLoader(); } else { this.eventLoop = null; this.tccl = null; } } public void setTCCL() { Thread.currentThread().setContextClassLoader(tccl); } public DeploymentHandle getDeploymentHandle() { return deploymentContext; } public void setDeploymentHandle(DeploymentHandle deploymentHandle) { this.deploymentContext = deploymentHandle; } public PathResolver getPathResolver() { return pathResolver; } public void setPathResolver(PathResolver pathResolver) { this.pathResolver = pathResolver; } public void reportException(Throwable t) { if (deploymentContext != null) { deploymentContext.reportException(t); } else { log.error("Unhandled exception", t); } } public void addCloseHook(Closeable hook) { if (closeHooks == null) { closeHooks = new HashSet<>(); } closeHooks.add(hook); } public void removeCloseHook(Closeable hook) { if (closeHooks != null) { closeHooks.remove(hook); } } public void runCloseHooks(Handler<AsyncResult<Void>> doneHandler) { if (closeHooks != null) { final CountingCompletionHandler<Void> aggHandler = new CountingCompletionHandler<>(async, closeHooks.size()); aggHandler.setHandler(doneHandler); // Copy to avoid ConcurrentModificationException for (Closeable hook : new HashSet<>(closeHooks)) { try { hook.close(new AsyncResultHandler<Void>() { @Override public void handle(AsyncResult<Void> asyncResult) { if (asyncResult.failed()) { aggHandler.failed(asyncResult.cause()); } else { aggHandler.complete(); } } }); } catch (Throwable t) { reportException(t); } } } else { doneHandler.handle(new DefaultFutureResult<>((Void) null)); } } public abstract void execute(Runnable handler); public abstract boolean isOnCorrectWorker(EventLoop worker); public void execute(EventLoop worker, Runnable handler) { if (isOnCorrectWorker(worker)) { wrapTask(handler).run(); } else { execute(handler); } } public void runOnContext(final Handler<Void> task) { execute(new Runnable() { public void run() { task.handle(null); } }); } public EventLoop getEventLoop() { return eventLoop; } // This executes the task in the worker pool using the ordered executor of the context // It's used e.g. from BlockingActions protected void executeOnOrderedWorkerExec(final Runnable task) { orderedBgExec.execute(wrapTask(task)); } public void close() { unsetContext(); closed = true; } private void unsetContext() { async.setContext(null); } protected Runnable wrapTask(final Runnable task) { return new Runnable() { public void run() { Thread currentThread = Thread.currentThread(); String threadName = currentThread.getName(); try { async.setContext(DefaultContext.this); task.run(); } catch (Throwable t) { reportException(t); } finally { if (!threadName.equals(currentThread.getName())) { currentThread.setName(threadName); } } if (closed) { // We allow tasks to be run after the context is closed but we make sure we unset the context afterwards // to avoid any leaks unsetContext(); } } }; } }