// Path: netty-http/src/main/java/http/searchcommand/SearchRequest.java
// public class SearchRequest implements Callable<char[]> {
//     private static final Logger LOGGER = LoggerFactory.getLogger(RestCommand.class);
// 
//     RestCommand command;
//     public SearchRequest(RestCommand command) {
//         this.command = command;
//     }
// 
//     @Override
//     public char[] call() throws Exception {
//         LOGGER.info("Start request: " + command.toString());
//         return command.execute();
//     }
// }
// 
// Path: netty-http/src/main/java/http/worker/notifyexecutor/INotifyingFuture.java
// public interface INotifyingFuture<V> extends RunnableFuture<V> {
// 
//     /**
//      * Sets this listener to a {@link INotifyingFuture}. When the future is done
//      * or canceled the listener gets notified.<br>
//      * @param listener
//      * @param the executor that executes the shiet.
//      */
//     public void setListener(IFutureListener<V> listener, ExecutorService executor);
// 
//     /**
//      * Sets this listener to a {@link INotifyingFuture}. When the future is done
//      * or canceled the listener gets notified.<br>
//      * <b>Attention</b>: Be aware of the fact that everything that is done in that
//      * listener is executed in same thread as the original task that this listener listens
//      * to. Only use this method when you are sure that no long running task is performed
//      * by the listener. When you want the listener's tasks to be performed asynchronous
//      * use {@link #setListener(IFutureListener, ExecutorService)} instead.
//      * @param listener
//      */
//     public void setListener(IFutureListener<V> listener);
// }
// 
// Path: netty-http/src/main/java/http/worker/notifyexecutor/SearchingFuture.java
// public class SearchingFuture<V> extends FutureTask<V> implements INotifyingFuture<V> {
// 
//     private static final ExecutorService DEFAULT_EXECUTOR = new SearchWorker(30, "SearchWorker", new LinkedBlockingDeque(100));;
// 
//     private IFutureListener<V> listener = null;
//     private ExecutorService executor = null;
//     private final AtomicBoolean executed = new AtomicBoolean();
// 
//     public SearchingFuture(Callable<V> callable) {
//         super(callable);
//         setExecutor(DEFAULT_EXECUTOR);
//     }
// 
//     public SearchingFuture(Runnable runnable, V result) {
//         super(runnable,result);
//         setExecutor(DEFAULT_EXECUTOR);
//     }
// 
// 
//     @Override
//     protected void done() {
//         if(listener == null){
//             return;
//         }
//         notifyListenerOnce();
//     }
// 
//     /**
//      * Atomically executes the task only one time.
//      */
//     protected void notifyListenerOnce(){
//         if(!this.executed.getAndSet(true)){
//             notifyListener();
//         }
//     }
// 
//     protected void notifyListener() {
//         this.executor.submit(new TaskCompletionRunner<V>(delegateFuture(),this.listener));
//     }
// 
//     /**
//      * @return the future that was processed.
//      */
//     protected RunnableFuture<V> delegateFuture(){
//         return this;
//     }
// 
//     @Override
//     public void setListener(IFutureListener<V> listener, ExecutorService executor) {
//         setExecutor(executor);
//         setListener(listener);
//     }
// 
//     public void setExecutor(ExecutorService executor) {
//         this.executor = executor;
//     }
// 
//     @Override
//     public void setListener(IFutureListener<V> listener) {
//         this.listener = listener;
//         /*
//          * Probably the task was already executed. If so, call done() manually.
//          */
//         runWhenDone();
//     }
// 
//     protected void runWhenDone(){
//         if(isDone()){
//             notifyListenerOnce();
//         }
//     }
// 
//     private static class TaskCompletionRunner<V> implements Runnable{
// 
//         private final IFutureListener<V> listener;
//         private final RunnableFuture<V> future;
// 
//         public TaskCompletionRunner(RunnableFuture<V> future, IFutureListener<V> listener) {
//             this.future = future;
//             this.listener = listener;
//         }
// 
//         @Override
//         public void run() {
//             if (this.future.isCancelled()) {
//                 this.listener.onCancel(this.future);
//             } else {
//                 try {
//                     this.listener.onSuccess(this.future.get());
//                 } catch (InterruptedException e) {
//                     this.listener.onError(e, this.future);
//                 } catch (ExecutionException e) {
//                     this.listener.onError(e, this.future);
//                 }
//             }
//         }
//     }
// }


import http.searchcommand.SearchRequest;
import http.worker.notifyexecutor.INotifyingFuture;
import http.worker.notifyexecutor.SearchingFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

package http.worker;





/**
 * Created by i311352 on 2/20/2017.
 */
public class SearchWorker extends ThreadPoolExecutor {
    private final static Logger logger = LoggerFactory.getLogger(SearchWorker.class);
    private static SearchWorker instance;

