1 // Copyright (C) 2011 Philip Aston
2 // All rights reserved.
3 //
4 // This file is part of The Grinder software distribution. Refer to
5 // the file LICENSE which is part of The Grinder distribution for
6 // licensing details. The Grinder distribution is available on the
7 // Internet at http://grinder.sourceforge.net/
8 //
9 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
10 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
11 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
12 // FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
13 // COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
14 // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
15 // (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
16 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
17 // HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
18 // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
19 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
20 // OF THE POSSIBILITY OF SUCH DAMAGE.
21
22 package net.grinder.scriptengine;
23
24 import java.util.List;
25
26 import net.grinder.engine.common.EngineException;
27 import net.grinder.engine.common.ScriptLocation;
28
29 /**
30 * Service interface that script engines should implement.
31 *
32 * <p>
33 * The Grinder discovers script engine implementations from the {@code
34 * META-INF/net.grinder.scriptengines} resource files. Each engine should
35 * register its class name as a line in such a resource file. The order of the
36 * search engines is important, since it determines priority. The engines are
37 * ordered first by the class path search order used to load the resource files,
38 * and then the order of lines in the resource files. Earlier engines have
39 * higher priority.
40 * </p>
41 *
42 * <p>
43 * Each script engine is injected with framework services using PicoContainer.
44 * The use of PicoContainer should be transparent; implementations simply need
45 * to declare the services they require as constructor parameters.
46 * </p>
47 *
48 * <p>
49 * Available services include:
50 * </p>
51 *
52 * <ul>
53 * <li><code>net.grinder.common.Logger</code></li>
54 * <li><code>net.grinder.common.GrinderProperties</code></li>
55 * <li><code>net.grinder.script.ScriptContext</code></li>
56 * <li><code>net.grinder.scriptengine.DCRContext</code></li>
57 * </ul>
58 *
59 * <p>
60 * A {@code DCRContext} will be provided only if DCR is available. Engines that
61 * use DCR should have two constructors, one of them requiring a {@code
62 * DCRContext}, and one of them not. The latter constructor will be used if DCR
63 * is unavailable.
64 * </p>
65 *
66 * @author Philip Aston
67 */
68 public interface ScriptEngineService {
69
70 /**
71 * All resources with this name are loaded to discover implementations.
72 */
73 String RESOURCE_NAME = "META-INF/net.grinder.scriptengine";
74
75 /**
76 * If the script engine service can handle the given script, it should return
77 * a suitable implementation.
78 *
79 * <p>
80 * Implementations typically will execute the script and perform any
81 * process level initialisation.
82 * </p>
83 *
84 * @param script
85 * The script.
86 * @return The script engine, or {@code null}.
87 * @throws EngineException
88 * If an implementation could not be created.
89 */
90 ScriptEngine createScriptEngine(ScriptLocation script) throws EngineException;
91
92 /**
93 * Initialises script engine instrumentation.
94 *
95 * <p>
96 * Each script engine can provide instrumenters, irrespective of the engine
97 * used to execute the script. The instrumenters provided by each engine are
98 * consulted according to service registration order in the META-INF file.
99 * </p>
100 *
101 * @return Additional instrumenters to use. Engines that do not provide
102 * instrumentation should return an empty list.
103 * @throws EngineException
104 * If a problem occurred creating instrumenters.
105 */
106 List<? extends Instrumenter> createInstrumenters() throws EngineException;
107
108 /**
109 * Handler for a particular type of script.
110 */
111 interface ScriptEngine {
112
113 /**
114 * Create a {@link WorkerRunnable} that will be used to run the work
115 * for one worker thread. The {@link WorkerRunnable} will forward to
116 * a new instance of the script's {@code TestRunner} class.
117 *
118 * @return The runnable.
119 * @throws EngineException If the runnable could not be created.
120 */
121 WorkerRunnable createWorkerRunnable() throws EngineException;
122
123 /**
124 * Create a {@link WorkerRunnable} that will be used to run the work
125 * for one worker thread. The {@link WorkerRunnable} will forward to
126 * a the supplied {@code TestRunner}.
127 *
128 * @param testRunner An existing script instance that is callable.
129 * @return The runnable.
130 * @throws EngineException If the runnable could not be created.
131 */
132 WorkerRunnable createWorkerRunnable(Object testRunner)
133 throws EngineException;
134
135 /**
136 * Shut down the engine.
137 *
138 * @throws EngineException If the engine could not be shut down.
139 */
140 void shutdown() throws EngineException;
141
142 /**
143 * Returns a description of the script engine for the log.
144 *
145 * @return The description.
146 */
147 String getDescription();
148 }
149
150 /**
151 * Interface to the runnable script object for a particular worker thread.
152 */
153 interface WorkerRunnable {
154 void run() throws ScriptExecutionException;
155
156 void shutdown() throws ScriptExecutionException;
157 }
158 }