PageRenderTime 54ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 0ms

/PLANTILLA CLÁSICA 3/EDICION/scripts/as2lib/org/as2lib/app/exec/AbstractProcess.as

http://flash-web.googlecode.com/
ActionScript | 418 lines | 172 code | 35 blank | 211 comment | 15 complexity | 08b5c6c033306fa0adf0f14cb4ef27eb MD5 | raw file
  1. /*
  2. * Copyright the original author or authors.
  3. *
  4. * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.mozilla.org/MPL/MPL-1.1.html
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. import org.as2lib.env.except.AbstractOperationException;
  17. import org.as2lib.env.except.IllegalArgumentException;
  18. import org.as2lib.app.exec.Process;
  19. import org.as2lib.app.exec.Executable;
  20. import org.as2lib.app.exec.ProcessErrorListener;
  21. import org.as2lib.app.exec.ProcessFinishListener;
  22. import org.as2lib.app.exec.ProcessStartListener;
  23. import org.as2lib.app.exec.ProcessPauseListener;
  24. import org.as2lib.app.exec.ProcessResumeListener;
  25. import org.as2lib.app.exec.ProcessUpdateListener;
  26. import org.as2lib.app.exec.AbstractTimeConsumer;
  27. import org.as2lib.data.holder.Map;
  28. import org.as2lib.data.holder.map.HashMap;
  29. import org.as2lib.util.MethodUtil;
  30. import org.as2lib.env.event.distributor.CompositeEventDistributorControl;
  31. /**
  32. * {@code AbstractProcess} is a abstract helper class to implement processes.
  33. *
  34. * <p>Most of the functionalities of {@link Process} are served well within
  35. * {@code AbstractProcess}. Because of the situation that most processes are
  36. * simple executions {@code AbstractProcess} allows easy implementations of
  37. * {@link Process}.
  38. *
  39. * <p>To use the advantage of {@code AbstractProcess} simple extend it and
  40. * implement the {@link #run} method.
  41. *
  42. * <p>It executes {@link #run} at {@link #start} and handles the exeuction of
  43. * events and the correct states. If you wan't to stop your process
  44. * {@link #pause} and {@link #resume} offer direct support.
  45. *
  46. * <p>Example for a process that can not be finished by return:
  47. * <code>
  48. * class MyProcess extends AbstractProcess {
  49. *
  50. * public function run() {
  51. * // Xml that has to work
  52. * var xml:Xml = new Xml();
  53. *
  54. * // helper for the call back.
  55. * var inst = this;
  56. *
  57. * // Mtasc compatible return from loading
  58. * xml.onLoad = function() {
  59. * inst["finish"]();
  60. * }
  61. *
  62. * // Flag to not finish automatically
  63. * working = true;
  64. *
  65. * // Start of loading the xml file.
  66. * xml.load("test.xml");
  67. * }
  68. * }
  69. * </code>
  70. *
  71. * @author Martin Heidegger
  72. * @version 1.0
  73. * @see Process
  74. * @see ProcessStartListener
  75. * @see ProcessFinishListener
  76. * @see ProcessErrorListener
  77. * @see ProcessPauseListener
  78. * @see ProcessResumeListener
  79. * @see ProcessUpdateListener
  80. */
  81. class org.as2lib.app.exec.AbstractProcess extends AbstractTimeConsumer
  82. implements Process,
  83. ProcessErrorListener,
  84. ProcessFinishListener {
  85. /** Flag if execution was paused. */
  86. private var paused:Boolean;
  87. /** Flag if execution is just not working (case if a event is not finished within .start). */
  88. private var working:Boolean;
  89. /** List of all errors that occur during execution. */
  90. private var errors:Array;
  91. /** All subprocesses (Key) and its mapped callBacks (Value). */
  92. private var subProcesses:Map;
  93. /** Contains the possible parent. */
  94. private var parent:Process;
  95. /** Shorter name for the concrete distributorControl. */
  96. private var dC:CompositeEventDistributorControl;
  97. /**
  98. * Constructs a new {@code AbstractProcess}.
  99. */
  100. private function AbstractProcess(Void) {
  101. dC = distributorControl;
  102. acceptListenerType(ProcessStartListener);
  103. acceptListenerType(ProcessErrorListener);
  104. acceptListenerType(ProcessUpdateListener);
  105. acceptListenerType(ProcessPauseListener);
  106. acceptListenerType(ProcessResumeListener);
  107. acceptListenerType(ProcessFinishListener);
  108. errors = new Array();
  109. subProcesses = new HashMap();
  110. paused = false;
  111. working = false;
  112. }
  113. /**
  114. * Setter for a parent process.
  115. *
  116. * <p>Validates if the passed-in {@code Process} is this instance or has
  117. * this instance in its parent hierarchy (to prevent recursions).
  118. *
  119. * @param p {@code Process} to act as parent
  120. * @throws IllegalArgumentException if the applied process has the current
  121. * instance in its parent hierarchy or it is the current instance
  122. */
  123. public function setParentProcess(p:Process):Void {
  124. do {
  125. if(p == this) {
  126. throw new IllegalArgumentException("You can not start a process with itself as super process.", this, arguments);
  127. }
  128. } while (p = p.getParentProcess());
  129. parent = p;
  130. }
  131. /**
  132. * Returns the {@code Process} that acts as parent for this process.
  133. *
  134. * @return parent {@code Process} if set, else {@code null}
  135. */
  136. public function getParentProcess(Void):Process {
  137. return parent;
  138. }
  139. /**
  140. * Starts a sub-process.
  141. *
  142. * <p>This method allows to start a {@code Process}. It registers itself as
  143. * parent of the passed-in {@code process} and starts the {@code process}
  144. * if necessary.
  145. *
  146. * <p>If you add a sub-process it will be started immediately. This is important
  147. * if you start more than one sub-process, because they won't get executed in
  148. * a row like its handled within a {@link org.as2lib.app.exec.Batch}.
  149. *
  150. * <p>This process will not be finished until all subprocesses have finished.
  151. *
  152. * <p>On finish of the {@code process} to start it will execute the passed-in
  153. * {@code callBack}.
  154. *
  155. * @param process process to be used as sub-process
  156. * @param args arguments for the process start
  157. * @param callBack call back to be executed if the process finishes
  158. */
  159. public function startSubProcess(process:Process, args:Array, callBack:Executable):Void {
  160. // Don't do anything if the the process is already registered as sub-process.
  161. if (!subProcesses.containsKey(process)) {
  162. process.addListener(this);
  163. process.setParentProcess(this);
  164. subProcesses.put(process, callBack);
  165. if (!isPaused()) {
  166. pause();
  167. }
  168. // Start if not started.
  169. // Re-start if finished.
  170. // Do nothing if started but not finished.
  171. if(!process.hasStarted() || process.hasFinished()) {
  172. process["start"].apply(process, args);
  173. }
  174. }
  175. }
  176. /**
  177. * Pauses the process.
  178. */
  179. public function pause(Void):Void {
  180. paused = true;
  181. sendPauseEvent();
  182. }
  183. /**
  184. * Resumes the process.
  185. */
  186. public function resume(Void):Void {
  187. paused = false;
  188. sendResumeEvent();
  189. }
  190. /**
  191. * Prepares the start of the process.
  192. */
  193. private function prepare(Void):Void {
  194. started = false;
  195. paused = false;
  196. finished = false;
  197. working = false;
  198. totalTime.setValue(0);
  199. restTime.setValue(0);
  200. sendStartEvent();
  201. started = true;
  202. }
  203. /**
  204. * Starts the process.
  205. *
  206. * <p>Any applied parameter will be passed to the {@link #run} implementation.
  207. *
  208. * @return (optional) result of {@code run()}
  209. */
  210. public function start() {
  211. prepare();
  212. var result;
  213. try {
  214. delete endTime;
  215. startTime = getTimer();
  216. result = MethodUtil.invoke("run", this, arguments);
  217. } catch(e) {
  218. sendErrorEvent(e);
  219. }
  220. if(!isPaused() && !isWorking()) {
  221. finish();
  222. }
  223. return result;
  224. }
  225. /**
  226. * Flag if the current implementation is working.
  227. *
  228. * <p>Important for {@link #start} this method indicates that the just starting
  229. * process is not finished by return.
  230. *
  231. * @return {@code true} if the implementation is working
  232. */
  233. private function isWorking(Void):Boolean {
  234. return working;
  235. }
  236. /**
  237. * Template method for running the process.
  238. *
  239. * @throws AbstractOperationException if the method was not extended
  240. */
  241. private function run(Void):Void {
  242. throw new AbstractOperationException(".run is abstract and has to be implemented.", this, arguments);
  243. }
  244. /**
  245. * Returns {@code true} if the process is paused.
  246. *
  247. * @return {@code true} if the process is paused
  248. */
  249. public function isPaused(Void):Boolean {
  250. return paused;
  251. }
  252. /**
  253. * Returns {@code true} if the process is running.
  254. *
  255. * @return {@code true} if the process is running
  256. */
  257. public function isRunning(Void):Boolean {
  258. return(!isPaused() && hasStarted());
  259. }
  260. /**
  261. * Method to be executed if a process finishes its execution.
  262. *
  263. * @param process {@link Process} that finished with execution
  264. */
  265. public function onProcessFinish(process:Process):Void {
  266. if (subProcesses.containsKey(process)) {
  267. // removes current as listener
  268. process.removeListener(this);
  269. // Remove the process and executes the registered callback.
  270. subProcesses.remove(process).execute();
  271. // Resume exeuction
  272. resume();
  273. }
  274. }
  275. /**
  276. * Method to be executed if a exception was thrown during the execution.
  277. *
  278. * @param process {@link Process} where a error occured
  279. * @param error error that occured
  280. * @return {@code true} if error was consumed
  281. */
  282. public function onProcessError(process:Process, error):Boolean {
  283. return sendErrorEvent(error);
  284. }
  285. /**
  286. * Internal Method to finish the execution.
  287. */
  288. private function finish(Void):Void {
  289. if (subProcesses.isEmpty() && isRunning()) {
  290. finished = true;
  291. started = false;
  292. working = false;
  293. endTime = getTimer();
  294. sendFinishEvent();
  295. }
  296. }
  297. /**
  298. * Returns {@code true} if a error occured.
  299. *
  300. * @return {@code true} if a error occured
  301. */
  302. public function hasError(Void):Boolean {
  303. return (getErrors().length != 0);
  304. }
  305. /**
  306. * Returns the list with all occured errors.
  307. *
  308. * @return list that contains all occured errors
  309. */
  310. public function getErrors(Void):Array {
  311. return errors;
  312. }
  313. /**
  314. * Stores the {@code error} in the list of occured errors and finishes the process.
  315. *
  316. * <p>It will set the error to -1 if you interrupt without a error.
  317. *
  318. * @param error error that occured to interrupt
  319. */
  320. private function interrupt(error):Void {
  321. publishError(error);
  322. finish();
  323. }
  324. /**
  325. * Publishes the error event and stores the error in the error list.
  326. *
  327. * @param error error to be published
  328. * @return {@code true} if event was consumed
  329. */
  330. private function publishError(error):Boolean {
  331. if (!error) error = -1;
  332. this.errors.push(error);
  333. return sendErrorEvent(error);
  334. }
  335. /**
  336. * Internal method to send update events for {@link ProcessUpdateListener}.
  337. */
  338. private function sendUpdateEvent(Void):Void {
  339. var updateDistributor:ProcessUpdateListener
  340. = dC.getDistributor(ProcessUpdateListener);
  341. updateDistributor.onProcessUpdate(this);
  342. }
  343. /**
  344. * Internal method to send pause events for {@link ProcessPauseListener}.
  345. */
  346. private function sendPauseEvent(Void):Void {
  347. var pauseDistributor:ProcessPauseListener
  348. = dC.getDistributor(ProcessPauseListener);
  349. pauseDistributor.onProcessPause(this);
  350. }
  351. /**
  352. * Internal method to send resume events for {@link ProcessResumeListener}.
  353. */
  354. private function sendResumeEvent(Void):Void {
  355. var resumeDistributor:ProcessResumeListener
  356. = dC.getDistributor(ProcessResumeListener);
  357. resumeDistributor.onProcessResume(this);
  358. }
  359. /**
  360. * Internal method to send start events for {@link ProcessStartListener}.
  361. */
  362. private function sendStartEvent(Void):Void {
  363. var startDistributor:ProcessStartListener
  364. = dC.getDistributor(ProcessStartListener);
  365. startDistributor.onProcessStart(this);
  366. }
  367. /**
  368. * Internal method to send error events for {@link ProcessErrorListener}.
  369. */
  370. private function sendErrorEvent(error):Boolean {
  371. var errorDistributor:ProcessErrorListener
  372. = dC.getDistributor(ProcessErrorListener);
  373. return errorDistributor.onProcessError(this, error);
  374. }
  375. /**
  376. * Internal method to send finish events for {@link ProcessFinishListener}.
  377. */
  378. private function sendFinishEvent(Void):Void {
  379. var finishDistributor:ProcessFinishListener
  380. = dC.getDistributor(ProcessFinishListener);
  381. finishDistributor.onProcessFinish(this);
  382. }
  383. }