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