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