]> SALOME platform Git repositories - tools/siman.git/blob - Workspace/Siman-Common/src/org/splat/service/DocumentServiceImpl.java
Salome HOME
Compare method signature and DocToCompareDTO are added.
[tools/siman.git] / Workspace / Siman-Common / src / org / splat / service / DocumentServiceImpl.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.text.DecimalFormat;
13 import java.text.SimpleDateFormat;
14 import java.util.Calendar;
15 import java.util.Iterator;
16 import java.util.List;
17
18 import org.hibernate.criterion.Criterion;
19 import org.hibernate.criterion.Restrictions;
20 import org.splat.dal.bo.kernel.Relation;
21 import org.splat.dal.bo.som.ConvertsRelation;
22 import org.splat.dal.bo.som.Document;
23 import org.splat.dal.bo.som.DocumentType;
24 import org.splat.dal.bo.som.File;
25 import org.splat.dal.bo.som.ProgressState;
26 import org.splat.dal.bo.som.ProjectElement;
27 import org.splat.dal.bo.som.Scenario;
28 import org.splat.dal.bo.som.StampRelation;
29 import org.splat.dal.bo.som.Study;
30 import org.splat.dal.bo.som.Timestamp;
31 import org.splat.dal.bo.som.ValidationStep;
32 import org.splat.dal.bo.som.Document.Properties;
33 import org.splat.dal.dao.kernel.RelationDAO;
34 import org.splat.dal.dao.som.DocumentDAO;
35 import org.splat.dal.dao.som.DocumentTypeDAO;
36 import org.splat.dal.dao.som.FileDAO;
37 import org.splat.dal.dao.som.StudyDAO;
38 import org.splat.kernel.InvalidPropertyException;
39 import org.splat.kernel.MissedPropertyException;
40 import org.splat.kernel.NotApplicableException;
41 import org.splat.log.AppLogger;
42 import org.splat.manox.Reader;
43 import org.splat.manox.Toolbox;
44 import org.splat.service.technical.ProjectSettingsService;
45 import org.splat.service.technical.RepositoryService;
46 import org.splat.service.technical.ProjectSettingsServiceImpl.FileNaming;
47 import org.splat.som.Revision;
48 import org.springframework.transaction.annotation.Transactional;
49
50 /**
51  * Document service implementation.
52  * 
53  * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
54  * 
55  */
56 public class DocumentServiceImpl implements DocumentService {
57
58         /**
59          * The logger for the service.
60          */
61         public final static AppLogger LOG = AppLogger
62                         .getLogger(DocumentServiceImpl.class);
63
64         /**
65          * Injected study service.
66          */
67         private StudyService _studyService;
68         /**
69          * Injected project settings service.
70          */
71         private ProjectSettingsService _projectSettings;
72         /**
73          * Injected repository service.
74          */
75         private RepositoryService _repositoryService;
76         /**
77          * Injected document DAO.
78          */
79         private DocumentDAO _documentDAO;
80         /**
81          * Injected relation DAO.
82          */
83         private RelationDAO _relationDAO;
84         /**
85          * Injected document type DAO.
86          */
87         private DocumentTypeDAO _documentTypeDAO;
88         /**
89          * Injected file DAO.
90          */
91         private FileDAO _fileDAO;
92         /**
93          * Injected study DAO.
94          */
95         private StudyDAO _studyDAO;
96
97         /**
98          * {@inheritDoc}
99          * 
100          * @see org.splat.service.DocumentService#selectDocument(long)
101          */
102         @Transactional(readOnly = true)
103         public Document selectDocument(final long index) {
104                 return getDocumentDAO().get(index);
105         }
106
107         /**
108          * {@inheritDoc}
109          * 
110          * @see org.splat.service.DocumentService#selectDocument(java.lang.String, java.lang.String)
111          */
112         @Transactional(readOnly = true)
113         public Document selectDocument(final String refid, final String version) {
114                 Criterion aCondition = Restrictions.and(Restrictions.eq("did", refid),
115                                 Restrictions.eq("version", version));
116                 return getDocumentDAO().findByCriteria(aCondition);
117         }
118
119         /**
120          * {@inheritDoc}
121          * 
122          * @see org.splat.service.DocumentService#generateDocumentId(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
123          */
124         @Transactional
125         public void generateDocumentId(final Document aDoc, final Properties dprop) {
126                 Study owner = dprop.getOwner().getOwnerStudy();
127
128                 // Synchronize the object with the current Hibernate session.
129                 owner.setLastLocalIndex(getStudyDAO().get(owner.getIndex())
130                                 .getLastLocalIndex());
131
132                 SimpleDateFormat tostring = new SimpleDateFormat("yyyy"); // RKV: NOPMD: TODO: Use locale here?
133                 String year = tostring.format(owner.getDate());
134                 String filename = generateEncodedName(aDoc, owner);
135                 String path = owner.getReference();
136                 ProjectSettingsService.Step step = getProjectSettings().getStep(
137                                 aDoc.getStep());
138                 aDoc.setDid(new StringBuffer(path).append(".%").append(
139                                 Document.suformat).toString()); // Document reference
140                 StringBuffer pathBuf = new StringBuffer(year).append("/").append(path)
141                                 .append("/").append(step.getPath())
142                                 // File path relative to the repository vault
143                                 .append(filename);
144                 if (!FileNaming.asis.equals(getProjectSettings().getFileNamingScheme())) {
145                         // Use format as extension if file naming strategy is not "asis".
146                         pathBuf.append(".").append(aDoc.getFile().getFormat()); // File name and extension
147                 }
148                 aDoc.getFile().changePath(pathBuf.toString());
149                 owner = getStudyDAO().merge(owner);
150         }
151
152         /**
153          * Generate encoded document file name according to the naming scheme from project settings.
154          * 
155          * @param aDoc
156          *            the document
157          * @param scope
158          *            the study
159          * @return document reference name
160          */
161         private String generateEncodedName(final Document aDoc, final Study scope) {
162                 StringBuffer encoding = new StringBuffer();
163                 FileNaming scheme = getProjectSettings().getFileNamingScheme();
164                 DecimalFormat tostring = new DecimalFormat(Document.suformat);
165
166                 int number = getStudyService().generateLocalIndex(scope);
167
168                 if (scheme == FileNaming.encoded) {
169                         encoding.append(scope.getReference()).append("_").append(
170                                         tostring.format(number));
171                 } else { // title and (temporarily) asis
172                         encoding.append(tostring.format(number)).append("_").append(
173                                         aDoc.getFile().getName());
174                 }
175                 return encoding.toString();
176         }
177
178         /**
179          * Get encoded root name for a document file.
180          * 
181          * @param aDoc
182          *            the document
183          * @param scope
184          *            the study
185          * @return file name
186          */
187         private String getEncodedRootName(final Document aDoc, final Study scope) {
188                 FileNaming scheme = getProjectSettings().getFileNamingScheme();
189                 String res;
190                 if (scheme == FileNaming.encoded) {
191                         res = scope.getReference();
192                 } else if (scheme == FileNaming.asis) {
193                         res = aDoc.getFile().getName();
194                 } else {
195                         res = aDoc.getTitle();
196                 }
197                 return res;
198         }
199
200         /**
201          * {@inheritDoc}
202          * 
203          * @see org.splat.service.DocumentService#initialize(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
204          */
205         @Transactional
206         public void initialize(final Document aDoc, final Properties dprop)
207                         throws MissedPropertyException, InvalidPropertyException,
208                         NotApplicableException {
209                 if (!aDoc.isUndefined()) {
210                         throw new NotApplicableException(
211                                         "Cannot initialize an existing Document");
212                 }
213                 if (dprop.getName() == null) {
214                         throw new MissedPropertyException("name");
215                 }
216                 if (dprop.getName().length() == 0) {
217                         throw new InvalidPropertyException("name");
218                 }
219                 if (dprop.getOwner() == null) {
220                         throw new MissedPropertyException("owner");
221                 }
222                 // if (dprop.owner instanceof Study && !ProjectSettings.getStep(step).appliesTo(Study.class)) {
223                 // throw new InvalidPropertyException("step");
224                 // }
225                 aDoc.setTitle(dprop.getName());
226                 aDoc.getFile().changePath(
227                                 aDoc.getFile().getRelativePath().replace("%n",
228                                                 getEncodedRootName(aDoc, (Study) dprop.getOwner())));
229                 if (aDoc.getHistory() == -1) {
230                         aDoc.setHistory(0);
231                 }
232                 if (dprop.getDate() == null) {
233                         Calendar current = Calendar.getInstance();
234                         aDoc.setLastModificationDate(current.getTime()); // Today
235                 } else {
236                         aDoc.setLastModificationDate(dprop.getDate());
237                 }
238                 getDocumentDAO().update(aDoc);
239         }
240
241         /**
242          * {@inheritDoc}
243          * 
244          * @see org.splat.service.DocumentService#getSaveDirectory(org.splat.dal.bo.som.Document)
245          */
246         public java.io.File getSaveDirectory(final Document aDoc) {
247                 String mypath = getRepositoryService().getRepositoryVaultPath()
248                                 + aDoc.getSourceFile().getRelativePath();
249                 String[] table = mypath.split("/");
250
251                 // Cutting the filename
252                 StringBuffer path = new StringBuffer(table[0]);
253                 for (int i = 1; i < table.length - 1; i++) {
254                         path = path.append("/").append(table[i]);
255                 }
256                 return new java.io.File(path.append("/").toString());
257         }
258
259         /**
260          * Extract title and reference properties from the given file.
261          * 
262          * @param file
263          *            the file to parse
264          * @return the extracted properties
265          */
266         public Properties extractProperties(final java.io.File file) {
267                 Properties fprop = new Properties();
268                 Reader tool = Toolbox.getReader(file);
269                 String value;
270                 if (tool != null) {
271                         try {
272                                 value = tool.extractProperty("title");
273                                 if (value != null) {
274                                         fprop.setName(value);
275                                 }
276
277                                 value = tool.extractProperty("reference");
278                                 if (value != null) {
279                                         fprop.setReference(value);
280                                 }
281                         } catch (Exception e) {
282                                 LOG.debug(e.getMessage(), e);
283                         }
284                 }
285                 return fprop;
286         }
287
288         /**
289          * Create "Converts" relation for the given document and the given format.
290          * 
291          * @param aDoc
292          *            the document
293          * @param format
294          *            the format
295          * @return the created "Converts" relation
296          */
297         @Transactional
298         public ConvertsRelation attach(final Document aDoc, final String format) {
299                 return attach(aDoc, format, null);
300         }
301
302         /**
303          * Create "Converts" relation for the given document, format and description.
304          * 
305          * @param aDoc
306          *            the document
307          * @param format
308          *            the format
309          * @param description
310          *            the description of the relation
311          * @return the created "Converts" relation
312          */
313         @Transactional
314         public ConvertsRelation attach(final Document aDoc, final String format,
315                         final String description) {
316                 String path = aDoc.getRelativePath();
317                 File export = new File(path + "." + format);
318                 ConvertsRelation attach = new ConvertsRelation(aDoc, export,
319                                 description);
320
321                 getFileDAO().create(export);
322                 getRelationDAO().create(attach);
323
324                 aDoc.getAllRelations().add(attach);
325                 getDocumentDAO().merge(aDoc);
326
327                 return attach;
328         }
329
330         /**
331          * Build a reference (document id) for the given document in the given study basing on the given original document.
332          * 
333          * @param aDoc
334          *            the document to set set the new reference to
335          * @param scope
336          *            the study
337          * @param lineage
338          *            the original document
339          * @return true if the new reference is set
340          */
341         public boolean buildReferenceFrom(final Document aDoc,
342                         final ProjectElement scope, final Document lineage) {
343                 boolean res = (aDoc.getProgressState() == ProgressState.inWORK);
344                 if (res) {
345                         Study owner = scope.getOwnerStudy();
346                         Scenario context = null;
347                         if (scope instanceof Scenario) {
348                                 context = ((Scenario) scope);
349                         }
350                         aDoc.setDid(lineage.getDid());
351                         if (context != null
352                                         && (lineage.isVersioned() || owner.shares(lineage))) {
353                                 aDoc.setVersion(new Revision(aDoc.getVersion()).setBranch(
354                                                 context.getReference()).toString());
355                         }
356                 }
357                 return res;
358         }
359
360         /**
361          * Build a reference (document id) for the given document in the given study.
362          * 
363          * @param aDoc
364          *            the document to set set the new reference to
365          * @param scope
366          *            the study
367          * @return true if the new reference is set
368          */
369         public boolean buildReferenceFrom(final Document aDoc, final Study scope) {
370                 if (aDoc.getProgressState() != ProgressState.inWORK
371                                 && aDoc.getProgressState() != ProgressState.EXTERN) {
372                         return false;
373                 }
374                 DecimalFormat tostring = new DecimalFormat(Document.suformat);
375
376                 aDoc.setDid(aDoc.getDid().replace("%" + Document.suformat,
377                                 tostring.format(scope.getLastLocalIndex())));
378                 return true;
379         }
380
381         /**
382          * Demote a document.
383          * 
384          * @param aDoc
385          *            the document to demote
386          * @return true if demoting succeeded
387          */
388         @Transactional
389         public boolean demote(final Document aDoc) {
390                 ValidationStep torem;
391
392                 if (aDoc.getProgressState() == ProgressState.inCHECK) {
393                         aDoc.setProgressState(ProgressState.inDRAFT);
394                         torem = ValidationStep.REVIEW;
395                         // This operation must not change the version number of documents.
396                         // Consequently, inDRAFT documents may have a minor version number equal to zero.
397                 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
398                         aDoc.setProgressState(ProgressState.inWORK);
399                         torem = ValidationStep.PROMOTION;
400                 } else {
401                         return false;
402                 }
403                 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
404                                 .hasNext();) {
405                         Relation link = i.next();
406                         if (!(link instanceof StampRelation)) {
407                                 continue;
408                         }
409                         if (((StampRelation) link).getStampType() != torem) {
410                                 continue;
411                         }
412                         i.remove();
413                         break;
414                 }
415                 getDocumentDAO().update(aDoc);
416                 return true;
417         }
418
419         /**
420          * Promote a document.
421          * 
422          * @param aDoc
423          *            the document to promote
424          * @param stamp
425          *            the timestamp of the promotion
426          * @return true if promotion succeeded
427          */
428         @Transactional
429         public boolean promote(final Document aDoc, final Timestamp stamp) {
430                 ProgressState newstate = null;
431
432                 if (aDoc.getProgressState() == ProgressState.inWORK) {
433                         newstate = ProgressState.inDRAFT; // Promotion to being reviewed
434                 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
435                         newstate = ProgressState.inCHECK; // Promotion to approval
436                         Revision myvers = new Revision(aDoc.getVersion());
437                         if (myvers.isMinor()) {
438                                 aDoc.setVersion(myvers.incrementAs(newstate).toString());
439                                 // TODO: If my physical file is programatically editable, update its (property) version number
440                                 // ISSUE: What about attached files such as PDF if exist, should we remove them ?
441                         }
442                 } else if (aDoc.getProgressState() == ProgressState.inCHECK) {
443                         newstate = ProgressState.APPROVED;
444                 }
445                 aDoc.setProgressState(newstate);
446                 if (stamp != null) {
447                         // RKV: aDoc.addRelation(stamp.getContext());
448                         aDoc.getAllRelations().add(stamp.getContext());
449                 }
450                 getDocumentDAO().update(aDoc);
451                 return true;
452         }
453
454         /**
455          * Increments the reference count of this document following its publication in a Study step.
456          * 
457          * @param aDoc
458          *            the document to hold
459          * @see #release()
460          */
461         @Transactional
462         public void hold(final Document aDoc) {
463                 aDoc.setCountag(aDoc.getCountag() + 1);
464                 if (aDoc.isSaved()) {
465                         getDocumentDAO().update(aDoc);
466                 }
467         }
468
469         /**
470          * Decrements the reference count of this document following the removal of a Publication from a Study step.
471          * 
472          * @param aDoc
473          *            the document to release
474          * @see #hold()
475          */
476         @Transactional
477         public void release(final Document aDoc) {
478                 aDoc.setCountag(aDoc.getCountag() - 1);
479                 if (aDoc.isSaved()) {
480                         getDocumentDAO().merge(aDoc);
481                 }
482         }
483
484         /**
485          * Rename a document.
486          * 
487          * @param aDoc
488          *            the document to rename
489          * @param title
490          *            the new document title
491          * @throws InvalidPropertyException
492          *             if the new title is empty
493          */
494         @Transactional
495         public void rename(final Document aDoc, final String title)
496                         throws InvalidPropertyException {
497                 if (title.length() == 0) {
498                         throw new InvalidPropertyException("name");
499                 }
500
501                 Calendar current = Calendar.getInstance();
502                 aDoc.setTitle(title);
503                 aDoc.setLastModificationDate(current.getTime()); // Today
504                 getDocumentDAO().update(aDoc);
505         }
506
507         /**
508          * Update a version of the given document.
509          * 
510          * @param aDoc
511          *            the document
512          * @param newvers
513          *            the new version
514          */
515         public void updateAs(final Document aDoc, final Revision newvers) {
516                 aDoc.setVersion(newvers.setBranch(aDoc.getVersion()).toString()); // Branch names are propagated by the versionning
517                 ProgressState newstate = ProgressState.inCHECK;
518                 if (newvers.isMinor()) {
519                         newstate = ProgressState.inWORK;
520                 }
521                 aDoc.setProgressState(null); // Just to tell updateAs(state) to not increment the version number
522                 updateAs(aDoc, newstate);
523         }
524
525         /**
526          * Update a state of the given document.
527          * 
528          * @param aDoc
529          *            the document
530          * @param state
531          *            the new state
532          */
533         @Transactional
534         public void updateAs(final Document aDoc, final ProgressState state) {
535                 Document previous = null;
536
537                 // Set of version number
538                 if (state == ProgressState.EXTERN) {
539                         if (aDoc.getProgressState() != ProgressState.EXTERN) {
540                                 aDoc.setVersion(null); // Strange use-case...
541                         }
542                 } else {
543                         Revision myvers = new Revision(aDoc.getVersion());
544                         if (!myvers.isNull()) { // Versionning context
545                                 previous = aDoc.getPreviousVersion();
546                         }
547                         if (aDoc.getProgressState() != null) {
548                                 myvers.incrementAs(state); // Incrementation if the reversion number is not imposed
549                         }
550                         aDoc.setVersion(myvers.toString());
551                 }
552                 // Update this document and the previous version, if exist
553                 if (previous != null) {
554                         previous.setHistory(previous.getHistory() + 1);
555                         getDocumentDAO().merge(previous);
556                 }
557                 aDoc.setProgressState(state);
558                 // RKV: getDocumentDAO().update(aDoc);
559         }
560
561         // protected void upgrade () {
562         // -------------------------
563         // if (this.state != ProgressState.inWORK) return;
564         //
565         // Calendar current = Calendar.getInstance();
566         // for (Iterator<Relation> i=getAllRelations().iterator(); i.hasNext();) {
567         // Relation link = i.next();
568         // if (!link.getClass().equals(UsesRelation.class)) continue;
569         //
570         // Document used = (Document)link.getTo();
571         // if (!used.isVersioned()) continue;
572         // TODO: Update the uses relation
573         // }
574         // this.promote();
575         // this.lasdate = current.getTime(); // Today
576         // Database.getSession().update(this);
577         //
578         // TODO: Promote documents using this one
579         // }
580
581         /**
582          * Checks if documents of this type are result of a study. A document is the result of a study when it is the result of the last step of
583          * the study.
584          * 
585          * @param aType
586          *            the document type
587          * @return true if documents of this type are result of a study.
588          * @see #isStepResult()
589          * @see #isResultOf(org.splat.service.technical.ProjectSettingsServiceImpl.Step)
590          */
591         public boolean isStudyResult(final DocumentType aType) {
592                 List<ProjectSettingsService.Step> step = getProjectSettings()
593                                 .getAllSteps();
594                 ProjectSettingsService.Step lastep = step.get(step.size() - 1);
595                 return (aType.isResultOf(lastep));
596         }
597
598         /**
599          * Get document by its path.
600          * 
601          * @param path
602          *            the document path
603          * @return the document if found or null
604          */
605         @Transactional(readOnly = true)
606         public Document getDocumentByPath(String path) {
607                 String[] parse = path.split("'");
608
609                 path = parse[0];
610                 for (int i = 1; i < parse.length; i++) {
611                         path = path + "''" + parse[i];
612                 }
613                 Criterion aCondition = Restrictions.eq("path", path);
614                 return getDocumentDAO().findByCriteria(aCondition);
615         }
616
617         /**
618          * Get the studyService.
619          * 
620          * @return the studyService
621          */
622         public StudyService getStudyService() {
623                 return _studyService;
624         }
625
626         /**
627          * Set the studyService.
628          * 
629          * @param studyService
630          *            the studyService to set
631          */
632         public void setStudyService(final StudyService studyService) {
633                 _studyService = studyService;
634         }
635
636         /**
637          * Get project settings.
638          * 
639          * @return Project settings service
640          */
641         private ProjectSettingsService getProjectSettings() {
642                 return _projectSettings;
643         }
644
645         /**
646          * Set project settings service.
647          * 
648          * @param projectSettingsService
649          *            project settings service
650          */
651         public void setProjectSettings(
652                         final ProjectSettingsService projectSettingsService) {
653                 _projectSettings = projectSettingsService;
654         }
655
656         /**
657          * Get the documentDAO.
658          * 
659          * @return the documentDAO
660          */
661         public DocumentDAO getDocumentDAO() {
662                 return _documentDAO;
663         }
664
665         /**
666          * Set the documentDAO.
667          * 
668          * @param documentDAO
669          *            the documentDAO to set
670          */
671         public void setDocumentDAO(final DocumentDAO documentDAO) {
672                 _documentDAO = documentDAO;
673         }
674
675         /**
676          * Get the repositoryService.
677          * 
678          * @return the repositoryService
679          */
680         public RepositoryService getRepositoryService() {
681                 return _repositoryService;
682         }
683
684         /**
685          * Set the repositoryService.
686          * 
687          * @param repositoryService
688          *            the repositoryService to set
689          */
690         public void setRepositoryService(final RepositoryService repositoryService) {
691                 _repositoryService = repositoryService;
692         }
693
694         /**
695          * Get the documentTypeDAO.
696          * 
697          * @return the documentTypeDAO
698          */
699         public DocumentTypeDAO getDocumentTypeDAO() {
700                 return _documentTypeDAO;
701         }
702
703         /**
704          * Set the documentTypeDAO.
705          * 
706          * @param documentTypeDAO
707          *            the documentTypeDAO to set
708          */
709         public void setDocumentTypeDAO(final DocumentTypeDAO documentTypeDAO) {
710                 _documentTypeDAO = documentTypeDAO;
711         }
712
713         /**
714          * Get the fileDAO.
715          * 
716          * @return the fileDAO
717          */
718         public FileDAO getFileDAO() {
719                 return _fileDAO;
720         }
721
722         /**
723          * Set the fileDAO.
724          * 
725          * @param fileDAO
726          *            the fileDAO to set
727          */
728         public void setFileDAO(final FileDAO fileDAO) {
729                 _fileDAO = fileDAO;
730         }
731
732         /**
733          * Get the studyDAO.
734          * 
735          * @return the studyDAO
736          */
737         public StudyDAO getStudyDAO() {
738                 return _studyDAO;
739         }
740
741         /**
742          * Set the studyDAO.
743          * 
744          * @param studyDAO
745          *            the studyDAO to set
746          */
747         public void setStudyDAO(final StudyDAO studyDAO) {
748                 _studyDAO = studyDAO;
749         }
750
751         /**
752          * Get the relationDAO.
753          * 
754          * @return the relationDAO
755          */
756         public RelationDAO getRelationDAO() {
757                 return _relationDAO;
758         }
759
760         /**
761          * Set the relationDAO.
762          * 
763          * @param relationDAO
764          *            the relationDAO to set
765          */
766         public void setRelationDAO(final RelationDAO relationDAO) {
767                 _relationDAO = relationDAO;
768         }
769
770 }