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