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