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