Salome HOME
d7969eeca54c9fc9ac291b5c61192890de18bae1
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / som / Publication.java
1 package org.splat.som;
2 /**
3  * Publication objects are the way to reference document versions from a Project Element.
4  * As such, a Document version is added (or published) to a Project Element through a Publication object.
5  * This publication is done by saving the Publication object produced when creating and versioning a Document from a given
6  * Project Element Step (call of the saveAs() function).<br/>
7  * <br/>
8  * A Publication object is homogeneous to a reference to a Document version and belongs to one Project Element, this latter
9  * being either a Study Scenario or a Study itself, depending on the Study Step to which the document is published.<br/>
10  * <br/>
11  * The document version referenced by a Publication object is the Value of the publication.
12  * 
13  * @see Document
14  * @see ProjectElement
15  * @see Step
16  * @author    Daniel Brunier-Coulin
17  * @copyright OPEN CASCADE 2012
18  */
19
20 import java.io.FileNotFoundException;
21 import java.util.ArrayList;
22 import java.util.Date;
23 import java.util.Iterator;
24 import java.util.List;
25
26 import org.hibernate.Session;
27 import org.splat.kernel.InvalidPropertyException;
28 import org.splat.kernel.NotApplicableException;
29 import org.splat.kernel.Persistent;
30 import org.splat.kernel.Relation;
31 import org.splat.kernel.User;
32 import org.splat.manox.Reader;
33 import org.splat.manox.Toolbox;
34
35
36 public class Publication extends Persistent {
37
38 //  Persistent fields
39     private  Document        mydoc;
40     private  ProjectElement  owner;     // Either Study or Scenario, depending on the step involved by the publication
41     private  char            isnew;     // True if this references a document version new for the owner project element
42
43 //  Transient fields
44     private  Step            mystep;
45
46 //  ==============================================================================================================================
47 //  Construction
48 //  ==============================================================================================================================
49
50 //  Database fetch constructor
51     protected Publication () {
52 //  ------------------------
53       mystep = null;
54     }
55 //  Internal constructors
56     protected Publication (Document doc, ProjectElement publisher) {
57 //  --------------------------------------------------------------
58       mydoc  = doc;
59       mystep = null;
60       owner  = publisher;
61       isnew  = 'Y';
62     }
63     protected Publication copy (ProjectElement publisher) {
64 //  -----------------------------------------------------
65       Publication copy = new Publication();
66       copy.mydoc   = this.mydoc;
67       copy.mystep  = this.mystep;       // May not be initialized yet
68       copy.owner   = publisher;
69       copy.isnew   = this.isnew;
70       if (!copy.getOwnerStudy().equals(this.getOwnerStudy())) {
71         copy.isnew = 'N';               // The referenced document is not new for the given study
72       }
73       return copy;
74     }
75
76 //  ==============================================================================================================================
77 //  Member functions
78 //  ==============================================================================================================================
79
80     public Relation addDependency (Publication to) {
81 //  ----------------------------------------------
82       return  this.addDependency(to.value());
83     }
84
85     public Relation addDependency (Document to) {
86 //  -------------------------------------------
87       if (to == null) return null;
88       else            return mydoc.addRelation( new UsesRelation(mydoc, to) );
89     }
90
91 /**
92  * Undo the out-date operation.
93  * 
94  * @return true if the acceptance succeeds
95  * @see    #outdate()
96  * @see    DocumentRights#canAccept()
97  */
98     public boolean actualize () {
99 //  ---------------------------
100       if (!this.isOutdated()) return false;
101       isnew = 'Y';
102       Database.getSession().update(this);
103       return true;
104     }
105
106 /**
107  * Promotes the document referenced by this publication from In-Check to Approved state, if not out-dated, and attaches the corresponding
108  * time-stamp to the document.</br>
109  * If the promoted document is the final result of the owner study, the study is itself is promoted as well.</br>
110  * </br>
111  * Limitation: the way this promotion is propagated to the study supposes that the study has only ONE final result document.
112  * 
113  * @param adate the date of approval
114  * @return true if the approval succeeded
115  * @see    #getProgressState()
116  * @see    DocumentRights#canApprove()
117  * @see    DocumentType#isStudyResult()
118  * @see    Study#getApproverOf(Publication)
119  */
120     public Timestamp approve (Date adate) {
121 //  -------------------------------------
122       if      (this.isOutdated())                                 return null;
123       else if (mydoc.getProgressState() != ProgressState.inCHECK) return null;   // This statement must conform to the corresponding right
124
125       DocumentType    type     = mydoc.getType();
126       Study           owner    = this.getOwnerStudy();
127       ValidationCycle cycle    = owner.getValidationCycleOf(type);
128       User            approver = cycle.getActor(ValidationStep.APPROVAL);
129       Timestamp       stamp    = new  Timestamp(ValidationStep.APPROVAL, mydoc, approver, adate);
130       if (!mydoc.promote(stamp)) return null;
131       if (type.isStudyResult() && owner.getProgressState() == ProgressState.inCHECK) owner.promote();
132       return stamp;                                                              // Hoping that promotion of the study succeeded
133     }
134
135     public ConvertsRelation attach (String format) {
136 //  ----------------------------------------------
137       return mydoc.attach(format);
138     }
139
140     public ConvertsRelation attach (String format, String description) {
141 //  ------------------------------------------------------------------
142       return mydoc.attach(format, description);
143     }
144
145 /**
146  * Demotes the document referenced by this publication to In-Work state, and removes the Promoter of the document, if exist.</br>
147  * The In-Draft state is skipped (direct demotion to In-Work) if the validation cycle of the document does not include the review step.</br>
148  * If the demoted document is the final result of the owner study, the study is itself is demoted as well.</br>
149  * </br>
150  * Limitation: the way this demotion is propagated to the study supposes that the study has only ONE final result document.
151  * 
152  * @return true if the demotion succeeded
153  * @see    #getProgressState()
154  * @see    DocumentRights#canDemote()
155  * @see    DocumentType#isStudyResult()
156  */
157     public boolean demote () {
158 //  ------------------------
159       DocumentType    type  = mydoc.getType();
160       Study           owner = this.getOwnerStudy();
161
162       if (mydoc.getProgressState() == ProgressState.inCHECK) {
163         ValidationCycle cycle = owner.getValidationCycleOf(type);
164         if (cycle.enables(ValidationStep.REVIEW)) {
165           if (!mydoc.demote()) return false;
166         } else {
167           if (!mydoc.demote()) return false;
168           mydoc.demote();
169         }
170       } else
171       if (mydoc.getProgressState() == ProgressState.inDRAFT) {
172         if (!mydoc.demote())   return false;
173       } else {
174         return false;
175       }
176       if (type.isStudyResult() && owner.getProgressState() != ProgressState.inWORK) owner.demote();
177       return true;
178     }
179
180 /**
181  * Returns the study Step into which the document version referenced by this publication has been published.
182  */
183     public Step getInvolvedStep () {
184 //  ------------------------------
185       if (mystep == null) {
186         Step[]  step = owner.getSteps();
187         for (int i=0; i<step.length; i++) {
188           mystep = step[i];                  // The involved step necessarily exists
189           if (mydoc.isInto(mystep)) break;
190         }
191       }
192       return mystep;
193     }
194
195 /**
196  * Returns either the Study Scenario or the Study itself to which this publication belongs, depending on the Study Step into
197  * which the referenced document has been published.<br/>
198  * If this publication belongs to a Study, the Project Element returned is the Study returned by getOwnerStudy().
199  * 
200  * @return the Study Scenario or the Study to which this publication belongs to
201  * @see    #getOwnerStudy()
202  */
203     public ProjectElement getOwner () {
204 //  ---------------------------------
205       return owner;
206     }
207
208     public Study getOwnerStudy () {
209 //  -----------------------------
210       if (owner instanceof Study) return  (Study)owner;
211       else                        return ((Scenario)owner).getOwnerStudy();
212     }
213
214 /**
215  * Returns the state of this published document.
216  * It is the same than the state of the referenced document, unless this publication is out-of-date, in which case it is
217  * In-Work state.
218  * 
219  * @see #outdate()
220  * @see #isOutdated()
221  */
222     public ProgressState getProgressState () {
223 //  ----------------------------------------
224       if (this.isOutdated()) return ProgressState.inWORK;   // Overrides the document state
225       else                   return mydoc.getProgressState();
226     }
227
228     public List<Publication> getRelations (Class<? extends Relation> type) {
229 //  ----------------------------------------------------------------------
230       if (type == null) return null;
231
232       List<Publication> result = new ArrayList<Publication>();
233       List<Relation>    relist = mydoc.getRelations(type);
234       for (Iterator<Relation> i=relist.iterator(); i.hasNext();) {
235         Relation     relation  = i.next();
236         Document     relatedoc = (Document)relation.getTo();
237         Publication  related   = owner.getPublication(relatedoc);
238         if (related != null) {
239           result.add(related);
240         } else
241         if (owner instanceof Scenario) {   // The relation may cross steps belonging to a scenario and its owner study
242           related = ((Scenario)owner).getOwnerStudy().getPublication(relatedoc);
243           if (related != null) result.add(related);
244         }
245       }
246       return result;
247     }
248
249     public File getSourceFile () {
250 //  ----------------------------
251       return mydoc.getSourceFile();
252     }
253
254 /**
255  * Undo the review operation by demoting the document referenced by this publication from In-Check to In-Draft state and
256  * removing the Reviewer.</br>
257  * If the demoted document is the final result of the owner study, the study is itself is demoted as well.</br>
258  * </br>
259  * Limitation: the way this demotion is propagated to the study supposes that the study has only ONE final result document.
260  * 
261  * @return true if the demotion succeeded
262  * @see    #getProgressState()
263  * @see    #review()
264  * @see    DocumentRights#canInvalidate()
265  * @see    DocumentType#isStudyResult()
266  */
267     public boolean invalidate () {
268 //  ----------------------------
269       if ( mydoc.getProgressState() != ProgressState.inCHECK ) return false;
270       if (!mydoc.demote())          // Removes the reviewer if this document is In-Check
271         return false;
272       DocumentType  type  = this.value().getType();
273       Study         owner = this.getOwnerStudy();
274       if (type.isStudyResult() && owner.getProgressState() == ProgressState.inCHECK) owner.demote();
275       return true;
276     }
277
278     public boolean isNewForOwner () {
279 //  -------------------------------
280       return (isnew == 'Y');
281     }
282
283     public boolean isOutdated () {
284 //  ----------------------------
285       return (isnew == 'O');
286     }
287
288 /**
289  * Promotes the document referenced by this publication from In-Work to In-Draft or In-Check state, if not out-dated, and attaches the corresponding
290  * time-stamp to the document.</br>
291  * The In-Draft state is skipped (direct promotion to In-Check) if the validation cycle of the document does not include the review step.</br>
292  * Also, if the promoted document is the final result of the owner study, the study is itself promoted as well.</br>
293  * This operation can be undo-ed by demote().</br>
294  * </br>
295  * Limitation: the way this promotion is propagated to the study supposes that the study has only ONE final result document.
296  * 
297  * @return true if the promotion succeeded
298  * @see    #getProgressState()
299  * @see    #demote()
300  * @see    DocumentRights#canPromote()
301  * @see    DocumentType#isStudyResult()
302  */
303     public Timestamp promote (Date pdate) {
304 //  -------------------------------------
305       if      (this.isOutdated())                                return null;
306       else if (mydoc.getProgressState() != ProgressState.inWORK) return null;      // This statement must conform to the corresponding right
307       else {
308         DocumentType    type     = mydoc.getType();
309         Study           owner    = this.getOwnerStudy();
310         ValidationCycle cycle    = owner.getValidationCycleOf(type);
311         User            promoter = cycle.getActor(ValidationStep.PROMOTION);
312         if (promoter == null) promoter = getInvolvedStep().getActor();
313         if (promoter == null) promoter = owner.getAuthor();
314         Timestamp          stamp = new  Timestamp(ValidationStep.PROMOTION, mydoc, promoter, pdate);
315
316         if (!mydoc.promote(stamp) )                                                // Promotion to being reviewed
317           return null;
318         if (!cycle.enables(ValidationStep.REVIEW)) {
319              mydoc.promote(null);
320         }
321         if (type.isStudyResult() && owner.getProgressState() == ProgressState.inWORK) owner.promote();
322         return stamp;                                                              // Hoping that promotion of the study succeeded
323       }
324     }
325
326     public void rename (String title) throws InvalidPropertyException {
327 //  ---------------------------------
328       mydoc.rename(title);
329     }
330
331 /**
332  * Promotes the document referenced by this publication from In-Draft to In-Check state, if not out-dated, and attaches the corresponding
333  * time-stamp to the document.</br>
334  * If the promoted document is the final result of the owner study, the study is itself is promoted as well.</br>
335  * This operation can be undo-ed by invalidate().</br>
336  * </br>
337  * Limitation: the way this promotion is propagated to the study supposes that the study has only ONE final result document.
338  * 
339  * @param rdate the date of review
340  * @return true if the review succeeded
341  * @see    #getProgressState()
342  * @see    #invalidate()
343  * @see    DocumentRights#canReview()
344  * @see    DocumentType#isStudyResult()
345  * @see    Study#getReviewerOf(Publication)
346  */
347     public Timestamp review (Date rdate) {
348 //  ------------------------------------
349       if      (this.isOutdated())                                 return null;
350       else if (mydoc.getProgressState() != ProgressState.inDRAFT) return null;   // This statement must conform to the corresponding right
351
352       DocumentType    type     = mydoc.getType();
353       Study           owner    = this.getOwnerStudy();
354       ValidationCycle cycle    = owner.getValidationCycleOf(type);
355       User            reviewer = cycle.getActor(ValidationStep.REVIEW);
356       Timestamp       stamp    = new  Timestamp(ValidationStep.REVIEW, mydoc, reviewer, rdate);
357       if (!mydoc.promote(stamp)) return null;
358       if (type.isStudyResult() && owner.getProgressState() == ProgressState.inDRAFT) owner.promote();
359       return stamp;                                                              // Hoping that promotion of the study succeeded
360     }
361
362 /**
363  * Publishes the document referenced by this publication into the owner Project Element under the given revision number.<br/>
364  * The state of the referenced document is supposed being automatically set according to the given revision number, but, due to the
365  * versioning scheme, as it is not possible to differentiate In-Work and In-Draft states, this function has been deprecated (it is
366  * currently used only for the need of integration of Microsoft Office which anyway has to be redesigned).
367  * <br/>
368  * Note: in the context of branch versioning, the given revision may be modified by an update of the branch name.
369  * 
370  * @param newvers the required revision number
371  * @throws FileNotFoundException  If the referenced document is empty
372  * @throws NotApplicableException If the referenced document is undefined
373  * @deprecated
374  */
375     public void saveAs (Revision newvers) throws FileNotFoundException, NotApplicableException {
376 //  -------------------------------------
377       if ( mydoc.isUndefined() )           throw new NotApplicableException("Cannot save a Publication object refering an undefined Document");
378       if (!mydoc.getSourceFile().exists()) throw new FileNotFoundException();
379
380       Database.getSession().save(this);       // Must be done before updating the study in order to fix this final (rid-based) hascode
381       mydoc.updateAs(newvers);                // May change the branch name of given revision
382       updateOwner();
383     }
384
385 /**
386  * Publishes the document referenced by this publication into the owner Project Element under the given state,
387  * the revision number of the document being automatically set accordingly.
388  * If the given state is In-Draft and the document is final result of the owner study, this automatically promotes the study to In-Draft.
389  * 
390  * @param state the required progress state
391  * @throws FileNotFoundException  If the referenced document is empty
392  * @throws NotApplicableException If the referenced document is undefined
393  */
394     public void saveAs (ProgressState state) throws FileNotFoundException, NotApplicableException {
395 //  ----------------------------------------
396       if ( mydoc.isUndefined() )           throw new NotApplicableException("Cannot save a Publication object refering an undefined Document");
397       if (!mydoc.getSourceFile().exists()) throw new FileNotFoundException();
398
399       if (state == ProgressState.inWORK || state == ProgressState.EXTERN) {
400         Database.getSession().save(this);               // Must be done before updating the study in order to fix this final (rid-based) hascode
401         mydoc.updateAs(state);
402       } else {
403         DocumentType    mytype = mydoc.getType();
404         Study           owner  = this.getOwnerStudy();
405         ValidationCycle cycle  = owner.getValidationCycleOf(mytype);
406         boolean         review = cycle.enables(ValidationStep.REVIEW);
407         if (!(state == ProgressState.inDRAFT && review) && !(state == ProgressState.inCHECK && !review)) {
408           throw new NotApplicableException("Cannot save a result document in " + state.toString() + " state");
409         }
410         Database.getSession().save(this);               // Must be done before updating the study in order to fix this final (rid-based) hascode
411         mydoc.updateAs(ProgressState.inWORK);
412
413         this.promote(mydoc.getLastModificationDate());  // Promotes to the appropriate state in accordance to the validation cycle
414       }
415       updateOwner();
416     }
417
418 /**
419  * Out-dates this publication and recursively all publications using this one.
420  * Typically, a publication is out-dated when modifying a document to which it depends.
421  * 
422  * @see #isOutdated()
423  * @see #getProgressState()
424  * @see #actualize()
425  */
426     public void outdate () {
427 //  ----------------------
428       if (this.isOutdated()) return;
429
430       List<Publication> relist = this.getRelations(UsedByRelation.class);
431       for (Iterator<Publication> i = relist.iterator(); i.hasNext(); ) {
432         i.next().outdate();
433       }
434       isnew = 'O';
435       Database.getSession().update(this);
436     }
437
438 /**
439  * Returns the document version referenced by this Publication.
440  */
441     public Document value () {
442 //  ------------------------
443       return mydoc;
444     }
445
446 //  ==============================================================================================================================
447 //  Private services
448 //  ==============================================================================================================================
449
450     private void updateOwner () {
451 //  ---------------------------
452       Session  session = Database.getSession();
453       Step     step    = this.getInvolvedStep();
454
455 //    Update of involved step
456       Document previous = mydoc.getPreviousVersion();
457       if (previous != null) {
458         Publication oldoc = step.getDocument(previous.getIndex());
459         boolean     done  = step.remove(oldoc);   // Decrements the configuration tag count of document
460         if (done) session.delete(oldoc);          //WARNING: Potential problem because it's not automatically done as orphan object
461       }
462       step.add(this);                             // Increments the configuration tag count of document
463
464 //    Import the document properties and update of the study
465       forwardProperties(mydoc.getSourceFile().asFile(), step);
466       session.update(getOwner());
467     }
468
469     private void forwardProperties (java.io.File from, Step to) {
470 //  -----------------------------------------------------------
471       Reader  tool = Toolbox.getReader(from);
472       if (tool == null) return;        // No properties extractor available for this type of document
473
474       SimulationContextType.Properties sprop   = new SimulationContextType.Properties()
475                                                                           .setStep(to.getStep())
476                                                                           .setState(ProgressState.APPROVED);
477       List<SimulationContextType>      contype = SimulationContext.selectTypesWhere(sprop);
478       if (contype.isEmpty()) return;   // No approved property type configured at this step
479
480       SimulationContext.Properties     cprop   = new SimulationContext.Properties();        
481       List<SimulationContext>          context = to.getAllSimulationContexts();
482
483       context = new ArrayList<SimulationContext>(context.size());
484       context.addAll(to.getAllSimulationContexts());
485       cprop.disableCheck();
486       for (Iterator<SimulationContextType> i=contype.iterator(); i.hasNext(); ) {
487         SimulationContextType property = i.next();
488         for (Iterator<SimulationContext> j=context.iterator(); j.hasNext(); ) {
489           SimulationContext   existing = j.next();
490           if (!existing.getType().equals(property)) continue;
491           property = null;                // Forget this property as it is already set
492           break;
493         }
494         if (property != null) try {
495           String value = tool.extractProperty(property.getName());
496           if (value == null) continue;    // Property not defined into the document
497
498               cprop.setType(property).setValue(value);
499               if (owner instanceof Study) ((Study)owner).addProjectContext(cprop);     // Re-indexes knowledges and the study
500               else                                    to.addSimulationContext(cprop);  // Re-indexes knowledges only
501         } catch (Exception e) {
502           break;
503         }
504       }
505     }
506 }