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.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;
52 * Document service implementation.
54 * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
57 public class DocumentServiceImpl implements DocumentService {
60 * Injected study service.
62 private StudyService _studyService;
64 * Injected project settings service.
66 private ProjectSettingsService _projectSettingsService;
68 * Injected repository service.
70 private RepositoryService _repositoryService;
72 * Injected document DAO.
74 private DocumentDAO _documentDAO;
76 * Injected document type DAO.
78 private DocumentTypeDAO _documentTypeDAO;
82 private FileDAO _fileDAO;
87 * @see org.splat.service.DocumentService#selectDocument(long)
89 @Transactional(readOnly = true)
90 public Document selectDocument(long index) {
91 return getDocumentDAO().get(index);
97 * @see org.splat.service.DocumentService#selectDocument(java.lang.String, java.lang.String)
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);
109 * @see org.splat.service.DocumentService#generateDocumentId(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
111 public void generateDocumentId(Document aDoc, Properties dprop) {
113 if (dprop.getOwner() instanceof Study)
114 owner = (Study) dprop.getOwner();
116 owner = ((Scenario) dprop.getOwner()).getOwnerStudy();
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
132 aDoc.getFile().changePath(path);
136 * Generate encoded document file name according to the naming scheme from project settings.
142 * @return document reference name
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);
149 int number = getStudyService().generateLocalIndex(scope);
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));
158 return encoding.toString();
162 * Get encoded root name for a document file.
170 private String getEncodedRootName(Document aDoc, Study scope) {
171 FileNaming scheme = getProjectSettings().getFileNamingScheme();
173 if (scheme == FileNaming.encoded)
174 return scope.getReference();
176 return aDoc.getTitle();
182 * @see org.splat.service.DocumentService#initialize(org.splat.dal.bo.som.Document, org.splat.dal.bo.som.Document.Properties)
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");
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)
206 if (dprop.getDate() == null) {
207 Calendar current = Calendar.getInstance();
208 aDoc.setLastModificationDate(current.getTime()); // Today
210 aDoc.setLastModificationDate(dprop.getDate());
212 getDocumentDAO().update(aDoc);
218 * @see org.splat.service.DocumentService#getSaveDirectory(org.splat.dal.bo.som.Document)
220 public java.io.File getSaveDirectory(Document aDoc) {
221 String mypath = getRepositoryService().getRepositoryVaultPath()
222 + aDoc.getSourceFile().getRelativePath();
223 String[] table = mypath.split("/");
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());
233 * Extract title and reference properties from the given file.
237 * @return the extracted properties
239 public Properties extractProperties(java.io.File file) {
240 Properties fprop = new Properties();
241 Reader tool = Toolbox.getReader(file);
245 value = tool.extractProperty("title");
247 fprop.setName(value);
249 value = tool.extractProperty("reference");
251 fprop.setReference(value);
252 } catch (Exception e) {
258 * Create "Converts" relation for the given document and the given format.
264 * @return the created "Converts" relation
266 public ConvertsRelation attach(Document aDoc, String format) {
267 return attach(aDoc, format, null);
271 * Create "Converts" relation for the given document, format and description.
278 * the description of the relation
279 * @return the created "Converts" relation
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,
289 // RKV Session session = Database.getSession();
290 // RKV session.save(export);
291 // RKV session.save(attach);
293 getFileDAO().create(export);
295 // RKV aDoc.addRelation(attach); // Updates this
296 aDoc.getAllRelations().add(attach); // Updates this //RKV
302 * Build a reference (document id) for the given document in the given study basing on the given original document.
305 * the document to set set the new reference to
309 * the original document
310 * @return true if the new reference is set
312 public boolean buildReferenceFrom(Document aDoc, ProjectElement scope,
314 if (aDoc.getProgressState() != ProgressState.inWORK)
317 Scenario context = null;
318 if (scope instanceof Study)
319 owner = (Study) scope;
321 context = ((Scenario) scope);
322 owner = context.getOwnerStudy();
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());
333 * Build a reference (document id) for the given document in the given study.
336 * the document to set set the new reference to
339 * @return true if the new reference is set
341 public boolean buildReferenceFrom(Document aDoc, Study scope) {
342 if (aDoc.getProgressState() != ProgressState.inWORK
343 && aDoc.getProgressState() != ProgressState.EXTERN)
345 DecimalFormat tostring = new DecimalFormat(Document.suformat);
347 aDoc.setDid(aDoc.getDid().replace("%" + Document.suformat,
348 tostring.format(scope.getLastLocalIndex())));
356 * the document to demote
357 * @return true if demoting succeeded
360 public boolean demote(Document aDoc) {
361 ValidationStep torem;
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;
374 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
376 Relation link = i.next();
377 if (!(link instanceof StampRelation))
379 if (((StampRelation) link).getStampType() != torem)
384 getDocumentDAO().update(aDoc);
389 * Promote a document.
392 * the document to promote
394 * the timestamp of the promotion
395 * @return true if promotion succeeded
398 public boolean promote(Document aDoc, Timestamp stamp) {
399 ProgressState newstate = null;
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 ?
411 } else if (aDoc.getProgressState() == ProgressState.inCHECK) {
412 newstate = ProgressState.APPROVED;
414 aDoc.setProgressState(newstate);
416 // RKV: aDoc.addRelation(stamp.getContext());
417 aDoc.getAllRelations().add(stamp.getContext());
419 getDocumentDAO().update(aDoc);
424 * Increments the reference count of this document following its publication in a Study step.
427 * the document to hold
431 public void hold(Document aDoc) {
432 aDoc.setCountag(aDoc.getCountag() + 1);
433 if (aDoc.isSaved()) {
434 getDocumentDAO().update(aDoc);
439 * Decrements the reference count of this document following the removal of a Publication from a Study step.
442 * the document to release
446 public void release(Document aDoc) {
447 aDoc.setCountag(aDoc.getCountag() - 1);
448 if (aDoc.isSaved()) {
449 getDocumentDAO().update(aDoc);
457 * the document to rename
459 * the new document title
460 * @throws InvalidPropertyException
461 * if the new title is empty
464 public void rename(Document aDoc, String title)
465 throws InvalidPropertyException {
466 if (title.length() == 0)
467 throw new InvalidPropertyException("name");
469 Calendar current = Calendar.getInstance();
470 aDoc.setTitle(title);
471 aDoc.setLastModificationDate(current.getTime()); // Today
472 getDocumentDAO().update(aDoc);
476 * Update a version of the given document.
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);
493 * Update a state of the given document.
501 public void updateAs(Document aDoc, ProgressState state) {
502 Document previous = null;
504 // Set of version number
505 if (state == ProgressState.EXTERN) {
506 if (aDoc.getProgressState() != ProgressState.EXTERN)
507 aDoc.setVersion(null); // Strange use-case...
509 Revision myvers = new Revision(aDoc.getVersion());
510 if (!myvers.isNull()) { // Versionning context
511 for (Iterator<Relation> i = aDoc.getAllRelations().iterator(); i
513 Relation link = i.next();
514 if (!link.getClass().equals(VersionsRelation.class))
516 previous = (Document) link.getTo(); // Versioned document
520 if (aDoc.getProgressState() != null)
521 myvers.incrementAs(state); // Incrementation if the reversion number is not imposed
522 aDoc.setVersion(myvers.toString());
524 // Update this document and the previous version, if exit
525 if (previous != null) {
526 previous.setHistory(previous.getHistory() + 1);
527 getDocumentDAO().update(previous);
529 aDoc.setProgressState(state);
530 getDocumentDAO().update(aDoc);
533 // protected void upgrade () {
534 // -------------------------
535 // if (this.state != ProgressState.inWORK) return;
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;
542 // Document used = (Document)link.getTo();
543 // if (!used.isVersioned()) continue;
544 // TODO: Update the uses relation
547 // this.lasdate = current.getTime(); // Today
548 // Database.getSession().update(this);
550 // TODO: Promote documents using this one
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
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)
563 public boolean isStudyResult(DocumentType aType) {
564 // -------------------------------
565 List<ProjectSettingsService.Step> step = getProjectSettings()
567 ProjectSettingsService.Step lastep = step.get(step.size() - 1);
568 return (aType.isResultOf(lastep));
572 * Get the studyService.
574 * @return the studyService
576 public StudyService getStudyService() {
577 return _studyService;
581 * Set the studyService.
583 * @param studyService
584 * the studyService to set
586 public void setStudyService(StudyService studyService) {
587 _studyService = studyService;
591 * Get project settings.
593 * @return Project settings service
595 private ProjectSettingsService getProjectSettings() {
596 return _projectSettingsService;
600 * Set project settings service.
602 * @param projectSettingsService
603 * project settings service
605 public void setProjectSettings(ProjectSettingsService projectSettingsService) {
606 _projectSettingsService = projectSettingsService;
610 * Get the documentDAO.
612 * @return the documentDAO
614 public DocumentDAO getDocumentDAO() {
619 * Set the documentDAO.
622 * the documentDAO to set
624 public void setDocumentDAO(DocumentDAO documentDAO) {
625 _documentDAO = documentDAO;
629 * Get the repositoryService.
631 * @return the repositoryService
633 public RepositoryService getRepositoryService() {
634 return _repositoryService;
638 * Set the repositoryService.
640 * @param repositoryService
641 * the repositoryService to set
643 public void setRepositoryService(RepositoryService repositoryService) {
644 _repositoryService = repositoryService;
648 * Get the documentTypeDAO.
650 * @return the documentTypeDAO
652 public DocumentTypeDAO getDocumentTypeDAO() {
653 return _documentTypeDAO;
657 * Set the documentTypeDAO.
659 * @param documentTypeDAO
660 * the documentTypeDAO to set
662 public void setDocumentTypeDAO(DocumentTypeDAO documentTypeDAO) {
663 _documentTypeDAO = documentTypeDAO;
669 * @return the fileDAO
671 public FileDAO getFileDAO() {
681 public void setFileDAO(FileDAO fileDAO) {