Salome HOME
dfb90ddf211102aad6af5ecc716e614245f262f9
[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.BusinessException;
48 import org.splat.exception.IncompatibleDataException;
49 import org.splat.exception.InvalidParameterException;
50 import org.splat.exception.UserRightsException;
51 import org.splat.kernel.InvalidPropertyException;
52 import org.splat.kernel.MismatchException;
53 import org.splat.kernel.MissedPropertyException;
54 import org.splat.kernel.MultiplyDefinedException;
55 import org.splat.kernel.NotApplicableException;
56 import org.splat.manox.Reader;
57 import org.splat.manox.Toolbox;
58 import org.splat.service.dto.DocToCompareDTO;
59 import org.splat.service.technical.RepositoryService;
60 import org.splat.som.DocumentRights;
61 import org.splat.som.Revision;
62 import org.splat.som.Step;
63 import org.springframework.transaction.annotation.Transactional;
64
65 /**
66  * Publication service implementation.
67  * 
68  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
69  */
70 public class PublicationServiceImpl implements PublicationService {
71
72         /**
73          * Logger for this class.
74          */
75         protected final static Logger LOG = Logger
76                         .getLogger(PublicationServiceImpl.class);
77
78         /**
79          * Injected study service.
80          */
81         private StudyService _studyService;
82         /**
83          * Injected step service.
84          */
85         private StepService _stepService;
86         /**
87          * Injected document service.
88          */
89         private DocumentService _documentService;
90         /**
91          * Injected document type service.
92          */
93         private DocumentTypeService _documentTypeService;
94         /**
95          * Injected user service.
96          */
97         private UserService _userService;
98         /**
99          * Injected project element service.
100          */
101         private ProjectElementService _projectElementService;
102         /**
103          * Injected simulation context service.
104          */
105         private SimulationContextService _simulationContextService;
106         /**
107          * Injected publication DAO.
108          */
109         private PublicationDAO _publicationDAO;
110         /**
111          * Injected timestamp DAO.
112          */
113         private TimestampDAO _timestampDAO;
114         /**
115          * Injected project element DAO.
116          */
117         private ProjectElementDAO _projectElementDAO;
118         /**
119          * Injected repository service.
120          */
121         private RepositoryService _repositoryService;
122         /**
123          * Injected versions relation DAO.
124          */
125         private VersionsRelationDAO _versionsRelationDAO;
126
127         /**
128          * {@inheritDoc}
129          * 
130          * @see org.splat.service.PublicationService#copy(org.splat.dal.bo.som.Publication, org.splat.dal.bo.som.ProjectElement)
131          */
132         public Publication copy(final Publication aPublication,
133                         final ProjectElement publisher) {
134                 Publication copy = new Publication();
135                 copy.setValue(aPublication.value());
136                 copy.setStep(aPublication.getStep()); // May not be initialized yet
137                 copy.setOwner(publisher);
138                 copy.setIsnew(aPublication.getIsnew());
139                 if (!copy.getOwnerStudy().equals(aPublication.getOwnerStudy())) {
140                         copy.setIsnew('N'); // The referenced document is not new for the given study
141                 }
142                 return copy;
143         }
144
145         /**
146          * {@inheritDoc}
147          * 
148          * @see org.splat.service.PublicationService#createDoc(long, org.splat.som.Step, long, long, java.lang.String, java.lang.String,
149          *      org.splat.dal.bo.som.ProgressState, java.lang.String, java.lang.String, java.util.Date, java.util.List)
150          */
151         @Transactional
152         public Publication createDoc(final long ownerId, final Step step,
153                         final long documentTypeId, final long userId, final String fname,
154                         final String doctitle, final ProgressState docstate,
155                         final String reference, final String version, final Date docDate,
156                         final List<Long> docuses) throws MissedPropertyException,
157                         InvalidPropertyException, MultiplyDefinedException, IOException,
158                         NotApplicableException, InterruptedException, ParseException {
159                 DocumentType type = getDocumentTypeService().selectType(
160                                 (int) documentTypeId);
161                 User user = getUserService().selectUser(userId);
162                 File updir = getRepositoryService().getDownloadDirectory(user);
163                 File upfile = new File(updir.getPath() + "/" + fname);
164                 String[] table = fname.split("\\x2E");
165
166                 // Creation of the document
167                 Document.Properties dprop = new Document.Properties();
168                 dprop.setLocalPath(upfile.getPath());
169                 Publication addoc;
170
171                 if (reference.length() == 0) { // Importation of a foreign document
172                         // TODO: Extract property of supported documents (DOCX, ODT...)
173                         addoc = getStepService().createDocument(
174                                         step,
175                                         dprop.setName(doctitle).setType(type).setFormat(
176                                                         table[table.length - 1]).setAuthor(user));
177                         moveFile(upfile, addoc);
178                         try {
179                                 saveAs(addoc, docstate); // May throw FileNotFound if rename was not done
180                         } catch (FileNotFoundException saverror) {
181                                 Thread.sleep(1000);
182                                 LOG.info("Waiting for the file.");
183                                 upfile.renameTo(updir);
184                                 saveAs(addoc, docstate); // Forget it if throw again FileNotFound
185                         }
186                 } else { // Importation of a previously created template-based document
187                         if (docDate != null) {
188                                 dprop.setDate(docDate);
189                         }
190                         addoc = getStepService().assignDocument(step,
191                                         dprop.setReference(reference).setName(doctitle));
192                         moveFile(upfile, addoc);
193                         try {
194                                 if (version.length() > 0) {
195                                         saveAs(addoc, new Revision(version));
196                                 } else {
197                                         saveAs(addoc, docstate);
198                                 }
199                         } catch (FileNotFoundException saverror) {
200                                 Thread.sleep(1000);
201                                 LOG.info("Waiting for the file.");
202                                 upfile.renameTo(updir);
203                                 if (version.length() > 0) {
204                                         saveAs(addoc, new Revision(version));
205                                 } else {
206                                         saveAs(addoc, docstate);
207                                 }
208                         }
209                 }
210                 // Creation of uses relations
211                 if (docuses != null) {
212                         for (Long index : docuses) {
213                                 Document used = getDocumentService().selectDocument(index);
214                                 addoc.addDependency(used);
215                         }
216                 }
217                 return addoc;
218         }
219
220         /**
221          * Move a file into the repository as a source file of the document.
222          * 
223          * @param upfile
224          *            the uploaded file to move
225          * @param addoc
226          *            the document
227          */
228         private void moveFile(final File upfile, final Publication addoc) {
229                 File updir = addoc.getSourceFile().asFile();
230                 if (LOG.isInfoEnabled()) {
231                         LOG.info("Moving \"" + upfile.getAbsolutePath() + "\" to \""
232                                         + updir.getPath() + "\".");
233                 }
234                 upfile.renameTo(updir);
235         }
236
237         /**
238          * {@inheritDoc}
239          * 
240          * @see org.splat.service.PublicationService#versionDocument(org.splat.som.Step, org.splat.dal.bo.kernel.User, java.lang.String, long,
241          *      java.lang.String, java.lang.String, org.splat.dal.bo.som.ProgressState, java.util.Date, java.lang.String[], long[])
242          */
243         @Transactional
244         public void versionDocument(final Step step, final User user,
245                         final String filename, final long docIndex, final String docver,
246                         final String summary, final ProgressState state, final Date date,
247                         final String[] docuses, final long[] docusedby)
248                         throws MissedPropertyException, InvalidPropertyException,
249                         MultiplyDefinedException, IOException, MismatchException,
250                         NotApplicableException, InterruptedException {
251                 File updir = getRepositoryService().getDownloadDirectory(user);
252                 File upfile = new File(updir.getPath() + "/" + filename);
253
254                 // Versioning of the document
255                 Document.Properties dprop = new Document.Properties();
256                 dprop.setLocalPath(upfile.getPath());
257                 Publication current = step.getDocument(docIndex);
258                 Publication next;
259
260                 if ((docver.length() != 0) && // Importation of a not foreign document
261                                 (date != null)) {
262                         dprop.setDate(date);
263                 }
264                 if ((summary != null) && (summary.length() > 0)) {
265                         dprop.setDescription(summary);
266                 }
267                 next = getStepService().versionDocument(step, current,
268                                 dprop.setAuthor(user));
269                 moveFile(upfile, next);
270
271                 try {
272                         if (docver.length() == 0) { // Importation of a foreign document
273                                 saveAs(next, state); // May throw FileNotFound if rename was not done
274                         } else {
275                                 saveAs(next, new Revision(docver));
276                         }
277                 } catch (FileNotFoundException saverror) {
278                         Thread.sleep(1000);
279                         LOG.info("Waiting for the file.");
280                         upfile.renameTo(updir);
281                         saveAs(next, state);
282                 }
283                 // TODO: Remove current document details from the contents of open study
284
285                 // Creation of uses relations
286                 Publication syncronizedCurrent = _publicationDAO.get(current.getIndex());
287                 updateRelations(syncronizedCurrent, next, docuses, docusedby);
288         }
289
290         /**
291          * Update relations after creation of a new document version.
292          * 
293          * @param current
294          *            the current version
295          * @param next
296          *            the new version
297          * @param docuses
298          *            ids of used documents
299          * @param docusedby
300          *            ids of documents used by the versioned one.
301          */
302         private void updateRelations(final Publication current,
303                         final Publication next, final String[] docuses,
304                         final long[] docusedby) {
305                 if (docuses != null) {
306                         for (int i = 0; i < docuses.length; i++) {
307                                 Long index = Long.valueOf(docuses[i].trim());
308                                 Document used = getDocumentService().selectDocument(index);// RKV: getPublication(index, steps);
309                                 next.addDependency(used);
310                         }
311                 }
312                 // Outdating impacted document
313                 HashSet<Long> compatible = new HashSet<Long>();
314                 if (docusedby != null) {
315                         for (int i = 0; i < docusedby.length; i++) {
316                                 compatible.add(docusedby[i]);
317                         }
318                 }
319                 for (Publication using : current.getRelations(UsedByRelation.class)) {
320                         if (!compatible.contains(using.getIndex())) {
321                                 outdate(using);
322                         }
323                 }
324         }
325
326         /*
327          * protected Publication getPublication(int index, List<Step> steps) { for (Iterator<Step> i = steps.iterator(); i.hasNext();) { List<Publication>
328          * published = i.next().getAllDocuments(); for (Iterator<Publication> j = published.iterator(); j.hasNext();) { Publication found =
329          * j.next(); // In a given study step, if (found.value().getIndex() == index) return found; // there is only one publication of a given
330          * document } } return null; }
331          */
332         /**
333          * {@inheritDoc}
334          * 
335          * @see org.splat.service.PublicationService#approve(org.splat.dal.bo.som.Publication, java.util.Date)
336          */
337         @Transactional
338         public Timestamp approve(final Publication aPublication, final Date adate, final User user)
339                                 throws UserRightsException, InvalidParameterException {
340                 Timestamp res = null;
341                 if(user == null){
342                         throw new InvalidParameterException("user", user.toString());
343                 }
344                 if (!(aPublication.isOutdated() || (aPublication.value()
345                                 .getProgressState() != ProgressState.inCHECK))) {
346                         DocumentRights rights = new DocumentRights(user, aPublication);
347                         if(!rights.canApprove()) {
348                                 throw new UserRightsException(user.toString(), "approve");
349                         }
350                         Timestamp stamp = new Timestamp(ValidationStep.APPROVAL,
351                                         aPublication.value(), user, adate);
352                         getTimestampDAO().create(stamp);
353
354                         if (getDocumentService().promote(aPublication.value(), stamp)) {
355                                 res = stamp;
356 //                              if (getDocumentService().isStudyResult(type)
357 //                                              && owner.getProgressState() == ProgressState.inCHECK) {
358 //                                      getStudyService().promote(owner);
359 //                              }
360                         }
361                 }
362                 return res; // Hoping that promotion of the study succeeded
363         }
364
365         /**
366          * {@inheritDoc}
367          * 
368          * @see org.splat.service.PublicationService#demote(org.splat.dal.bo.som.Publication)
369          */
370         @Transactional
371         public boolean demote(final Publication aPublication) {
372                 boolean res = false;
373                 DocumentType type = aPublication.value().getType();
374                 Study owner = aPublication.getOwnerStudy();
375
376                 if (aPublication.value().getProgressState() == ProgressState.inCHECK) {
377                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
378                                         owner, type);
379                         if (cycle.enables(ValidationStep.REVIEW)) {
380                                 res = getDocumentService().demote(aPublication.value());
381                         } else {
382                                 res = getDocumentService().demote(aPublication.value());
383                                 if (res) {
384                                         getDocumentService().demote(aPublication.value());
385                                 }
386                         }
387                 } else if (aPublication.value().getProgressState() == ProgressState.inDRAFT) {
388                         res = getDocumentService().demote(aPublication.value());
389                 }
390 //              if (res && getDocumentService().isStudyResult(type)
391 //                              && owner.getProgressState() != ProgressState.inWORK) {
392 //                      getStudyService().demote(owner);
393 //              }
394                 return res;
395         }
396
397         /**
398          * {@inheritDoc}
399          * 
400          * @see org.splat.service.PublicationService#invalidate(org.splat.dal.bo.som.Publication)
401          */
402         @Transactional
403         public boolean invalidate(final Publication aPublication) {
404                 boolean res = false;
405                 if ((aPublication.value().getProgressState() == ProgressState.inCHECK)) {
406                         DocumentType type = aPublication.value().getType();
407                         Study owner = aPublication.getOwnerStudy();
408
409                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
410                                         owner, type);
411                         // Check if the validation cycle allows the review step
412                         if (cycle.enables(ValidationStep.REVIEW)) {
413 //                              if (getDocumentService().demote(aPublication.value())
414 //                                              && getDocumentService().isStudyResult(type)
415 //                                              && owner.getProgressState() == ProgressState.inCHECK) {
416 //                                      getStudyService().demote(owner);
417 //                              }
418                                 res = true;
419                         } else { // If the validation cycle has no inDraft step
420                                 res = demote(aPublication);
421                         }
422                 }
423                 return res;
424         }
425
426         /**
427          * {@inheritDoc}
428          * 
429          * @see org.splat.service.PublicationService#promote(org.splat.dal.bo.som.Publication, java.util.Date)
430          */
431         @Transactional
432         public Timestamp promote(final Publication aPublication, final Date pdate, User user)
433                                 throws UserRightsException {
434                 Timestamp res = null;
435                 if ((!aPublication.isOutdated())
436                                 && (aPublication.value().getProgressState() == ProgressState.inWORK)) {
437                         DocumentType type = aPublication.value().getType();
438                         Study owner = aPublication.getOwnerStudy();
439                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
440                                         owner, type);
441                         if(user == null) {
442                                 user = cycle.getActor(ValidationStep.PROMOTION);
443                                 if (user == null) {
444                                         getInvolvedStep(aPublication).getActor();
445                                 }
446                                 if (user == null) {
447                                         user = owner.getAuthor();
448                                 }
449                         } else {
450                                 DocumentRights rights = new DocumentRights(user, aPublication);
451                                 if(!rights.canPromote()) {
452                                         throw new UserRightsException(user.toString(), "promote");
453                                 }
454                         }
455                         Timestamp stamp = new Timestamp(ValidationStep.PROMOTION,
456                                         aPublication.value(), user, pdate);
457                         getTimestampDAO().create(stamp);
458
459                         if (getDocumentService().promote(aPublication.value(), stamp)) {
460                                 res = stamp;
461                                 if (!cycle.enables(ValidationStep.REVIEW)) {
462                                         getDocumentService().promote(aPublication.value(), null);
463                                 }
464 //                              if (getDocumentService().isStudyResult(type)
465 //                                              && owner.getProgressState() == ProgressState.inWORK) {
466 //                                      getStudyService().promote(owner);
467 //                              }
468                         }
469                 }
470                 return res; // Hoping that promotion of the study succeeded
471         }
472
473         /**
474          * {@inheritDoc}
475          * 
476          * @see org.splat.service.PublicationService#review(org.splat.dal.bo.som.Publication, java.util.Date)
477          */
478         @Transactional
479         public Timestamp review(final Publication aPublication, final Date rdate, final User user)
480                                 throws UserRightsException, InvalidParameterException {
481                 Timestamp res = null;
482                 if(user == null){
483                         throw new InvalidParameterException("user", user.toString());
484                 }
485                 if (!aPublication.isOutdated()
486                                 && !(aPublication.value().getProgressState() != ProgressState.inDRAFT)) {
487
488                         DocumentRights rights = new DocumentRights(user, aPublication);
489                         if(!rights.canReview()) {
490                                 throw new UserRightsException(user.toString(), "review");
491                         }
492                         Timestamp stamp = new Timestamp(ValidationStep.REVIEW, aPublication
493                                         .value(), user, rdate);
494                         getTimestampDAO().create(stamp);
495
496                         if (getDocumentService().promote(aPublication.value(), stamp)) {
497                                 res = stamp;
498 //                              if (getDocumentService().isStudyResult(type)
499 //                                              && owner.getProgressState() == ProgressState.inDRAFT) {
500 //                                      getStudyService().promote(owner);
501 //                              }
502                         }
503                 }
504                 return res; // Hoping that promotion of the study succeeded
505         }
506
507         /**
508          * {@inheritDoc}
509          * 
510          * @see org.splat.service.PublicationService#saveAs(org.splat.dal.bo.som.Publication, org.splat.som.Revision)
511          * @deprecated
512          */
513         @Deprecated
514         @Transactional
515         public void saveAs(final Publication aPublication, final Revision newvers)
516                         throws FileNotFoundException, NotApplicableException {
517                 if (aPublication.value().isUndefined()) {
518                         throw new NotApplicableException(
519                                         "Cannot save a Publication object refering an undefined Document");
520                 }
521                 if (!aPublication.value().getSourceFile().exists()) {
522                         throw new FileNotFoundException();
523                 }
524
525                 getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based) hascode
526                 getDocumentService().updateAs(aPublication.value(), newvers); // May change the branch name of given revision
527                 updateOwner(aPublication);
528         }
529
530         /**
531          * {@inheritDoc}
532          * 
533          * @see org.splat.service.PublicationService#saveAs(org.splat.dal.bo.som.Publication, org.splat.dal.bo.som.ProgressState)
534          */
535         @Transactional
536         public void saveAs(final Publication aPublication, final ProgressState state)
537                         throws FileNotFoundException, NotApplicableException {
538                 if (aPublication.value().isUndefined()) {
539                         throw new NotApplicableException(
540                                         "Cannot save a Publication object refering an undefined Document");
541                 }
542                 if (!aPublication.value().getSourceFile().exists()) {
543                         throw new FileNotFoundException(aPublication.value()
544                                         .getSourceFile().asFile().getAbsolutePath());
545                 }
546
547                 if (state == ProgressState.inWORK || state == ProgressState.EXTERN) {
548                         getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based)
549                         // hascode
550                         getDocumentService().updateAs(aPublication.value(), state);
551                 } else {
552                         // Check that the state is applicable for the validation cycle
553                         DocumentType mytype = aPublication.value().getType();
554                         Study owner = aPublication.getOwnerStudy();
555                         ValidationCycle cycle = getStudyService().getValidationCycleOf(
556                                         owner, mytype);
557                         boolean review = cycle.enables(ValidationStep.REVIEW);
558                         if (!(state == ProgressState.inDRAFT && review)
559                                         && !(state == ProgressState.inCHECK && !review)) {
560                                 throw new NotApplicableException(MessageKeyEnum.DCT_000003
561                                                 .toString(), state.toString());
562                         }
563                         getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based)
564                         // hascode
565                         getDocumentService().updateAs(aPublication.value(),
566                                         ProgressState.inWORK);
567                         
568                         try {
569                                 promote(aPublication, aPublication.value()
570                                                 .getLastModificationDate(), null); // Promotes to the appropriate state in accordance to the validation cycle
571                         } catch(UserRightsException e) {
572                                 LOG.info("a BusinessException is thrown.");
573                         }
574                 }
575                 updateOwner(aPublication);
576         }
577
578         /**
579          * Update an owner of the publication.
580          * 
581          * @param aPublication
582          *            the document publication
583          */
584         @Transactional
585         private void updateOwner(final Publication aPublication) {
586                 Step step = getInvolvedStep(aPublication);
587
588                 // Update of involved step
589                 Document previous = aPublication.value().getPreviousVersion();
590                 if (previous != null) {
591                         Publication oldoc = step.getDocument(previous.getIndex());
592                         getStepService().remove(step, oldoc); // Decrements the configuration tag count of document
593                 }
594                 getStepService().add(step, aPublication); // Increments the configuration tag count of document
595
596                 // Import the document properties and update of the study
597                 forwardProperties(aPublication, aPublication.value().getSourceFile()
598                                 .asFile(), step);
599                 getProjectElementDAO().merge(aPublication.getOwner());
600         }
601
602         /**
603          * Propagate simulation contexts from the given config file to the publication's owner (study or step).
604          * 
605          * @param aPublication
606          *            the document publication
607          * @param from
608          *            the config file
609          * @param to
610          *            the study step
611          */
612         private void forwardProperties(final Publication aPublication,
613                         final java.io.File from, final Step to) {
614                 Reader tool = Toolbox.getReader(from);
615                 if (tool != null) { // Properties extractor available for this type of document
616                         SimulationContextType.Properties sprop = new SimulationContextType.Properties()
617                                         .setStep(to.getStep()).setProgressState(
618                                                         ProgressState.APPROVED);
619                         List<SimulationContextType> contype = getSimulationContextService()
620                                         .selectTypesWhere(sprop);
621                         if (!contype.isEmpty()) { // There is an approved property type configured at this step
622
623                                 SimulationContext.Properties cprop = new SimulationContext.Properties();
624                                 List<SimulationContext> context = to.getAllSimulationContexts();
625
626                                 context = new ArrayList<SimulationContext>(context.size());
627                                 context.addAll(to.getAllSimulationContexts());
628                                 cprop.disableCheck();
629                                 for (Iterator<SimulationContextType> i = contype.iterator(); i
630                                                 .hasNext();) {
631                                         SimulationContextType property = i.next();
632                                         boolean isFound = false;
633                                         for (Iterator<SimulationContext> j = context.iterator(); j
634                                                         .hasNext();) {
635                                                 SimulationContext existing = j.next();
636                                                 isFound = existing.getType().equals(property);
637                                                 if (isFound) {
638                                                         // Forget this property as it is already set
639                                                         break;
640                                                 }
641                                         }
642                                         if (!isFound) {
643                                                 try {
644                                                         String value = tool.extractProperty(property
645                                                                         .getName());
646                                                         if (value == null) {
647                                                                 continue; // Property not defined into the document
648                                                         }
649
650                                                         cprop.setType(property).setValue(value);
651                                                         if (aPublication.getOwner() instanceof Study) {
652                                                                 getStudyService().addProjectContext(
653                                                                                 (Study) aPublication.getOwner(), cprop); // Re-indexes knowledges and the study
654                                                         } else {
655                                                                 getStepService()
656                                                                                 .addSimulationContext(to, cprop); // Re-indexes knowledges only
657                                                         }
658                                                 } catch (Exception e) {
659                                                         break;
660                                                 }
661                                         }
662                                 }
663                         }
664                 }
665         }
666
667         /**
668          * Returns the study Step into which the document version referenced by this publication has been published.
669          * 
670          * @param aPublication
671          *            the document publication
672          * @return the study step where the document is published
673          */
674         public Step getInvolvedStep(final Publication aPublication) {
675                 if (aPublication.getStep() == null) {
676                         Step[] step = getProjectElementService().getSteps(
677                                         aPublication.getOwner());
678                         for (int i = 0; i < step.length; i++) {
679                                 aPublication.setStep(step[i]); // The involved step necessarily exists
680                                 if (aPublication.value().isInto(aPublication.getStep())) {
681                                         break;
682                                 }
683                         }
684                 }
685                 return aPublication.getStep();
686         }
687
688         /** 
689          * {@inheritDoc}
690          * @see org.splat.service.PublicationService#getLastVersion(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.ProjectElement)
691          */
692         @Transactional(readOnly=true)
693         public Document getLastVersion(final Document doc, final ProjectElement owner) {
694                 Document document = _documentService.selectDocument(doc.getIndex());    //get document attached to hibernate session
695                 ProjectElement trueOwner = _projectElementDAO.merge(owner);
696                 Document theLastVersion = null;
697                 if(trueOwner.getPublication(document) != null) {
698                         theLastVersion = document;
699                 } else {        //start recursive search
700                         List<VersionsRelation> relations = _versionsRelationDAO
701                                         .getFilteredList(Restrictions.eq("refer", theLastVersion));
702                         //there may be several next versions if document is shared between scenarios,
703                         //but only one leads to a publication from given project elements.
704                         for(Relation relation : relations) {
705                                 Document candidate = getLastVersion((Document)(relation.getFrom()), trueOwner);
706                                 if(candidate != null ) {
707                                         theLastVersion = candidate;
708                                 }
709                         }
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 }