1 /*****************************************************************************
5 * Creation date 06.10.2012
8 *****************************************************************************/
10 package org.splat.service;
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;
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.ProjectSettingsServiceImpl;
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;
51 * Document service implementation.
53 * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
56 public class DocumentServiceImpl implements DocumentService {
59 * Injected study service.
61 private StudyService _studyService;
63 * Injected project settings service.
65 private ProjectSettingsService _projectSettingsService;
67 * Injected repository service.
69 private RepositoryService _repositoryService;
71 * Injected document DAO.
73 private DocumentDAO _documentDAO;
75 * Injected document type DAO.
77 private DocumentTypeDAO _documentTypeDAO;
81 private FileDAO _fileDAO;
85 private StudyDAO _studyDAO;
90 * @see org.splat.service.DocumentService#selectDocument(long)
92 @Transactional(readOnly = true)
93 public Document selectDocument(long index) {
94 return getDocumentDAO().get(index);
100 * @see org.splat.service.DocumentService#selectDocument(java.lang.String, java.lang.String)
102 @Transactional(readOnly = true)
103 public Document selectDocument(String refid, String version) {
104 Criterion aCondition = Restrictions.and(Restrictions.eq("did", refid),
105 Restrictions.eq("version", version));
106 return getDocumentDAO().findByCriteria(aCondition);
112 * @see org.splat.service.DocumentService#generateDocumentId(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
115 public void generateDocumentId(Document aDoc, Properties dprop) {
117 if (dprop.getOwner() instanceof Study)
118 owner = (Study) dprop.getOwner();
120 owner = ((Scenario) dprop.getOwner()).getOwnerStudy();
122 // Synchronize the object with the current Hibernate session.
123 owner = getStudyDAO().get(owner.getIndex());
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 = ProjectSettingsServiceImpl
130 .getStep(aDoc.getStep());
131 aDoc.setDid(new StringBuffer(path).append(".%")
132 .append(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
139 aDoc.getFile().changePath(path);
143 * Generate encoded document file name according to the naming scheme from project settings.
149 * @return document reference name
151 private String generateEncodedName(Document aDoc, Study scope) {
152 StringBuffer encoding = new StringBuffer();
153 FileNaming scheme = getProjectSettings().getFileNamingScheme();
154 DecimalFormat tostring = new DecimalFormat(Document.suformat);
156 int number = getStudyService().generateLocalIndex(scope);
158 if (scheme == FileNaming.encoded) {
159 encoding.append(scope.getReference()).append(".")
160 .append(tostring.format(number));
161 } else { // title and (temporarily) asis
162 encoding.append(aDoc.getTitle()).append(".")
163 .append(tostring.format(number));
165 return encoding.toString();
169 * Get encoded root name for a document file.
177 private String getEncodedRootName(Document aDoc, Study scope) {
178 FileNaming scheme = getProjectSettings().getFileNamingScheme();
180 if (scheme == FileNaming.encoded)
181 return scope.getReference();
183 return aDoc.getTitle();
189 * @see org.splat.service.DocumentService#initialize(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
192 public void initialize(Document aDoc, Properties dprop)
193 throws MissedPropertyException, InvalidPropertyException,
194 NotApplicableException {
195 if (!aDoc.isUndefined())
196 throw new NotApplicableException(
197 "Cannot initialize an existing Document");
198 if (dprop.getName() == null)
199 throw new MissedPropertyException("name");
200 if (dprop.getName().length() == 0)
201 throw new InvalidPropertyException("name");
202 if (dprop.getOwner() == null)
203 throw new MissedPropertyException("owner");
204 // if (dprop.owner instanceof Study && !ProjectSettings.getStep(step).appliesTo(Study.class)) {
205 // throw new InvalidPropertyException("step");
207 aDoc.setTitle(dprop.getName());
208 aDoc.getFile().changePath(
213 getEncodedRootName(aDoc,
214 (Study) dprop.getOwner())));
215 if (aDoc.getHistory() == -1)
217 if (dprop.getDate() == null) {
218 Calendar current = Calendar.getInstance();
219 aDoc.setLastModificationDate(current.getTime()); // Today
221 aDoc.setLastModificationDate(dprop.getDate());
223 getDocumentDAO().update(aDoc);
229 * @see org.splat.service.DocumentService#getSaveDirectory(org.splat.dal.bo.som.Document)
231 public java.io.File getSaveDirectory(Document aDoc) {
232 String mypath = getRepositoryService().getRepositoryVaultPath()
233 + aDoc.getSourceFile().getRelativePath();
234 String[] table = mypath.split("/");
236 // Cutting the filename
237 StringBuffer path = new StringBuffer(table[0]);
238 for (int i = 1; i < table.length - 1; i++)
239 path = path.append("/").append(table[i]);
240 return new java.io.File(path.append("/").toString());
244 * Extract title and reference properties from the given file.
248 * @return the extracted properties
250 public Properties extractProperties(java.io.File file) {
251 Properties fprop = new Properties();
252 Reader tool = Toolbox.getReader(file);
256 value = tool.extractProperty("title");
258 fprop.setName(value);
260 value = tool.extractProperty("reference");
262 fprop.setReference(value);
263 } catch (Exception e) {
269 * Create "Converts" relation for the given document and the given format.
275 * @return the created "Converts" relation
277 public ConvertsRelation attach(Document aDoc, String format) {
278 return attach(aDoc, format, null);
282 * Create "Converts" relation for the given document, format and description.
289 * the description of the relation
290 * @return the created "Converts" relation
293 public ConvertsRelation attach(Document aDoc, String format,
294 String description) {
295 String path = aDoc.getRelativePath();
296 File export = new File(path + "." + format);
297 ConvertsRelation attach = new ConvertsRelation(aDoc, export,
300 // RKV Session session = Database.getSession();
301 // RKV session.save(export);
302 // RKV session.save(attach);
304 getFileDAO().create(export);
306 // RKV aDoc.addRelation(attach); // Updates this
307 aDoc.getAllRelations().add(attach); // Updates this //RKV
313 * Build a reference (document id) for the given document in the given study basing on the given original document.
316 * the document to set set the new reference to
320 * the original document
321 * @return true if the new reference is set
323 public boolean buildReferenceFrom(Document aDoc, ProjectElement scope,
325 if (aDoc.getProgressState() != ProgressState.inWORK)
328 Scenario context = null;
329 if (scope instanceof Study)
330 owner = (Study) scope;
332 context = ((Scenario) scope);
333 owner = context.getOwnerStudy();
335 aDoc.setDid(lineage.getDid());
336 if (context != null && (lineage.isVersioned() || owner.shares(lineage))) {
337 aDoc.setVersion(new Revision(aDoc.getVersion()).setBranch(
338 context.getReference()).toString());
344 * Build a reference (document id) for the given document in the given study.
347 * the document to set set the new reference to
350 * @return true if the new reference is set
352 public boolean buildReferenceFrom(Document aDoc, Study scope) {
353 if (aDoc.getProgressState() != ProgressState.inWORK
354 && aDoc.getProgressState() != ProgressState.EXTERN)
356 DecimalFormat tostring = new DecimalFormat(Document.suformat);
358 aDoc.setDid(aDoc.getDid().replace("%" + Document.suformat,
359 tostring.format(scope.getLastLocalIndex())));
367 * the document to demote
368 * @return true if demoting succeeded
371 public boolean demote(Document aDoc) {
372 ValidationStep torem;
374 if (aDoc.getProgressState() == ProgressState.inCHECK) {
375 aDoc.setProgressState(ProgressState.inDRAFT);
376 torem = ValidationStep.REVIEW;
377 // This operation must not change the version number of documents.
378 // Consequently, inDRAFT documents may have a minor version number equal to zero.
379 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
380 aDoc.setProgressState(ProgressState.inWORK);
381 torem = ValidationStep.PROMOTION;
385 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
387 Relation link = i.next();
388 if (!(link instanceof StampRelation))
390 if (((StampRelation) link).getStampType() != torem)
395 getDocumentDAO().update(aDoc);
400 * Promote a document.
403 * the document to promote
405 * the timestamp of the promotion
406 * @return true if promotion succeeded
409 public boolean promote(Document aDoc, Timestamp stamp) {
410 ProgressState newstate = null;
412 if (aDoc.getProgressState() == ProgressState.inWORK) {
413 newstate = ProgressState.inDRAFT; // Promotion to being reviewed
414 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
415 newstate = ProgressState.inCHECK; // Promotion to approval
416 Revision myvers = new Revision(aDoc.getVersion());
417 if (myvers.isMinor()) {
418 aDoc.setVersion(myvers.incrementAs(newstate).toString());
419 // TODO: If my physical file is programatically editable, update its (property) version number
420 // ISSUE: What about attached files such as PDF if exist, should we remove them ?
422 } else if (aDoc.getProgressState() == ProgressState.inCHECK) {
423 newstate = ProgressState.APPROVED;
425 aDoc.setProgressState(newstate);
427 // RKV: aDoc.addRelation(stamp.getContext());
428 aDoc.getAllRelations().add(stamp.getContext());
430 getDocumentDAO().update(aDoc);
435 * Increments the reference count of this document following its publication in a Study step.
438 * the document to hold
442 public void hold(Document aDoc) {
443 aDoc.setCountag(aDoc.getCountag() + 1);
444 if (aDoc.isSaved()) {
445 getDocumentDAO().update(aDoc);
450 * Decrements the reference count of this document following the removal of a Publication from a Study step.
453 * the document to release
457 public void release(Document aDoc) {
458 aDoc.setCountag(aDoc.getCountag() - 1);
459 if (aDoc.isSaved()) {
460 getDocumentDAO().merge(aDoc);
468 * the document to rename
470 * the new document title
471 * @throws InvalidPropertyException
472 * if the new title is empty
475 public void rename(Document aDoc, String title)
476 throws InvalidPropertyException {
477 if (title.length() == 0)
478 throw new InvalidPropertyException("name");
480 Calendar current = Calendar.getInstance();
481 aDoc.setTitle(title);
482 aDoc.setLastModificationDate(current.getTime()); // Today
483 getDocumentDAO().update(aDoc);
487 * Update a version of the given document.
494 public void updateAs(Document aDoc, Revision newvers) {
495 aDoc.setVersion(newvers.setBranch(aDoc.getVersion()).toString()); // Branch names are propagated by the versionning
496 ProgressState newstate = ProgressState.inCHECK;
497 if (newvers.isMinor())
498 newstate = ProgressState.inWORK;
499 aDoc.setProgressState(null); // Just to tell updateAs(state) to not increment the version number
500 updateAs(aDoc, newstate);
504 * Update a state of the given document.
512 public void updateAs(Document aDoc, ProgressState state) {
513 Document previous = null;
515 // Set of version number
516 if (state == ProgressState.EXTERN) {
517 if (aDoc.getProgressState() != ProgressState.EXTERN)
518 aDoc.setVersion(null); // Strange use-case...
520 Revision myvers = new Revision(aDoc.getVersion());
521 if (!myvers.isNull()) { // Versionning context
522 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
524 Relation link = i.next();
525 if (!link.getClass().equals(VersionsRelation.class))
527 previous = (Document) link.getTo(); // Versioned document
531 if (aDoc.getProgressState() != null)
532 myvers.incrementAs(state); // Incrementation if the reversion number is not imposed
533 aDoc.setVersion(myvers.toString());
535 // Update this document and the previous version, if exit
536 if (previous != null) {
537 previous.setHistory(previous.getHistory() + 1);
538 getDocumentDAO().merge(previous);
540 aDoc.setProgressState(state);
541 getDocumentDAO().update(aDoc);
544 // protected void upgrade () {
545 // -------------------------
546 // if (this.state != ProgressState.inWORK) return;
548 // Calendar current = Calendar.getInstance();
549 // for (Iterator<Relation> i=getAllRelations().iterator(); i.hasNext();) {
550 // Relation link = i.next();
551 // if (!link.getClass().equals(UsesRelation.class)) continue;
553 // Document used = (Document)link.getTo();
554 // if (!used.isVersioned()) continue;
555 // TODO: Update the uses relation
558 // this.lasdate = current.getTime(); // Today
559 // Database.getSession().update(this);
561 // TODO: Promote documents using this one
565 * 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
570 * @return true if documents of this type are result of a study.
571 * @see #isStepResult()
572 * @see #isResultOf(org.splat.service.technical.ProjectSettingsServiceImpl.Step)
574 public boolean isStudyResult(DocumentType aType) {
575 // -------------------------------
576 List<ProjectSettingsService.Step> step = getProjectSettings()
578 ProjectSettingsService.Step lastep = step.get(step.size() - 1);
579 return (aType.isResultOf(lastep));
583 * Get document by its path.
584 * @param path the document path
585 * @return the document if found or null
587 @Transactional(readOnly=true)
588 public Document getDocumentByPath(String path) {
589 String[] parse = path.split("'");
592 for (int i = 1; i < parse.length; i++) {
593 path = path + "''" + parse[i];
595 Criterion aCondition = Restrictions.eq("path", path);
596 return getDocumentDAO().findByCriteria(aCondition);
600 * Get the studyService.
602 * @return the studyService
604 public StudyService getStudyService() {
605 return _studyService;
609 * Set the studyService.
611 * @param studyService
612 * the studyService to set
614 public void setStudyService(StudyService studyService) {
615 _studyService = studyService;
619 * Get project settings.
621 * @return Project settings service
623 private ProjectSettingsService getProjectSettings() {
624 return _projectSettingsService;
628 * Set project settings service.
630 * @param projectSettingsService
631 * project settings service
633 public void setProjectSettings(ProjectSettingsService projectSettingsService) {
634 _projectSettingsService = projectSettingsService;
638 * Get the documentDAO.
640 * @return the documentDAO
642 public DocumentDAO getDocumentDAO() {
647 * Set the documentDAO.
650 * the documentDAO to set
652 public void setDocumentDAO(DocumentDAO documentDAO) {
653 _documentDAO = documentDAO;
657 * Get the repositoryService.
659 * @return the repositoryService
661 public RepositoryService getRepositoryService() {
662 return _repositoryService;
666 * Set the repositoryService.
668 * @param repositoryService
669 * the repositoryService to set
671 public void setRepositoryService(RepositoryService repositoryService) {
672 _repositoryService = repositoryService;
676 * Get the documentTypeDAO.
678 * @return the documentTypeDAO
680 public DocumentTypeDAO getDocumentTypeDAO() {
681 return _documentTypeDAO;
685 * Set the documentTypeDAO.
687 * @param documentTypeDAO
688 * the documentTypeDAO to set
690 public void setDocumentTypeDAO(DocumentTypeDAO documentTypeDAO) {
691 _documentTypeDAO = documentTypeDAO;
697 * @return the fileDAO
699 public FileDAO getFileDAO() {
709 public void setFileDAO(FileDAO fileDAO) {
715 * @return the studyDAO
717 public StudyDAO getStudyDAO() {
723 * @param studyDAO the studyDAO to set
725 public void setStudyDAO(StudyDAO studyDAO) {
726 _studyDAO = studyDAO;