/*
 * Copyright (C) 2009 the original author(s).
 *
 * 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 org.sonatype.gshell.console;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Encapsulates a console execute task.
 *
 * @author <a href="mailto:jason@planet57.com">Jason Dillon</a>
 * @since 2.0
 */
public abstract class ConsoleTask
{
    protected static final Logger log = LoggerFactory.getLogger(ConsoleTask.class);

    private Thread thread;

    private boolean running;

    private boolean stopping;

    public synchronized boolean isRunning() {
        return running;
    }

    public synchronized void stop() {
        if (running) {
            log.trace("Stopping");
            thread.interrupt();
            stopping = true;
        }
    }

    public synchronized boolean isStopping() {
        return stopping;
    }

    @SuppressWarnings({"deprecation"})
    public synchronized void abort() {
        if (running) {
            log.trace("Aborting");
            thread.stop(new AbortTaskError());
        }
    }

    public boolean execute(final String input) throws Exception {
        synchronized (this) {
            log.trace("Running");
            thread = Thread.currentThread();
            running = true;
        }

        try {
            return doExecute(input);
        }
        finally {
            synchronized (this) {
                stopping = false;
                running = false;
                thread = null;
                log.trace("Stopped");
            }
        }
    }

    public abstract boolean doExecute(String input) throws Exception;

    public static class AbortTaskError
        extends Error
    {
        ///CLOVER:OFF

        private static final long serialVersionUID = 1;
    }
}
@@ -695,16 +695,50 @@
 Factory;
+%0Aimport org.sonatype.gshell.Shell;
 %0A%0A/**%0A *
@@ -981,16 +981,134 @@
 lass);%0A%0A
+    private static final InheritableThreadLocal%3CConsoleTask%3E holder = new InheritableThreadLocal%3CConsoleTask%3E();%0A    %0A
     priv
@@ -1784,16 +1784,44 @@
 ption %7B%0A
+        ConsoleTask ptask;%0A%0A
         
@@ -1872,24 +1872,88 @@
 %22Running%22);%0A
+            ptask = holder.get();%0A            holder.set(this);%0A
             
@@ -2235,16 +2235,51 @@
 = null;%0A
+                holder.set(ptask);%0A
         
@@ -2410,16 +2410,476 @@
 ption;%0A%0A
+    public void setThread(final Thread thread) %7B%0A        this.thread = thread;%0A    %7D%0A%0A    public static ConsoleTask get(final boolean allowNull) %7B%0A        ConsoleTask task = holder.get();%0A%0A        if (!allowNull && task == null) %7B%0A            throw new IllegalStateException(%22ConsoleTask not initialized for thread: %22 + Thread.currentThread());%0A        %7D%0A%0A        return task;%0A    %7D%0A%0A    public static ConsoleTask get() %7B%0A        return get(false);%0A    %7D%0A    %0A
     publ

Support thread access to the current ConsoleTask and allow the task's execute thread to be mutated.