1 package org.splat.service.technical;
5 * @author Daniel Brunier-Coulin
6 * @copyright OPEN CASCADE 2012
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;
19 import java.util.Properties;
22 import javax.xml.parsers.DocumentBuilder;
23 import javax.xml.parsers.DocumentBuilderFactory;
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;
46 * SIMAN workflow configuration data service.
48 public class ProjectSettingsServiceImpl implements ProjectSettingsService {
51 * The logger for the service.
53 protected final static Logger LOG = Logger
54 .getLogger(ProjectSettingsServiceImpl.class);
56 // Non persistent configuration information
58 * Repository settings.
60 private transient final Properties _reprop = new Properties();
62 * Pattern of study references.
64 private transient String _pattern;
66 * Scheme of file names stored into the repository.
68 private transient FileNaming _naming;
70 * Pattern of the presentation of version numbers.
72 private transient String _versioning;
74 * Ordered list of (transient) study steps.
76 private transient final List<ProjectSettingsService.Step> _steps = new ArrayList<ProjectSettingsService.Step>();
78 * Configuration document validation cycles.
80 private transient List<ProjectSettingsValidationCycle> _concycles;
82 * Document type mappings to file formats which should be imported into SALOME during check-out.
84 private transient Map<String, List<String>> _mapimport;
86 // Temporary attributes initialized from the configuration file for populating the database with object types
88 * Document type names and uses mapping.
90 private transient Map<String, String> _mapuse;
92 * Simulation Context type names.
94 private transient List<String> _context;
96 * Knowledge Element type names.
98 private transient List<String> _kname;
102 private transient List<NamedNodeMap> _flows;
104 * Study classifications.
106 private transient List<NamedNodeMap> _sclass;
110 * Database service to check its version, etc.
112 private Database _database;
114 * Injected simulation context type service.
116 private SimulationContextTypeService _simulationContextTypeService;
118 * Injected knowledge element type service.
120 private KnowledgeElementTypeService _knowledgeElementTypeService;
122 * Injected document type service.
124 private DocumentTypeService _documentTypeService;
126 public enum FileNaming {
131 * Validation cycle defined in the XML configuration.
133 public static class ProjectSettingsValidationCycle {
135 * Cycle (document) type name.
137 private transient final String _name;
139 * Array of cycle actors positions in the organization. TODO: Must be replaced by Roles.
141 private transient final Actor[] _actor;
144 * Default constructor.
146 private ProjectSettingsValidationCycle() {
147 this._name = "built-in";
148 this._actor = new Actor[] { null, null, null };
152 * Create a validation cycle definition for the given document type name and actors positions.
155 * the document type name
157 * the array of actors positions
159 private ProjectSettingsValidationCycle(final String name,
160 final Actor[] actor) {
166 * The processed document type name.
168 * @return the document type name
170 public String getName() {
175 * Get an array of cycle actors positions.
177 * @return the array of actors positions
178 * @see org.splat.dal.bo.som.ValidationCycle.Actor
180 public Actor[] getActorTypes() {
185 // ==============================================================================================================================
187 // ==============================================================================================================================
190 * Load workflow configuration from the given file. <br/> Create necessary default staff in the database if it is not initialized yet.
193 * the workflow configuration file
194 * @throws IOException
195 * if there is a file reading or index creation problem
196 * @throws SQLException
197 * if there is a database population problem
199 public void configure(final String filename) throws IOException,
201 if (!_steps.isEmpty()) {
202 return; // Project already configured
205 Database base = getDatabase().getCheckedDB();
206 File config = new File(filename);
207 if (config.exists()) {
208 loadCustomization(config);
210 LOG.fatal("Could not find the database configuration file \""
211 + config.getAbsolutePath() + "\"");
212 throw new FileNotFoundException();
214 base.configure(_reprop);
215 if (!base.isInitialized()) {
217 initialize(); // Populates the database with all necessary stuff
222 * Get ordered list of (transient) study steps.
224 * @return the list of steps from project settings
226 public List<ProjectSettingsService.Step> getAllSteps() {
231 * Return the validation cycles of result documents defined in the workflow, ordered by study activities and ending by the default
232 * validation cycle, if defined.
234 * @return the validation cycles of the workflow
236 public List<ProjectSettingsValidationCycle> getAllValidationCycles() {
241 * Get file naming scheme setting.
243 * @return file naming scheme
244 * @see org.splat.service.technical.ProjectSettingsServiceImpl.FileNaming
246 public FileNaming getFileNamingScheme() {
251 * Get a pattern of study references.
253 * @return the reference pattern
255 public String getReferencePattern() {
260 * Get a pattern of the presentation of version numbers.
262 * @return the version numbers presentation pattern
264 public String getRevisionPattern() {
269 * Get a study step by its sequential number.
275 public ProjectSettingsService.Step getStep(final int number) {
276 ProjectSettingsService.Step res = null;
277 for (int i = 0; i < _steps.size(); i++) {
278 ProjectSettingsService.Step step = _steps.get(i);
279 if (step.getNumber() == number) {
288 * Get steps of the given project element (study or scenario).
291 * the project element (study or scenario)
292 * @return the list of steps
294 public List<ProjectSettingsService.Step> getStepsOf(
295 final Class<? extends ProjectElement> level) {
296 List<ProjectSettingsService.Step> result = new ArrayList<ProjectSettingsService.Step>();
298 for (int i = 0; i < _steps.size(); i++) {
299 ProjectSettingsService.Step step = _steps.get(i);
300 if (step.appliesTo(level)) {
308 * Check if a file of the given format should be imported during check-in of a document of the given type.
314 * @return true if file should be imported
316 public boolean doImport(final String type, final String format) {
317 return (_mapimport.containsKey(type) && _mapimport.get(type).contains(
322 * Initialize the database: create all necessary default staff defined in the configuration file.
324 protected void initialize() {
325 createDocumentTypes();
326 createSimulationContextTypes();
327 createKnowledgeElementTypes();
330 // ==============================================================================================================================
331 // Private member function
332 // ==============================================================================================================================
335 * Read the configuration file and fill transient project settings fields.
338 * the configuration XML file
340 private void loadCustomization(final File config) {
342 DocumentBuilderFactory dfactory = javax.xml.parsers.DocumentBuilderFactory
344 DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
346 org.w3c.dom.Document conf = dBuilder.parse(config.getPath());
347 HashMap<String, Node> children = XDOM.getNamedChildNodes(conf
348 .getDocumentElement());
350 // Repository tag initializing the reprop attribute
351 Node child = children.get("database");
352 HashMap<String, Node> datag = XDOM.getNamedChildNodes(child);
354 String disk = datag.get("repository").getAttributes().getNamedItem(
355 "disk").getNodeValue();
356 if (!disk.endsWith("/")) {
359 LOG.info("Database root set to " + disk);
360 _reprop.setProperty("repository", disk);
362 // Formats tag initializing the reference pattern and date attributes
363 child = children.get("formats");
364 datag = XDOM.getNamedChildNodes(child);
366 NamedNodeMap natr = datag.get("references").getAttributes();
367 _pattern = natr.getNamedItem("study").getNodeValue();
369 natr = datag.get("files").getAttributes();
370 _naming = FileNaming.valueOf(natr.getNamedItem("name")
373 natr = datag.get("versions").getAttributes();
374 _versioning = natr.getNamedItem("pattern").getNodeValue();
376 // Activities tag initializing the steps and rex attributes
377 child = children.get("activities");
378 NodeList nlist = child.getChildNodes();
379 List<NamedNodeMap> flist = new ArrayList<NamedNodeMap>();
380 List<String> resultype = new ArrayList<String>();
381 List<NamedNodeMap> clist = new ArrayList<NamedNodeMap>();
383 int snum = 1; // Base number of steps
384 for (int i = 0; i < nlist.getLength(); i++) {
385 child = nlist.item(i);
386 if ("scenario".equals(child.getNodeName())) {
387 NodeList slist = child.getChildNodes();
388 for (int j = 0; j < slist.getLength(); j++) {
389 snum = loadStep(slist.item(j), Scenario.class, snum,
390 flist, clist, resultype);
393 snum = loadStep(child, Study.class, snum, flist, clist,
398 _concycles = loadValidationCycles(children, resultype);
400 _mapimport = loadFormatMappings(children);
402 if (!getDatabase().getCheckedDB().isInitialized()) {
403 // Load object type definitions
405 child = children.get("documents");
406 nlist = child.getChildNodes();
408 _flows = flist; // Kept for later use in document type definition
409 _sclass = clist; // Kept for later use in simulation context type definition
410 _mapuse = new LinkedHashMap<String, String>();
411 for (int i = 0; i < nlist.getLength(); i++) {
412 child = nlist.item(i);
413 if ("article".equals(child.getNodeName())) {
414 natr = child.getAttributes();
415 String type = natr.getNamedItem("type").getNodeValue();
417 child = natr.getNamedItem("uses");
419 uses = child.getNodeValue();
421 _mapuse.put(type, uses); // Must be added to the map even if no (null) uses
424 // Simulation Contexts tag
425 _context = loadArticles(children, "contexts");
426 // Knowledge Elements tag
427 _kname = loadArticles(children, "knowledges");
429 } catch (Exception error) {
430 LOG.info("Error in customization", error);
435 * Load mappings of document types to lists of importable file formats.
439 * @return map of document type names to lists of file formats
441 private Map<String, List<String>> loadFormatMappings(
442 final Map<String, Node> children) {
443 Map<String, List<String>> res = new HashMap<String, List<String>>();
444 Element maps = (Element) children.get("mappings");
447 List<String> formats;
448 NodeList docs, imports;
450 // Read document types
451 docs = maps.getElementsByTagName("document");
452 for (int i = 0; i < docs.getLength(); i++) {
453 doc = (Element) docs.item(i);
454 type = doc.getAttribute("type");
455 if (!type.isEmpty()) {
456 // Read file formats for the document type
457 imports = doc.getElementsByTagName("import");
458 formats = new ArrayList<String>();
459 for (int j = 0; j < imports.getLength(); j++) {
460 imp = (Element) imports.item(j);
461 format = imp.getAttribute("format");
462 if (!format.isEmpty()) {
466 if (!formats.isEmpty()) {
467 res.put(type, formats);
476 * Load a step from the given XML node. Return the next step's number.
481 * the class of a step's owner project element - study or scenario
487 * list of classifications
489 * list of flow results
490 * @return the next step's number
492 private int loadStep(final Node node,
493 final Class<? extends ProjectElement> ownerClass, final int snum,
494 final List<NamedNodeMap> flist, final List<NamedNodeMap> clist,
495 final List<String> resultype) {
497 if ("step".equals(node.getNodeName())) {
499 String name = ((Element) node).getAttribute("name");
500 HashMap<String, Node> tags = XDOM.getNamedChildNodes(node);
502 NamedNodeMap natr = tags.get("storage").getAttributes();
503 ProjectSettingsService.Step step = new ProjectSettingsService.Step(
504 snum, ownerClass, natr.getNamedItem("path").getNodeValue());
507 // Keeping flow and classification information for eventual later use
508 natr = tags.get("flow").getAttributes();
510 Node child = natr.getNamedItem("result");
512 resultype.add(child.getNodeValue());
515 child = tags.get("classification");
519 clist.add(child.getAttributes());
522 if (natr.getNamedItem("contents").getNodeValue()
523 .equals("knowledge")) {
524 if (Study.class.equals(ownerClass)) {
526 .error("Error: knowledges must be attached to scenarios.");
528 // TODO In a given scenario, only one step must contain knowledges
529 step._contents.add(KnowledgeElement.class);
532 step._contents.add(Document.class);
535 Element module = (Element) tags.get("module");
536 if (module != null) {
537 step.setModule(module.getAttribute("name"));
547 * Get custom validation cycles.
552 * list of result types
553 * @return return list of validation cycles
555 private List<ProjectSettingsValidationCycle> loadValidationCycles(
556 final Map<String, Node> children, final List<String> resultype) {
557 Node child = children.get("validations");
558 List<ProjectSettingsValidationCycle> cycles = new ArrayList<ProjectSettingsValidationCycle>();
559 Map<String, Node> datag = XDOM.getNamedChildNodes(child);
562 String[] step = { "review", "approval", "acceptance" };
563 resultype.add("default");
564 for (Iterator<String> i = resultype.iterator(); i.hasNext();) {
565 Actor[] actor = { null, null, null };
566 String name = i.next();
567 child = datag.get(name);
569 // Document type is the subject of a validation
570 natr = child.getAttributes();
571 for (int j = 0; j < step.length; j++) {
572 child = natr.getNamedItem(step[j]);
574 actor[j] = Actor.valueOf(child.getNodeValue()); // Validation step is required
577 cycles.add(new ProjectSettingsValidationCycle(name, actor));
580 cycles.add(new ProjectSettingsValidationCycle()); // Adds the built-in validation cycle
585 * Read list of articles types.
588 * XML nodes containing articles
590 * the name of the list of articles
591 * @return list of articles types
593 private List<String> loadArticles(final Map<String, Node> children,
594 final String listName) {
595 Node child = children.get(listName);
596 NodeList nlist = child.getChildNodes();
598 List<String> articles = new ArrayList<String>();
599 for (int i = 0; i < nlist.getLength(); i++) {
600 child = nlist.item(i);
601 if (child.getNodeName().equals("article")) {
602 articles.add(child.getAttributes().getNamedItem("type")
610 * Create in the database document types defined in the custom configuration.
612 private void createDocumentTypes() {
613 if (LOG.isDebugEnabled()) {
614 LOG.debug("Creating documents types...");
616 DocumentType.Properties tprop = new DocumentType.Properties();
617 Map<String, List<ProjectSettingsService.Step>> mapsteps = new HashMap<String, List<ProjectSettingsService.Step>>();
618 Map<String, ProjectSettingsService.Step> mapresult = new HashMap<String, ProjectSettingsService.Step>();
619 Map<String, DocumentType> maptype = new HashMap<String, DocumentType>();
621 List<ProjectSettingsService.Step> slist = null; // List of Steps to which each document type is valid
622 int snum = 0; // Step number
625 for (Iterator<NamedNodeMap> i = _flows.iterator(); i.hasNext(); snum++) {
626 NamedNodeMap flow = i.next();
627 ProjectSettingsService.Step step = _steps.get(snum);
628 String[] contents = flow.getNamedItem("contents").getNodeValue()
630 for (int j = 0; j < contents.length; j++) {
632 if (!_mapuse.containsKey(type)) {
633 LOG.warn("Undefined \"" + type + "\" document type.");
636 slist = mapsteps.get(type);
638 slist = new ArrayList<ProjectSettingsService.Step>();
641 mapsteps.put(type, slist);
643 Node result = flow.getNamedItem("result");
644 if (result != null) {
645 mapresult.put(result.getNodeValue(), step);
649 DocumentType tdoc = null;
650 Set<String> tset = _mapuse.keySet();
651 ProjectSettingsService.Step step;
652 for (Iterator<String> i = tset.iterator(); i.hasNext();) {
654 slist = mapsteps.get(type);
656 uses = _mapuse.get(type);
657 step = mapresult.get(type);
660 tprop.setName(type).setStep(
661 slist.toArray(new ProjectSettingsService.Step[slist
664 tdoc = maptype.get(uses);
666 LOG.warn("Undefined \"" + uses
667 + "\" document type.");
673 tprop.setResult(step);
676 tprop.disableCheck();
677 tdoc = getDocumentTypeService().createType(tprop); // Creation of Document Types
678 getDocumentTypeService().approve(tdoc);
679 maptype.put(type, tdoc);
682 } catch (Exception error) {
683 LOG.warn("Error creating document types, reason:", error); // Should not happen
685 if (LOG.isDebugEnabled()) {
686 LOG.debug("Documents types are created: " + maptype.size());
691 * Create in the database knowledge types defined in the custom configuration.
693 private void createKnowledgeElementTypes() {
695 KnowledgeElementType ktype = getKnowledgeElementTypeService()
696 .createType("usecase"); // Internal reserved knowledge element type
697 getKnowledgeElementTypeService().reserve(ktype);
698 for (Iterator<String> i = _kname.iterator(); i.hasNext();) {
699 String type = i.next();
701 ktype = getKnowledgeElementTypeService().createType(type); // Knowledge Elements Types defined in the configuration
702 getKnowledgeElementTypeService().approve(ktype);
704 } catch (Exception error) {
705 LOG.warn("Error creating knowledge types, reason:", error); // Should not happen
710 * Create in the database simulation contexts types defined in the custom configuration.
712 private void createSimulationContextTypes() {
713 Map<String, ProjectSettingsService.Step> mapstep = new HashMap<String, ProjectSettingsService.Step>();
715 for (Iterator<NamedNodeMap> i = _sclass.iterator(); i.hasNext(); snum++) {
716 NamedNodeMap clatr = i.next();
718 String[] clist = clatr.getNamedItem("context").getNodeValue()
720 for (int j = 0; j < clist.length; j++) {
721 mapstep.put(clist[j], _steps.get(snum));
726 SimulationContextType tctex = null;
727 for (Iterator<String> i = _context.iterator(); i.hasNext();) {
728 String type = i.next();
729 if (mapstep.containsKey(type)) {
730 tctex = getSimulationContextTypeService().createType(type,
731 mapstep.get(type)); // Creation of Simulation Context Types
732 getSimulationContextTypeService().approve(tctex);
735 .warn("Could not find \""
737 + "\" classification. Simulation Context type ignored.");
740 } catch (Exception error) {
741 LOG.warn("Error creating context types, reason:", error); // Should not happen
748 * @return the database
750 public Database getDatabase() {
758 * the database to set
760 public void setDatabase(final Database database) {
761 _database = database;
765 * Get the simulationContextTypeService.
767 * @return the simulationContextTypeService
769 public SimulationContextTypeService getSimulationContextTypeService() {
770 return _simulationContextTypeService;
774 * Set the simulationContextTypeService.
776 * @param simulationContextTypeService
777 * the simulationContextTypeService to set
779 public void setSimulationContextTypeService(
780 final SimulationContextTypeService simulationContextTypeService) {
781 _simulationContextTypeService = simulationContextTypeService;
785 * Get the knowledgeElementTypeService.
787 * @return the knowledgeElementTypeService
789 public KnowledgeElementTypeService getKnowledgeElementTypeService() {
790 return _knowledgeElementTypeService;
794 * Set the knowledgeElementTypeService.
796 * @param knowledgeElementTypeService
797 * the knowledgeElementTypeService to set
799 public void setKnowledgeElementTypeService(
800 final KnowledgeElementTypeService knowledgeElementTypeService) {
801 _knowledgeElementTypeService = knowledgeElementTypeService;
805 * Get the documentTypeService.
807 * @return the documentTypeService
809 public DocumentTypeService getDocumentTypeService() {
810 return _documentTypeService;
814 * Set the documentTypeService.
816 * @param documentTypeService
817 * the documentTypeService to set
819 public void setDocumentTypeService(
820 final DocumentTypeService documentTypeService) {
821 _documentTypeService = documentTypeService;