View Javadoc

1   /*
2    *                Doelan development code
3    *
4    * This code may be freely distributed and modified under the
5    * terms of the GNU General Public Licence.  This should
6    * be distributed with the code. If you do not have a copy,
7    * see:
8    *
9    *      http://www.gnu.org/copyleft/gpl.txt
10   *
11   * Copyright (c) 2004-2005 ENS Microarray Platform
12   * Copyright for this code is held jointly by the individual
13   * authors.  These should be listed in @author doc comments.
14   *
15   * For more information on the Doelan project and its aims,
16   * or to join the Doelan mailing list, visit the home page
17   * at:
18   *
19   *      http://www.transcriptome.ens.fr/doelan
20   */
21  
22  package fr.ens.transcriptome.doelan;
23  
24  import java.applet.Applet;
25  import java.io.File;
26  import java.io.FileNotFoundException;
27  import java.io.FileOutputStream;
28  import java.io.IOException;
29  import java.io.OutputStream;
30  import java.net.MalformedURLException;
31  import java.net.URL;
32  
33  import javax.swing.JLabel;
34  
35  import org.apache.log4j.Logger;
36  
37  import fr.ens.transcriptome.doelan.algorithms.DoelanConfigure;
38  import fr.ens.transcriptome.doelan.algorithms.DoelanExecuteGlobalTests;
39  import fr.ens.transcriptome.doelan.algorithms.DoelanGenerateReport;
40  import fr.ens.transcriptome.doelan.algorithms.DoelanLoadGenepixData;
41  import fr.ens.transcriptome.doelan.algorithms.DoelanShowReport;
42  import fr.ens.transcriptome.doelan.data.QualityTestSuiteURL;
43  import fr.ens.transcriptome.doelan.gui.MainTabWidget;
44  import fr.ens.transcriptome.doelan.gui.ReportTabWidget;
45  import fr.ens.transcriptome.doelan.gui.StatusWidget;
46  import fr.ens.transcriptome.doelan.gui.TestSuitePanel;
47  import fr.ens.transcriptome.nividic.platform.Platform;
48  import fr.ens.transcriptome.nividic.platform.PlatformException;
49  import fr.ens.transcriptome.nividic.platform.PlatformRegistery;
50  import fr.ens.transcriptome.nividic.platform.workflow.SimpleWorkflowBuilder;
51  import fr.ens.transcriptome.nividic.platform.workflow.Workflow;
52  import fr.ens.transcriptome.nividic.platform.workflow.WorkflowElement;
53  import fr.ens.transcriptome.nividic.platform.workflow.WorkflowEvent;
54  import fr.ens.transcriptome.nividic.platform.workflow.WorkflowGraph;
55  import fr.ens.transcriptome.nividic.platform.workflow.WorkflowListener;
56  import fr.ens.transcriptome.nividic.platform.workflow.io.WorkflowIO;
57  import fr.ens.transcriptome.nividic.platform.workflow.io.WorkflowXMLIO;
58  import fr.ens.transcriptome.nividic.util.parameter.ParameterException;
59  
60  /***
61   * Manage the Workflows
62   * @author Laurent Jourdren
63   */
64  public final class Core implements WorkflowListener {
65  
66    // For log system
67    private static Logger log = Logger.getLogger(Core.class);
68  
69    /*** Singleton. */
70    private static Core core;
71  
72    /*** Identifier of the load algorithm. */
73    public static final String LOAD_ALGORITHM = "DoelanLoadData";
74    /*** Identifier of the algorithm for executing global test. */
75    public static final String EXECUTE_GLOBAL_TESTS_ALGORITHM = "DoelanExecuteGlobalTests";
76    /*** Identifier of the generate report algorithm. */
77    public static final String GENERATE_REPORT_ALGORITHM = "DoelanGenerateReport";
78    /*** Identifier of the show report algorithm. */
79    public static final String SHOW_REPORT_ALGORITHM = "DoelanShowReport";
80    /*** Identifier of the show report algorithm. */
81    public static final String CONFIGURE_ALGORITHM = "DoelanConfigure";
82  
83    private static final int NUMBER_OF_DOELAN_ALGORITHM = 4;
84  
85    private String testSuiteName;
86    private int countAlgorithm;
87    private Workflow workflow;
88    private MainTabWidget mainTab;
89    private TestSuitePanel table;
90    private ReportTabWidget report;
91    private StatusWidget status;
92    private Applet applet;
93    private JLabel statusBar;
94    private URL testSuiteListURL;
95  
96    //
97    // Getters
98    //
99  
100   /***
101    * Get the table.
102    * @return Returns the table
103    */
104   public TestSuitePanel getTable() {
105     return table;
106   }
107 
108   /***
109    * Get the workflow
110    * @return Returns the workflow
111    */
112   private Workflow getWorkflow() {
113     return workflow;
114   }
115 
116   /***
117    * Test if a suite is load in memory.
118    * @return true if a suite is load in memory
119    */
120   public boolean isSuite() {
121     return this.workflow != null;
122   }
123 
124   /***
125    * Get the report widget
126    * @return Returns the editor
127    */
128   public ReportTabWidget getReport() {
129     return report;
130   }
131 
132   /***
133    * Set the report widget.
134    * @param report The repory to set
135    */
136   public void setReport(final ReportTabWidget report) {
137     if (report != null)
138       this.report = report;
139   }
140 
141   /***
142    * Test if the applet is enable.
143    * @return Returns the appletMode
144    */
145   public boolean isAppletMode() {
146     return this.applet != null;
147   }
148 
149   /***
150    * Get the applet.
151    * @return Returns the applet
152    */
153   public Applet getApplet() {
154     return applet;
155   }
156 
157   /***
158    * Get the status widget.
159    * @return Returns the status
160    */
161   public StatusWidget getStatus() {
162     return status;
163   }
164 
165   /***
166    * Get the test suite name.
167    * @return Returns the testSuiteName
168    */
169   private String getTestSuiteName() {
170     return testSuiteName;
171   }
172 
173   /***
174    * Get the status bar object.
175    * @return Returns the statusBar
176    */
177   public JLabel getStatusBar() {
178     return statusBar;
179   }
180 
181   /***
182    * Get the URL of the test suite list.
183    * @return Returns the testSuiteListURL
184    */
185   public URL getTestSuiteListURL() {
186     return testSuiteListURL;
187   }
188 
189   /***
190    * Get the main tab widget.
191    * @return Returns the mainTab
192    */
193   public MainTabWidget getMainTab() {
194     return mainTab;
195   }
196 
197   //
198   // Setters
199   //
200 
201   /***
202    * Set the table.
203    * @param table The table to set
204    */
205   public void setTable(final TestSuitePanel table) {
206     this.table = table;
207   }
208 
209   /***
210    * Set the workflow
211    * @param workflow The workflow to set
212    */
213   private void setWorkflow(final Workflow workflow) {
214     this.workflow = workflow;
215   }
216 
217   /***
218    * Set the applet.
219    * @param applet The applet to set
220    */
221   public void setApplet(final Applet applet) {
222     this.applet = applet;
223   }
224 
225   /***
226    * Set the status widget.
227    * @param status The status to set
228    */
229   public void setStatus(final StatusWidget status) {
230     this.status = status;
231   }
232 
233   /***
234    * Set the test suite name.
235    * @param testSuiteName The testSuiteName to set
236    */
237   private void setTestSuiteName(final String testSuiteName) {
238     this.testSuiteName = testSuiteName;
239   }
240 
241   /***
242    * Set the status bar object.
243    * @param statusBar The statusBar to set
244    */
245   public void setStatusBar(final JLabel statusBar) {
246     this.statusBar = statusBar;
247   }
248 
249   /***
250    * Set the URL of the test suite list.
251    * @param testSuiteListURL The testSuiteListURL to set
252    */
253   public void setTestSuiteListURL(final URL testSuiteListURL) {
254     this.testSuiteListURL = testSuiteListURL;
255   }
256 
257   /***
258    * Set the main tab widget
259    * @param mainTab The mainTab to set
260    */
261   public void setMainTab(final MainTabWidget mainTab) {
262     this.mainTab = mainTab;
263   }
264 
265   //
266   // WorkflowException Listener
267   //
268 
269   //
270   // Other methods
271   //
272 
273   /***
274    * Load an new workflow
275    * @param url url of the testsuite to load
276    * @throws DoelanException if error occurs while the initialization of the
277    *           test suite.
278    */
279   public void loadNewWorkflow(final QualityTestSuiteURL url)
280       throws DoelanException {
281 
282     if (url == null)
283       throw new DoelanException("Url is null");
284 
285     log.info("Load workflow : " + url.getURL());
286 
287     if (url.getURL() == null) {
288       createEmptyWorkflow();
289       saveWorkflow(url);
290     } else
291       loadWorkflow(url);
292     getTable().setUrl(url);
293     activateWorflow();
294 
295   }
296 
297   /***
298    * Save a workflow.
299    * @param url of the testsuite to save
300    * @throws DoelanException if error occurs while saving workflow
301    */
302   public void saveWorkflow(final QualityTestSuiteURL url)
303       throws DoelanException {
304 
305     if (url == null)
306       return;
307 
308     if (url.getURL() == null) {
309       File f = new File(PlatformRegistery.getConfDirectory() + File.separator
310           + System.currentTimeMillis() + ".rwf");
311       try {
312         url.setURL(f.toURL());
313       } catch (MalformedURLException e) {
314         log.error("invalid URL :" + e.getMessage());
315       }
316     }
317 
318     try {
319       OutputStream os = new FileOutputStream(url.getURL().getFile());
320       WorkflowIO wfio = new WorkflowXMLIO(os);
321       wfio.write(getWorkflow());
322       log.info("save workflow url=" + url.getURL().getFile());
323     } catch (FileNotFoundException e) {
324       throw new DoelanException("Error while writing the file : "
325           + e.getMessage());
326     } catch (PlatformException e) {
327       throw new DoelanException("Error while writing the file : "
328           + e.getMessage());
329     }
330 
331   }
332 
333   /***
334    * Create and activate the demo test suite.
335    * @throws DoelanException if an error occurs while the initialization of the
336    *           test suite.
337    */
338   public void createDemoWorkflow() throws DoelanException {
339 
340     SimpleWorkflowBuilder swb = new SimpleWorkflowBuilder();
341     Workflow w = swb.addElement("DoelanLoadData", LOAD_ALGORITHM).addElement(
342         "EmptySpotTest", "algo1").addElement("SpotDiameterTest", "algo2")
343         .addElement(EXECUTE_GLOBAL_TESTS_ALGORITHM,
344             EXECUTE_GLOBAL_TESTS_ALGORITHM).addElement(
345             GENERATE_REPORT_ALGORITHM, GENERATE_REPORT_ALGORITHM).addElement(
346             SHOW_REPORT_ALGORITHM, SHOW_REPORT_ALGORITHM).getWorkflow();
347 
348     try {
349       w.getElement("algo1").getParameters().setParameter("threshold", "10");
350 
351       w.getElement("algo1").getParameters().setParameter("quorum", "10");
352 
353       w.getElement("algo2").getParameters().setParameter("min", "10");
354       w.getElement("algo2").getParameters().setParameter("max", "50");
355       w.getElement("algo2").getParameters().setParameter("quorum", "10");
356 
357     } catch (ParameterException e) {
358       throw new DoelanException("Unable to set parameters");
359     }
360 
361     setWorkflow(w);
362   }
363 
364   /***
365    * Create and activate the empty test suite.
366    * @throws DoelanException if an error occurs while the initialization of the
367    *           test suite.
368    */
369   public void createEmptyWorkflow() throws DoelanException {
370 
371     SimpleWorkflowBuilder swb = new SimpleWorkflowBuilder();
372     Workflow w = swb.addElement(LOAD_ALGORITHM, LOAD_ALGORITHM).addElement(
373         CONFIGURE_ALGORITHM, CONFIGURE_ALGORITHM).addElement(
374         EXECUTE_GLOBAL_TESTS_ALGORITHM, EXECUTE_GLOBAL_TESTS_ALGORITHM)
375         .addElement(GENERATE_REPORT_ALGORITHM, GENERATE_REPORT_ALGORITHM)
376         .addElement(SHOW_REPORT_ALGORITHM, SHOW_REPORT_ALGORITHM).getWorkflow();
377 
378     w.setType(Defaults.DOELAN_WORKFLOW_TYPE);
379     w.setGenerator(DoelanRegistery.getAppName() + " "
380         + DoelanRegistery.getAppVersion());
381 
382     // w.setName(getTestSuiteName());
383     w.getAnnotations().setProperty(
384         Defaults.DOELAN_WORKFLOW_VERSION_ANNOTATION_KEY,
385         Defaults.DOELAN_WORKFLOW_VERSION);
386 
387     /*
388      * w.getAnnotations().setProperty(Defaults.CHIP_TYPE_ANNOTATION_KEY,
389      * "Mouse");
390      * w.getAnnotations().setProperty(Defaults.TEST_SUITE_NAME_ANNOTATION_KEY,
391      * "22k");
392      */
393 
394     setWorkflow(w);
395   }
396 
397   /***
398    * Load a workflow
399    * @param url Location of the test suite
400    * @throws DoelanException if an error occurs while reading the test suite
401    */
402   private void loadWorkflow(final QualityTestSuiteURL url)
403       throws DoelanException {
404 
405     if (url == null || url.getURL() == null)
406       throw new DoelanException("Url is null");
407 
408     try {
409       WorkflowIO wfio = new WorkflowXMLIO(url.getURL().openStream());
410 
411       Workflow w = wfio.read();
412       setWorkflow(w);
413       setTestSuiteName(url.getName());
414 
415     } catch (FileNotFoundException e) {
416       throw new DoelanException("Test suite file not found");
417     } catch (IOException e) {
418       throw new DoelanException("IO error while reading the test suite");
419     } catch (PlatformException e) {
420       throw new DoelanException("IO error while reading the test suite");
421     }
422   }
423 
424   /***
425    * Test if a workflow is a valid testsuite.
426    * @param workflow Workflow to test
427    * @return true if the workflow is a valid workflow
428    */
429   private boolean isValidTestSuite(final Workflow workflow) {
430 
431     if (workflow == null)
432       return false;
433 
434     if (workflow.getType() == null
435         || !workflow.getType().equals(Defaults.DOELAN_WORKFLOW_TYPE)) {
436       log.error("Invalid test suite: Not a doelan workflow type");
437       return false;
438     }
439 
440     WorkflowElement wfeLoad = workflow.getRootElement();
441 
442     // Test if load data algorithm is the first
443     if (wfeLoad == null || wfeLoad.getAlgorithm() == null
444         || !(wfeLoad.getAlgorithm() instanceof DoelanLoadGenepixData)
445         || !wfeLoad.getId().equals(LOAD_ALGORITHM)) {
446       log
447           .error("Invalid test suite: load data algorithmn isn't the first element");
448       return false;
449     }
450 
451     WorkflowElement wfeConfigure = wfeLoad.getNextElements()[0];
452     if (!(wfeConfigure.getAlgorithm() instanceof DoelanConfigure)
453         || !wfeConfigure.getId().equals(CONFIGURE_ALGORITHM)) {
454       log
455           .error("Invalid test suite: configure algorithm isn't the sedond element");
456       return false;
457     }
458 
459     // Test if report algorithm is the last
460     WorkflowElement[] endElements = new WorkflowGraph(workflow)
461         .getEndElementsOfTheGraph();
462 
463     if (endElements == null || endElements.length != 1) {
464       log.error("Invalid test suite: no end element");
465       return false;
466     }
467 
468     WorkflowElement wfeShowReport = endElements[0];
469     if (!(wfeShowReport.getAlgorithm() instanceof DoelanShowReport)
470         || !wfeShowReport.getId().equals(SHOW_REPORT_ALGORITHM)) {
471       log.error("Invalid test suite: show report isn't the last element");
472       return false;
473     }
474 
475     WorkflowElement wfeGenerateReport = wfeShowReport.getPreviousElements()[0];
476     if (!(wfeGenerateReport.getAlgorithm() instanceof DoelanGenerateReport)
477         || !wfeGenerateReport.getId().equals(GENERATE_REPORT_ALGORITHM)) {
478       log.error("Invalid test suite: generate report isn't the n-1 element");
479       return false;
480     }
481 
482     WorkflowElement wfeExecuteGlobalTests = wfeGenerateReport
483         .getPreviousElements()[0];
484     if (!(wfeExecuteGlobalTests.getAlgorithm() instanceof DoelanExecuteGlobalTests)
485         || !wfeExecuteGlobalTests.getId()
486             .equals(EXECUTE_GLOBAL_TESTS_ALGORITHM)) {
487       log
488           .error("Invalid test suite: execute global tests isn't the n-2 element");
489       return false;
490     }
491 
492     return true;
493   }
494 
495   /***
496    * Activate the test suite.
497    * @throws DoelanException if an error occurs while activate the workflow
498    */
499   private void activateWorflow() throws DoelanException {
500 
501     final Workflow w = getWorkflow();
502 
503     if (w == null)
504       return;
505 
506     try {
507       // activate the workflow
508       w.activate();
509 
510       if (!isValidTestSuite(w))
511         throw new DoelanException("invalid test suite");
512 
513       WorkflowElement wfeLoad = workflow.getRootElement();
514       WorkflowElement wfeShowReport = new WorkflowGraph(workflow)
515           .getEndElementsOfTheGraph()[0];
516 
517       // Active the applet mode
518       if (isAppletMode()) {
519         DoelanLoadGenepixData mlgd = (DoelanLoadGenepixData) wfeLoad
520             .getAlgorithm();
521         mlgd.setApplet(getApplet());
522       }
523 
524       // Link the report tab with the workflow
525       DoelanShowReport mr = (DoelanShowReport) wfeShowReport.getAlgorithm();
526       mr.setReport(getReport());
527       mr.setStatus(getStatus());
528 
529       // Link the workflow with the table
530       getTable().getModel().setWorkflow(w);
531 
532     } catch (PlatformException e) {
533       throw new DoelanException("Error while activate the test suite: "
534           + e.getMessage());
535     }
536 
537   }
538 
539   /***
540    * Start the workflow.
541    * @param chipTypeName Name of the selected chipType
542    * @param testSuiteName Name of the selected testSuite
543    * @param gprFilename Filename of the GPR data
544    * @param galFilename Filename of the GAL data
545    * @param description Description of the file
546    * @param applet applet used to load data
547    * @param listener workflow listener
548    * @throws DoelanException if an error occurs during the workflow
549    */
550   public void startWorkflow(final String chipTypeName,
551       final String testSuiteName, final String gprFilename,
552       final String galFilename, final String description, final Applet applet,
553       final WorkflowListener listener) throws DoelanException {
554 
555     System.gc();
556 
557     // start the workflow
558     if (getWorkflow() != null) {
559 
560       if (getWorkflow().size() < NUMBER_OF_DOELAN_ALGORITHM) {
561         throw new DoelanException("Warning: Your test suite contains no test.");
562       }
563 
564       // TODO here set the parameters of the workflow
565       WorkflowElement wfe = getWorkflow().getRootElement();
566 
567       try {
568 
569         wfe.getParameters().setParameter("chipTypeName", chipTypeName);
570         wfe.getParameters().setParameter("testSuiteName", testSuiteName);
571         wfe.getParameters().setParameter("gprFilename",
572             gprFilename == null ? "" : gprFilename);
573         wfe.getParameters().setParameter("galFilename",
574             galFilename == null ? "" : galFilename);
575         wfe.getParameters().setParameter("description", description);
576         wfe.getParameters().setParameter("loadFromApplet",
577             applet == null ? "false" : "true");
578 
579       } catch (ParameterException e) {
580         throw new DoelanException("Invalid parameters ; " + e.getMessage());
581       }
582 
583       // clear testsuite tab and report tab
584       getReport().clear();
585       getTable().clearResults();
586 
587       // for progress info
588       this.countAlgorithm = 0;
589 
590       getWorkflow().addListener(listener);
591       getWorkflow().addListener(this);
592       setTestSuiteName(testSuiteName);
593       showProgressWorkflow();
594 
595       new Thread(getWorkflow()).start();
596 
597     }
598   }
599 
600   /***
601    * Stop the workflow.
602    * @throws PlatformException if the workflow is not running
603    */
604   public void stopWorkflow() throws PlatformException {
605     getWorkflow().stop();
606   }
607 
608   //
609   // Algorithm Listener
610   //
611 
612   /***
613    * Throws an execption to a listener.
614    * @param e Exception to throw.
615    */
616   public void workflowNewException(final PlatformException e) {
617   }
618 
619   /***
620    * Invoked when the target of the listener has changed its state.
621    * @param event a WorkflowEvent object
622    */
623   public void workflowStateChanged(final WorkflowEvent event) {
624 
625     if (event == null)
626       return;
627 
628     if (event.getId() == WorkflowEvent.END_ALGORITHM_EVENT)
629       showProgressWorkflow();
630 
631   }
632 
633   /***
634    * Show the progression of the workflow in the statusbar.
635    */
636   private void showProgressWorkflow() {
637 
638     if (getStatusBar() == null)
639       return;
640 
641     String msg = getTestSuiteName();
642     /*
643      * + " executed with "; if (DoelanRegistery.isAppletMode()) msg = msg +
644      * "Genepix data."; else msg = msg + getGprFilename();
645      */
646 
647     if (countAlgorithm == getWorkflow().size()) {
648       msg = msg + " - done";
649       this.countAlgorithm = 0;
650     } else {
651 
652       int percent = (int) ((double) countAlgorithm
653           / (double) getWorkflow().size() * 100);
654       msg = msg + " - " + percent + "% done";
655       this.countAlgorithm++;
656     }
657 
658     getStatusBar().setText(msg);
659   }
660 
661   /***
662    * Return the unique instance of the Core object
663    * @return The instance of the core object
664    */
665   public static Core getCore() {
666 
667     if (core == null)
668       core = new Core();
669     return core;
670   }
671 
672   //
673   // Constructor
674   //
675 
676   /***
677    * Private constructor.
678    */
679   private Core() {
680 
681     // Start the platform
682     Platform.start(Defaults.INTERNALS_MODULES, new String[] {PlatformRegistery
683         .getPluginsDirectory()}); // ,
684     // !DoelanRegistery.isAppletMode());
685   }
686 
687 }