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