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