]> SALOME platform Git repositories - tools/siman.git/blob - Workspace/Siman-Common/src/org/splat/service/DocumentServiceImpl.java
Salome HOME
Integration of ISR fixes:
[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         @Transactional
342         public boolean buildReferenceFrom(final Document aDoc,
343                         final ProjectElement scope, final Document lineage) {
344                 boolean res = (aDoc.getProgressState() == ProgressState.inWORK);
345                 if (res) {
346                         Study owner = scope.getOwnerStudy();
347                         Scenario context = null;
348                         if (scope instanceof Scenario) {
349                                 context = ((Scenario) scope);
350                         }
351                         aDoc.setDid(lineage.getDid());
352                         if (context != null
353                                         && (lineage.isVersioned() || owner.shares(lineage))) {
354                                 aDoc.setVersion(new Revision(aDoc.getVersion()).setBranch(
355                                                 context.getReference()).toString());
356                         }
357                 }
358                 return res;
359         }
360
361         /**
362          * Build a reference (document id) for the given document in the given study.
363          * 
364          * @param aDoc
365          *            the document to set set the new reference to
366          * @param scope
367          *            the study
368          * @return true if the new reference is set
369          */
370         @Transactional
371         public boolean buildReferenceFrom(final Document aDoc, final Study scope) {
372                 if (aDoc.getProgressState() != ProgressState.inWORK
373                                 && aDoc.getProgressState() != ProgressState.EXTERN) {
374                         return false;
375                 }
376                 DecimalFormat tostring = new DecimalFormat(Document.suformat);
377
378                 aDoc.setDid(aDoc.getDid().replace("%" + Document.suformat,
379                                 tostring.format(scope.getLastLocalIndex())));
380                 return true;
381         }
382
383         /**
384          * Demote a document.
385          * 
386          * @param aDoc
387          *            the document to demote
388          * @return true if demoting succeeded
389          */
390         @Transactional
391         public boolean demote(final Document aDoc) {
392                 ValidationStep torem;
393
394                 if (aDoc.getProgressState() == ProgressState.inCHECK) {
395                         aDoc.setProgressState(ProgressState.inDRAFT);
396                         torem = ValidationStep.REVIEW;
397                         // This operation must not change the version number of documents.
398                         // Consequently, inDRAFT documents may have a minor version number equal to zero.
399                 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
400                         aDoc.setProgressState(ProgressState.inWORK);
401                         torem = ValidationStep.PROMOTION;
402                 } else {
403                         return false;
404                 }
405                 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
406                                 .hasNext();) {
407                         Relation link = i.next();
408                         if (!(link instanceof StampRelation)) {
409                                 continue;
410                         }
411                         if (((StampRelation) link).getStampType() != torem) {
412                                 continue;
413                         }
414                         i.remove();
415                         break;
416                 }
417                 getDocumentDAO().update(aDoc);
418                 return true;
419         }
420
421         /**
422          * Promote a document.
423          * 
424          * @param aDoc
425          *            the document to promote
426          * @param stamp
427          *            the timestamp of the promotion
428          * @return true if promotion succeeded
429          */
430         @Transactional
431         public boolean promote(final Document aDoc, final Timestamp stamp) {
432                 ProgressState newstate = null;
433
434                 if (aDoc.getProgressState() == ProgressState.inWORK) {
435                         newstate = ProgressState.inDRAFT; // Promotion to being reviewed
436                 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
437                         newstate = ProgressState.inCHECK; // Promotion to approval
438                         Revision myvers = new Revision(aDoc.getVersion());
439                         if (myvers.isMinor()) {
440                                 aDoc.setVersion(myvers.incrementAs(newstate).toString());
441                                 // TODO: If my physical file is programatically editable, update its (property) version number
442                                 // ISSUE: What about attached files such as PDF if exist, should we remove them ?
443                         }
444                 } else if (aDoc.getProgressState() == ProgressState.inCHECK) {
445                         newstate = ProgressState.APPROVED;
446                 }
447                 aDoc.setProgressState(newstate);
448                 if (stamp != null) {
449                         // RKV: aDoc.addRelation(stamp.getContext());
450                         aDoc.getAllRelations().add(stamp.getContext());
451                 }
452                 getDocumentDAO().update(aDoc);
453                 return true;
454         }
455
456         /**
457          * Increments the reference count of this document following its publication in a Study step.
458          * 
459          * @param aDoc
460          *            the document to hold
461          * @see #release()
462          */
463         @Transactional
464         public void hold(final Document aDoc) {
465                 aDoc.setCountag(aDoc.getCountag() + 1);
466                 if (aDoc.isSaved()) {
467                         getDocumentDAO().merge(aDoc);
468                 }
469         }
470
471         /**
472          * Decrements the reference count of this document following the removal of a Publication from a Study step.
473          * 
474          * @param aDoc
475          *            the document to release
476          * @see #hold()
477          */
478         @Transactional
479         public void release(final Document aDoc) {
480                 aDoc.setCountag(aDoc.getCountag() - 1);
481                 if (aDoc.isSaved()) {
482                         getDocumentDAO().merge(aDoc);
483                 }
484         }
485
486         /**
487          * Rename a document.
488          * 
489          * @param aDoc
490          *            the document to rename
491          * @param title
492          *            the new document title
493          * @throws InvalidPropertyException
494          *             if the new title is empty
495          */
496         @Transactional
497         public void rename(final Document aDoc, final String title)
498                         throws InvalidPropertyException {
499                 if (title.length() == 0) {
500                         throw new InvalidPropertyException("name");
501                 }
502
503                 Calendar current = Calendar.getInstance();
504                 aDoc.setTitle(title);
505                 aDoc.setLastModificationDate(current.getTime()); // Today
506                 getDocumentDAO().update(aDoc);
507         }
508
509         /**
510          * Update a version of the given document.
511          * 
512          * @param aDoc
513          *            the document
514          * @param newvers
515          *            the new version
516          */
517         public void updateAs(final Document aDoc, final Revision newvers) {
518                 aDoc.setVersion(newvers.setBranch(aDoc.getVersion()).toString()); // Branch names are propagated by the versionning
519                 ProgressState newstate = ProgressState.inCHECK;
520                 if (newvers.isMinor()) {
521                         newstate = ProgressState.inWORK;
522                 }
523                 aDoc.setProgressState(null); // Just to tell updateAs(state) to not increment the version number
524                 updateAs(aDoc, newstate);
525         }
526
527         /**
528          * Update a state of the given document.
529          * 
530          * @param aDoc
531          *            the document
532          * @param state
533          *            the new state
534          */
535         @Transactional
536         public void updateAs(final Document aDoc, final ProgressState state) {
537                 Document previous = null;
538
539                 // Set of version number
540                         Revision myvers = new Revision(aDoc.getVersion());
541                         if (!myvers.isNull()) { // Versionning context
542                                 previous = aDoc.getPreviousVersion();
543                         }
544                         if (aDoc.getProgressState() != null) {
545                                 myvers.incrementAs(state); // Incrementation if the reversion number is not imposed
546                         }
547                         aDoc.setVersion(myvers.toString());
548
549                 // Update this document and the previous version, if exist
550                 if (previous != null) {
551                         previous.setHistory(previous.getHistory() + 1);
552                         getDocumentDAO().merge(previous);
553                 }
554                 aDoc.setProgressState(state);
555                 // RKV: getDocumentDAO().update(aDoc);
556         }
557
558         // protected void upgrade () {
559         // -------------------------
560         // if (this.state != ProgressState.inWORK) return;
561         //
562         // Calendar current = Calendar.getInstance();
563         // for (Iterator<Relation> i=getAllRelations().iterator(); i.hasNext();) {
564         // Relation link = i.next();
565         // if (!link.getClass().equals(UsesRelation.class)) continue;
566         //
567         // Document used = (Document)link.getTo();
568         // if (!used.isVersioned()) continue;
569         // TODO: Update the uses relation
570         // }
571         // this.promote();
572         // this.lasdate = current.getTime(); // Today
573         // Database.getSession().update(this);
574         //
575         // TODO: Promote documents using this one
576         // }
577
578         /**
579          * 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
580          * the study.
581          * 
582          * @param aType
583          *            the document type
584          * @return true if documents of this type are result of a study.
585          * @see #isStepResult()
586          * @see #isResultOf(org.splat.service.technical.ProjectSettingsServiceImpl.Step)
587          */
588         public boolean isStudyResult(final DocumentType aType) {
589                 List<ProjectSettingsService.Step> step = getProjectSettings()
590                                 .getAllSteps();
591                 ProjectSettingsService.Step lastep = step.get(step.size() - 1);
592                 return (aType.isResultOf(lastep));
593         }
594
595         /**
596          * Get document by its path.
597          * 
598          * @param path
599          *            the document path
600          * @return the document if found or null
601          */
602         @Transactional(readOnly = true)
603         public Document getDocumentByPath(String path) {
604                 String[] parse = path.split("'");
605
606                 path = parse[0];
607                 for (int i = 1; i < parse.length; i++) {
608                         path = path + "''" + parse[i];
609                 }
610                 Criterion aCondition = Restrictions.eq("path", path);
611                 return getDocumentDAO().findByCriteria(aCondition);
612         }
613
614         /**
615          * Get the studyService.
616          * 
617          * @return the studyService
618          */
619         public StudyService getStudyService() {
620                 return _studyService;
621         }
622
623         /**
624          * Set the studyService.
625          * 
626          * @param studyService
627          *            the studyService to set
628          */
629         public void setStudyService(final StudyService studyService) {
630                 _studyService = studyService;
631         }
632
633         /**
634          * Get project settings.
635          * 
636          * @return Project settings service
637          */
638         private ProjectSettingsService getProjectSettings() {
639                 return _projectSettings;
640         }
641
642         /**
643          * Set project settings service.
644          * 
645          * @param projectSettingsService
646          *            project settings service
647          */
648         public void setProjectSettings(
649                         final ProjectSettingsService projectSettingsService) {
650                 _projectSettings = projectSettingsService;
651         }
652
653         /**
654          * Get the documentDAO.
655          * 
656          * @return the documentDAO
657          */
658         public DocumentDAO getDocumentDAO() {
659                 return _documentDAO;
660         }
661
662         /**
663          * Set the documentDAO.
664          * 
665          * @param documentDAO
666          *            the documentDAO to set
667          */
668         public void setDocumentDAO(final DocumentDAO documentDAO) {
669                 _documentDAO = documentDAO;
670         }
671
672         /**
673          * Get the repositoryService.
674          * 
675          * @return the repositoryService
676          */
677         public RepositoryService getRepositoryService() {
678                 return _repositoryService;
679         }
680
681         /**
682          * Set the repositoryService.
683          * 
684          * @param repositoryService
685          *            the repositoryService to set
686          */
687         public void setRepositoryService(final RepositoryService repositoryService) {
688                 _repositoryService = repositoryService;
689         }
690
691         /**
692          * Get the documentTypeDAO.
693          * 
694          * @return the documentTypeDAO
695          */
696         public DocumentTypeDAO getDocumentTypeDAO() {
697                 return _documentTypeDAO;
698         }
699
700         /**
701          * Set the documentTypeDAO.
702          * 
703          * @param documentTypeDAO
704          *            the documentTypeDAO to set
705          */
706         public void setDocumentTypeDAO(final DocumentTypeDAO documentTypeDAO) {
707                 _documentTypeDAO = documentTypeDAO;
708         }
709
710         /**
711          * Get the fileDAO.
712          * 
713          * @return the fileDAO
714          */
715         public FileDAO getFileDAO() {
716                 return _fileDAO;
717         }
718
719         /**
720          * Set the fileDAO.
721          * 
722          * @param fileDAO
723          *            the fileDAO to set
724          */
725         public void setFileDAO(final FileDAO fileDAO) {
726                 _fileDAO = fileDAO;
727         }
728
729         /**
730          * Get the studyDAO.
731          * 
732          * @return the studyDAO
733          */
734         public StudyDAO getStudyDAO() {
735                 return _studyDAO;
736         }
737
738         /**
739          * Set the studyDAO.
740          * 
741          * @param studyDAO
742          *            the studyDAO to set
743          */
744         public void setStudyDAO(final StudyDAO studyDAO) {
745                 _studyDAO = studyDAO;
746         }
747
748         /**
749          * Get the relationDAO.
750          * 
751          * @return the relationDAO
752          */
753         public RelationDAO getRelationDAO() {
754                 return _relationDAO;
755         }
756
757         /**
758          * Set the relationDAO.
759          * 
760          * @param relationDAO
761          *            the relationDAO to set
762          */
763         public void setRelationDAO(final RelationDAO relationDAO) {
764                 _relationDAO = relationDAO;
765         }
766
767 }