001: package dalma.ant;
002:
003: import dalma.Engine;
004: import dalma.EngineFactory;
005: import dalma.Program;
006: import dalma.impl.Util;
007: import dalma.container.ClassLoaderImpl;
008: import dalma.container.model.IllegalResourceException;
009: import dalma.container.model.InjectionException;
010: import dalma.container.model.Model;
011: import dalma.helpers.ThreadPoolExecutor;
012: import org.apache.tools.ant.BuildException;
013: import org.apache.tools.ant.Task;
014: import org.apache.tools.ant.types.Environment;
015: import org.apache.tools.ant.types.Path;
016:
017: import java.io.File;
018: import java.io.IOException;
019: import java.io.BufferedReader;
020: import java.io.InputStreamReader;
021: import java.text.ParseException;
022:
023: /**
024: * Runs a workflow application in a stand-alone mode.
025: *
026: * @author Kohsuke Kawaguchi
027: */
028: public class Runner extends Task {
029: private File workDir;
030:
031: private final Path classpath = new Path(null);
032:
033: private final PropList props = new PropList();
034: private boolean parentFirst = true;
035:
036: private String mainClassName = null;
037:
038: /**
039: * Sets the work directory.
040: */
041: public void setWorkDir(File workDir) {
042: this .workDir = workDir;
043: }
044:
045: // for nested <classpath> element
046: public Path createClasspath() {
047: return classpath.createPath();
048: }
049:
050: // for classpath attribute
051: public void setClasspath(Path cp) {
052: classpath.createPath().append(cp);
053: }
054:
055: /**
056: * Configures the resource injection.
057: */
058: public void addProperty(Environment.Variable p) {
059: props.addVariable(p);
060: }
061:
062: public void setPropertyFile(File propFile) {
063: try {
064: props.addPropertyFile(propFile);
065: } catch (IOException e) {
066: throw new BuildException("Failed to load " + propFile, e);
067: }
068: }
069:
070: public void setParentFirst(boolean b) {
071: this .parentFirst = b;
072: }
073:
074: public File getWorkDir() {
075: if (workDir == null) {
076: try {
077: workDir = File.createTempFile("dalma", "ws");
078: workDir.delete();
079: workDir.mkdir();
080: } catch (IOException e) {
081: // very unlikely
082: throw new Error(
083: "Unable to allocate a temporary directory");
084: }
085: Runtime.getRuntime().addShutdownHook(new Thread() {
086: public void run() {
087: try {
088: Util.deleteRecursive(workDir);
089: } catch (IOException e) {
090: e.printStackTrace(System.err);
091: }
092: }
093: });
094: }
095: return workDir;
096: }
097:
098: /**
099: * Sets the main {@link Program} class to run.
100: *
101: * @param mainClass
102: * Can be null, in which case the main class will be determined by
103: * the manifest.
104: */
105: public void setMainClass(String mainClass) {
106: this .mainClassName = mainClass;
107: }
108:
109: public void execute() {
110: ClassLoader cl = Thread.currentThread().getContextClassLoader();
111: try {
112: doExecute();
113: } finally {
114: Thread.currentThread().setContextClassLoader(cl);
115: }
116: }
117:
118: private void doExecute() {
119: // Container con = Container.create(getWorkDir());
120: if (!getWorkDir().exists())
121: throw new BuildException(
122: "work space directory doesn't exist: "
123: + getWorkDir());
124:
125: ClassLoaderImpl loader = new ClassLoaderImpl(getClass()
126: .getClassLoader());
127: loader.makeContinuable();
128: loader.setParentFirst(parentFirst);
129: Engine engine;
130:
131: try {
132: classpath.setProject(getProject());
133: for (String pathElement : classpath.list()) {
134: loader.addPathFile(getProject()
135: .resolveFile(pathElement));
136: }
137: Thread.currentThread().setContextClassLoader(loader);
138:
139: engine = EngineFactory.newEngine(getWorkDir(), loader,
140: new ThreadPoolExecutor(1, true));
141: } catch (IOException e) {
142: throw new BuildException("Unable to initialize engine: "
143: + e.getMessage(), e);
144: }
145:
146: // test that class loader is set up correctly
147: try {
148: if (loader.loadClass("java.lang.String") != String.class)
149: throw new BuildException(
150: "ClassLoader set up error. Can't load java.lang.String correctly");
151: if (loader.loadClass(Engine.class.getName()) != Engine.class)
152: throw new BuildException(
153: "ClassLoader set up error. Can't load the Engine class correctly");
154: } catch (ClassNotFoundException e) {
155: throw new BuildException(e);
156: }
157:
158: Class<?> mainClass;
159: Program program;
160:
161: try {
162: if (this .mainClassName != null)
163: mainClass = loader.loadClass(mainClassName);
164: else
165: mainClass = loader.loadMainClass();
166: Object _program = mainClass.newInstance();
167: if (!(_program instanceof Program)) {
168: throw new BuildException(mainClass.getName()
169: + " doesn't inherit Program");
170: }
171:
172: program = (Program) _program;
173: } catch (ClassNotFoundException e) {
174: throw new BuildException("Failed to load the main class: "
175: + e.getMessage(), e);
176: } catch (IOException e) {
177: throw new BuildException("Failed to load the main class: "
178: + e.getMessage(), e);
179: } catch (IllegalAccessException e) {
180: throw new BuildException("Failed to load the main class: "
181: + e.getMessage(), e);
182: } catch (InstantiationException e) {
183: throw new BuildException("Failed to load the main class: "
184: + e.getMessage(), e);
185: }
186:
187: try {
188: Model<Object> model = new Model<Object>(mainClass);
189: model.inject(engine, program, props.toProperties());
190: } catch (InjectionException e) {
191: throw new BuildException("Failed to configure program: "
192: + e.getMessage(), e);
193: } catch (IllegalResourceException e) {
194: throw new BuildException("Failed to configure program: "
195: + e.getMessage(), e);
196: } catch (ParseException e) {
197: throw new BuildException("Failed to configure program: "
198: + e.getMessage(), e);
199: }
200:
201: try {
202: program.init(engine);
203: } catch (Throwable e) {
204: throw new BuildException(mainClass.getName()
205: + ".init() method reported an exception", e);
206: }
207:
208: engine.start();
209:
210: try {
211: program.main(engine);
212: } catch (Throwable e) {
213: throw new BuildException(mainClass.getName()
214: + ".main() method reported an exception", e);
215: }
216:
217: System.out.println("Press ENTER to quit");
218: try {
219: new BufferedReader(new InputStreamReader(System.in))
220: .readLine();
221: } catch (IOException e) {
222: throw new Error(e); // impossible
223: }
224:
225: try {
226: program.cleanup(engine);
227: } catch (Throwable e) {
228: throw new BuildException(mainClass.getName()
229: + ".cleanup() method reported an exception", e);
230: }
231:
232: engine.stop();
233: loader.cleanup();
234: }
235: }
|