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.NamedNodeMap;
41 import org.w3c.dom.Node;
42 import org.w3c.dom.NodeList;
45 * SIMAN configuration data service.
47 public class ProjectSettingsServiceImpl implements ProjectSettingsService {
50 * The logger for the service.
52 protected final static Logger LOG = Logger
53 .getLogger(ProjectSettingsServiceImpl.class);
55 // Non persistent configuration information
57 * Repository settings.
59 private transient final Properties _reprop = new Properties();
61 * Pattern of study references.
63 private transient String _pattern;
65 * Scheme of file names stored into the repository.
67 private transient FileNaming _naming;
69 * Pattern of the presentation of version numbers.
71 private transient String _versioning;
73 * Ordered list of (transient) study steps.
75 private transient final List<ProjectSettingsService.Step> _steps = new ArrayList<ProjectSettingsService.Step>();
77 * Configuration document validation cycles.
79 private transient List<ProjectSettingsValidationCycle> _concycles;
81 // Temporary attributes initialized from the configuration file for populating the database with object types
83 * Document type names and uses mapping.
85 private transient Map<String, String> _mapuse;
87 * Simulation Context type names.
89 private transient List<String> _context;
91 * Knowledge Element type names.
93 private transient List<String> _kname;
97 private transient List<NamedNodeMap> _flows;
99 * Study classifications.
101 private transient List<NamedNodeMap> _sclass;
105 * Database service to check its version, etc.
107 private Database _database;
109 * Injected simulation context type service.
111 private SimulationContextTypeService _simulationContextTypeService;
113 * Injected knowledge element type service.
115 private KnowledgeElementTypeService _knowledgeElementTypeService;
117 * Injected document type service.
119 private DocumentTypeService _documentTypeService;
121 public enum FileNaming {
126 * Validation cycle defined in the XML configuration.
128 public static class ProjectSettingsValidationCycle {
130 * Cycle (document) type name.
132 private final String _name;
134 * Array of cycle actors positions in the organization. TODO: Must be replaced by Roles.
136 private final Actor[] _actor;
139 * Default constructor.
141 private ProjectSettingsValidationCycle() {
142 this._name = "built-in";
143 this._actor = new Actor[] { null, null, null };
147 * Create a validation cycle definition for the given document type name and actors positions.
150 * the document type name
152 * the array of actors positions
154 private ProjectSettingsValidationCycle(final String name,
155 final Actor[] actor) {
161 * The processed document type name.
163 * @return the document type name
165 public String getName() {
170 * Get an array of cycle actors positions.
172 * @return the array of actors positions
173 * @see org.splat.dal.bo.som.ValidationCycle.Actor
175 public Actor[] getActorTypes() {
180 // ==============================================================================================================================
182 // ==============================================================================================================================
185 * Load workflow configuration from the given file. <br/> Create necessary default staff in the database if it is not initialized yet.
188 * the workflow configuration file
189 * @throws IOException
190 * if there is a file reading or index creation problem
191 * @throws SQLException
192 * if there is a database population problem
194 public void configure(final String filename) throws IOException,
196 if (!_steps.isEmpty()) {
197 return; // Project already configured
200 Database base = getDatabase().getCheckedDB();
201 File config = new File(filename);
202 if (config.exists()) {
203 loadCustomization(config);
205 LOG.fatal("Could not find the database configuration file \""
206 + config.getAbsolutePath() + "\"");
207 throw new FileNotFoundException();
209 base.configure(_reprop);
210 if (!base.isInitialized()) {
212 initialize(); // Populates the database with all necessary stuff
217 * Get ordered list of (transient) study steps.
219 * @return the list of steps from project settings
221 public List<ProjectSettingsService.Step> getAllSteps() {
226 * Return the validation cycles of result documents defined in the workflow, ordered by study activities and ending by the default
227 * validation cycle, if defined.
229 * @return the validation cycles of the workflow
231 public List<ProjectSettingsValidationCycle> getAllValidationCycles() {
236 * Get file naming scheme setting.
238 * @return file naming scheme
239 * @see org.splat.service.technical.ProjectSettingsServiceImpl.FileNaming
241 public FileNaming getFileNamingScheme() {
246 * Get a pattern of study references.
248 * @return the reference pattern
250 public String getReferencePattern() {
255 * Get a pattern of the presentation of version numbers.
257 * @return the version numbers presentation pattern
259 public String getRevisionPattern() {
264 * Get a study step by its sequential number.
270 public ProjectSettingsService.Step getStep(final int number) {
271 ProjectSettingsService.Step res = null;
272 for (int i = 0; i < _steps.size(); i++) {
273 ProjectSettingsService.Step step = _steps.get(i);
274 if (step.getNumber() == number) {
283 * Get steps of the given project element (study or scenario).
286 * the project element (study or scenario)
287 * @return the list of steps
289 public List<ProjectSettingsService.Step> getStepsOf(
290 final Class<? extends ProjectElement> level) {
291 List<ProjectSettingsService.Step> result = new ArrayList<ProjectSettingsService.Step>();
293 for (int i = 0; i < _steps.size(); i++) {
294 ProjectSettingsService.Step step = _steps.get(i);
295 if (step.appliesTo(level)) {
303 * Initialize the database: create all necessary default staff defined in the configuration file.
305 protected void initialize() {
306 createDocumentTypes();
307 createSimulationContextTypes();
308 createKnowledgeElementTypes();
311 // ==============================================================================================================================
312 // Private member function
313 // ==============================================================================================================================
316 * Read the configuration file and fill transient project settings fields.
319 * the configuration XML file
321 private void loadCustomization(final File config) {
323 DocumentBuilderFactory dfactory = javax.xml.parsers.DocumentBuilderFactory
325 DocumentBuilder dBuilder = dfactory.newDocumentBuilder();
327 org.w3c.dom.Document conf = dBuilder.parse(config.getPath());
328 HashMap<String, Node> children = XDOM.getNamedChildNodes(conf
329 .getDocumentElement());
331 // Repository tag initializing the reprop attribute
332 Node child = children.get("database");
333 HashMap<String, Node> datag = XDOM.getNamedChildNodes(child);
335 String disk = datag.get("repository").getAttributes().getNamedItem(
336 "disk").getNodeValue();
337 if (!disk.endsWith("/")) {
340 LOG.info("Database root set to " + disk);
341 _reprop.setProperty("repository", disk);
343 // Formats tag initializing the reference pattern and date attributes
344 child = children.get("formats");
345 datag = XDOM.getNamedChildNodes(child);
347 NamedNodeMap natr = datag.get("references").getAttributes();
348 _pattern = natr.getNamedItem("study").getNodeValue();
350 natr = datag.get("files").getAttributes();
351 _naming = FileNaming.valueOf(natr.getNamedItem("name")
354 natr = datag.get("versions").getAttributes();
355 _versioning = natr.getNamedItem("pattern").getNodeValue();
357 // Activities tag initializing the steps and rex attributes
358 child = children.get("activities");
359 NodeList nlist = child.getChildNodes();
360 List<NamedNodeMap> flist = new ArrayList<NamedNodeMap>();
361 List<String> resultype = new ArrayList<String>();
362 List<NamedNodeMap> clist = new ArrayList<NamedNodeMap>();
364 int snum = 1; // Base number of steps
365 for (int i = 0; i < nlist.getLength(); i++) {
366 child = nlist.item(i);
367 if (child.getNodeName().equals("scenario")) {
368 NodeList slist = child.getChildNodes();
369 for (int j = 0; j < slist.getLength(); j++) {
370 child = slist.item(j);
371 if (!child.getNodeName().equals("step")) {
374 HashMap<String, Node> tags = XDOM
375 .getNamedChildNodes(child);
377 natr = tags.get("storage").getAttributes();
378 ProjectSettingsService.Step step = new ProjectSettingsService.Step(
379 snum, Scenario.class, natr.getNamedItem("path")
382 // Keeping flow and classification information for eventual later use
383 natr = tags.get("flow").getAttributes();
385 child = natr.getNamedItem("result");
387 resultype.add(child.getNodeValue());
390 child = tags.get("classification");
394 clist.add(child.getAttributes());
397 if (natr.getNamedItem("contents").getNodeValue()
398 .equals("knowledge")) {
399 // TODO In a given scenario, only one step must contain knowledges
400 step._contents.add(KnowledgeElement.class);
402 step._contents.add(Document.class);
408 if (!child.getNodeName().equals("step")) {
411 HashMap<String, Node> tags = XDOM.getNamedChildNodes(child);
413 natr = tags.get("storage").getAttributes(); // Mandatory information
414 ProjectSettingsService.Step step = new ProjectSettingsService.Step(
415 snum, Study.class, natr.getNamedItem("path")
418 // Keeping flow and classification information for eventual later use
419 natr = tags.get("flow").getAttributes();
421 child = natr.getNamedItem("result");
423 resultype.add(child.getNodeValue());
426 child = tags.get("classification"); // Optional information
430 clist.add(child.getAttributes());
433 if (natr.getNamedItem("contents").getNodeValue().equals(
435 // TODO Error: knowledges must be attached to scenarios
436 LOG.error("Error: knowledges must be attached to scenarios.");
438 step._contents.add(Document.class);
445 child = children.get("validations");
446 _concycles = new ArrayList<ProjectSettingsValidationCycle>();
447 datag = XDOM.getNamedChildNodes(child);
449 String[] step = { "review", "approval", "acceptance" };
450 resultype.add("default");
451 for (Iterator<String> i = resultype.iterator(); i.hasNext();) {
452 Actor[] actor = { null, null, null };
453 String name = i.next();
454 child = datag.get(name);
456 continue; // Document type not subject of any validation
458 natr = child.getAttributes();
459 for (int j = 0; j < step.length; j++) {
460 child = natr.getNamedItem(step[j]);
462 continue; // Validation step not required
464 actor[j] = Actor.valueOf(child.getNodeValue());
466 _concycles.add(new ProjectSettingsValidationCycle(name, actor));
468 _concycles.add(new ProjectSettingsValidationCycle()); // Adds the built-in validation cycle
470 if (getDatabase().getCheckedDB().isInitialized()) {
471 return; // No need to load object type definitions as they are already stored
475 child = children.get("documents");
476 nlist = child.getChildNodes();
478 _flows = flist; // Kept for later use in document type definition
479 _sclass = clist; // Kept for later use in simulation context type definition
480 _mapuse = new LinkedHashMap<String, String>();
481 for (int i = 0; i < nlist.getLength(); i++) {
482 child = nlist.item(i);
483 if (!child.getNodeName().equals("article")) {
487 natr = child.getAttributes();
488 String type = natr.getNamedItem("type").getNodeValue();
490 child = natr.getNamedItem("uses");
492 uses = child.getNodeValue();
494 _mapuse.put(type, uses); // Must be added to the map even if no (null) uses
496 // Simulation Contexts tag
497 child = children.get("contexts");
498 nlist = child.getChildNodes();
500 _context = new ArrayList<String>();
501 for (int i = 0; i < nlist.getLength(); i++) {
502 child = nlist.item(i);
503 if (!child.getNodeName().equals("article")) {
507 _context.add(child.getAttributes().getNamedItem("type")
510 // Knowledge Elements tag
511 child = children.get("knowledges");
512 nlist = child.getChildNodes();
514 _kname = new ArrayList<String>();
515 for (int i = 0; i < nlist.getLength(); i++) {
516 child = nlist.item(i);
517 if (!child.getNodeName().equals("article")) {
521 _kname.add(child.getAttributes().getNamedItem("type")
524 } catch (Exception error) {
525 LOG.info("Error in customization", error);
530 * Create in the database document types defined in the custom configuration.
532 private void createDocumentTypes() {
533 DocumentType.Properties tprop = new DocumentType.Properties();
534 Map<String, List<ProjectSettingsService.Step>> mapsteps = new HashMap<String, List<ProjectSettingsService.Step>>();
535 Map<String, ProjectSettingsService.Step> mapresult = new HashMap<String, ProjectSettingsService.Step>();
536 Map<String, DocumentType> maptype = new HashMap<String, DocumentType>();
538 List<ProjectSettingsService.Step> slist = null; // List of Steps to which each document type is valid
539 int snum = 0; // Step number
542 for (Iterator<NamedNodeMap> i = _flows.iterator(); i.hasNext(); snum++) {
543 NamedNodeMap flow = i.next();
544 ProjectSettingsService.Step step = _steps.get(snum);
545 String[] contents = flow.getNamedItem("contents").getNodeValue()
547 for (int j = 0; j < contents.length; j++) {
549 if (!_mapuse.containsKey(type)) {
550 LOG.warn("Undefined \"" + type + "\" document type.");
553 slist = mapsteps.get(type);
555 slist = new ArrayList<ProjectSettingsService.Step>();
558 mapsteps.put(type, slist);
560 Node result = flow.getNamedItem("result");
561 if (result != null) {
562 mapresult.put(result.getNodeValue(), step);
566 DocumentType tdoc = null;
567 Set<String> tset = _mapuse.keySet();
568 ProjectSettingsService.Step step;
569 for (Iterator<String> i = tset.iterator(); i.hasNext();) {
571 slist = mapsteps.get(type);
572 uses = _mapuse.get(type);
573 step = mapresult.get(type);
576 tprop.setName(type).setStep(
577 slist.toArray(new ProjectSettingsService.Step[slist
580 tdoc = maptype.get(uses);
583 .warn("Undefined \"" + uses
584 + "\" document type.");
590 tprop.setResult(step);
593 tprop.disableCheck();
594 tdoc = getDocumentTypeService().createType(tprop); // Creation of Document Types
595 getDocumentTypeService().approve(tdoc);
596 maptype.put(type, tdoc);
598 } catch (Exception error) {
599 LOG.warn("Error creating document types, reason:", error); // Should not happen
604 * Create in the database knowledge types defined in the custom configuration.
606 private void createKnowledgeElementTypes() {
608 KnowledgeElementType ktype = getKnowledgeElementTypeService()
609 .createType("usecase"); // Internal reserved knowledge element type
610 getKnowledgeElementTypeService().reserve(ktype);
611 for (Iterator<String> i = _kname.iterator(); i.hasNext();) {
612 String type = i.next();
614 ktype = getKnowledgeElementTypeService().createType(type); // Knowledge Elements Types defined in the configuration
615 getKnowledgeElementTypeService().approve(ktype);
617 } catch (Exception error) {
618 LOG.warn("Error creating knowledge types, reason:", error); // Should not happen
623 * Create in the database simulation contexts types defined in the custom configuration.
625 private void createSimulationContextTypes() {
626 Map<String, ProjectSettingsService.Step> mapstep = new HashMap<String, ProjectSettingsService.Step>();
628 for (Iterator<NamedNodeMap> i = _sclass.iterator(); i.hasNext(); snum++) {
629 NamedNodeMap clatr = i.next();
634 String[] clist = clatr.getNamedItem("context").getNodeValue()
636 for (int j = 0; j < clist.length; j++) {
637 mapstep.put(clist[j], _steps.get(snum));
641 SimulationContextType tctex = null;
642 for (Iterator<String> i = _context.iterator(); i.hasNext();) {
643 String type = i.next();
644 if (!mapstep.containsKey(type)) {
646 .warn("Could not find \""
648 + "\" classification. Simulation Context type ignored.");
651 tctex = getSimulationContextTypeService().createType(type,
652 mapstep.get(type)); // Creation of Simulation Context Types
653 getSimulationContextTypeService().approve(tctex);
655 } catch (Exception error) {
656 LOG.warn("Error creating context types, reason:", error); // Should not happen
663 * @return the database
665 public Database getDatabase() {
673 * the database to set
675 public void setDatabase(final Database database) {
676 _database = database;
680 * Get the simulationContextTypeService.
682 * @return the simulationContextTypeService
684 public SimulationContextTypeService getSimulationContextTypeService() {
685 return _simulationContextTypeService;
689 * Set the simulationContextTypeService.
691 * @param simulationContextTypeService
692 * the simulationContextTypeService to set
694 public void setSimulationContextTypeService(
695 final SimulationContextTypeService simulationContextTypeService) {
696 _simulationContextTypeService = simulationContextTypeService;
700 * Get the knowledgeElementTypeService.
702 * @return the knowledgeElementTypeService
704 public KnowledgeElementTypeService getKnowledgeElementTypeService() {
705 return _knowledgeElementTypeService;
709 * Set the knowledgeElementTypeService.
711 * @param knowledgeElementTypeService
712 * the knowledgeElementTypeService to set
714 public void setKnowledgeElementTypeService(
715 final KnowledgeElementTypeService knowledgeElementTypeService) {
716 _knowledgeElementTypeService = knowledgeElementTypeService;
720 * Get the documentTypeService.
722 * @return the documentTypeService
724 public DocumentTypeService getDocumentTypeService() {
725 return _documentTypeService;
729 * Set the documentTypeService.
731 * @param documentTypeService
732 * the documentTypeService to set
734 public void setDocumentTypeService(
735 final DocumentTypeService documentTypeService) {
736 _documentTypeService = documentTypeService;