Salome HOME
Show and Edit description functionalities are implemented
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / StudyServiceImpl.java
1 /*****************************************************************************
2  * Company         OPEN CASCADE
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.DecimalFormat;
14 import java.text.SimpleDateFormat;
15 import java.util.Calendar;
16 import java.util.Collections;
17 import java.util.Date;
18 import java.util.Iterator;
19 import java.util.List;
20 import java.util.Map;
21 import java.util.Set;
22
23 import org.hibernate.criterion.Restrictions;
24 import org.splat.dal.bo.kernel.Relation;
25 import org.splat.dal.bo.kernel.User;
26 import org.splat.dal.bo.som.ActorRelation;
27 import org.splat.dal.bo.som.ContributorRelation;
28 import org.splat.dal.bo.som.DescriptionAttribute;
29 import org.splat.dal.bo.som.DocumentType;
30 import org.splat.dal.bo.som.IDBuilder;
31 import org.splat.dal.bo.som.KnowledgeElement;
32 import org.splat.dal.bo.som.ProgressState;
33 import org.splat.dal.bo.som.Publication;
34 import org.splat.dal.bo.som.Scenario;
35 import org.splat.dal.bo.som.SimulationContext;
36 import org.splat.dal.bo.som.Study;
37 import org.splat.dal.bo.som.Study.Properties;
38 import org.splat.dal.bo.som.ValidationCycle;
39 import org.splat.dal.bo.som.ValidationCycle.Actor;
40 import org.splat.dal.bo.som.ValidationCycleRelation;
41 import org.splat.dal.bo.som.ValidationStep;
42 import org.splat.dal.bo.som.Visibility;
43 import org.splat.dal.dao.som.DescriptionAttributeDAO;
44 import org.splat.dal.dao.som.DocumentDAO;
45 import org.splat.dal.dao.som.IDBuilderDAO;
46 import org.splat.dal.dao.som.PublicationDAO;
47 import org.splat.dal.dao.som.ScenarioDAO;
48 import org.splat.dal.dao.som.StudyDAO;
49 import org.splat.dal.dao.som.ValidationCycleDAO;
50 import org.splat.exception.InvalidParameterException;
51 import org.splat.kernel.InvalidPropertyException;
52 import org.splat.kernel.MissedPropertyException;
53 import org.splat.kernel.MultiplyDefinedException;
54 import org.splat.log.AppLogger;
55 import org.splat.service.technical.IndexService;
56 import org.splat.service.technical.ProjectSettingsService;
57 import org.splat.service.technical.ProjectSettingsServiceImpl;
58 import org.splat.service.technical.RepositoryService;
59 import org.splat.som.Revision;
60 import org.springframework.transaction.annotation.Transactional;
61
62 /**
63  * This class defines all methods for creation, modification the study.
64  * 
65  * @author Maria KRUCHININA
66  * 
67  */
68 public class StudyServiceImpl implements StudyService {
69
70         /**
71          * logger for the service.
72          */
73         public final static AppLogger LOG = AppLogger
74                         .getLogger(StudyServiceImpl.class);
75
76         /**
77          * Injected index service.
78          */
79         private IndexService _indexService;
80
81         /**
82          * Injected step service.
83          */
84         private StepService _stepService;
85
86         /**
87          * Injected project service.
88          */
89         private ProjectSettingsService _projectSettings;
90
91         /**
92          * Injected project element service.
93          */
94         private ProjectElementService _projectElementService;
95
96         /**
97          * Injected study DAO.
98          */
99         private StudyDAO _studyDAO;
100
101         /**
102          * Injected scenario DAO.
103          */
104         private ScenarioDAO _scenarioDAO;
105
106         /**
107          * Injected validation cycle DAO.
108          */
109         private ValidationCycleDAO _validationCycleDAO;
110
111         /**
112          * Injected IDBuilder DAO.
113          */
114         private IDBuilderDAO _iDBuilderDAO;
115
116         /**
117          * Injected document type service.
118          */
119         private DocumentTypeService _documentTypeService;
120
121         /**
122          * Injected user service.
123          */
124         private UserService _userService;
125         
126         /**
127          * Injected publication DAO.
128          */
129         private PublicationDAO _publicationDAO;
130
131         /**
132          * Injected repository service.
133          */
134         private RepositoryService _repositoryService;
135
136         /**
137          * Injected document DAO.
138          */
139         private DocumentDAO _documentDAO;
140
141         /**
142          * Injected description attribute DAO.
143          */
144         private DescriptionAttributeDAO _descriptionAttributeDAO;
145
146         /**
147          * {@inheritDoc}
148          * 
149          * @see org.splat.service.StudyService#selectStudy(long)
150          */
151         @Transactional
152         public Study selectStudy(final long index) {
153                 Study result = getStudyDAO().get(index);
154                 loadWorkflow(result);
155                 return result;
156         }
157
158         /**
159          * Get study by its reference.
160          * 
161          * @param refid
162          *            the study reference
163          * @return found study or null
164          */
165         @Transactional(readOnly = true)
166         public Study selectStudy(final String refid) {
167                 Study result = getStudyDAO().findByCriteria(
168                                 Restrictions.eq("sid", refid));
169                 loadWorkflow(result);
170                 return result;
171         }
172
173         /**
174          * {@inheritDoc}
175          * 
176          * @see org.splat.service.StudyService#createStudy(org.splat.dal.bo.som.Study.Properties)
177          */
178         @Transactional
179         public Study createStudy(final Study.Properties sprop)
180                         throws MissedPropertyException, InvalidPropertyException,
181                         MultiplyDefinedException {
182                 sprop.setReference(getProjectSettings().getReferencePattern());
183                 Study study = new Study(sprop);
184
185                 buildReference(study);
186                 getStudyDAO().create(study);
187                 try {
188                         IndexService lucin = getIndex();
189                         lucin.add(study);
190                 } catch (IOException error) {
191                         LOG.error("Unable to index the study '" + study.getIndex()
192                                         + "', reason:", error);
193                         // Continue and try to index later
194                 }
195                 return study;
196         }
197
198         /**
199          * {@inheritDoc}
200          * 
201          * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext.Properties)
202          */
203         @Transactional
204         public SimulationContext addProjectContext(final Study aStudy,
205                         final SimulationContext.Properties cprop)
206                         throws MissedPropertyException, InvalidPropertyException,
207                         MultiplyDefinedException {
208                 SimulationContext added = getStepService().addSimulationContext(
209                                 getProjectElementService().getFirstStep(aStudy), cprop);
210                 update(aStudy);
211                 return added;
212         }
213
214         /**
215          * {@inheritDoc}
216          * 
217          * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
218          */
219         @Transactional
220         public SimulationContext addProjectContext(final Study aStudy,
221                         final SimulationContext context) {
222                 SimulationContext added = getStepService().addSimulationContext(
223                                 getProjectElementService().getFirstStep(aStudy), context);
224                 update(aStudy);
225                 return added;
226         }
227
228         /**
229          * {@inheritDoc}
230          * 
231          * @see org.splat.service.StudyService#addContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User)
232          */
233         public boolean addContributor(final Study aStudy, final User user) {
234                 List<User> contributor = getModifiableContributors(aStudy); // Initializes contributor
235                 for (Iterator<User> i = contributor.iterator(); i.hasNext();) {
236                         User present = i.next();
237                         if (present.equals(user)) {
238                                 return false;
239                         }
240                 }
241                 boolean absent = getModifiableActors(aStudy).add(user); // User may already be a reviewer or an approver
242
243                 aStudy.addRelation(new ContributorRelation(aStudy, user));
244                 if (absent) {
245                         update(aStudy); // Else, useless to re-index the study
246                 }
247                 contributor.add(user);
248                 return true;
249         }
250
251         /**
252          * Moves this study from the Public to the Reference area of the repository. For being moved to the Reference area, the study must
253          * previously be approved.
254          * 
255          * @param aStudy
256          *            the study to move
257          * @return true if the move succeeded.
258          * @see #moveToPublic()
259          * @see #isPublic()
260          * @see Publication#approve(Date)
261          */
262         public boolean moveToReference(final Study aStudy) {
263                 if (aStudy.getProgressState() != ProgressState.APPROVED) {
264                         return false;
265                 }
266                 if (aStudy.getVisibility() != Visibility.PUBLIC) {
267                         return false;
268                 }
269
270                 aStudy.setVisibility(Visibility.REFERENCE);
271                 if (update(aStudy)) {
272                         return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
273                 }
274                 return false;
275         }
276
277         /**
278          * {@inheritDoc}
279          * 
280          * @see org.splat.service.StudyService#update(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Study.Properties)
281          */
282         public boolean update(final Study aStudy, final Properties sprop)
283                         throws InvalidPropertyException {
284                 if (sprop.getTitle() != null) {
285                         aStudy.setTitle(sprop.getTitle());
286                 }
287                 if (sprop.getSummary() != null) {
288                         aStudy.setAttribute(new DescriptionAttribute(aStudy, sprop
289                                         .getSummary()));
290                 }
291                 // TODO: To be completed
292                 return update(aStudy);
293         }
294
295         /**
296          * Check if the document is published in the study.
297          * 
298          * @param aStudy
299          *            the study
300          * @param doc
301          *            the document
302          * @return true if the document is published in the study
303          */
304 /*      private boolean publishes(final Study aStudy, final Document doc) {
305                 if (!aStudy.publishes(doc)) {
306                         Scenario[] scene = aStudy.getScenarii();
307                         for (int i = 0; i < scene.length; i++) {
308                                 if (scene[i].publishes(doc)) {
309                                         return true;
310                                 }
311                         }
312                 }
313                 return false;
314         }
315 */
316         /**
317          * {@inheritDoc}
318          * 
319          * @see org.splat.service.StudyService#removeContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User[])
320          */
321         public boolean removeContributor(final Study aStudy, final User... users) {
322                 List<User> contributor = getModifiableContributors(aStudy); // Initializes contributor
323                 Boolean done = false;
324                 for (int i = 0; i < users.length; i++) {
325                         User user = users[i];
326                         for (Iterator<User> j = contributor.iterator(); j.hasNext();) {
327                                 User present = j.next();
328                                 if (!present.equals(user)) {
329                                         continue;
330                                 }
331
332                                 aStudy.removeRelation(ContributorRelation.class, user);
333                                 j.remove(); // Updates the contributor shortcut
334                                 done = true;
335                                 break;
336                         }
337                 }
338                 if (done) {
339                         update(aStudy);
340                 }
341                 return done;
342         }
343
344         /**
345          * {@inheritDoc}
346          * 
347          * @see org.splat.service.StudyService#removeProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
348          */
349         public boolean removeProjectContext(final Study aStudy,
350                         final SimulationContext context) {
351                 boolean done = getStepService().removeSimulationContext(
352                                 getProjectElementService().getFirstStep(aStudy), context);
353                 update(aStudy);
354                 return done;
355         }
356
357         /**
358          * {@inheritDoc}
359          * 
360          * @see org.splat.service.StudyService#setValidationCycle(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.DocumentType,
361          *      org.splat.dal.bo.som.ValidationCycle.Properties)
362          */
363         @Transactional
364         public void setValidationCycle(final Study aStudyDTO, final DocumentType type,
365                         final ValidationCycle.Properties vprop) {
366                 Map<String, ValidationCycle> validactor = aStudyDTO.getValidationCycles();
367                 if (validactor == null) {
368                         setShortCuts(aStudyDTO); // Initializes validactor and actor
369                 }
370
371                 Study aStudy = selectStudy(aStudyDTO.getIndex());
372                 
373                 String cname = type.getName();
374                 ValidationCycle cycle = validactor.get(cname);
375
376                 if (cycle != null && cycle.isAssigned()) {
377                         resetActors(cycle, vprop);
378                 } else {
379                         try {
380                                 cycle = new ValidationCycle(aStudy, vprop.setDocumentType(type));
381
382                                 getValidationCycleDAO().create(cycle); // RKV
383
384                                 ValidationCycleRelation link = cycle.getContext();
385                                 aStudy.addRelation(link);
386                                 aStudyDTO.getAllRelations().add(link); // RKV
387
388                                 validactor.put(cname, link.getTo()); // Replaces the cycle if exists as default,
389                         } catch (Exception error) {
390                                 LOG.error("Unable to re-index Knowledge Elements, reason:",
391                                                 error);
392                                 return;
393                         }
394                 }
395                 resetActorsShortCut(aStudyDTO);
396                 update(aStudy); // Re-index the study, just in case
397         }
398
399         /**
400          * Demotes this study from In-Check to In-Draft then In-Work states. This function is called internally when demoting the final result
401          * document of the study.
402          * 
403          * @param aStudy
404          *            a study to demote
405          * @return true if the demotion succeeded.
406          */
407         public boolean demote(final Study aStudy) {
408                 if (aStudy.getProgressState() == ProgressState.inCHECK) {
409                         aStudy.setProgressState(ProgressState.inDRAFT);
410                 } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
411                         aStudy.setProgressState(ProgressState.inWORK);
412                 } else {
413                         return false;
414                 }
415                 return update(aStudy);
416         }
417
418         /**
419          * {@inheritDoc}
420          * 
421          * @see org.splat.service.StudyService#generateLocalIndex(org.splat.dal.bo.som.Study)
422          */
423         @Transactional
424         public int generateLocalIndex(final Study aStudy) {
425                 aStudy.setLastLocalIndex(aStudy.getLastLocalIndex() + 1);
426                 return aStudy.getLastLocalIndex();
427         }
428
429         /**
430          * Promotes this study from In-Work to In-Draft then In-Check and APPROVED states. This function is called internally when promoting the
431          * final result document of the study.
432          * 
433          * @param aStudy
434          *            a study to promote
435          * @return true if the demotion succeeded.
436          */
437         @Transactional
438         public boolean promote(final Study aStudy) {
439                 if (aStudy.getProgressState() == ProgressState.inWORK) {
440                         aStudy.setProgressState(ProgressState.inDRAFT);
441                 } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
442                         aStudy.setProgressState(ProgressState.inCHECK);
443                         Revision myvers = new Revision(aStudy.getVersion());
444                         if (myvers.isMinor()) {
445                                 aStudy.setVersion(myvers.incrementAs(aStudy.getProgressState())
446                                                 .toString());
447                         }
448                 } else if (aStudy.getProgressState() == ProgressState.inCHECK) {
449                         aStudy.setProgressState(ProgressState.APPROVED);
450                 } else {
451                         return false;
452                 }
453
454                 return update(aStudy);
455         }
456
457         /**
458          * Moves this study from the Private to the Public area of the repository.
459          * 
460          * @param aStudy
461          *            a study to move
462          * @return true if the move succeeded.
463          * @see #isPublic()
464          */
465         @Transactional
466         public boolean moveToPublic(final Study aStudy) {
467                 boolean isOk = false;
468                 if (aStudy.getVisibility() == Visibility.PRIVATE) {
469                         aStudy.setVisibility(Visibility.PUBLIC);
470                         if (update(aStudy)) {
471                                 isOk = updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
472                         }
473                 }
474                 return isOk;
475         }
476         
477         /**
478          * Moves this study from the Public to the Private area of the repository.
479          * 
480          * @param aStudy
481          *            a study to move
482          * @return true if the move succeeded.
483          */
484         @Transactional
485         public boolean moveToPrivate(final Study aStudy) {
486                 boolean isOk = false;
487                 if (aStudy.getVisibility() == Visibility.PUBLIC) {
488                         aStudy.setVisibility(Visibility.PRIVATE);
489                         if (update(aStudy)) {
490                                 isOk = updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
491                         }
492                 }
493                 return isOk;
494         }
495
496         /**
497          * Update a study in the database.
498          * 
499          * @param aStudy
500          *            the study to update
501          * @return true if the study is updated successfully
502          */
503         @Transactional
504         private boolean update(final Study aStudy) {
505                 boolean isOk = false;
506                 try {
507                         getStudyDAO().merge(aStudy); // Update of relational base
508                         setShortCuts(aStudy); // RKV: initialize transient actors set
509                         getIndex().update(aStudy); // Update of Lucene index
510                         isOk = true;
511                 } catch (Exception e) {
512                         LOG.error("STD-000001", e, aStudy.getIndex(), e.getMessage());
513                 }
514                 return isOk;
515         }
516
517         /**
518          * Build reference for the study. The reference of the study is stored as a new reference pattern (IDBuilder).
519          * 
520          * @param aStudy
521          *            the study
522          * @return true if reference building is succeded
523          */
524         @Transactional
525         private boolean buildReference(final Study aStudy) {
526                 String pattern = aStudy.getReference(); // The study being supposed just created, its reference is the reference pattern
527                 IDBuilder tool = selectIDBuilder(aStudy.getDate());
528                 if (tool == null) {
529                         tool = new IDBuilder(aStudy.getDate());
530                         getIDBuilderDAO().create(tool);
531                 }
532                 aStudy.setReference(buildReference(tool, pattern, aStudy));
533                 return true;
534         }
535
536         /**
537          * Build reference for the study. The reference of the study is stored as a new reference pattern (IDBuilder).
538          * 
539          * @param aBuilder
540          *            the id builder
541          * @param study
542          *            the study
543          * @param pattern
544          *            the reference pattern
545          * @return true if reference building is succeded
546          */
547         @Transactional
548         public String buildReference(final IDBuilder aBuilder,
549                         final String pattern, final Study study) {
550                 char[] format = pattern.toCharArray();
551                 char[] ref = new char[80]; // Better evaluate the length of the generated string
552                 int next = aBuilder.getBase() + 1;
553
554                 int count = 0;
555                 for (int i = 0; i < format.length; i++) {
556
557                         // Insertion of attribute values
558                         if (format[i] == '%') {
559                                 i += 1;
560
561                                 if (format[i] == 'y') { // Insertion of year in format 2 (e.g. 09) or 4 (e.g. 2009) digits
562                                         int n = i;
563                                         while (format[i] == 'y') {
564                                                 i += 1;
565                                                 if (i == format.length) {
566                                                         break;
567                                                 }
568                                         }
569                                         SimpleDateFormat tostring = new SimpleDateFormat("yyyy"); //RKV: NOPMD: TODO: Use locale here?
570                                         String year = tostring.format(study.getDate());
571                                         year = year.substring(4 - (i - n), 4); // 4-(i-n) must be equal to either 0 or 2
572                                         for (int j = 0; j < year.length(); j++) {
573                                                 ref[count] = year.charAt(j);
574                                                 count += 1;
575                                         }
576                                         i -= 1; // Back to the last 'y' character
577                                 } else if (format[i] == '0') { // Insertion of the index
578                                         int n = i;
579                                         while (format[i] == '0') {
580                                                 i += 1;
581                                                 if (i == format.length) {
582                                                         break;
583                                                 }
584                                         }
585                                         DecimalFormat tostring = new DecimalFormat(pattern
586                                                         .substring(n, i));
587                                         String number = tostring.format(next);
588                                         for (int j = 0; j < number.length(); j++) {
589                                                 ref[count] = number.charAt(j);
590                                                 count += 1;
591                                         }
592                                         i -= 1; // Back to the last '0' character
593                                 }
594                                 // Keep the character
595                         } else {
596                                 ref[count] = format[i];
597                                 count += 1;
598                         }
599                 }
600                 // Incrementation of the number of study
601                 aBuilder.setBase(next);
602                 getIDBuilderDAO().update(aBuilder);
603                 return String.copyValueOf(ref, 0, count);
604         }
605
606         /**
607          * Find an id builder by date.
608          * 
609          * @param date
610          *            the date
611          * @return found id builder
612          */
613         private IDBuilder selectIDBuilder(final Date date) {
614                 Calendar aDate = Calendar.getInstance();
615                 aDate.setTime(date);
616                 return getIDBuilderDAO().findByCriteria(
617                                 Restrictions.eq("cycle", aDate.get(Calendar.YEAR)));
618         }
619
620         /**
621          * Fill transient collection ModifiableActors of the study.
622          * 
623          * @param aStudy
624          *            the study
625          */
626         private void resetActorsShortCut(final Study aStudy) {
627                 getModifiableActors(aStudy).clear();
628                 // Get all actors involved in validation cycles
629                 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
630                                 .values().iterator(); i.hasNext();) {
631                         ValidationCycle cycle = i.next();
632                         User[] user = cycle.getAllActors();
633                         for (int j = 0; j < user.length; j++) {
634                                 getModifiableActors(aStudy).add(user[j]);
635                         }
636                 }
637                 // Get all other actors
638                 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
639                                 .hasNext();) {
640                         Relation link = i.next();
641                         Class<?> kindof = link.getClass().getSuperclass();
642                         if (!kindof.equals(ActorRelation.class)) {
643                                 continue;
644                         }
645                         getModifiableActors(aStudy).add(((ActorRelation) link).getTo());
646                 }
647         }
648
649         /**
650          * Update lucene index for the study knowledge elements.
651          * 
652          * @param aStudy
653          *            the study
654          * @return true if reindexing succeeded
655          */
656         private boolean updateKnowledgeElementsIndex(final Study aStudy) {
657                 boolean isOk = false;
658                 try {
659                         IndexService lucin = getIndex();
660
661                         for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
662                                         .hasNext();) {
663                                 Scenario scene = i.next();
664                                 for (Iterator<KnowledgeElement> j = scene
665                                                 .getAllKnowledgeElements().iterator(); j.hasNext();) {
666                                         KnowledgeElement kelm = j.next();
667                                         lucin.update(kelm);
668                                 }
669                         }
670                         isOk = true;
671                 } catch (Exception error) {
672                         LOG.error("Unable to re-index Knowledge Elements, reason:",
673                                         error);
674                 }
675                 return isOk;
676         }
677
678         /**
679          * Get lucene index service. Create a lucene index if it does not exist.
680          * 
681          * @return index service
682          * @throws IOException
683          *             if error occurs during lucene index creation
684          */
685         private IndexService getIndex() throws IOException {
686                 IndexService lucin = getIndexService();
687                 if (!lucin.exists()) {
688                         lucin.create(); // Happens when re-indexing all studies
689                 }
690                 return lucin;
691         }
692
693         /**
694          * Create a new validation cycle for documents of the given study.
695          * 
696          * @param from
697          *            the study
698          * @param cycle
699          *            the cycle description
700          * @return the new validation cycle
701          */
702         protected ValidationCycle createValidationCycle(
703                         final Study from,
704                         final ProjectSettingsServiceImpl.ProjectSettingsValidationCycle cycle) {
705                 Actor[] actype = cycle.getActorTypes();
706                 User.Properties uprop = new User.Properties();
707
708                 ValidationCycle aValidationCycle = new ValidationCycle();
709                 aValidationCycle.setDocumentType(getDocumentTypeService().selectType(
710                                 cycle.getName())); // Null in case of default validation cycle
711                 // context = new ValidationCycleRelation(from, vprop);
712                 // RKV aValidationCycle.context = null; // Validation cycle defined in the workflow
713                 for (int i = 0; i < actype.length; i++) {
714                         User actor = null;
715                         if (actype[i] != null) {
716                                 try {
717                                         if (actype[i] == Actor.manager) {
718                                                 actor = from.getAuthor();
719                                         } else if (actype[i] == Actor.Nx1) {
720                                                 List<User> manager = getUserService().selectUsersWhere(
721                                                                 uprop.setOrganizationName("Nx1"));
722                                                 if (manager.size() == 1) {
723                                                         actor = manager.get(0);
724                                                 }
725                                         } else if (actype[i] == Actor.Nx2) {
726                                                 List<User> manager = getUserService().selectUsersWhere(
727                                                                 uprop.setOrganizationName("Nx2"));
728                                                 if (manager.size() == 1) {
729                                                         actor = manager.get(0);
730                                                 }
731                                         } else { /* Actor.customer */
732                                                 actor = from.getAuthor();
733                                                 // TODO: Get the customer of the study, if exists
734                                         }
735                                 } catch (Exception e) { // Should not happen
736                                         actor = null;
737                                 }
738                         }
739                         if (i == 0) {
740                                 aValidationCycle.setReviewer(actor);
741                         } else if (i == 1) {
742                                 aValidationCycle.setApprover(actor);
743                         } else if (i == 2) {
744                                 aValidationCycle.setSignatory(actor);
745                         }
746                 }
747                 return aValidationCycle;
748         }
749
750         /**
751          * Remove a validation step from the validation cycle.
752          * 
753          * @param aValidationCycle
754          *            the validation cycle
755          * @param step
756          *            the validation step to remove
757          */
758         @Transactional
759         protected void remove(final ValidationCycle aValidationCycle,
760                         final ValidationStep step) {
761                 if (step == ValidationStep.REVIEW) {
762                         aValidationCycle.setReviewer(null);
763                 } else if (step == ValidationStep.APPROVAL) {
764                         aValidationCycle.setApprover(null);
765                 } else if (step == ValidationStep.ACCEPTANCE
766                                 || step == ValidationStep.REFUSAL) {
767                         aValidationCycle.setSignatory(null);
768                 }
769                 if (aValidationCycle.isSaved()) {
770                         getValidationCycleDAO().update(aValidationCycle);
771                 }
772         }
773
774         /**
775          * Reset actors for the validation cycle.
776          * 
777          * @param aValidationCycle
778          *            the validation cycle to update
779          * @param vprop
780          *            new validation cycle properties containing new actors
781          */
782         @Transactional
783         public void resetActors(final ValidationCycle aValidationCycle,
784                         final ValidationCycle.Properties vprop) {
785                 aValidationCycle.setPublisher(vprop.getPublisher()); // May be null
786                 aValidationCycle.setReviewer(vprop.getReviewer()); // May be null
787                 aValidationCycle.setApprover(vprop.getApprover()); // May be null
788                 aValidationCycle.setSignatory(vprop.getSignatory()); // May be null
789                 if (aValidationCycle.isSaved()) {
790                         getValidationCycleDAO().merge(aValidationCycle);
791                 }
792         }
793
794         /**
795          * Set actor for the given validation cycle and validation step.
796          * 
797          * @param aValidationCycle
798          *            the validation cycle
799          * @param step
800          *            the validation step
801          * @param actor
802          *            the actor to set
803          */
804         @Transactional
805         protected void setActor(final ValidationCycle aValidationCycle,
806                         final ValidationStep step, final User actor) {
807                 if (step == ValidationStep.PROMOTION) {
808                         aValidationCycle.setPublisher(actor);
809                 } else if (step == ValidationStep.REVIEW) {
810                         aValidationCycle.setReviewer(actor);
811                 } else if (step == ValidationStep.APPROVAL) {
812                         aValidationCycle.setApprover(actor);
813                 } else if (step == ValidationStep.ACCEPTANCE
814                                 || step == ValidationStep.REFUSAL) {
815                         aValidationCycle.setSignatory(actor);
816                 }
817                 if (aValidationCycle.isSaved()) {
818                         getValidationCycleDAO().update(aValidationCycle);
819                 }
820         }
821
822         /**
823          * Returns all actors of this study other than the author, including contributors, reviewers and approvers.
824          * 
825          * @param aStudy
826          *            the study
827          * @return the actors of this study
828          * @see #hasActor(User)
829          */
830         public Set<User> getActors(final Study aStudy) {
831                 if (aStudy.getActor() == null) {
832                         setShortCuts(aStudy);
833                 }
834                 return Collections.unmodifiableSet(aStudy.getActor());
835         }
836
837         /**
838          * Returns all actors of this study other than the author, including contributors, reviewers and approvers.
839          * 
840          * @param aStudy
841          *            the study
842          * @return the modifiable set of actors of this study
843          * @see #hasActor(User)
844          */
845         public Set<User> getModifiableActors(final Study aStudy) {
846                 if (aStudy.getActor() == null) {
847                         setShortCuts(aStudy);
848                 }
849                 return aStudy.getActor();
850         }
851
852         /**
853          * Returns unmodifiable initialized transient list of contributors of this study.
854          * 
855          * @param aStudy
856          *            the study
857          * @return the unmodifiable not null transient list of contributors of this study
858          */
859         public List<User> getContributors(final Study aStudy) {
860                 if (aStudy.getContributor() == null) {
861                         setShortCuts(aStudy);
862                 }
863                 return Collections.unmodifiableList(aStudy.getContributor()); // May be empty
864         }
865
866         /**
867          * Returns modifiable initialized transient list of contributors of this study.
868          * 
869          * @param aStudy
870          *            the study
871          * @return the modifiable not null transient list of contributors of this study
872          */
873         public List<User> getModifiableContributors(final Study aStudy) {
874                 if (aStudy.getContributor() == null) {
875                         setShortCuts(aStudy);
876                 }
877                 return aStudy.getContributor(); // May be empty
878         }
879
880         /**
881          * Returns the validation cycle of the given document type.
882          * 
883          * @param aStudy
884          *            the study
885          * @param type
886          *            the document type being subject of validation
887          * @return the validation cycle of the document, or null if not defined.
888          */
889         public ValidationCycle getValidationCycleOf(final Study aStudy,
890                         final DocumentType type) {
891                 if (aStudy.getValidationCycles() == null || aStudy.getValidationCycles().isEmpty()) {
892                         setShortCuts(aStudy);
893                 }
894                 ValidationCycle result = aStudy.getValidationCycles().get(
895                                 type.getName());
896                 if (result == null) {
897                         if (type.isStepResult()) {
898                                 result = aStudy.getValidationCycles().get("default"); // "default" validation cycle defined in the configuration, if exist
899                         }
900                         if (result == null) {
901                                 result = aStudy.getValidationCycles().get("built-in");
902                         }
903                 }
904                 return result;
905         }
906
907         /**
908          * Checks if the given user is actor of this study. Actors include contributors, reviewers and approvers.
909          * 
910          * @param aStudy
911          *            the study
912          * @param user
913          *            the user to look for
914          * @return true if the given user is actor of this study.
915          * @see #getActors()
916          */
917         public boolean hasActor(final Study aStudy, final User user) {
918                 if (user == null) {
919                         return false;
920                 }
921                 for (Iterator<User> i = getActors(aStudy).iterator(); i.hasNext();) {
922                         User involved = i.next();
923                         if (involved.equals(user)) {
924                                 return true;
925                         }
926                 }
927                 return false;
928         }
929
930         /**
931          * Checks if the given user participates to this study. The Study staff includes the author and contributors.
932          * 
933          * @param aStudy
934          *            the study
935          * @param user
936          *            the user to look for
937          * @return true if the given user is actor of this study.
938          * @see #getContributors()
939          */
940         public boolean isStaffedBy(final Study aStudy, final User user) {
941                 if (user == null) {
942                         return false;
943                 }
944                 if (aStudy == null) {
945                         return false;
946                 }
947                 if (aStudy.getAuthor() == null) {
948                         return false;
949                 }
950                 if (aStudy.getAuthor().equals(user)) {
951                         return true;
952                 }
953                 for (Iterator<User> i = getContributors(aStudy).iterator(); i.hasNext();) {
954                         if (i.next().equals(user)) {
955                                 return true;
956                         }
957                 }
958                 return false;
959         }
960
961         /**
962          * Initialize shortcuts of the study as its transient collections.
963          * 
964          * @param aStudy
965          *            the study
966          */
967         public void loadWorkflow(final Study aStudy) {
968                 setShortCuts(aStudy);
969         }
970
971         /**
972          * Initialize shortcuts of the study as its transient collections.
973          * 
974          * @param aStudy
975          *            the study
976          */
977         public void setShortCuts(final Study aStudy) {
978                 aStudy.getContributor().clear();
979                 aStudy.getValidationCycles().clear();
980                 aStudy.getActor().clear();
981
982                 // Get the contributors
983                 for (Iterator<Relation> i = aStudy.getRelations(
984                                 ContributorRelation.class).iterator(); i.hasNext();) {
985                         ContributorRelation link = (ContributorRelation) i.next();
986                         aStudy.getContributor().add(link.getTo());
987                 }
988                 // Get the validation cycles specific to this study
989                 for (Iterator<Relation> i = aStudy.getRelations(
990                                 ValidationCycleRelation.class).iterator(); i.hasNext();) {
991                         ValidationCycleRelation link = (ValidationCycleRelation) i.next();
992                         aStudy.getValidationCycles().put(link.getDocumentType().getName(),
993                                         link.getTo()); // The associated document type is necessarily not null in this
994                         // context
995                 }
996                 // Get the validation cycles coming from the configured workflow and not overridden in this study
997                 for (Iterator<ProjectSettingsServiceImpl.ProjectSettingsValidationCycle> i = getProjectSettings()
998                                 .getAllValidationCycles().iterator(); i.hasNext();) {
999                         ProjectSettingsServiceImpl.ProjectSettingsValidationCycle cycle = i
1000                                         .next();
1001                         String type = cycle.getName();
1002                         if (!aStudy.getValidationCycles().containsKey(type)) {
1003                                 aStudy.getValidationCycles().put(type,
1004                                                 createValidationCycle(aStudy, cycle));
1005                         }
1006                 }
1007                 // Get all corresponding actors
1008                 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
1009                                 .values().iterator(); i.hasNext();) {
1010                         ValidationCycle cycle = i.next();
1011                         User[] user = cycle.getAllActors();
1012                         for (int j = 0; j < user.length; j++) {
1013                                 aStudy.getActor().add(user[j]);
1014                         }
1015                 }
1016                 // Get all other actors
1017                 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
1018                                 .hasNext();) {
1019                         Relation link = i.next();
1020                         Class<?> kindof = link.getClass().getSuperclass();
1021                         if (!kindof.equals(ActorRelation.class)) {
1022                                 continue;
1023                         }
1024                         aStudy.getActor().add(((ActorRelation) link).getTo());
1025                 }
1026         }
1027         
1028         /**
1029          * 
1030          * {@inheritDoc}
1031          * @see org.splat.service.StudyService#markStudyAsReference(org.splat.dal.bo.som.Study)
1032          */
1033         @Override
1034         @Transactional
1035         public void markStudyAsReference (final Study aStudy) {
1036                 
1037                 aStudy.setMarkreference(1);
1038                 aStudy.setProgressState(ProgressState.TEMPLATE);
1039                 getStudyDAO().merge(aStudy);
1040         }
1041         
1042         /**
1043          * 
1044          * {@inheritDoc}
1045          * @see org.splat.service.StudyService#removeStudyAsReference(org.splat.dal.bo.som.Study)
1046          */
1047         @Override
1048         @Transactional
1049         public void removeStudyAsReference(final Study aStudy) {
1050                 
1051                 aStudy.setMarkreference(0);
1052                 aStudy.setProgressState(ProgressState.APPROVED);
1053                 getStudyDAO().merge(aStudy);
1054         }
1055         
1056         /** 
1057          * {@inheritDoc}
1058          * @see org.splat.service.StudyService#getDescription(java.lang.Long)
1059          */
1060         @Override
1061         @Transactional(readOnly = true)
1062         public String getDescription(final Long studyId) throws InvalidParameterException {
1063                 if(studyId == null) {
1064                         throw new InvalidParameterException("studyId", "null");
1065                 }
1066                 Study study = _studyDAO.get(studyId);
1067                 if(study == null) {
1068                         throw new InvalidParameterException("studyId", studyId.toString());
1069                 }
1070                 return study.getDescription();
1071         }
1072         
1073         
1074         /** 
1075          * {@inheritDoc}
1076          * @see org.splat.service.StudyService#setDescription(java.lang.Long, java.lang.String)
1077          */
1078         @Override
1079         @Transactional
1080         public void setDescription(final Long studyId, final String descriptionText) 
1081                         throws InvalidParameterException {
1082                 if(studyId == null) {
1083                         throw new InvalidParameterException("studyId", "null");
1084                 }
1085                 Study study = _studyDAO.get(studyId);
1086                 if(study == null) {
1087                         throw new InvalidParameterException("studyId", studyId.toString());
1088                 }
1089                 study.setAttribute(new DescriptionAttribute(study, descriptionText));
1090         }
1091
1092         /**
1093          * Get project settings.
1094          * 
1095          * @return Project settings service
1096          */
1097         private ProjectSettingsService getProjectSettings() {
1098                 return _projectSettings;
1099         }
1100
1101         /**
1102          * Set project settings service.
1103          * 
1104          * @param projectSettingsService
1105          *            project settings service
1106          */
1107         public void setProjectSettings(
1108                         final ProjectSettingsService projectSettingsService) {
1109                 _projectSettings = projectSettingsService;
1110         }
1111
1112         /**
1113          * Get the projectElementService.
1114          * 
1115          * @return the projectElementService
1116          */
1117         public ProjectElementService getProjectElementService() {
1118                 return _projectElementService;
1119         }
1120
1121         /**
1122          * Set the projectElementService.
1123          * 
1124          * @param projectElementService
1125          *            the projectElementService to set
1126          */
1127         public void setProjectElementService(
1128                         final ProjectElementService projectElementService) {
1129                 _projectElementService = projectElementService;
1130         }
1131
1132         /**
1133          * Get the stepService.
1134          * 
1135          * @return the stepService
1136          */
1137         public StepService getStepService() {
1138                 return _stepService;
1139         }
1140
1141         /**
1142          * Set the stepService.
1143          * 
1144          * @param stepService
1145          *            the stepService to set
1146          */
1147         public void setStepService(final StepService stepService) {
1148                 _stepService = stepService;
1149         }
1150
1151         /**
1152          * Get the indexService.
1153          * 
1154          * @return the indexService
1155          */
1156         public IndexService getIndexService() {
1157                 return _indexService;
1158         }
1159
1160         /**
1161          * Set the indexService.
1162          * 
1163          * @param indexService
1164          *            the indexService to set
1165          */
1166         public void setIndexService(final IndexService indexService) {
1167                 _indexService = indexService;
1168         }
1169
1170         /**
1171          * Get the studyDAO.
1172          * 
1173          * @return the studyDAO
1174          */
1175         public StudyDAO getStudyDAO() {
1176                 return _studyDAO;
1177         }
1178
1179         /**
1180          * Set the studyDAO.
1181          * 
1182          * @param studyDAO
1183          *            the studyDAO to set
1184          */
1185         public void setStudyDAO(final StudyDAO studyDAO) {
1186                 _studyDAO = studyDAO;
1187         }
1188
1189         /**
1190          * Get the iDBuilderDAO.
1191          * 
1192          * @return the iDBuilderDAO
1193          */
1194         public IDBuilderDAO getIDBuilderDAO() {
1195                 return _iDBuilderDAO;
1196         }
1197
1198         /**
1199          * Set the iDBuilderDAO.
1200          * 
1201          * @param builderDAO
1202          *            the iDBuilderDAO to set
1203          */
1204         public void setIDBuilderDAO(final IDBuilderDAO builderDAO) {
1205                 _iDBuilderDAO = builderDAO;
1206         }
1207
1208         /**
1209          * Get the scenarioDAO.
1210          * 
1211          * @return the scenarioDAO
1212          */
1213         public ScenarioDAO getScenarioDAO() {
1214                 return _scenarioDAO;
1215         }
1216
1217         /**
1218          * Set the scenarioDAO.
1219          * 
1220          * @param scenarioDAO
1221          *            the scenarioDAO to set
1222          */
1223         public void setScenarioDAO(final ScenarioDAO scenarioDAO) {
1224                 _scenarioDAO = scenarioDAO;
1225         }
1226
1227         /**
1228          * Get the validationCycleDAO.
1229          * 
1230          * @return the validationCycleDAO
1231          */
1232         public ValidationCycleDAO getValidationCycleDAO() {
1233                 return _validationCycleDAO;
1234         }
1235
1236         /**
1237          * Set the validationCycleDAO.
1238          * 
1239          * @param validationCycleDAO
1240          *            the validationCycleDAO to set
1241          */
1242         public void setValidationCycleDAO(
1243                         final ValidationCycleDAO validationCycleDAO) {
1244                 _validationCycleDAO = validationCycleDAO;
1245         }
1246
1247         /**
1248          * Get the documentTypeService.
1249          * 
1250          * @return the documentTypeService
1251          */
1252         public DocumentTypeService getDocumentTypeService() {
1253                 return _documentTypeService;
1254         }
1255
1256         /**
1257          * Set the documentTypeService.
1258          * 
1259          * @param documentTypeService
1260          *            the documentTypeService to set
1261          */
1262         public void setDocumentTypeService(
1263                         final DocumentTypeService documentTypeService) {
1264                 _documentTypeService = documentTypeService;
1265         }
1266
1267         /**
1268          * Get the userService.
1269          * 
1270          * @return the userService
1271          */
1272         public UserService getUserService() {
1273                 return _userService;
1274         }
1275
1276         /**
1277          * Set the userService.
1278          * 
1279          * @param userService
1280          *            the userService to set
1281          */
1282         public void setUserService(final UserService userService) {
1283                 _userService = userService;
1284         }
1285
1286         /**
1287          * Get the publicationDAO.
1288          * @return the publicationDAO
1289          */
1290         public PublicationDAO getPublicationDAO() {
1291                 return _publicationDAO;
1292         }
1293
1294         /**
1295          * Set the publicationDAO.
1296          * @param publicationDAO the publicationDAO to set
1297          */
1298         public void setPublicationDAO(final PublicationDAO publicationDAO) {
1299                 _publicationDAO = publicationDAO;
1300         }
1301
1302         /**
1303          * Get the repositoryService.
1304          * @return the repositoryService
1305          */
1306         public RepositoryService getRepositoryService() {
1307                 return _repositoryService;
1308         }
1309
1310         /**
1311          * Set the repositoryService.
1312          * @param repositoryService the repositoryService to set
1313          */
1314         public void setRepositoryService(final RepositoryService repositoryService) {
1315                 _repositoryService = repositoryService;
1316         }
1317
1318         /**
1319          * Get the documentDAO.
1320          * @return the documentDAO
1321          */
1322         public DocumentDAO getDocumentDAO() {
1323                 return _documentDAO;
1324         }
1325
1326         /**
1327          * Set the documentDAO.
1328          * @param documentDAO the documentDAO to set
1329          */
1330         public void setDocumentDAO(final DocumentDAO documentDAO) {
1331                 _documentDAO = documentDAO;
1332         }
1333
1334         /**
1335          * Get the descriptionAttributeDAO.
1336          * @return the descriptionAttributeDAO
1337          */
1338         public DescriptionAttributeDAO getDescriptionAttributeDAO() {
1339                 return _descriptionAttributeDAO;
1340         }
1341
1342         /**
1343          * Set the descriptionAttributeDAO.
1344          * @param descriptionAttributeDAO the descriptionAttributeDAO to set
1345          */
1346         public void setDescriptionAttributeDAO(
1347                         final DescriptionAttributeDAO descriptionAttributeDAO) {
1348                 _descriptionAttributeDAO = descriptionAttributeDAO;
1349         }
1350
1351 }