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 SimpleDateFormat year = new SimpleDateFormat("yyyy");
503 String cycle = year.format(date);
504 // StringBuffer buffer = new StringBuffer("from IDBuilder where cycle='")
505 // .append(cycle).append("'");
506 // String qstring = buffer.toString();
507 // Query query = Database.getSession().createQuery(qstring);
508 // IDBuilder result = (IDBuilder) query.uniqueResult();
512 // Calendar aDate = Calendar.getInstance();
513 // aDate.setTime(date);
514 // return getIDBuilderDAO().findByCriteria(
515 // Restrictions.eq("cycle", aDate.get(Calendar.YEAR)));
516 return getIDBuilderDAO()
517 .findByCriteria(Restrictions.eq("cycle", cycle));
521 * Fill transient collection ModifiableActors of the study.
526 private void resetActorsShortCut(Study aStudy) {
527 aStudy.getModifiableActors().clear();
528 // Get all actors involved in validation cycles
529 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
530 .values().iterator(); i.hasNext();) {
531 ValidationCycle cycle = i.next();
532 User[] user = cycle.getAllActors();
533 for (int j = 0; j < user.length; j++)
534 aStudy.getModifiableActors().add(user[j]);
536 // Get all other actors
537 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
539 Relation link = i.next();
540 Class<?> kindof = link.getClass().getSuperclass();
541 if (!kindof.equals(ActorRelation.class))
543 aStudy.getModifiableActors().add(((ActorRelation) link).getTo());
548 * Update lucene index for the study knowledge elements.
552 * @return true if reindexing succeeded
554 private boolean updateKnowledgeElementsIndex(Study aStudy) {
555 boolean isOk = false;
557 IndexService lucin = getIndex();
559 for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
561 Scenario scene = i.next();
562 for (Iterator<KnowledgeElement> j = scene
563 .getAllKnowledgeElements().iterator(); j.hasNext();) {
564 KnowledgeElement kelm = j.next();
569 } catch (Exception error) {
570 logger.error("Unable to re-index Knowledge Elements, reason:",
577 * Get lucene index service. Create a lucene index if it does not exist.
579 * @return index service
580 * @throws IOException
581 * if error occurs during lucene index creation
583 private IndexService getIndex() throws IOException {
584 IndexService lucin = getIndexService();
586 lucin.create(); // Happens when re-indexing all studies
591 * Get project settings.
593 * @return Project settings service
595 private ProjectSettingsService getProjectSettings() {
596 return _projectSettingsService;
600 * Set project settings service.
602 * @param projectSettingsService
603 * project settings service
605 public void setProjectSettings(ProjectSettingsService projectSettingsService) {
606 _projectSettingsService = projectSettingsService;
610 * Get the projectElementService.
612 * @return the projectElementService
614 public ProjectElementService getProjectElementService() {
615 return _projectElementService;
619 * Set the projectElementService.
621 * @param projectElementService
622 * the projectElementService to set
624 public void setProjectElementService(
625 ProjectElementService projectElementService) {
626 _projectElementService = projectElementService;
630 * Get the stepService.
632 * @return the stepService
634 public StepService getStepService() {
639 * Set the stepService.
642 * the stepService to set
644 public void setStepService(StepService stepService) {
645 _stepService = stepService;
649 * Get the indexService.
651 * @return the indexService
653 public IndexService getIndexService() {
654 return _indexService;
658 * Set the indexService.
660 * @param indexService
661 * the indexService to set
663 public void setIndexService(IndexService indexService) {
664 _indexService = indexService;
670 * @return the studyDAO
672 public StudyDAO getStudyDAO() {
680 * the studyDAO to set
682 public void setStudyDAO(StudyDAO studyDAO) {
683 _studyDAO = studyDAO;
687 * Get the iDBuilderDAO.
689 * @return the iDBuilderDAO
691 public IDBuilderDAO getIDBuilderDAO() {
692 return _iDBuilderDAO;
696 * Set the iDBuilderDAO.
699 * the iDBuilderDAO to set
701 public void setIDBuilderDAO(IDBuilderDAO builderDAO) {
702 _iDBuilderDAO = builderDAO;
706 * Get the scenarioService.
708 * @return the scenarioService
710 public ScenarioService getScenarioService() {
711 return _scenarioService;
715 * Set the scenarioService.
717 * @param scenarioService
718 * the scenarioService to set
720 public void setScenarioService(ScenarioService scenarioService) {
721 _scenarioService = scenarioService;
725 * Get the scenarioDAO.
727 * @return the scenarioDAO
729 public ScenarioDAO getScenarioDAO() {
734 * Set the scenarioDAO.
737 * the scenarioDAO to set
739 public void setScenarioDAO(ScenarioDAO scenarioDAO) {
740 _scenarioDAO = scenarioDAO;