Salome HOME
Database class usage is removed from StudyService.
[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                 SimpleDateFormat year = new SimpleDateFormat("yyyy");
503                 String cycle = year.format(date);
504                 // StringBuffer buffer = new StringBuffer("from IDBuilder where cycle='")
505                 // .append(cycle).append("'");
506                 // String qstring = buffer.toString();
507                 // Query query = Database.getSession().createQuery(qstring);
508                 // IDBuilder result = (IDBuilder) query.uniqueResult();
509
510                 // return result;
511
512                 // Calendar aDate = Calendar.getInstance();
513                 // aDate.setTime(date);
514                 // return getIDBuilderDAO().findByCriteria(
515                 // Restrictions.eq("cycle", aDate.get(Calendar.YEAR)));
516                 return getIDBuilderDAO()
517                                 .findByCriteria(Restrictions.eq("cycle", cycle));
518         }
519
520         /**
521          * Fill transient collection ModifiableActors of the study.
522          * 
523          * @param aStudy
524          *            the study
525          */
526         private void resetActorsShortCut(Study aStudy) {
527                 aStudy.getModifiableActors().clear();
528                 // Get all actors involved in validation cycles
529                 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
530                                 .values().iterator(); i.hasNext();) {
531                         ValidationCycle cycle = i.next();
532                         User[] user = cycle.getAllActors();
533                         for (int j = 0; j < user.length; j++)
534                                 aStudy.getModifiableActors().add(user[j]);
535                 }
536                 // Get all other actors
537                 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
538                                 .hasNext();) {
539                         Relation link = i.next();
540                         Class<?> kindof = link.getClass().getSuperclass();
541                         if (!kindof.equals(ActorRelation.class))
542                                 continue;
543                         aStudy.getModifiableActors().add(((ActorRelation) link).getTo());
544                 }
545         }
546
547         /**
548          * Update lucene index for the study knowledge elements.
549          * 
550          * @param aStudy
551          *            the study
552          * @return true if reindexing succeeded
553          */
554         private boolean updateKnowledgeElementsIndex(Study aStudy) {
555                 boolean isOk = false;
556                 try {
557                         IndexService lucin = getIndex();
558
559                         for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
560                                         .hasNext();) {
561                                 Scenario scene = i.next();
562                                 for (Iterator<KnowledgeElement> j = scene
563                                                 .getAllKnowledgeElements().iterator(); j.hasNext();) {
564                                         KnowledgeElement kelm = j.next();
565                                         lucin.update(kelm);
566                                 }
567                         }
568                         isOk = true;
569                 } catch (Exception error) {
570                         logger.error("Unable to re-index Knowledge Elements, reason:",
571                                         error);
572                 }
573                 return isOk;
574         }
575
576         /**
577          * Get lucene index service. Create a lucene index if it does not exist.
578          * 
579          * @return index service
580          * @throws IOException
581          *             if error occurs during lucene index creation
582          */
583         private IndexService getIndex() throws IOException {
584                 IndexService lucin = getIndexService();
585                 if (!lucin.exists())
586                         lucin.create(); // Happens when re-indexing all studies
587                 return lucin;
588         }
589
590         /**
591          * Get project settings.
592          * 
593          * @return Project settings service
594          */
595         private ProjectSettingsService getProjectSettings() {
596                 return _projectSettingsService;
597         }
598
599         /**
600          * Set project settings service.
601          * 
602          * @param projectSettingsService
603          *            project settings service
604          */
605         public void setProjectSettings(ProjectSettingsService projectSettingsService) {
606                 _projectSettingsService = projectSettingsService;
607         }
608
609         /**
610          * Get the projectElementService.
611          * 
612          * @return the projectElementService
613          */
614         public ProjectElementService getProjectElementService() {
615                 return _projectElementService;
616         }
617
618         /**
619          * Set the projectElementService.
620          * 
621          * @param projectElementService
622          *            the projectElementService to set
623          */
624         public void setProjectElementService(
625                         ProjectElementService projectElementService) {
626                 _projectElementService = projectElementService;
627         }
628
629         /**
630          * Get the stepService.
631          * 
632          * @return the stepService
633          */
634         public StepService getStepService() {
635                 return _stepService;
636         }
637
638         /**
639          * Set the stepService.
640          * 
641          * @param stepService
642          *            the stepService to set
643          */
644         public void setStepService(StepService stepService) {
645                 _stepService = stepService;
646         }
647
648         /**
649          * Get the indexService.
650          * 
651          * @return the indexService
652          */
653         public IndexService getIndexService() {
654                 return _indexService;
655         }
656
657         /**
658          * Set the indexService.
659          * 
660          * @param indexService
661          *            the indexService to set
662          */
663         public void setIndexService(IndexService indexService) {
664                 _indexService = indexService;
665         }
666
667         /**
668          * Get the studyDAO.
669          * 
670          * @return the studyDAO
671          */
672         public StudyDAO getStudyDAO() {
673                 return _studyDAO;
674         }
675
676         /**
677          * Set the studyDAO.
678          * 
679          * @param studyDAO
680          *            the studyDAO to set
681          */
682         public void setStudyDAO(StudyDAO studyDAO) {
683                 _studyDAO = studyDAO;
684         }
685
686         /**
687          * Get the iDBuilderDAO.
688          * 
689          * @return the iDBuilderDAO
690          */
691         public IDBuilderDAO getIDBuilderDAO() {
692                 return _iDBuilderDAO;
693         }
694
695         /**
696          * Set the iDBuilderDAO.
697          * 
698          * @param builderDAO
699          *            the iDBuilderDAO to set
700          */
701         public void setIDBuilderDAO(IDBuilderDAO builderDAO) {
702                 _iDBuilderDAO = builderDAO;
703         }
704
705         /**
706          * Get the scenarioService.
707          * 
708          * @return the scenarioService
709          */
710         public ScenarioService getScenarioService() {
711                 return _scenarioService;
712         }
713
714         /**
715          * Set the scenarioService.
716          * 
717          * @param scenarioService
718          *            the scenarioService to set
719          */
720         public void setScenarioService(ScenarioService scenarioService) {
721                 _scenarioService = scenarioService;
722         }
723
724         /**
725          * Get the scenarioDAO.
726          * 
727          * @return the scenarioDAO
728          */
729         public ScenarioDAO getScenarioDAO() {
730                 return _scenarioDAO;
731         }
732
733         /**
734          * Set the scenarioDAO.
735          * 
736          * @param scenarioDAO
737          *            the scenarioDAO to set
738          */
739         public void setScenarioDAO(ScenarioDAO scenarioDAO) {
740                 _scenarioDAO = scenarioDAO;
741         }
742 }