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