Salome HOME
Copyrights update 2015.
[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.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import org.hibernate.criterion.DetachedCriteria;
24 import org.hibernate.criterion.Order;
25 import org.hibernate.criterion.Projections;
26 import org.hibernate.criterion.Restrictions;
27 import org.hibernate.transform.Transformers;
28 import org.splat.common.properties.MessageKeyEnum;
29 import org.splat.dal.bo.kernel.Relation;
30 import org.splat.dal.bo.kernel.Role;
31 import org.splat.dal.bo.kernel.User;
32 import org.splat.dal.bo.som.ConvertsRelation;
33 import org.splat.dal.bo.som.Document;
34 import org.splat.dal.bo.som.DocumentType;
35 import org.splat.dal.bo.som.File;
36 import org.splat.dal.bo.som.KnowledgeElement;
37 import org.splat.dal.bo.som.KnowledgeElementType;
38 import org.splat.dal.bo.som.ProgressState;
39 import org.splat.dal.bo.som.ProjectElement;
40 import org.splat.dal.bo.som.Publication;
41 import org.splat.dal.bo.som.Scenario;
42 import org.splat.dal.bo.som.SimulationContext;
43 import org.splat.dal.bo.som.SimulationContextType;
44 import org.splat.dal.bo.som.Study;
45 import org.splat.dal.bo.som.UsedByRelation;
46 import org.splat.dal.bo.som.UsesRelation;
47 import org.splat.dal.bo.som.ValidationCycle;
48 import org.splat.dal.bo.som.Document.Properties;
49 import org.splat.dal.dao.kernel.RoleDAO;
50 import org.splat.dal.dao.kernel.UserDAO;
51 import org.splat.dal.dao.som.DocumentDAO;
52 import org.splat.dal.dao.som.KnowledgeElementDAO;
53 import org.splat.dal.dao.som.KnowledgeElementTypeDAO;
54 import org.splat.dal.dao.som.ScenarioDAO;
55 import org.splat.dal.dao.som.StudyDAO;
56 import org.splat.dal.dao.som.ValidationCycleDAO;
57 import org.splat.exception.InvalidParameterException;
58 import org.splat.i18n.I18nUtils;
59 import org.splat.kernel.InvalidPropertyException;
60 import org.splat.kernel.MismatchException;
61 import org.splat.kernel.MissedPropertyException;
62 import org.splat.kernel.MultiplyDefinedException;
63 import org.splat.kernel.NotApplicableException;
64 import org.splat.log.AppLogger;
65 import org.splat.service.dto.DocumentDTO;
66 import org.splat.service.dto.FileDTO;
67 import org.splat.service.dto.ScenarioDTO;
68 import org.splat.service.dto.StepDTO;
69 import org.splat.service.technical.IndexService;
70 import org.splat.service.technical.ProjectSettingsService;
71 import org.splat.service.technical.RepositoryService;
72 import org.splat.service.technical.StepsConfigService;
73 import org.splat.som.Step;
74 import org.splat.util.BeanHelper;
75 import org.splat.util.IOUtils;
76 import org.springframework.transaction.annotation.Transactional;
77
78 /**
79  * Scenario service implementation.
80  * 
81  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
82  */
83 public class ScenarioServiceImpl implements ScenarioService {
84
85     /**
86      * The logger for the service.
87      */
88     public final static AppLogger LOG = AppLogger
89             .getLogger(ScenarioServiceImpl.class);
90
91     /**
92      * " to " literal.
93      */
94     private static final String TO = " to ";
95     /**
96      * Injected index service.
97      */
98     private IndexService _indexService;
99     /**
100      * Injected step service.
101      */
102     private StepService _stepService;
103     /**
104      * Injected study service.
105      */
106     private StudyService _studyService;
107     /**
108      * Injected publication service.
109      */
110     private PublicationService _publicationService;
111     /**
112      * Injected project element service.
113      */
114     private ProjectElementService _projectElementService;
115     /**
116      * Injected knowledge element DAO.
117      */
118     private KnowledgeElementDAO _knowledgeElementDAO;
119     /**
120      * Injected scenario DAO.
121      */
122     private ScenarioDAO _scenarioDAO;
123
124     /**
125      * Injected study DAO.
126      */
127     private StudyDAO _studyDAO;
128
129     /**
130      * Injected knowledge element service.
131      */
132     private KnowledgeElementTypeService _knowledgeElementTypeService;
133
134     /**
135      * Injected user service.
136      */
137     private UserService _userService;
138
139     /**
140      * Injected user DAO.
141      */
142     private UserDAO _userDAO;
143
144     /**
145      * Injected role DAO.
146      */
147     private RoleDAO _roleDAO;
148
149     /**
150      * Injected knowledge element type DAO.
151      */
152     private KnowledgeElementTypeDAO _knowledgeElementTypeDAO;
153
154     /**
155      * Injected document DAO.
156      */
157     private DocumentDAO _documentDAO;
158
159     /**
160      * Injected simulation context service.
161      */
162     private SimulationContextService _simulationContextService;
163
164     /**
165      * Injected simulation context type service.
166      */
167     private SimulationContextTypeService _simulationContextTypeService;
168
169     /**
170      * Injected project service.
171      */
172     private ProjectSettingsService _projectSettings;
173
174     /**
175      * Injected document type service.
176      */
177     private DocumentTypeService _documentTypeService;
178
179     /**
180      * Injected validation cycle DAO.
181      */
182     private ValidationCycleDAO _validationCycleDAO;
183
184     /**
185      * Injected project settings service.
186      */
187     private StepsConfigService _stepsConfigService;
188
189     /**
190      * Injected repository service.
191      */
192     private RepositoryService _repositoryService;
193
194
195     /**
196      * Get a new id to document arriver after check-out.
197      * Return two several values: -1 or ID of the existing document.
198      *
199      * @param scenId
200      *            the scenario id
201      * @param activityNumber
202      *            the number of activity
203      * @param docId
204      *            the document id
205      * @param fileExt
206      *            the file extension
207      * @return new document id or -1 if same document do nor exist.
208      * @throws InvalidPropertyException if activityNumber is incorrect.
209      */
210
211     @Override
212     public final long getNewDocumentId(final long scenId,
213             final int activityNumber, final Long docId,
214             final String fileExt) throws InvalidPropertyException {
215
216         Scenario aScenario = getScenarioDAO().get(scenId);
217         Step[] steps = getProjectElementService().getSteps(aScenario);
218         Step currentStep = null;
219         for (Step step : steps) {
220             if (step.getNumber() == activityNumber) {
221                 currentStep = step;
222                 break;
223             }
224         }
225         if (currentStep == null) {
226             throw new InvalidPropertyException(
227                     MessageKeyEnum.SCN_000001.toString(), activityNumber);
228         }
229
230         long resId = -1;
231         if (docId > 0) {
232             ProjectSettingsService.Step stepType = currentStep.getStep();
233             DocumentType documentType = _projectSettings
234                     .getDefaultDocumentType(stepType, fileExt);
235             if (currentStep.getDocument(docId).value().getType()
236                     .equals(documentType)) {
237                 resId = docId;
238             } else {
239                 List<Publication> allDocs = currentStep.getAllDocuments();
240                 for (Publication publication : allDocs) {
241                     if (publication.value().getType().equals(documentType)
242                             && publication.value().getIndex() > resId) {
243                         resId = publication.value().getIndex();
244                     }
245                 }
246             }
247         }
248         return resId;
249     }
250
251     /**
252      * Get the projectElementService.
253      *
254      * @return the projectElementService
255      */
256     public ProjectElementService getProjectElementService() {
257         return _projectElementService;
258     }
259
260     /**
261      * Set the projectElementService.
262      * 
263      * @param projectElementService
264      *            the projectElementService to set
265      */
266     public void setProjectElementService(
267             final ProjectElementService projectElementService) {
268         _projectElementService = projectElementService;
269     }
270
271     /**
272      * Get the publicationService.
273      * 
274      * @return the publicationService
275      */
276     public PublicationService getPublicationService() {
277         return _publicationService;
278     }
279
280     /**
281      * Set the publicationService.
282      * 
283      * @param publicationService
284      *            the publicationService to set
285      */
286     public void setPublicationService(
287             final PublicationService publicationService) {
288         _publicationService = publicationService;
289     }
290
291     /**
292      * Get the stepService.
293      * 
294      * @return the stepService
295      */
296     public StepService getStepService() {
297         return _stepService;
298     }
299
300     /**
301      * Set the stepService.
302      * 
303      * @param stepService
304      *            the stepService to set
305      */
306     public void setStepService(final StepService stepService) {
307         _stepService = stepService;
308     }
309
310     /**
311      * {@inheritDoc}
312      * 
313      * @see org.splat.service.ScenarioService#getStudyScenarios(java.lang.Long)
314      */
315     @Override
316     @Transactional(readOnly = true)
317     public List<ScenarioDTO> getStudyScenarios(final Long studyId) {
318         DetachedCriteria query = DetachedCriteria
319                 .forClass(Scenario.class, "scen")
320                 .add(Restrictions.eq("owner.rid", studyId))
321                 .setProjection(
322                         Projections
323                                 .projectionList()
324                                 .add(Projections.property("scen.title"),
325                                         "title")
326                                 .add(Projections.property("scen.rid"), "index"))
327                 .setResultTransformer(
328                         Transformers.aliasToBean(ScenarioDTO.class));
329         return getScenarioDAO().getFilteredDTOList(query);
330     }
331
332     /**
333      * {@inheritDoc}
334      * 
335      * @see org.splat.service.ScenarioService#copyStudyContent(long, long, int,
336      *      long)
337      */
338     @Override
339     @Transactional
340     public void copyStudyContent(final long fromStudyId, final long fromScenId,
341             final int finalStepNum, final long toStudyId)
342             throws InvalidParameterException, MissedPropertyException,
343             InvalidPropertyException, MultiplyDefinedException,
344             NotApplicableException, IOException {
345         Study fromStudy = getStudyService().selectStudy(fromStudyId);
346         if (fromStudy == null) {
347             throw new InvalidParameterException(
348                     MessageKeyEnum.STD_000002.toString(),
349                     String.valueOf(fromStudyId));
350         }
351         Scenario fromScen = null;
352         for (Scenario scen : fromStudy.getScenariiList()) {
353             if (scen.getIndex() == fromScenId) {
354                 fromScen = scen;
355                 break;
356             }
357         }
358
359         Study toStudy = getStudyService().selectStudy(toStudyId);
360         if (toStudy == null) {
361             throw new InvalidParameterException(
362                     MessageKeyEnum.STD_000002.toString(),
363                     String.valueOf(toStudy));
364         }
365
366         // Check if the step is applied to a scenario and scenario is defined
367         if (fromScen == null
368                 && getStepsConfigService().stepInvolves(finalStepNum,
369                         Scenario.class)) {
370             throw new InvalidParameterException(
371                     MessageKeyEnum.SCN_000006.toString(),
372                     String.valueOf(fromScenId));
373         }
374
375         // Copy validation cycles
376         copyValidationCycles(fromStudy, toStudy);
377
378         // Copy content of the study up to the given step
379         Map<Publication, Publication> oldToNewPub = new HashMap<Publication, Publication>();
380         copyDocs(fromStudy, toStudy, finalStepNum, oldToNewPub);
381         if (fromScen != null) {
382             copyDocs(fromScen, toStudy.getScenariiList().get(0), finalStepNum,
383                     oldToNewPub);
384         }
385         copyDependencies(fromStudy, finalStepNum, oldToNewPub);
386         if (fromScen != null) {
387             copyDependencies(fromScen, finalStepNum, oldToNewPub);
388         }
389     }
390
391     /**
392      * Copy validation cycles from study to study.
393      * 
394      * @param fromStudy
395      *            the source study
396      * @param toStudy
397      *            the destination study
398      */
399     private void copyValidationCycles(final Study fromStudy, final Study toStudy) {
400         for (ValidationCycle fromCycle : fromStudy.getValidationCycles()
401                 .values()) {
402             if (fromCycle.isAssigned()) {
403                 ValidationCycle cycle = fromCycle.clone(toStudy);
404                 getValidationCycleDAO().create(cycle);
405                 toStudy.addRelation(cycle.getContext());
406                 toStudy.getValidationCycles().put(
407                         cycle.getDocumentType().getName(), cycle); // Replaces
408                                                                    // the cycle
409                                                                    // if exists
410                                                                    // as
411                                                                    // default,
412             }
413         }
414     }
415
416     /**
417      * Copy dependencies between documents from the given project element up to <BR>
418      * the given step according to the given map of old publications to new
419      * publications.
420      * 
421      * @param from
422      *            the source project element
423      * @param finalStepNum
424      *            the final step for copy processing
425      * @param oldToNewPub
426      *            the old to new publications map
427      */
428     private void copyDependencies(final ProjectElement from,
429             final int finalStepNum,
430             final Map<Publication, Publication> oldToNewPub) {
431         // Copy dependencies between copied documents
432         for (Publication pub : from.getDocums()) {
433             // If the document in the step before the final one
434             if (pub.value().getStep() <= finalStepNum) {
435                 Publication newPub = oldToNewPub.get(pub);
436                 for (Publication used : pub.getRelations(UsesRelation.class)) {
437                     newPub.addDependency(oldToNewPub.get(used));
438                 }
439             }
440         }
441     }
442
443     /**
444      * Copy documents with dependencies up to the given step.
445      * 
446      * @param from
447      *            the source project element
448      * @param to
449      *            the destination project element
450      * @param finalStepNum
451      *            the final step for copy process
452      * @param oldToNewPub2
453      * @throws MissedPropertyException
454      *             if document creation is failed
455      * @throws InvalidPropertyException
456      *             if document creation is failed
457      * @throws MultiplyDefinedException
458      *             if document creation is failed
459      * @throws IOException
460      *             if document file creation is failed
461      * @throws NotApplicableException
462      *             if document state is not applicable
463      * @param oldToNewPub
464      *            the old to new publications map
465      * 
466      */
467     private void copyDocs(final ProjectElement from, final ProjectElement to,
468             final int finalStepNum,
469             final Map<Publication, Publication> oldToNewPub)
470             throws MissedPropertyException, InvalidPropertyException,
471             MultiplyDefinedException, NotApplicableException, IOException {
472         Map<Integer, Step> steps = getProjectElementService().getStepsMap(to);
473         // Copy publications without old versions and relations to not copied
474         // steps documents
475         for (Publication pub : from.getDocums()) {
476             // If the document in the step before the final one
477             if (pub.value().getStep() <= finalStepNum) {
478                 // Copy the document
479                 oldToNewPub
480                         .put(pub,
481                                 createDoc(pub.value(),
482                                         steps.get(pub.value().getStep())));
483             }
484         }
485     }
486
487     /**
488      * Create a copy of the given document and publish it in the given step.
489      * 
490      * @param fromDoc
491      *            the source document
492      * @param step
493      *            the destination step
494      * @return the created publication
495      * @throws MissedPropertyException
496      *             if document creation is failed
497      * @throws InvalidPropertyException
498      *             if document creation is failed
499      * @throws MultiplyDefinedException
500      *             if document creation is failed
501      * @throws IOException
502      *             if document file creation is failed
503      * @throws NotApplicableException
504      *             if document state is not applicable
505      */
506     private Publication createDoc(final Document fromDoc, final Step step)
507             throws MissedPropertyException, InvalidPropertyException,
508             MultiplyDefinedException, IOException, NotApplicableException {
509
510         java.io.File srcFile = fromDoc.getSourceFile().asFile();
511         // Creation of the document
512         Document.Properties dprop = new Document.Properties()
513                 .setName(fromDoc.getTitle()).setType(fromDoc.getType())
514                 .setFormat(fromDoc.getFormat()).setAuthor(fromDoc.getAuthor());
515
516         java.io.File tmpDir = getRepositoryService().getDownloadDirectory(
517                 step.getOwnerStudy().getAuthor());
518
519         // Remove local file index prefix to get original filename.
520         java.io.File upfile = new java.io.File(tmpDir.getPath()
521                 + "/"
522                 + srcFile.getName().substring(
523                         srcFile.getName().indexOf('_') + 1));
524         // Copy the source file into the temporary folder with original
525         // filename.
526         copyFile(srcFile, upfile);
527
528         dprop.setLocalPath(upfile.getPath());
529         Publication addoc = getStepService().createDocument(step, dprop);
530
531         // Move the temporary file into the repository
532         moveFile(upfile, addoc.getSourceFile().asFile());
533
534         getPublicationService().saveAs(addoc, fromDoc.getProgressState());
535
536         // Copy attached files
537         for (Relation rel : fromDoc.getRelations(ConvertsRelation.class)) {
538             File attach = ((ConvertsRelation) rel).getTo();
539             ConvertsRelation export = getPublicationService().attach(addoc,
540                     attach.getFormat());
541             // Copy the source document attachment file to the new study vault
542             copyFile(attach.asFile(), export.getTo().asFile());
543         }
544         return addoc;
545     }
546
547     /**
548      * Copy a file. Print info message.
549      * 
550      * @param upfile
551      *            the source file.
552      * @param file
553      *            the target file
554      * @throws IOException
555      *             if failed
556      */
557     private void copyFile(final java.io.File upfile, final java.io.File file)
558             throws IOException {
559         if (LOG.isInfoEnabled()) {
560             LOG.info("Copy " + upfile.getAbsolutePath() + TO + file.getPath());
561         }
562         IOUtils.copy(upfile, file);
563     }
564
565     /**
566      * Copy a file. Print info message.
567      * 
568      * @param upfile
569      *            the source file.
570      * @param file
571      *            the target file
572      * @return true if renamed otherwise return false
573      */
574     private boolean moveFile(final java.io.File upfile, final java.io.File file) {
575         if (LOG.isInfoEnabled()) {
576             LOG.info("Move " + upfile.getAbsolutePath() + TO + file.getPath());
577         }
578         file.delete(); // necessary on some platforms if the file exists.
579         return upfile.renameTo(file);
580     }
581
582     /**
583      * {@inheritDoc}
584      * 
585      * @see org.splat.service.ScenarioService#getScenarioInfo(long)
586      */
587     @Transactional(readOnly = true)
588     public List<StepDTO> getScenarioInfo(final long scenarioId) {
589         List<StepDTO> res = new ArrayList<StepDTO>();
590         // Get the scenario from the database by id
591         Scenario scen = getScenarioDAO().get(scenarioId);
592         if (LOG.isDebugEnabled()) {
593             LOG.debug("Scenario[" + scenarioId + "]: Number of publications: "
594                     + scen.getDocums().size());
595         }
596         // Get activities of the scenario
597         Step[] steps = getProjectElementService().getSteps(scen);
598         StepDTO stepDTO;
599         DocumentDTO docDTO;
600         String docType, fileFormat;
601         String processing;
602         boolean doImport;
603         // For each activity create a step DTO and add it to the result list
604         for (Step step : steps) {
605             stepDTO = BeanHelper.copyBean(step.getStep(), StepDTO.class);
606             res.add(stepDTO);
607             if (LOG.isDebugEnabled()) {
608                 LOG.debug("Step[" + stepDTO.getNumber()
609                         + "]: Number of documents: "
610                         + step.getDocuments().size());
611             }
612             // For each publication of the activity create a document DTO.
613             // Each file is considered as a source file.
614             for (Publication tag : step.getDocuments()) {
615                 docDTO = stepDTO.addDoc(tag.value().getIndex(), tag.value()
616                         .getTitle());
617                 char aState = tag.getIsnew();
618                 docType = tag.value().getType().getName();
619                 // For each file of the document create a file DTO
620                 // Process source file of the document
621                 fileFormat = tag.value().getFile().getFormat();
622                 doImport = getProjectSettings().doImport(docType, fileFormat);
623                 if (doImport && (!tag.isOutdated())) {
624                     processing = "file-import";
625                 } else {
626                     processing = "file-download";
627                 }
628                 File aFile = tag.value().getFile();
629                 docDTO.addFile(aFile.getIndex(), aFile.getRelativePath(),
630                         aState, processing, false);
631                 // Process all exported files
632                 for (Relation rel : tag.value().getRelations(
633                         ConvertsRelation.class)) {
634                     aFile = ((ConvertsRelation) rel).getTo();
635                     fileFormat = aFile.getFormat();
636                     doImport = getProjectSettings().doImport(docType,
637                             fileFormat);
638                     if (doImport && (!tag.isOutdated())) {
639                         processing = "file-import";
640                     } else {
641                         processing = "file-download";
642                     }
643                     docDTO.addFile(aFile.getIndex(), aFile.getRelativePath(),
644                             aState, processing, false);
645                 }
646             }
647         }
648         return res;
649     }
650
651     /**
652      * {@inheritDoc}
653      * 
654      * @see org.splat.service.ScenarioService#createStudy(java.lang.String,
655      *      java.lang.String, java.lang.String, java.lang.String)
656      */
657     @Transactional
658     public long createStudy(final String username, final String title,
659             final String productName, final String description)
660             throws InvalidPropertyException, MissedPropertyException,
661             MultiplyDefinedException {
662         long id = 0;
663
664         // Find the author
665         User author = getUserService().selectUser(username);
666         if (author == null) {
667             // User is not found
668             throw new InvalidPropertyException(
669                     MessageKeyEnum.USR_000001.toString(), username);
670         }
671
672         // Set the study properties
673         Study.Properties sprop = new Study.Properties();
674         sprop.setTitle(title).setManager(author);
675         sprop.setDescription(description);
676
677         // Find the product simulation context
678         SimulationContextType productContextType = getSimulationContextService()
679                 .selectType("product");
680         SimulationContext.Properties cprop = new SimulationContext.Properties();
681         cprop.setType(productContextType).setValue(productName);
682         SimulationContext productCtx = getSimulationContextService()
683                 .selectSimulationContext(productContextType, productName);
684         if (productCtx != null) {
685             cprop.setIndex(productCtx.getIndex());
686         }
687
688         // Set a first scenario properties
689         Scenario.Properties oprop = new Scenario.Properties();
690         oprop.setTitle(I18nUtils.getMessageLocaleDefault("label.scenario")
691                 + " 1");
692
693         Study study = createStudy(sprop, oprop, cprop);
694         id = study.getIndex();
695
696         return id;
697     }
698
699     /**
700      * Create a new study with one scenario and "product" simulation context.
701      * 
702      * @param sprop
703      *            the study properties
704      * @param oprop
705      *            the scenario properties
706      * @param cprop
707      *            the "product" simulation context properties
708      * @return the created study
709      * @throws MissedPropertyException
710      *             if a mandatory property is missed
711      * @throws InvalidPropertyException
712      *             if a property is invalid
713      * @throws MultiplyDefinedException
714      *             if some property occurs several times
715      */
716     @Transactional
717     public Study createStudy(final Study.Properties sprop,
718             final Scenario.Properties oprop,
719             final SimulationContext.Properties cprop)
720             throws MissedPropertyException, InvalidPropertyException,
721             MultiplyDefinedException {
722         Study study = getStudyService().createStudy(sprop);
723         addScenario(study, oprop);
724         if (cprop.getIndex() == 0) { // Input of new project context
725             cprop.setType(getSimulationContextService().selectType("product"))
726                     .setValue(cprop.getValue());
727             getStudyService().addProjectContext(study, cprop);
728         } else { // Selection of existing project context
729             SimulationContext context = getSimulationContextService()
730                     .selectSimulationContext(cprop.getIndex());
731             getStudyService().addProjectContext(study, context);
732         }
733         return study;
734     }
735
736     /**
737      * {@inheritDoc}
738      * 
739      * @see org.splat.service.ScenarioService#assignStudyContext(java.lang.Long,
740      *      java.lang.String, java.lang.String)
741      */
742     @Transactional
743     public void assignStudyContext(final Long studyId, final String ctxType,
744             final String ctxValue) throws MissedPropertyException,
745             InvalidPropertyException, MultiplyDefinedException {
746         // Find the study by the given id
747         Study study = getStudyDAO().get(studyId);
748         if (study == null) {
749             throw new InvalidPropertyException(
750                     MessageKeyEnum.STD_000002.toString(), studyId);
751         }
752         // Find the context type by its name
753         SimulationContextType celt = getSimulationContextService().selectType(
754                 ctxType);
755         if (celt == null) {
756             // Creation of a new context type
757             celt = getSimulationContextTypeService().createType(ctxType,
758                     getProjectElementService().getFirstStep(study).getStep());
759         }
760         // Find the given context value of the given type
761         SimulationContext context = getSimulationContextService()
762                 .selectSimulationContext(celt, ctxValue);
763         if (context == null) { // Input of a new project context
764             SimulationContext.Properties cprop = new SimulationContext.Properties();
765             cprop.setType(celt).setValue(ctxValue);
766             getStudyService().addProjectContext(study, cprop);
767         } else { // Selection of existing project context
768             getStudyService().addProjectContext(study, context);
769         }
770     }
771
772     /**
773      * {@inheritDoc}
774      * 
775      * @see org.splat.service.ScenarioService#addKnowledgeElement(org.splat.dal.bo.som.Scenario,
776      *      org.splat.dal.bo.som.KnowledgeElement.Properties)
777      */
778     @Transactional
779     public KnowledgeElement addKnowledgeElement(final Scenario aScenarioDTO,
780             final KnowledgeElement.Properties kprop)
781             throws MissedPropertyException, InvalidPropertyException,
782             MultiplyDefinedException {
783         KnowledgeElement kelm = null;
784         // try {
785         long aScenarioId = aScenarioDTO.getIndex();
786         if (LOG.isDebugEnabled()) {
787             LOG.debug("Add a knowledge element to the scenario #" + aScenarioId);
788         }
789         // Get the persistent scenario.
790         Scenario aScenario = getScenarioDAO().get(aScenarioId);
791         // Get persistent objects for creating a new knowledge.
792         // TODO: Actions must use DTO instead of persistent objects.
793         getUserDAO().merge(kprop.getAuthor());
794         getKnowledgeElementTypeDAO().merge(kprop.getType());
795         // Create a transient knowledge element related to the given scenario.
796         kelm = new KnowledgeElement(kprop.setOwnerScenario(aScenario));
797         // Save the new knowledge in the database.
798         getKnowledgeElementDAO().create(kelm);
799         // Update scenario transient data.
800         if (kelm.getType().equals("usecase")) {
801             aScenarioDTO.setUcase(kelm);
802         } else if (aScenarioDTO.getKnowledgeElementsList() != null) { // If
803                                                                       // null,
804                                                                       // knowl
805                                                                       // will be
806                                                                       // initialized
807                                                                       // when
808                                                                       // needed
809             aScenarioDTO.getKnowledgeElementsList().add(kelm);
810         }
811
812         // Load the workflow for the parent study to take into account
813         // all study actors durng reindexing.
814         getStudyService().loadWorkflow(aScenario.getOwnerStudy());
815
816         // // Update the lucene index of knowledge elements.
817         // getIndexService().add(kelm);
818         if (LOG.isDebugEnabled()) {
819             LOG.debug("A knowledge element #" + kelm.getIndex()
820                     + " is added to the scenario #" + aScenario.getIndex());
821         }
822         // } catch (IOException error) {
823         // LOG.error("Unable to index the knowedge element '"
824         // + kelm.getIndex() + "', reason:", error);
825         // kelm = null;
826         // }
827
828         return kelm;
829     }
830
831     /**
832      * {@inheritDoc}
833      * 
834      * @see org.splat.service.ScenarioService#checkin(long, long,
835      *      java.util.List)
836      */
837     @Transactional
838     public void checkin(final long scenId, final long userId,
839             final List<StepDTO> scInfo) throws InvalidPropertyException,
840             MissedPropertyException, MultiplyDefinedException,
841             MismatchException, IOException, NotApplicableException {
842         // Get the scenario from the database by id
843         Scenario aScenario = getScenarioDAO().get(scenId);
844         // Get the user who perform this check-in operation
845         User aUser = getUserService().selectUser(userId);
846         // Get activities of the scenario
847         Step[] steps = getProjectElementService().getSteps(aScenario);
848         // Find result document types
849         List<DocumentType> resTypes = getDocumentTypeService()
850                 .selectResultTypes();
851
852         // Keep newly created documents to create uses relations to results of a
853         // previous step.
854         // For each processed existing document keep its new version
855         Map<Document, Document> newVersion = new HashMap<Document, Document>();
856         // Created publications of new created versions of existing documents
857         List<Publication> newVers = new ArrayList<Publication>();
858         // The list of publications of new created documents not existing before
859         // the checkin
860         List<Publication> newDocs = new ArrayList<Publication>();
861         // For each step DTO
862         DocumentType resType;
863         Date aDate = new Date(); // The timestamp of the checkin operation
864         for (StepDTO stepDTO : scInfo) {
865             if (LOG.isDebugEnabled()) {
866                 LOG.debug("Checkin the step:\n" + stepDTO);
867             }
868             if (stepDTO.getDocs().size() == 0) {
869                 break;
870             }
871             // Find a result document type of the step
872             int i = 0;
873             resType = null;
874             do {
875                 if (resTypes.get(i).isResultOf(
876                         getProjectSettings().getStep(stepDTO.getNumber()))) {
877                     resType = resTypes.get(i);
878                 }
879                 i++;
880             } while ((resType == null) && (i < resTypes.size()));
881
882             // Find the appropriate scenario step
883             Step step = findStep(stepDTO, steps);
884
885             List<FileDTO> filesToBeAttached = new ArrayList<FileDTO>();
886             FileDTO fileToAttachTo = null; // all the rest documents will be
887                                            // attached to it
888
889             // The id is the same for all DocumentDTOs of a step
890             Long currentDocId = stepDTO.getDocs().get(0).getId();
891             if (currentDocId != null && currentDocId > 0) { // there is a result
892                                                             // document in the
893                                                             // step
894                 String currentFormat = step.getDocument(currentDocId).value()
895                         .getFormat();
896
897                 // Process each document of the step
898                 for (DocumentDTO doc : stepDTO.getDocs()) {
899                     for (FileDTO fileDTO : doc.getFiles()) {
900
901                         String path = fileDTO.getPath();
902                         String format = path
903                                 .substring(path.lastIndexOf('.') + 1);
904
905                         // If it has the same format as current doc (there can
906                         // be just one such file)
907                         // then this doc will be DocToAttachTo.
908                         if (format != null && format.equals(currentFormat)) {
909                             fileToAttachTo = fileDTO;
910                         } else {
911                             // Else, put it in the list of docs that will be
912                             // attached to DocToAttachTo
913                             filesToBeAttached.add(fileDTO);
914                         }
915                     }
916                 }
917             } else {
918                 // Process each document of the step
919                 for (DocumentDTO doc : stepDTO.getDocs()) {
920                     for (FileDTO fileDTO : doc.getFiles()) {
921                         String path = doc.getFiles().get(0).getPath();
922                         String format = path
923                                 .substring(path.lastIndexOf('.') + 1);
924
925                         ProjectSettingsService.Step stepType = step.getStep();
926                         // If the default type for its format in the current
927                         // step is the result type,
928                         // then this doc will be DocToAttachTo.
929                         DocumentType defaultDocType = _projectSettings
930                                 .getDefaultDocumentType(stepType, format);
931                         if (defaultDocType != null
932                                 && defaultDocType.isResultOf(stepType)) {
933                             // It is possible that there is not just one such
934                             // doc
935                             if (fileToAttachTo != null) {
936                                 filesToBeAttached.add(fileToAttachTo);
937                             }
938                             fileToAttachTo = fileDTO;
939                         } else {
940                             // Else, put it in the list of docs that will be
941                             // attached to DocToAttachTo
942                             filesToBeAttached.add(fileDTO);
943                         }
944                     }
945                 }
946
947                 // could not find any file with appropriate format
948                 if (fileToAttachTo == null && !filesToBeAttached.isEmpty()) {
949                     // All the rest documents will be attached to the first in
950                     // the list
951                     fileToAttachTo = filesToBeAttached.get(0);
952                     filesToBeAttached.remove(0);
953                 }
954             }
955
956             if (fileToAttachTo != null) { // true if the DocumentDTO list is not
957                                           // empty
958
959                 // Process docToAttachTo
960                 Publication pub = checkinDoc(step, fileToAttachTo,
961                         currentDocId, aUser, resType, aDate, newVersion,
962                         newVers, newDocs);
963                 currentDocId = pub.value().getIndex();
964             }
965
966             // Process rest docs
967             for (FileDTO file : filesToBeAttached) {
968                 checkinDoc(step, file, currentDocId, aUser, resType, aDate,
969                         newVersion, newVers, newDocs);
970             }
971         }
972
973         // Set uses/used relations
974         updateRelationsAfterCheckin(aScenario, newVersion, newVers, newDocs);
975
976         // Mark the scenario as checked in
977         checkin(aScenario);
978     }
979
980     /**
981      * Updated uses/used relations after checkin operation:<BR>
982      * <ul>
983      * <li>For each new version copy uses relations from the previous version.</li>
984      * <li>Outdate documents which depend from the previous version and were not
985      * checked in during this operation.</li>
986      * <li>For each new document create uses relation to the last versions of
987      * results of the previous step.</li>
988      * </ul>
989      * 
990      * @param aScenario
991      *            the checked in scenario
992      * @param newVersion
993      *            the mapping of documents existed before the checkin to their
994      *            new created versions
995      * @param newVers
996      *            the list of publications of new created versions of documents
997      *            existed before the checkin
998      * @param newDocs
999      *            the list of publications of new created documents not existed
1000      *            before the checkin
1001      */
1002     private void updateRelationsAfterCheckin(final Scenario aScenario,
1003             final Map<Document, Document> newVersion,
1004             final List<Publication> newVers, final List<Publication> newDocs) {
1005         // For each new version copy uses relations from the previous version.
1006         for (Publication newVer : newVers) {
1007             // For each Uses relation of the previous version
1008             Document prevDoc = newVer.value().getPreviousVersion();// prevVersion.get(newVer);
1009             if (LOG.isDebugEnabled()) {
1010                 LOG.debug("Previous version for publication #"
1011                         + newVer.getIndex() + " is found: " + prevDoc);
1012             }
1013             List<Relation> usesRelations = prevDoc
1014                     .getRelations(UsesRelation.class);
1015             for (Relation rel : usesRelations) {
1016                 // If used document has been also versioned then refer to its
1017                 // new version.
1018                 Document usedDoc = ((UsesRelation) rel).getTo();
1019                 if (newVersion.containsKey(usedDoc)) {
1020                     usedDoc = newVersion.get(usedDoc);
1021                 }
1022                 // Build the appropriate relation for the new version.
1023                 newVer.addDependency(usedDoc);
1024             }
1025             // Outdate documents which depend from the previous version and
1026             // were not checked in during this operation.
1027             // 1. Get all usedBy relations of the previous document version
1028             for (Relation rel : prevDoc.getRelations(UsedByRelation.class)) {
1029                 Document using = ((UsedByRelation) rel).getTo();
1030                 // Check that not checked in dependent documents became outdated
1031                 Publication usingPub = aScenario.getPublication(using);
1032                 if (usingPub != null) { // if the document using the old version
1033                                         // is still published
1034                     usingPub.setIsnew('O');
1035                 }
1036             }
1037         }
1038
1039         // For each new document create uses relation to the last versions of
1040         // results of the previous step.
1041         for (Publication newPub : newDocs) {
1042             // Find used document type according to the configuration.
1043             Set<DocumentType> usedTypes = newPub.value().getType()
1044                     .getDefaultUses();
1045             // Find documents of used type in the previous study step.
1046             for (Publication pub : aScenario.getDocums()) {
1047                 if ((pub.getStep().getNumber() <= newPub.getStep().getNumber())
1048                         && (!pub.isOutdated())
1049                         && usedTypes.contains(pub.value().getType())
1050                         && !newPub.equals(pub)) {
1051                     // Create uses relation from the new document
1052                     // to the found document in the previous step.
1053                     newPub.addDependency(pub);
1054                 }
1055             }
1056         }
1057     }
1058
1059     /**
1060      * Pure checkin of the document without creation of uses/usedBy relations.
1061      * For an existing document a new version is created. New documents become
1062      * published in the given step of the appropriate scenario. The appropriate
1063      * uploaded file is attached to the created document and the document is
1064      * published in the scenario. The publication of the old version is removed
1065      * from the scenario.
1066      * 
1067      * @param step
1068      *            the destination scenario step
1069      * @param file
1070      *            the FilDTO to checkin
1071      * @param docId
1072      *            target document id
1073      * @param aUser
1074      *            the user who performs checkin
1075      * @param resType
1076      *            the result document type of the given step
1077      * @param aDate
1078      *            timestamp of the checkin operation
1079      * @param newVersion
1080      *            the mapping of existing documents to their new created
1081      *            versions
1082      * @param newVers
1083      *            the list of publications of new created versions of existing
1084      *            documents
1085      * @param newDocs
1086      *            the list of publications of new created documents not existing
1087      *            before the checkin
1088      * @return the newly created publication, if exists (the document has been
1089      *         created or versioned), null otherwise (the doc has been attached
1090      *         to the old one)
1091      * @throws InvalidPropertyException
1092      *             if the scenario hasn't some of given steps or documents
1093      * @throws IOException
1094      *             if a file can't be moved into the vault
1095      * @throws MismatchException
1096      *             if version creation in some of steps is failed
1097      * @throws MissedPropertyException
1098      *             if some mandatory property is missed when new document or new
1099      *             document version is created
1100      * @throws MultiplyDefinedException
1101      *             if some property is defined several times when new document
1102      *             or new document version is created
1103      * @throws NotApplicableException
1104      *             if failed saving of a new publication with a given state
1105      */
1106     private Publication checkinDoc(final Step step, final FileDTO file,
1107             final long docId, final User aUser, final DocumentType resType,
1108             final Date aDate, final Map<Document, Document> newVersion,
1109             final List<Publication> newVers, final List<Publication> newDocs)
1110             throws InvalidPropertyException, MismatchException,
1111             MissedPropertyException, MultiplyDefinedException, IOException,
1112             NotApplicableException {
1113         Publication newPub = null;
1114         if (file != null) {
1115             Document.Properties dprop = new Document.Properties();
1116             // NOTE: Process only the first attached file for each document
1117             dprop.setLocalPath(file.getPath());
1118
1119             // Get document title as the file name
1120             java.io.File upfile = new java.io.File(file.getPath());
1121             String fileFormat = upfile.getName().substring(
1122                     upfile.getName().lastIndexOf('.') + 1);
1123
1124             // Attach the file via ConvertsRelation, create a new document or
1125             // create a new version of the document
1126             dprop.setAuthor(aUser).setDate(aDate).setFormat(fileFormat);
1127             String authorName = I18nUtils.getMessageLocaleDefault(aUser
1128                     .getDisplayName());
1129             String summary = I18nUtils.getMessageLocaleDefault(
1130                     MessageKeyEnum.DCT_000005.toString(), authorName);
1131             dprop.setDescription(summary);
1132
1133             if (docId > 0) {
1134                 newPub = checkinExistingDoc(step, docId, dprop, fileFormat,
1135                         upfile, newVersion, newVers);
1136             } else {
1137
1138                 // Otherwise create a new document of the result type
1139                 // If result type is not found try to get type by file extension
1140                 if (resType == null) {
1141                     dprop.setType(getProjectSettings().getDefaultDocumentType(
1142                             step.getStep(), fileFormat));
1143                 } else {
1144                     dprop.setType(resType);
1145                 }
1146                 // New document title generation as <document type name>_N
1147                 String docname = dprop.getType().getName();
1148                 int i = 1;
1149                 for (Publication scenPub : step.getOwner().getDocums()) {
1150                     if (scenPub.value().getTitle().startsWith(docname)) {
1151                         i++;
1152                     }
1153                 }
1154                 docname += "_" + i; // The generated new document title
1155
1156                 dprop.setName(docname);
1157                 newPub = getStepService().createDocument(step, dprop);
1158
1159                 // Remember the new document
1160                 newDocs.add(newPub);
1161
1162                 saveFile(newPub, step, upfile);
1163             }
1164         }
1165         return newPub;
1166     }
1167
1168     /**
1169      * Check in existing document.
1170      * 
1171      * @param step
1172      *            study step to check in
1173      * @param docId
1174      *            target document id
1175      * @param dprop
1176      *            document properties
1177      * @param fileFormat
1178      *            checked in file format
1179      * @param upfile
1180      *            the file to check in
1181      * @param newVersion
1182      *            the map of created versions during this check in
1183      * @param newVers
1184      *            the list of new versions created during this check in
1185      * @return the newly created publication, if exists (the document has been
1186      *         versioned), null otherwise (the doc has been attached to the old
1187      *         one)
1188      * @throws InvalidPropertyException
1189      *             if publication of the document is not found in the step
1190      * @throws MismatchException
1191      *             if the found publication does not point to a document
1192      * @throws IOException
1193      *             if can not move the file into the vault
1194      * @throws MultiplyDefinedException
1195      *             thrown by versionDocument
1196      * @throws MissedPropertyException
1197      *             thrown by versionDocument
1198      * @throws NotApplicableException
1199      *             if failed saving of a new publication with a given state
1200      */
1201     private Publication checkinExistingDoc(final Step step, final long docId,
1202             final Properties dprop, final String fileFormat,
1203             final java.io.File upfile,
1204             final Map<Document, Document> newVersion,
1205             final List<Publication> newVers) throws InvalidPropertyException,
1206             MismatchException, MissedPropertyException,
1207             MultiplyDefinedException, IOException, NotApplicableException {
1208         // If the document already exists then
1209         // Attach the file via ConvertsRelation if the extension of the
1210         // new file differs from the old one.
1211         // If file format (i.e. extension) is the same then create a new
1212         // version of the document.
1213         // Find the document publication
1214         // Publication pub = step.getDocument(doc.getId());
1215         Publication pub = step.getDocument(docId);
1216         Publication newPub = null;
1217         if (pub == null) {
1218             throw new InvalidPropertyException(
1219                     MessageKeyEnum.SCN_000002.toString(), docId);
1220         }
1221         if (pub.value() == null) {
1222             throw new MismatchException(MessageKeyEnum.SCN_000002.toString(),
1223                     docId);
1224         }
1225         if (LOG.isDebugEnabled()) {
1226             LOG.debug("Old format: " + pub.value().getFormat()
1227                     + " => New format: " + fileFormat);
1228         }
1229         // If formats are same then create a new document version
1230         if (pub.value().getFormat() != null
1231                 && pub.value().getFormat().equals(fileFormat)) {
1232             newPub = getStepService().versionDocument(step, pub, dprop);
1233             if (LOG.isDebugEnabled()) {
1234                 LOG.debug("Created document type: "
1235                         + newPub.value().getType().getName() + ", format: "
1236                         + newPub.value().getFormat());
1237             }
1238             // Remeber the link from the old document to the new document
1239             // version
1240             newVersion.put(pub.value(), newPub.value());
1241             // Remember the new version publication
1242             newVers.add(newPub);
1243
1244             saveFile(newPub, step, upfile);
1245
1246         } else { // If formats are different then attach the new file via
1247                  // ConvertsRelation
1248             File attach = pub.value().getAttachedFile(fileFormat);
1249             if (attach == null) {
1250                 // If there is no attachment with this extension then attach the
1251                 // new one
1252                 ConvertsRelation export = getPublicationService().attach(pub,
1253                         fileFormat);
1254                 moveFile(upfile, export.getTo().asFile());
1255             } else {
1256                 // If an attachment with this extension already exists then
1257                 // replace it by the new one
1258                 moveFile(upfile, attach.asFile());
1259                 // Update attached file modification date
1260                 attach.setDate(new Date());
1261             }
1262         }
1263         return newPub;
1264     }
1265
1266     /**
1267      * Save the file in the vault and create its publication in the step.
1268      * 
1269      * @param newPub
1270      *            the new publication to save
1271      * @param step
1272      *            the study step to publish the document
1273      * @param upfile
1274      *            the downloaded file
1275      * @throws IOException
1276      *             if a file can't be moved into the vault
1277      * @throws NotApplicableException
1278      *             if failed saving of a new publication with a given state
1279      */
1280     private void saveFile(final Publication newPub, final Step step,
1281             final java.io.File upfile) throws IOException,
1282             NotApplicableException {
1283         // Attach the file to the created document
1284         java.io.File updir = newPub.getSourceFile().asFile();
1285         if (updir.exists()) {
1286             if (updir.delete()) {
1287                 LOG.info(MessageKeyEnum.SCN_000003.toString(),
1288                         updir.getAbsoluteFile(), step.getOwner().getIndex());
1289             } else {
1290                 throw new IOException(
1291                         "Can't delete the existing destination file to move file from "
1292                                 + upfile.getAbsolutePath() + TO
1293                                 + updir.getAbsolutePath());
1294             }
1295         }
1296         if (moveFile(upfile, updir)) {
1297             // Save the new publication in the scenario.
1298             // The old publication is removed from the scenario here.
1299             getPublicationService().saveAs(newPub, ProgressState.inWORK); // May
1300                                                                           // throw
1301                                                                           // FileNotFound
1302                                                                           // if
1303                                                                           // rename
1304                                                                           // was
1305                                                                           // not
1306                                                                           // done
1307         } else {
1308             throw new IOException("Can't move file from "
1309                     + upfile.getAbsolutePath() + TO + updir.getAbsolutePath());
1310         }
1311     }
1312
1313     /**
1314      * Find appropriate step in the array of scenario steps according to the
1315      * given step DTO.
1316      * 
1317      * @param stepDTO
1318      *            the stepDTO
1319      * @param steps
1320      *            scenario steps
1321      * @return appropriate scenario step
1322      * @throws InvalidPropertyException
1323      *             if appropriate step is not found
1324      */
1325     private Step findStep(final StepDTO stepDTO, final Step[] steps)
1326             throws InvalidPropertyException {
1327         int i = 0;
1328         Step step = null;
1329         do {
1330             if (steps[i].getNumber() == stepDTO.getNumber()) {
1331                 step = steps[i];
1332             }
1333             i++;
1334         } while ((step == null) && (i < steps.length));
1335
1336         if (step == null) {
1337             throw new InvalidPropertyException(
1338                     MessageKeyEnum.SCN_000001.toString(), stepDTO.getNumber());
1339         }
1340         return step;
1341     }
1342
1343     /**
1344      * {@inheritDoc}
1345      * 
1346      * @see org.splat.service.ScenarioService#checkin(long)
1347      */
1348     @Transactional
1349     public void checkin(final long scenarioId) throws InvalidPropertyException {
1350         Scenario aScenario = getScenarioDAO().get(scenarioId);
1351         if (aScenario == null) {
1352             // Scenario not found
1353             throw new InvalidPropertyException(
1354                     MessageKeyEnum.SCN_000006.toString(), scenarioId);
1355         }
1356         checkin(aScenario);
1357     }
1358
1359     /**
1360      * Mark the scenario as checked in.
1361      * 
1362      * @param aScenario
1363      *            the scenario to check in.
1364      */
1365     private void checkin(final Scenario aScenario) {
1366         aScenario.setUser(null);
1367         aScenario.setLastModificationDate(Calendar.getInstance().getTime());
1368         // getScenarioDAO().update(aScenario);
1369     }
1370
1371     /**
1372      * {@inheritDoc}
1373      * 
1374      * @see org.splat.service.ScenarioService#checkout(org.splat.dal.bo.som.Scenario,
1375      *      org.splat.dal.bo.kernel.User)
1376      */
1377     public boolean checkout(final Scenario aScenario, final User user) {
1378         boolean res = getStudyService().isStaffedBy(aScenario.getOwnerStudy(),
1379                 user);
1380         if (res) {
1381             aScenario.setUser(user);
1382             aScenario.setLastModificationDate(Calendar.getInstance().getTime());
1383             // RKV: getScenarioDAO().update(aScenario);
1384         }
1385         return res;
1386     }
1387
1388     /**
1389      * Mark the given scenario as checked out by the given user.
1390      * 
1391      * @param scenarioId
1392      *            the scenario id
1393      * @param userId
1394      *            the id of the user performing the check out
1395      * @throws InvalidPropertyException
1396      *             if the user or the scenario is not found in the database
1397      * @throws NotApplicableException
1398      *             if the given user can not check out the scenario
1399      */
1400     @Transactional
1401     public void checkout(final long scenarioId, final long userId)
1402             throws InvalidPropertyException, NotApplicableException {
1403         User aUser = getUserService().selectUser(userId);
1404         if (aUser == null) {
1405             // User not found
1406             throw new InvalidPropertyException(
1407                     MessageKeyEnum.USR_000001.toString(), userId);
1408         }
1409         Scenario aScenario = getScenarioDAO().get(scenarioId);
1410         if (aScenario == null) {
1411             // Scenario not found
1412             throw new InvalidPropertyException(
1413                     MessageKeyEnum.SCN_000006.toString(), scenarioId);
1414         }
1415         boolean res = getStudyService().isStaffedBy(aScenario.getOwnerStudy(),
1416                 aUser);
1417         if (res) {
1418             if (aScenario.isCheckedout()
1419                     && (!aScenario.getUser().getUsername()
1420                             .equals(aUser.getUsername()))) {
1421                 throw new NotApplicableException(
1422                         MessageKeyEnum.SCN_000008.toString(), scenarioId,
1423                         aScenario.getUser().getUsername());
1424             }
1425             aScenario.setUser(aUser);
1426             aScenario.setLastModificationDate(Calendar.getInstance().getTime());
1427         } else {
1428             // User doesn't participate in the scenario
1429             throw new NotApplicableException(
1430                     MessageKeyEnum.SCN_000007.toString(), aUser.getUsername(),
1431                     scenarioId);
1432         }
1433     }
1434
1435     /**
1436      * {@inheritDoc}
1437      * 
1438      * @see org.splat.service.ScenarioService#copyContentsUpTo(org.splat.dal.bo.som.Scenario,
1439      *      org.splat.som.Step)
1440      */
1441     public void copyContentsUpTo(final Scenario scenario, final Step lastep) {
1442         Scenario base = (Scenario) lastep.getOwner();
1443         Step[] from = getProjectElementService().getSteps(base);
1444         Step[] to = getProjectElementService().getSteps(scenario);
1445         for (int i = 0; i < from.length; i++) {
1446             Step step = from[i];
1447             if (step.getNumber() > lastep.getNumber()) {
1448                 break;
1449             }
1450
1451             List<Publication> docs = step.getAllDocuments();
1452             for (Iterator<Publication> j = docs.iterator(); j.hasNext();) {
1453                 Publication doc = getPublicationService().copy(j.next(),
1454                         scenario); // Creation of a new reference to the
1455                                    // document
1456                 // Database.getSession().save(doc); Publications MUST be saved
1457                 // later through cascading when saving the scenario
1458                 getStepService().add(to[i], doc);
1459             }
1460             List<SimulationContext> ctex = step.getAllSimulationContexts();
1461             for (Iterator<SimulationContext> j = ctex.iterator(); j.hasNext();) {
1462                 getStepService().addSimulationContext(to[i], j.next());
1463             }
1464         }
1465     }
1466
1467     /**
1468      * {@inheritDoc}
1469      * 
1470      * @see org.splat.service.ScenarioService#isEmpty(org.splat.dal.bo.som.Scenario)
1471      */
1472     public boolean isEmpty(final Scenario scenario) {
1473         Step[] mystep = getProjectElementService().getSteps(scenario);
1474         boolean isEmp = true;
1475         for (int i = 0; i < mystep.length; i++) {
1476             if (mystep[i].isStarted()) {
1477                 isEmp = false;
1478                 break;
1479             }
1480         }
1481         return isEmp;
1482     }
1483
1484     /**
1485      * @param scenario
1486      * @return
1487      */
1488     public boolean isFinished(final Scenario scenario) {
1489         Step[] mystep = getProjectElementService().getSteps(scenario);
1490         boolean notempty = false; // If this is empty, this is not finished
1491         for (int i = 0; i < mystep.length; i++) {
1492             if (!mystep[i].isStarted()) {
1493                 continue;
1494             }
1495             if (!mystep[i].isFinished()) {
1496                 return false;
1497             }
1498             notempty = true;
1499         }
1500         return notempty;
1501     }
1502
1503     /**
1504      * {@inheritDoc}
1505      * 
1506      * @see org.splat.service.StudyService#addScenario(org.splat.dal.bo.som.Study,
1507      *      org.splat.dal.bo.som.Scenario.Properties)
1508      */
1509     @Transactional
1510     public Scenario addScenario(final Study aStudy,
1511             final Scenario.Properties sprop) throws MissedPropertyException,
1512             InvalidPropertyException, MultiplyDefinedException {
1513         if (sprop.getManager() == null) {
1514             sprop.setManager(aStudy.getAuthor());
1515         }
1516
1517         Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy));
1518         if (sprop.getBaseStep() != null) {
1519             copyContentsUpTo(scenario, sprop.getBaseStep());
1520         }
1521         Scenario previous = sprop.getInsertAfter();
1522
1523         if (previous == null) {
1524             aStudy.getScenariiList().add(scenario);
1525         } else {
1526             aStudy.getScenariiList().add(
1527                     aStudy.getScenariiList().indexOf(previous) + 1, scenario);
1528         }
1529         getStudyDAO().update(aStudy); // No need to update the Lucene index
1530         getScenarioDAO().create(scenario); // Must be done after updating this
1531                                            // study because of the back
1532                                            // reference to the study
1533         if (sprop.getBaseStep() != null) {
1534             // No need to update the Knowledge Element index as Knowledge
1535             // Elements are not copied
1536             getProjectElementService().refresh(scenario); // Because saving the
1537                                                           // scenario changes
1538                                                           // the hashcode of
1539                                                           // copied Publications
1540         }
1541         KnowledgeElementType ucase = getKnowledgeElementTypeService()
1542                 .selectType("usecase");
1543         KnowledgeElement.Properties kprop = new KnowledgeElement.Properties();
1544         // TODO: Get appropriate user by its role: UserService.getAdmin();
1545         // User admin = getUserService().selectUser(1); // First user created
1546         // when creating the database
1547         Role adminRole = getRoleDAO().getFilteredList(
1548                 Restrictions.like("role", "%sysadmin%")).get(0);
1549         User admin = getUserDAO().getFilteredList(
1550                 Restrictions.eq("role", adminRole), Order.asc("rid")).get(0); // First
1551                                                                               // sysadmin
1552                                                                               // in
1553                                                                               // the
1554                                                                               // database
1555
1556         kprop.setType(ucase).setTitle(aStudy.getTitle())
1557                 .setValue(scenario.getTitle()).setAuthor(admin); // Internal
1558                                                                  // Knowledge
1559                                                                  // Element
1560                                                                  // required by
1561                                                                  // the
1562                                                                  // validation
1563                                                                  // process of
1564         // knowledges
1565         addKnowledgeElement(scenario, kprop);
1566         return scenario;
1567     }
1568
1569     /**
1570      * Remove a knowledge element from a scenario.
1571      * 
1572      * @param scenario
1573      *            the scenario
1574      * @param kelm
1575      *            the knowledge element to remove
1576      * @return true if removal succeeded
1577      */
1578     @Transactional
1579     public boolean removeKnowledgeElement(final Scenario scenario,
1580             final KnowledgeElement kelm) {
1581         KnowledgeElement torem = scenario.getKnowledgeElement(kelm.getIndex());
1582         boolean isOk = (torem != null);
1583         if (isOk) {
1584             isOk = scenario.getKnowledgeElements().remove(torem);
1585             if (isOk) {
1586                 getScenarioDAO().merge(scenario);
1587                 // Update of my transient data
1588                 // RKV: These transient data are not used indeed.
1589                 // RKV: List<KnowledgeElement> kelms =
1590                 // scenario.getKnowledgeByType().get(
1591                 // RKV: kelm.getType().getIndex());
1592                 // RKV: kelms.remove(torem);
1593                 if (scenario.getKnowledgeElementsList() != null) {
1594                     scenario.getKnowledgeElementsList().remove(torem);
1595                 }
1596                 // TODO: If the owner study is not private, remove the knowledge
1597                 // from the Lucene index
1598             }
1599         }
1600         return isOk;
1601     }
1602
1603     /**
1604      * 
1605      * {@inheritDoc}
1606      * 
1607      * @see org.splat.service.ScenarioService#renameScenario(java.lang.String)
1608      */
1609     @Transactional
1610     public void renameScenario(final Scenario scenario) {
1611         getScenarioDAO().merge(scenario);
1612     }
1613
1614     /**
1615      * {@inheritDoc}
1616      * 
1617      * @see org.splat.service.ScenarioService#removeScenario(long)
1618      */
1619     @Transactional
1620     public void removeScenario(final long scenarioId) {
1621         Scenario scenario = getScenarioDAO().get(scenarioId);
1622         Study study = scenario.getOwnerStudy();
1623
1624         if (scenario != null && study != null) {
1625             getScenarioDAO().delete(scenario);
1626
1627             // Collect all documents which are published in another scenario
1628             // or are previous versions of documents published in another
1629             // scenario
1630             Set<Document> untouched = new HashSet<Document>();
1631
1632             List<Scenario> otherScenarios = study.getScenariiList();
1633             otherScenarios.remove(scenario);
1634
1635             for (Scenario otherScenario : otherScenarios) {
1636                 for (Publication publication : otherScenario.getDocums()) {
1637                     for (Document document = publication.value(); document != null; document = document
1638                             .getPreviousVersion()) {
1639                         untouched.add(document);
1640                     }
1641                 }
1642             }
1643
1644             // Collect all documents which are published in this scenario
1645             // or are previous versions of documents published in this scenario
1646             Set<Document> toRemove = new HashSet<Document>();
1647             for (Publication publication : scenario.getDocums()) {
1648                 for (Document document = publication.value(); document != null; document = document
1649                         .getPreviousVersion()) {
1650                     toRemove.add(document);
1651                 }
1652             }
1653
1654             toRemove.removeAll(untouched);
1655
1656             // Delete all necessary documents
1657             for (Document document : toRemove) {
1658                 _documentDAO.delete(document);
1659             }
1660         }
1661     }
1662
1663     /**
1664      * Get the knowledgeElementDAO.
1665      * 
1666      * @return the knowledgeElementDAO
1667      */
1668     public KnowledgeElementDAO getKnowledgeElementDAO() {
1669         return _knowledgeElementDAO;
1670     }
1671
1672     /**
1673      * Set the knowledgeElementDAO.
1674      * 
1675      * @param knowledgeElementDAO
1676      *            the knowledgeElementDAO to set
1677      */
1678     public void setKnowledgeElementDAO(
1679             final KnowledgeElementDAO knowledgeElementDAO) {
1680         _knowledgeElementDAO = knowledgeElementDAO;
1681     }
1682
1683     /**
1684      * Get the indexService.
1685      * 
1686      * @return the indexService
1687      */
1688     public IndexService getIndexService() {
1689         return _indexService;
1690     }
1691
1692     /**
1693      * Set the indexService.
1694      * 
1695      * @param indexService
1696      *            the indexService to set
1697      */
1698     public void setIndexService(final IndexService indexService) {
1699         _indexService = indexService;
1700     }
1701
1702     /**
1703      * Get the scenarioDAO.
1704      * 
1705      * @return the scenarioDAO
1706      */
1707     public ScenarioDAO getScenarioDAO() {
1708         return _scenarioDAO;
1709     }
1710
1711     /**
1712      * Set the scenarioDAO.
1713      * 
1714      * @param scenarioDAO
1715      *            the scenarioDAO to set
1716      */
1717     public void setScenarioDAO(final ScenarioDAO scenarioDAO) {
1718         _scenarioDAO = scenarioDAO;
1719     }
1720
1721     /**
1722      * Get the studyDAO.
1723      * 
1724      * @return the studyDAO
1725      */
1726     public StudyDAO getStudyDAO() {
1727         return _studyDAO;
1728     }
1729
1730     /**
1731      * Set the studyDAO.
1732      * 
1733      * @param studyDAO
1734      *            the studyDAO to set
1735      */
1736     public void setStudyDAO(final StudyDAO studyDAO) {
1737         _studyDAO = studyDAO;
1738     }
1739
1740     /**
1741      * Get the knowledgeElementTypeService.
1742      * 
1743      * @return the knowledgeElementTypeService
1744      */
1745     public KnowledgeElementTypeService getKnowledgeElementTypeService() {
1746         return _knowledgeElementTypeService;
1747     }
1748
1749     /**
1750      * Set the knowledgeElementTypeService.
1751      * 
1752      * @param knowledgeElementTypeService
1753      *            the knowledgeElementTypeService to set
1754      */
1755     public void setKnowledgeElementTypeService(
1756             final KnowledgeElementTypeService knowledgeElementTypeService) {
1757         _knowledgeElementTypeService = knowledgeElementTypeService;
1758     }
1759
1760     /**
1761      * Get the studyService.
1762      * 
1763      * @return the studyService
1764      */
1765     public StudyService getStudyService() {
1766         return _studyService;
1767     }
1768
1769     /**
1770      * Set the studyService.
1771      * 
1772      * @param studyService
1773      *            the studyService to set
1774      */
1775     public void setStudyService(final StudyService studyService) {
1776         _studyService = studyService;
1777     }
1778
1779     /**
1780      * Get the userService.
1781      * 
1782      * @return the userService
1783      */
1784     public UserService getUserService() {
1785         return _userService;
1786     }
1787
1788     /**
1789      * Set the userService.
1790      * 
1791      * @param userService
1792      *            the userService to set
1793      */
1794     public void setUserService(final UserService userService) {
1795         _userService = userService;
1796     }
1797
1798     /**
1799      * Get the userDAO.
1800      * 
1801      * @return the userDAO
1802      */
1803     public UserDAO getUserDAO() {
1804         return _userDAO;
1805     }
1806
1807     /**
1808      * Set the userDAO.
1809      * 
1810      * @param userDAO
1811      *            the userDAO to set
1812      */
1813     public void setUserDAO(final UserDAO userDAO) {
1814         _userDAO = userDAO;
1815     }
1816
1817     /**
1818      * Get the knowledgeElementTypeDAO.
1819      * 
1820      * @return the knowledgeElementTypeDAO
1821      */
1822     public KnowledgeElementTypeDAO getKnowledgeElementTypeDAO() {
1823         return _knowledgeElementTypeDAO;
1824     }
1825
1826     /**
1827      * Set the knowledgeElementTypeDAO.
1828      * 
1829      * @param knowledgeElementTypeDAO
1830      *            the knowledgeElementTypeDAO to set
1831      */
1832     public void setKnowledgeElementTypeDAO(
1833             final KnowledgeElementTypeDAO knowledgeElementTypeDAO) {
1834         _knowledgeElementTypeDAO = knowledgeElementTypeDAO;
1835     }
1836
1837     /**
1838      * Get the documentDAO.
1839      * 
1840      * @return the documentDAO
1841      */
1842     public DocumentDAO getDocumentDAO() {
1843         return _documentDAO;
1844     }
1845
1846     /**
1847      * Set the documentDAO.
1848      * 
1849      * @param documentDAO
1850      *            the documentDAO to set
1851      */
1852     public void setDocumentDAO(final DocumentDAO documentDAO) {
1853         _documentDAO = documentDAO;
1854     }
1855
1856     /**
1857      * Get the simulationContextService.
1858      * 
1859      * @return the simulationContextService
1860      */
1861     public SimulationContextService getSimulationContextService() {
1862         return _simulationContextService;
1863     }
1864
1865     /**
1866      * Set the simulationContextService.
1867      * 
1868      * @param simulationContextService
1869      *            the simulationContextService to set
1870      */
1871     public void setSimulationContextService(
1872             final SimulationContextService simulationContextService) {
1873         _simulationContextService = simulationContextService;
1874     }
1875
1876     /**
1877      * Get project settings.
1878      * 
1879      * @return Project settings service
1880      */
1881     private ProjectSettingsService getProjectSettings() {
1882         return _projectSettings;
1883     }
1884
1885     /**
1886      * Set project settings service.
1887      * 
1888      * @param projectSettingsService
1889      *            project settings service
1890      */
1891     public void setProjectSettings(
1892             final ProjectSettingsService projectSettingsService) {
1893         _projectSettings = projectSettingsService;
1894     }
1895
1896     /**
1897      * Get the documentTypeService.
1898      * 
1899      * @return the documentTypeService
1900      */
1901     public DocumentTypeService getDocumentTypeService() {
1902         return _documentTypeService;
1903     }
1904
1905     /**
1906      * Set the documentTypeService.
1907      * 
1908      * @param documentTypeService
1909      *            the documentTypeService to set
1910      */
1911     public void setDocumentTypeService(
1912             final DocumentTypeService documentTypeService) {
1913         _documentTypeService = documentTypeService;
1914     }
1915
1916     /**
1917      * Get the roleDAO.
1918      * 
1919      * @return the roleDAO
1920      */
1921     public RoleDAO getRoleDAO() {
1922         return _roleDAO;
1923     }
1924
1925     /**
1926      * Set the roleDAO.
1927      * 
1928      * @param roleDAO
1929      *            the roleDAO to set
1930      */
1931     public void setRoleDAO(final RoleDAO roleDAO) {
1932         _roleDAO = roleDAO;
1933     }
1934
1935     /**
1936      * Get the simulationContextTypeService.
1937      * 
1938      * @return the simulationContextTypeService
1939      */
1940     public SimulationContextTypeService getSimulationContextTypeService() {
1941         return _simulationContextTypeService;
1942     }
1943
1944     /**
1945      * Set the simulationContextTypeService.
1946      * 
1947      * @param simulationContextTypeService
1948      *            the simulationContextTypeService to set
1949      */
1950     public void setSimulationContextTypeService(
1951             final SimulationContextTypeService simulationContextTypeService) {
1952         _simulationContextTypeService = simulationContextTypeService;
1953     }
1954
1955     /**
1956      * Get the validationCycleDAO.
1957      * 
1958      * @return the validationCycleDAO
1959      */
1960     public ValidationCycleDAO getValidationCycleDAO() {
1961         return _validationCycleDAO;
1962     }
1963
1964     /**
1965      * Set the validationCycleDAO.
1966      * 
1967      * @param validationCycleDAO
1968      *            the validationCycleDAO to set
1969      */
1970     public void setValidationCycleDAO(
1971             final ValidationCycleDAO validationCycleDAO) {
1972         _validationCycleDAO = validationCycleDAO;
1973     }
1974
1975     /**
1976      * Get steps config.
1977      * 
1978      * @return steps config service
1979      */
1980     private StepsConfigService getStepsConfigService() {
1981         return _stepsConfigService;
1982     }
1983
1984     /**
1985      * Set steps config service.
1986      * 
1987      * @param stepsConfigService
1988      *            steps config service
1989      */
1990     public void setStepsConfigService(
1991             final StepsConfigService stepsConfigService) {
1992         _stepsConfigService = stepsConfigService;
1993     }
1994
1995     /**
1996      * Get the repositoryService.
1997      * 
1998      * @return the repositoryService
1999      */
2000     public RepositoryService getRepositoryService() {
2001         return _repositoryService;
2002     }
2003
2004     /**
2005      * Set the repositoryService.
2006      * 
2007      * @param repositoryService
2008      *            the repositoryService to set
2009      */
2010     public void setRepositoryService(final RepositoryService repositoryService) {
2011         _repositoryService = repositoryService;
2012     }
2013 }