1 /*****************************************************************************
5 * Creation date 06.10.2012
8 *****************************************************************************/
10 package org.splat.service;
13 import java.io.FileNotFoundException;
14 import java.io.IOException;
15 import java.util.ArrayList;
16 import java.util.Date;
17 import java.util.HashSet;
18 import java.util.Iterator;
19 import java.util.List;
21 import org.apache.log4j.Logger;
22 import org.splat.dal.bo.kernel.User;
23 import org.splat.dal.bo.som.ConvertsRelation;
24 import org.splat.dal.bo.som.Document;
25 import org.splat.dal.bo.som.DocumentType;
26 import org.splat.dal.bo.som.ProgressState;
27 import org.splat.dal.bo.som.ProjectElement;
28 import org.splat.dal.bo.som.Publication;
29 import org.splat.dal.bo.som.SimulationContext;
30 import org.splat.dal.bo.som.SimulationContextType;
31 import org.splat.dal.bo.som.Study;
32 import org.splat.dal.bo.som.Timestamp;
33 import org.splat.dal.bo.som.UsedByRelation;
34 import org.splat.dal.bo.som.ValidationCycle;
35 import org.splat.dal.bo.som.ValidationStep;
36 import org.splat.dal.dao.som.ProjectElementDAO;
37 import org.splat.dal.dao.som.PublicationDAO;
38 import org.splat.dal.dao.som.TimestampDAO;
39 import org.splat.kernel.InvalidPropertyException;
40 import org.splat.kernel.MismatchException;
41 import org.splat.kernel.MissedPropertyException;
42 import org.splat.kernel.MultiplyDefinedException;
43 import org.splat.kernel.NotApplicableException;
44 import org.splat.manox.Reader;
45 import org.splat.manox.Toolbox;
46 import org.splat.service.technical.RepositoryService;
47 import org.splat.som.DocumentRights;
48 import org.splat.som.Revision;
49 import org.splat.som.Step;
50 import org.springframework.transaction.annotation.Transactional;
53 * Publication service implementation.
55 * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
57 public class PublicationServiceImpl implements PublicationService {
60 * Logger for this class.
62 protected final static Logger LOG = Logger
63 .getLogger(PublicationServiceImpl.class);
66 * Injected study service.
68 private StudyService _studyService;
70 * Injected step service.
72 private StepService _stepService;
74 * Injected document service.
76 private DocumentService _documentService;
78 * Injected project element service.
80 private ProjectElementService _projectElementService;
82 * Injected simulation context service.
84 private SimulationContextService _simulationContextService;
86 * Injected publication DAO.
88 private PublicationDAO _publicationDAO;
90 * Injected timestamp DAO.
92 private TimestampDAO _timestampDAO;
94 * Injected project element DAO.
96 private ProjectElementDAO _projectElementDAO;
98 * Injected repository service.
100 private RepositoryService _repositoryService;
105 * @see org.splat.service.PublicationService#copy(org.splat.dal.bo.som.Publication, org.splat.dal.bo.som.ProjectElement)
107 public Publication copy(final Publication aPublication, final ProjectElement publisher) {
108 Publication copy = new Publication();
109 copy.setValue(aPublication.value());
110 copy.setStep(aPublication.getStep()); // May not be initialized yet
111 copy.setOwner(publisher);
112 copy.setIsnew(aPublication.getIsnew());
113 if (!copy.getOwnerStudy().equals(aPublication.getOwnerStudy())) {
114 copy.setIsnew('N'); // The referenced document is not new for the given study
121 * @see org.splat.service.PublicationService#versionDocument(org.splat.som.Step, org.splat.dal.bo.kernel.User, java.lang.String, long, java.lang.String, java.lang.String, org.splat.dal.bo.som.ProgressState, java.util.Date, java.lang.String[], long[])
124 public void versionDocument(final Step step, final User user,
125 final String filename, final long docIndex, final String docver,
126 final String summary, final ProgressState state, final Date date,
127 final String[] docuses, final long[] docusedby)
128 throws MissedPropertyException, InvalidPropertyException,
129 MultiplyDefinedException, IOException, MismatchException,
130 NotApplicableException, InterruptedException {
131 File updir = getRepositoryService().getDownloadDirectory(user);
132 File upfile = new File(updir.getPath() + "/" + filename);
134 // Versioning of the document
135 Document.Properties dprop = new Document.Properties();
136 Publication current = step.getDocument(docIndex);
139 if ((docver.length() != 0) && // Importation of a not foreign document
143 next = getStepService().versionDocument(step, current,
144 dprop.setAuthor(user).setDescription(summary));
145 updir = next.getSourceFile().asFile();
146 if (LOG.isInfoEnabled()) {
147 LOG.info("Moving \"" + upfile.getName() + "\" to \""
148 + updir.getPath() + "\".");
150 upfile.renameTo(updir);
153 if (docver.length() == 0) { // Importation of a foreign document
154 saveAs(next, state); // May throw FileNotFound if rename was not done
156 saveAs(next, new Revision(docver));
158 } catch (FileNotFoundException saverror) {
160 LOG.info("Waiting for the file.");
161 upfile.renameTo(updir);
164 // TODO: Remove current document details from the contents of open study
166 // Creation of uses relations
167 updateRelations(current, next, docuses, docusedby);
171 * Update relations after creation of a new document version.
174 * the current version
178 * ids of used documents
180 * ids of documents used by the versioned one.
182 private void updateRelations(final Publication current,
183 final Publication next, final String[] docuses,
184 final long[] docusedby) {
185 if (docuses != null) {
186 for (int i = 0; i < docuses.length; i++) {
187 Long index = Long.valueOf(docuses[i].trim());
188 Publication used = getPublicationDAO().get(index);// RKV: getPublication(index, steps);
189 next.addDependency(used);
192 // Outdating impacted document
193 HashSet<Long> compatible = new HashSet<Long>();
194 if (docusedby != null) {
195 for (int i = 0; i < docusedby.length; i++) {
196 compatible.add(docusedby[i]);
199 List<Publication> relist = current.getRelations(UsedByRelation.class);
200 for (Iterator<Publication> i = relist.iterator(); i.hasNext();) {
201 Publication using = i.next();
202 if (!compatible.contains(using.getIndex())) {
208 /* protected Publication getPublication(int index, List<Step> steps) {
209 for (Iterator<Step> i = steps.iterator(); i.hasNext();) {
210 List<Publication> published = i.next().getAllDocuments();
211 for (Iterator<Publication> j = published.iterator(); j.hasNext();) {
212 Publication found = j.next(); // In a given study step,
213 if (found.value().getIndex() == index)
214 return found; // there is only one publication of a given document
223 * @see org.splat.service.PublicationService#approve(org.splat.dal.bo.som.Publication, java.util.Date)
226 public Timestamp approve(final Publication aPublication, final Date adate) {
227 Timestamp res = null;
228 if (!(aPublication.isOutdated() || (aPublication.value().getProgressState() != ProgressState.inCHECK))) {
229 DocumentType type = aPublication.value().getType();
230 Study owner = aPublication.getOwnerStudy();
231 ValidationCycle cycle = getStudyService().getValidationCycleOf(owner,
233 User approver = cycle.getActor(ValidationStep.APPROVAL);
234 Timestamp stamp = new Timestamp(ValidationStep.APPROVAL, aPublication
235 .value(), approver, adate);
236 getTimestampDAO().create(stamp);
238 if (getDocumentService().promote(aPublication.value(), stamp)) {
240 if (getDocumentService().isStudyResult(type)
241 && owner.getProgressState() == ProgressState.inCHECK) {
242 getStudyService().promote(owner);
246 return res; // Hoping that promotion of the study succeeded
252 * @see org.splat.service.PublicationService#demote(org.splat.dal.bo.som.Publication)
255 public boolean demote(final Publication aPublication) {
257 DocumentType type = aPublication.value().getType();
258 Study owner = aPublication.getOwnerStudy();
260 if (aPublication.value().getProgressState() == ProgressState.inCHECK) {
261 ValidationCycle cycle = getStudyService().getValidationCycleOf(
263 if (cycle.enables(ValidationStep.REVIEW)) {
264 res = getDocumentService().demote(aPublication.value());
266 res = getDocumentService().demote(aPublication.value());
268 getDocumentService().demote(aPublication.value());
271 } else if (aPublication.value().getProgressState() == ProgressState.inDRAFT) {
272 res = getDocumentService().demote(aPublication.value());
274 if (res && getDocumentService().isStudyResult(type)
275 && owner.getProgressState() != ProgressState.inWORK) {
276 getStudyService().demote(owner);
284 * @see org.splat.service.PublicationService#invalidate(org.splat.dal.bo.som.Publication)
287 public boolean invalidate(final Publication aPublication) {
289 if ((aPublication.value().getProgressState() == ProgressState.inCHECK)
290 && getDocumentService().demote(aPublication.value())) {
291 DocumentType type = aPublication.value().getType();
292 Study owner = aPublication.getOwnerStudy();
293 if (getDocumentService().isStudyResult(type)
294 && owner.getProgressState() == ProgressState.inCHECK) {
295 getStudyService().demote(owner);
305 * @see org.splat.service.PublicationService#promote(org.splat.dal.bo.som.Publication, java.util.Date)
308 public Timestamp promote(final Publication aPublication, final Date pdate) {
309 Timestamp res = null;
310 if ((!aPublication.isOutdated())
311 && (aPublication.value().getProgressState() == ProgressState.inWORK)) {
312 DocumentType type = aPublication.value().getType();
313 Study owner = aPublication.getOwnerStudy();
314 ValidationCycle cycle = getStudyService().getValidationCycleOf(
316 User promoter = cycle.getActor(ValidationStep.PROMOTION);
317 if (promoter == null) {
318 promoter = getInvolvedStep(aPublication).getActor();
320 if (promoter == null) {
321 promoter = owner.getAuthor();
323 Timestamp stamp = new Timestamp(ValidationStep.PROMOTION,
324 aPublication.value(), promoter, pdate);
325 getTimestampDAO().create(stamp);
327 if (getDocumentService().promote(aPublication.value(), stamp)) {
329 if (!cycle.enables(ValidationStep.REVIEW)) {
330 getDocumentService().promote(aPublication.value(), null);
332 if (getDocumentService().isStudyResult(type)
333 && owner.getProgressState() == ProgressState.inWORK) {
334 getStudyService().promote(owner);
338 return res; // Hoping that promotion of the study succeeded
344 * @see org.splat.service.PublicationService#review(org.splat.dal.bo.som.Publication, java.util.Date)
347 public Timestamp review(final Publication aPublication, final Date rdate) {
348 Timestamp res = null;
349 if (!aPublication.isOutdated()
350 && !(aPublication.value().getProgressState() != ProgressState.inDRAFT)) {
352 DocumentType type = aPublication.value().getType();
353 Study owner = aPublication.getOwnerStudy();
354 ValidationCycle cycle = getStudyService().getValidationCycleOf(
356 User reviewer = cycle.getActor(ValidationStep.REVIEW);
357 Timestamp stamp = new Timestamp(ValidationStep.REVIEW, aPublication
358 .value(), reviewer, rdate);
359 getTimestampDAO().create(stamp);
361 if (getDocumentService().promote(aPublication.value(), stamp)) {
363 if (getDocumentService().isStudyResult(type)
364 && owner.getProgressState() == ProgressState.inDRAFT) {
365 getStudyService().promote(owner);
369 return res; // Hoping that promotion of the study succeeded
375 * @see org.splat.service.PublicationService#saveAs(org.splat.dal.bo.som.Publication, org.splat.som.Revision)
380 public void saveAs(final Publication aPublication, final Revision newvers)
381 throws FileNotFoundException, NotApplicableException {
382 if (aPublication.value().isUndefined()) {
383 throw new NotApplicableException(
384 "Cannot save a Publication object refering an undefined Document");
386 if (!aPublication.value().getSourceFile().exists()) {
387 throw new FileNotFoundException();
390 getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based) hascode
391 getDocumentService().updateAs(aPublication.value(), newvers); // May change the branch name of given revision
392 updateOwner(aPublication);
398 * @see org.splat.service.PublicationService#saveAs(org.splat.dal.bo.som.Publication, org.splat.dal.bo.som.ProgressState)
401 public void saveAs(final Publication aPublication, final ProgressState state)
402 throws FileNotFoundException, NotApplicableException {
403 if (aPublication.value().isUndefined()) {
404 throw new NotApplicableException(
405 "Cannot save a Publication object refering an undefined Document");
407 if (!aPublication.value().getSourceFile().exists()) {
408 throw new FileNotFoundException();
411 if (state == ProgressState.inWORK || state == ProgressState.EXTERN) {
412 getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based)
414 getDocumentService().updateAs(aPublication.value(), state);
416 DocumentType mytype = aPublication.value().getType();
417 Study owner = aPublication.getOwnerStudy();
418 ValidationCycle cycle = getStudyService().getValidationCycleOf(
420 boolean review = cycle.enables(ValidationStep.REVIEW);
421 if (!(state == ProgressState.inDRAFT && review)
422 && !(state == ProgressState.inCHECK && !review)) {
423 throw new NotApplicableException(
424 "Cannot save a result document in " + state.toString()
427 getPublicationDAO().create(aPublication); // Must be done before updating the study in order to fix this final (rid-based)
429 getDocumentService().updateAs(aPublication.value(),
430 ProgressState.inWORK);
432 promote(aPublication, aPublication.value()
433 .getLastModificationDate()); // Promotes to the appropriate state in accordance to the validation cycle
435 updateOwner(aPublication);
439 * Update an owner of the publication.
441 * @param aPublication
442 * the document publication
445 private void updateOwner(final Publication aPublication) {
446 Step step = getInvolvedStep(aPublication);
448 // Update of involved step
449 Document previous = aPublication.value().getPreviousVersion();
450 if (previous != null) {
451 Publication oldoc = step.getDocument(previous.getIndex());
452 boolean done = getStepService().remove(step, oldoc); // Decrements the configuration tag count of document
454 oldoc = getPublicationDAO().merge(oldoc); //RKV: to avoid: NonUniqueObjectException: a different object with the same identifier value was already associated with the session
455 //RKV: use delete-orphan by removing from project element, see StepService.remove
456 //RKV: getPublicationDAO().delete(oldoc); // WARNING: Potential problem because it's not automatically done as orphan object
459 getStepService().add(step, aPublication); // Increments the configuration tag count of document
461 // Import the document properties and update of the study
462 forwardProperties(aPublication, aPublication.value().getSourceFile()
464 getProjectElementDAO().merge(aPublication.getOwner());
468 * Propagate simulation contexts from the given config file to the publication's owner (study or step).
470 * @param aPublication
471 * the document publication
477 private void forwardProperties(final Publication aPublication,
478 final java.io.File from, final Step to) {
479 Reader tool = Toolbox.getReader(from);
480 if (tool != null) { // Properties extractor available for this type of document
481 SimulationContextType.Properties sprop = new SimulationContextType.Properties()
482 .setStep(to.getStep()).setProgressState(
483 ProgressState.APPROVED);
484 List<SimulationContextType> contype = getSimulationContextService()
485 .selectTypesWhere(sprop);
486 if (!contype.isEmpty()) { // There is an approved property type configured at this step
488 SimulationContext.Properties cprop = new SimulationContext.Properties();
489 List<SimulationContext> context = to.getAllSimulationContexts();
491 context = new ArrayList<SimulationContext>(context.size());
492 context.addAll(to.getAllSimulationContexts());
493 cprop.disableCheck();
494 for (Iterator<SimulationContextType> i = contype.iterator(); i
496 SimulationContextType property = i.next();
497 boolean isFound = false;
498 for (Iterator<SimulationContext> j = context.iterator(); j
500 SimulationContext existing = j.next();
501 isFound = existing.getType().equals(property);
503 // Forget this property as it is already set
509 String value = tool.extractProperty(property
512 continue; // Property not defined into the document
515 cprop.setType(property).setValue(value);
516 if (aPublication.getOwner() instanceof Study) {
517 getStudyService().addProjectContext(
518 (Study) aPublication.getOwner(), cprop); // Re-indexes knowledges and the study
521 .addSimulationContext(to, cprop); // Re-indexes knowledges only
523 } catch (Exception e) {
533 * Returns the study Step into which the document version referenced by this publication has been published.
535 * @param aPublication
536 * the document publication
537 * @return the study step where the document is published
539 public Step getInvolvedStep(final Publication aPublication) {
540 if (aPublication.getStep() == null) {
541 Step[] step = getProjectElementService().getSteps(
542 aPublication.getOwner());
543 for (int i = 0; i < step.length; i++) {
544 aPublication.setStep(step[i]); // The involved step necessarily exists
545 if (aPublication.value().isInto(aPublication.getStep())) {
550 return aPublication.getStep();
554 * Undo the out-date operation.
556 * @param aPublication
558 * @return true if the acceptance succeeds
560 * @see DocumentRights#canAccept()
563 public boolean actualize(final Publication aPublication) {
564 boolean res = aPublication.isOutdated();
566 aPublication.setIsnew('Y');
567 getPublicationDAO().update(aPublication);
573 * Out-dates this publication and recursively all publications using this one. Typically, a publication is out-dated when modifying a
574 * document to which it depends.
576 * @param aPublication
579 * @see #getProgressState()
582 public void outdate(final Publication aPublication) {
583 if (aPublication.isOutdated()) {
587 List<Publication> relist = aPublication
588 .getRelations(UsedByRelation.class);
589 for (Iterator<Publication> i = relist.iterator(); i.hasNext();) {
592 aPublication.setIsnew('O');
593 getPublicationDAO().update(aPublication);
597 * Create "Converts" relation for the given document publication and format.
599 * @param aPublication
600 * the document publication
603 * @return the created "Converts" relation
605 public ConvertsRelation attach(final Publication aPublication, final String format) {
606 return getDocumentService().attach(aPublication.value(), format);
610 * Create "Converts" relation for the given document publication, format and description.
612 * @param aPublication
613 * the document publication
617 * the description of the relation
618 * @return the created "Converts" relation
620 public ConvertsRelation attach(final Publication aPublication, final String format,
621 final String description) {
622 return getDocumentService().attach(aPublication.value(), format,
627 * Rename the published document.
629 * @param aPublication
630 * the publication of the document
632 * the new document title
633 * @throws InvalidPropertyException
634 * if the new title is empty
636 public void rename(final Publication aPublication, final String title)
637 throws InvalidPropertyException {
638 getDocumentService().rename(aPublication.value(), title);
642 * Get the projectElementService.
644 * @return the projectElementService
646 public ProjectElementService getProjectElementService() {
647 return _projectElementService;
651 * Set the projectElementService.
653 * @param projectElementService
654 * the projectElementService to set
656 public void setProjectElementService(
657 final ProjectElementService projectElementService) {
658 _projectElementService = projectElementService;
662 * Get the simulationContextService.
664 * @return the simulationContextService
666 public SimulationContextService getSimulationContextService() {
667 return _simulationContextService;
671 * Set the simulationContextService.
673 * @param simulationContextService
674 * the simulationContextService to set
676 public void setSimulationContextService(
677 final SimulationContextService simulationContextService) {
678 _simulationContextService = simulationContextService;
682 * Get the studyService.
684 * @return the studyService
686 public StudyService getStudyService() {
687 return _studyService;
691 * Set the studyService.
693 * @param studyService
694 * the studyService to set
696 public void setStudyService(final StudyService studyService) {
697 _studyService = studyService;
701 * Get the stepService.
703 * @return the stepService
705 public StepService getStepService() {
710 * Set the stepService.
713 * the stepService to set
715 public void setStepService(final StepService stepService) {
716 _stepService = stepService;
720 * Get the documentService.
722 * @return the documentService
724 public DocumentService getDocumentService() {
725 return _documentService;
729 * Set the documentService.
731 * @param documentService
732 * the documentService to set
734 public void setDocumentService(final DocumentService documentService) {
735 _documentService = documentService;
739 * Get the publicationDAO.
741 * @return the publicationDAO
743 public PublicationDAO getPublicationDAO() {
744 return _publicationDAO;
748 * Set the publicationDAO.
750 * @param publicationDAO
751 * the publicationDAO to set
753 public void setPublicationDAO(final PublicationDAO publicationDAO) {
754 _publicationDAO = publicationDAO;
758 * Get the projectElementDAO.
760 * @return the projectElementDAO
762 public ProjectElementDAO getProjectElementDAO() {
763 return _projectElementDAO;
767 * Set the projectElementDAO.
769 * @param projectElementDAO
770 * the projectElementDAO to set
772 public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
773 _projectElementDAO = projectElementDAO;
777 * Get the repositoryService.
779 * @return the repositoryService
781 public RepositoryService getRepositoryService() {
782 return _repositoryService;
786 * Set the repositoryService.
788 * @param repositoryService
789 * the repositoryService to set
791 public void setRepositoryService(final RepositoryService repositoryService) {
792 _repositoryService = repositoryService;
796 * Get the timestampDAO.
797 * @return the timestampDAO
799 public TimestampDAO getTimestampDAO() {
800 return _timestampDAO;
804 * Set the timestampDAO.
805 * @param timestampDAO the timestampDAO to set
807 public void setTimestampDAO(final TimestampDAO timestampDAO) {
808 _timestampDAO = timestampDAO;