001: package dalma;
002:
003: import dalma.helpers.Java5Executor;
004: import dalma.helpers.ParallelInstrumentingClassLoader;
005: import dalma.helpers.ThreadPoolExecutor;
006: import dalma.impl.EngineImpl;
007:
008: import java.io.File;
009: import java.io.IOException;
010: import java.util.Collection;
011: import java.util.HashMap;
012: import java.util.Map;
013: import java.util.concurrent.Executors;
014:
015: /**
016: * Factory for {@link Engine}.
017: *
018: * <p>
019: * This class is mostly useful when you are configuring {@link Engine} from IoC containers
020: * such as Spring. When you are creating an {@link Engine} programatically, consider
021: * using {@link #newEngine(File, ClassLoader, Executor)} directly.
022: *
023: * @author Kohsuke Kawaguchi
024: */
025: public class EngineFactory {
026:
027: private File rootDir;
028: private ClassLoader classLoader;
029: private Executor executor;
030: private final Map<String, EndPoint> endPoints = new HashMap<String, EndPoint>();
031:
032: /**
033: * Creates a new uninitialized {@link EngineFactory}.
034: */
035: public EngineFactory() {
036: }
037:
038: /**
039: * Sets the directory to be used for persisting the state of conversations.
040: *
041: * @param rootDir
042: * must not be null. This directory must exist.
043: */
044: public void setRootDir(File rootDir) {
045: this .rootDir = rootDir;
046: }
047:
048: // TODO
049: public void setClassLoader(ClassLoader classLoader) {
050: this .classLoader = classLoader;
051: }
052:
053: /**
054: * Sets the thread pool that executes the conversations.
055: *
056: * @param executor
057: * must not be null.
058: */
059: public void setExecutor(Executor executor) {
060: this .executor = executor;
061: }
062:
063: /**
064: * Adds a new {@link EndPoint} to the engine.
065: *
066: * @throws IllegalArgumentException
067: * if there's already an {@link EndPoint} that has the same name.
068: */
069: public void addEndPoint(EndPoint ep) {
070: endPoints.put(ep.getName(), ep);
071: }
072:
073: /**
074: * Adds multiple {@link EndPoint}s from the given list.
075: *
076: * <p>
077: * Note that this method copies the values from the collection but not the
078: * collection itself. Therefore once the method returns, changes can be
079: * made to the collection object that is used for this method invocation
080: * and it will not affect the engine.
081: */
082: public void setEndPoints(Collection<? extends EndPoint> endPoints) {
083: for (EndPoint endPoint : endPoints)
084: addEndPoint(endPoint);
085: }
086:
087: /**
088: * Creates {@link EndPoint}s from endpoint URLs and adds them
089: * to the engine when it's created.
090: *
091: * @param endPoints
092: * Keys are endpoint names, and values are endpoint URLs.
093: */
094: public void setEndPointURLs(Map<String, String> endPoints) {
095:
096: }
097:
098: /**
099: * Creates a new {@link Engine} based on the current configuration.
100: *
101: * @throws IOException
102: * if the engine failed to set up the files for persistence,
103: * or fails to read from the existing persisted conversations.
104: */
105: public Engine newInstance() throws IOException {
106: EngineImpl engine = new EngineImpl(rootDir, classLoader,
107: executor);
108: for (EndPoint endPoint : endPoints.values()) {
109: engine.addEndPoint(endPoint);
110: }
111: return engine;
112: }
113:
114: /**
115: * Creates or loads a new {@link Engine} with a single invocation.
116: *
117: * @param rootDir
118: * see {@link #setRootDir(File)}
119: * @param classLoader
120: * see {@link #setClassLoader(ClassLoader)}
121: * @param executor
122: * see {@link #setExecutor(Executor)}
123: */
124: public static Engine newEngine(File rootDir,
125: ClassLoader classLoader, Executor executor)
126: throws IOException {
127: return new EngineImpl(rootDir, classLoader, executor);
128: }
129:
130: /**
131: * Creates or loads a new {@link Engine} with a single invocation.
132: *
133: * <p>
134: * This method is a convenient version of {@link #newEngine(File, ClassLoader, Executor)}
135: * that uses the current thread's context class loader.
136: *
137: * @param rootDir
138: * see {@link #setRootDir(File)}
139: * @param executor
140: * see {@link #setExecutor(Executor)}
141: */
142: public static Engine newEngine(File rootDir, Executor executor)
143: throws IOException {
144: ClassLoader cl = Thread.currentThread().getContextClassLoader();
145: if (cl == null)
146: cl = EngineFactory.class.getClassLoader();
147: return newEngine(rootDir, cl, executor);
148: }
149:
150: /**
151: * The easiest way to create a new {@link Engine}.
152: *
153: * <p>
154: * This method creates a new {@link Engine} with the following configuration.
155: *
156: * <ol>
157: * <li>"./dalma" directory is used to store the data.
158: * <li>the conversation programs are assumed to be in the specified
159: * package name. A new {@link ClassLoader} is created to load
160: * classes in this package with necessary bytecode instrumentation.
161: * <li>If you are running in JRE 5.0 or later,
162: * {@link Executors#newCachedThreadPool()}
163: * is used to run conversions. If you are running in earlier versions
164: * of JRE, then a single worker thread is used to run conversations.
165: *
166: * @param packagePrefix
167: * String like "org.acme.foo." See {@link ParallelInstrumentingClassLoader#ParallelInstrumentingClassLoader(ClassLoader, String)}
168: * for details.
169: */
170: public static Engine newEngine(String packagePrefix)
171: throws IOException {
172: Executor exec;
173:
174: try {
175: exec = new Java5Executor(Executors.newCachedThreadPool());
176: } catch (Throwable e) {
177: // must be running in earlier JVM
178: // TODO: implement CachedThreadPool
179: exec = new ThreadPoolExecutor(1);
180: }
181:
182: ClassLoader cl = new ParallelInstrumentingClassLoader(
183: EngineFactory.class.getClassLoader(), packagePrefix);
184:
185: return newEngine(new File("dalma"), cl, exec);
186: }
187: }
|