Salome HOME
ScenarioService.getScenarioInfo method is added.
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / technical / ProjectSettingsServiceImpl.java
1 package org.splat.service.technical;
2
3 /**
4  * 
5  * @author    Daniel Brunier-Coulin
6  * @copyright OPEN CASCADE 2012
7  */
8
9 import java.io.File;
10 import java.io.FileNotFoundException;
11 import java.io.IOException;
12 import java.sql.SQLException;
13 import java.util.ArrayList;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.LinkedHashMap;
17 import java.util.List;
18 import java.util.Map;
19 import java.util.Properties;
20 import java.util.Set;
21
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
24
25 import org.apache.log4j.Logger;
26 import org.splat.dal.bo.som.Document;
27 import org.splat.dal.bo.som.DocumentType;
28 import org.splat.dal.bo.som.KnowledgeElement;
29 import org.splat.dal.bo.som.KnowledgeElementType;
30 import org.splat.dal.bo.som.ProjectElement;
31 import org.splat.dal.bo.som.Scenario;
32 import org.splat.dal.bo.som.SimulationContextType;
33 import org.splat.dal.bo.som.Study;
34 import org.splat.dal.bo.som.ValidationCycle.Actor;
35 import org.splat.dal.dao.som.Database;
36 import org.splat.manox.XDOM;
37 import org.splat.service.DocumentTypeService;
38 import org.splat.service.KnowledgeElementTypeService;
39 import org.splat.service.SimulationContextTypeService;
40 import org.w3c.dom.Element;
41 import org.w3c.dom.NamedNodeMap;
42 import org.w3c.dom.Node;
43 import org.w3c.dom.NodeList;
44
45 /**
46  * SIMAN workflow configuration data service.
47  */
48 public class ProjectSettingsServiceImpl implements ProjectSettingsService {
49
50         /**
51          * The logger for the service.
52          */
53         protected final static Logger LOG = Logger
54                         .getLogger(ProjectSettingsServiceImpl.class);
55
56         // Non persistent configuration information
57         /**
58          * Repository settings.
59          */
60         private transient final Properties _reprop = new Properties();
61         /**
62          * Pattern of study references.
63          */
64         private transient String _pattern;
65         /**
66          * Scheme of file names stored into the repository.
67          */
68         private transient FileNaming _naming;
69         /**
70          * Pattern of the presentation of version numbers.
71          */
72         private transient String _versioning;
73         /**
74          * Ordered list of (transient) study steps.
75          */
76         private transient final List<ProjectSettingsService.Step> _steps = new ArrayList<ProjectSettingsService.Step>();
77         /**
78          * Configuration document validation cycles.
79          */
80         private transient List<ProjectSettingsValidationCycle> _concycles;
81
82         // Temporary attributes initialized from the configuration file for populating the database with object types
83         /**
84          * Document type names and uses mapping.
85          */
86         private transient Map<String, String> _mapuse;
87         /**
88          * Simulation Context type names.
89          */
90         private transient List<String> _context;
91         /**
92          * Knowledge Element type names.
93          */
94         private transient List<String> _kname;
95         /**
96          * Document flows.
97          */
98         private transient List<NamedNodeMap> _flows;
99         /**
100          * Study classifications.
101          */
102         private transient List<NamedNodeMap> _sclass;
103
104         // Other resources
105         /**
106          * Database service to check its version, etc.
107          */
108         private Database _database;
109         /**
110          * Injected simulation context type service.
111          */
112         private SimulationContextTypeService _simulationContextTypeService;
113         /**
114          * Injected knowledge element type service.
115          */
116         private KnowledgeElementTypeService _knowledgeElementTypeService;
117         /**
118          * Injected document type service.
119          */
120         private DocumentTypeService _documentTypeService;
121
122         public enum FileNaming {
123                 title, encoded, asis
124         }
125
126         /**
127          * Validation cycle defined in the XML configuration.
128          */
129         public static class ProjectSettingsValidationCycle {
130                 /**
131                  * Cycle (document) type name.
132                  */
133                 private transient final String _name;
134                 /**
135                  * Array of cycle actors positions in the organization. TODO: Must be replaced by Roles.
136                  */
137                 private transient final Actor[] _actor;
138
139                 /**
140                  * Default constructor.
141                  */
142                 private ProjectSettingsValidationCycle() {
143                         this._name = "built-in";
144                         this._actor = new Actor[] { null, null, null };
145                 }
146
147                 /**
148                  * Create a validation cycle definition for the given document type name and actors positions.
149                  * 
150                  * @param name
151                  *            the document type name
152                  * @param actor
153                  *            the array of actors positions
154                  */
155                 private ProjectSettingsValidationCycle(final String name,
156                                 final Actor[] actor) {
157                         this._name = name;
158                         this._actor = actor;
159                 }
160
161                 /**
162                  * The processed document type name.
163                  * 
164                  * @return the document type name
165                  */
166                 public String getName() {
167                         return _name;
168                 }
169
170                 /**
171                  * Get an array of cycle actors positions.
172                  * 
173                  * @return the array of actors positions
174                  * @see org.splat.dal.bo.som.ValidationCycle.Actor
175                  */
176                 public Actor[] getActorTypes() {
177                         return _actor;
178                 }
179         }
180
181         // ==============================================================================================================================
182         // Public functions
183         // ==============================================================================================================================
184
185         /**
186          * Load workflow configuration from the given file. <br/> Create necessary default staff in the database if it is not initialized yet.
187          * 
188          * @param filename
189          *            the workflow configuration file
190          * @throws IOException
191          *             if there is a file reading or index creation problem
192          * @throws SQLException
193          *             if there is a database population problem
194          */
195         public void configure(final String filename) throws IOException,
196                         SQLException {
197                 if (!_steps.isEmpty()) {
198                         return; // Project already configured
199                 }
200
201                 Database base = getDatabase().getCheckedDB();
202                 File config = new File(filename);
203                 if (config.exists()) {
204                         loadCustomization(config);
205                 } else {
206                         LOG.fatal("Could not find the database configuration file \""
207                                         + config.getAbsolutePath() + "\"");
208                         throw new FileNotFoundException();
209                 }
210                 base.configure(_reprop);
211                 if (!base.isInitialized()) {
212                         base.initialize();
213                         initialize(); // Populates the database with all necessary stuff
214                 }
215         }
216
217         /**
218          * Get ordered list of (transient) study steps.
219          * 
220          * @return the list of steps from project settings
221          */
222         public List<ProjectSettingsService.Step> getAllSteps() {
223                 return _steps;
224         }
225
226         /**
227          * Return the validation cycles of result documents defined in the workflow, ordered by study activities and ending by the default
228          * validation cycle, if defined.
229          * 
230          * @return the validation cycles of the workflow
231          */
232         public List<ProjectSettingsValidationCycle> getAllValidationCycles() {
233                 return _concycles;
234         }
235
236         /**
237          * Get file naming scheme setting.
238          * 
239          * @return file naming scheme
240          * @see org.splat.service.technical.ProjectSettingsServiceImpl.FileNaming
241          */
242         public FileNaming getFileNamingScheme() {
243                 return _naming;
244         }
245
246         /**
247          * Get a pattern of study references.
248          * 
249          * @return the reference pattern
250          */
251         public String getReferencePattern() {
252                 return _pattern;
253         }
254
255         /**
256          * Get a pattern of the presentation of version numbers.
257          * 
258          * @return the version numbers presentation pattern
259          */
260         public String getRevisionPattern() {
261                 return _versioning;
262         }
263
264         /**
265          * Get a study step by its sequential number.
266          * 
267          * @param number
268          *            the step number
269          * @return the step
270          */
271         public ProjectSettingsService.Step getStep(final int number) {
272                 ProjectSettingsService.Step res = null;
273                 for (int i = 0; i < _steps.size(); i++) {
274                         ProjectSettingsService.Step step = _steps.get(i);
275                         if (step.getNumber() == number) {
276                                 res = step;
277                                 break;
278                         }
279                 }
280                 return res;
281         }
282
283         /**
284          * Get steps of the given project element (study or scenario).
285          * 
286          * @param level
287          *            the project element (study or scenario)
288          * @return the list of steps
289          */
290         public List<ProjectSettingsService.Step> getStepsOf(
291                         final Class<? extends ProjectElement> level) {
292                 List<ProjectSettingsService.Step> result = new ArrayList<ProjectSettingsService.Step>();
293
294                 for (int i = 0; i < _steps.size(); i++) {
295                         ProjectSettingsService.Step step = _steps.get(i);
296                         if (step.appliesTo(level)) {
297                                 result.add(step);
298                         }
299                 }
300                 return result;
301         }
302
303         /**
304          * Initialize the database: create all necessary default staff defined in the configuration file.
305          */
306         protected void initialize() {
307                 createDocumentTypes();
308                 createSimulationContextTypes();
309                 createKnowledgeElementTypes();
310         }
311
312         // ==============================================================================================================================
313         // Private member function
314         // ==============================================================================================================================
315
316         /**
317          * Read the configuration file and fill transient project settings fields.
318          * 
319          * @param config
320          *            the configuration XML file
321          */
322         private void loadCustomization(final File config) {
323                 try {
324                         DocumentBuilderFactory dfactory = javax.xml.parsers.DocumentBuilderFactory
325                                         .newInstance();
326                         DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
327
328                         org.w3c.dom.Document conf = dBuilder.parse(config.getPath());
329                         HashMap<String, Node> children = XDOM.getNamedChildNodes(conf
330                                         .getDocumentElement());
331
332                         // Repository tag initializing the reprop attribute
333                         Node child = children.get("database");
334                         HashMap<String, Node> datag = XDOM.getNamedChildNodes(child);
335
336                         String disk = datag.get("repository").getAttributes().getNamedItem(
337                                         "disk").getNodeValue();
338                         if (!disk.endsWith("/")) {
339                                 disk = disk + "/";
340                         }
341                         LOG.info("Database root set to " + disk);
342                         _reprop.setProperty("repository", disk);
343
344                         // Formats tag initializing the reference pattern and date attributes
345                         child = children.get("formats");
346                         datag = XDOM.getNamedChildNodes(child);
347
348                         NamedNodeMap natr = datag.get("references").getAttributes();
349                         _pattern = natr.getNamedItem("study").getNodeValue();
350
351                         natr = datag.get("files").getAttributes();
352                         _naming = FileNaming.valueOf(natr.getNamedItem("name")
353                                         .getNodeValue());
354
355                         natr = datag.get("versions").getAttributes();
356                         _versioning = natr.getNamedItem("pattern").getNodeValue();
357
358                         // Activities tag initializing the steps and rex attributes
359                         child = children.get("activities");
360                         NodeList nlist = child.getChildNodes();
361                         List<NamedNodeMap> flist = new ArrayList<NamedNodeMap>();
362                         List<String> resultype = new ArrayList<String>();
363                         List<NamedNodeMap> clist = new ArrayList<NamedNodeMap>();
364
365                         int snum = 1; // Base number of steps
366                         for (int i = 0; i < nlist.getLength(); i++) {
367                                 child = nlist.item(i);
368                                 if ("scenario".equals(child.getNodeName())) {
369                                         NodeList slist = child.getChildNodes();
370                                         for (int j = 0; j < slist.getLength(); j++) {
371                                                 snum = loadStep(slist.item(j), Scenario.class, snum,
372                                                                 flist, clist, resultype);
373                                         }
374                                 } else {
375                                         snum = loadStep(child, Study.class, snum, flist, clist,
376                                                         resultype);
377                                 }
378                         }
379                         // Validations tag
380                         _concycles = loadValidationCycles(children, resultype);
381
382                         if (!getDatabase().getCheckedDB().isInitialized()) {
383                                 // Load object type definitions
384                                 // Documents tag
385                                 child = children.get("documents");
386                                 nlist = child.getChildNodes();
387
388                                 _flows = flist; // Kept for later use in document type definition
389                                 _sclass = clist; // Kept for later use in simulation context type definition
390                                 _mapuse = new LinkedHashMap<String, String>();
391                                 for (int i = 0; i < nlist.getLength(); i++) {
392                                         child = nlist.item(i);
393                                         if ("article".equals(child.getNodeName())) {
394                                                 natr = child.getAttributes();
395                                                 String type = natr.getNamedItem("type").getNodeValue();
396                                                 String uses = null;
397                                                 child = natr.getNamedItem("uses");
398                                                 if (child != null) {
399                                                         uses = child.getNodeValue();
400                                                 }
401                                                 _mapuse.put(type, uses); // Must be added to the map even if no (null) uses
402                                         }
403                                 }
404                                 // Simulation Contexts tag
405                                 _context = loadArticles(children, "contexts");
406                                 // Knowledge Elements tag
407                                 _kname = loadArticles(children, "knowledges");
408                         }
409                 } catch (Exception error) {
410                         LOG.info("Error in customization", error);
411                 }
412         }
413
414         /**
415          * Load a step from the given XML node. Return the next step's number.
416          * 
417          * @param node
418          *            XML node to parse
419          * @param ownerClass
420          *            the class of a step's owner project element - study or scenario
421          * @param snum
422          *            step's number
423          * @param flist
424          *            list of flows
425          * @param clist
426          *            list of classifications
427          * @param resultype
428          *            list of flow results
429          * @return the next step's number
430          */
431         private int loadStep(final Node node,
432                         final Class<? extends ProjectElement> ownerClass, final int snum,
433                         final List<NamedNodeMap> flist, final List<NamedNodeMap> clist,
434                         final List<String> resultype) {
435                 int res = snum;
436                 if ("step".equals(node.getNodeName())) {
437                         
438                         String name = ((Element)node).getAttribute("name");
439                         HashMap<String, Node> tags = XDOM.getNamedChildNodes(node);
440
441                         NamedNodeMap natr = tags.get("storage").getAttributes();
442                         ProjectSettingsService.Step step = new ProjectSettingsService.Step(
443                                         snum, ownerClass, natr.getNamedItem("path").getNodeValue());
444                         step.setKey(name);
445
446                         // Keeping flow and classification information for eventual later use
447                         natr = tags.get("flow").getAttributes();
448                         flist.add(natr);
449                         Node child = natr.getNamedItem("result");
450                         if (child != null) {
451                                 resultype.add(child.getNodeValue());
452                         }
453
454                         child = tags.get("classification");
455                         if (child == null) {
456                                 clist.add(null);
457                         } else {
458                                 clist.add(child.getAttributes());
459                         }
460
461                         if (natr.getNamedItem("contents").getNodeValue()
462                                         .equals("knowledge")) {
463                                 if (Study.class.equals(ownerClass)) {
464                                         LOG
465                                                         .error("Error: knowledges must be attached to scenarios.");
466                                 } else {
467                                         // TODO In a given scenario, only one step must contain knowledges
468                                         step._contents.add(KnowledgeElement.class);
469                                 }
470                         } else {
471                                 step._contents.add(Document.class);
472                         }
473
474                         Element module = (Element) tags.get("module");
475                         if (module != null) {
476                                 step.setModule(module.getAttribute("name"));
477                         }
478
479                         _steps.add(step);
480                         res += 1;
481                 }
482                 return res;
483         }
484
485         /**
486          * Get custom validation cycles.
487          * 
488          * @param children
489          *            XML nodes
490          * @param resultype
491          *            list of result types
492          * @return return list of validation cycles
493          */
494         private List<ProjectSettingsValidationCycle> loadValidationCycles(
495                         final Map<String, Node> children, final List<String> resultype) {
496                 Node child = children.get("validations");
497                 List<ProjectSettingsValidationCycle> cycles = new ArrayList<ProjectSettingsValidationCycle>();
498                 Map<String, Node> datag = XDOM.getNamedChildNodes(child);
499                 NamedNodeMap natr;
500
501                 String[] step = { "review", "approval", "acceptance" };
502                 resultype.add("default");
503                 for (Iterator<String> i = resultype.iterator(); i.hasNext();) {
504                         Actor[] actor = { null, null, null };
505                         String name = i.next();
506                         child = datag.get(name);
507                         if (child != null) {
508                                 // Document type is the subject of a validation
509                                 natr = child.getAttributes();
510                                 for (int j = 0; j < step.length; j++) {
511                                         child = natr.getNamedItem(step[j]);
512                                         if (child != null) {
513                                                 actor[j] = Actor.valueOf(child.getNodeValue()); // Validation step is required
514                                         }
515                                 }
516                                 cycles.add(new ProjectSettingsValidationCycle(name, actor));
517                         }
518                 }
519                 cycles.add(new ProjectSettingsValidationCycle()); // Adds the built-in validation cycle
520                 return cycles;
521         }
522
523         /**
524          * Read list of articles types.
525          * 
526          * @param children
527          *            XML nodes containing articles
528          * @param listName
529          *            the name of the list of articles
530          * @return list of articles types
531          */
532         private List<String> loadArticles(final Map<String, Node> children,
533                         final String listName) {
534                 Node child = children.get(listName);
535                 NodeList nlist = child.getChildNodes();
536
537                 List<String> articles = new ArrayList<String>();
538                 for (int i = 0; i < nlist.getLength(); i++) {
539                         child = nlist.item(i);
540                         if (child.getNodeName().equals("article")) {
541                                 articles.add(child.getAttributes().getNamedItem("type")
542                                                 .getNodeValue());
543                         }
544                 }
545                 return articles;
546         }
547
548         /**
549          * Create in the database document types defined in the custom configuration.
550          */
551         private void createDocumentTypes() {
552                 DocumentType.Properties tprop = new DocumentType.Properties();
553                 Map<String, List<ProjectSettingsService.Step>> mapsteps = new HashMap<String, List<ProjectSettingsService.Step>>();
554                 Map<String, ProjectSettingsService.Step> mapresult = new HashMap<String, ProjectSettingsService.Step>();
555                 Map<String, DocumentType> maptype = new HashMap<String, DocumentType>();
556
557                 List<ProjectSettingsService.Step> slist = null; // List of Steps to which each document type is valid
558                 int snum = 0; // Step number
559                 String type = null;
560                 String uses = null;
561                 for (Iterator<NamedNodeMap> i = _flows.iterator(); i.hasNext(); snum++) {
562                         NamedNodeMap flow = i.next();
563                         ProjectSettingsService.Step step = _steps.get(snum);
564                         String[] contents = flow.getNamedItem("contents").getNodeValue()
565                                         .split(",");
566                         for (int j = 0; j < contents.length; j++) {
567                                 type = contents[j];
568                                 if (!_mapuse.containsKey(type)) {
569                                         LOG.warn("Undefined \"" + type + "\" document type.");
570                                         continue;
571                                 }
572                                 slist = mapsteps.get(type);
573                                 if (slist == null) {
574                                         slist = new ArrayList<ProjectSettingsService.Step>();
575                                 }
576                                 slist.add(step);
577                                 mapsteps.put(type, slist);
578                         }
579                         Node result = flow.getNamedItem("result");
580                         if (result != null) {
581                                 mapresult.put(result.getNodeValue(), step);
582                         }
583                 }
584                 try {
585                         DocumentType tdoc = null;
586                         Set<String> tset = _mapuse.keySet();
587                         ProjectSettingsService.Step step;
588                         for (Iterator<String> i = tset.iterator(); i.hasNext();) {
589                                 type = i.next();
590                                 slist = mapsteps.get(type);
591                                 uses = _mapuse.get(type);
592                                 step = mapresult.get(type);
593
594                                 tprop.clear();
595                                 tprop.setName(type).setStep(
596                                                 slist.toArray(new ProjectSettingsService.Step[slist
597                                                                 .size()]));
598                                 if (uses != null) {
599                                         tdoc = maptype.get(uses);
600                                         if (tdoc == null) {
601                                                 LOG.warn("Undefined \"" + uses + "\" document type.");
602                                         } else {
603                                                 tprop.setUses(tdoc);
604                                         }
605                                 }
606                                 if (step != null) {
607                                         tprop.setResult(step);
608                                 }
609
610                                 tprop.disableCheck();
611                                 tdoc = getDocumentTypeService().createType(tprop); // Creation of Document Types
612                                 getDocumentTypeService().approve(tdoc);
613                                 maptype.put(type, tdoc);
614                         }
615                 } catch (Exception error) {
616                         LOG.warn("Error creating document types, reason:", error); // Should not happen
617                 }
618         }
619
620         /**
621          * Create in the database knowledge types defined in the custom configuration.
622          */
623         private void createKnowledgeElementTypes() {
624                 try {
625                         KnowledgeElementType ktype = getKnowledgeElementTypeService()
626                                         .createType("usecase"); // Internal reserved knowledge element type
627                         getKnowledgeElementTypeService().reserve(ktype);
628                         for (Iterator<String> i = _kname.iterator(); i.hasNext();) {
629                                 String type = i.next();
630
631                                 ktype = getKnowledgeElementTypeService().createType(type); // Knowledge Elements Types defined in the configuration
632                                 getKnowledgeElementTypeService().approve(ktype);
633                         }
634                 } catch (Exception error) {
635                         LOG.warn("Error creating knowledge types, reason:", error); // Should not happen
636                 }
637         }
638
639         /**
640          * Create in the database simulation contexts types defined in the custom configuration.
641          */
642         private void createSimulationContextTypes() {
643                 Map<String, ProjectSettingsService.Step> mapstep = new HashMap<String, ProjectSettingsService.Step>();
644                 int snum = 0;
645                 for (Iterator<NamedNodeMap> i = _sclass.iterator(); i.hasNext(); snum++) {
646                         NamedNodeMap clatr = i.next();
647                         if (clatr != null) {
648                                 String[] clist = clatr.getNamedItem("context").getNodeValue()
649                                                 .split(",");
650                                 for (int j = 0; j < clist.length; j++) {
651                                         mapstep.put(clist[j], _steps.get(snum));
652                                 }
653                         }
654                 }
655                 try {
656                         SimulationContextType tctex = null;
657                         for (Iterator<String> i = _context.iterator(); i.hasNext();) {
658                                 String type = i.next();
659                                 if (mapstep.containsKey(type)) {
660                                         tctex = getSimulationContextTypeService().createType(type,
661                                                         mapstep.get(type)); // Creation of Simulation Context Types
662                                         getSimulationContextTypeService().approve(tctex);
663                                 } else {
664                                         LOG
665                                                         .warn("Could not find \""
666                                                                         + type
667                                                                         + "\" classification. Simulation Context type ignored.");
668                                 }
669                         }
670                 } catch (Exception error) {
671                         LOG.warn("Error creating context types, reason:", error); // Should not happen
672                 }
673         }
674
675         /**
676          * Get the database.
677          * 
678          * @return the database
679          */
680         public Database getDatabase() {
681                 return _database;
682         }
683
684         /**
685          * Set the database.
686          * 
687          * @param database
688          *            the database to set
689          */
690         public void setDatabase(final Database database) {
691                 _database = database;
692         }
693
694         /**
695          * Get the simulationContextTypeService.
696          * 
697          * @return the simulationContextTypeService
698          */
699         public SimulationContextTypeService getSimulationContextTypeService() {
700                 return _simulationContextTypeService;
701         }
702
703         /**
704          * Set the simulationContextTypeService.
705          * 
706          * @param simulationContextTypeService
707          *            the simulationContextTypeService to set
708          */
709         public void setSimulationContextTypeService(
710                         final SimulationContextTypeService simulationContextTypeService) {
711                 _simulationContextTypeService = simulationContextTypeService;
712         }
713
714         /**
715          * Get the knowledgeElementTypeService.
716          * 
717          * @return the knowledgeElementTypeService
718          */
719         public KnowledgeElementTypeService getKnowledgeElementTypeService() {
720                 return _knowledgeElementTypeService;
721         }
722
723         /**
724          * Set the knowledgeElementTypeService.
725          * 
726          * @param knowledgeElementTypeService
727          *            the knowledgeElementTypeService to set
728          */
729         public void setKnowledgeElementTypeService(
730                         final KnowledgeElementTypeService knowledgeElementTypeService) {
731                 _knowledgeElementTypeService = knowledgeElementTypeService;
732         }
733
734         /**
735          * Get the documentTypeService.
736          * 
737          * @return the documentTypeService
738          */
739         public DocumentTypeService getDocumentTypeService() {
740                 return _documentTypeService;
741         }
742
743         /**
744          * Set the documentTypeService.
745          * 
746          * @param documentTypeService
747          *            the documentTypeService to set
748          */
749         public void setDocumentTypeService(
750                         final DocumentTypeService documentTypeService) {
751                 _documentTypeService = documentTypeService;
752         }
753 }