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