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.Date;
15 import java.util.HashMap;
16 import java.util.Iterator;
17 import java.util.List;
19 import org.hibernate.Query;
20 import org.hibernate.Session;
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.Database;
41 import org.splat.dal.dao.som.StudyDAO;
42 import org.splat.kernel.InvalidPropertyException;
43 import org.splat.kernel.MissedPropertyException;
44 import org.splat.kernel.MultiplyDefinedException;
45 import org.splat.kernel.UserDirectory;
46 import org.splat.log.AppLogger;
47 import org.splat.service.technical.IndexService;
48 import org.splat.service.technical.ProjectSettingsService;
49 import org.splat.som.Revision;
50 import org.springframework.transaction.annotation.Transactional;
53 * This class defines all methods for creation, modification the study.
55 * @author Maria KRUCHININA
58 public class StudyServiceImpl implements StudyService {
61 * logger for the service.
63 public final static AppLogger logger = AppLogger
64 .getLogger(StudyServiceImpl.class);
67 * Injected index service.
69 private IndexService _indexService;
72 * Injected step service.
74 private StepService _stepService;
77 * Injected scenario service.
79 private ScenarioService _scenarioService;
82 * Injected project service.
84 private ProjectSettingsService _projectSettingsService;
87 * Injected project element service.
89 private ProjectElementService _projectElementService;
94 private StudyDAO _studyDAO;
98 * @see org.splat.service.StudyService#selectStudy(long)
101 public Study selectStudy(long index) {
102 Study result = getStudyDAO().get(index);
103 result.loadWorkflow();
107 public Study selectStudy(String refid) {
108 // ----------------------------------------------
109 StringBuffer query = new StringBuffer("from Study where sid='").append(
111 Study result = (Study) Database.getSession().createQuery(
112 query.toString()).uniqueResult();
114 result.loadWorkflow();
119 public Study createStudy(Study.Properties sprop)
120 throws MissedPropertyException, InvalidPropertyException,
121 MultiplyDefinedException, RuntimeException {
122 sprop.setReference(getProjectSettings().getReferencePattern());
123 Study study = new Study(sprop);
125 buildReference(study);
126 getStudyDAO().create(study);
128 IndexService lucin = getIndex();
130 } catch (IOException error) {
131 logger.error("Unable to index the study '" + study.getIndex()
132 + "', reason:", error);
133 // Continue and try to index later
138 public IndexService getIndex() throws IOException {
139 IndexService lucin = getIndexService();
141 lucin.create(); // Happens when re-indexing all studies
145 public SimulationContext addProjectContext(Study aStudy,
146 SimulationContext.Properties cprop) throws MissedPropertyException,
147 InvalidPropertyException, MultiplyDefinedException,
149 // -------------------------------------------------------------------------------
150 SimulationContext added = getStepService().addSimulationContext(
151 getProjectElementService().getFirstStep(aStudy), cprop);
156 public SimulationContext addProjectContext(Study aStudy,
157 SimulationContext context) {
158 // ----------------------------------------------------------------------
159 SimulationContext added = getStepService().addSimulationContext(
160 getProjectElementService().getFirstStep(aStudy), context);
165 public boolean addContributor(Study aStudy, User user) {
166 // -----------------------------------------
167 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
168 for (Iterator<User> i = contributor.iterator(); i.hasNext();) {
169 User present = i.next();
170 if (present.equals(user))
173 boolean absent = aStudy.getModifiableActors().add(user); // User may already be a reviewer or an approver
175 aStudy.addRelation(new ContributorRelation(aStudy, user));
177 update(aStudy); // Else, useless to re-index the study
178 contributor.add(user);
183 * Moves this study from the Public to the Reference area of the repository. For being moved to the Reference area, the study must
184 * previously be approved.
186 * @return true if the move succeeded.
187 * @see #moveToPublic()
189 * @see Publication#approve(Date)
191 public boolean moveToReference(Study aStudy) {
192 // ---------------------------------
193 if (aStudy.getProgressState() != ProgressState.APPROVED)
195 if (aStudy.getVisibility() != Visibility.PUBLIC)
198 aStudy.setVisibility(Visibility.REFERENCE);
199 if (update(aStudy)) {
200 return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
205 public boolean update(Study aStudy, Properties sprop)
206 throws InvalidPropertyException {
207 if (sprop.getTitle() != null)
208 aStudy.setTitle(sprop.getTitle());
209 if (sprop.getSummary() != null)
210 aStudy.setAttribute(new DescriptionAttribute(aStudy, sprop
212 // TODO: To be completed
213 return update(aStudy);
216 public boolean buildReference(Study aStudy) {
217 String pattern = aStudy.getReference(); // The study being supposed just created, its reference is the reference pattern
218 IDBuilder tool = selectIDBuilder(aStudy.getDate());
220 tool = new IDBuilder(aStudy.getDate());
221 Database.getSession().save(tool);
223 aStudy.setReference(tool.buildReference(pattern, aStudy));
227 public IDBuilder selectIDBuilder(Date date) {
228 // ------------------------------------------------------
229 SimpleDateFormat year = new SimpleDateFormat("yyyy");
230 String cycle = year.format(date);
231 StringBuffer buffer = new StringBuffer("from IDBuilder where cycle='")
232 .append(cycle).append("'");
233 String qstring = buffer.toString();
234 Query query = Database.getSession().createQuery(qstring);
235 IDBuilder result = (IDBuilder) query.uniqueResult();
240 public boolean publishes(Study aStudy, Document doc) {
241 // ---------------------------------------
242 if (!aStudy.publishes(doc)) {
243 Scenario[] scene = aStudy.getScenarii();
244 for (int i = 0; i < scene.length; i++) {
245 if (scene[i].publishes(doc))
252 public boolean removeContributor(Study aStudy, User... users) {
253 // ------------------------------------------------
254 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
255 Boolean done = false;
256 for (int i = 0; i < users.length; i++) {
257 User user = users[i];
258 for (Iterator<User> j = contributor.iterator(); j.hasNext();) {
259 User present = j.next();
260 if (!present.equals(user))
263 aStudy.removeRelation(ContributorRelation.class, user);
264 j.remove(); // Updates the contributor shortcut
274 public boolean removeProjectContext(Study aStudy, SimulationContext context) {
275 // ---------------------------------------------------------------
276 boolean done = getStepService().removeSimulationContext(
277 getProjectElementService().getFirstStep(aStudy), context);
282 public void setValidationCycle(Study aStudy, DocumentType type,
283 ValidationCycle.Properties vprop) {
284 HashMap<String, ValidationCycle> validactor = aStudy
285 .getValidationCycles();
286 if (validactor == null)
287 aStudy.setShortCuts(); // Initializes validactor and actor
289 String cname = type.getName();
290 ValidationCycle cycle = validactor.get(cname);
292 if (cycle != null && cycle.isAssigned()) {
293 cycle.resetActors(vprop);
296 cycle = new ValidationCycle(aStudy, vprop.setDocumentType(type));
298 ValidationCycleRelation link = cycle.getContext();
299 aStudy.addRelation(link);
300 validactor.put(cname, link.getTo()); // Replaces the cycle if exists as default,
301 } catch (Exception error) {
302 logger.error("Unable to re-index Knowledge Elements, reason:",
306 resetActorsShortCut(aStudy);
307 update(aStudy); // Re-index the study, just in case
310 private void resetActorsShortCut(Study aStudy) {
311 aStudy.getModifiableActors().clear();
312 // Get all actors involved in validation cycles
313 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
314 .values().iterator(); i.hasNext();) {
315 ValidationCycle cycle = i.next();
316 User[] user = cycle.getAllActors();
317 for (int j = 0; j < user.length; j++)
318 aStudy.getModifiableActors().add(user[j]);
320 // Get all other actors
321 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
323 Relation link = i.next();
324 Class<?> kindof = link.getClass().getSuperclass();
325 if (!kindof.equals(ActorRelation.class))
327 aStudy.getModifiableActors().add(((ActorRelation) link).getTo());
332 * Demotes this study from In-Check to In-Draft then In-Work states. This function is called internally when demoting the final result
333 * document of the study.
335 * @return true if the demotion succeeded.
337 public boolean demote(Study aStudy) {
338 // ---------------------------
339 if (aStudy.getProgressState() == ProgressState.inCHECK)
340 aStudy.setProgressState(ProgressState.inDRAFT);
341 else if (aStudy.getProgressState() == ProgressState.inDRAFT)
342 aStudy.setProgressState(ProgressState.inWORK);
345 return update(aStudy);
348 public int generateLocalIndex(Study aStudy) {
349 aStudy.setLastLocalIndex(aStudy.getLastLocalIndex() + 1);
350 Database.getSession().update(aStudy);
351 return aStudy.getLastLocalIndex();
354 // ==============================================================================================================================
355 // Public member functions
356 // ==============================================================================================================================
358 public Scenario addScenario(Study aStudy, Scenario.Properties sprop)
359 throws MissedPropertyException, InvalidPropertyException,
360 MultiplyDefinedException, RuntimeException {
361 // -------------------------------------------------------
362 if (sprop.getManager() == null)
363 sprop.setManager(aStudy.getAuthor());
365 Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy));
366 if (sprop.getBaseStep() != null)
368 .copyContentsUpTo(scenario, sprop.getBaseStep());
369 Scenario previous = sprop.getInsertAfter();
370 Session session = Database.getSession();
372 if (previous == null) {
373 aStudy.getScenariiList().add(scenario);
375 aStudy.getScenariiList().add(
376 aStudy.getScenariiList().indexOf(previous) + 1, scenario);
378 session.update(aStudy); // No need to update the Lucene index
379 session.save(scenario); // Must be done after updating this study because of the back reference to the study
380 if (sprop.getBaseStep() != null) {
381 // No need to update the Knowledge Element index as Knowledge Elements are not copied
382 scenario.refresh(); // Because saving the scenario changes the hashcode of copied Publications
384 KnowledgeElementType ucase = KnowledgeElement.selectType("usecase");
385 KnowledgeElement.Properties kprop = new KnowledgeElement.Properties();
386 User admin = UserDirectory.selectUser(1); // First user created when creating the database
387 kprop.setType(ucase).setTitle(aStudy.getTitle()).setValue(
388 scenario.getTitle()).setAuthor(admin); // Internal Knowledge Element required by the validation process of
390 getScenarioService().addKnowledgeElement(scenario, kprop);
397 private ScenarioService getScenarioService() {
398 return _scenarioService;
401 public void setScenarioService(ScenarioService scenarioService) {
402 _scenarioService = scenarioService;
406 * Promotes this study from In-Work to In-Draft then In-Check and APPROVED states. This function is called internally when promoting the
407 * final result document of the study.
409 * @return true if the demotion succeeded.
411 public boolean promote(Study aStudy) {
412 // ----------------------------
413 if (aStudy.getProgressState() == ProgressState.inWORK) {
414 aStudy.setProgressState(ProgressState.inDRAFT);
415 } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
416 aStudy.setProgressState(ProgressState.inCHECK);
417 Revision myvers = new Revision(aStudy.getVersion());
418 if (myvers.isMinor()) {
419 aStudy.setVersion(myvers.incrementAs(aStudy.getProgressState())
422 } else if (aStudy.getProgressState() == ProgressState.inCHECK) {
423 aStudy.setProgressState(ProgressState.APPROVED);
427 return update(aStudy);
431 * Moves this study from the Private to the Public area of the repository.
433 * @return true if the move succeeded.
436 public boolean moveToPublic(Study aStudy) {
437 // ------------------------------
438 if (aStudy.getVisibility() != Visibility.PRIVATE)
441 aStudy.setVisibility(Visibility.PUBLIC);
442 if (update(aStudy)) {
443 return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
448 private boolean update(Study aStudy) {
450 Database.getSession().update(aStudy); // Update of relational base
451 getIndex().update(aStudy); // Update of Lucene index
453 } catch (Exception error) {
454 logger.error("Unable to re-index the study '" + aStudy.getIndex()
455 + "', reason:", error);
460 private boolean updateKnowledgeElementsIndex(Study aStudy) {
461 // ----------------------------------------------
463 IndexService lucin = getIndex();
465 for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
467 Scenario scene = i.next();
468 for (Iterator<KnowledgeElement> j = scene
469 .getAllKnowledgeElements().iterator(); j.hasNext();) {
470 KnowledgeElement kelm = j.next();
475 } catch (Exception error) {
476 logger.error("Unable to re-index Knowledge Elements, reason:",
483 * Get project settings.
485 * @return Project settings service
487 private ProjectSettingsService getProjectSettings() {
488 return _projectSettingsService;
492 * Set project settings service.
494 * @param projectSettingsService
495 * project settings service
497 public void setProjectSettings(ProjectSettingsService projectSettingsService) {
498 _projectSettingsService = projectSettingsService;
502 * Get the projectElementService.
504 * @return the projectElementService
506 public ProjectElementService getProjectElementService() {
507 return _projectElementService;
511 * Set the projectElementService.
513 * @param projectElementService
514 * the projectElementService to set
516 public void setProjectElementService(
517 ProjectElementService projectElementService) {
518 _projectElementService = projectElementService;
522 * Get the stepService.
524 * @return the stepService
526 public StepService getStepService() {
531 * Set the stepService.
534 * the stepService to set
536 public void setStepService(StepService stepService) {
537 _stepService = stepService;
541 * Get the indexService.
542 * @return the indexService
544 public IndexService getIndexService() {
545 return _indexService;
549 * Set the indexService.
550 * @param indexService the indexService to set
552 public void setIndexService(IndexService indexService) {
553 _indexService = indexService;
558 * @return the studyDAO
560 public StudyDAO getStudyDAO() {
566 * @param studyDAO the studyDAO to set
568 public void setStudyDAO(StudyDAO studyDAO) {
569 _studyDAO = studyDAO;