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.kernel.InvalidPropertyException;
44 import org.splat.kernel.MissedPropertyException;
45 import org.splat.kernel.MultiplyDefinedException;
46 import org.splat.kernel.UserDirectory;
47 import org.splat.log.AppLogger;
48 import org.splat.service.technical.IndexService;
49 import org.splat.service.technical.ProjectSettingsService;
50 import org.splat.som.Revision;
51 import org.springframework.transaction.annotation.Transactional;
54 * This class defines all methods for creation, modification the study.
56 * @author Maria KRUCHININA
59 public class StudyServiceImpl implements StudyService {
62 * logger for the service.
64 public final static AppLogger logger = AppLogger
65 .getLogger(StudyServiceImpl.class);
68 * Injected index service.
70 private IndexService _indexService;
73 * Injected step service.
75 private StepService _stepService;
78 * Injected scenario service.
80 private ScenarioService _scenarioService;
83 * Injected project service.
85 private ProjectSettingsService _projectSettingsService;
88 * Injected project element service.
90 private ProjectElementService _projectElementService;
95 private StudyDAO _studyDAO;
98 * Injected scenario DAO.
100 private ScenarioDAO _scenarioDAO;
103 * Injected IDBuilder DAO.
105 private IDBuilderDAO _iDBuilderDAO;
110 * @see org.splat.service.StudyService#selectStudy(long)
113 public Study selectStudy(long index) {
114 Study result = getStudyDAO().get(index);
115 result.loadWorkflow();
120 * Get study by its reference.
123 * the study reference
124 * @return found study or null
126 @Transactional(readOnly = true)
127 public Study selectStudy(String refid) {
128 Study result = getStudyDAO().findByCriteria(
129 Restrictions.eq("sid", refid));
130 result.loadWorkflow();
137 * @see org.splat.service.StudyService#createStudy(org.splat.dal.bo.som.Study.Properties)
140 public Study createStudy(Study.Properties sprop)
141 throws MissedPropertyException, InvalidPropertyException,
142 MultiplyDefinedException {
143 sprop.setReference(getProjectSettings().getReferencePattern());
144 Study study = new Study(sprop);
146 buildReference(study);
147 getStudyDAO().create(study);
149 IndexService lucin = getIndex();
151 } catch (IOException error) {
152 logger.error("Unable to index the study '" + study.getIndex()
153 + "', reason:", error);
154 // Continue and try to index later
162 * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext.Properties)
164 public SimulationContext addProjectContext(Study aStudy,
165 SimulationContext.Properties cprop) throws MissedPropertyException,
166 InvalidPropertyException, MultiplyDefinedException {
167 SimulationContext added = getStepService().addSimulationContext(
168 getProjectElementService().getFirstStep(aStudy), cprop);
176 * @see org.splat.service.StudyService#addProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
178 public SimulationContext addProjectContext(Study aStudy,
179 SimulationContext context) {
180 SimulationContext added = getStepService().addSimulationContext(
181 getProjectElementService().getFirstStep(aStudy), context);
189 * @see org.splat.service.StudyService#addContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User)
191 public boolean addContributor(Study aStudy, User user) {
192 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
193 for (Iterator<User> i = contributor.iterator(); i.hasNext();) {
194 User present = i.next();
195 if (present.equals(user))
198 boolean absent = aStudy.getModifiableActors().add(user); // User may already be a reviewer or an approver
200 aStudy.addRelation(new ContributorRelation(aStudy, user));
202 update(aStudy); // Else, useless to re-index the study
203 contributor.add(user);
208 * Moves this study from the Public to the Reference area of the repository. For being moved to the Reference area, the study must
209 * previously be approved.
213 * @return true if the move succeeded.
214 * @see #moveToPublic()
216 * @see Publication#approve(Date)
218 public boolean moveToReference(Study aStudy) {
219 if (aStudy.getProgressState() != ProgressState.APPROVED)
221 if (aStudy.getVisibility() != Visibility.PUBLIC)
224 aStudy.setVisibility(Visibility.REFERENCE);
225 if (update(aStudy)) {
226 return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
234 * @see org.splat.service.StudyService#update(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Study.Properties)
236 public boolean update(Study aStudy, Properties sprop)
237 throws InvalidPropertyException {
238 if (sprop.getTitle() != null)
239 aStudy.setTitle(sprop.getTitle());
240 if (sprop.getSummary() != null)
241 aStudy.setAttribute(new DescriptionAttribute(aStudy, sprop
243 // TODO: To be completed
244 return update(aStudy);
248 * Check if the document is published in the study.
254 * @return true if the document is published in the study
256 private boolean publishes(Study aStudy, Document doc) {
257 if (!aStudy.publishes(doc)) {
258 Scenario[] scene = aStudy.getScenarii();
259 for (int i = 0; i < scene.length; i++) {
260 if (scene[i].publishes(doc))
270 * @see org.splat.service.StudyService#removeContributor(org.splat.dal.bo.som.Study, org.splat.dal.bo.kernel.User[])
272 public boolean removeContributor(Study aStudy, User... users) {
273 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
274 Boolean done = false;
275 for (int i = 0; i < users.length; i++) {
276 User user = users[i];
277 for (Iterator<User> j = contributor.iterator(); j.hasNext();) {
278 User present = j.next();
279 if (!present.equals(user))
282 aStudy.removeRelation(ContributorRelation.class, user);
283 j.remove(); // Updates the contributor shortcut
296 * @see org.splat.service.StudyService#removeProjectContext(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.SimulationContext)
298 public boolean removeProjectContext(Study aStudy, SimulationContext context) {
299 boolean done = getStepService().removeSimulationContext(
300 getProjectElementService().getFirstStep(aStudy), context);
308 * @see org.splat.service.StudyService#setValidationCycle(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.DocumentType,
309 * org.splat.dal.bo.som.ValidationCycle.Properties)
311 public void setValidationCycle(Study aStudy, DocumentType type,
312 ValidationCycle.Properties vprop) {
313 HashMap<String, ValidationCycle> validactor = aStudy
314 .getValidationCycles();
315 if (validactor == null)
316 aStudy.setShortCuts(); // Initializes validactor and actor
318 String cname = type.getName();
319 ValidationCycle cycle = validactor.get(cname);
321 if (cycle != null && cycle.isAssigned()) {
322 cycle.resetActors(vprop);
325 cycle = new ValidationCycle(aStudy, vprop.setDocumentType(type));
327 ValidationCycleRelation link = cycle.getContext();
328 aStudy.addRelation(link);
329 validactor.put(cname, link.getTo()); // Replaces the cycle if exists as default,
330 } catch (Exception error) {
331 logger.error("Unable to re-index Knowledge Elements, reason:",
335 resetActorsShortCut(aStudy);
336 update(aStudy); // Re-index the study, just in case
340 * Demotes this study from In-Check to In-Draft then In-Work states. This function is called internally when demoting the final result
341 * document of the study.
345 * @return true if the demotion succeeded.
347 public boolean demote(Study aStudy) {
348 if (aStudy.getProgressState() == ProgressState.inCHECK)
349 aStudy.setProgressState(ProgressState.inDRAFT);
350 else if (aStudy.getProgressState() == ProgressState.inDRAFT)
351 aStudy.setProgressState(ProgressState.inWORK);
354 return update(aStudy);
360 * @see org.splat.service.StudyService#generateLocalIndex(org.splat.dal.bo.som.Study)
363 public int generateLocalIndex(Study aStudy) {
364 aStudy.setLastLocalIndex(aStudy.getLastLocalIndex() + 1);
365 getStudyDAO().update(aStudy);
366 return aStudy.getLastLocalIndex();
372 * @see org.splat.service.StudyService#addScenario(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Scenario.Properties)
375 public Scenario addScenario(Study aStudy, Scenario.Properties sprop)
376 throws MissedPropertyException, InvalidPropertyException,
377 MultiplyDefinedException {
378 if (sprop.getManager() == null)
379 sprop.setManager(aStudy.getAuthor());
381 Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy));
382 if (sprop.getBaseStep() != null)
384 .copyContentsUpTo(scenario, sprop.getBaseStep());
385 Scenario previous = sprop.getInsertAfter();
387 if (previous == null) {
388 aStudy.getScenariiList().add(scenario);
390 aStudy.getScenariiList().add(
391 aStudy.getScenariiList().indexOf(previous) + 1, scenario);
393 getStudyDAO().update(aStudy); // No need to update the Lucene index
394 getScenarioDAO().create(scenario); // Must be done after updating this study because of the back reference to the study
395 if (sprop.getBaseStep() != null) {
396 // No need to update the Knowledge Element index as Knowledge Elements are not copied
397 scenario.refresh(); // Because saving the scenario changes the hashcode of copied Publications
399 KnowledgeElementType ucase = KnowledgeElement.selectType("usecase");
400 KnowledgeElement.Properties kprop = new KnowledgeElement.Properties();
401 User admin = UserDirectory.selectUser(1); // First user created when creating the database
402 kprop.setType(ucase).setTitle(aStudy.getTitle()).setValue(
403 scenario.getTitle()).setAuthor(admin); // Internal Knowledge Element required by the validation process of
405 getScenarioService().addKnowledgeElement(scenario, kprop);
410 * Promotes this study from In-Work to In-Draft then In-Check and APPROVED states. This function is called internally when promoting the
411 * final result document of the study.
415 * @return true if the demotion succeeded.
417 public boolean promote(Study aStudy) {
418 if (aStudy.getProgressState() == ProgressState.inWORK) {
419 aStudy.setProgressState(ProgressState.inDRAFT);
420 } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
421 aStudy.setProgressState(ProgressState.inCHECK);
422 Revision myvers = new Revision(aStudy.getVersion());
423 if (myvers.isMinor()) {
424 aStudy.setVersion(myvers.incrementAs(aStudy.getProgressState())
427 } else if (aStudy.getProgressState() == ProgressState.inCHECK) {
428 aStudy.setProgressState(ProgressState.APPROVED);
432 return update(aStudy);
436 * Moves this study from the Private to the Public area of the repository.
440 * @return true if the move succeeded.
443 public boolean moveToPublic(Study aStudy) {
444 boolean isOk = false;
445 if (aStudy.getVisibility() == Visibility.PRIVATE) {
446 aStudy.setVisibility(Visibility.PUBLIC);
447 if (update(aStudy)) {
448 isOk = updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
455 * Update a study in the database.
458 * the study to update
459 * @return true if the study is updated successfully
462 private boolean update(Study aStudy) {
463 boolean isOk = false;
465 getStudyDAO().update(aStudy); // Update of relational base
466 getIndex().update(aStudy); // Update of Lucene index
468 } catch (Exception error) {
469 logger.error("Unable to re-index the study '" + aStudy.getIndex()
470 + "', reason:", error);
476 * Build reference for the study. The reference of the study is stored as a new reference pattern (IDBuilder).
480 * @return true if reference building is succeded
483 private boolean buildReference(Study aStudy) {
484 String pattern = aStudy.getReference(); // The study being supposed just created, its reference is the reference pattern
485 IDBuilder tool = selectIDBuilder(aStudy.getDate());
487 tool = new IDBuilder(aStudy.getDate());
488 getIDBuilderDAO().create(tool);
490 aStudy.setReference(tool.buildReference(pattern, aStudy));
495 * Find an id builder by date.
499 * @return found id builder
501 private IDBuilder selectIDBuilder(Date date) {
502 Calendar aDate = Calendar.getInstance();
504 return getIDBuilderDAO().findByCriteria(
505 Restrictions.eq("cycle", aDate.get(Calendar.YEAR)));
509 * Fill transient collection ModifiableActors of the study.
514 private void resetActorsShortCut(Study aStudy) {
515 aStudy.getModifiableActors().clear();
516 // Get all actors involved in validation cycles
517 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
518 .values().iterator(); i.hasNext();) {
519 ValidationCycle cycle = i.next();
520 User[] user = cycle.getAllActors();
521 for (int j = 0; j < user.length; j++)
522 aStudy.getModifiableActors().add(user[j]);
524 // Get all other actors
525 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
527 Relation link = i.next();
528 Class<?> kindof = link.getClass().getSuperclass();
529 if (!kindof.equals(ActorRelation.class))
531 aStudy.getModifiableActors().add(((ActorRelation) link).getTo());
536 * Update lucene index for the study knowledge elements.
540 * @return true if reindexing succeeded
542 private boolean updateKnowledgeElementsIndex(Study aStudy) {
543 boolean isOk = false;
545 IndexService lucin = getIndex();
547 for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
549 Scenario scene = i.next();
550 for (Iterator<KnowledgeElement> j = scene
551 .getAllKnowledgeElements().iterator(); j.hasNext();) {
552 KnowledgeElement kelm = j.next();
557 } catch (Exception error) {
558 logger.error("Unable to re-index Knowledge Elements, reason:",
565 * Get lucene index service. Create a lucene index if it does not exist.
567 * @return index service
568 * @throws IOException
569 * if error occurs during lucene index creation
571 private IndexService getIndex() throws IOException {
572 IndexService lucin = getIndexService();
574 lucin.create(); // Happens when re-indexing all studies
579 * Get project settings.
581 * @return Project settings service
583 private ProjectSettingsService getProjectSettings() {
584 return _projectSettingsService;
588 * Set project settings service.
590 * @param projectSettingsService
591 * project settings service
593 public void setProjectSettings(ProjectSettingsService projectSettingsService) {
594 _projectSettingsService = projectSettingsService;
598 * Get the projectElementService.
600 * @return the projectElementService
602 public ProjectElementService getProjectElementService() {
603 return _projectElementService;
607 * Set the projectElementService.
609 * @param projectElementService
610 * the projectElementService to set
612 public void setProjectElementService(
613 ProjectElementService projectElementService) {
614 _projectElementService = projectElementService;
618 * Get the stepService.
620 * @return the stepService
622 public StepService getStepService() {
627 * Set the stepService.
630 * the stepService to set
632 public void setStepService(StepService stepService) {
633 _stepService = stepService;
637 * Get the indexService.
639 * @return the indexService
641 public IndexService getIndexService() {
642 return _indexService;
646 * Set the indexService.
648 * @param indexService
649 * the indexService to set
651 public void setIndexService(IndexService indexService) {
652 _indexService = indexService;
658 * @return the studyDAO
660 public StudyDAO getStudyDAO() {
668 * the studyDAO to set
670 public void setStudyDAO(StudyDAO studyDAO) {
671 _studyDAO = studyDAO;
675 * Get the iDBuilderDAO.
677 * @return the iDBuilderDAO
679 public IDBuilderDAO getIDBuilderDAO() {
680 return _iDBuilderDAO;
684 * Set the iDBuilderDAO.
687 * the iDBuilderDAO to set
689 public void setIDBuilderDAO(IDBuilderDAO builderDAO) {
690 _iDBuilderDAO = builderDAO;
694 * Get the scenarioService.
696 * @return the scenarioService
698 public ScenarioService getScenarioService() {
699 return _scenarioService;
703 * Set the scenarioService.
705 * @param scenarioService
706 * the scenarioService to set
708 public void setScenarioService(ScenarioService scenarioService) {
709 _scenarioService = scenarioService;
713 * Get the scenarioDAO.
715 * @return the scenarioDAO
717 public ScenarioDAO getScenarioDAO() {
722 * Set the scenarioDAO.
725 * the scenarioDAO to set
727 public void setScenarioDAO(ScenarioDAO scenarioDAO) {
728 _scenarioDAO = scenarioDAO;