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