io.jsync.impl.DefaultContext.java Source code

Java tutorial

Introduction

Here is the source code for io.jsync.impl.DefaultContext.java

Source

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

}