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