Salome HOME
The method createStudy from Python is marked as Transactional in ScenarioService.
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / ScenarioServiceImpl.java
1 /*****************************************************************************
2  * Company         OPEN CASCADE
3  * Application     SIMAN
4  * File            $Id$ 
5  * Creation date   06.10.2012
6  * @author         $Author$
7  * @version        $Revision$
8  *****************************************************************************/
9
10 package org.splat.service;
11
12 import java.io.IOException;
13 import java.util.ArrayList;
14 import java.util.Calendar;
15 import java.util.Date;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
19 import java.util.Map;
20 import java.util.Set;
21
22 import org.hibernate.criterion.Order;
23 import org.hibernate.criterion.Restrictions;
24 import org.splat.common.properties.MessageKeyEnum;
25 import org.splat.dal.bo.kernel.Relation;
26 import org.splat.dal.bo.kernel.Role;
27 import org.splat.dal.bo.kernel.User;
28 import org.splat.dal.bo.som.ConvertsRelation;
29 import org.splat.dal.bo.som.Document;
30 import org.splat.dal.bo.som.DocumentType;
31 import org.splat.dal.bo.som.File;
32 import org.splat.dal.bo.som.KnowledgeElement;
33 import org.splat.dal.bo.som.KnowledgeElementType;
34 import org.splat.dal.bo.som.ProgressState;
35 import org.splat.dal.bo.som.Publication;
36 import org.splat.dal.bo.som.Scenario;
37 import org.splat.dal.bo.som.SimulationContext;
38 import org.splat.dal.bo.som.SimulationContextType;
39 import org.splat.dal.bo.som.Study;
40 import org.splat.dal.bo.som.UsedByRelation;
41 import org.splat.dal.bo.som.UsesRelation;
42 import org.splat.dal.bo.som.Document.Properties;
43 import org.splat.dal.dao.kernel.RoleDAO;
44 import org.splat.dal.dao.kernel.UserDAO;
45 import org.splat.dal.dao.som.KnowledgeElementDAO;
46 import org.splat.dal.dao.som.KnowledgeElementTypeDAO;
47 import org.splat.dal.dao.som.ScenarioDAO;
48 import org.splat.dal.dao.som.StudyDAO;
49 import org.splat.i18n.I18nUtils;
50 import org.splat.kernel.InvalidPropertyException;
51 import org.splat.kernel.MismatchException;
52 import org.splat.kernel.MissedPropertyException;
53 import org.splat.kernel.MultiplyDefinedException;
54 import org.splat.kernel.NotApplicableException;
55 import org.splat.log.AppLogger;
56 import org.splat.service.dto.DocumentDTO;
57 import org.splat.service.dto.FileDTO;
58 import org.splat.service.dto.StepDTO;
59 import org.splat.service.technical.IndexService;
60 import org.splat.service.technical.ProjectSettingsService;
61 import org.splat.som.Step;
62 import org.splat.util.BeanHelper;
63 import org.springframework.transaction.annotation.Transactional;
64
65 /**
66  * Scenario service implementation.
67  * 
68  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
69  */
70 public class ScenarioServiceImpl implements ScenarioService {
71
72         /**
73          * The logger for the service.
74          */
75         public final static AppLogger LOG = AppLogger
76                         .getLogger(ScenarioServiceImpl.class);
77
78         /**
79          * Injected index service.
80          */
81         private IndexService _indexService;
82         /**
83          * Injected step service.
84          */
85         private StepService _stepService;
86         /**
87          * Injected study service.
88          */
89         private StudyService _studyService;
90         /**
91          * Injected publication service.
92          */
93         private PublicationService _publicationService;
94         /**
95          * Injected project element service.
96          */
97         private ProjectElementService _projectElementService;
98         /**
99          * Injected knowledge element DAO.
100          */
101         private KnowledgeElementDAO _knowledgeElementDAO;
102         /**
103          * Injected scenario DAO.
104          */
105         private ScenarioDAO _scenarioDAO;
106
107         /**
108          * Injected study DAO.
109          */
110         private StudyDAO _studyDAO;
111
112         /**
113          * Injected knowledge element service.
114          */
115         private KnowledgeElementTypeService _knowledgeElementTypeService;
116
117         /**
118          * Injected user service.
119          */
120         private UserService _userService;
121
122         /**
123          * Injected user DAO.
124          */
125         private UserDAO _userDAO;
126
127         /**
128          * Injected role DAO.
129          */
130         private RoleDAO _roleDAO;
131
132         /**
133          * Injected knowledge element type DAO.
134          */
135         private KnowledgeElementTypeDAO _knowledgeElementTypeDAO;
136
137         /**
138          * Injected simulation context service.
139          */
140         private SimulationContextService _simulationContextService;
141
142         /**
143          * Injected project service.
144          */
145         private ProjectSettingsService _projectSettings;
146
147         /**
148          * Injected document type service.
149          */
150         private DocumentTypeService _documentTypeService;
151
152         /**
153          * Get the projectElementService.
154          * 
155          * @return the projectElementService
156          */
157         public ProjectElementService getProjectElementService() {
158                 return _projectElementService;
159         }
160
161         /**
162          * Set the projectElementService.
163          * 
164          * @param projectElementService
165          *            the projectElementService to set
166          */
167         public void setProjectElementService(
168                         final ProjectElementService projectElementService) {
169                 _projectElementService = projectElementService;
170         }
171
172         /**
173          * Get the publicationService.
174          * 
175          * @return the publicationService
176          */
177         public PublicationService getPublicationService() {
178                 return _publicationService;
179         }
180
181         /**
182          * Set the publicationService.
183          * 
184          * @param publicationService
185          *            the publicationService to set
186          */
187         public void setPublicationService(
188                         final PublicationService publicationService) {
189                 _publicationService = publicationService;
190         }
191
192         /**
193          * Get the stepService.
194          * 
195          * @return the stepService
196          */
197         public StepService getStepService() {
198                 return _stepService;
199         }
200
201         /**
202          * Set the stepService.
203          * 
204          * @param stepService
205          *            the stepService to set
206          */
207         public void setStepService(final StepService stepService) {
208                 _stepService = stepService;
209         }
210
211         /**
212          * {@inheritDoc}
213          * 
214          * @see org.splat.service.ScenarioService#getScenarioInfo(long)
215          */
216         @Transactional(readOnly = true)
217         public List<StepDTO> getScenarioInfo(final long scenarioId) {
218                 List<StepDTO> res = new ArrayList<StepDTO>();
219                 // Get the scenario from the database by id
220                 Scenario scen = getScenarioDAO().get(scenarioId);
221                 if (LOG.isDebugEnabled()) {
222                         LOG.debug("Scenario[" + scenarioId + "]: Number of publications: "
223                                         + scen.getDocums().size());
224                 }
225                 // Get activities of the scenario
226                 Step[] steps = getProjectElementService().getSteps(scen);
227                 StepDTO stepDTO;
228                 DocumentDTO docDTO;
229                 String docType, fileFormat;
230                 String processing;
231                 boolean doImport;
232                 // For each activity create a step DTO and add it to the result list
233                 for (Step step : steps) {
234                         stepDTO = BeanHelper.copyBean(step.getStep(), StepDTO.class);
235                         res.add(stepDTO);
236                         if (LOG.isDebugEnabled()) {
237                                 LOG.debug("Step[" + stepDTO.getNumber()
238                                                 + "]: Number of documents: "
239                                                 + step.getDocuments().size());
240                         }
241                         // For each publication of the activity create a document DTO.
242                         // Each file is considered as a source file.
243                         for (Publication tag : step.getDocuments()) {
244                                 docDTO = stepDTO.addDoc(tag.value().getIndex(), tag.value()
245                                                 .getTitle());
246                                 char aState = tag.getIsnew();
247                                 docType = tag.value().getType().getName();
248                                 // For each file of the document create a file DTO
249                                 // Process source file of the document
250                                 fileFormat = tag.value().getFile().getFormat();
251                                 doImport = getProjectSettings().doImport(docType, fileFormat);
252                                 if (doImport && (!tag.isOutdated())) {
253                                         processing = "file-import";
254                                 } else {
255                                         processing = "file-download";
256                                 }
257                                 File aFile = tag.value().getFile();
258                                 docDTO.addFile(aFile.getIndex(), aFile.getRelativePath(),
259                                                 aState, processing, false);
260                                 // Process all exported files
261                                 for (Relation rel : tag.value().getRelations(
262                                                 ConvertsRelation.class)) {
263                                         aFile = ((ConvertsRelation) rel).getTo();
264                                         fileFormat = aFile.getFormat();
265                                         doImport = getProjectSettings().doImport(docType,
266                                                         fileFormat);
267                                         if (doImport && (!tag.isOutdated())) {
268                                                 processing = "file-import";
269                                         } else {
270                                                 processing = "file-download";
271                                         }
272                                         docDTO.addFile(aFile.getIndex(), aFile.getRelativePath(),
273                                                         aState, processing, false);
274                                 }
275                         }
276                 }
277                 return res;
278         }
279
280         /**
281          * {@inheritDoc}
282          * 
283          * @see org.splat.service.ScenarioService#createStudy(java.lang.String, java.lang.String, java.lang.String, java.lang.String)
284          */
285         @Transactional
286         public long createStudy(final String username, final String title,
287                         final String productName, final String description)
288                         throws InvalidPropertyException, MissedPropertyException,
289                         MultiplyDefinedException {
290                 long id = 0;
291
292                 // Find the author
293                 User author = getUserService().selectUser(username);
294                 if (author == null) {
295                         // User is not found
296                         throw new InvalidPropertyException(MessageKeyEnum.USR_000001
297                                         .toString(), username);
298                 }
299
300                 // Set the study properties
301                 Study.Properties sprop = new Study.Properties();
302                 sprop.setTitle(title).setManager(author);
303                 sprop.setDescription(description);
304
305                 // Find the product simulation context
306                 SimulationContextType productContextType = getSimulationContextService()
307                                 .selectType("product");
308                 SimulationContext.Properties cprop = new SimulationContext.Properties();
309                 cprop.setType(productContextType).setValue(productName);
310                 SimulationContext productCtx = getSimulationContextService()
311                                 .selectSimulationContext(productContextType, productName);
312                 if (productCtx != null) {
313                         cprop.setIndex(productCtx.getIndex());
314                 }
315
316                 // Set a first scenario properties
317                 Scenario.Properties oprop = new Scenario.Properties();
318                 oprop.setTitle(I18nUtils.getMessageLocaleDefault("label.scenario")
319                                 + " 1");
320
321                 Study study = createStudy(sprop, oprop, cprop);
322                 id = study.getIndex();
323
324                 return id;
325         }
326
327         /**
328          * Create a new study with one scenario and "product" simulation context.
329          * 
330          * @param sprop
331          *            the study properties
332          * @param oprop
333          *            the scenario properties
334          * @param cprop
335          *            the "product" simulation context properties
336          * @return the created study
337          * @throws MissedPropertyException
338          *             if a mandatory property is missed
339          * @throws InvalidPropertyException
340          *             if a property is invalid
341          * @throws MultiplyDefinedException
342          *             if some property occurs several times
343          */
344         @Transactional
345         public Study createStudy(final Study.Properties sprop,
346                         final Scenario.Properties oprop,
347                         final SimulationContext.Properties cprop)
348                         throws MissedPropertyException, InvalidPropertyException,
349                         MultiplyDefinedException {
350                 Study study = getStudyService().createStudy(sprop);
351                 addScenario(study, oprop);
352                 if (cprop.getIndex() == 0) { // Input of new project context
353                         cprop.setType(getSimulationContextService().selectType("product"))
354                                         .setValue(cprop.getValue());
355                         getStudyService().addProjectContext(study, cprop);
356                 } else { // Selection of existing project context
357                         SimulationContext context = getSimulationContextService()
358                                         .selectSimulationContext(cprop.getIndex());
359                         getStudyService().addProjectContext(study, context);
360                 }
361                 return study;
362         }
363
364         /**
365          * {@inheritDoc}
366          * 
367          * @see org.splat.service.ScenarioService#addKnowledgeElement(org.splat.dal.bo.som.Scenario,
368          *      org.splat.dal.bo.som.KnowledgeElement.Properties)
369          */
370         @Transactional
371         public KnowledgeElement addKnowledgeElement(final Scenario aScenarioDTO,
372                         final KnowledgeElement.Properties kprop)
373                         throws MissedPropertyException, InvalidPropertyException,
374                         MultiplyDefinedException {
375                 KnowledgeElement kelm = null;
376                 // try {
377                 long aScenarioId = aScenarioDTO.getIndex();
378                 if (LOG.isDebugEnabled()) {
379                         LOG
380                                         .debug("Add a knowledge element to the scenario #"
381                                                         + aScenarioId);
382                 }
383                 // Get the persistent scenario.
384                 Scenario aScenario = getScenarioDAO().get(aScenarioId);
385                 // Get persistent objects for creating a new knowledge.
386                 // TODO: Actions must use DTO instead of persistent objects.
387                 getUserDAO().merge(kprop.getAuthor());
388                 getKnowledgeElementTypeDAO().merge(kprop.getType());
389                 // Create a transient knowledge element related to the given scenario.
390                 kelm = new KnowledgeElement(kprop.setOwnerScenario(aScenario));
391                 // Save the new knowledge in the database.
392                 getKnowledgeElementDAO().create(kelm);
393                 // Update scenario transient data.
394                 if (kelm.getType().equals("usecase")) {
395                         aScenarioDTO.setUcase(kelm);
396                 } else if (aScenarioDTO.getKnowledgeElementsList() != null) { // If null, knowl will be initialized when needed
397                         aScenarioDTO.getKnowledgeElementsList().add(kelm);
398                 }
399
400                 // Load the workflow for the parent study to take into account
401                 // all study actors durng reindexing.
402                 getStudyService().loadWorkflow(aScenario.getOwnerStudy());
403
404                 // // Update the lucene index of knowledge elements.
405                 // getIndexService().add(kelm);
406                 if (LOG.isDebugEnabled()) {
407                         LOG.debug("A knowledge element #" + kelm.getIndex()
408                                         + " is added to the scenario #" + aScenario.getIndex());
409                 }
410                 // } catch (IOException error) {
411                 // LOG.error("Unable to index the knowedge element '"
412                 // + kelm.getIndex() + "', reason:", error);
413                 // kelm = null;
414                 // }
415
416                 return kelm;
417         }
418
419         /**
420          * Update the scenario in the database.
421          * 
422          * @param aScenario
423          *            the scenario to update
424          * @return true if updating succeeded
425          */
426         @Transactional
427         private boolean update(final Scenario aScenario) {
428                 boolean isOk = false;
429                 try {
430                         getScenarioDAO().update(aScenario); // Update of relational base
431                         isOk = true;
432                 } catch (Exception error) {
433                         LOG.error("Unable to re-index the knowledge element '"
434                                         + aScenario.getIndex() + "', reason:", error);
435                 }
436                 return isOk;
437         }
438
439         /**
440          * {@inheritDoc}
441          * 
442          * @see org.splat.service.ScenarioService#checkin(long, long, java.util.List)
443          */
444         @Transactional
445         public void checkin(final long scenId, final long userId,
446                         final List<StepDTO> scInfo) throws InvalidPropertyException,
447                         MissedPropertyException, MultiplyDefinedException,
448                         MismatchException, IOException, NotApplicableException {
449                 // Get the scenario from the database by id
450                 Scenario aScenario = getScenarioDAO().get(scenId);
451                 // Get the user who perform this check-in operation
452                 User aUser = getUserService().selectUser(userId);
453                 // Get activities of the scenario
454                 Step[] steps = getProjectElementService().getSteps(aScenario);
455                 // Find result document types
456                 List<DocumentType> resTypes = getDocumentTypeService()
457                                 .selectResultTypes();
458
459                 // Keep newly created documents to create uses relations to results of a previous step.
460                 // For each processed existing document keep its new version
461                 Map<Document, Document> newVersion = new HashMap<Document, Document>();
462                 // Created publications of new created versions of existing documents
463                 List<Publication> newVers = new ArrayList<Publication>();
464                 // The list of publications of new created documents not existing before the checkin
465                 List<Publication> newDocs = new ArrayList<Publication>();
466                 // For each step DTO
467                 DocumentType resType;
468                 Date aDate = new Date(); // The timestamp of the checkin operation
469                 for (StepDTO stepDTO : scInfo) {
470                         if (LOG.isDebugEnabled()) {
471                                 LOG.debug("Checkin the step:\n" + stepDTO);
472                         }
473                         // Find a result document type of the step
474                         int i = 0;
475                         resType = null;
476                         do {
477                                 if (resTypes.get(i).isResultOf(
478                                                 getProjectSettings().getStep(stepDTO.getNumber()))) {
479                                         resType = resTypes.get(i);
480                                 }
481                                 i++;
482                         } while ((resType == null) && (i < resTypes.size()));
483
484                         // Find the appropriate scenario step
485                         Step step = findStep(stepDTO, steps);
486
487                         // Process each document of the step
488                         for (DocumentDTO doc : stepDTO.getDocs()) {
489                                 checkinDoc(step, doc, aUser, resType, aDate, newVersion,
490                                                 newVers, newDocs);
491                         }
492                 }
493
494                 // Set uses/used relations
495                 updateRelationsAfterCheckin(aScenario, newVersion, newVers, newDocs);
496
497                 // Mark the scenario as checked in
498                 checkin(aScenario);
499         }
500
501         /**
502          * Updated uses/used relations after checkin operation:<BR>
503          * <ul>
504          * <li>For each new version copy uses relations from the previous version.</li>
505          * <li>Outdate documents which depend from the previous version and were not checked in during this operation.</li>
506          * <li>For each new document create uses relation to the last versions of results of the previous step.</li>
507          * </ul>
508          * 
509          * @param aScenario
510          *            the checked in scenario
511          * @param newVersion
512          *            the mapping of documents existed before the checkin to their new created versions
513          * @param newVers
514          *            the list of publications of new created versions of documents existed before the checkin
515          * @param newDocs
516          *            the list of publications of new created documents not existed before the checkin
517          */
518         private void updateRelationsAfterCheckin(final Scenario aScenario,
519                         final Map<Document, Document> newVersion,
520                         final List<Publication> newVers, final List<Publication> newDocs) {
521                 // For each new version copy uses relations from the previous version.
522                 for (Publication newVer : newVers) {
523                         // For each Uses relation of the previous version
524                         Document prevDoc = newVer.value().getPreviousVersion();// prevVersion.get(newVer);
525                         if (LOG.isDebugEnabled()) {
526                                 LOG.debug("Previous version for publication #"
527                                                 + newVer.getIndex() + " is found: " + prevDoc);
528                         }
529                         List<Relation> usesRelations = prevDoc
530                                         .getRelations(UsesRelation.class);
531                         for (Relation rel : usesRelations) {
532                                 // If used document has been also versioned then refer to its new version.
533                                 Document usedDoc = ((UsesRelation) rel).getTo();
534                                 if (newVersion.containsKey(usedDoc)) {
535                                         usedDoc = newVersion.get(usedDoc);
536                                 }
537                                 // Build the appropriate relation for the new version.
538                                 newVer.addDependency(usedDoc);
539                         }
540                         // Outdate documents which depend from the previous version and
541                         // were not checked in during this operation.
542                         // 1. Get all usedBy relations of the previous document version
543                         for (Relation rel : prevDoc.getRelations(UsedByRelation.class)) {
544                                 Document using = ((UsedByRelation) rel).getTo();
545                                 // Check that not checked in dependent documents became outdated
546                                 Publication usingPub = aScenario.getPublication(using);
547                                 if (usingPub != null) { // if the document using the old version is still published
548                                         usingPub.setIsnew('O');
549                                 }
550                         }
551                 }
552
553                 // For each new document create uses relation to the last versions of
554                 // results of the previous step.
555                 for (Publication newPub : newDocs) {
556                         // Find used document type according to the configuration.
557                         Set<DocumentType> usedTypes = newPub.value().getType()
558                                         .getDefaultUses();
559                         // Find documents of used type in the previous study step.
560                         for (Publication pub : aScenario.getDocums()) {
561                                 if ((pub.getStep().getNumber() <= newPub.getStep().getNumber())
562                                                 && (!pub.isOutdated())
563                                                 && usedTypes.contains(pub.value().getType())) {
564                                         // Create uses relation from the new document
565                                         // to the found document in the previous step.
566                                         newPub.addDependency(pub);
567                                 }
568                         }
569                 }
570         }
571
572         /**
573          * Pure checkin of the document without creation of uses/usedBy relations. For an existing document a new version is created. New
574          * documents become published in the given step of the appropriate scenario. The appropriate uploaded file is attached to the created
575          * document and the document is published in the scenario. The publication of the old version is removed from the scenario.
576          * 
577          * @param step
578          *            the destination scenario step
579          * @param doc
580          *            the DTO of the document to checkin
581          * @param aUser
582          *            the user who performs checkin
583          * @param resType
584          *            the result document type of the given step
585          * @param aDate
586          *            timestamp of the checkin operation
587          * @param newVersion
588          *            the mapping of existing documents to their new created versions
589          * @param newVers
590          *            the list of publications of new created versions of existing documents
591          * @param newDocs
592          *            the list of publications of new created documents not existing before the checkin
593          * @throws InvalidPropertyException
594          *             if the scenario hasn't some of given steps or documents
595          * @throws IOException
596          *             if a file can't be moved into the vault
597          * @throws MismatchException
598          *             if version creation in some of steps is failed
599          * @throws MissedPropertyException
600          *             if some mandatory property is missed when new document or new document version is created
601          * @throws MultiplyDefinedException
602          *             if some property is defined several times when new document or new document version is created
603          * @throws NotApplicableException
604          *             if failed saving of a new publication with a given state
605          */
606         private void checkinDoc(final Step step, final DocumentDTO doc,
607                         final User aUser, final DocumentType resType, final Date aDate,
608                         final Map<Document, Document> newVersion,
609                         final List<Publication> newVers, final List<Publication> newDocs)
610                         throws InvalidPropertyException, MismatchException,
611                         MissedPropertyException, MultiplyDefinedException, IOException,
612                         NotApplicableException {
613                 if (doc.getFiles().size() > 0) {
614                         Document.Properties dprop = new Document.Properties();
615                         // NOTE: Process only the first attached file for each document
616                         FileDTO file = doc.getFiles().get(0);
617                         dprop.setLocalPath(file.getPath());
618
619                         // Get document title as the file name
620                         java.io.File upfile = new java.io.File(file.getPath());
621                         String fileFormat = upfile.getName().substring(
622                                         upfile.getName().lastIndexOf('.') + 1);
623
624                         // Attach the file via ConvertsRelation, create a new document or
625                         // create a new version of the document
626                         dprop.setAuthor(aUser).setDate(aDate).setFormat(fileFormat);
627
628                         if (doc.getId() > 0) {
629                                 checkinExistingDoc(step, doc, dprop, fileFormat, upfile,
630                                                 newVersion, newVers);
631                         } else {
632
633                                 // Otherwise create a new document of the result type
634                                 // If result type is not found try to get type by file extension
635                                 if (resType == null) {
636                                         dprop.setType(getProjectSettings().getDefaultDocumentType(
637                                                         step.getStep(), fileFormat));
638                                 } else {
639                                         dprop.setType(resType);
640                                 }
641                                 // New document title generation as <document type name>_N
642                                 String docname = dprop.getType().getName();
643                                 int i = 1;
644                                 for (Publication scenPub : step.getOwner().getDocums()) {
645                                         if (scenPub.value().getTitle().startsWith(docname)) {
646                                                 i++;
647                                         }
648                                 }
649                                 docname += "_" + i; // The generated new document title
650
651                                 dprop.setDescription("Checked in").setName(docname);
652                                 Publication newPub = getStepService().createDocument(step,
653                                                 dprop);
654
655                                 // Remeber the new document
656                                 newDocs.add(newPub);
657
658                                 saveFile(newPub, step, upfile);
659                         }
660                 }
661         }
662
663         /**
664          * Check in existing document.
665          * 
666          * @param step
667          *            study step to check in
668          * @param doc
669          *            document DTO to check in
670          * @param dprop
671          *            document properties
672          * @param fileFormat
673          *            checked in file format
674          * @param upfile
675          *            the file to check in
676          * @param newVersion
677          *            the map of created versions during this check in
678          * @param newVers
679          *            the list of new versions created during this check in
680          * @throws InvalidPropertyException
681          *             if publication of the document is not found in the step
682          * @throws MismatchException
683          *             if the found publication does not point to a document
684          * @throws IOException
685          *             if can not move the file into the vault
686          * @throws MultiplyDefinedException
687          *             thrown by versionDocument
688          * @throws MissedPropertyException
689          *             thrown by versionDocument
690          * @throws NotApplicableException
691          *             if failed saving of a new publication with a given state
692          */
693         private void checkinExistingDoc(final Step step, final DocumentDTO doc,
694                         final Properties dprop, final String fileFormat,
695                         final java.io.File upfile,
696                         final Map<Document, Document> newVersion,
697                         final List<Publication> newVers) throws InvalidPropertyException,
698                         MismatchException, MissedPropertyException,
699                         MultiplyDefinedException, IOException, NotApplicableException {
700                 // If the document already exists then
701                 // Attach the file via ConvertsRelation if the extension of the
702                 // new file differs from the old one.
703                 // If file format (i.e. extension) is the same then create a new
704                 // version of the document.
705                 // Find the document publication
706                 Publication pub = step.getDocument(doc.getId());
707                 if (pub == null) {
708                         throw new InvalidPropertyException(MessageKeyEnum.SCN_000002
709                                         .toString(), doc.getId());
710                 }
711                 if (pub.value() == null) {
712                         throw new MismatchException(MessageKeyEnum.SCN_000002.toString(),
713                                         doc.getId());
714                 }
715                 if (LOG.isDebugEnabled()) {
716                         LOG.debug("Old format: " + pub.value().getFormat()
717                                         + " => New format: " + fileFormat);
718                 }
719                 // If formats are same then create a new document version
720                 if (pub.value().getFormat() != null
721                                 && pub.value().getFormat().equals(fileFormat)) {
722                         Publication newPub = getStepService().versionDocument(step, pub,
723                                         dprop);
724                         if (LOG.isDebugEnabled()) {
725                                 LOG.debug("Created document type: "
726                                                 + newPub.value().getType().getName() + ", format: "
727                                                 + newPub.value().getFormat());
728                         }
729                         // Remeber the link from the old document to the new document version
730                         newVersion.put(pub.value(), newPub.value());
731                         // Remember the new version publication
732                         newVers.add(newPub);
733
734                         saveFile(newPub, step, upfile);
735
736                 } else { // If formats are different then attach the new file via ConvertsRelation
737                         File attach = pub.value().getAttachedFile(fileFormat);
738                         if (attach == null) {
739                                 // If there is no attachment with this extension then attach the new one
740                                 ConvertsRelation export = getPublicationService().attach(pub,
741                                                 fileFormat);
742                                 if (LOG.isDebugEnabled()) {
743                                         LOG.debug("Moving " + upfile.getName() + " to "
744                                                         + export.getTo().asFile().getPath());
745                                 }
746                                 upfile.renameTo(export.getTo().asFile());
747                         } else {
748                                 // If an attachment with this extension already exists then
749                                 // replace it by the new one
750                                 upfile.renameTo(attach.asFile());
751                                 // Update attached file modification date
752                                 attach.setDate(new Date());
753                         }
754                 }
755         }
756
757         /**
758          * Save the file in the vault and create its publication in the step.
759          * 
760          * @param newPub
761          *            the new publication to save
762          * @param step
763          *            the study step to publish the document
764          * @param upfile
765          *            the downloaded file
766          * @throws IOException
767          *             if a file can't be moved into the vault
768          * @throws NotApplicableException
769          *             if failed saving of a new publication with a given state
770          */
771         private void saveFile(final Publication newPub, final Step step,
772                         final java.io.File upfile) throws IOException,
773                         NotApplicableException {
774                 // Attach the file to the created document
775                 java.io.File updir = newPub.getSourceFile().asFile();
776                 if (LOG.isDebugEnabled()) {
777                         LOG.debug("Moving \"" + upfile.getName() + "\" to \""
778                                         + updir.getPath() + "\".");
779                 }
780                 if (updir.exists()) {
781                         if (updir.delete()) {
782                                 LOG.info(MessageKeyEnum.SCN_000003.toString(), updir
783                                                 .getAbsoluteFile(), step.getOwner().getIndex());
784                         } else {
785                                 throw new IOException(
786                                                 "Can't delete the existing destination file to move file from "
787                                                                 + upfile.getAbsolutePath() + " to "
788                                                                 + updir.getAbsolutePath());
789                         }
790                 }
791                 if (upfile.renameTo(updir)) {
792                         // Save the new publication in the scenario.
793                         // The old publication is removed from the scenario here.
794                         getPublicationService().saveAs(newPub, ProgressState.inWORK); // May throw FileNotFound if rename was not done
795                 } else {
796                         throw new IOException("Can't move file from "
797                                         + upfile.getAbsolutePath() + " to "
798                                         + updir.getAbsolutePath());
799                 }
800         }
801
802         /**
803          * Find appropriate step in the array of scenario steps according to the given step DTO.
804          * 
805          * @param stepDTO
806          *            the stepDTO
807          * @param steps
808          *            scenario steps
809          * @return appropriate scenario step
810          * @throws InvalidPropertyException
811          *             if appropriate step is not found
812          */
813         private Step findStep(final StepDTO stepDTO, final Step[] steps)
814                         throws InvalidPropertyException {
815                 int i = 0;
816                 Step step = null;
817                 do {
818                         if (steps[i].getNumber() == stepDTO.getNumber()) {
819                                 step = steps[i];
820                         }
821                         i++;
822                 } while ((step == null) && (i < steps.length));
823
824                 if (step == null) {
825                         throw new InvalidPropertyException(MessageKeyEnum.SCN_000001
826                                         .toString(), stepDTO.getNumber());
827                 }
828                 return step;
829         }
830
831         /**
832          * {@inheritDoc}
833          * 
834          * @see org.splat.service.ScenarioService#checkin(long)
835          */
836         @Transactional
837         public void checkin(final long scenarioId) throws InvalidPropertyException {
838                 Scenario aScenario = getScenarioDAO().get(scenarioId);
839                 if (aScenario == null) {
840                         // Scenario not found
841                         throw new InvalidPropertyException(MessageKeyEnum.SCN_000006
842                                         .toString(), scenarioId);
843                 }
844                 checkin(aScenario);
845         }
846
847         /**
848          * Mark the scenario as checked in.
849          * 
850          * @param aScenario
851          *            the scenario to check in.
852          */
853         private void checkin(final Scenario aScenario) {
854                 aScenario.setUser(null);
855                 aScenario.setLastModificationDate(Calendar.getInstance().getTime());
856                 // getScenarioDAO().update(aScenario);
857         }
858
859         /**
860          * {@inheritDoc}
861          * 
862          * @see org.splat.service.ScenarioService#checkout(org.splat.dal.bo.som.Scenario, org.splat.dal.bo.kernel.User)
863          */
864         public boolean checkout(final Scenario aScenario, final User user) {
865                 boolean res = getStudyService().isStaffedBy(aScenario.getOwnerStudy(),
866                                 user);
867                 if (res) {
868                         aScenario.setUser(user);
869                         aScenario.setLastModificationDate(Calendar.getInstance().getTime());
870                         // RKV: getScenarioDAO().update(aScenario);
871                 }
872                 return res;
873         }
874
875         /**
876          * Mark the given scenario as checked out by the given user.
877          * 
878          * @param scenarioId
879          *            the scenario id
880          * @param userId
881          *            the id of the user performing the check out
882          * @throws InvalidPropertyException
883          *             if the user or the scenario is not found in the database
884          * @throws NotApplicableException
885          *             if the given user can not check out the scenario
886          */
887         @Transactional
888         public void checkout(final long scenarioId, final long userId)
889                         throws InvalidPropertyException, NotApplicableException {
890                 User aUser = getUserService().selectUser(userId);
891                 if (aUser == null) {
892                         // User not found
893                         throw new InvalidPropertyException(MessageKeyEnum.USR_000001
894                                         .toString(), userId);
895                 }
896                 Scenario aScenario = getScenarioDAO().get(scenarioId);
897                 if (aScenario == null) {
898                         // Scenario not found
899                         throw new InvalidPropertyException(MessageKeyEnum.SCN_000006
900                                         .toString(), scenarioId);
901                 }
902                 boolean res = getStudyService().isStaffedBy(aScenario.getOwnerStudy(),
903                                 aUser);
904                 if (res) {
905                         if (aScenario.isCheckedout()
906                                         && (!aScenario.getUser().getUsername().equals(
907                                                         aUser.getUsername()))) {
908                                 throw new NotApplicableException(MessageKeyEnum.SCN_000008
909                                                 .toString(), scenarioId, aScenario.getUser()
910                                                 .getUsername());
911                         }
912                         aScenario.setUser(aUser);
913                         aScenario.setLastModificationDate(Calendar.getInstance().getTime());
914                 } else {
915                         // User doesn't participate in the scenario
916                         throw new NotApplicableException(MessageKeyEnum.SCN_000007
917                                         .toString(), aUser.getUsername(), scenarioId);
918                 }
919         }
920
921         /**
922          * {@inheritDoc}
923          * 
924          * @see org.splat.service.ScenarioService#copyContentsUpTo(org.splat.dal.bo.som.Scenario, org.splat.som.Step)
925          */
926         public void copyContentsUpTo(final Scenario scenario, final Step lastep) {
927                 Scenario base = (Scenario) lastep.getOwner();
928                 Step[] from = getProjectElementService().getSteps(base);
929                 Step[] to = getProjectElementService().getSteps(scenario);
930                 for (int i = 0; i < from.length; i++) {
931                         Step step = from[i];
932                         if (step.getNumber() > lastep.getNumber()) {
933                                 break;
934                         }
935
936                         List<Publication> docs = step.getAllDocuments();
937                         for (Iterator<Publication> j = docs.iterator(); j.hasNext();) {
938                                 Publication doc = getPublicationService().copy(j.next(),
939                                                 scenario); // Creation of a new reference to the document
940                                 // Database.getSession().save(doc); Publications MUST be saved later through cascading when saving the scenario
941                                 getStepService().add(to[i], doc);
942                         }
943                         List<SimulationContext> ctex = step.getAllSimulationContexts();
944                         for (Iterator<SimulationContext> j = ctex.iterator(); j.hasNext();) {
945                                 getStepService().addSimulationContext(to[i], j.next());
946                         }
947                 }
948         }
949
950         /**
951          * {@inheritDoc}
952          * 
953          * @see org.splat.service.ScenarioService#isEmpty(org.splat.dal.bo.som.Scenario)
954          */
955         public boolean isEmpty(final Scenario scenario) {
956                 Step[] mystep = getProjectElementService().getSteps(scenario);
957                 boolean isEmp = true;
958                 for (int i = 0; i < mystep.length; i++) {
959                         if (mystep[i].isStarted()) {
960                                 isEmp = false;
961                                 break;
962                         }
963                 }
964                 return isEmp;
965         }
966
967         /**
968          * @param scenario
969          * @return
970          */
971         public boolean isFinished(final Scenario scenario) {
972                 Step[] mystep = getProjectElementService().getSteps(scenario);
973                 boolean notempty = false; // If this is empty, this is not finished
974                 for (int i = 0; i < mystep.length; i++) {
975                         if (!mystep[i].isStarted()) {
976                                 continue;
977                         }
978                         if (!mystep[i].isFinished()) {
979                                 return false;
980                         }
981                         notempty = true;
982                 }
983                 return notempty;
984         }
985
986         /**
987          * {@inheritDoc}
988          * 
989          * @see org.splat.service.StudyService#addScenario(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Scenario.Properties)
990          */
991         @Transactional
992         public Scenario addScenario(final Study aStudy,
993                         final Scenario.Properties sprop) throws MissedPropertyException,
994                         InvalidPropertyException, MultiplyDefinedException {
995                 if (sprop.getManager() == null) {
996                         sprop.setManager(aStudy.getAuthor());
997                 }
998
999                 Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy));
1000                 if (sprop.getBaseStep() != null) {
1001                         copyContentsUpTo(scenario, sprop.getBaseStep());
1002                 }
1003                 Scenario previous = sprop.getInsertAfter();
1004
1005                 if (previous == null) {
1006                         aStudy.getScenariiList().add(scenario);
1007                 } else {
1008                         aStudy.getScenariiList().add(
1009                                         aStudy.getScenariiList().indexOf(previous) + 1, scenario);
1010                 }
1011                 getStudyDAO().update(aStudy); // No need to update the Lucene index
1012                 getScenarioDAO().create(scenario); // Must be done after updating this study because of the back reference to the study
1013                 if (sprop.getBaseStep() != null) {
1014                         // No need to update the Knowledge Element index as Knowledge Elements are not copied
1015                         getProjectElementService().refresh(scenario); // Because saving the scenario changes the hashcode of copied Publications
1016                 }
1017                 KnowledgeElementType ucase = getKnowledgeElementTypeService()
1018                                 .selectType("usecase");
1019                 KnowledgeElement.Properties kprop = new KnowledgeElement.Properties();
1020                 // TODO: Get appropriate user by its role: UserService.getAdmin();
1021                 // User admin = getUserService().selectUser(1); // First user created when creating the database
1022                 Role adminRole = getRoleDAO().getFilteredList(
1023                                 Restrictions.like("role", "%sysadmin%")).get(0);
1024                 User admin = getUserDAO().getFilteredList(
1025                                 Restrictions.eq("role", adminRole), Order.asc("rid")).get(0); // First sysadmin in the database
1026
1027                 kprop.setType(ucase).setTitle(aStudy.getTitle()).setValue(
1028                                 scenario.getTitle()).setAuthor(admin); // Internal Knowledge Element required by the validation process of
1029                 // knowledges
1030                 addKnowledgeElement(scenario, kprop);
1031                 return scenario;
1032         }
1033
1034         /**
1035          * Remove a knowledge element from a scenario.
1036          * 
1037          * @param scenario
1038          *            the scenario
1039          * @param kelm
1040          *            the knowledge element to remove
1041          * @return true if removal succeeded
1042          */
1043         @Transactional
1044         public boolean removeKnowledgeElement(final Scenario scenario,
1045                         final KnowledgeElement kelm) {
1046                 KnowledgeElement torem = scenario.getKnowledgeElement(kelm.getIndex());
1047                 boolean isOk = (torem != null);
1048                 if (isOk) {
1049                         isOk = scenario.getKnowledgeElements().remove(torem);
1050                         if (isOk) {
1051                                 getScenarioDAO().merge(scenario);
1052                                 // Update of my transient data
1053                                 // RKV: These transient data are not used indeed.
1054                                 // RKV: List<KnowledgeElement> kelms = scenario.getKnowledgeByType().get(
1055                                 // RKV: kelm.getType().getIndex());
1056                                 // RKV: kelms.remove(torem);
1057                                 if (scenario.getKnowledgeElementsList() != null) {
1058                                         scenario.getKnowledgeElementsList().remove(torem);
1059                                 }
1060                                 // TODO: If the owner study is not private, remove the knowledge from the Lucene index
1061                         }
1062                 }
1063                 return isOk;
1064         }
1065
1066         /**
1067          * 
1068          * {@inheritDoc}
1069          * 
1070          * @see org.splat.service.ScenarioService#renameScenario(java.lang.String)
1071          */
1072         @Transactional
1073         public void renameScenario(final Scenario scenario) {
1074                 getScenarioDAO().merge(scenario);
1075         }
1076
1077         /**
1078          * Get the knowledgeElementDAO.
1079          * 
1080          * @return the knowledgeElementDAO
1081          */
1082         public KnowledgeElementDAO getKnowledgeElementDAO() {
1083                 return _knowledgeElementDAO;
1084         }
1085
1086         /**
1087          * Set the knowledgeElementDAO.
1088          * 
1089          * @param knowledgeElementDAO
1090          *            the knowledgeElementDAO to set
1091          */
1092         public void setKnowledgeElementDAO(
1093                         final KnowledgeElementDAO knowledgeElementDAO) {
1094                 _knowledgeElementDAO = knowledgeElementDAO;
1095         }
1096
1097         /**
1098          * Get the indexService.
1099          * 
1100          * @return the indexService
1101          */
1102         public IndexService getIndexService() {
1103                 return _indexService;
1104         }
1105
1106         /**
1107          * Set the indexService.
1108          * 
1109          * @param indexService
1110          *            the indexService to set
1111          */
1112         public void setIndexService(final IndexService indexService) {
1113                 _indexService = indexService;
1114         }
1115
1116         /**
1117          * Get the scenarioDAO.
1118          * 
1119          * @return the scenarioDAO
1120          */
1121         public ScenarioDAO getScenarioDAO() {
1122                 return _scenarioDAO;
1123         }
1124
1125         /**
1126          * Set the scenarioDAO.
1127          * 
1128          * @param scenarioDAO
1129          *            the scenarioDAO to set
1130          */
1131         public void setScenarioDAO(final ScenarioDAO scenarioDAO) {
1132                 _scenarioDAO = scenarioDAO;
1133         }
1134
1135         /**
1136          * Get the studyDAO.
1137          * 
1138          * @return the studyDAO
1139          */
1140         public StudyDAO getStudyDAO() {
1141                 return _studyDAO;
1142         }
1143
1144         /**
1145          * Set the studyDAO.
1146          * 
1147          * @param studyDAO
1148          *            the studyDAO to set
1149          */
1150         public void setStudyDAO(final StudyDAO studyDAO) {
1151                 _studyDAO = studyDAO;
1152         }
1153
1154         /**
1155          * Get the knowledgeElementTypeService.
1156          * 
1157          * @return the knowledgeElementTypeService
1158          */
1159         public KnowledgeElementTypeService getKnowledgeElementTypeService() {
1160                 return _knowledgeElementTypeService;
1161         }
1162
1163         /**
1164          * Set the knowledgeElementTypeService.
1165          * 
1166          * @param knowledgeElementTypeService
1167          *            the knowledgeElementTypeService to set
1168          */
1169         public void setKnowledgeElementTypeService(
1170                         final KnowledgeElementTypeService knowledgeElementTypeService) {
1171                 _knowledgeElementTypeService = knowledgeElementTypeService;
1172         }
1173
1174         /**
1175          * Get the studyService.
1176          * 
1177          * @return the studyService
1178          */
1179         public StudyService getStudyService() {
1180                 return _studyService;
1181         }
1182
1183         /**
1184          * Set the studyService.
1185          * 
1186          * @param studyService
1187          *            the studyService to set
1188          */
1189         public void setStudyService(final StudyService studyService) {
1190                 _studyService = studyService;
1191         }
1192
1193         /**
1194          * Get the userService.
1195          * 
1196          * @return the userService
1197          */
1198         public UserService getUserService() {
1199                 return _userService;
1200         }
1201
1202         /**
1203          * Set the userService.
1204          * 
1205          * @param userService
1206          *            the userService to set
1207          */
1208         public void setUserService(final UserService userService) {
1209                 _userService = userService;
1210         }
1211
1212         /**
1213          * Get the userDAO.
1214          * 
1215          * @return the userDAO
1216          */
1217         public UserDAO getUserDAO() {
1218                 return _userDAO;
1219         }
1220
1221         /**
1222          * Set the userDAO.
1223          * 
1224          * @param userDAO
1225          *            the userDAO to set
1226          */
1227         public void setUserDAO(final UserDAO userDAO) {
1228                 _userDAO = userDAO;
1229         }
1230
1231         /**
1232          * Get the knowledgeElementTypeDAO.
1233          * 
1234          * @return the knowledgeElementTypeDAO
1235          */
1236         public KnowledgeElementTypeDAO getKnowledgeElementTypeDAO() {
1237                 return _knowledgeElementTypeDAO;
1238         }
1239
1240         /**
1241          * Set the knowledgeElementTypeDAO.
1242          * 
1243          * @param knowledgeElementTypeDAO
1244          *            the knowledgeElementTypeDAO to set
1245          */
1246         public void setKnowledgeElementTypeDAO(
1247                         final KnowledgeElementTypeDAO knowledgeElementTypeDAO) {
1248                 _knowledgeElementTypeDAO = knowledgeElementTypeDAO;
1249         }
1250
1251         /**
1252          * Get the simulationContextService.
1253          * 
1254          * @return the simulationContextService
1255          */
1256         public SimulationContextService getSimulationContextService() {
1257                 return _simulationContextService;
1258         }
1259
1260         /**
1261          * Set the simulationContextService.
1262          * 
1263          * @param simulationContextService
1264          *            the simulationContextService to set
1265          */
1266         public void setSimulationContextService(
1267                         final SimulationContextService simulationContextService) {
1268                 _simulationContextService = simulationContextService;
1269         }
1270
1271         /**
1272          * Get project settings.
1273          * 
1274          * @return Project settings service
1275          */
1276         private ProjectSettingsService getProjectSettings() {
1277                 return _projectSettings;
1278         }
1279
1280         /**
1281          * Set project settings service.
1282          * 
1283          * @param projectSettingsService
1284          *            project settings service
1285          */
1286         public void setProjectSettings(
1287                         final ProjectSettingsService projectSettingsService) {
1288                 _projectSettings = projectSettingsService;
1289         }
1290
1291         /**
1292          * Get the documentTypeService.
1293          * 
1294          * @return the documentTypeService
1295          */
1296         public DocumentTypeService getDocumentTypeService() {
1297                 return _documentTypeService;
1298         }
1299
1300         /**
1301          * Set the documentTypeService.
1302          * 
1303          * @param documentTypeService
1304          *            the documentTypeService to set
1305          */
1306         public void setDocumentTypeService(
1307                         final DocumentTypeService documentTypeService) {
1308                 _documentTypeService = documentTypeService;
1309         }
1310
1311         /**
1312          * Get the roleDAO.
1313          * 
1314          * @return the roleDAO
1315          */
1316         public RoleDAO getRoleDAO() {
1317                 return _roleDAO;
1318         }
1319
1320         /**
1321          * Set the roleDAO.
1322          * 
1323          * @param roleDAO
1324          *            the roleDAO to set
1325          */
1326         public void setRoleDAO(final RoleDAO roleDAO) {
1327                 _roleDAO = roleDAO;
1328         }
1329
1330 }