    public SearchWorker(int size, String name, BlockingQueue blockingQueue) {
        super(size, size+5, 0L, TimeUnit.MILLISECONDS, blockingQueue, new WorkerThread(name));
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        logger.info("start to exectue: " + t);
        super.beforeExecute(t, r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        logger.info("after to exectue: " + t);
    }


// Path: netty-http/src/main/java/http/searchcommand/SearchRequest.java
// public class SearchRequest implements Callable<char[]> {
//     private static final Logger LOGGER = LoggerFactory.getLogger(RestCommand.class);
// 
//     RestCommand command;
//     public SearchRequest(RestCommand command) {
//         this.command = command;
//     }
// 
//     @Override
//     public char[] call() throws Exception {
//         LOGGER.info("Start request: " + command.toString());
//         return command.execute();
//     }
// }
// 
// Path: netty-http/src/main/java/http/worker/notifyexecutor/INotifyingFuture.java
// public interface INotifyingFuture<V> extends RunnableFuture<V> {
// 
//     /**
//      * Sets this listener to a {@link INotifyingFuture}. When the future is done
//      * or canceled the listener gets notified.<br>
//      * @param listener
//      * @param the executor that executes the shiet.
//      */
//     public void setListener(IFutureListener<V> listener, ExecutorService executor);
// 
//     /**
//      * Sets this listener to a {@link INotifyingFuture}. When the future is done
//      * or canceled the listener gets notified.<br>
//      * <b>Attention</b>: Be aware of the fact that everything that is done in that
//      * listener is executed in same thread as the original task that this listener listens
//      * to. Only use this method when you are sure that no long running task is performed
//      * by the listener. When you want the listener's tasks to be performed asynchronous
//      * use {@link #setListener(IFutureListener, ExecutorService)} instead.
//      * @param listener
//      */
//     public void setListener(IFutureListener<V> listener);
// }
// 
// Path: netty-http/src/main/java/http/worker/notifyexecutor/SearchingFuture.java
// public class SearchingFuture<V> extends FutureTask<V> implements INotifyingFuture<V> {
// 
//     private static final ExecutorService DEFAULT_EXECUTOR = new SearchWorker(30, "SearchWorker", new LinkedBlockingDeque(100));;
// 
//     private IFutureListener<V> listener = null;
//     private ExecutorService executor = null;
//     private final AtomicBoolean executed = new AtomicBoolean();
// 
//     public SearchingFuture(Callable<V> callable) {
//         super(callable);
//         setExecutor(DEFAULT_EXECUTOR);
//     }
// 
//     public SearchingFuture(Runnable runnable, V result) {
//         super(runnable,result);
//         setExecutor(DEFAULT_EXECUTOR);
//     }
// 
// 
//     @Override
//     protected void done() {
//         if(listener == null){
//             return;
//         }
//         notifyListenerOnce();
//     }
// 
//     /**
//      * Atomically executes the task only one time.
//      */
//     protected void notifyListenerOnce(){
//         if(!this.executed.getAndSet(true)){
//             notifyListener();
//         }
//     }
// 
//     protected void notifyListener() {
//         this.executor.submit(new TaskCompletionRunner<V>(delegateFuture(),this.listener));
//     }
// 
//     /**
//      * @return the future that was processed.
//      */
//     protected RunnableFuture<V> delegateFuture(){
//         return this;
//     }
// 
//     @Override
//     public void setListener(IFutureListener<V> listener, ExecutorService executor) {
//         setExecutor(executor);
//         setListener(listener);
//     }
// 
//     public void setExecutor(ExecutorService executor) {
//         this.executor = executor;
//     }
// 
//     @Override
//     public void setListener(IFutureListener<V> listener) {
//         this.listener = listener;
//         /*
//          * Probably the task was already executed. If so, call done() manually.
//          */
//         runWhenDone();
//     }
// 
//     protected void runWhenDone(){
//         if(isDone()){
//             notifyListenerOnce();
//         }
//     }
// 
//     private static class TaskCompletionRunner<V> implements Runnable{
// 
//         private final IFutureListener<V> listener;
//         private final RunnableFuture<V> future;
// 
//         public TaskCompletionRunner(RunnableFuture<V> future, IFutureListener<V> listener) {
//             this.future = future;
//             this.listener = listener;
//         }
// 
//         @Override
//         public void run() {
//             if (this.future.isCancelled()) {
//                 this.listener.onCancel(this.future);
//             } else {
//                 try {
//                     this.listener.onSuccess(this.future.get());
//                 } catch (InterruptedException e) {
//                     this.listener.onError(e, this.future);
//                 } catch (ExecutionException e) {
//                     this.listener.onError(e, this.future);
//                 }
//             }
//         }
//     }
// }


// Path: netty-http/src/main/java/http/worker/SearchWorker.java
import http.searchcommand.SearchRequest;
import http.worker.notifyexecutor.INotifyingFuture;
import http.worker.notifyexecutor.SearchingFuture;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

package http.worker;





/**
 * Created by i311352 on 2/20/2017.
 */
public class SearchWorker extends ThreadPoolExecutor {
    private final static Logger logger = LoggerFactory.getLogger(SearchWorker.class);
    private static SearchWorker instance;

    public SearchWorker(int size, String name, BlockingQueue blockingQueue) {
        super(size, size+5, 0L, TimeUnit.MILLISECONDS, blockingQueue, new WorkerThread(name));
    }

    @Override
    protected void beforeExecute(Thread t, Runnable r) {
        logger.info("start to exectue: " + t);
        super.beforeExecute(t, r);
    }

    @Override
    protected void afterExecute(Runnable r, Throwable t) {
        super.afterExecute(r, t);
        logger.info("after to exectue: " + t);
    }


    public INotifyingFuture doSearch(SearchRequest request) {
