]> SALOME platform Git repositories - tools/siman.git/blob - Workspace/Siman-Common/src/org/splat/service/DocumentServiceImpl.java
Salome HOME
Modifications done to respect PMD rules. Versioning a document is fixed. Validation...
[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                                                 continue;
547                                         }
548                                         previous = (Document) link.getTo(); // Versioned document
549                                         break;
550                                 }
551                         }
552                         if (aDoc.getProgressState() != null) {
553                                 myvers.incrementAs(state); // Incrementation if the reversion number is not imposed
554                         }
555                         aDoc.setVersion(myvers.toString());
556                 }
557                 // Update this document and the previous version, if exit
558                 if (previous != null) {
559                         previous.setHistory(previous.getHistory() + 1);
560                         getDocumentDAO().merge(previous);
561                 }
562                 aDoc.setProgressState(state);
563                 getDocumentDAO().update(aDoc);
564         }
565
566         // protected void upgrade () {
567         // -------------------------
568         // if (this.state != ProgressState.inWORK) return;
569         //
570         // Calendar current = Calendar.getInstance();
571         // for (Iterator<Relation> i=getAllRelations().iterator(); i.hasNext();) {
572         // Relation link = i.next();
573         // if (!link.getClass().equals(UsesRelation.class)) continue;
574         //
575         // Document used = (Document)link.getTo();
576         // if (!used.isVersioned()) continue;
577         // TODO: Update the uses relation
578         // }
579         // this.promote();
580         // this.lasdate = current.getTime(); // Today
581         // Database.getSession().update(this);
582         //
583         // TODO: Promote documents using this one
584         // }
585
586         /**
587          * 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
588          * the study.
589          * 
590          * @param aType
591          *            the document type
592          * @return true if documents of this type are result of a study.
593          * @see #isStepResult()
594          * @see #isResultOf(org.splat.service.technical.ProjectSettingsServiceImpl.Step)
595          */
596         public boolean isStudyResult(final DocumentType aType) {
597                 // -------------------------------
598                 List<ProjectSettingsService.Step> step = getProjectSettings()
599                                 .getAllSteps();
600                 ProjectSettingsService.Step lastep = step.get(step.size() - 1);
601                 return (aType.isResultOf(lastep));
602         }
603
604         /**
605          * Get document by its path.
606          * 
607          * @param path
608          *            the document path
609          * @return the document if found or null
610          */
611         @Transactional(readOnly = true)
612         public Document getDocumentByPath(String path) {
613                 String[] parse = path.split("'");
614
615                 path = parse[0];
616                 for (int i = 1; i < parse.length; i++) {
617                         path = path + "''" + parse[i];
618                 }
619                 Criterion aCondition = Restrictions.eq("path", path);
620                 return getDocumentDAO().findByCriteria(aCondition);
621         }
622
623         /**
624          * Get the studyService.
625          * 
626          * @return the studyService
627          */
628         public StudyService getStudyService() {
629                 return _studyService;
630         }
631
632         /**
633          * Set the studyService.
634          * 
635          * @param studyService
636          *            the studyService to set
637          */
638         public void setStudyService(final StudyService studyService) {
639                 _studyService = studyService;
640         }
641
642         /**
643          * Get project settings.
644          * 
645          * @return Project settings service
646          */
647         private ProjectSettingsService getProjectSettings() {
648                 return _projectSettings;
649         }
650
651         /**
652          * Set project settings service.
653          * 
654          * @param projectSettingsService
655          *            project settings service
656          */
657         public void setProjectSettings(
658                         final ProjectSettingsService projectSettingsService) {
659                 _projectSettings = projectSettingsService;
660         }
661
662         /**
663          * Get the documentDAO.
664          * 
665          * @return the documentDAO
666          */
667         public DocumentDAO getDocumentDAO() {
668                 return _documentDAO;
669         }
670
671         /**
672          * Set the documentDAO.
673          * 
674          * @param documentDAO
675          *            the documentDAO to set
676          */
677         public void setDocumentDAO(final DocumentDAO documentDAO) {
678                 _documentDAO = documentDAO;
679         }
680
681         /**
682          * Get the repositoryService.
683          * 
684          * @return the repositoryService
685          */
686         public RepositoryService getRepositoryService() {
687                 return _repositoryService;
688         }
689
690         /**
691          * Set the repositoryService.
692          * 
693          * @param repositoryService
694          *            the repositoryService to set
695          */
696         public void setRepositoryService(final RepositoryService repositoryService) {
697                 _repositoryService = repositoryService;
698         }
699
700         /**
701          * Get the documentTypeDAO.
702          * 
703          * @return the documentTypeDAO
704          */
705         public DocumentTypeDAO getDocumentTypeDAO() {
706                 return _documentTypeDAO;
707         }
708
709         /**
710          * Set the documentTypeDAO.
711          * 
712          * @param documentTypeDAO
713          *            the documentTypeDAO to set
714          */
715         public void setDocumentTypeDAO(final DocumentTypeDAO documentTypeDAO) {
716                 _documentTypeDAO = documentTypeDAO;
717         }
718
719         /**
720          * Get the fileDAO.
721          * 
722          * @return the fileDAO
723          */
724         public FileDAO getFileDAO() {
725                 return _fileDAO;
726         }
727
728         /**
729          * Set the fileDAO.
730          * 
731          * @param fileDAO
732          *            the fileDAO to set
733          */
734         public void setFileDAO(final FileDAO fileDAO) {
735                 _fileDAO = fileDAO;
736         }
737
738         /**
739          * Get the studyDAO.
740          * 
741          * @return the studyDAO
742          */
743         public StudyDAO getStudyDAO() {
744                 return _studyDAO;
745         }
746
747         /**
748          * Set the studyDAO.
749          * 
750          * @param studyDAO
751          *            the studyDAO to set
752          */
753         public void setStudyDAO(final StudyDAO studyDAO) {
754                 _studyDAO = studyDAO;
755         }
756
757 }