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 getPublicationDAO().delete(oldoc); // WARNING: Potential problem because it's not automatically done as orphan object
458 getStepService().add(step, aPublication); // Increments the configuration tag count of document
460 // Import the document properties and update of the study
461 forwardProperties(aPublication, aPublication.value().getSourceFile()
463 getProjectElementDAO().merge(aPublication.getOwner());
467 * Propagate simulation contexts from the given config file to the publication's owner (study or step).
469 * @param aPublication
470 * the document publication
476 private void forwardProperties(final Publication aPublication,
477 final java.io.File from, final Step to) {
478 Reader tool = Toolbox.getReader(from);
479 if (tool != null) { // Properties extractor available for this type of document
480 SimulationContextType.Properties sprop = new SimulationContextType.Properties()
481 .setStep(to.getStep()).setProgressState(
482 ProgressState.APPROVED);
483 List<SimulationContextType> contype = getSimulationContextService()
484 .selectTypesWhere(sprop);
485 if (!contype.isEmpty()) { // There is an approved property type configured at this step
487 SimulationContext.Properties cprop = new SimulationContext.Properties();
488 List<SimulationContext> context = to.getAllSimulationContexts();
490 context = new ArrayList<SimulationContext>(context.size());
491 context.addAll(to.getAllSimulationContexts());
492 cprop.disableCheck();
493 for (Iterator<SimulationContextType> i = contype.iterator(); i
495 SimulationContextType property = i.next();
496 boolean isFound = false;
497 for (Iterator<SimulationContext> j = context.iterator(); j
499 SimulationContext existing = j.next();
500 isFound = existing.getType().equals(property);
502 // Forget this property as it is already set
508 String value = tool.extractProperty(property
511 continue; // Property not defined into the document
514 cprop.setType(property).setValue(value);
515 if (aPublication.getOwner() instanceof Study) {
516 getStudyService().addProjectContext(
517 (Study) aPublication.getOwner(), cprop); // Re-indexes knowledges and the study
520 .addSimulationContext(to, cprop); // Re-indexes knowledges only
522 } catch (Exception e) {
532 * Returns the study Step into which the document version referenced by this publication has been published.
534 * @param aPublication
535 * the document publication
536 * @return the study step where the document is published
538 public Step getInvolvedStep(final Publication aPublication) {
539 if (aPublication.getStep() == null) {
540 Step[] step = getProjectElementService().getSteps(
541 aPublication.getOwner());
542 for (int i = 0; i < step.length; i++) {
543 aPublication.setStep(step[i]); // The involved step necessarily exists
544 if (aPublication.value().isInto(aPublication.getStep())) {
549 return aPublication.getStep();
553 * Undo the out-date operation.
555 * @param aPublication
557 * @return true if the acceptance succeeds
559 * @see DocumentRights#canAccept()
562 public boolean actualize(final Publication aPublication) {
563 boolean res = aPublication.isOutdated();
565 aPublication.setIsnew('Y');
566 getPublicationDAO().update(aPublication);
572 * Out-dates this publication and recursively all publications using this one. Typically, a publication is out-dated when modifying a
573 * document to which it depends.
575 * @param aPublication
578 * @see #getProgressState()
581 public void outdate(final Publication aPublication) {
582 if (aPublication.isOutdated()) {
586 List<Publication> relist = aPublication
587 .getRelations(UsedByRelation.class);
588 for (Iterator<Publication> i = relist.iterator(); i.hasNext();) {
591 aPublication.setIsnew('O');
592 getPublicationDAO().update(aPublication);
596 * Create "Converts" relation for the given document publication and format.
598 * @param aPublication
599 * the document publication
602 * @return the created "Converts" relation
604 public ConvertsRelation attach(final Publication aPublication, final String format) {
605 return getDocumentService().attach(aPublication.value(), format);
609 * Create "Converts" relation for the given document publication, format and description.
611 * @param aPublication
612 * the document publication
616 * the description of the relation
617 * @return the created "Converts" relation
619 public ConvertsRelation attach(final Publication aPublication, final String format,
620 final String description) {
621 return getDocumentService().attach(aPublication.value(), format,
626 * Rename the published document.
628 * @param aPublication
629 * the publication of the document
631 * the new document title
632 * @throws InvalidPropertyException
633 * if the new title is empty
635 public void rename(final Publication aPublication, final String title)
636 throws InvalidPropertyException {
637 getDocumentService().rename(aPublication.value(), title);
641 * Get the projectElementService.
643 * @return the projectElementService
645 public ProjectElementService getProjectElementService() {
646 return _projectElementService;
650 * Set the projectElementService.
652 * @param projectElementService
653 * the projectElementService to set
655 public void setProjectElementService(
656 final ProjectElementService projectElementService) {
657 _projectElementService = projectElementService;
661 * Get the simulationContextService.
663 * @return the simulationContextService
665 public SimulationContextService getSimulationContextService() {
666 return _simulationContextService;
670 * Set the simulationContextService.
672 * @param simulationContextService
673 * the simulationContextService to set
675 public void setSimulationContextService(
676 final SimulationContextService simulationContextService) {
677 _simulationContextService = simulationContextService;
681 * Get the studyService.
683 * @return the studyService
685 public StudyService getStudyService() {
686 return _studyService;
690 * Set the studyService.
692 * @param studyService
693 * the studyService to set
695 public void setStudyService(final StudyService studyService) {
696 _studyService = studyService;
700 * Get the stepService.
702 * @return the stepService
704 public StepService getStepService() {
709 * Set the stepService.
712 * the stepService to set
714 public void setStepService(final StepService stepService) {
715 _stepService = stepService;
719 * Get the documentService.
721 * @return the documentService
723 public DocumentService getDocumentService() {
724 return _documentService;
728 * Set the documentService.
730 * @param documentService
731 * the documentService to set
733 public void setDocumentService(final DocumentService documentService) {
734 _documentService = documentService;
738 * Get the publicationDAO.
740 * @return the publicationDAO
742 public PublicationDAO getPublicationDAO() {
743 return _publicationDAO;
747 * Set the publicationDAO.
749 * @param publicationDAO
750 * the publicationDAO to set
752 public void setPublicationDAO(final PublicationDAO publicationDAO) {
753 _publicationDAO = publicationDAO;
757 * Get the projectElementDAO.
759 * @return the projectElementDAO
761 public ProjectElementDAO getProjectElementDAO() {
762 return _projectElementDAO;
766 * Set the projectElementDAO.
768 * @param projectElementDAO
769 * the projectElementDAO to set
771 public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
772 _projectElementDAO = projectElementDAO;
776 * Get the repositoryService.
778 * @return the repositoryService
780 public RepositoryService getRepositoryService() {
781 return _repositoryService;
785 * Set the repositoryService.
787 * @param repositoryService
788 * the repositoryService to set
790 public void setRepositoryService(final RepositoryService repositoryService) {
791 _repositoryService = repositoryService;
795 * Get the timestampDAO.
796 * @return the timestampDAO
798 public TimestampDAO getTimestampDAO() {
799 return _timestampDAO;
803 * Set the timestampDAO.
804 * @param timestampDAO the timestampDAO to set
806 public void setTimestampDAO(final TimestampDAO timestampDAO) {
807 _timestampDAO = timestampDAO;