1 /*****************************************************************************
5 * Creation date 06.10.2012
8 *****************************************************************************/
10 package org.splat.service;
12 import java.io.IOException;
13 import java.util.ArrayList;
14 import java.util.Iterator;
15 import java.util.List;
17 import org.hibernate.criterion.Restrictions;
18 import org.splat.dal.bo.kernel.Relation;
19 import org.splat.dal.bo.kernel.User;
20 import org.splat.dal.bo.som.ConvertsRelation;
21 import org.splat.dal.bo.som.Document;
22 import org.splat.dal.bo.som.DocumentType;
23 import org.splat.dal.bo.som.File;
24 import org.splat.dal.bo.som.KnowledgeElement;
25 import org.splat.dal.bo.som.ProjectElement;
26 import org.splat.dal.bo.som.Publication;
27 import org.splat.dal.bo.som.Scenario;
28 import org.splat.dal.bo.som.SimulationContext;
29 import org.splat.dal.bo.som.StepCommentAttribute;
30 import org.splat.dal.bo.som.UsedByRelation;
31 import org.splat.dal.bo.som.UsesRelation;
32 import org.splat.dal.bo.som.VersionsRelation;
33 import org.splat.dal.dao.kernel.RelationDAO;
34 import org.splat.dal.dao.kernel.UserDAO;
35 import org.splat.dal.dao.som.DocumentDAO;
36 import org.splat.dal.dao.som.FileDAO;
37 import org.splat.dal.dao.som.ProjectElementDAO;
38 import org.splat.dal.dao.som.PublicationDAO;
39 import org.splat.dal.dao.som.SimulationContextDAO;
40 import org.splat.dal.dao.som.StepCommentAttributeDAO;
41 import org.splat.dal.dao.som.VersionsRelationDAO;
42 import org.splat.exception.DocumentIsUsedException;
43 import org.splat.exception.InvalidParameterException;
44 import org.splat.kernel.InvalidPropertyException;
45 import org.splat.kernel.MismatchException;
46 import org.splat.kernel.MissedPropertyException;
47 import org.splat.kernel.MultiplyDefinedException;
48 import org.splat.kernel.NotApplicableException;
49 import org.splat.log.AppLogger;
50 import org.splat.service.dto.StepCommentDTO;
51 import org.splat.service.technical.IndexService;
52 import org.splat.service.technical.ProjectSettingsService;
53 import org.splat.som.Revision;
54 import org.splat.som.Step;
55 import org.splat.util.BeanHelper;
56 import org.springframework.transaction.annotation.Transactional;
60 * Step service implementation.
62 * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
64 public class StepServiceImpl implements StepService {
67 * logger for the service.
69 public final static AppLogger LOG = AppLogger
70 .getLogger(StepServiceImpl.class);
72 * Injected index service.
74 private IndexService _indexService;
76 * Injected document service.
78 private DocumentService _documentService;
80 * Injected document type service.
82 private DocumentTypeService _documentTypeService;
84 * Injected document DAO.
86 private DocumentDAO _documentDAO;
88 * Injected relation DAO.
90 private RelationDAO _relationDAO;
94 private FileDAO _fileDAO;
96 * Injected simulation context service.
98 private SimulationContextService _simulationContextService;
100 * Injected simulation context DAO.
102 private SimulationContextDAO _simulationContextDAO;
104 * Injected project element DAO.
106 private ProjectElementDAO _projectElementDAO;
108 * Injected versions relation DAO.
110 private VersionsRelationDAO _versionsRelationDAO;
112 * Injected project service.
114 private ProjectSettingsService _projectSettings;
116 * Injected publication DAO.
118 private PublicationDAO _publicationDAO;
121 * Injected text attribute DAO.
123 private StepCommentAttributeDAO _stepCommentAttributeDAO;
128 private UserDAO _userDAO;
134 * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext.Properties)
137 public SimulationContext addSimulationContext(final Step aStep,
138 final SimulationContext.Properties dprop)
139 throws MissedPropertyException, InvalidPropertyException,
140 MultiplyDefinedException {
141 SimulationContext context = new SimulationContext(dprop.setStep(aStep
143 return addSimulationContext(aStep, context);
149 * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
153 public SimulationContext addSimulationContext(final Step aStep,
154 final SimulationContext context) {
155 SimulationContext res = null;
156 getSimulationContextService().hold(context); // Increments the reference count of simulation context
157 if (aStep.getOwner().isSaved()) {
159 if (!context.isSaved()) {
160 getSimulationContextDAO().create(context);
162 aStep.getOwner().add(context);
163 aStep.getContex().add(context); // The context is also referenced from this (transient) Step
164 getProjectElementDAO().update(aStep.getOwner());
165 updateKnowledgeElementsIndex(aStep);
167 } catch (Exception error) {
168 LOG.debug(error.getMessage(), error);
170 } else { // Happens when copying a scenario
171 aStep.getOwner().add(context);
172 aStep.getContex().add(context); // The context is also referenced from this (transient) Step
173 // In case of owner scenario, the Knowledge Element index will be updated later, when saving the scenario
180 * Update lucene index of knowledge elements of a scenario or a study which the given step is related to.
183 * the step (activity)
185 private void updateKnowledgeElementsIndex(final Step aStep) {
187 if (aStep.getOwner() instanceof Scenario) {
188 scenarii = new Scenario[1];
189 scenarii[0] = (Scenario) aStep.getOwner();
191 scenarii = aStep.getOwnerStudy().getScenarii();
194 for (int i = 0; i < scenarii.length; i++) {
195 Scenario scene = scenarii[i];
196 List<KnowledgeElement> knelm = scene.getAllKnowledgeElements();
197 for (Iterator<KnowledgeElement> j = knelm.iterator(); j
199 KnowledgeElement kelm = j.next();
200 getIndexService().update(kelm);
202 updateScenarioIndex(scene);
204 } catch (Exception error) {
205 LOG.error("Unable to re-index Knowledge Elements, reason:", error);
210 * Update lucene index for knowledge elements of the scenario.
214 * @throws IOException
215 * if can't update lucene index
217 private void updateScenarioIndex(final Scenario scene) throws IOException {
218 if (scene.getUcase() == null) {
219 for (Iterator<KnowledgeElement> i = scene.getKnowledgeElements()
220 .iterator(); i.hasNext();) {
221 KnowledgeElement kelm = i.next();
222 if (!kelm.getType().equals("usecase")) {
225 scene.setUcase(kelm);
229 getIndexService().update(scene.getUcase());
235 * @see org.splat.service.StepService#removeSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
239 public boolean removeSimulationContext(final Step aStep,
240 final SimulationContext context) {
241 SimulationContext torem = aStep
242 .getSimulationContext(context.getIndex());
244 boolean isOk = (torem != null) && (aStep.getOwner().remove(torem));
247 aStep.getContex().remove(torem);
248 getProjectElementDAO().update(aStep.getOwner());
249 if (torem.isShared()) {
250 getSimulationContextService().release(torem);
251 getSimulationContextDAO().update(torem);
253 getSimulationContextDAO().delete(torem);
262 * @see org.splat.service.StepService#createDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
266 public Publication createDocument(final Step aStep,
267 final Document.Properties dprop) throws MissedPropertyException,
268 InvalidPropertyException, MultiplyDefinedException, IOException {
269 if (LOG.isDebugEnabled()) {
270 LOG.debug("Local index before: "
271 + aStep.getOwnerStudy().getLastLocalIndex());
273 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
274 .setStep(aStep.getStep()));
275 getDocumentService().generateDocumentId(newdoc, dprop);
277 // Creation of the save directory
278 java.io.File wdir = getDocumentService().getSaveDirectory(newdoc);
279 if ((!wdir.exists()) && (!wdir.mkdirs())) {
280 throw new IOException(
281 "Cannot create the repository vault directory");
284 // Identification and save
285 if (LOG.isDebugEnabled()) {
286 LOG.debug("Local index after: "
287 + aStep.getOwnerStudy().getLastLocalIndex());
289 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwnerStudy());
290 getDocumentDAO().create(newdoc);
292 return new Publication(newdoc, aStep.getOwner());
298 * @see org.splat.service.StepService#assignDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
301 public Publication assignDocument(final Step aStep,
302 final Document.Properties dprop) throws MissedPropertyException,
303 InvalidPropertyException, NotApplicableException {
304 String refid = dprop.getReference();
305 Publication res = null;
307 Document slot = getDocumentService().selectDocument(refid,
308 new Revision().toString());
309 if ((slot != null) && (slot.isUndefined())) {
310 getDocumentService().initialize(slot,
311 dprop.setOwner(aStep.getOwnerStudy()));
312 res = new Publication(slot, aStep.getOwner());
319 * Create a new version of a document in the given study step.
324 * the base document published version
325 * @return the new version publication
326 * @throws MissedPropertyException
327 * if a mandatory property is missed
328 * @throws InvalidPropertyException
329 * if some property doesn't exist
330 * @throws MultiplyDefinedException
331 * if some property is defined several times
332 * @throws IOException
333 * if a file system error occurs
334 * @throws MismatchException
335 * if the document is not applicable to the given study step
337 public Publication versionDocument(final Step aStep, final Publication base)
338 throws MissedPropertyException, InvalidPropertyException,
339 MultiplyDefinedException, IOException, MismatchException {
340 return versionDocument(aStep, base, new Document.Properties());
344 * Create a new version of a document in the given study step.
349 * the base document published version
351 * the comment for the new version
352 * @return the new version publication
353 * @throws MissedPropertyException
354 * if a mandatory property is missed
355 * @throws InvalidPropertyException
356 * if some property doesn't exist
357 * @throws MultiplyDefinedException
358 * if some property is defined several times
359 * @throws IOException
360 * if a file system error occurs
361 * @throws MismatchException
362 * if the document is not applicable to the given study step
364 public Publication versionDocument(final Step aStep,
365 final Publication base, final String reason)
366 throws MissedPropertyException, InvalidPropertyException,
367 MultiplyDefinedException, IOException, MismatchException {
368 return versionDocument(aStep, base, new Document.Properties()
369 .setDescription(reason));
373 * Create a new version of a document in the given study step.
378 * the base document published version
380 * properties of the new version
381 * @return the new version publication
382 * @throws MissedPropertyException
383 * if a mandatory property is missed
384 * @throws InvalidPropertyException
385 * if some property doesn't exist
386 * @throws MultiplyDefinedException
387 * if some property is defined several times
388 * @throws IOException
389 * if a file system error occurs
390 * @throws MismatchException
391 * if the document is not applicable to the given study step
395 public Publication versionDocument(final Step aStep,
396 final Publication base, final Document.Properties dprop)
397 throws MissedPropertyException, InvalidPropertyException,
398 MultiplyDefinedException, IOException, MismatchException {
399 Document previous = base.value();
401 // RKV: Keep the new file format if it is related to the same document type on this step.
402 String newFormat = dprop.getFormat();
404 dprop.setDocument(previous, getProjectSettings().getStep(
405 base.getStep().getNumber())); // Initializes the Step property
406 if (dprop.getStep().getNumber() != aStep.getNumber()) {
407 throw new MismatchException();
410 if (newFormat != null
411 /*&& previous.getType().equals(
412 getProjectSettings().getDefaultDocumentType(
413 aStep.getStep(), newFormat))*/) {
414 dprop.setFormat(newFormat);
417 if (dprop.getAuthor() == null) {
418 dprop.setAuthor(previous.getAuthor());
420 String summary = dprop.getDescription();
422 // Creation of the document
423 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
424 .setStep(aStep.getStep()));
425 getDocumentService().generateDocumentId(newdoc, dprop);
426 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwner(),
428 getDocumentDAO().create(newdoc);
431 VersionsRelation aRel;
432 aRel = new VersionsRelation(newdoc, previous, summary);
433 // getVersionsRelationDAO().create(aRel);
434 newdoc.addRelation(aRel);
436 // Update of usedby relations, if exist
438 * RKV: Consider the new version as not used by old dependent documents. So these documents must be marked as outdated then. List<Relation>
439 * relist = previous.getRelations(UsedByRelation.class); Study scope = aStep.getOwnerStudy(); for (Iterator<Relation> i =
440 * relist.iterator(); i.hasNext();) { UsedByRelation relation = (UsedByRelation) i.next(); Document relatedoc = relation.getTo(); if
441 * (scope.shares(relatedoc)) { relatedoc.addRelation(new UsesRelation(relatedoc, newdoc)); } else { relation.moveTo(newdoc); } }
443 return new Publication(newdoc, aStep.getOwner());
447 * Get document types which are applicable for the given study step (activity).
451 * @return the list of document types
454 public List<DocumentType> getValidDocumentTypes(final Step aStep) {
455 return getDocumentTypeService().selectTypesOf(aStep.getStep());
459 * Add a document publication to the given step.
462 * the target study step
464 * the document publication to add
465 * @return true if publication succeeded
468 public boolean add(final Step aStep, final Publication newdoc) {
469 boolean res = aStep.getOwner().add(newdoc); // Updates the study in memory
471 aStep.getDocuments().add(0, newdoc); // Updates this step
472 getDocumentService().hold(newdoc.value()); // Increments the configuration tag count of document
473 // If not yet saved, the Publication MUST NOT be saved here, although this creates a temporary inconsistent state into the
474 // database (it will be saved later by cascading the update of owner scenario).
480 * Remove a document publication from the given step.
485 * the document publication to remove
486 * @return true if removing of the publication succeeded
489 public boolean remove(final Step aStep, final Publication oldoc) {
490 aStep.getDocuments().remove(oldoc); // Updates this step
491 aStep.getOwner().remove(oldoc); // remove from the parent project element
492 getProjectElementDAO().merge(aStep.getOwner());
493 getDocumentService().release(oldoc.value()); // Decrements the configuration tag count of document
494 // The publication becoming orphan, it should automatically be removed from the database when updating of owner scenario.
499 * Remove a document from the given step and from the database if it is no more used.
505 * @return true if removing of the document succeeded
506 * @throws DocumentIsUsedException
507 * if the document is used by other documents
511 public boolean removeDocument(final Step aStep, final long docId)
512 throws DocumentIsUsedException {
513 Publication torem = aStep.getDocument(docId);
514 boolean res = (torem != null);
516 if (!torem.value().getRelations(UsedByRelation.class).isEmpty()) {
517 throw new DocumentIsUsedException(torem.value().getTitle());
519 remove(aStep, torem);
520 Document value = torem.value();
521 if (!value.isPublished() && !value.isVersioned()) { // The referenced document is no more used
522 List<Document> using = new ArrayList<Document>();
523 List<File> files = new ArrayList<File>();
524 for (Relation link : value.getAllRelations()) {
525 if (link.getClass().equals(ConvertsRelation.class)) { // File conversion
526 files.add((File) link.getTo());
527 } else if (link.getClass().equals(UsesRelation.class)) { // Document dependency
528 using.add((Document) link.getTo());
531 // Remove relations from depending documents
532 if (LOG.isDebugEnabled()) {
533 LOG.debug("Remove " + using.size() + " UsedByRelation(s).");
535 for (Document doc : using) {
536 if (LOG.isDebugEnabled()) {
537 LOG.debug("Remove UsedByRelation from "
538 + doc.getTitle() + " to " + value.getTitle());
539 LOG.debug("Nb relations of doc " + doc.getTitle()
540 + " before: " + doc.getAllRelations().size());
542 doc.removeRelation(UsedByRelation.class, value);
543 if (LOG.isDebugEnabled()) {
544 LOG.debug("Nb relations of doc " + doc.getTitle()
545 + " after: " + doc.getAllRelations().size());
547 getDocumentDAO().merge(doc);
549 // Synchronize deleted objects with the database to avoid hibernate exception
550 // org.hibernate.PropertyValueException: not-null property references a null or transient value
551 getDocumentDAO().flush();
552 // The corresponding physical file is not removed from the vault
553 getDocumentDAO().delete(getDocumentDAO().merge(torem.value()));
554 // Delete document's files
555 for (File file : files) {
556 getFileDAO().delete(getFileDAO().merge(file)); // The corresponding physical file is not removed from the vault
566 * @see org.splat.service.StepService#addComment(org.splat.som.Step, org.splat.dal.bo.som.CommentAttribute)
570 public void addStepComment(final StepCommentDTO comment) throws InvalidParameterException {
572 if(comment.getId()!= null) {
573 throw new InvalidParameterException("id", String.valueOf(comment.getId()));
575 User user = getUserDAO().get(comment.getUserId());
577 throw new InvalidParameterException("userId", String.valueOf(comment.getUserId()));
579 ProjectElement projectElement = getProjectElementDAO().get(comment.getProjectElementId());
580 if (projectElement==null) {
581 throw new InvalidParameterException("projectElementId", comment.getProjectElementId().toString());
583 if(comment.getStep() == null || comment.getStep()<0) {
584 throw new InvalidParameterException("step", String.valueOf(comment.getStep()));
586 if(comment.getDate() == null) {
587 throw new InvalidParameterException("date", String.valueOf(comment.getDate()));
589 if(comment.getTitle() == null) {
590 throw new InvalidParameterException("title", String.valueOf(comment.getTitle()));
593 StepCommentAttribute newComment = new StepCommentAttribute(
602 Long resultKey=getStepCommentAttributeDAO().create(newComment);
603 comment.setId(resultKey);
608 * @see org.splat.service.StepService#getStepComments(org.splat.som.Step)
611 @Transactional(readOnly = true)
612 public List<StepCommentDTO> getStepComments(final Step step) throws InvalidParameterException {
613 ProjectElement owner = _projectElementDAO.get(step.getOwner().getRid());
615 throw new InvalidParameterException("step owner id",
616 Long.valueOf(step.getOwner().getRid()).toString());
618 List<StepCommentAttribute> comments = _stepCommentAttributeDAO.getFilteredList(
620 Restrictions.eq("step", Integer.valueOf(step.getNumber())),
621 Restrictions.eq("owner", owner)));
622 List<StepCommentDTO> commentDTOs = new ArrayList<StepCommentDTO>();
623 for(StepCommentAttribute comment : comments) {
624 StepCommentDTO stepCommentDTO = BeanHelper.copyBean(comment, StepCommentDTO.class);
625 stepCommentDTO.setText(comment.getValue());
626 stepCommentDTO.setId(Long.valueOf(comment.getRid()));
627 commentDTOs.add(stepCommentDTO);
633 * Get the documentService.
635 * @return the documentService
637 public DocumentService getDocumentService() {
638 return _documentService;
642 * Set the documentService.
644 * @param documentService
645 * the documentService to set
647 public void setDocumentService(final DocumentService documentService) {
648 _documentService = documentService;
652 * Get the simulationContextService.
654 * @return the simulationContextService
656 public SimulationContextService getSimulationContextService() {
657 return _simulationContextService;
661 * Set the simulationContextService.
663 * @param simulationContextService
664 * the simulationContextService to set
666 public void setSimulationContextService(
667 final SimulationContextService simulationContextService) {
668 _simulationContextService = simulationContextService;
672 * Get the documentDAO.
674 * @return the documentDAO
676 public DocumentDAO getDocumentDAO() {
681 * Set the documentDAO.
684 * the documentDAO to set
686 public void setDocumentDAO(final DocumentDAO documentDAO) {
687 _documentDAO = documentDAO;
691 * Get the simulationContextDAO.
693 * @return the simulationContextDAO
695 public SimulationContextDAO getSimulationContextDAO() {
696 return _simulationContextDAO;
700 * Set the simulationContextDAO.
702 * @param simulationContextDAO
703 * the simulationContextDAO to set
705 public void setSimulationContextDAO(
706 final SimulationContextDAO simulationContextDAO) {
707 _simulationContextDAO = simulationContextDAO;
711 * Get the projectElementDAO.
713 * @return the projectElementDAO
715 public ProjectElementDAO getProjectElementDAO() {
716 return _projectElementDAO;
720 * Set the projectElementDAO.
722 * @param projectElementDAO
723 * the projectElementDAO to set
725 public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
726 _projectElementDAO = projectElementDAO;
730 * Get the indexService.
732 * @return the indexService
734 public IndexService getIndexService() {
735 return _indexService;
739 * Set the indexService.
741 * @param indexService
742 * the indexService to set
744 public void setIndexService(final IndexService indexService) {
745 _indexService = indexService;
751 * @return the fileDAO
753 public FileDAO getFileDAO() {
763 public void setFileDAO(final FileDAO fileDAO) {
768 * Get the documentTypeService.
770 * @return the documentTypeService
772 public DocumentTypeService getDocumentTypeService() {
773 return _documentTypeService;
777 * Set the documentTypeService.
779 * @param documentTypeService
780 * the documentTypeService to set
782 public void setDocumentTypeService(
783 final DocumentTypeService documentTypeService) {
784 _documentTypeService = documentTypeService;
788 * Get the versionsRelationDAO.
790 * @return the versionsRelationDAO
792 public VersionsRelationDAO getVersionsRelationDAO() {
793 return _versionsRelationDAO;
797 * Set the versionsRelationDAO.
799 * @param versionsRelationDAO
800 * the versionsRelationDAO to set
802 public void setVersionsRelationDAO(
803 final VersionsRelationDAO versionsRelationDAO) {
804 _versionsRelationDAO = versionsRelationDAO;
808 * Get project settings.
810 * @return Project settings service
812 private ProjectSettingsService getProjectSettings() {
813 return _projectSettings;
817 * Set project settings service.
819 * @param projectSettingsService
820 * project settings service
822 public void setProjectSettings(
823 final ProjectSettingsService projectSettingsService) {
824 _projectSettings = projectSettingsService;
828 * Get the stepCommentAttributeDAO.
829 * @return the stepCommentAttributeDAO
831 public StepCommentAttributeDAO getStepCommentAttributeDAO() {
832 return _stepCommentAttributeDAO;
836 * Set the stepCommentAttributeDAO.
837 * @param commentAttributeDAO the stepCommentAttributeDAO to set
839 public void setStepCommentAttributeDAO(
840 final StepCommentAttributeDAO commentAttributeDAO) {
841 _stepCommentAttributeDAO = commentAttributeDAO;
846 * @return the userDAO
848 public UserDAO getUserDAO() {
853 * @param userDAO the userDAO to set
855 public void setUserDAO(final UserDAO userDAO) {
860 * Get the publicationDAO.
862 * @return the publicationDAO
864 public PublicationDAO getPublicationDAO() {
865 return _publicationDAO;
869 * Set the publicationDAO.
871 * @param publicationDAO
872 * the publicationDAO to set
874 public void setPublicationDAO(final PublicationDAO publicationDAO) {
875 this._publicationDAO = publicationDAO;
879 * Get the relationDAO.
881 * @return the relationDAO
883 public RelationDAO getRelationDAO() {
888 * Set the relationDAO.
891 * the relationDAO to set
893 public void setRelationDAO(final RelationDAO relationDAO) {
894 _relationDAO = relationDAO;