PageRenderTime 87ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/src/egats/EGATSProcess.java

https://github.com/augie/egats
Java | 479 lines | 267 code | 50 blank | 162 comment | 30 complexity | a17b48ff31f9cf76e52d1d857abf9847 MD5 | raw file
  1. package egats;
  2. import com.mongodb.BasicDBList;
  3. import com.mongodb.DBObject;
  4. import com.mongodb.util.JSON;
  5. import java.io.File;
  6. import java.lang.reflect.Method;
  7. /**
  8. * The verbs.
  9. * Acts upon objects to produce new objects.
  10. * @author Augie Hill - augie@umich.edu
  11. */
  12. public class EGATSProcess extends DataObject implements Runnable {
  13. public static final DataObjectCache<EGATSProcess> CACHE = new DataObjectCache<EGATSProcess>(Data.PROCESSES, EGATSProcess.class);
  14. public static final String STATUS_CREATED = "Created";
  15. public static final String STATUS_SUBMITTED = "Submitted";
  16. public static final String STATUS_RUNNING = "Running";
  17. public static final String STATUS_COMPLETED = "Completed";
  18. public static final String STATUS_FAILED = "Failed";
  19. // Transient variables are not serialized
  20. private transient Server server;
  21. private String status;
  22. private String exceptionMessage;
  23. private Long createTime;
  24. private Long startTime;
  25. private Long finishTime;
  26. private String name;
  27. private String methodPath;
  28. private String[] args = new String[0];
  29. private String outputID;
  30. /**
  31. *
  32. */
  33. @Override
  34. public final void run() {
  35. try {
  36. // Set up
  37. setStatus(STATUS_RUNNING);
  38. setStartTime(System.currentTimeMillis());
  39. save();
  40. // Checks
  41. if (methodPath == null) {
  42. throw new Exception("Method path is not set.");
  43. }
  44. if (args == null) {
  45. throw new Exception("Argument list is not set.");
  46. }
  47. // Is this a python script or a java method?
  48. if (server.getToolkit().containsPyScript(methodPath)) {
  49. // Check the args
  50. String[] mArgs = args;
  51. if (mArgs == null) {
  52. mArgs = new String[0];
  53. }
  54. // Replace requests for egats object file references
  55. String[] pyArgs = new String[mArgs.length];
  56. for (int i = 0; i < pyArgs.length; i++) {
  57. if (mArgs[i].startsWith("egats-obj-file:")) {
  58. EGATSObject o = EGATSObject.CACHE.get(mArgs[i].replaceFirst("egats-obj-file:", ""));
  59. EGATSObjectFile of = Data.GSON.fromJson(o.getObject(), EGATSObjectFile.class);
  60. File file = server.getWorkFileManager().getFile(o, of);
  61. pyArgs[i] = file.getAbsolutePath();
  62. } else {
  63. pyArgs[i] = mArgs[i];
  64. }
  65. }
  66. // Execute
  67. StringBuilder command = new StringBuilder();
  68. // To run python on Windows (which is what I'm running when I test)
  69. // command.append("C:/Windows/System32/cmd.exe /c C:/Python32/python.exe ");
  70. command.append("python ");
  71. command.append(server.getToolkit().getToolkitDirectoryPath());
  72. command.append(File.separator);
  73. command.append(methodPath);
  74. for (String arg : pyArgs) {
  75. command.append(" ");
  76. command.append(arg);
  77. }
  78. // Create an output buffer
  79. StringBuffer buffer = new StringBuffer();
  80. // Execute the command
  81. Process p = Runtime.getRuntime().exec(command.toString());
  82. // Stream the output amd error in to a buffer
  83. StreamToBufferThread outThread = new StreamToBufferThread(p.getInputStream(), buffer);
  84. StreamToBufferThread errThread = new StreamToBufferThread(p.getErrorStream(), buffer);
  85. outThread.start();
  86. errThread.start();
  87. // Wait on the script to complete execution (waitFor doesn't always work)
  88. boolean exited = false;
  89. while (!exited) {
  90. try {
  91. p.exitValue();
  92. exited = true;
  93. } catch (IllegalThreadStateException e) {
  94. Thread.sleep(1000);
  95. }
  96. }
  97. // Make sure the output and error has been written to the file
  98. outThread.join();
  99. errThread.join();
  100. // Create an EGATSObject from the output
  101. EGATSObject o = new EGATSObject();
  102. o.setClassPath(String.class.getName());
  103. o.setObject(buffer.toString());
  104. // Save it
  105. o.save();
  106. // Add it to the cache
  107. EGATSObject.CACHE.insert(o.getID(), o);
  108. // Save the ID of the output object
  109. setOutputID(o.getID().intern());
  110. } else {
  111. // Convert all '/' to '.'
  112. String cMethodPath = methodPath.replaceAll("/", ".").trim();
  113. String methodClassPath = cMethodPath;
  114. if (cMethodPath.lastIndexOf(".") >= 0) {
  115. methodClassPath = cMethodPath.substring(0, cMethodPath.lastIndexOf("."));
  116. }
  117. Class methodClass = server.getToolkit().getClass(methodClassPath);
  118. if (methodClass == null) {
  119. throw new Exception("Method class not found in toolkit: " + methodClassPath);
  120. }
  121. String methodName = cMethodPath.substring(cMethodPath.lastIndexOf(".") + 1);
  122. // Check the args
  123. String[] mArgs = args;
  124. if (mArgs == null) {
  125. mArgs = new String[0];
  126. }
  127. // Get the objects from the cache
  128. EGATSObject[] argEObjs = new EGATSObject[mArgs.length];
  129. for (int i = 0; i < mArgs.length; i++) {
  130. argEObjs[i] = EGATSObject.CACHE.get(mArgs[i]);
  131. if (argEObjs[i] == null) {
  132. throw new Exception("Could not find object with id \"" + mArgs[i] + "\".");
  133. }
  134. }
  135. // Generate objects
  136. Class[] argCObjs = new Class[argEObjs.length];
  137. Object[] argObjs = new Object[argEObjs.length];
  138. for (int i = 0; i < argEObjs.length; i++) {
  139. String classPath = argEObjs[i].getClassPath().replaceAll("/", ".").trim();
  140. argCObjs[i] = server.getToolkit().getClass(classPath);
  141. argObjs[i] = argCObjs[i].cast(Data.GSON.fromJson(argEObjs[i].getObject(), argCObjs[i]));
  142. }
  143. // Instantiate the method to be run
  144. Method method = methodClass.getMethod(methodName, argCObjs);
  145. if (method == null) {
  146. throw new Exception("Unknown method name and argument class combination.");
  147. }
  148. // Execute the static method (need to create a dummy instance even though it's a static method)
  149. Object output = method.invoke(methodClass.newInstance(), argObjs);
  150. // Create an EGATSObject from the output
  151. EGATSObject o = new EGATSObject();
  152. o.setClassPath(method.getReturnType().getName());
  153. o.setObject(Data.GSON.toJson(output));
  154. // Save it
  155. o.save();
  156. // Add it to the cache
  157. EGATSObject.CACHE.insert(o.getID(), o);
  158. // Save the ID of the output object
  159. setOutputID(o.getID().intern());
  160. }
  161. // All done
  162. setStatus(STATUS_COMPLETED);
  163. } catch (Exception e) {
  164. if (e instanceof NullPointerException) {
  165. setExceptionMessage("Null pointer encountered.");
  166. } else if (e instanceof NoSuchMethodException) {
  167. setExceptionMessage("No such method.");
  168. } else {
  169. setExceptionMessage(e.getMessage());
  170. }
  171. setStatus(STATUS_FAILED);
  172. } finally {
  173. setFinishTime(System.currentTimeMillis());
  174. }
  175. try {
  176. save();
  177. } catch (Exception e) {
  178. // Log
  179. // TODO
  180. }
  181. }
  182. /**
  183. *
  184. * @return
  185. */
  186. public final Server getServer() {
  187. return server;
  188. }
  189. /**
  190. *
  191. * @param server
  192. */
  193. public final void setServer(Server server) {
  194. this.server = server;
  195. }
  196. /**
  197. *
  198. * @return
  199. */
  200. public final String[] getArgs() {
  201. return args;
  202. }
  203. /**
  204. *
  205. * @param args
  206. */
  207. public final void setArgs(String[] args) {
  208. this.args = args;
  209. put("args", args);
  210. }
  211. /**
  212. *
  213. */
  214. public final Long getCreateTime() {
  215. return createTime;
  216. }
  217. /**
  218. *
  219. * @param time
  220. */
  221. private void setCreateTime(Long time) {
  222. this.createTime = time;
  223. put("createTime", time);
  224. }
  225. /**
  226. *
  227. * @return
  228. */
  229. public final String getExceptionMessage() {
  230. return exceptionMessage;
  231. }
  232. /**
  233. *
  234. * @param message
  235. */
  236. private void setExceptionMessage(String message) {
  237. this.exceptionMessage = message;
  238. put("exceptionMessage", message);
  239. }
  240. /**
  241. *
  242. * @return
  243. */
  244. public final Long getFinishTime() {
  245. return finishTime;
  246. }
  247. /**
  248. *
  249. * @param time
  250. */
  251. private void setFinishTime(Long time) {
  252. this.finishTime = time;
  253. put("finishTime", time);
  254. }
  255. /**
  256. *
  257. * @return
  258. */
  259. public final String getMethodPath() {
  260. return methodPath;
  261. }
  262. /**
  263. *
  264. * @param methodPath
  265. */
  266. public final void setMethodPath(String methodPath) {
  267. this.methodPath = methodPath;
  268. put("methodPath", methodPath);
  269. }
  270. /**
  271. *
  272. * @return
  273. */
  274. public final String getName() {
  275. return name;
  276. }
  277. /**
  278. *
  279. * @param name
  280. */
  281. public final void setName(String name) {
  282. this.name = name;
  283. put("name", name);
  284. }
  285. /**
  286. *
  287. * @return
  288. */
  289. public final String getOutputID() {
  290. return outputID;
  291. }
  292. /**
  293. *
  294. * @param outputID
  295. */
  296. private void setOutputID(String outputID) {
  297. this.outputID = outputID;
  298. put("outputID", outputID);
  299. }
  300. /**
  301. *
  302. * @return
  303. */
  304. public final Long getStartTime() {
  305. return startTime;
  306. }
  307. /**
  308. *
  309. * @param time
  310. */
  311. private void setStartTime(Long time) {
  312. this.startTime = time;
  313. put("startTime", time);
  314. }
  315. /**
  316. *
  317. * @return
  318. */
  319. public final String getStatus() {
  320. return status;
  321. }
  322. /**
  323. *
  324. * @param status
  325. */
  326. private void setStatus(String status) {
  327. this.status = status;
  328. put("status", status);
  329. }
  330. /**
  331. *
  332. * @throws Exception
  333. */
  334. protected final void save() throws Exception {
  335. Data.save(Data.PROCESSES, this);
  336. }
  337. /**
  338. *
  339. * @return
  340. */
  341. public final String getJSON() {
  342. return JSON.serialize(this);
  343. }
  344. /**
  345. *
  346. * @return
  347. */
  348. @Override
  349. public int hashCode() {
  350. return toString().hashCode();
  351. }
  352. /**
  353. *
  354. * @param o
  355. * @return
  356. */
  357. @Override
  358. public boolean equals(Object o) {
  359. if (!(o instanceof EGATSProcess)) {
  360. return false;
  361. }
  362. return toString().equals(((EGATSProcess) o).toString());
  363. }
  364. /**
  365. *
  366. * @return
  367. */
  368. @Override
  369. public String toString() {
  370. return getJSON();
  371. }
  372. /**
  373. * Cleans the process JSON and adds it to the database.
  374. * @param json
  375. * @return
  376. * @throws Exception
  377. */
  378. public static EGATSProcess create(String json) throws Exception {
  379. // Read the DBObject (attributes must be set separately)
  380. EGATSProcess o = CACHE.convert((DBObject) JSON.parse(json));
  381. // Set the attributes the user can set
  382. o.setName(o.getString("name"));
  383. o.setMethodPath(o.getString("methodPath"));
  384. o.setArgs(((BasicDBList) o.get("args")).toArray(new String[0]));
  385. // Set everything the client can't set
  386. o.removeField(DataObject.ATTR_ID);
  387. o.setCreateTime(System.currentTimeMillis());
  388. o.removeField("outputID");
  389. o.setStatus(STATUS_CREATED);
  390. o.removeField("exceptionMessage");
  391. o.removeField("startTime");
  392. o.removeField("finishTime");
  393. // Create a new entry in the database
  394. o.save();
  395. // Add it to the cache now because it will probably be referenced soon
  396. CACHE.insert(o.getID(), o);
  397. return o;
  398. }
  399. /**
  400. * Reads a process already in the database.
  401. * @param json
  402. * @return
  403. * @throws Exception
  404. */
  405. public static EGATSProcess read(String json) throws Exception {
  406. return read((DBObject) JSON.parse(json));
  407. }
  408. /**
  409. * Reads a process already in the database.
  410. * @param dbo
  411. * @return
  412. * @throws Exception
  413. */
  414. public static EGATSProcess read(DBObject dbo) throws Exception {
  415. EGATSProcess o = CACHE.convert(dbo);
  416. o.setName(o.getString("name"));
  417. o.setMethodPath(o.getString("methodPath"));
  418. o.setArgs(((BasicDBList) o.get("args")).toArray(new String[0]));
  419. o.setCreateTime(o.getLong("createTime"));
  420. o.setOutputID(o.getString("outputID"));
  421. o.setStatus(o.getString("status"));
  422. o.setExceptionMessage(o.getString("exceptionMessage"));
  423. o.setStartTime(o.getLong("startTime"));
  424. if (o.containsField("finishTime")) {
  425. o.setFinishTime(o.getLong("finishTime"));
  426. }
  427. return o;
  428. }
  429. }