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