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