Salome HOME
Integration of ISR fixes:
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / PublicationServiceImpl.java
1 /*****************************************************************************
2  * Company         OPEN CASCADE
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.File;
13 import java.io.FileNotFoundException;
14 import java.io.IOException;
15 import java.text.ParseException;
16 import java.util.ArrayList;
17 import java.util.Date;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.List;
21
22 import org.apache.log4j.Logger;
23 import org.splat.common.properties.MessageKeyEnum;
24 import org.splat.dal.bo.kernel.User;
25 import org.splat.dal.bo.som.ConvertsRelation;
26 import org.splat.dal.bo.som.Document;
27 import org.splat.dal.bo.som.DocumentType;
28 import org.splat.dal.bo.som.ProgressState;
29 import org.splat.dal.bo.som.ProjectElement;
30 import org.splat.dal.bo.som.Publication;
31 import org.splat.dal.bo.som.SimulationContext;
32 import org.splat.dal.bo.som.SimulationContextType;
33 import org.splat.dal.bo.som.Study;
34 import org.splat.dal.bo.som.Timestamp;
35 import org.splat.dal.bo.som.UsedByRelation;
36 import org.splat.dal.bo.som.ValidationCycle;
37 import org.splat.dal.bo.som.ValidationStep;
38 import org.splat.dal.dao.som.ProjectElementDAO;
39 import org.splat.dal.dao.som.PublicationDAO;
40 import org.splat.dal.dao.som.TimestampDAO;
41 import org.splat.exception.IncompatibleDataException;
42 import org.splat.exception.InvalidParameterException;
43 import org.splat.kernel.InvalidPropertyException;
44 import org.splat.kernel.MismatchException;
45 import org.splat.kernel.MissedPropertyException;
46 import org.splat.kernel.MultiplyDefinedException;
47 import org.splat.kernel.NotApplicableException;
48 import org.splat.manox.Reader;
49 import org.splat.manox.Toolbox;
50 import org.splat.service.dto.DocToCompareDTO;
51 import org.splat.service.technical.RepositoryService;
52 import org.splat.som.DocumentRights;
53 import org.splat.som.Revision;
54 import org.splat.som.Step;
55 import org.springframework.transaction.annotation.Transactional;
56
57 /**
58  * Publication service implementation.
59  * 
60  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
61  */
62 public class PublicationServiceImpl implements PublicationService {
63
64         /**
65          * Logger for this class.
66          */
67         protected final static Logger LOG = Logger
68                         .getLogger(PublicationServiceImpl.class);
69
70         /**
71          * Injected study service.
72          */
73         private StudyService _studyService;
74         /**
75          * Injected step service.
76          */
77         private StepService _stepService;
78         /**
79          * Injected document service.
80          */
81         private DocumentService _documentService;
82         /**
83          * Injected document type service.
84          */
85         private DocumentTypeService _documentTypeService;
86         /**
87          * Injected user service.
88          */
89         private UserService _userService;
90         /**
91          * Injected project element service.
92          */
93         private ProjectElementService _projectElementService;
94         /**
95          * Injected simulation context service.
96          */
97         private SimulationContextService _simulationContextService;
98         /**
99          * Injected publication DAO.
100          */
101         private PublicationDAO _publicationDAO;
102         /**
103          * Injected timestamp DAO.
104          */
105         private TimestampDAO _timestampDAO;
106         /**
107          * Injected project element DAO.
108          */
109         private ProjectElementDAO _projectElementDAO;
110         /**
111          * Injected repository service.
112          */
113         private RepositoryService _repositoryService;
114
115         /**
116          * {@inheritDoc}
117          * 
118          * @see org.splat.service.PublicationService#copy(org.splat.dal.bo.som.Publication, org.splat.dal.bo.som.ProjectElement)
119          */
120         public Publication copy(final Publication aPublication,
121                         final ProjectElement publisher) {
122                 Publication copy = new Publication();
123                 copy.setValue(aPublication.value());
124                 copy.setStep(aPublication.getStep()); // May not be initialized yet
125                 copy.setOwner(publisher);
126                 copy.setIsnew(aPublication.getIsnew());
127                 if (!copy.getOwnerStudy().equals(aPublication.getOwnerStudy())) {
128                         copy.setIsnew('N'); // The referenced document is not new for the given study
129                 }
130                 return copy;
131         }
132
133         /**
134          * {@inheritDoc}
135          * 
136          * @see org.splat.service.PublicationService#createDoc(long, org.splat.som.Step, long, long, java.lang.String, java.lang.String,
137          *      org.splat.dal.bo.som.ProgressState, java.lang.String, java.lang.String, java.util.Date, java.util.List)
138          */
139         @Transactional
140         public Publication createDoc(final long ownerId, final Step step,
141                         final long documentTypeId, final long userId, final String fname,
142                         final String doctitle, final ProgressState docstate,
143                         final String reference, final String version, final Date docDate,
144                         final List<Long> docuses) throws MissedPropertyException,
145                         InvalidPropertyException, MultiplyDefinedException, IOException,
146                         NotApplicableException, InterruptedException, ParseException {
147                 DocumentType type = getDocumentTypeService().selectType(
148                                 (int) documentTypeId);
149                 User user = getUserService().selectUser(userId);
150                 File updir = getRepositoryService().getDownloadDirectory(user);
151                 File upfile = new File(updir.getPath() + "/" + fname);
152                 String[] table = fname.split("\\x2E");
153
154                 // Creation of the document
155                 Document.Properties dprop = new Document.Properties();
156                 dprop.setLocalPath(upfile.getPath());
157                 Publication addoc;
158
159                 if (reference.length() == 0) { // Importation of a foreign document
160                         // TODO: Extract property of supported documents (DOCX, ODT...)
161                         addoc = getStepService().createDocument(
162                                         step,
163                                         dprop.setName(doctitle).setType(type).setFormat(
164                                                         table[table.length - 1]).setAuthor(user));
165                         moveFile(upfile, addoc);
166                         try {
167                                 saveAs(addoc, docstate); // May throw FileNotFound if rename was not done
168                         } catch (FileNotFoundException saverror) {
169                                 Thread.sleep(1000);
170                                 LOG.info("Waiting for the file.");
171                                 upfile.renameTo(updir);
172                                 saveAs(addoc, docstate); // Forget it if throw again FileNotFound
173                         }
174                 } else { // Importation of a previously created template-based document
175                         if (docDate != null) {
176                                 dprop.setDate(docDate);
177                         }
178                         addoc = getStepService().assignDocument(step,
179                                         dprop.setReference(reference).setName(doctitle));
180                         moveFile(upfile, addoc);
181                         try {
182                                 if (version.length() > 0) {
183                                         saveAs(addoc, new Revision(version));
184                                 } else {
185                                         saveAs(addoc, docstate);
186                                 }
187                         } catch (FileNotFoundException saverror) {
188                                 Thread.sleep(1000);
189                                 LOG.info("Waiting for the file.");
190                                 upfile.renameTo(updir);
191                                 if (version.length() > 0) {
192                                         saveAs(addoc, new Revision(version));
193                                 } else {
194                                         saveAs(addoc, docstate);
195                                 }
196                         }
197                 }
198                 // Creation of uses relations
199                 if (docuses != null) {
200                         for (Long index : docuses) {
201                                 Document used = getDocumentService().selectDocument(index);
202                                 addoc.addDependency(used);
203                         }
204                 }
205                 return addoc;
206         }
207
208         /**
209          * Move a file into the repository as a source file of the document.
210          * 
211          * @param upfile
212          *            the uploaded file to move
213          * @param addoc
214          *            the document
215          */
216         private void moveFile(final File upfile, final Publication addoc) {
217                 File updir = addoc.getSourceFile().asFile();
218                 if (LOG.isInfoEnabled()) {
219                         LOG.info("Moving \"" + upfile.getAbsolutePath() + "\" to \""
220                                         + updir.getPath() + "\".");
221                 }
222                 upfile.renameTo(updir);
223         }
224
225         /**
226          * {@inheritDoc}
227          * 
228          * @see org.splat.service.PublicationService#versionDocument(org.splat.som.Step, org.splat.dal.bo.kernel.User, java.lang.String, long,
229          *      java.lang.String, java.lang.String, org.splat.dal.bo.som.ProgressState, java.util.Date, java.lang.String[], long[])
230          */
231         @Transactional
232         public void versionDocument(final Step step, final User user,
233                         final String filename, final long docIndex, final String docver,
234                         final String summary, final ProgressState state, final Date date,
235                         final String[] docuses, final long[] docusedby)
236                         throws MissedPropertyException, InvalidPropertyException,
237                         MultiplyDefinedException, IOException, MismatchException,
238                         NotApplicableException, InterruptedException {
239                 File updir = getRepositoryService().getDownloadDirectory(user);
240                 File upfile = new File(updir.getPath() + "/" + filename);
241
242                 // Versioning of the document
243                 Document.Properties dprop = new Document.Properties();
244                 dprop.setLocalPath(upfile.getPath());
245                 Publication current = step.getDocument(docIndex);
246                 Publication next;
247
248                 if ((docver.length() != 0) && // Importation of a not foreign document
249                                 (date != null)) {
250                         dprop.setDate(date);
251                 }
252                 if ((summary != null) && (summary.length() > 0)) {
253                         dprop.setDescription(summary);
254                 }
255                 next = getStepService().versionDocument(step, current,
256                                 dprop.setAuthor(user));
257                 moveFile(upfile, next);
258
259                 try {
260                         if (docver.length() == 0) { // Importation of a foreign document
261                                 saveAs(next, state); // May throw FileNotFound if rename was not done
262                         } else {
263                                 saveAs(next, new Revision(docver));
264                         }
265                 } catch (FileNotFoundException saverror) {
266                         Thread.sleep(1000);
267                         LOG.info("Waiting for the file.");
268                         upfile.renameTo(updir);
269                         saveAs(next, state);
270                 }
271                 // TODO: Remove current document details from the contents of open study
272
273                 // Creation of uses relations
274                 Publication syncronizedCurrent = _publicationDAO.get(current.getIndex());
275                 updateRelations(syncronizedCurrent, next, docuses, docusedby);
276         }
277
278         /**
279          * Update relations after creation of a new document version.
280          * 
281          * @param current
282          *            the current version
283          * @param next
284          *            the new version
285          * @param docuses
286          *            ids of used documents
287          * @param docusedby
288          *            ids of documents used by the versioned one.
289          */
290         private void updateRelations(final Publication current,
291                         final Publication next, final String[] docuses,
292                         final long[] docusedby) {
293                 if (docuses != null) {
294                         for (int i = 0; i < docuses.length; i++) {
295                                 Long index = Long.valueOf(docuses[i].trim());
296                                 Document used = getDocumentService().selectDocument(index);// RKV: getPublication(index, steps);
297                                 next.addDependency(used);
298                         }
299                 }
300                 // Outdating impacted document
301                 HashSet<Long> compatible = new HashSet<Long>();
302                 if (docusedby != null) {
303                         for (int i = 0; i < docusedby.length; i++) {
304                                 compatible.add(docusedby[i]);
305                         }
306                 }
307                 List<Publication> relist = current.getRelations(UsedByRelation.class);
308                 for (Iterator<Publication> i = relist.iterator(); i.hasNext();) {
309                         Publication using = i.next();
310                         if (!compatible.contains(using.getIndex())) {
311                                 outdate(using);
312                         }
313                 }
314         }
315
316         /*
317          * protected Publication getPublication(int index, List<Step> steps) { for (Iterator<Step> i = steps.iterator(); i.hasNext();) { List<Publication>
318          * published = i.next().getAllDocuments(); for (Iterator<Publication> j = published.iterator(); j.hasNext();) { Publication found =
319          * j.next(); // In a given study step, if (found.value().getIndex() == index) return found; // there is only one publication of a given
320          * document } } return null; }
321          */
322         /**
323          * {@inheritDoc}
324          * 
325          * @see org.splat.service.PublicationService#approve(org.splat.dal.bo.som.Publication, java.util.Date)
326          */
327         @Transactional
328         public Timestamp approve(final Publication aPublication, final Date adate) {
329                 Timestamp res = null;
330                 if (!(aPublication.isOutdated() || (aPublication.value()
331                                 .getProgressState() != ProgressState.inCHECK))) {
332                         DocumentType type = aPublication.value().getType();
333                         Study owner = aPublication.getOwnerStudy();
334                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
335                                         owner, type);
336                         User approver = cycle.getActor(ValidationStep.APPROVAL);
337                         Timestamp stamp = new Timestamp(ValidationStep.APPROVAL,
338                                         aPublication.value(), approver, adate);
339                         getTimestampDAO().create(stamp);
340
341                         if (getDocumentService().promote(aPublication.value(), stamp)) {
342                                 res = stamp;
343 //                              if (getDocumentService().isStudyResult(type)
344 //                                              && owner.getProgressState() == ProgressState.inCHECK) {
345 //                                      getStudyService().promote(owner);
346 //                              }
347                         }
348                 }
349                 return res; // Hoping that promotion of the study succeeded
350         }
351
352         /**
353          * {@inheritDoc}
354          * 
355          * @see org.splat.service.PublicationService#demote(org.splat.dal.bo.som.Publication)
356          */
357         @Transactional
358         public boolean demote(final Publication aPublication) {
359                 boolean res = false;
360                 DocumentType type = aPublication.value().getType();
361                 Study owner = aPublication.getOwnerStudy();
362
363                 if (aPublication.value().getProgressState() == ProgressState.inCHECK) {
364                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
365                                         owner, type);
366                         if (cycle.enables(ValidationStep.REVIEW)) {
367                                 res = getDocumentService().demote(aPublication.value());
368                         } else {
369                                 res = getDocumentService().demote(aPublication.value());
370                                 if (res) {
371                                         getDocumentService().demote(aPublication.value());
372                                 }
373                         }
374                 } else if (aPublication.value().getProgressState() == ProgressState.inDRAFT) {
375                         res = getDocumentService().demote(aPublication.value());
376                 }
377 //              if (res && getDocumentService().isStudyResult(type)
378 //                              && owner.getProgressState() != ProgressState.inWORK) {
379 //                      getStudyService().demote(owner);
380 //              }
381                 return res;
382         }
383
384         /**
385          * {@inheritDoc}
386          * 
387          * @see org.splat.service.PublicationService#invalidate(org.splat.dal.bo.som.Publication)
388          */
389         @Transactional
390         public boolean invalidate(final Publication aPublication) {
391                 boolean res = false;
392                 if ((aPublication.value().getProgressState() == ProgressState.inCHECK)) {
393                         DocumentType type = aPublication.value().getType();
394                         Study owner = aPublication.getOwnerStudy();
395
396                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
397                                         owner, type);
398                         // Check if the validation cycle allows the review step
399                         if (cycle.enables(ValidationStep.REVIEW)) {
400 //                              if (getDocumentService().demote(aPublication.value())
401 //                                              && getDocumentService().isStudyResult(type)
402 //                                              && owner.getProgressState() == ProgressState.inCHECK) {
403 //                                      getStudyService().demote(owner);
404 //                              }
405                                 res = true;
406                         } else { // If the validation cycle has no inDraft step
407                                 res = demote(aPublication);
408                         }
409                 }
410                 return res;
411         }
412
413         /**
414          * {@inheritDoc}
415          * 
416          * @see org.splat.service.PublicationService#promote(org.splat.dal.bo.som.Publication, java.util.Date)
417          */
418         @Transactional
419         public Timestamp promote(final Publication aPublication, final Date pdate) {
420                 Timestamp res = null;
421                 if ((!aPublication.isOutdated())
422                                 && (aPublication.value().getProgressState() == ProgressState.inWORK)) {
423                         DocumentType type = aPublication.value().getType();
424                         Study owner = aPublication.getOwnerStudy();
425                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
426                                         owner, type);
427                         User promoter = cycle.getActor(ValidationStep.PROMOTION);
428                         if (promoter == null) {
429                                 promoter = getInvolvedStep(aPublication).getActor();
430                         }
431                         if (promoter == null) {
432                                 promoter = owner.getAuthor();
433                         }
434                         Timestamp stamp = new Timestamp(ValidationStep.PROMOTION,
435                                         aPublication.value(), promoter, pdate);
436                         getTimestampDAO().create(stamp);
437
438                         if (getDocumentService().promote(aPublication.value(), stamp)) {
439                                 res = stamp;
440                                 if (!cycle.enables(ValidationStep.REVIEW)) {
441                                         getDocumentService().promote(aPublication.value(), null);
442                                 }
443 //                              if (getDocumentService().isStudyResult(type)
444 //                                              && owner.getProgressState() == ProgressState.inWORK) {
445 //                                      getStudyService().promote(owner);
446 //                              }
447                         }
448                 }
449                 return res; // Hoping that promotion of the study succeeded
450         }
451
452         /**
453          * {@inheritDoc}
454          * 
455          * @see org.splat.service.PublicationService#review(org.splat.dal.bo.som.Publication, java.util.Date)
456          */
457         @Transactional
458         public Timestamp review(final Publication aPublication, final Date rdate) {
459                 Timestamp res = null;
460                 if (!aPublication.isOutdated()
461                                 && !(aPublication.value().getProgressState() != ProgressState.inDRAFT)) {
462
463                         DocumentType type = aPublication.value().getType();
464                         Study owner = aPublication.getOwnerStudy();
465                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
466                                         owner, type);
467                         User reviewer = cycle.getActor(ValidationStep.REVIEW);
468                         Timestamp stamp = new Timestamp(ValidationStep.REVIEW, aPublication
469                                         .value(), reviewer, rdate);
470                         getTimestampDAO().create(stamp);
471
472                         if (getDocumentService().promote(aPublication.value(), stamp)) {
473                                 res = stamp;
474 //                              if (getDocumentService().isStudyResult(type)
475 //                                              && owner.getProgressState() == ProgressState.inDRAFT) {
476 //                                      getStudyService().promote(owner);
477 //                              }
478                         }
479                 }
480                 return res; // Hoping that promotion of the study succeeded
481         }
482
483         /**
484          * {@inheritDoc}
485          * 
486          * @see org.splat.service.PublicationService#saveAs(org.splat.dal.bo.som.Publication, org.splat.som.Revision)
487          * @deprecated
488          */
489         @Deprecated
490         @Transactional
491         public void saveAs(final Publication aPublication, final Revision newvers)
492                         throws FileNotFoundException, NotApplicableException {
493                 if (aPublication.value().isUndefined()) {
494                         throw new NotApplicableException(
495                                         "Cannot save a Publication object refering an undefined Document");
496                 }
497                 if (!aPublication.value().getSourceFile().exists()) {
498                         throw new FileNotFoundException();
499                 }
500
501                 getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based) hascode
502                 getDocumentService().updateAs(aPublication.value(), newvers); // May change the branch name of given revision
503                 updateOwner(aPublication);
504         }
505
506         /**
507          * {@inheritDoc}
508          * 
509          * @see org.splat.service.PublicationService#saveAs(org.splat.dal.bo.som.Publication, org.splat.dal.bo.som.ProgressState)
510          */
511         @Transactional
512         public void saveAs(final Publication aPublication, final ProgressState state)
513                         throws FileNotFoundException, NotApplicableException {
514                 if (aPublication.value().isUndefined()) {
515                         throw new NotApplicableException(
516                                         "Cannot save a Publication object refering an undefined Document");
517                 }
518                 if (!aPublication.value().getSourceFile().exists()) {
519                         throw new FileNotFoundException(aPublication.value()
520                                         .getSourceFile().asFile().getAbsolutePath());
521                 }
522
523                 if (state == ProgressState.inWORK || state == ProgressState.EXTERN) {
524                         getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based)
525                         // hascode
526                         getDocumentService().updateAs(aPublication.value(), state);
527                 } else {
528                         // Check that the state is applicable for the validation cycle
529                         DocumentType mytype = aPublication.value().getType();
530                         Study owner = aPublication.getOwnerStudy();
531                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
532                                         owner, mytype);
533                         boolean review = cycle.enables(ValidationStep.REVIEW);
534                         if (!(state == ProgressState.inDRAFT && review)
535                                         && !(state == ProgressState.inCHECK && !review)) {
536                                 throw new NotApplicableException(MessageKeyEnum.DCT_000003
537                                                 .toString(), state.toString());
538                         }
539                         getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based)
540                         // hascode
541                         getDocumentService().updateAs(aPublication.value(),
542                                         ProgressState.inWORK);
543
544                         promote(aPublication, aPublication.value()
545                                         .getLastModificationDate()); // Promotes to the appropriate state in accordance to the validation cycle
546                 }
547                 updateOwner(aPublication);
548         }
549
550         /**
551          * Update an owner of the publication.
552          * 
553          * @param aPublication
554          *            the document publication
555          */
556         @Transactional
557         private void updateOwner(final Publication aPublication) {
558                 Step step = getInvolvedStep(aPublication);
559
560                 // Update of involved step
561                 Document previous = aPublication.value().getPreviousVersion();
562                 if (previous != null) {
563                         Publication oldoc = step.getDocument(previous.getIndex());
564                         getStepService().remove(step, oldoc); // Decrements the configuration tag count of document
565                 }
566                 getStepService().add(step, aPublication); // Increments the configuration tag count of document
567
568                 // Import the document properties and update of the study
569                 forwardProperties(aPublication, aPublication.value().getSourceFile()
570                                 .asFile(), step);
571                 getProjectElementDAO().merge(aPublication.getOwner());
572         }
573
574         /**
575          * Propagate simulation contexts from the given config file to the publication's owner (study or step).
576          * 
577          * @param aPublication
578          *            the document publication
579          * @param from
580          *            the config file
581          * @param to
582          *            the study step
583          */
584         private void forwardProperties(final Publication aPublication,
585                         final java.io.File from, final Step to) {
586                 Reader tool = Toolbox.getReader(from);
587                 if (tool != null) { // Properties extractor available for this type of document
588                         SimulationContextType.Properties sprop = new SimulationContextType.Properties()
589                                         .setStep(to.getStep()).setProgressState(
590                                                         ProgressState.APPROVED);
591                         List<SimulationContextType> contype = getSimulationContextService()
592                                         .selectTypesWhere(sprop);
593                         if (!contype.isEmpty()) { // There is an approved property type configured at this step
594
595                                 SimulationContext.Properties cprop = new SimulationContext.Properties();
596                                 List<SimulationContext> context = to.getAllSimulationContexts();
597
598                                 context = new ArrayList<SimulationContext>(context.size());
599                                 context.addAll(to.getAllSimulationContexts());
600                                 cprop.disableCheck();
601                                 for (Iterator<SimulationContextType> i = contype.iterator(); i
602                                                 .hasNext();) {
603                                         SimulationContextType property = i.next();
604                                         boolean isFound = false;
605                                         for (Iterator<SimulationContext> j = context.iterator(); j
606                                                         .hasNext();) {
607                                                 SimulationContext existing = j.next();
608                                                 isFound = existing.getType().equals(property);
609                                                 if (isFound) {
610                                                         // Forget this property as it is already set
611                                                         break;
612                                                 }
613                                         }
614                                         if (!isFound) {
615                                                 try {
616                                                         String value = tool.extractProperty(property
617                                                                         .getName());
618                                                         if (value == null) {
619                                                                 continue; // Property not defined into the document
620                                                         }
621
622                                                         cprop.setType(property).setValue(value);
623                                                         if (aPublication.getOwner() instanceof Study) {
624                                                                 getStudyService().addProjectContext(
625                                                                                 (Study) aPublication.getOwner(), cprop); // Re-indexes knowledges and the study
626                                                         } else {
627                                                                 getStepService()
628                                                                                 .addSimulationContext(to, cprop); // Re-indexes knowledges only
629                                                         }
630                                                 } catch (Exception e) {
631                                                         break;
632                                                 }
633                                         }
634                                 }
635                         }
636                 }
637         }
638
639         /**
640          * Returns the study Step into which the document version referenced by this publication has been published.
641          * 
642          * @param aPublication
643          *            the document publication
644          * @return the study step where the document is published
645          */
646         public Step getInvolvedStep(final Publication aPublication) {
647                 if (aPublication.getStep() == null) {
648                         Step[] step = getProjectElementService().getSteps(
649                                         aPublication.getOwner());
650                         for (int i = 0; i < step.length; i++) {
651                                 aPublication.setStep(step[i]); // The involved step necessarily exists
652                                 if (aPublication.value().isInto(aPublication.getStep())) {
653                                         break;
654                                 }
655                         }
656                 }
657                 return aPublication.getStep();
658         }
659
660         /**
661          * Undo the out-date operation.
662          * 
663          * @param aPublication
664          *            the publication
665          * @return true if the acceptance succeeds
666          * @see #outdate()
667          * @see DocumentRights#canAccept()
668          */
669         @Transactional
670         public boolean actualize(final Publication aPublication) {
671                 boolean res = aPublication.isOutdated();
672                 if (res) {
673                         aPublication.setIsnew('Y');
674                         getPublicationDAO().update(aPublication);
675                 }
676                 return res;
677         }
678
679         /**
680          * Out-dates this publication and recursively all publications using this one. Typically, a publication is out-dated when modifying a
681          * document to which it depends.
682          * 
683          * @param aPublication
684          *            the publication
685          * @see #isOutdated()
686          * @see #getProgressState()
687          * @see #actualize()
688          */
689         public void outdate(final Publication aPublication) {
690                 if (aPublication.isOutdated()) {
691                         return;
692                 }
693
694                 List<Publication> relist = aPublication
695                                 .getRelations(UsedByRelation.class);
696                 for (Iterator<Publication> i = relist.iterator(); i.hasNext();) {
697                         outdate(i.next());
698                 }
699                 aPublication.setIsnew('O');
700                 getPublicationDAO().update(aPublication);
701         }
702
703         /**
704          * Create "Converts" relation for the given document publication and format.
705          * 
706          * @param aPublication
707          *            the document publication
708          * @param format
709          *            the format
710          * @return the created "Converts" relation
711          */
712         @Transactional
713         public ConvertsRelation attach(final Publication aPublication,
714                         final String format) {
715                 return getDocumentService().attach(aPublication.value(), format);
716         }
717
718         /**
719          * Create "Converts" relation for the given document publication, format and description.
720          * 
721          * @param aPublication
722          *            the document publication
723          * @param format
724          *            the format
725          * @param description
726          *            the description of the relation
727          * @return the created "Converts" relation
728          */
729         @Transactional
730         public ConvertsRelation attach(final Publication aPublication,
731                         final String format, final String description) {
732                 return getDocumentService().attach(aPublication.value(), format,
733                                 description);
734         }
735
736         /**
737          * Rename the published document.
738          * 
739          * @param aPublication
740          *            the publication of the document
741          * @param title
742          *            the new document title
743          * @throws InvalidPropertyException
744          *             if the new title is empty
745          */
746         public void rename(final Publication aPublication, final String title)
747                         throws InvalidPropertyException {
748                 getDocumentService().rename(aPublication.value(), title);
749         }
750
751         /**
752          * {@inheritDoc}
753          * 
754          * @see org.splat.service.PublicationService#getDocToCompareDTO(long)
755          */
756         @Transactional(readOnly = true)
757         @Override
758         public DocToCompareDTO getDocToCompareDTO(final long publicationId)
759                         throws InvalidParameterException {
760                 DocToCompareDTO res = new DocToCompareDTO();
761                 Publication pub = _publicationDAO.get(Long.valueOf(publicationId));
762                 if (pub == null) {
763                         throw new InvalidParameterException("id", String
764                                         .valueOf(publicationId));
765                 }
766
767                 res.setDocumentTitle(pub.value().getTitle());
768                 res.setPathToFile(pub.value().getFile().asFile().getAbsolutePath());
769                 res.setScenarioTitle(pub.getOwner().getTitle());
770                 res.setStudyTitle(pub.getOwnerStudy().getTitle());
771                 return res;
772         }
773
774         /**
775          * Get the projectElementService.
776          * 
777          * @return the projectElementService
778          */
779         public ProjectElementService getProjectElementService() {
780                 return _projectElementService;
781         }
782
783         /**
784          * Set the projectElementService.
785          * 
786          * @param projectElementService
787          *            the projectElementService to set
788          */
789         public void setProjectElementService(
790                         final ProjectElementService projectElementService) {
791                 _projectElementService = projectElementService;
792         }
793
794         /**
795          * Get the simulationContextService.
796          * 
797          * @return the simulationContextService
798          */
799         public SimulationContextService getSimulationContextService() {
800                 return _simulationContextService;
801         }
802
803         /**
804          * Set the simulationContextService.
805          * 
806          * @param simulationContextService
807          *            the simulationContextService to set
808          */
809         public void setSimulationContextService(
810                         final SimulationContextService simulationContextService) {
811                 _simulationContextService = simulationContextService;
812         }
813
814         /**
815          * Get the studyService.
816          * 
817          * @return the studyService
818          */
819         public StudyService getStudyService() {
820                 return _studyService;
821         }
822
823         /**
824          * Set the studyService.
825          * 
826          * @param studyService
827          *            the studyService to set
828          */
829         public void setStudyService(final StudyService studyService) {
830                 _studyService = studyService;
831         }
832
833         /**
834          * Get the stepService.
835          * 
836          * @return the stepService
837          */
838         public StepService getStepService() {
839                 return _stepService;
840         }
841
842         /**
843          * Set the stepService.
844          * 
845          * @param stepService
846          *            the stepService to set
847          */
848         public void setStepService(final StepService stepService) {
849                 _stepService = stepService;
850         }
851
852         /**
853          * Get the documentService.
854          * 
855          * @return the documentService
856          */
857         public DocumentService getDocumentService() {
858                 return _documentService;
859         }
860
861         /**
862          * Set the documentService.
863          * 
864          * @param documentService
865          *            the documentService to set
866          */
867         public void setDocumentService(final DocumentService documentService) {
868                 _documentService = documentService;
869         }
870
871         /**
872          * Get the publicationDAO.
873          * 
874          * @return the publicationDAO
875          */
876         public PublicationDAO getPublicationDAO() {
877                 return _publicationDAO;
878         }
879
880         /**
881          * Set the publicationDAO.
882          * 
883          * @param publicationDAO
884          *            the publicationDAO to set
885          */
886         public void setPublicationDAO(final PublicationDAO publicationDAO) {
887                 _publicationDAO = publicationDAO;
888         }
889
890         /**
891          * Get the projectElementDAO.
892          * 
893          * @return the projectElementDAO
894          */
895         public ProjectElementDAO getProjectElementDAO() {
896                 return _projectElementDAO;
897         }
898
899         /**
900          * Set the projectElementDAO.
901          * 
902          * @param projectElementDAO
903          *            the projectElementDAO to set
904          */
905         public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
906                 _projectElementDAO = projectElementDAO;
907         }
908
909         /**
910          * Get the repositoryService.
911          * 
912          * @return the repositoryService
913          */
914         public RepositoryService getRepositoryService() {
915                 return _repositoryService;
916         }
917
918         /**
919          * Set the repositoryService.
920          * 
921          * @param repositoryService
922          *            the repositoryService to set
923          */
924         public void setRepositoryService(final RepositoryService repositoryService) {
925                 _repositoryService = repositoryService;
926         }
927
928         /**
929          * Get the timestampDAO.
930          * 
931          * @return the timestampDAO
932          */
933         public TimestampDAO getTimestampDAO() {
934                 return _timestampDAO;
935         }
936
937         /**
938          * Set the timestampDAO.
939          * 
940          * @param timestampDAO
941          *            the timestampDAO to set
942          */
943         public void setTimestampDAO(final TimestampDAO timestampDAO) {
944                 _timestampDAO = timestampDAO;
945         }
946
947         /**
948          * Get the documentTypeService.
949          * 
950          * @return the documentTypeService
951          */
952         public DocumentTypeService getDocumentTypeService() {
953                 return _documentTypeService;
954         }
955
956         /**
957          * Set the documentTypeService.
958          * 
959          * @param documentTypeService
960          *            the documentTypeService to set
961          */
962         public void setDocumentTypeService(
963                         final DocumentTypeService documentTypeService) {
964                 _documentTypeService = documentTypeService;
965         }
966
967         /**
968          * Get the userService.
969          * 
970          * @return the userService
971          */
972         public UserService getUserService() {
973                 return _userService;
974         }
975
976         /**
977          * Set the userService.
978          * 
979          * @param userService
980          *            the userService to set
981          */
982         public void setUserService(final UserService userService) {
983                 _userService = userService;
984         }
985
986         /**
987          * {@inheritDoc}
988          * 
989          * @see org.splat.service.PublicationService#replace(long, java.io.File)
990          */
991         @Override
992         @Transactional
993         public boolean replace(final Publication pub, final File newFile,
994                         final Date modifTime) throws IncompatibleDataException {
995                 if (!(ProgressState.EXTERN.equals(pub.getProgressState()) || ProgressState.inWORK
996                                 .equals(pub.getProgressState()))) {
997                         throw new IncompatibleDataException(MessageKeyEnum.DCT_000004
998                                         .toString());
999                 }
1000                 Document doc = getDocumentService().selectDocument(
1001                                 pub.value().getIndex());
1002                 if (LOG.isInfoEnabled()) {
1003                         LOG.info("Moving \"" + newFile.getName() + "\" to \""
1004                                         + doc.getSourceFile().asFile().getAbsolutePath() + "\".");
1005                 }
1006                 // Save a temporary copy of the original file as <old file name>.backup
1007                 String oldFilePath = doc.getSourceFile().asFile().getAbsolutePath();
1008                 File oldFile = new File(oldFilePath);
1009                 File backupFile = new File(oldFilePath + ".backup");
1010                 oldFile.renameTo(backupFile);
1011                 boolean res = newFile.renameTo(oldFile);
1012                 if (res) {
1013                         // Delete the temporary copy of the old file
1014                         // if the new one is moved into the repository.
1015                         backupFile.delete();
1016                         // Update the document modification date.
1017                         doc.setLastModificationDate(modifTime);
1018                         // Update presentation data
1019                         pub.value().setLastModificationDate(modifTime);
1020                 } else {
1021                         // Restore the original file if replacing is failed
1022                         backupFile.renameTo(oldFile);
1023                 }
1024                 return res;
1025         }
1026 }