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