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