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