Salome HOME
Creation of a new study is fixed. Database.getSessoin is not used now during creation...
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / StudyServiceImpl.java
1 /*****************************************************************************
2  * Company         EURIWARE
3  * Application     SIMAN
4  * File            Id: 
5  * Creation date   02.10.2012
6  * @author         Author: Maria KRUCHININA
7  * @version        Revision: 
8  *****************************************************************************/
9
10 package org.splat.service;
11
12 import java.io.IOException;
13 import java.text.SimpleDateFormat;
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
20 import org.hibernate.criterion.Restrictions;
21 import org.splat.dal.bo.kernel.Relation;
22 import org.splat.dal.bo.kernel.User;
23 import org.splat.dal.bo.som.ActorRelation;
24 import org.splat.dal.bo.som.ContributorRelation;
25 import org.splat.dal.bo.som.DescriptionAttribute;
26 import org.splat.dal.bo.som.Document;
27 import org.splat.dal.bo.som.DocumentType;
28 import org.splat.dal.bo.som.IDBuilder;
29 import org.splat.dal.bo.som.KnowledgeElement;
30 import org.splat.dal.bo.som.KnowledgeElementType;
31 import org.splat.dal.bo.som.ProgressState;
32 import org.splat.dal.bo.som.Publication;
33 import org.splat.dal.bo.som.Scenario;
34 import org.splat.dal.bo.som.SimulationContext;
35 import org.splat.dal.bo.som.Study;
36 import org.splat.dal.bo.som.ValidationCycle;
37 import org.splat.dal.bo.som.ValidationCycleRelation;
38 import org.splat.dal.bo.som.Visibility;
39 import org.splat.dal.bo.som.Study.Properties;
40 import org.splat.dal.dao.som.IDBuilderDAO;
41 import org.splat.dal.dao.som.ScenarioDAO;
42 import org.splat.dal.dao.som.StudyDAO;
43 import org.splat.kernel.InvalidPropertyException;
44 import org.splat.kernel.MissedPropertyException;
45 import org.splat.kernel.MultiplyDefinedException;
46 import org.splat.kernel.UserDirectory;
47 import org.splat.log.AppLogger;
48 import org.splat.service.technical.IndexService;
49 import org.splat.service.technical.ProjectSettingsService;
50 import org.splat.som.Revision;
51 import org.springframework.transaction.annotation.Transactional;
52
53 /**
54  * This class defines all methods for creation, modification the study.
55  * 
56  * @author Maria KRUCHININA
57  * 
58  */
59 public class StudyServiceImpl implements StudyService {
60
61         /**
62          * logger for the service.
63          */
64         public final static AppLogger logger = AppLogger
65                         .getLogger(StudyServiceImpl.class);
66
67         /**
68          * Injected index service.
69          */
70         private IndexService _indexService;
71
72         /**
73          * Injected step service.
74          */
75         private StepService _stepService;
76
77         /**
78          * Injected scenario service.
79          */
80         private ScenarioService _scenarioService;
81
82         /**
83          * Injected project service.
84          */
85         private ProjectSettingsService _projectSettingsService;
86
87         /**
88          * Injected project element service.
89          */
90         private ProjectElementService _projectElementService;
91
92         /**
93          * Injected study DAO.
94          */
95         private StudyDAO _studyDAO;
96
97         /**
98          * Injected scenario DAO.
99          */
100         private ScenarioDAO _scenarioDAO;
101
102         /**
103          * Injected IDBuilder DAO.
104          */
105         private IDBuilderDAO _iDBuilderDAO;
106
107         /**
108          * {@inheritDoc}
109          * 
110          * @see org.splat.service.StudyService#selectStudy(long)
111          */
112         @Transactional
113         public Study selectStudy(long index) {
114                 Study result = getStudyDAO().get(index);
115                 result.loadWorkflow();
116                 return result;
117         }
118
119         /**
120          * Get study by its reference.
121          * 
122          * @param refid
123          *            the study reference
124          * @return found study or null
125          */
126         @Transactional(readOnly = true)
127         public Study selectStudy(String refid) {
128                 Study result = getStudyDAO().findByCriteria(
129                                 Restrictions.eq("sid", refid));
130                 result.loadWorkflow();
131                 return result;
132         }
133
134         /**
135          * {@inheritDoc}
136          * 
137          * @see org.splat.service.StudyService#createStudy(org.splat.dal.bo.som.Study.Properties)
138          */
139         @Transactional
140         public Study createStudy(Study.Properties sprop)
141                         throws MissedPropertyException, InvalidPropertyException,
142                         MultiplyDefinedException {
143                 sprop.setReference(getProjectSettings().getReferencePattern());
144                 Study study = new Study(sprop);
145
146                 buildReference(study);
147                 getStudyDAO().create(study);
148                 try {
149                         IndexService lucin = getIndex();
150                         lucin.add(study);
151                 } catch (IOException error) {
152                         logger.error("Unable to index the study '" + study.getIndex()
153                                         + "', reason:", error);
154                         // Continue and try to index later
155                 }
156                 return study;
157         }
158
159         /**
160          * {@inheritDoc}
161          * 
162          * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext.Properties)
163          */
164         public SimulationContext addProjectContext(Study aStudy,
165                         SimulationContext.Properties cprop) throws MissedPropertyException,
166                         InvalidPropertyException, MultiplyDefinedException {
167                 SimulationContext added = getStepService().addSimulationContext(
168                                 getProjectElementService().getFirstStep(aStudy), cprop);
169                 update(aStudy);
170                 return added;
171         }
172
173         /**
174          * {@inheritDoc}
175          * 
176          * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
177          */
178         public SimulationContext addProjectContext(Study aStudy,
179                         SimulationContext context) {
180                 SimulationContext added = getStepService().addSimulationContext(
181                                 getProjectElementService().getFirstStep(aStudy), context);
182                 update(aStudy);
183                 return added;
184         }
185
186         /**
187          * {@inheritDoc}
188          * 
189          * @see org.splat.service.StudyService#addContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User)
190          */
191         public boolean addContributor(Study aStudy, User user) {
192                 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
193                 for (Iterator<User> i = contributor.iterator(); i.hasNext();) {
194                         User present = i.next();
195                         if (present.equals(user))
196                                 return false;
197                 }
198                 boolean absent = aStudy.getModifiableActors().add(user); // User may already be a reviewer or an approver
199
200                 aStudy.addRelation(new ContributorRelation(aStudy, user));
201                 if (absent)
202                         update(aStudy); // Else, useless to re-index the study
203                 contributor.add(user);
204                 return true;
205         }
206
207         /**
208          * Moves this study from the Public to the Reference area of the repository. For being moved to the Reference area, the study must
209          * previously be approved.
210          * 
211          * @param aStudy
212          *            the study to move
213          * @return true if the move succeeded.
214          * @see #moveToPublic()
215          * @see #isPublic()
216          * @see Publication#approve(Date)
217          */
218         public boolean moveToReference(Study aStudy) {
219                 if (aStudy.getProgressState() != ProgressState.APPROVED)
220                         return false;
221                 if (aStudy.getVisibility() != Visibility.PUBLIC)
222                         return false;
223
224                 aStudy.setVisibility(Visibility.REFERENCE);
225                 if (update(aStudy)) {
226                         return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
227                 }
228                 return false;
229         }
230
231         /**
232          * {@inheritDoc}
233          * 
234          * @see org.splat.service.StudyService#update(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Study.Properties)
235          */
236         public boolean update(Study aStudy, Properties sprop)
237                         throws InvalidPropertyException {
238                 if (sprop.getTitle() != null)
239                         aStudy.setTitle(sprop.getTitle());
240                 if (sprop.getSummary() != null)
241                         aStudy.setAttribute(new DescriptionAttribute(aStudy, sprop
242                                         .getSummary()));
243                 // TODO: To be completed
244                 return update(aStudy);
245         }
246
247         /**
248          * Check if the document is published in the study.
249          * 
250          * @param aStudy
251          *            the study
252          * @param doc
253          *            the document
254          * @return true if the document is published in the study
255          */
256         private boolean publishes(Study aStudy, Document doc) {
257                 if (!aStudy.publishes(doc)) {
258                         Scenario[] scene = aStudy.getScenarii();
259                         for (int i = 0; i < scene.length; i++) {
260                                 if (scene[i].publishes(doc))
261                                         return true;
262                         }
263                 }
264                 return false;
265         }
266
267         /**
268          * {@inheritDoc}
269          * 
270          * @see org.splat.service.StudyService#removeContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User[])
271          */
272         public boolean removeContributor(Study aStudy, User... users) {
273                 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
274                 Boolean done = false;
275                 for (int i = 0; i < users.length; i++) {
276                         User user = users[i];
277                         for (Iterator<User> j = contributor.iterator(); j.hasNext();) {
278                                 User present = j.next();
279                                 if (!present.equals(user))
280                                         continue;
281
282                                 aStudy.removeRelation(ContributorRelation.class, user);
283                                 j.remove(); // Updates the contributor shortcut
284                                 done = true;
285                                 break;
286                         }
287                 }
288                 if (done)
289                         update(aStudy);
290                 return done;
291         }
292
293         /**
294          * {@inheritDoc}
295          * 
296          * @see org.splat.service.StudyService#removeProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
297          */
298         public boolean removeProjectContext(Study aStudy, SimulationContext context) {
299                 boolean done = getStepService().removeSimulationContext(
300                                 getProjectElementService().getFirstStep(aStudy), context);
301                 update(aStudy);
302                 return done;
303         }
304
305         /**
306          * {@inheritDoc}
307          * 
308          * @see org.splat.service.StudyService#setValidationCycle(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.DocumentType,
309          *      org.splat.dal.bo.som.ValidationCycle.Properties)
310          */
311         public void setValidationCycle(Study aStudy, DocumentType type,
312                         ValidationCycle.Properties vprop) {
313                 HashMap<String, ValidationCycle> validactor = aStudy
314                                 .getValidationCycles();
315                 if (validactor == null)
316                         aStudy.setShortCuts(); // Initializes validactor and actor
317
318                 String cname = type.getName();
319                 ValidationCycle cycle = validactor.get(cname);
320
321                 if (cycle != null && cycle.isAssigned()) {
322                         cycle.resetActors(vprop);
323                 } else
324                         try {
325                                 cycle = new ValidationCycle(aStudy, vprop.setDocumentType(type));
326
327                                 ValidationCycleRelation link = cycle.getContext();
328                                 aStudy.addRelation(link);
329                                 validactor.put(cname, link.getTo()); // Replaces the cycle if exists as default,
330                         } catch (Exception error) {
331                                 logger.error("Unable to re-index Knowledge Elements, reason:",
332                                                 error);
333                                 return;
334                         }
335                 resetActorsShortCut(aStudy);
336                 update(aStudy); // Re-index the study, just in case
337         }
338
339         /**
340          * Demotes this study from In-Check to In-Draft then In-Work states. This function is called internally when demoting the final result
341          * document of the study.
342          * 
343          * @param aStudy
344          *            a study to demote
345          * @return true if the demotion succeeded.
346          */
347         public boolean demote(Study aStudy) {
348                 if (aStudy.getProgressState() == ProgressState.inCHECK)
349                         aStudy.setProgressState(ProgressState.inDRAFT);
350                 else if (aStudy.getProgressState() == ProgressState.inDRAFT)
351                         aStudy.setProgressState(ProgressState.inWORK);
352                 else
353                         return false;
354                 return update(aStudy);
355         }
356
357         /**
358          * {@inheritDoc}
359          * 
360          * @see org.splat.service.StudyService#generateLocalIndex(org.splat.dal.bo.som.Study)
361          */
362         @Transactional
363         public int generateLocalIndex(Study aStudy) {
364                 aStudy.setLastLocalIndex(aStudy.getLastLocalIndex() + 1);
365                 getStudyDAO().update(aStudy);
366                 return aStudy.getLastLocalIndex();
367         }
368
369         /**
370          * {@inheritDoc}
371          * 
372          * @see org.splat.service.StudyService#addScenario(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Scenario.Properties)
373          */
374         @Transactional
375         public Scenario addScenario(Study aStudy, Scenario.Properties sprop)
376                         throws MissedPropertyException, InvalidPropertyException,
377                         MultiplyDefinedException {
378                 if (sprop.getManager() == null)
379                         sprop.setManager(aStudy.getAuthor());
380
381                 Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy));
382                 if (sprop.getBaseStep() != null)
383                         getScenarioService()
384                                         .copyContentsUpTo(scenario, sprop.getBaseStep());
385                 Scenario previous = sprop.getInsertAfter();
386
387                 if (previous == null) {
388                         aStudy.getScenariiList().add(scenario);
389                 } else {
390                         aStudy.getScenariiList().add(
391                                         aStudy.getScenariiList().indexOf(previous) + 1, scenario);
392                 }
393                 getStudyDAO().update(aStudy); // No need to update the Lucene index
394                 getScenarioDAO().create(scenario); // Must be done after updating this study because of the back reference to the study
395                 if (sprop.getBaseStep() != null) {
396                         // No need to update the Knowledge Element index as Knowledge Elements are not copied
397                         scenario.refresh(); // Because saving the scenario changes the hashcode of copied Publications
398                 }
399                 KnowledgeElementType ucase = KnowledgeElement.selectType("usecase");
400                 KnowledgeElement.Properties kprop = new KnowledgeElement.Properties();
401                 User admin = UserDirectory.selectUser(1); // First user created when creating the database
402                 kprop.setType(ucase).setTitle(aStudy.getTitle()).setValue(
403                                 scenario.getTitle()).setAuthor(admin); // Internal Knowledge Element required by the validation process of
404                 // knowledges
405                 getScenarioService().addKnowledgeElement(scenario, kprop);
406                 return scenario;
407         }
408
409         /**
410          * Promotes this study from In-Work to In-Draft then In-Check and APPROVED states. This function is called internally when promoting the
411          * final result document of the study.
412          * 
413          * @param aStudy
414          *            a study to promote
415          * @return true if the demotion succeeded.
416          */
417         public boolean promote(Study aStudy) {
418                 if (aStudy.getProgressState() == ProgressState.inWORK) {
419                         aStudy.setProgressState(ProgressState.inDRAFT);
420                 } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
421                         aStudy.setProgressState(ProgressState.inCHECK);
422                         Revision myvers = new Revision(aStudy.getVersion());
423                         if (myvers.isMinor()) {
424                                 aStudy.setVersion(myvers.incrementAs(aStudy.getProgressState())
425                                                 .toString());
426                         }
427                 } else if (aStudy.getProgressState() == ProgressState.inCHECK) {
428                         aStudy.setProgressState(ProgressState.APPROVED);
429                 } else
430                         return false;
431
432                 return update(aStudy);
433         }
434
435         /**
436          * Moves this study from the Private to the Public area of the repository.
437          * 
438          * @param aStudy
439          *            a study to move
440          * @return true if the move succeeded.
441          * @see #isPublic()
442          */
443         public boolean moveToPublic(Study aStudy) {
444                 boolean isOk = false;
445                 if (aStudy.getVisibility() == Visibility.PRIVATE) {
446                         aStudy.setVisibility(Visibility.PUBLIC);
447                         if (update(aStudy)) {
448                                 isOk = updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
449                         }
450                 }
451                 return isOk;
452         }
453
454         /**
455          * Update a study in the database.
456          * 
457          * @param aStudy
458          *            the study to update
459          * @return true if the study is updated successfully
460          */
461         @Transactional
462         private boolean update(Study aStudy) {
463                 boolean isOk = false;
464                 try {
465                         getStudyDAO().update(aStudy); // Update of relational base
466                         getIndex().update(aStudy); // Update of Lucene index
467                         isOk = true;
468                 } catch (Exception error) {
469                         logger.error("Unable to re-index the study '" + aStudy.getIndex()
470                                         + "', reason:", error);
471                 }
472                 return isOk;
473         }
474
475         /**
476          * Build reference for the study. The reference of the study is stored as a new reference pattern (IDBuilder).
477          * 
478          * @param aStudy
479          *            the study
480          * @return true if reference building is succeded
481          */
482         @Transactional
483         private boolean buildReference(Study aStudy) {
484                 String pattern = aStudy.getReference(); // The study being supposed just created, its reference is the reference pattern
485                 IDBuilder tool = selectIDBuilder(aStudy.getDate());
486                 if (tool == null) {
487                         tool = new IDBuilder(aStudy.getDate());
488                         getIDBuilderDAO().create(tool);
489                 }
490                 aStudy.setReference(tool.buildReference(pattern, aStudy));
491                 return true;
492         }
493
494         /**
495          * Find an id builder by date.
496          * 
497          * @param date
498          *            the date
499          * @return found id builder
500          */
501         private IDBuilder selectIDBuilder(Date date) {
502                 Calendar aDate = Calendar.getInstance();
503                 aDate.setTime(date);
504                 return getIDBuilderDAO().findByCriteria(
505                                 Restrictions.eq("cycle", aDate.get(Calendar.YEAR)));
506         }
507
508         /**
509          * Fill transient collection ModifiableActors of the study.
510          * 
511          * @param aStudy
512          *            the study
513          */
514         private void resetActorsShortCut(Study aStudy) {
515                 aStudy.getModifiableActors().clear();
516                 // Get all actors involved in validation cycles
517                 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
518                                 .values().iterator(); i.hasNext();) {
519                         ValidationCycle cycle = i.next();
520                         User[] user = cycle.getAllActors();
521                         for (int j = 0; j < user.length; j++)
522                                 aStudy.getModifiableActors().add(user[j]);
523                 }
524                 // Get all other actors
525                 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
526                                 .hasNext();) {
527                         Relation link = i.next();
528                         Class<?> kindof = link.getClass().getSuperclass();
529                         if (!kindof.equals(ActorRelation.class))
530                                 continue;
531                         aStudy.getModifiableActors().add(((ActorRelation) link).getTo());
532                 }
533         }
534
535         /**
536          * Update lucene index for the study knowledge elements.
537          * 
538          * @param aStudy
539          *            the study
540          * @return true if reindexing succeeded
541          */
542         private boolean updateKnowledgeElementsIndex(Study aStudy) {
543                 boolean isOk = false;
544                 try {
545                         IndexService lucin = getIndex();
546
547                         for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
548                                         .hasNext();) {
549                                 Scenario scene = i.next();
550                                 for (Iterator<KnowledgeElement> j = scene
551                                                 .getAllKnowledgeElements().iterator(); j.hasNext();) {
552                                         KnowledgeElement kelm = j.next();
553                                         lucin.update(kelm);
554                                 }
555                         }
556                         isOk = true;
557                 } catch (Exception error) {
558                         logger.error("Unable to re-index Knowledge Elements, reason:",
559                                         error);
560                 }
561                 return isOk;
562         }
563
564         /**
565          * Get lucene index service. Create a lucene index if it does not exist.
566          * 
567          * @return index service
568          * @throws IOException
569          *             if error occurs during lucene index creation
570          */
571         private IndexService getIndex() throws IOException {
572                 IndexService lucin = getIndexService();
573                 if (!lucin.exists())
574                         lucin.create(); // Happens when re-indexing all studies
575                 return lucin;
576         }
577
578         /**
579          * Get project settings.
580          * 
581          * @return Project settings service
582          */
583         private ProjectSettingsService getProjectSettings() {
584                 return _projectSettingsService;
585         }
586
587         /**
588          * Set project settings service.
589          * 
590          * @param projectSettingsService
591          *            project settings service
592          */
593         public void setProjectSettings(ProjectSettingsService projectSettingsService) {
594                 _projectSettingsService = projectSettingsService;
595         }
596
597         /**
598          * Get the projectElementService.
599          * 
600          * @return the projectElementService
601          */
602         public ProjectElementService getProjectElementService() {
603                 return _projectElementService;
604         }
605
606         /**
607          * Set the projectElementService.
608          * 
609          * @param projectElementService
610          *            the projectElementService to set
611          */
612         public void setProjectElementService(
613                         ProjectElementService projectElementService) {
614                 _projectElementService = projectElementService;
615         }
616
617         /**
618          * Get the stepService.
619          * 
620          * @return the stepService
621          */
622         public StepService getStepService() {
623                 return _stepService;
624         }
625
626         /**
627          * Set the stepService.
628          * 
629          * @param stepService
630          *            the stepService to set
631          */
632         public void setStepService(StepService stepService) {
633                 _stepService = stepService;
634         }
635
636         /**
637          * Get the indexService.
638          * 
639          * @return the indexService
640          */
641         public IndexService getIndexService() {
642                 return _indexService;
643         }
644
645         /**
646          * Set the indexService.
647          * 
648          * @param indexService
649          *            the indexService to set
650          */
651         public void setIndexService(IndexService indexService) {
652                 _indexService = indexService;
653         }
654
655         /**
656          * Get the studyDAO.
657          * 
658          * @return the studyDAO
659          */
660         public StudyDAO getStudyDAO() {
661                 return _studyDAO;
662         }
663
664         /**
665          * Set the studyDAO.
666          * 
667          * @param studyDAO
668          *            the studyDAO to set
669          */
670         public void setStudyDAO(StudyDAO studyDAO) {
671                 _studyDAO = studyDAO;
672         }
673
674         /**
675          * Get the iDBuilderDAO.
676          * 
677          * @return the iDBuilderDAO
678          */
679         public IDBuilderDAO getIDBuilderDAO() {
680                 return _iDBuilderDAO;
681         }
682
683         /**
684          * Set the iDBuilderDAO.
685          * 
686          * @param builderDAO
687          *            the iDBuilderDAO to set
688          */
689         public void setIDBuilderDAO(IDBuilderDAO builderDAO) {
690                 _iDBuilderDAO = builderDAO;
691         }
692
693         /**
694          * Get the scenarioService.
695          * 
696          * @return the scenarioService
697          */
698         public ScenarioService getScenarioService() {
699                 return _scenarioService;
700         }
701
702         /**
703          * Set the scenarioService.
704          * 
705          * @param scenarioService
706          *            the scenarioService to set
707          */
708         public void setScenarioService(ScenarioService scenarioService) {
709                 _scenarioService = scenarioService;
710         }
711
712         /**
713          * Get the scenarioDAO.
714          * 
715          * @return the scenarioDAO
716          */
717         public ScenarioDAO getScenarioDAO() {
718                 return _scenarioDAO;
719         }
720
721         /**
722          * Set the scenarioDAO.
723          * 
724          * @param scenarioDAO
725          *            the scenarioDAO to set
726          */
727         public void setScenarioDAO(ScenarioDAO scenarioDAO) {
728                 _scenarioDAO = scenarioDAO;
729         }
730 }