1 // 2 // ======================================================================== 3 // Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd. 4 // ------------------------------------------------------------------------ 5 // All rights reserved. This program and the accompanying materials 6 // are made available under the terms of the Eclipse Public License v1.0 7 // and Apache License v2.0 which accompanies this distribution. 8 // 9 // The Eclipse Public License is available at 10 // http://www.eclipse.org/legal/epl-v10.html 11 // 12 // The Apache License v2.0 is available at 13 // http://www.opensource.org/licenses/apache2.0.php 14 // 15 // You may elect to redistribute this code under either of these licenses. 16 // ======================================================================== 17 // 18 19 package org.eclipse.jetty.util.thread; 20 21 import java.lang.reflect.Constructor; 22 import java.util.concurrent.Executor; 23 import java.util.concurrent.RejectedExecutionException; 24 25 import org.eclipse.jetty.util.Loader; 26 import org.eclipse.jetty.util.log.Log; 27 import org.eclipse.jetty.util.log.Logger; 28 import org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume; 29 30 /** 31 * <p>An {@link ExecutionStrategy} executes {@link Runnable} tasks produced by a {@link Producer}. 32 * The strategy to execute the task may vary depending on the implementation; the task may be 33 * run in the calling thread, or in a new thread, etc.</p> 34 * <p>The strategy delegates the production of tasks to a {@link Producer}, and continues to 35 * execute tasks until the producer continues to produce them.</p> 36 */ 37 public interface ExecutionStrategy 38 { 39 /** 40 * <p>Initiates (or resumes) the task production and execution.</p> 41 * <p>This method guarantees that the task is never run by the 42 * thread that called this method.</p> 43 * 44 * @see #execute() 45 */ 46 public void dispatch(); 47 48 /** 49 * <p>Initiates (or resumes) the task production and execution.</p> 50 * <p>The produced task may be run by the same thread that called 51 * this method.</p> 52 * 53 * @see #dispatch() 54 */ 55 public void execute(); 56 57 /** 58 * A task that can handle {@link RejectedExecutionException} 59 */ 60 public interface Rejectable 61 { 62 public void reject(); 63 } 64 65 /** 66 * <p>A producer of {@link Runnable} tasks to run.</p> 67 * <p>The {@link ExecutionStrategy} will repeatedly invoke {@link #produce()} until 68 * the producer returns null, indicating that it has nothing more to produce.</p> 69 * <p>When no more tasks can be produced, implementations should arrange for the 70 * {@link ExecutionStrategy} to be invoked again in case an external event resumes 71 * the tasks production.</p> 72 */ 73 public interface Producer 74 { 75 /** 76 * <p>Produces a task to be executed.</p> 77 * 78 * @return a task to executed or null if there are no more tasks to execute 79 */ 80 Runnable produce(); 81 } 82 83 84 /** 85 * <p>A factory for {@link ExecutionStrategy}.</p> 86 */ 87 public static interface Factory 88 { 89 /** 90 * <p>Creates a new {@link ExecutionStrategy}.</p> 91 * 92 * @param producer the execution strategy producer 93 * @param executor the execution strategy executor 94 * @return a new {@link ExecutionStrategy} 95 */ 96 public ExecutionStrategy newExecutionStrategy(Producer producer, Executor executor); 97 98 /** 99 * @return the default {@link ExecutionStrategy} 100 */ 101 public static Factory getDefault() 102 { 103 return DefaultExecutionStrategyFactory.INSTANCE; 104 } 105 106 /** 107 * @param producer the execution strategy producer 108 * @param executor the execution strategy executor 109 * @deprecated use {@code getDefault().newExecutionStrategy(Producer, Executor)} instead 110 */ 111 @Deprecated 112 public static ExecutionStrategy instanceFor(Producer producer, Executor executor) 113 { 114 return getDefault().newExecutionStrategy(producer, executor); 115 } 116 } 117 118 public static class DefaultExecutionStrategyFactory implements Factory 119 { 120 private static final Logger LOG = Log.getLogger(Factory.class); 121 private static final Factory INSTANCE = new DefaultExecutionStrategyFactory(); 122 123 @Override 124 public ExecutionStrategy newExecutionStrategy(Producer producer, Executor executor) 125 { 126 String strategy = System.getProperty(producer.getClass().getName() + ".ExecutionStrategy"); 127 if (strategy != null) 128 { 129 try 130 { 131 Class<? extends ExecutionStrategy> c = Loader.loadClass(producer.getClass(), strategy); 132 Constructor<? extends ExecutionStrategy> m = c.getConstructor(Producer.class, Executor.class); 133 LOG.info("Use {} for {}", c.getSimpleName(), producer.getClass().getName()); 134 return m.newInstance(producer, executor); 135 } 136 catch (Exception e) 137 { 138 LOG.warn(e); 139 } 140 } 141 142 return new ExecuteProduceConsume(producer, executor); 143 } 144 } 145 }