1 /*****************************************************************************
5 * Creation date 02.10.2012
6 * @author Author: Maria KRUCHININA
8 *****************************************************************************/
10 package org.splat.service;
12 import java.io.IOException;
13 import java.text.SimpleDateFormat;
14 import java.util.Calendar;
15 import java.util.Date;
16 import java.util.HashMap;
17 import java.util.Iterator;
18 import java.util.List;
20 import org.hibernate.criterion.Restrictions;
21 import org.splat.dal.bo.kernel.Relation;
22 import org.splat.dal.bo.kernel.User;
23 import org.splat.dal.bo.som.ActorRelation;
24 import org.splat.dal.bo.som.ContributorRelation;
25 import org.splat.dal.bo.som.DescriptionAttribute;
26 import org.splat.dal.bo.som.Document;
27 import org.splat.dal.bo.som.DocumentType;
28 import org.splat.dal.bo.som.IDBuilder;
29 import org.splat.dal.bo.som.KnowledgeElement;
30 import org.splat.dal.bo.som.KnowledgeElementType;
31 import org.splat.dal.bo.som.ProgressState;
32 import org.splat.dal.bo.som.Publication;
33 import org.splat.dal.bo.som.Scenario;
34 import org.splat.dal.bo.som.SimulationContext;
35 import org.splat.dal.bo.som.Study;
36 import org.splat.dal.bo.som.ValidationCycle;
37 import org.splat.dal.bo.som.ValidationCycleRelation;
38 import org.splat.dal.bo.som.Visibility;
39 import org.splat.dal.bo.som.Study.Properties;
40 import org.splat.dal.dao.som.IDBuilderDAO;
41 import org.splat.dal.dao.som.ScenarioDAO;
42 import org.splat.dal.dao.som.StudyDAO;
43 import org.splat.dal.dao.som.ValidationCycleDAO;
44 import org.splat.kernel.InvalidPropertyException;
45 import org.splat.kernel.MissedPropertyException;
46 import org.splat.kernel.MultiplyDefinedException;
47 import org.splat.kernel.UserDirectory;
48 import org.splat.log.AppLogger;
49 import org.splat.service.technical.IndexService;
50 import org.splat.service.technical.ProjectSettingsService;
51 import org.splat.som.Revision;
52 import org.springframework.transaction.annotation.Transactional;
55 * This class defines all methods for creation, modification the study.
57 * @author Maria KRUCHININA
60 public class StudyServiceImpl implements StudyService {
63 * logger for the service.
65 public final static AppLogger logger = AppLogger
66 .getLogger(StudyServiceImpl.class);
69 * Injected index service.
71 private IndexService _indexService;
74 * Injected step service.
76 private StepService _stepService;
79 * Injected scenario service.
81 private ScenarioService _scenarioService;
84 * Injected project service.
86 private ProjectSettingsService _projectSettingsService;
89 * Injected project element service.
91 private ProjectElementService _projectElementService;
96 private StudyDAO _studyDAO;
99 * Injected scenario DAO.
101 private ScenarioDAO _scenarioDAO;
104 * Injected validation cycle DAO.
106 private ValidationCycleDAO _validationCycleDAO;
109 * Injected IDBuilder DAO.
111 private IDBuilderDAO _iDBuilderDAO;
116 * @see org.splat.service.StudyService#selectStudy(long)
119 public Study selectStudy(long index) {
120 Study result = getStudyDAO().get(index);
121 result.loadWorkflow();
126 * Get study by its reference.
129 * the study reference
130 * @return found study or null
132 @Transactional(readOnly = true)
133 public Study selectStudy(String refid) {
134 Study result = getStudyDAO().findByCriteria(
135 Restrictions.eq("sid", refid));
136 result.loadWorkflow();
143 * @see org.splat.service.StudyService#createStudy(org.splat.dal.bo.som.Study.Properties)
146 public Study createStudy(Study.Properties sprop)
147 throws MissedPropertyException, InvalidPropertyException,
148 MultiplyDefinedException {
149 sprop.setReference(getProjectSettings().getReferencePattern());
150 Study study = new Study(sprop);
152 buildReference(study);
153 getStudyDAO().create(study);
155 IndexService lucin = getIndex();
157 } catch (IOException error) {
158 logger.error("Unable to index the study '" + study.getIndex()
159 + "', reason:", error);
160 // Continue and try to index later
168 * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext.Properties)
170 public SimulationContext addProjectContext(Study aStudy,
171 SimulationContext.Properties cprop) throws MissedPropertyException,
172 InvalidPropertyException, MultiplyDefinedException {
173 SimulationContext added = getStepService().addSimulationContext(
174 getProjectElementService().getFirstStep(aStudy), cprop);
182 * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
184 public SimulationContext addProjectContext(Study aStudy,
185 SimulationContext context) {
186 SimulationContext added = getStepService().addSimulationContext(
187 getProjectElementService().getFirstStep(aStudy), context);
195 * @see org.splat.service.StudyService#addContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User)
197 public boolean addContributor(Study aStudy, User user) {
198 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
199 for (Iterator<User> i = contributor.iterator(); i.hasNext();) {
200 User present = i.next();
201 if (present.equals(user))
204 boolean absent = aStudy.getModifiableActors().add(user); // User may already be a reviewer or an approver
206 aStudy.addRelation(new ContributorRelation(aStudy, user));
208 update(aStudy); // Else, useless to re-index the study
209 contributor.add(user);
214 * Moves this study from the Public to the Reference area of the repository. For being moved to the Reference area, the study must
215 * previously be approved.
219 * @return true if the move succeeded.
220 * @see #moveToPublic()
222 * @see Publication#approve(Date)
224 public boolean moveToReference(Study aStudy) {
225 if (aStudy.getProgressState() != ProgressState.APPROVED)
227 if (aStudy.getVisibility() != Visibility.PUBLIC)
230 aStudy.setVisibility(Visibility.REFERENCE);
231 if (update(aStudy)) {
232 return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
240 * @see org.splat.service.StudyService#update(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Study.Properties)
242 public boolean update(Study aStudy, Properties sprop)
243 throws InvalidPropertyException {
244 if (sprop.getTitle() != null)
245 aStudy.setTitle(sprop.getTitle());
246 if (sprop.getSummary() != null)
247 aStudy.setAttribute(new DescriptionAttribute(aStudy, sprop
249 // TODO: To be completed
250 return update(aStudy);
254 * Check if the document is published in the study.
260 * @return true if the document is published in the study
262 private boolean publishes(Study aStudy, Document doc) {
263 if (!aStudy.publishes(doc)) {
264 Scenario[] scene = aStudy.getScenarii();
265 for (int i = 0; i < scene.length; i++) {
266 if (scene[i].publishes(doc))
276 * @see org.splat.service.StudyService#removeContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User[])
278 public boolean removeContributor(Study aStudy, User... users) {
279 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
280 Boolean done = false;
281 for (int i = 0; i < users.length; i++) {
282 User user = users[i];
283 for (Iterator<User> j = contributor.iterator(); j.hasNext();) {
284 User present = j.next();
285 if (!present.equals(user))
288 aStudy.removeRelation(ContributorRelation.class, user);
289 j.remove(); // Updates the contributor shortcut
302 * @see org.splat.service.StudyService#removeProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
304 public boolean removeProjectContext(Study aStudy, SimulationContext context) {
305 boolean done = getStepService().removeSimulationContext(
306 getProjectElementService().getFirstStep(aStudy), context);
314 * @see org.splat.service.StudyService#setValidationCycle(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.DocumentType,
315 * org.splat.dal.bo.som.ValidationCycle.Properties)
318 public void setValidationCycle(Study aStudy, DocumentType type,
319 ValidationCycle.Properties vprop) {
320 HashMap<String, ValidationCycle> validactor = aStudy
321 .getValidationCycles();
322 if (validactor == null)
323 aStudy.setShortCuts(); // Initializes validactor and actor
325 String cname = type.getName();
326 ValidationCycle cycle = validactor.get(cname);
328 if (cycle != null && cycle.isAssigned()) {
329 cycle.resetActors(vprop);
332 cycle = new ValidationCycle(aStudy, vprop.setDocumentType(type));
334 getValidationCycleDAO().create(cycle); //RKV
336 ValidationCycleRelation link = cycle.getContext();
337 //RKV: aStudy.addRelation(link);
338 aStudy.getAllRelations().add(link); //RKV
340 validactor.put(cname, link.getTo()); // Replaces the cycle if exists as default,
341 } catch (Exception error) {
342 logger.error("Unable to re-index Knowledge Elements, reason:",
346 resetActorsShortCut(aStudy);
347 update(aStudy); // Re-index the study, just in case
351 * Demotes this study from In-Check to In-Draft then In-Work states. This function is called internally when demoting the final result
352 * document of the study.
356 * @return true if the demotion succeeded.
358 public boolean demote(Study aStudy) {
359 if (aStudy.getProgressState() == ProgressState.inCHECK)
360 aStudy.setProgressState(ProgressState.inDRAFT);
361 else if (aStudy.getProgressState() == ProgressState.inDRAFT)
362 aStudy.setProgressState(ProgressState.inWORK);
365 return update(aStudy);
371 * @see org.splat.service.StudyService#generateLocalIndex(org.splat.dal.bo.som.Study)
374 public int generateLocalIndex(Study aStudy) {
375 aStudy.setLastLocalIndex(aStudy.getLastLocalIndex() + 1);
376 getStudyDAO().update(aStudy);
377 return aStudy.getLastLocalIndex();
383 * @see org.splat.service.StudyService#addScenario(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Scenario.Properties)
386 public Scenario addScenario(Study aStudy, Scenario.Properties sprop)
387 throws MissedPropertyException, InvalidPropertyException,
388 MultiplyDefinedException {
389 if (sprop.getManager() == null)
390 sprop.setManager(aStudy.getAuthor());
392 Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy));
393 if (sprop.getBaseStep() != null)
395 .copyContentsUpTo(scenario, sprop.getBaseStep());
396 Scenario previous = sprop.getInsertAfter();
398 if (previous == null) {
399 aStudy.getScenariiList().add(scenario);
401 aStudy.getScenariiList().add(
402 aStudy.getScenariiList().indexOf(previous) + 1, scenario);
404 getStudyDAO().update(aStudy); // No need to update the Lucene index
405 getScenarioDAO().create(scenario); // Must be done after updating this study because of the back reference to the study
406 if (sprop.getBaseStep() != null) {
407 // No need to update the Knowledge Element index as Knowledge Elements are not copied
408 scenario.refresh(); // Because saving the scenario changes the hashcode of copied Publications
410 KnowledgeElementType ucase = KnowledgeElement.selectType("usecase");
411 KnowledgeElement.Properties kprop = new KnowledgeElement.Properties();
412 User admin = UserDirectory.selectUser(1); // First user created when creating the database
413 kprop.setType(ucase).setTitle(aStudy.getTitle()).setValue(
414 scenario.getTitle()).setAuthor(admin); // Internal Knowledge Element required by the validation process of
416 getScenarioService().addKnowledgeElement(scenario, kprop);
421 * Promotes this study from In-Work to In-Draft then In-Check and APPROVED states. This function is called internally when promoting the
422 * final result document of the study.
426 * @return true if the demotion succeeded.
428 public boolean promote(Study aStudy) {
429 if (aStudy.getProgressState() == ProgressState.inWORK) {
430 aStudy.setProgressState(ProgressState.inDRAFT);
431 } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
432 aStudy.setProgressState(ProgressState.inCHECK);
433 Revision myvers = new Revision(aStudy.getVersion());
434 if (myvers.isMinor()) {
435 aStudy.setVersion(myvers.incrementAs(aStudy.getProgressState())
438 } else if (aStudy.getProgressState() == ProgressState.inCHECK) {
439 aStudy.setProgressState(ProgressState.APPROVED);
443 return update(aStudy);
447 * Moves this study from the Private to the Public area of the repository.
451 * @return true if the move succeeded.
454 public boolean moveToPublic(Study aStudy) {
455 boolean isOk = false;
456 if (aStudy.getVisibility() == Visibility.PRIVATE) {
457 aStudy.setVisibility(Visibility.PUBLIC);
458 if (update(aStudy)) {
459 isOk = updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
466 * Update a study in the database.
469 * the study to update
470 * @return true if the study is updated successfully
473 private boolean update(Study aStudy) {
474 boolean isOk = false;
476 getStudyDAO().update(aStudy); // Update of relational base
477 getIndex().update(aStudy); // Update of Lucene index
479 } catch (Exception error) {
480 logger.error("Unable to re-index the study '" + aStudy.getIndex()
481 + "', reason:", error);
487 * Build reference for the study. The reference of the study is stored as a new reference pattern (IDBuilder).
491 * @return true if reference building is succeded
494 private boolean buildReference(Study aStudy) {
495 String pattern = aStudy.getReference(); // The study being supposed just created, its reference is the reference pattern
496 IDBuilder tool = selectIDBuilder(aStudy.getDate());
498 tool = new IDBuilder(aStudy.getDate());
499 getIDBuilderDAO().create(tool);
501 aStudy.setReference(tool.buildReference(pattern, aStudy));
506 * Find an id builder by date.
510 * @return found id builder
512 private IDBuilder selectIDBuilder(Date date) {
513 Calendar aDate = Calendar.getInstance();
515 return getIDBuilderDAO().findByCriteria(
516 Restrictions.eq("cycle", aDate.get(Calendar.YEAR)));
520 * Fill transient collection ModifiableActors of the study.
525 private void resetActorsShortCut(Study aStudy) {
526 aStudy.getModifiableActors().clear();
527 // Get all actors involved in validation cycles
528 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
529 .values().iterator(); i.hasNext();) {
530 ValidationCycle cycle = i.next();
531 User[] user = cycle.getAllActors();
532 for (int j = 0; j < user.length; j++)
533 aStudy.getModifiableActors().add(user[j]);
535 // Get all other actors
536 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
538 Relation link = i.next();
539 Class<?> kindof = link.getClass().getSuperclass();
540 if (!kindof.equals(ActorRelation.class))
542 aStudy.getModifiableActors().add(((ActorRelation) link).getTo());
547 * Update lucene index for the study knowledge elements.
551 * @return true if reindexing succeeded
553 private boolean updateKnowledgeElementsIndex(Study aStudy) {
554 boolean isOk = false;
556 IndexService lucin = getIndex();
558 for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
560 Scenario scene = i.next();
561 for (Iterator<KnowledgeElement> j = scene
562 .getAllKnowledgeElements().iterator(); j.hasNext();) {
563 KnowledgeElement kelm = j.next();
568 } catch (Exception error) {
569 logger.error("Unable to re-index Knowledge Elements, reason:",
576 * Get lucene index service. Create a lucene index if it does not exist.
578 * @return index service
579 * @throws IOException
580 * if error occurs during lucene index creation
582 private IndexService getIndex() throws IOException {
583 IndexService lucin = getIndexService();
585 lucin.create(); // Happens when re-indexing all studies
590 * Get project settings.
592 * @return Project settings service
594 private ProjectSettingsService getProjectSettings() {
595 return _projectSettingsService;
599 * Set project settings service.
601 * @param projectSettingsService
602 * project settings service
604 public void setProjectSettings(ProjectSettingsService projectSettingsService) {
605 _projectSettingsService = projectSettingsService;
609 * Get the projectElementService.
611 * @return the projectElementService
613 public ProjectElementService getProjectElementService() {
614 return _projectElementService;
618 * Set the projectElementService.
620 * @param projectElementService
621 * the projectElementService to set
623 public void setProjectElementService(
624 ProjectElementService projectElementService) {
625 _projectElementService = projectElementService;
629 * Get the stepService.
631 * @return the stepService
633 public StepService getStepService() {
638 * Set the stepService.
641 * the stepService to set
643 public void setStepService(StepService stepService) {
644 _stepService = stepService;
648 * Get the indexService.
650 * @return the indexService
652 public IndexService getIndexService() {
653 return _indexService;
657 * Set the indexService.
659 * @param indexService
660 * the indexService to set
662 public void setIndexService(IndexService indexService) {
663 _indexService = indexService;
669 * @return the studyDAO
671 public StudyDAO getStudyDAO() {
679 * the studyDAO to set
681 public void setStudyDAO(StudyDAO studyDAO) {
682 _studyDAO = studyDAO;
686 * Get the iDBuilderDAO.
688 * @return the iDBuilderDAO
690 public IDBuilderDAO getIDBuilderDAO() {
691 return _iDBuilderDAO;
695 * Set the iDBuilderDAO.
698 * the iDBuilderDAO to set
700 public void setIDBuilderDAO(IDBuilderDAO builderDAO) {
701 _iDBuilderDAO = builderDAO;
705 * Get the scenarioService.
707 * @return the scenarioService
709 public ScenarioService getScenarioService() {
710 return _scenarioService;
714 * Set the scenarioService.
716 * @param scenarioService
717 * the scenarioService to set
719 public void setScenarioService(ScenarioService scenarioService) {
720 _scenarioService = scenarioService;
724 * Get the scenarioDAO.
726 * @return the scenarioDAO
728 public ScenarioDAO getScenarioDAO() {
733 * Set the scenarioDAO.
736 * the scenarioDAO to set
738 public void setScenarioDAO(ScenarioDAO scenarioDAO) {
739 _scenarioDAO = scenarioDAO;
743 * Get the validationCycleDAO.
744 * @return the validationCycleDAO
746 public ValidationCycleDAO getValidationCycleDAO() {
747 return _validationCycleDAO;
751 * Set the validationCycleDAO.
752 * @param validationCycleDAO the validationCycleDAO to set
754 public void setValidationCycleDAO(ValidationCycleDAO validationCycleDAO) {
755 _validationCycleDAO = validationCycleDAO;