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