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 }