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