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 // Temporary attributes initialized from the configuration file for populating the database with object types
84 * Document type names and uses mapping.
86 private transient Map<String, String> _mapuse;
88 * Simulation Context type names.
90 private transient List<String> _context;
92 * Knowledge Element type names.
94 private transient List<String> _kname;
98 private transient List<NamedNodeMap> _flows;
100 * Study classifications.
102 private transient List<NamedNodeMap> _sclass;
106 * Database service to check its version, etc.
108 private Database _database;
110 * Injected simulation context type service.
112 private SimulationContextTypeService _simulationContextTypeService;
114 * Injected knowledge element type service.
116 private KnowledgeElementTypeService _knowledgeElementTypeService;
118 * Injected document type service.
120 private DocumentTypeService _documentTypeService;
122 public enum FileNaming {
127 * Validation cycle defined in the XML configuration.
129 public static class ProjectSettingsValidationCycle {
131 * Cycle (document) type name.
133 private transient final String _name;
135 * Array of cycle actors positions in the organization. TODO: Must be replaced by Roles.
137 private transient final Actor[] _actor;
140 * Default constructor.
142 private ProjectSettingsValidationCycle() {
143 this._name = "built-in";
144 this._actor = new Actor[] { null, null, null };
148 * Create a validation cycle definition for the given document type name and actors positions.
151 * the document type name
153 * the array of actors positions
155 private ProjectSettingsValidationCycle(final String name,
156 final Actor[] actor) {
162 * The processed document type name.
164 * @return the document type name
166 public String getName() {
171 * Get an array of cycle actors positions.
173 * @return the array of actors positions
174 * @see org.splat.dal.bo.som.ValidationCycle.Actor
176 public Actor[] getActorTypes() {
181 // ==============================================================================================================================
183 // ==============================================================================================================================
186 * Load workflow configuration from the given file. <br/> Create necessary default staff in the database if it is not initialized yet.
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
195 public void configure(final String filename) throws IOException,
197 if (!_steps.isEmpty()) {
198 return; // Project already configured
201 Database base = getDatabase().getCheckedDB();
202 File config = new File(filename);
203 if (config.exists()) {
204 loadCustomization(config);
206 LOG.fatal("Could not find the database configuration file \""
207 + config.getAbsolutePath() + "\"");
208 throw new FileNotFoundException();
210 base.configure(_reprop);
211 if (!base.isInitialized()) {
213 initialize(); // Populates the database with all necessary stuff
218 * Get ordered list of (transient) study steps.
220 * @return the list of steps from project settings
222 public List<ProjectSettingsService.Step> getAllSteps() {
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.
230 * @return the validation cycles of the workflow
232 public List<ProjectSettingsValidationCycle> getAllValidationCycles() {
237 * Get file naming scheme setting.
239 * @return file naming scheme
240 * @see org.splat.service.technical.ProjectSettingsServiceImpl.FileNaming
242 public FileNaming getFileNamingScheme() {
247 * Get a pattern of study references.
249 * @return the reference pattern
251 public String getReferencePattern() {
256 * Get a pattern of the presentation of version numbers.
258 * @return the version numbers presentation pattern
260 public String getRevisionPattern() {
265 * Get a study step by its sequential number.
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) {
284 * Get steps of the given project element (study or scenario).
287 * the project element (study or scenario)
288 * @return the list of steps
290 public List<ProjectSettingsService.Step> getStepsOf(
291 final Class<? extends ProjectElement> level) {
292 List<ProjectSettingsService.Step> result = new ArrayList<ProjectSettingsService.Step>();
294 for (int i = 0; i < _steps.size(); i++) {
295 ProjectSettingsService.Step step = _steps.get(i);
296 if (step.appliesTo(level)) {
304 * Initialize the database: create all necessary default staff defined in the configuration file.
306 protected void initialize() {
307 createDocumentTypes();
308 createSimulationContextTypes();
309 createKnowledgeElementTypes();
312 // ==============================================================================================================================
313 // Private member function
314 // ==============================================================================================================================
317 * Read the configuration file and fill transient project settings fields.
320 * the configuration XML file
322 private void loadCustomization(final File config) {
324 DocumentBuilderFactory dfactory = javax.xml.parsers.DocumentBuilderFactory
326 DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
328 org.w3c.dom.Document conf = dBuilder.parse(config.getPath());
329 HashMap<String, Node> children = XDOM.getNamedChildNodes(conf
330 .getDocumentElement());
332 // Repository tag initializing the reprop attribute
333 Node child = children.get("database");
334 HashMap<String, Node> datag = XDOM.getNamedChildNodes(child);
336 String disk = datag.get("repository").getAttributes().getNamedItem(
337 "disk").getNodeValue();
338 if (!disk.endsWith("/")) {
341 LOG.info("Database root set to " + disk);
342 _reprop.setProperty("repository", disk);
344 // Formats tag initializing the reference pattern and date attributes
345 child = children.get("formats");
346 datag = XDOM.getNamedChildNodes(child);
348 NamedNodeMap natr = datag.get("references").getAttributes();
349 _pattern = natr.getNamedItem("study").getNodeValue();
351 natr = datag.get("files").getAttributes();
352 _naming = FileNaming.valueOf(natr.getNamedItem("name")
355 natr = datag.get("versions").getAttributes();
356 _versioning = natr.getNamedItem("pattern").getNodeValue();
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>();
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);
375 snum = loadStep(child, Study.class, snum, flist, clist,
380 _concycles = loadValidationCycles(children, resultype);
382 if (!getDatabase().getCheckedDB().isInitialized()) {
383 // Load object type definitions
385 child = children.get("documents");
386 nlist = child.getChildNodes();
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();
397 child = natr.getNamedItem("uses");
399 uses = child.getNodeValue();
401 _mapuse.put(type, uses); // Must be added to the map even if no (null) uses
404 // Simulation Contexts tag
405 _context = loadArticles(children, "contexts");
406 // Knowledge Elements tag
407 _kname = loadArticles(children, "knowledges");
409 } catch (Exception error) {
410 LOG.info("Error in customization", error);
415 * Load a step from the given XML node. Return the next step's number.
420 * the class of a step's owner project element - study or scenario
426 * list of classifications
428 * list of flow results
429 * @return the next step's number
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) {
436 if ("step".equals(node.getNodeName())) {
438 String name = ((Element)node).getAttribute("name");
439 HashMap<String, Node> tags = XDOM.getNamedChildNodes(node);
441 NamedNodeMap natr = tags.get("storage").getAttributes();
442 ProjectSettingsService.Step step = new ProjectSettingsService.Step(
443 snum, ownerClass, natr.getNamedItem("path").getNodeValue());
446 // Keeping flow and classification information for eventual later use
447 natr = tags.get("flow").getAttributes();
449 Node child = natr.getNamedItem("result");
451 resultype.add(child.getNodeValue());
454 child = tags.get("classification");
458 clist.add(child.getAttributes());
461 if (natr.getNamedItem("contents").getNodeValue()
462 .equals("knowledge")) {
463 if (Study.class.equals(ownerClass)) {
465 .error("Error: knowledges must be attached to scenarios.");
467 // TODO In a given scenario, only one step must contain knowledges
468 step._contents.add(KnowledgeElement.class);
471 step._contents.add(Document.class);
474 Element module = (Element) tags.get("module");
475 if (module != null) {
476 step.setModule(module.getAttribute("name"));
486 * Get custom validation cycles.
491 * list of result types
492 * @return return list of validation cycles
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);
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);
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]);
513 actor[j] = Actor.valueOf(child.getNodeValue()); // Validation step is required
516 cycles.add(new ProjectSettingsValidationCycle(name, actor));
519 cycles.add(new ProjectSettingsValidationCycle()); // Adds the built-in validation cycle
524 * Read list of articles types.
527 * XML nodes containing articles
529 * the name of the list of articles
530 * @return list of articles types
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();
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")
549 * Create in the database document types defined in the custom configuration.
551 private void createDocumentTypes() {
552 if (LOG.isDebugEnabled()) {
553 LOG.debug("Creating documents types...");
555 DocumentType.Properties tprop = new DocumentType.Properties();
556 Map<String, List<ProjectSettingsService.Step>> mapsteps = new HashMap<String, List<ProjectSettingsService.Step>>();
557 Map<String, ProjectSettingsService.Step> mapresult = new HashMap<String, ProjectSettingsService.Step>();
558 Map<String, DocumentType> maptype = new HashMap<String, DocumentType>();
560 List<ProjectSettingsService.Step> slist = null; // List of Steps to which each document type is valid
561 int snum = 0; // Step number
564 for (Iterator<NamedNodeMap> i = _flows.iterator(); i.hasNext(); snum++) {
565 NamedNodeMap flow = i.next();
566 ProjectSettingsService.Step step = _steps.get(snum);
567 String[] contents = flow.getNamedItem("contents").getNodeValue()
569 for (int j = 0; j < contents.length; j++) {
571 if (!_mapuse.containsKey(type)) {
572 LOG.warn("Undefined \"" + type + "\" document type.");
575 slist = mapsteps.get(type);
577 slist = new ArrayList<ProjectSettingsService.Step>();
580 mapsteps.put(type, slist);
582 Node result = flow.getNamedItem("result");
583 if (result != null) {
584 mapresult.put(result.getNodeValue(), step);
588 DocumentType tdoc = null;
589 Set<String> tset = _mapuse.keySet();
590 ProjectSettingsService.Step step;
591 for (Iterator<String> i = tset.iterator(); i.hasNext();) {
593 slist = mapsteps.get(type);
595 uses = _mapuse.get(type);
596 step = mapresult.get(type);
599 tprop.setName(type).setStep(
600 slist.toArray(new ProjectSettingsService.Step[slist
603 tdoc = maptype.get(uses);
605 LOG.warn("Undefined \"" + uses + "\" document type.");
611 tprop.setResult(step);
614 tprop.disableCheck();
615 tdoc = getDocumentTypeService().createType(tprop); // Creation of Document Types
616 getDocumentTypeService().approve(tdoc);
617 maptype.put(type, tdoc);
620 } catch (Exception error) {
621 LOG.warn("Error creating document types, reason:", error); // Should not happen
623 if (LOG.isDebugEnabled()) {
624 LOG.debug("Documents types are created: " + maptype.size());
629 * Create in the database knowledge types defined in the custom configuration.
631 private void createKnowledgeElementTypes() {
633 KnowledgeElementType ktype = getKnowledgeElementTypeService()
634 .createType("usecase"); // Internal reserved knowledge element type
635 getKnowledgeElementTypeService().reserve(ktype);
636 for (Iterator<String> i = _kname.iterator(); i.hasNext();) {
637 String type = i.next();
639 ktype = getKnowledgeElementTypeService().createType(type); // Knowledge Elements Types defined in the configuration
640 getKnowledgeElementTypeService().approve(ktype);
642 } catch (Exception error) {
643 LOG.warn("Error creating knowledge types, reason:", error); // Should not happen
648 * Create in the database simulation contexts types defined in the custom configuration.
650 private void createSimulationContextTypes() {
651 Map<String, ProjectSettingsService.Step> mapstep = new HashMap<String, ProjectSettingsService.Step>();
653 for (Iterator<NamedNodeMap> i = _sclass.iterator(); i.hasNext(); snum++) {
654 NamedNodeMap clatr = i.next();
656 String[] clist = clatr.getNamedItem("context").getNodeValue()
658 for (int j = 0; j < clist.length; j++) {
659 mapstep.put(clist[j], _steps.get(snum));
664 SimulationContextType tctex = null;
665 for (Iterator<String> i = _context.iterator(); i.hasNext();) {
666 String type = i.next();
667 if (mapstep.containsKey(type)) {
668 tctex = getSimulationContextTypeService().createType(type,
669 mapstep.get(type)); // Creation of Simulation Context Types
670 getSimulationContextTypeService().approve(tctex);
673 .warn("Could not find \""
675 + "\" classification. Simulation Context type ignored.");
678 } catch (Exception error) {
679 LOG.warn("Error creating context types, reason:", error); // Should not happen
686 * @return the database
688 public Database getDatabase() {
696 * the database to set
698 public void setDatabase(final Database database) {
699 _database = database;
703 * Get the simulationContextTypeService.
705 * @return the simulationContextTypeService
707 public SimulationContextTypeService getSimulationContextTypeService() {
708 return _simulationContextTypeService;
712 * Set the simulationContextTypeService.
714 * @param simulationContextTypeService
715 * the simulationContextTypeService to set
717 public void setSimulationContextTypeService(
718 final SimulationContextTypeService simulationContextTypeService) {
719 _simulationContextTypeService = simulationContextTypeService;
723 * Get the knowledgeElementTypeService.
725 * @return the knowledgeElementTypeService
727 public KnowledgeElementTypeService getKnowledgeElementTypeService() {
728 return _knowledgeElementTypeService;
732 * Set the knowledgeElementTypeService.
734 * @param knowledgeElementTypeService
735 * the knowledgeElementTypeService to set
737 public void setKnowledgeElementTypeService(
738 final KnowledgeElementTypeService knowledgeElementTypeService) {
739 _knowledgeElementTypeService = knowledgeElementTypeService;
743 * Get the documentTypeService.
745 * @return the documentTypeService
747 public DocumentTypeService getDocumentTypeService() {
748 return _documentTypeService;
752 * Set the documentTypeService.
754 * @param documentTypeService
755 * the documentTypeService to set
757 public void setDocumentTypeService(
758 final DocumentTypeService documentTypeService) {
759 _documentTypeService = documentTypeService;