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/>
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/>
11 * The document version referenced by a Publication object is the Value of the publication.
16 * @author Daniel Brunier-Coulin
17 * @copyright OPEN CASCADE 2012
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;
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;
36 public class Publication extends Persistent {
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
46 // ==============================================================================================================================
48 // ==============================================================================================================================
50 // Database fetch constructor
51 protected Publication () {
52 // ------------------------
55 // Internal constructors
56 protected Publication (Document doc, ProjectElement publisher) {
57 // --------------------------------------------------------------
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
76 // ==============================================================================================================================
78 // ==============================================================================================================================
80 public Relation addDependency (Publication to) {
81 // ----------------------------------------------
82 return this.addDependency(to.value());
85 public Relation addDependency (Document to) {
86 // -------------------------------------------
87 if (to == null) return null;
88 else return mydoc.addRelation( new UsesRelation(mydoc, to) );
92 * Undo the out-date operation.
94 * @return true if the acceptance succeeds
96 * @see DocumentRights#canAccept()
98 public boolean actualize () {
99 // ---------------------------
100 if (!this.isOutdated()) return false;
102 Database.getSession().update(this);
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>
111 * Limitation: the way this promotion is propagated to the study supposes that the study has only ONE final result document.
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)
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
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
135 public ConvertsRelation attach (String format) {
136 // ----------------------------------------------
137 return mydoc.attach(format);
140 public ConvertsRelation attach (String format, String description) {
141 // ------------------------------------------------------------------
142 return mydoc.attach(format, description);
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>
150 * Limitation: the way this demotion is propagated to the study supposes that the study has only ONE final result document.
152 * @return true if the demotion succeeded
153 * @see #getProgressState()
154 * @see DocumentRights#canDemote()
155 * @see DocumentType#isStudyResult()
157 public boolean demote () {
158 // ------------------------
159 DocumentType type = mydoc.getType();
160 Study owner = this.getOwnerStudy();
162 if (mydoc.getProgressState() == ProgressState.inCHECK) {
163 ValidationCycle cycle = owner.getValidationCycleOf(type);
164 if (cycle.enables(ValidationStep.REVIEW)) {
165 if (!mydoc.demote()) return false;
167 if (!mydoc.demote()) return false;
171 if (mydoc.getProgressState() == ProgressState.inDRAFT) {
172 if (!mydoc.demote()) return false;
176 if (type.isStudyResult() && owner.getProgressState() != ProgressState.inWORK) owner.demote();
181 * Returns the study Step into which the document version referenced by this publication has been published.
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;
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().
200 * @return the Study Scenario or the Study to which this publication belongs to
201 * @see #getOwnerStudy()
203 public ProjectElement getOwner () {
204 // ---------------------------------
208 public Study getOwnerStudy () {
209 // -----------------------------
210 if (owner instanceof Study) return (Study)owner;
211 else return ((Scenario)owner).getOwnerStudy();
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
222 public ProgressState getProgressState () {
223 // ----------------------------------------
224 if (this.isOutdated()) return ProgressState.inWORK; // Overrides the document state
225 else return mydoc.getProgressState();
228 public List<Publication> getRelations (Class<? extends Relation> type) {
229 // ----------------------------------------------------------------------
230 if (type == null) return null;
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) {
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);
249 public File getSourceFile () {
250 // ----------------------------
251 return mydoc.getSourceFile();
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>
259 * Limitation: the way this demotion is propagated to the study supposes that the study has only ONE final result document.
261 * @return true if the demotion succeeded
262 * @see #getProgressState()
264 * @see DocumentRights#canInvalidate()
265 * @see DocumentType#isStudyResult()
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
272 DocumentType type = this.value().getType();
273 Study owner = this.getOwnerStudy();
274 if (type.isStudyResult() && owner.getProgressState() == ProgressState.inCHECK) owner.demote();
278 public boolean isNewForOwner () {
279 // -------------------------------
280 return (isnew == 'Y');
283 public boolean isOutdated () {
284 // ----------------------------
285 return (isnew == 'O');
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>
295 * Limitation: the way this promotion is propagated to the study supposes that the study has only ONE final result document.
297 * @return true if the promotion succeeded
298 * @see #getProgressState()
300 * @see DocumentRights#canPromote()
301 * @see DocumentType#isStudyResult()
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
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);
316 if (!mydoc.promote(stamp) ) // Promotion to being reviewed
318 if (!cycle.enables(ValidationStep.REVIEW)) {
321 if (type.isStudyResult() && owner.getProgressState() == ProgressState.inWORK) owner.promote();
322 return stamp; // Hoping that promotion of the study succeeded
326 public void rename (String title) throws InvalidPropertyException {
327 // ---------------------------------
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>
337 * Limitation: the way this promotion is propagated to the study supposes that the study has only ONE final result document.
339 * @param rdate the date of review
340 * @return true if the review succeeded
341 * @see #getProgressState()
343 * @see DocumentRights#canReview()
344 * @see DocumentType#isStudyResult()
345 * @see Study#getReviewerOf(Publication)
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
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
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).
368 * Note: in the context of branch versioning, the given revision may be modified by an update of the branch name.
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
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();
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
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.
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
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();
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);
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");
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);
413 this.promote(mydoc.getLastModificationDate()); // Promotes to the appropriate state in accordance to the validation cycle
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.
423 * @see #getProgressState()
426 public void outdate () {
427 // ----------------------
428 if (this.isOutdated()) return;
430 List<Publication> relist = this.getRelations(UsedByRelation.class);
431 for (Iterator<Publication> i = relist.iterator(); i.hasNext(); ) {
435 Database.getSession().update(this);
439 * Returns the document version referenced by this Publication.
441 public Document value () {
442 // ------------------------
446 // ==============================================================================================================================
448 // ==============================================================================================================================
450 private void updateOwner () {
451 // ---------------------------
452 Session session = Database.getSession();
453 Step step = this.getInvolvedStep();
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
462 step.add(this); // Increments the configuration tag count of document
464 // Import the document properties and update of the study
465 forwardProperties(mydoc.getSourceFile().asFile(), step);
466 session.update(getOwner());
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
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
480 SimulationContext.Properties cprop = new SimulationContext.Properties();
481 List<SimulationContext> context = to.getAllSimulationContexts();
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
494 if (property != null) try {
495 String value = tool.extractProperty(property.getName());
496 if (value == null) continue; // Property not defined into the document
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) {