Salome HOME
Study validation cycle operations are implemented according to the specification.
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / StudyServiceImpl.java
index d75d3ccfa29cd440919d9bd6ac10de208b6a8753..86863e9829f107c5e9f56ea976c906ceb4ff4cac 100644 (file)
@@ -33,6 +33,7 @@ import org.apache.lucene.store.FSDirectory;
 import org.hibernate.Criteria;
 import org.hibernate.Hibernate;
 import org.hibernate.criterion.DetachedCriteria;
+import org.hibernate.criterion.Order;
 import org.hibernate.criterion.Restrictions;
 import org.hibernate.proxy.HibernateProxy;
 import org.jfree.chart.ChartFactory;
@@ -48,6 +49,7 @@ import org.splat.dal.bo.som.ContributorRelation;
 import org.splat.dal.bo.som.DescriptionAttribute;
 import org.splat.dal.bo.som.DocumentType;
 import org.splat.dal.bo.som.IDBuilder;
+import org.splat.dal.bo.som.KnowledgeElement;
 import org.splat.dal.bo.som.ProgressState;
 import org.splat.dal.bo.som.ProjectElement;
 import org.splat.dal.bo.som.Publication;
@@ -63,6 +65,7 @@ import org.splat.dal.bo.som.Study.Properties;
 import org.splat.dal.bo.som.ValidationCycle.Actor;
 import org.splat.dal.dao.som.DescriptionAttributeDAO;
 import org.splat.dal.dao.som.DocumentDAO;
+import org.splat.dal.dao.som.DocumentTypeDAO;
 import org.splat.dal.dao.som.IDBuilderDAO;
 import org.splat.dal.dao.som.PublicationDAO;
 import org.splat.dal.dao.som.ScenarioDAO;
