Salome HOME
Beans initialization is fixed. Document can be added to study now.
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / StudyServiceImpl.java
1 /*****************************************************************************
2  * Company         EURIWARE
3  * Application     SIMAN
4  * File            $Id$ 
5  * Creation date   06.10.2012
6  * @author         $Author$
7  * @version        $Revision$
8  *****************************************************************************/
9
10 package org.splat.service;
11
12 import java.io.IOException;
13 import java.util.Date;
14 import java.util.HashMap;
15 import java.util.Iterator;
16 import java.util.List;
17
18 import org.apache.log4j.Logger;
19 import org.hibernate.Session;
20 import org.splat.dal.bo.kernel.Relation;
21 import org.splat.dal.bo.kernel.User;
22 import org.splat.dal.bo.som.ActorRelation;
23 import org.splat.dal.bo.som.ContributorRelation;
24 import org.splat.dal.bo.som.DescriptionAttribute;
25 import org.splat.dal.bo.som.Document;
26 import org.splat.dal.bo.som.DocumentType;
27 import org.splat.dal.bo.som.IDBuilder;
28 import org.splat.dal.bo.som.KnowledgeElement;
29 import org.splat.dal.bo.som.KnowledgeElementType;
30 import org.splat.dal.bo.som.ProgressState;
31 import org.splat.dal.bo.som.Publication;
32 import org.splat.dal.bo.som.Scenario;
33 import org.splat.dal.bo.som.SimulationContext;
34 import org.splat.dal.bo.som.Study;
35 import org.splat.dal.bo.som.ValidationCycle;
36 import org.splat.dal.bo.som.ValidationCycleRelation;
37 import org.splat.dal.bo.som.Visibility;
38 import org.splat.dal.bo.som.Study.Properties;
39 import org.splat.dal.dao.som.Database;
40 import org.splat.kernel.InvalidPropertyException;
41 import org.splat.kernel.MissedPropertyException;
42 import org.splat.kernel.MultiplyDefinedException;
43 import org.splat.kernel.UserDirectory;
44 import org.splat.service.technical.IndexService;
45 import org.splat.service.technical.ProjectSettingsService;
46 import org.splat.som.Revision;
47
48 /**
49  * @author RKV
50  * 
51  */
52 public class StudyServiceImpl implements StudyService {
53
54         public final static Logger logger = Logger.getLogger(org.splat.service.StudyServiceImpl.class);
55
56         private IndexService _indexService;
57
58         private StepService _stepService;
59
60         private ScenarioService _scenarioService;
61
62         private ProjectSettingsService _projectSettingsService;
63
64         private ProjectElementService _projectElementService;
65
66         public Study selectStudy(int index) {
67                 // -------------------------------------------
68                 StringBuffer query = new StringBuffer("from Study where rid='").append(
69                                 index).append("'");
70                 Study result = (Study) Database.getSession().createQuery(
71                                 query.toString()).uniqueResult();
72
73                 result.loadWorkflow();
74                 return result;
75         }
76
77         public Study selectStudy(String refid) {
78                 // ----------------------------------------------
79                 StringBuffer query = new StringBuffer("from Study where sid='").append(
80                                 refid).append("'");
81                 Study result = (Study) Database.getSession().createQuery(
82                                 query.toString()).uniqueResult();
83
84                 result.loadWorkflow();
85                 return result;
86         }
87
88         public Study createStudy(Study.Properties sprop)
89                         throws MissedPropertyException, InvalidPropertyException,
90                         MultiplyDefinedException, RuntimeException {
91                 sprop.setReference(getProjectSettings().getReferencePattern());
92                 Study study = new Study(sprop);
93
94                 buildReference(study);
95                 Database.getSession().save(study); // TODO: use StudyDAO and throw out Database.
96                 try {
97                         IndexService lucin = getIndex();
98                         lucin.add(study);
99                 } catch (IOException error) {
100                         logger.error("Unable to index the study '" + study.getIndex()
101                                         + "', reason:", error);
102                         // Continue and try to index later
103                 }
104                 return study;
105         }
106
107         public IndexService getIndex() throws IOException {
108                 IndexService lucin = getIndexService();
109                 if (!lucin.exists())
110                         lucin.create(); // Happens when re-indexing all studies
111                 return lucin;
112         }
113
114         public SimulationContext addProjectContext(Study aStudy,
115                         SimulationContext.Properties cprop) throws MissedPropertyException,
116                         InvalidPropertyException, MultiplyDefinedException,
117                         RuntimeException {
118                 // -------------------------------------------------------------------------------
119                 SimulationContext added = getStepService().addSimulationContext(
120                                 getProjectElementService().getFirstStep(aStudy), cprop);
121                 update(aStudy);
122                 return added;
123         }
124
125         public SimulationContext addProjectContext(Study aStudy,
126                         SimulationContext context) {
127                 // ----------------------------------------------------------------------
128                 SimulationContext added = getStepService().addSimulationContext(
129                                 getProjectElementService().getFirstStep(aStudy), context);
130                 update(aStudy);
131                 return added;
132         }
133
134         public boolean addContributor(Study aStudy, User user) {
135                 // -----------------------------------------
136                 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
137                 for (Iterator<User> i = contributor.iterator(); i.hasNext();) {
138                         User present = i.next();
139                         if (present.equals(user))
140                                 return false;
141                 }
142                 boolean absent = aStudy.getModifiableActors().add(user); // User may already be a reviewer or an approver
143
144                 aStudy.addRelation(new ContributorRelation(aStudy, user));
145                 if (absent)
146                         update(aStudy); // Else, useless to re-index the study
147                 contributor.add(user);
148                 return true;
149         }
150
151         /**
152          * Moves this study from the Public to the Reference area of the repository. For being moved to the Reference area, the study must
153          * previously be approved.
154          * 
155          * @return true if the move succeeded.
156          * @see #moveToPublic()
157          * @see #isPublic()
158          * @see Publication#approve(Date)
159          */
160         public boolean moveToReference(Study aStudy) {
161                 // ---------------------------------
162                 if (aStudy.getProgressState() != ProgressState.APPROVED)
163                         return false;
164                 if (aStudy.getVisibility() != Visibility.PUBLIC)
165                         return false;
166
167                 aStudy.setVisibility(Visibility.REFERENCE);
168                 if (update(aStudy)) {
169                         return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
170                 }
171                 return false;
172         }
173
174         public boolean update(Study aStudy, Properties sprop)
175                         throws InvalidPropertyException {
176                 if (sprop.getTitle() != null)
177                         aStudy.setTitle(sprop.getTitle());
178                 if (sprop.getSummary() != null)
179                         aStudy.setAttribute(new DescriptionAttribute(aStudy, sprop
180                                         .getSummary()));
181                 // TODO: To be completed
182                 return update(aStudy);
183         }
184
185         public boolean buildReference(Study aStudy) {
186                 String pattern = aStudy.getReference(); // The study being supposed just created, its reference is the reference pattern
187                 IDBuilder tool = Database.selectIDBuilder(aStudy.getDate());
188                 if (tool == null) {
189                         tool = new IDBuilder(aStudy.getDate());
190                         Database.getSession().save(tool);
191                 }
192                 aStudy.setReference(tool.buildReference(pattern, aStudy));
193                 return true;
194         }
195
196         public boolean publishes(Study aStudy, Document doc) {
197                 // ---------------------------------------
198                 if (!aStudy.publishes(doc)) {
199                         Scenario[] scene = aStudy.getScenarii();
200                         for (int i = 0; i < scene.length; i++) {
201                                 if (scene[i].publishes(doc))
202                                         return true;
203                         }
204                 }
205                 return false;
206         }
207
208         public boolean removeContributor(Study aStudy, User... users) {
209                 // ------------------------------------------------
210                 List<User> contributor = aStudy.getModifiableContributors(); // Initializes contributor
211                 Boolean done = false;
212                 for (int i = 0; i < users.length; i++) {
213                         User user = users[i];
214                         for (Iterator<User> j = contributor.iterator(); j.hasNext();) {
215                                 User present = j.next();
216                                 if (!present.equals(user))
217                                         continue;
218
219                                 aStudy.removeRelation(ContributorRelation.class, user);
220                                 j.remove(); // Updates the contributor shortcut
221                                 done = true;
222                                 break;
223                         }
224                 }
225                 if (done)
226                         update(aStudy);
227                 return done;
228         }
229
230         public boolean removeProjectContext(Study aStudy, SimulationContext context) {
231                 // ---------------------------------------------------------------
232                 boolean done = getStepService().removeSimulationContext(
233                                 getProjectElementService().getFirstStep(aStudy), context);
234                 update(aStudy);
235                 return done;
236         }
237
238         public void setValidationCycle(Study aStudy, DocumentType type,
239                         ValidationCycle.Properties vprop) {
240                 HashMap<String, ValidationCycle> validactor = aStudy
241                                 .getValidationCycles();
242                 if (validactor == null)
243                         aStudy.setShortCuts(); // Initializes validactor and actor
244
245                 String cname = type.getName();
246                 ValidationCycle cycle = validactor.get(cname);
247
248                 if (cycle != null && cycle.isAssigned()) {
249                         cycle.resetActors(vprop);
250                 } else
251                         try {
252                                 cycle = new ValidationCycle(aStudy, vprop.setDocumentType(type));
253
254                                 ValidationCycleRelation link = cycle.getContext();
255                                 aStudy.addRelation(link);
256                                 validactor.put(cname, link.getTo()); // Replaces the cycle if exists as default,
257                         } catch (Exception error) {
258                                 logger.error("Unable to re-index Knowledge Elements, reason:",
259                                                 error);
260                                 return;
261                         }
262                 resetActorsShortCut(aStudy);
263                 update(aStudy); // Re-index the study, just in case
264         }
265
266         private void resetActorsShortCut(Study aStudy) {
267                 aStudy.getModifiableActors().clear();
268                 // Get all actors involved in validation cycles
269                 for (Iterator<ValidationCycle> i = aStudy.getValidationCycles()
270                                 .values().iterator(); i.hasNext();) {
271                         ValidationCycle cycle = i.next();
272                         User[] user = cycle.getAllActors();
273                         for (int j = 0; j < user.length; j++)
274                                 aStudy.getModifiableActors().add(user[j]);
275                 }
276                 // Get all other actors
277                 for (Iterator<Relation> i = aStudy.getAllRelations().iterator(); i
278                                 .hasNext();) {
279                         Relation link = i.next();
280                         Class<?> kindof = link.getClass().getSuperclass();
281                         if (!kindof.equals(ActorRelation.class))
282                                 continue;
283                         aStudy.getModifiableActors().add(((ActorRelation) link).getTo());
284                 }
285         }
286
287         /**
288          * Demotes this study from In-Check to In-Draft then In-Work states. This function is called internally when demoting the final result
289          * document of the study.
290          * 
291          * @return true if the demotion succeeded.
292          */
293         public boolean demote(Study aStudy) {
294                 // ---------------------------
295                 if (aStudy.getProgressState() == ProgressState.inCHECK)
296                         aStudy.setProgressState(ProgressState.inDRAFT);
297                 else if (aStudy.getProgressState() == ProgressState.inDRAFT)
298                         aStudy.setProgressState(ProgressState.inWORK);
299                 else
300                         return false;
301                 return update(aStudy);
302         }
303
304         public int generateLocalIndex(Study aStudy) {
305                 aStudy.setLastLocalIndex(aStudy.getLastLocalIndex() + 1);
306                 Database.getSession().update(aStudy);
307                 return aStudy.getLastLocalIndex();
308         }
309
310         // ==============================================================================================================================
311         // Public member functions
312         // ==============================================================================================================================
313
314         public Scenario addScenario(Study aStudy, Scenario.Properties sprop)
315                         throws MissedPropertyException, InvalidPropertyException,
316                         MultiplyDefinedException, RuntimeException {
317                 // -------------------------------------------------------
318                 if (sprop.getManager() == null)
319                         sprop.setManager(aStudy.getAuthor());
320
321                 Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy));
322                 if (sprop.getBaseStep() != null)
323                         getScenarioService()
324                                         .copyContentsUpTo(scenario, sprop.getBaseStep());
325                 Scenario previous = sprop.getInsertAfter();
326                 Session session = Database.getSession();
327
328                 if (previous == null) {
329                         aStudy.getScenariiList().add(scenario);
330                 } else {
331                         aStudy.getScenariiList().add(
332                                         aStudy.getScenariiList().indexOf(previous) + 1, scenario);
333                 }
334                 session.update(aStudy); // No need to update the Lucene index
335                 session.save(scenario); // Must be done after updating this study because of the back reference to the study
336                 if (sprop.getBaseStep() != null) {
337                         // No need to update the Knowledge Element index as Knowledge Elements are not copied
338                         scenario.refresh(); // Because saving the scenario changes the hashcode of copied Publications
339                 }
340                 KnowledgeElementType ucase = KnowledgeElement.selectType("usecase");
341                 KnowledgeElement.Properties kprop = new KnowledgeElement.Properties();
342                 User admin = UserDirectory.selectUser(1); // First user created when creating the database
343                 kprop.setType(ucase).setTitle(aStudy.getTitle())
344                                 .setValue(scenario.getTitle()).setAuthor(admin); // Internal Knowledge Element required by the validation process of
345                                                                                                                                         // knowledges
346                 getScenarioService().addKnowledgeElement(scenario, kprop);
347                 return scenario;
348         }
349
350         /**
351          * @return
352          */
353         private ScenarioService getScenarioService() {
354                 return _scenarioService;
355         }
356
357         public void setScenarioService(ScenarioService scenarioService) {
358                 _scenarioService = scenarioService;
359         }
360
361         /**
362          * Promotes this study from In-Work to In-Draft then In-Check and APPROVED states. This function is called internally when promoting the
363          * final result document of the study.
364          * 
365          * @return true if the demotion succeeded.
366          */
367         public boolean promote(Study aStudy) {
368                 // ----------------------------
369                 if (aStudy.getProgressState() == ProgressState.inWORK) {
370                         aStudy.setProgressState(ProgressState.inDRAFT);
371                 } else if (aStudy.getProgressState() == ProgressState.inDRAFT) {
372                         aStudy.setProgressState(ProgressState.inCHECK);
373                         Revision myvers = new Revision(aStudy.getVersion());
374                         if (myvers.isMinor()) {
375                                 aStudy.setVersion(myvers.incrementAs(aStudy.getProgressState())
376                                                 .toString());
377                         }
378                 } else if (aStudy.getProgressState() == ProgressState.inCHECK) {
379                         aStudy.setProgressState(ProgressState.APPROVED);
380                 } else
381                         return false;
382
383                 return update(aStudy);
384         }
385
386         /**
387          * Moves this study from the Private to the Public area of the repository.
388          * 
389          * @return true if the move succeeded.
390          * @see #isPublic()
391          */
392         public boolean moveToPublic(Study aStudy) {
393                 // ------------------------------
394                 if (aStudy.getVisibility() != Visibility.PRIVATE)
395                         return false;
396
397                 aStudy.setVisibility(Visibility.PUBLIC);
398                 if (update(aStudy)) {
399                         return updateKnowledgeElementsIndex(aStudy); // If fails, the database roll-back is under responsibility of the caller
400                 }
401                 return false;
402         }
403
404         private boolean update(Study aStudy) {
405                 try {
406                         Database.getSession().update(aStudy); // Update of relational base
407                         getIndex().update(aStudy); // Update of Lucene index
408                         return true;
409                 } catch (Exception error) {
410                         logger.error("Unable to re-index the study '" + aStudy.getIndex()
411                                         + "', reason:", error);
412                         return false;
413                 }
414         }
415
416         private boolean updateKnowledgeElementsIndex(Study aStudy) {
417                 // ----------------------------------------------
418                 try {
419                         IndexService lucin = getIndex();
420
421                         for (Iterator<Scenario> i = aStudy.getScenariiList().iterator(); i
422                                         .hasNext();) {
423                                 Scenario scene = i.next();
424                                 for (Iterator<KnowledgeElement> j = scene
425                                                 .getAllKnowledgeElements().iterator(); j.hasNext();) {
426                                         KnowledgeElement kelm = j.next();
427                                         lucin.update(kelm);
428                                 }
429                         }
430                         return true;
431                 } catch (Exception error) {
432                         logger.error("Unable to re-index Knowledge Elements, reason:",
433                                         error);
434                         return false;
435                 }
436         }
437
438         /**
439          * @return
440          */
441         public IndexService getIndexService() {
442                 return _indexService;
443         }
444
445         public void setIndexService(IndexService indexService) {
446                 _indexService = indexService;
447         }
448
449         /**
450          * Get project settings.
451          * 
452          * @return Project settings service
453          */
454         private ProjectSettingsService getProjectSettings() {
455                 return _projectSettingsService;
456         }
457
458         /**
459          * Set project settings service.
460          * 
461          * @param projectSettingsService
462          *            project settings service
463          */
464         public void setProjectSettings(ProjectSettingsService projectSettingsService) {
465                 _projectSettingsService = projectSettingsService;
466         }
467
468         /**
469          * Get the projectElementService.
470          * 
471          * @return the projectElementService
472          */
473         public ProjectElementService getProjectElementService() {
474                 return _projectElementService;
475         }
476
477         /**
478          * Set the projectElementService.
479          * 
480          * @param projectElementService
481          *            the projectElementService to set
482          */
483         public void setProjectElementService(
484                         ProjectElementService projectElementService) {
485                 _projectElementService = projectElementService;
486         }
487
488         /**
489          * Get the stepService.
490          * @return the stepService
491          */
492         public StepService getStepService() {
493                 return _stepService;
494         }
495
496         /**
497          * Set the stepService.
498          * @param stepService the stepService to set
499          */
500         public void setStepService(StepService stepService) {
501                 _stepService = stepService;
502         }
503 }