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