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