@@ -190,6 +193,10 @@ public class StudyServiceImpl implements StudyService {
         * Injected description attribute DAO.
         */
        private DescriptionAttributeDAO _descriptionAttributeDAO;
+       /**
+        * Injected document type DAO.
+        */
+       private DocumentTypeDAO _documentTypeDAO;
 
        /**
         * {@inheritDoc}
@@ -339,24 +346,24 @@ public class StudyServiceImpl implements StudyService {
        @Transactional
        public boolean addContributor(final Study aStudy, final User user) {
                List<User> contributors = getModifiableContributors(aStudy); // Initializes contributor
-               
-               if(contributors.contains(user)) {
+
+               if (contributors.contains(user)) {
                        return false;
                }
-               
-               //Remove user from readers
+
+               // Remove user from readers
                try {
                        List<UserDTO> readers = getReaders(aStudy.getIndex());
-                       for(UserDTO reader : readers) {
-                               if(reader.getIndex() == user.getIndex()) {
-                                       //user must be the actual user in the relationship object in the aStudy object for this to work
+                       for (UserDTO reader : readers) {
+                               if (reader.getIndex() == user.getIndex()) {
+                                       // user must be the actual user in the relationship object in the aStudy object for this to work
                                        aStudy.removeRelation(ReaderRelation.class, user);
                                }
                        }
-               } catch(InvalidParameterException e) {
-                       LOG.error(e.getMessage(), e);   
+               } catch (InvalidParameterException e) {
+                       LOG.error(e.getMessage(), e);
                }
-               
+
                boolean absent = getModifiableActors(aStudy).add(user); // User may already be a reviewer or an approver
 
                aStudy.addRelation(new ContributorRelation(aStudy, user));
@@ -366,33 +373,6 @@ public class StudyServiceImpl implements StudyService {
                return true;
        }
 
-       /**
-        * Moves this study from the Public to the Reference area of the repository. For being moved to the Reference area, the study must
-        * previously be approved.
-        * 
-        * @param aStudy
-        *            the study to move
-        * @return true if the move succeeded.
-        * @see #moveToPublic()
-        * @see #isPublic()
-        * @see Publication#approve(Date)
-        */
-       @Transactional
-       public boolean moveToReference(final Study aStudy) {
-               if (aStudy.getProgressState() != ProgressState.APPROVED) {
-                       return false;
-               }
-               if (aStudy.getVisibility() != Visibility.PUBLIC) {
-                       return false;
-               }
-
-               aStudy.setVisibility(Visibility.REFERENCE);
-               if (update(aStudy)) {
-                       return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
-               }
-               return false;
-       }
-
        /**
         * {@inheritDoc}
         * 
@@ -434,8 +414,8 @@ public class StudyServiceImpl implements StudyService {
        public boolean removeContributor(final Study aStudy, final User... users) {
                List<User> contributors = getModifiableContributors(aStudy); // Initializes contributor
                Boolean done = false;
-               for(User user : users) {
-                       if(contributors.contains(user)) {
+               for (User user : users) {
+                       if (contributors.contains(user)) {
                                aStudy.removeRelation(ContributorRelation.class, user);
                                contributors.remove(user);
                                done = true;
@@ -504,26 +484,6 @@ public class StudyServiceImpl implements StudyService {
                update(aStudy); // Re-index the study, just in case
        }
 
-       /**
-        * Demotes this study from In-Check to In-Draft then In-Work states. This function is called internally when demoting the final result
-        * document of the study.
-        * 
-        * @param aStudy
-        *            a study to demote
-        * @return true if the demotion succeeded.
-        */
-       @Transactional
-       public boolean demote(final Study aStudy) {
-               if (aStudy.getProgressState() == ProgressState.inCHECK) {
-                       aStudy.setProgressState(ProgressState.inDRAFT);
-               } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
-                       aStudy.setProgressState(ProgressState.inWORK);
-               } else {
-                       return false;
-               }
-               return update(aStudy);
-       }
-
        /**
         * {@inheritDoc}
         * 
@@ -536,31 +496,60 @@ public class StudyServiceImpl implements StudyService {
        }
 
        /**
-        * Promotes this study from In-Work to In-Draft then In-Check and APPROVED states. This function is called internally when promoting the
-        * final result document of the study.
+        * Promotes this study from In-Work to In-Draft then In-Check and APPROVED <BR>
+        * states. This function takes into account statuses of final result<BR>
+        * documents of the study.
         * 
         * @param aStudy
         *            a study to promote
-        * @return true if the demotion succeeded.
+        * @return true if the promotion succeeded.
         */
        @Transactional
        public boolean promote(final Study aStudy) {
-               if (aStudy.getProgressState() == ProgressState.inWORK) {
+               boolean res = true;
+               if (aStudy.getProgressState() == ProgressState.inWORK
+                               && canBePromoted(aStudy)) {
                        aStudy.setProgressState(ProgressState.inDRAFT);
-               } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
+               } else if (aStudy.getProgressState() == ProgressState.inDRAFT
+                               && canBeReviewed(aStudy)) {
                        aStudy.setProgressState(ProgressState.inCHECK);
                        Revision myvers = new Revision(aStudy.getVersion());
                        if (myvers.isMinor()) {
                                aStudy.setVersion(myvers.incrementAs(aStudy.getProgressState())
                                                .toString());
                        }
-               } else if (aStudy.getProgressState() == ProgressState.inCHECK) {
+               } else if (aStudy.getProgressState() == ProgressState.inCHECK
+                               && canBeApproved(aStudy)) {
                        aStudy.setProgressState(ProgressState.APPROVED);
+                       updateKnowledgeElementsState(aStudy);
                } else {
-                       return false;
+                       res = false;
+               }
+               if (res) {
+                       res = update(aStudy);
                }
 
-               return update(aStudy);
+               return res;
+       }
+
+       /**
+        * Demotes this study from In-Check or In-Draft to In-Work states.
+        * 
+        * @param aStudy
+        *            a study to demote
+        * @return true if the demotion succeeded.
+        */
+       @Transactional
+       public boolean demote(final Study aStudy) {
+               boolean res;
+               if (aStudy.getProgressState() == ProgressState.inCHECK
+                               || aStudy.getProgressState() == ProgressState.inDRAFT) {
+                       aStudy.setProgressState(ProgressState.inWORK);
+                       res = update(aStudy);
+               } else {
+                       res = false;
+               }
+               return res;
        }
 
        /**
@@ -577,7 +566,7 @@ public class StudyServiceImpl implements StudyService {
                if (aStudy.getVisibility() == Visibility.PRIVATE) {
                        aStudy.setVisibility(Visibility.PUBLIC);
                        if (update(aStudy)) {
-                               isOk = updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
+                               isOk = updateKnowledgeElementsState(aStudy); // If fails, the database roll-back is under responsibility of the caller
                        }
                }
                return isOk;
@@ -596,7 +585,7 @@ public class StudyServiceImpl implements StudyService {
                if (aStudy.getVisibility() == Visibility.PUBLIC) {
                        aStudy.setVisibility(Visibility.PRIVATE);
                        if (update(aStudy)) {
-                               isOk = updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
+                               isOk = updateKnowledgeElementsState(aStudy); // If fails, the database roll-back is under responsibility of the caller
                        }
                }
                return isOk;
@@ -614,7 +603,7 @@ public class StudyServiceImpl implements StudyService {
                try {
                        getStudyDAO().merge(aStudy); // Update of relational base
                        setShortCuts(aStudy); // RKV: initialize transient actors set
-                       //RKV: getIndex().update(aStudy); // Update of Lucene index
+                       // RKV: getIndex().update(aStudy); // Update of Lucene index
                        isOk = true;
                } catch (Exception e) {
                        LOG.error("STD-000001", e, aStudy.getIndex(), e.getMessage());
@@ -755,27 +744,18 @@ public class StudyServiceImpl implements StudyService {
        }
 
        /**
-        * Update lucene index for the study knowledge elements.
+        * Update knowledge elements states.
         * 
         * @param aStudy
         *            the study
-        * @return true if reindexing succeeded
-        */
-       private boolean updateKnowledgeElementsIndex(final Study aStudy) {
-//             boolean isOk = false;
-//              try {
-//                      IndexService lucin = getIndex();
-//                      for(Scenario scenario : aStudy.getScenariiList()) {
-//                              for (KnowledgeElement element : scenario.getAllKnowledgeElements()) {
-//                                      lucin.update(element);
-//                              }
-//                      }
-//                      isOk = true;
-//              } catch (Exception error) {
-//                      LOG.error("Unable to re-index Knowledge Elements, reason:",
-//                      error);
-//              }
-//              return isOk;
+        * @return true if succeeded
+        */
+       private boolean updateKnowledgeElementsState(final Study aStudy) {
+               for (Scenario scenario : aStudy.getScenariiList()) {
+                       for (KnowledgeElement element : scenario.getAllKnowledgeElements()) {
+                               element.setProgressState(aStudy.getProgressState());
+                       }
+               }
                return true;
        }
 
@@ -997,14 +977,18 @@ public class StudyServiceImpl implements StudyService {
         */
        public ValidationCycle getValidationCycleOf(final Study aStudy,
                        final DocumentType type) {
-               if (aStudy.getValidationCycles() == null
-                               || aStudy.getValidationCycles().isEmpty()) {
-                       setShortCuts(aStudy);
+               ValidationCycle result = null;
+               if (aStudy != null) {
+                       if (aStudy.getValidationCycles() == null
+                                       || aStudy.getValidationCycles().isEmpty()) {
+                               setShortCuts(aStudy);
+                       }
+                       if (type != null) {
+                               result = aStudy.getValidationCycles().get(type.getName());
+                       }
                }
-               ValidationCycle result = aStudy.getValidationCycles().get(
-                               type.getName());
-               if (result == null) {
-                       if (type.isStepResult()) {
+               if ((result == null) && (aStudy != null)) {
+                       if ((type == null) || type.isStepResult()) {
                                result = aStudy.getValidationCycles().get("default"); // "default" validation cycle defined in the configuration, if exist
                        }
                        if (result == null) {
@@ -1142,11 +1126,15 @@ public class StudyServiceImpl implements StudyService {
         * @see org.splat.service.StudyService#markStudyAsReference(org.splat.dal.bo.som.Study)
         */
        @Transactional
-       public void markStudyAsReference(final Study aStudy) {
-
-               aStudy.setMarkreference(1);
-               aStudy.setProgressState(ProgressState.TEMPLATE);
-               getStudyDAO().merge(aStudy);
+       public boolean markStudyAsReference(final Study aStudy) {
+               boolean res = false;
+               if (aStudy.getProgressState() == ProgressState.APPROVED) {
+                       aStudy.setMarkreference(1);
+                       aStudy.setProgressState(ProgressState.TEMPLATE);
+                       res = updateKnowledgeElementsState(aStudy);
+                       getStudyDAO().merge(aStudy);
+               }
+               return res;
        }
 
        /**
@@ -1157,9 +1145,9 @@ public class StudyServiceImpl implements StudyService {
         */
        @Transactional
        public void removeStudyAsReference(final Study aStudy) {
-
                aStudy.setMarkreference(0);
                aStudy.setProgressState(ProgressState.APPROVED);
+               updateKnowledgeElementsState(aStudy);
                getStudyDAO().merge(aStudy);
        }
 
@@ -1349,45 +1337,52 @@ public class StudyServiceImpl implements StudyService {
                } catch (DocumentException e) {
                        LOG.error("Sorry, the DocumentException is thrown.", e);
                }
-       
+
                return resultPath;
        }
-       
-       /** 
+
+       /**
         * {@inheritDoc}
+        * 
         * @see org.splat.service.StudyService#getReaders(long)
         */
        @Transactional(readOnly = true)
-       public List<UserDTO> getReaders(final long studyId) throws InvalidParameterException {
+       public List<UserDTO> getReaders(final long studyId)
+                       throws InvalidParameterException {
                Study aStudy = selectStudy(studyId);
-               if(aStudy == null){
-                       throw new InvalidParameterException(PARAM_STUDY_ID, String.valueOf(studyId));
+               if (aStudy == null) {
+                       throw new InvalidParameterException(PARAM_STUDY_ID, String
+                                       .valueOf(studyId));
                }
                List<Relation> relations = aStudy.getRelations(ReaderRelation.class);
                List<UserDTO> result = new ArrayList<UserDTO>();
-               for(Relation relation : relations){
+               for (Relation relation : relations) {
                        result.add(BeanHelper.copyBean(relation.getTo(), UserDTO.class));
                }
                return Collections.unmodifiableList(result);
        }
-       
-       /** 
+
+       /**
         * {@inheritDoc}
+        * 
         * @see org.splat.service.StudyService#addReader(long, long)
         */
        @Transactional
-       public boolean addReader(final long studyId, final long userId) throws InvalidParameterException {
+       public boolean addReader(final long studyId, final long userId)
+                       throws InvalidParameterException {
                Study aStudy = selectStudy(studyId);
-               if(aStudy == null){
-                       throw new InvalidParameterException(PARAM_STUDY_ID, String.valueOf(studyId));
+               if (aStudy == null) {
+                       throw new InvalidParameterException(PARAM_STUDY_ID, String
+                                       .valueOf(studyId));
                }
                User user = _userService.selectUser(userId);
-               if(user == null){
-                       throw new InvalidParameterException("userId", String.valueOf(userId));
+               if (user == null) {
+                       throw new InvalidParameterException("userId", String
+                                       .valueOf(userId));
                }
 
-               for(Relation relation : aStudy.getRelations(ReaderRelation.class)) {
-                       if(user.equals(relation.getTo())) {
+               for (Relation relation : aStudy.getRelations(ReaderRelation.class)) {
+                       if (user.equals(relation.getTo())) {
                                return false;
                        }
                }
@@ -1396,26 +1391,30 @@ public class StudyServiceImpl implements StudyService {
                return true;
        }
 
-       /** 
+       /**
         * {@inheritDoc}
+        * 
         * @see org.splat.service.StudyService#removeReader(long, long)
         */
        @Transactional
-       public boolean removeReader(final long studyId, final long userId) throws InvalidParameterException {
+       public boolean removeReader(final long studyId, final long userId)
+                       throws InvalidParameterException {
                Study aStudy = selectStudy(studyId);
-               if(aStudy == null){
-                       throw new InvalidParameterException(PARAM_STUDY_ID, String.valueOf(studyId));
+               if (aStudy == null) {
+                       throw new InvalidParameterException(PARAM_STUDY_ID, String
+                                       .valueOf(studyId));
                }
                User user = _userService.selectUser(userId);
-               if(user == null){
-                       throw new InvalidParameterException("userId", String.valueOf(userId));
+               if (user == null) {
+                       throw new InvalidParameterException("userId", String
+                                       .valueOf(userId));
                }
 
                Relation relation = aStudy.removeRelation(ReaderRelation.class, user);
                update(aStudy);
                return relation != null;
        }
-       
+
        /**
         * Get project settings.
         * 
@@ -1808,4 +1807,91 @@ public class StudyServiceImpl implements StudyService {
                _usedByRelationDAO = usedByRelationDAO;
        }
 
+       /**
+        * {@inheritDoc}
+        * 
+        * @see org.splat.service.StudyService#getStudyResultType(org.splat.dal.bo.som.Study)
+        */
+       @Override
+       @Transactional(readOnly = true)
+       public DocumentType getStudyResultType(final Study study) {
+               DetachedCriteria query = DetachedCriteria.forClass(DocumentType.class)
+                               .addOrder(Order.desc("result"));
+               return getDocumentTypeDAO().getFirstResult(query);
+       }
+
+       /**
+        * Get the documentTypeDAO.
+        * 
+        * @return the documentTypeDAO
+        */
+       public DocumentTypeDAO getDocumentTypeDAO() {
+               return _documentTypeDAO;
+       }
+
+       /**
+        * Set the documentTypeDAO.
+        * 
+        * @param documentTypeDAO
+        *            the documentTypeDAO to set
+        */
+       public void setDocumentTypeDAO(final DocumentTypeDAO documentTypeDAO) {
+               _documentTypeDAO = documentTypeDAO;
+       }
+
+       /**
+        * {@inheritDoc}
+        * 
+        * @see org.splat.service.StudyService#canBeApproved(org.splat.dal.bo.som.Study)
+        */
+       @Override
+       @Transactional(readOnly = true)
+       public boolean canBeApproved(final Study study) {
+               return resultDocsAtLeast(study, ProgressState.APPROVED);
+       }
+
+       /**
+        * {@inheritDoc}
+        * 
+        * @see org.splat.service.StudyService#canBePromoted(org.splat.dal.bo.som.Study)
+        */
+       @Override
+       @Transactional(readOnly = true)
+       public boolean canBePromoted(final Study study) {
+               return resultDocsAtLeast(study, ProgressState.inDRAFT);
+       }
+
+       /**
+        * {@inheritDoc}
+        * 
+        * @see org.splat.service.StudyService#canBeReviewed(org.splat.dal.bo.som.Study)
+        */
+       @Override
+       @Transactional(readOnly = true)
+       public boolean canBeReviewed(final Study study) {
+               return resultDocsAtLeast(study, ProgressState.inCHECK);
+       }
+
+       /**
+        * Check that all result documents of the study are at least in the given state.
+        * 
+        * @param study
+        *            the study to check
+        * @param state
+        *            the minimal acceptable state
+        * @return true if study result documents have acceptable states
+        */
+       private boolean resultDocsAtLeast(final Study study,
+                       final ProgressState state) {
+               boolean res = true;
+               // Check that all study result documents have the state APPROVED or more.
+               for (Publication pub : getProjectElementService().getLastStep(study)
+                               .getResultDocuments()) {
+                       res = pub.getProgressState().compareTo(ProgressState.APPROVED) >= 0;
+                       if (!res) {
+                               break;
+                       }
+               }
+               return res;
+       }
 }