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.kernel.InvalidPropertyException;
38 import org.splat.kernel.MissedPropertyException;
39 import org.splat.kernel.NotApplicableException;
40 import org.splat.manox.Reader;
41 import org.splat.manox.Toolbox;
42 import org.splat.service.technical.ProjectSettingsService;
43 import org.splat.service.technical.ProjectSettingsServiceImpl;
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;
50 * Document service implementation.
52 * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
55 public class DocumentServiceImpl implements DocumentService {
58 * Injected study service.
60 private StudyService _studyService;
62 * Injected project settings service.
64 private ProjectSettingsService _projectSettingsService;
66 * Injected repository service.
68 private RepositoryService _repositoryService;
70 * Injected document DAO.
72 private DocumentDAO _documentDAO;
74 * Injected document type DAO.
76 private DocumentTypeDAO _documentTypeDAO;
80 private FileDAO _fileDAO;
85 * @see org.splat.service.DocumentService#selectDocument(long)
87 @Transactional(readOnly = true)
88 public Document selectDocument(long index) {
89 return getDocumentDAO().get(index);
95 * @see org.splat.service.DocumentService#selectDocument(java.lang.String, java.lang.String)
97 @Transactional(readOnly = true)
98 public Document selectDocument(String refid, String version) {
99 Criterion aCondition = Restrictions.and(Restrictions.eq("did", refid),
100 Restrictions.eq("version", version));
101 return getDocumentDAO().findByCriteria(aCondition);
107 * @see org.splat.service.DocumentService#generateDocumentId(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
109 public void generateDocumentId(Document aDoc, Properties dprop) {
111 if (dprop.getOwner() instanceof Study)
112 owner = (Study) dprop.getOwner();
114 owner = ((Scenario) dprop.getOwner()).getOwnerStudy();
116 SimpleDateFormat tostring = new SimpleDateFormat("yyyy");
117 String year = tostring.format(owner.getDate());
118 String filename = generateEncodedName(aDoc, owner);
119 String path = owner.getReference();
120 ProjectSettingsService.Step step = ProjectSettingsServiceImpl
121 .getStep(aDoc.getStep());
122 aDoc.setDid(new StringBuffer(path).append(".%")
123 .append(Document.suformat).toString()); // Document reference
124 path = new StringBuffer(year).append("/").append(path).append("/")
125 .append(step.getPath())
126 // File path relative to the repository vault
127 .append(filename).append(".")
128 .append(aDoc.getFile().getFormat()) // File name and extension
130 aDoc.getFile().changePath(path);
134 * Generate encoded document file name according to the naming scheme from project settings.
140 * @return document reference name
142 private String generateEncodedName(Document aDoc, Study scope) {
143 StringBuffer encoding = new StringBuffer();
144 FileNaming scheme = getProjectSettings().getFileNamingScheme();
145 DecimalFormat tostring = new DecimalFormat(Document.suformat);
147 int number = getStudyService().generateLocalIndex(scope);
149 if (scheme == FileNaming.encoded) {
150 encoding.append(scope.getReference()).append(".")
151 .append(tostring.format(number));
152 } else { // title and (temporarily) asis
153 encoding.append(aDoc.getTitle()).append(".")
154 .append(tostring.format(number));
156 return encoding.toString();
160 * Get encoded root name for a document file.
168 private String getEncodedRootName(Document aDoc, Study scope) {
169 FileNaming scheme = getProjectSettings().getFileNamingScheme();
171 if (scheme == FileNaming.encoded)
172 return scope.getReference();
174 return aDoc.getTitle();
180 * @see org.splat.service.DocumentService#initialize(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
183 public void initialize(Document aDoc, Properties dprop)
184 throws MissedPropertyException, InvalidPropertyException,
185 NotApplicableException {
186 if (!aDoc.isUndefined())
187 throw new NotApplicableException(
188 "Cannot initialize an existing Document");
189 if (dprop.getName() == null)
190 throw new MissedPropertyException("name");
191 if (dprop.getName().length() == 0)
192 throw new InvalidPropertyException("name");
193 if (dprop.getOwner() == null)
194 throw new MissedPropertyException("owner");
195 // if (dprop.owner instanceof Study && !ProjectSettings.getStep(step).appliesTo(Study.class)) {
196 // throw new InvalidPropertyException("step");
198 aDoc.setTitle(dprop.getName());
199 aDoc.getFile().changePath(
204 getEncodedRootName(aDoc,
205 (Study) dprop.getOwner())));
206 if (aDoc.getHistory() == -1)
208 if (dprop.getDate() == null) {
209 Calendar current = Calendar.getInstance();
210 aDoc.setLastModificationDate(current.getTime()); // Today
212 aDoc.setLastModificationDate(dprop.getDate());
214 getDocumentDAO().update(aDoc);
220 * @see org.splat.service.DocumentService#getSaveDirectory(org.splat.dal.bo.som.Document)
222 public java.io.File getSaveDirectory(Document aDoc) {
223 String mypath = getRepositoryService().getRepositoryVaultPath()
224 + aDoc.getSourceFile().getRelativePath();
225 String[] table = mypath.split("/");
227 // Cutting the filename
228 StringBuffer path = new StringBuffer(table[0]);
229 for (int i = 1; i < table.length - 1; i++)
230 path = path.append("/").append(table[i]);
231 return new java.io.File(path.append("/").toString());
235 * Extract title and reference properties from the given file.
239 * @return the extracted properties
241 public Properties extractProperties(java.io.File file) {
242 Properties fprop = new Properties();
243 Reader tool = Toolbox.getReader(file);
247 value = tool.extractProperty("title");
249 fprop.setName(value);
251 value = tool.extractProperty("reference");
253 fprop.setReference(value);
254 } catch (Exception e) {
260 * Create "Converts" relation for the given document and the given format.
266 * @return the created "Converts" relation
268 public ConvertsRelation attach(Document aDoc, String format) {
269 return attach(aDoc, format, null);
273 * Create "Converts" relation for the given document, format and description.
280 * the description of the relation
281 * @return the created "Converts" relation
284 public ConvertsRelation attach(Document aDoc, String format,
285 String description) {
286 String path = aDoc.getRelativePath();
287 File export = new File(path + "." + format);
288 ConvertsRelation attach = new ConvertsRelation(aDoc, export,
291 // RKV Session session = Database.getSession();
292 // RKV session.save(export);
293 // RKV session.save(attach);
295 getFileDAO().create(export);
297 // RKV aDoc.addRelation(attach); // Updates this
298 aDoc.getAllRelations().add(attach); // Updates this //RKV
304 * Build a reference (document id) for the given document in the given study basing on the given original document.
307 * the document to set set the new reference to
311 * the original document
312 * @return true if the new reference is set
314 public boolean buildReferenceFrom(Document aDoc, ProjectElement scope,
316 if (aDoc.getProgressState() != ProgressState.inWORK)
319 Scenario context = null;
320 if (scope instanceof Study)
321 owner = (Study) scope;
323 context = ((Scenario) scope);
324 owner = context.getOwnerStudy();
326 aDoc.setDid(lineage.getDid());
327 if (context != null && (lineage.isVersioned() || owner.shares(lineage))) {
328 aDoc.setVersion(new Revision(aDoc.getVersion()).setBranch(
329 context.getReference()).toString());
335 * Build a reference (document id) for the given document in the given study.
338 * the document to set set the new reference to
341 * @return true if the new reference is set
343 public boolean buildReferenceFrom(Document aDoc, Study scope) {
344 if (aDoc.getProgressState() != ProgressState.inWORK
345 && aDoc.getProgressState() != ProgressState.EXTERN)
347 DecimalFormat tostring = new DecimalFormat(Document.suformat);
349 aDoc.setDid(aDoc.getDid().replace("%" + Document.suformat,
350 tostring.format(scope.getLastLocalIndex())));
358 * the document to demote
359 * @return true if demoting succeeded
362 public boolean demote(Document aDoc) {
363 ValidationStep torem;
365 if (aDoc.getProgressState() == ProgressState.inCHECK) {
366 aDoc.setProgressState(ProgressState.inDRAFT);
367 torem = ValidationStep.REVIEW;
368 // This operation must not change the version number of documents.
369 // Consequently, inDRAFT documents may have a minor version number equal to zero.
370 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
371 aDoc.setProgressState(ProgressState.inWORK);
372 torem = ValidationStep.PROMOTION;
376 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
378 Relation link = i.next();
379 if (!(link instanceof StampRelation))
381 if (((StampRelation) link).getStampType() != torem)
386 getDocumentDAO().update(aDoc);
391 * Promote a document.
394 * the document to promote
396 * the timestamp of the promotion
397 * @return true if promotion succeeded
400 public boolean promote(Document aDoc, Timestamp stamp) {
401 ProgressState newstate = null;
403 if (aDoc.getProgressState() == ProgressState.inWORK) {
404 newstate = ProgressState.inDRAFT; // Promotion to being reviewed
405 } else if (aDoc.getProgressState() == ProgressState.inDRAFT) {
406 newstate = ProgressState.inCHECK; // Promotion to approval
407 Revision myvers = new Revision(aDoc.getVersion());
408 if (myvers.isMinor()) {
409 aDoc.setVersion(myvers.incrementAs(newstate).toString());
410 // TODO: If my physical file is programatically editable, update its (property) version number
411 // ISSUE: What about attached files such as PDF if exist, should we remove them ?
413 } else if (aDoc.getProgressState() == ProgressState.inCHECK) {
414 newstate = ProgressState.APPROVED;
416 aDoc.setProgressState(newstate);
418 // RKV: aDoc.addRelation(stamp.getContext());
419 aDoc.getAllRelations().add(stamp.getContext());
421 getDocumentDAO().update(aDoc);
426 * Increments the reference count of this document following its publication in a Study step.
429 * the document to hold
433 public void hold(Document aDoc) {
434 aDoc.setCountag(aDoc.getCountag() + 1);
435 if (aDoc.isSaved()) {
436 getDocumentDAO().update(aDoc);
441 * Decrements the reference count of this document following the removal of a Publication from a Study step.
444 * the document to release
448 public void release(Document aDoc) {
449 aDoc.setCountag(aDoc.getCountag() - 1);
450 if (aDoc.isSaved()) {
451 getDocumentDAO().update(aDoc);
459 * the document to rename
461 * the new document title
462 * @throws InvalidPropertyException
463 * if the new title is empty
466 public void rename(Document aDoc, String title)
467 throws InvalidPropertyException {
468 if (title.length() == 0)
469 throw new InvalidPropertyException("name");
471 Calendar current = Calendar.getInstance();
472 aDoc.setTitle(title);
473 aDoc.setLastModificationDate(current.getTime()); // Today
474 getDocumentDAO().update(aDoc);
478 * Update a version of the given document.
485 public void updateAs(Document aDoc, Revision newvers) {
486 aDoc.setVersion(newvers.setBranch(aDoc.getVersion()).toString()); // Branch names are propagated by the versionning
487 ProgressState newstate = ProgressState.inCHECK;
488 if (newvers.isMinor())
489 newstate = ProgressState.inWORK;
490 aDoc.setProgressState(null); // Just to tell updateAs(state) to not increment the version number
491 updateAs(aDoc, newstate);
495 * Update a state of the given document.
503 public void updateAs(Document aDoc, ProgressState state) {
504 Document previous = null;
506 // Set of version number
507 if (state == ProgressState.EXTERN) {
508 if (aDoc.getProgressState() != ProgressState.EXTERN)
509 aDoc.setVersion(null); // Strange use-case...
511 Revision myvers = new Revision(aDoc.getVersion());
512 if (!myvers.isNull()) { // Versionning context
513 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
515 Relation link = i.next();
516 if (!link.getClass().equals(VersionsRelation.class))
518 previous = (Document) link.getTo(); // Versioned document
522 if (aDoc.getProgressState() != null)
523 myvers.incrementAs(state); // Incrementation if the reversion number is not imposed
524 aDoc.setVersion(myvers.toString());
526 // Update this document and the previous version, if exit
527 if (previous != null) {
528 previous.setHistory(previous.getHistory() + 1);
529 getDocumentDAO().update(previous);
531 aDoc.setProgressState(state);
532 getDocumentDAO().update(aDoc);
535 // protected void upgrade () {
536 // -------------------------
537 // if (this.state != ProgressState.inWORK) return;
539 // Calendar current = Calendar.getInstance();
540 // for (Iterator<Relation> i=getAllRelations().iterator(); i.hasNext();) {
541 // Relation link = i.next();
542 // if (!link.getClass().equals(UsesRelation.class)) continue;
544 // Document used = (Document)link.getTo();
545 // if (!used.isVersioned()) continue;
546 // TODO: Update the uses relation
549 // this.lasdate = current.getTime(); // Today
550 // Database.getSession().update(this);
552 // TODO: Promote documents using this one
556 * 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
561 * @return true if documents of this type are result of a study.
562 * @see #isStepResult()
563 * @see #isResultOf(org.splat.service.technical.ProjectSettingsServiceImpl.Step)
565 public boolean isStudyResult(DocumentType aType) {
566 // -------------------------------
567 List<ProjectSettingsService.Step> step = getProjectSettings()
569 ProjectSettingsService.Step lastep = step.get(step.size() - 1);
570 return (aType.isResultOf(lastep));
574 * Get document by its path.
575 * @param path the document path
576 * @return the document if found or null
578 @Transactional(readOnly=true)
579 public Document getDocumentByPath(String path) {
580 String[] parse = path.split("'");
583 for (int i = 1; i < parse.length; i++) {
584 path = path + "''" + parse[i];
586 Criterion aCondition = Restrictions.eq("path", path);
587 return getDocumentDAO().findByCriteria(aCondition);
591 * Get the studyService.
593 * @return the studyService
595 public StudyService getStudyService() {
596 return _studyService;
600 * Set the studyService.
602 * @param studyService
603 * the studyService to set
605 public void setStudyService(StudyService studyService) {
606 _studyService = studyService;
610 * Get project settings.
612 * @return Project settings service
614 private ProjectSettingsService getProjectSettings() {
615 return _projectSettingsService;
619 * Set project settings service.
621 * @param projectSettingsService
622 * project settings service
624 public void setProjectSettings(ProjectSettingsService projectSettingsService) {
625 _projectSettingsService = projectSettingsService;
629 * Get the documentDAO.
631 * @return the documentDAO
633 public DocumentDAO getDocumentDAO() {
638 * Set the documentDAO.
641 * the documentDAO to set
643 public void setDocumentDAO(DocumentDAO documentDAO) {
644 _documentDAO = documentDAO;
648 * Get the repositoryService.
650 * @return the repositoryService
652 public RepositoryService getRepositoryService() {
653 return _repositoryService;
657 * Set the repositoryService.
659 * @param repositoryService
660 * the repositoryService to set
662 public void setRepositoryService(RepositoryService repositoryService) {
663 _repositoryService = repositoryService;
667 * Get the documentTypeDAO.
669 * @return the documentTypeDAO
671 public DocumentTypeDAO getDocumentTypeDAO() {
672 return _documentTypeDAO;
676 * Set the documentTypeDAO.
678 * @param documentTypeDAO
679 * the documentTypeDAO to set
681 public void setDocumentTypeDAO(DocumentTypeDAO documentTypeDAO) {
682 _documentTypeDAO = documentTypeDAO;
688 * @return the fileDAO
690 public FileDAO getFileDAO() {
700 public void setFileDAO(FileDAO fileDAO) {