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);
57 * Type attribute name.
59 private final static String TYPE_ATTR = "type";
61 // Non persistent configuration information
63 * Repository settings.
65 private transient final Properties _reprop = new Properties();
67 * Pattern of study references.
69 private transient String _pattern;
71 * Scheme of file names stored into the repository.
73 private transient FileNaming _naming;
75 * Pattern of the presentation of version numbers.
77 private transient String _versioning;
79 * Ordered list of (transient) study steps.
81 private transient final List<ProjectSettingsService.Step> _steps = new ArrayList<ProjectSettingsService.Step>();
83 * Configuration document validation cycles.
85 private transient final List<ProjectSettingsValidationCycle> _concycles = new ArrayList<ProjectSettingsValidationCycle>();
87 * Document type mappings to file formats which should be imported into SALOME during check-out.
89 private transient final Map<String, List<String>> _mapimport = new HashMap<String, List<String>>();
91 // Temporary attributes initialized from the configuration file for populating the database with object types
93 * Document type names and uses mapping.
95 private transient Map<String, String> _mapuse;
97 * Simulation Context type names.
99 private transient List<String> _context;
101 * Knowledge Element type names.
103 private transient List<String> _kname;
107 private transient List<NamedNodeMap> _flows;
109 * Study classifications.
111 private transient List<NamedNodeMap> _sclass;
115 * Database service to check its version, etc.
117 private Database _database;
119 * Injected simulation context type service.
121 private SimulationContextTypeService _simulationContextTypeService;
123 * Injected knowledge element type service.
125 private KnowledgeElementTypeService _knowledgeElementTypeService;
127 * Injected document type service.
129 private DocumentTypeService _documentTypeService;
132 * Default document types structured by step.formats.
134 private transient final Map<String, DocumentType> _defdoctype = new LinkedHashMap<String, DocumentType>();
137 * File naming strategy enumeration.
139 public enum FileNaming {
141 * Name by document title.
145 * Generate encoded name.
149 * Keep original file name.
155 * Validation cycle defined in the XML configuration.
157 public static class ProjectSettingsValidationCycle {
159 * Cycle (document) type name.
161 private transient final String _name;
163 * Array of cycle actors positions in the organization. TODO: Must be replaced by Roles.
165 private transient final Actor[] _actor;
168 * Default constructor.
170 private ProjectSettingsValidationCycle() {
171 this._name = "built-in";
172 this._actor = new Actor[] { null, null, null };
176 * Create a validation cycle definition for the given document type name and actors positions.
179 * the document type name
181 * the array of actors positions
183 private ProjectSettingsValidationCycle(final String name,
184 final Actor[] actor) {
190 * The processed document type name.
192 * @return the document type name
194 public String getName() {
199 * Get an array of cycle actors positions.
201 * @return the array of actors positions
202 * @see org.splat.dal.bo.som.ValidationCycle.Actor
204 public Actor[] getActorTypes() {
209 // ==============================================================================================================================
211 // ==============================================================================================================================
214 * Load workflow configuration from the given file. <br/> Create necessary default staff in the database if it is not initialized yet.
217 * the workflow configuration file
218 * @throws IOException
219 * if there is a file reading or index creation problem
220 * @throws SQLException
221 * if there is a database population problem
223 public void configure(final String filename) throws IOException,
225 if (!_steps.isEmpty()) {
226 return; // Project already configured
229 Database base = getDatabase().getCheckedDB();
230 File config = new File(filename);
231 if (config.exists()) {
232 loadCustomization(config);
234 LOG.fatal("Could not find the database configuration file \""
235 + config.getAbsolutePath() + "\"");
236 throw new FileNotFoundException();
238 base.configure(_reprop);
239 if (!base.isInitialized()) {
241 initialize(); // Populates the database with all necessary stuff
246 * Get ordered list of (transient) study steps.
248 * @return the list of steps from project settings
250 public List<ProjectSettingsService.Step> getAllSteps() {
255 * Return the validation cycles of result documents defined in the workflow, ordered by study activities and ending by the default
256 * validation cycle, if defined.
258 * @return the validation cycles of the workflow
260 public List<ProjectSettingsValidationCycle> getAllValidationCycles() {
265 * Get file naming scheme setting.
267 * @return file naming scheme
268 * @see org.splat.service.technical.ProjectSettingsServiceImpl.FileNaming
270 public FileNaming getFileNamingScheme() {
275 * Get a pattern of study references.
277 * @return the reference pattern
279 public String getReferencePattern() {
284 * Get a pattern of the presentation of version numbers.
286 * @return the version numbers presentation pattern
288 public String getRevisionPattern() {
293 * Get a study step by its sequential number.
299 public ProjectSettingsService.Step getStep(final int number) {
300 ProjectSettingsService.Step res = null;
301 for (int i = 0; i < _steps.size(); i++) {
302 ProjectSettingsService.Step step = _steps.get(i);
303 if (step.getNumber() == number) {
312 * Get steps of the given project element (study or scenario).
315 * the project element (study or scenario)
316 * @return the list of steps
318 public List<ProjectSettingsService.Step> getStepsOf(
319 final Class<? extends ProjectElement> level) {
320 List<ProjectSettingsService.Step> result = new ArrayList<ProjectSettingsService.Step>();
322 for (int i = 0; i < _steps.size(); i++) {
323 ProjectSettingsService.Step step = _steps.get(i);
324 if (step.appliesTo(level)) {
332 * Check if a file of the given format should be imported during check-in of a document of the given type.
338 * @return true if file should be imported
340 public boolean doImport(final String type, final String format) {
341 return (_mapimport.containsKey(type) && _mapimport.get(type).contains(
346 * Get default document type for the given file format on the given study step.
351 * the file format (extension)
352 * @return document type
354 public DocumentType getDefaultDocumentType(final Step step,
355 final String format) {
356 String[] table = format.split("\\x2E");
358 .get(step.getNumber() + "." + table[table.length - 1]); // May be null
362 * Get the list of default formats for the given study step.
366 * @return list of formats (file extensions)
368 public List<String> getDefaultFormats(final Step step) {
369 Integer stepNumber = step.getNumber();
370 List<String> result = new ArrayList<String>();
372 for (String i : _defdoctype.keySet()) {
373 String[] key = i.split("\\x2E");
374 // PDF is not an authoring format
375 if (stepNumber.equals(Integer.valueOf(key[0]))
376 && (!key[1].equals("pdf"))) {
377 result.add(key[1]); // Formats are unique
384 * Initialize the database: create all necessary default staff defined in the configuration file.
386 protected void initialize() {
387 createDocumentTypes();
388 createSimulationContextTypes();
389 createKnowledgeElementTypes();
392 // ==============================================================================================================================
393 // Private member function
394 // ==============================================================================================================================
397 * Read the configuration file and fill transient project settings fields.
400 * the configuration XML file
402 private void loadCustomization(final File config) {
404 DocumentBuilderFactory dfactory = javax.xml.parsers.DocumentBuilderFactory
406 DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
408 org.w3c.dom.Document conf = dBuilder.parse(config.getPath());
409 HashMap<String, Node> children = XDOM.getNamedChildNodes(conf
410 .getDocumentElement());
412 // Repository tag initializing the reprop attribute
413 Node child = children.get("database");
414 HashMap<String, Node> datag = XDOM.getNamedChildNodes(child);
416 String disk = datag.get("repository").getAttributes().getNamedItem(
417 "disk").getNodeValue();
418 if (!disk.endsWith("/")) {
421 LOG.info("Database root set to " + disk);
422 _reprop.setProperty("repository", disk);
424 // Formats tag initializing the reference pattern and date attributes
425 child = children.get("formats");
426 datag = XDOM.getNamedChildNodes(child);
428 NamedNodeMap natr = datag.get("references").getAttributes();
429 _pattern = natr.getNamedItem("study").getNodeValue();
431 natr = datag.get("files").getAttributes();
432 _naming = FileNaming.valueOf(natr.getNamedItem("name")
435 natr = datag.get("versions").getAttributes();
436 _versioning = natr.getNamedItem("pattern").getNodeValue();
438 // Activities tag initializing the steps and rex attributes
439 child = children.get("activities");
440 NodeList nlist = child.getChildNodes();
441 List<NamedNodeMap> flist = new ArrayList<NamedNodeMap>();
442 List<String> resultype = new ArrayList<String>();
443 List<NamedNodeMap> clist = new ArrayList<NamedNodeMap>();
445 int snum = 1; // Base number of steps
446 for (int i = 0; i < nlist.getLength(); i++) {
447 child = nlist.item(i);
448 if ("scenario".equals(child.getNodeName())) {
449 NodeList slist = child.getChildNodes();
450 for (int j = 0; j < slist.getLength(); j++) {
451 snum = loadStep(slist.item(j), Scenario.class, snum,
452 flist, clist, resultype);
455 snum = loadStep(child, Study.class, snum, flist, clist,
461 loadValidationCycles(children, resultype);
462 // Load steps result document types mapped to file formats
463 loadFormatMappings(children);
464 // Load default mapping of file formats to document types for each step
465 loadDefaultDocTypes(children);
467 if (!getDatabase().getCheckedDB().isInitialized()) {
468 // Load object type definitions
470 child = children.get("documents");
471 nlist = child.getChildNodes();
473 _flows = flist; // Kept for later use in document type definition
474 _sclass = clist; // Kept for later use in simulation context type definition
475 _mapuse = new LinkedHashMap<String, String>();
476 for (int i = 0; i < nlist.getLength(); i++) {
477 child = nlist.item(i);
478 if ("article".equals(child.getNodeName())) {
479 natr = child.getAttributes();
480 String type = natr.getNamedItem(TYPE_ATTR)
483 child = natr.getNamedItem("uses");
485 uses = child.getNodeValue();
487 _mapuse.put(type, uses); // Must be added to the map even if no (null) uses
490 // Simulation Contexts tag
491 _context = loadArticles(children, "contexts");
492 // Knowledge Elements tag
493 _kname = loadArticles(children, "knowledges");
495 } catch (Exception error) {
496 LOG.info("Error in customization", error);
501 * Load mappings of document types to lists of importable file formats.
506 private void loadFormatMappings(final Map<String, Node> children) {
508 Element maps = (Element) children.get("mappings");
511 List<String> formats;
512 NodeList docs, imports;
514 // Read document types
515 docs = maps.getElementsByTagName("document");
516 for (int i = 0; i < docs.getLength(); i++) {
517 doc = (Element) docs.item(i);
518 type = doc.getAttribute(TYPE_ATTR);
519 if (!type.isEmpty()) {
520 // Read file formats for the document type
521 imports = doc.getElementsByTagName("import");
522 formats = new ArrayList<String>();
523 for (int j = 0; j < imports.getLength(); j++) {
524 imp = (Element) imports.item(j);
525 format = imp.getAttribute("format");
526 if (!format.isEmpty()) {
530 if (!formats.isEmpty()) {
531 _mapimport.put(type, formats);
539 * Load default document types from XML configuration.
544 private void loadDefaultDocTypes(final Map<String, Node> children) {
546 Node child = children.get("default-doctypes");
547 NodeList nlist = child.getChildNodes();
549 List<DocumentType> listype = getDocumentTypeService().selectAllTypes();
550 Map<String, DocumentType> maptype = new HashMap<String, DocumentType>();
551 for (Iterator<DocumentType> i = listype.iterator(); i.hasNext();) {
552 DocumentType type = i.next();
553 maptype.put(type.getName(), type);
555 for (int i = 0; i < nlist.getLength(); i++) {
556 child = nlist.item(i);
557 if (!child.getNodeName().equals("step")) {
561 String nstep = child.getAttributes().getNamedItem("number")
563 NodeList map = child.getChildNodes();
564 for (int j = 0; j < map.getLength(); j++) {
566 if (!child.getNodeName().equals("mapping")) {
569 NamedNodeMap natr = child.getAttributes();
570 String dext = natr.getNamedItem("extension").getNodeValue();
571 String type = natr.getNamedItem(TYPE_ATTR).getNodeValue();
572 _defdoctype.put(nstep + "." + dext, maptype.get(type));
578 * Load a step from the given XML node. Return the next step's number.
583 * the class of a step's owner project element - study or scenario
589 * list of classifications
591 * list of flow results
592 * @return the next step's number
594 private int loadStep(final Node node,
595 final Class<? extends ProjectElement> ownerClass, final int snum,
596 final List<NamedNodeMap> flist, final List<NamedNodeMap> clist,
597 final List<String> resultype) {
599 if ("step".equals(node.getNodeName())) {
601 String name = ((Element) node).getAttribute("name");
602 HashMap<String, Node> tags = XDOM.getNamedChildNodes(node);
604 NamedNodeMap natr = tags.get("storage").getAttributes();
605 ProjectSettingsService.Step step = new ProjectSettingsService.Step(
606 snum, ownerClass, natr.getNamedItem("path").getNodeValue());
609 // Keeping flow and classification information for eventual later use
610 natr = tags.get("flow").getAttributes();
612 Node child = natr.getNamedItem("result");
614 resultype.add(child.getNodeValue());
617 child = tags.get("classification");
621 clist.add(child.getAttributes());
624 if (natr.getNamedItem("contents").getNodeValue()
625 .equals("knowledge")) {
626 if (Study.class.equals(ownerClass)) {
628 .error("Error: knowledges must be attached to scenarios.");
630 // TODO In a given scenario, only one step must contain knowledges
631 step._contents.add(KnowledgeElement.class);
634 step._contents.add(Document.class);
637 Element module = (Element) tags.get("module");
638 if (module != null) {
639 step.setModule(module.getAttribute("name"));
649 * Get custom validation cycles.
654 * list of result types
656 private void loadValidationCycles(final Map<String, Node> children,
657 final List<String> resultype) {
659 Node child = children.get("validations");
660 Map<String, Node> datag = XDOM.getNamedChildNodes(child);
663 String[] step = { "review", "approval", "acceptance" };
664 resultype.add("default");
665 for (Iterator<String> i = resultype.iterator(); i.hasNext();) {
666 Actor[] actor = { null, null, null };
667 String name = i.next();
668 child = datag.get(name);
670 // Document type is the subject of a validation
671 natr = child.getAttributes();
672 for (int j = 0; j < step.length; j++) {
673 child = natr.getNamedItem(step[j]);
675 actor[j] = Actor.valueOf(child.getNodeValue()); // Validation step is required
678 _concycles.add(new ProjectSettingsValidationCycle(name, actor));
681 _concycles.add(new ProjectSettingsValidationCycle()); // Adds the built-in validation cycle
685 * Read list of articles types.
688 * XML nodes containing articles
690 * the name of the list of articles
691 * @return list of articles types
693 private List<String> loadArticles(final Map<String, Node> children,
694 final String listName) {
695 Node child = children.get(listName);
696 NodeList nlist = child.getChildNodes();
698 List<String> articles = new ArrayList<String>();
699 for (int i = 0; i < nlist.getLength(); i++) {
700 child = nlist.item(i);
701 if (child.getNodeName().equals("article")) {
702 articles.add(child.getAttributes().getNamedItem(TYPE_ATTR)
710 * Create in the database document types defined in the custom configuration.
712 private void createDocumentTypes() {
713 if (LOG.isDebugEnabled()) {
714 LOG.debug("Creating documents types...");
716 DocumentType.Properties tprop = new DocumentType.Properties();
717 Map<String, List<ProjectSettingsService.Step>> mapsteps = new HashMap<String, List<ProjectSettingsService.Step>>();
718 Map<String, ProjectSettingsService.Step> mapresult = new HashMap<String, ProjectSettingsService.Step>();
719 Map<String, DocumentType> maptype = new HashMap<String, DocumentType>();
721 List<ProjectSettingsService.Step> slist = null; // List of Steps to which each document type is valid
722 int snum = 0; // Step number
725 for (Iterator<NamedNodeMap> i = _flows.iterator(); i.hasNext(); snum++) {
726 NamedNodeMap flow = i.next();
727 ProjectSettingsService.Step step = _steps.get(snum);
728 String[] contents = flow.getNamedItem("contents").getNodeValue()
730 for (int j = 0; j < contents.length; j++) {
732 if (!_mapuse.containsKey(type)) {
733 LOG.warn("Undefined \"" + type + "\" document type.");
736 slist = mapsteps.get(type);
738 slist = new ArrayList<ProjectSettingsService.Step>();
741 mapsteps.put(type, slist);
743 Node result = flow.getNamedItem("result");
744 if (result != null) {
745 mapresult.put(result.getNodeValue(), step);
749 DocumentType tdoc = null;
750 Set<String> tset = _mapuse.keySet();
751 ProjectSettingsService.Step step;
752 for (Iterator<String> i = tset.iterator(); i.hasNext();) {
754 slist = mapsteps.get(type);
756 uses = _mapuse.get(type);
757 step = mapresult.get(type);
760 tprop.setName(type).setStep(
761 slist.toArray(new ProjectSettingsService.Step[slist
764 tdoc = maptype.get(uses);
766 LOG.warn("Undefined \"" + uses
767 + "\" document type.");
773 tprop.setResult(step);
776 tprop.disableCheck();
777 tdoc = getDocumentTypeService().createType(tprop); // Creation of Document Types
778 getDocumentTypeService().approve(tdoc);
779 maptype.put(type, tdoc);
782 } catch (Exception error) {
783 LOG.warn("Error creating document types, reason:", error); // Should not happen
785 if (LOG.isDebugEnabled()) {
786 LOG.debug("Documents types are created: " + maptype.size());
791 * Create in the database knowledge types defined in the custom configuration.
793 private void createKnowledgeElementTypes() {
795 KnowledgeElementType ktype = getKnowledgeElementTypeService()
796 .createType("usecase"); // Internal reserved knowledge element type
797 getKnowledgeElementTypeService().reserve(ktype);
798 for (Iterator<String> i = _kname.iterator(); i.hasNext();) {
799 String type = i.next();
801 ktype = getKnowledgeElementTypeService().createType(type); // Knowledge Elements Types defined in the configuration
802 getKnowledgeElementTypeService().approve(ktype);
804 } catch (Exception error) {
805 LOG.warn("Error creating knowledge types, reason:", error); // Should not happen
810 * Create in the database simulation contexts types defined in the custom configuration.
812 private void createSimulationContextTypes() {
813 Map<String, ProjectSettingsService.Step> mapstep = new HashMap<String, ProjectSettingsService.Step>();
815 for (Iterator<NamedNodeMap> i = _sclass.iterator(); i.hasNext(); snum++) {
816 NamedNodeMap clatr = i.next();
818 String[] clist = clatr.getNamedItem("context").getNodeValue()
820 for (int j = 0; j < clist.length; j++) {
821 mapstep.put(clist[j], _steps.get(snum));
826 SimulationContextType tctex = null;
827 for (Iterator<String> i = _context.iterator(); i.hasNext();) {
828 String type = i.next();
829 if (mapstep.containsKey(type)) {
830 tctex = getSimulationContextTypeService().createType(type,
831 mapstep.get(type)); // Creation of Simulation Context Types
832 getSimulationContextTypeService().approve(tctex);
835 .warn("Could not find \""
837 + "\" classification. Simulation Context type ignored.");
840 } catch (Exception error) {
841 LOG.warn("Error creating context types, reason:", error); // Should not happen
848 * @return the database
850 public Database getDatabase() {
858 * the database to set
860 public void setDatabase(final Database database) {
861 _database = database;
865 * Get the simulationContextTypeService.
867 * @return the simulationContextTypeService
869 public SimulationContextTypeService getSimulationContextTypeService() {
870 return _simulationContextTypeService;
874 * Set the simulationContextTypeService.
876 * @param simulationContextTypeService
877 * the simulationContextTypeService to set
879 public void setSimulationContextTypeService(
880 final SimulationContextTypeService simulationContextTypeService) {
881 _simulationContextTypeService = simulationContextTypeService;
885 * Get the knowledgeElementTypeService.
887 * @return the knowledgeElementTypeService
889 public KnowledgeElementTypeService getKnowledgeElementTypeService() {
890 return _knowledgeElementTypeService;
894 * Set the knowledgeElementTypeService.
896 * @param knowledgeElementTypeService
897 * the knowledgeElementTypeService to set
899 public void setKnowledgeElementTypeService(
900 final KnowledgeElementTypeService knowledgeElementTypeService) {
901 _knowledgeElementTypeService = knowledgeElementTypeService;
905 * Get the documentTypeService.
907 * @return the documentTypeService
909 public DocumentTypeService getDocumentTypeService() {
910 return _documentTypeService;
914 * Set the documentTypeService.
916 * @param documentTypeService
917 * the documentTypeService to set
919 public void setDocumentTypeService(
920 final DocumentTypeService documentTypeService) {
921 _documentTypeService = documentTypeService;