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