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.splat.dal.bo.kernel.Relation;
18 import org.splat.dal.bo.som.ConvertsRelation;
19 import org.splat.dal.bo.som.Document;
20 import org.splat.dal.bo.som.DocumentType;
21 import org.splat.dal.bo.som.File;
22 import org.splat.dal.bo.som.KnowledgeElement;
23 import org.splat.dal.bo.som.ProjectElement;
24 import org.splat.dal.bo.som.Publication;
25 import org.splat.dal.bo.som.Scenario;
26 import org.splat.dal.bo.som.SimulationContext;
27 import org.splat.dal.bo.som.UsedByRelation;
28 import org.splat.dal.bo.som.UsesRelation;
29 import org.splat.dal.bo.som.VersionsRelation;
30 import org.splat.dal.dao.kernel.RelationDAO;
31 import org.splat.dal.dao.som.DocumentDAO;
32 import org.splat.dal.dao.som.FileDAO;
33 import org.splat.dal.dao.som.ProjectElementDAO;
34 import org.splat.dal.dao.som.PublicationDAO;
35 import org.splat.dal.dao.som.SimulationContextDAO;
36 import org.splat.dal.dao.som.VersionsRelationDAO;
37 import org.splat.kernel.InvalidPropertyException;
38 import org.splat.kernel.MismatchException;
39 import org.splat.kernel.MissedPropertyException;
40 import org.splat.kernel.MultiplyDefinedException;
41 import org.splat.kernel.NotApplicableException;
42 import org.splat.log.AppLogger;
43 import org.splat.service.technical.IndexService;
44 import org.splat.service.technical.ProjectSettingsService;
45 import org.splat.som.Revision;
46 import org.splat.som.Step;
47 import org.springframework.transaction.annotation.Transactional;
50 * Step service implementation.
52 * @author <a href="mailto:roman.kozlov@opencascade.com">Roman Kozlov (RKV)</a>
54 public class StepServiceImpl implements StepService {
57 * logger for the service.
59 public final static AppLogger LOG = AppLogger
60 .getLogger(StepServiceImpl.class);
62 * Injected index service.
64 private IndexService _indexService;
66 * Injected document service.
68 private DocumentService _documentService;
70 * Injected document type service.
72 private DocumentTypeService _documentTypeService;
74 * Injected document DAO.
76 private DocumentDAO _documentDAO;
78 * Injected relation DAO.
80 private RelationDAO _relationDAO;
84 private FileDAO _fileDAO;
86 * Injected simulation context service.
88 private SimulationContextService _simulationContextService;
90 * Injected simulation context DAO.
92 private SimulationContextDAO _simulationContextDAO;
94 * Injected project element DAO.
96 private ProjectElementDAO _projectElementDAO;
98 * Injected versions relation DAO.
100 private VersionsRelationDAO _versionsRelationDAO;
102 * Injected project service.
104 private ProjectSettingsService _projectSettings;
106 * Injected publication DAO.
108 private PublicationDAO _publicationDAO;
113 * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext.Properties)
115 public SimulationContext addSimulationContext(final Step aStep,
116 final SimulationContext.Properties dprop)
117 throws MissedPropertyException, InvalidPropertyException,
118 MultiplyDefinedException {
119 SimulationContext context = new SimulationContext(dprop.setStep(aStep
121 return addSimulationContext(aStep, context);
127 * @see org.splat.service.StepService#addSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
130 public SimulationContext addSimulationContext(final Step aStep,
131 final SimulationContext context) {
132 SimulationContext res = null;
133 getSimulationContextService().hold(context); // Increments the reference count of simulation context
134 if (aStep.getOwner().isSaved()) {
136 if (!context.isSaved()) {
137 getSimulationContextDAO().create(context);
139 aStep.getOwner().add(context);
140 aStep.getContex().add(context); // The context is also referenced from this (transient) Step
141 getProjectElementDAO().update(aStep.getOwner());
142 updateKnowledgeElementsIndex(aStep);
144 } catch (Exception error) {
145 LOG.debug(error.getMessage(), error);
147 } else { // Happens when copying a scenario
148 aStep.getOwner().add(context);
149 aStep.getContex().add(context); // The context is also referenced from this (transient) Step
150 // In case of owner scenario, the Knowledge Element index will be updated later, when saving the scenario
157 * Update lucene index of knowledge elements of a scenario or a study which the given step is related to.
160 * the step (activity)
162 private void updateKnowledgeElementsIndex(final Step aStep) {
164 if (aStep.getOwner() instanceof Scenario) {
165 scenarii = new Scenario[1];
166 scenarii[0] = (Scenario) aStep.getOwner();
168 scenarii = aStep.getOwnerStudy().getScenarii();
171 for (int i = 0; i < scenarii.length; i++) {
172 Scenario scene = scenarii[i];
173 List<KnowledgeElement> knelm = scene.getAllKnowledgeElements();
174 for (Iterator<KnowledgeElement> j = knelm.iterator(); j
176 KnowledgeElement kelm = j.next();
177 getIndexService().update(kelm);
179 updateScenarioIndex(scene);
181 } catch (Exception error) {
182 LOG.error("Unable to re-index Knowledge Elements, reason:", error);
187 * Update lucene index for knowledge elements of the scenario.
191 * @throws IOException
192 * if can't update lucene index
194 private void updateScenarioIndex(final Scenario scene) throws IOException {
195 if (scene.getUcase() == null) {
196 for (Iterator<KnowledgeElement> i = scene.getKnowledgeElements()
197 .iterator(); i.hasNext();) {
198 KnowledgeElement kelm = i.next();
199 if (!kelm.getType().equals("usecase")) {
202 scene.setUcase(kelm);
206 getIndexService().update(scene.getUcase());
212 * @see org.splat.service.StepService#removeSimulationContext(org.splat.som.Step, org.splat.dal.bo.som.SimulationContext)
215 public boolean removeSimulationContext(final Step aStep,
216 final SimulationContext context) {
217 SimulationContext torem = aStep
218 .getSimulationContext(context.getIndex());
220 boolean isOk = (torem != null) && (aStep.getOwner().remove(torem));
223 aStep.getContex().remove(torem);
224 getProjectElementDAO().update(aStep.getOwner());
225 if (torem.isShared()) {
226 getSimulationContextService().release(torem);
227 getSimulationContextDAO().update(torem);
229 getSimulationContextDAO().delete(torem);
238 * @see org.splat.service.StepService#createDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
241 public Publication createDocument(final Step aStep,
242 final Document.Properties dprop) throws MissedPropertyException,
243 InvalidPropertyException, MultiplyDefinedException, IOException {
244 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
245 .setStep(aStep.getStep()));
246 getDocumentService().generateDocumentId(newdoc, dprop);
248 // Creation of the save directory
249 java.io.File wdir = getDocumentService().getSaveDirectory(newdoc);
250 if ((!wdir.exists()) && (!wdir.mkdirs())) {
251 throw new IOException(
252 "Cannot create the repository vault directory");
255 // Identification and save
256 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwnerStudy());
257 getDocumentDAO().create(newdoc);
259 return new Publication(newdoc, aStep.getOwner());
265 * @see org.splat.service.StepService#assignDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
267 public Publication assignDocument(final Step aStep,
268 final Document.Properties dprop) throws MissedPropertyException,
269 InvalidPropertyException, NotApplicableException {
270 String refid = dprop.getReference();
271 Publication res = null;
273 Document slot = getDocumentService().selectDocument(refid,
274 new Revision().toString());
275 if ((slot != null) && (slot.isUndefined())) {
276 getDocumentService().initialize(slot,
277 dprop.setOwner(aStep.getOwnerStudy()));
278 res = new Publication(slot, aStep.getOwner());
285 * Create a new version of a document in the given study step.
290 * the base document published version
291 * @return the new version publication
292 * @throws MissedPropertyException
293 * if a mandatory property is missed
294 * @throws InvalidPropertyException
295 * if some property doesn't exist
296 * @throws MultiplyDefinedException
297 * if some property is defined several times
298 * @throws IOException
299 * if a file system error occurs
300 * @throws MismatchException
301 * if the document is not applicable to the given study step
303 public Publication versionDocument(final Step aStep, final Publication base)
304 throws MissedPropertyException, InvalidPropertyException,
305 MultiplyDefinedException, IOException, MismatchException {
306 return versionDocument(aStep, base, new Document.Properties());
310 * Create a new version of a document in the given study step.
315 * the base document published version
317 * the comment for the new version
318 * @return the new version publication
319 * @throws MissedPropertyException
320 * if a mandatory property is missed
321 * @throws InvalidPropertyException
322 * if some property doesn't exist
323 * @throws MultiplyDefinedException
324 * if some property is defined several times
325 * @throws IOException
326 * if a file system error occurs
327 * @throws MismatchException
328 * if the document is not applicable to the given study step
330 public Publication versionDocument(final Step aStep,
331 final Publication base, final String reason)
332 throws MissedPropertyException, InvalidPropertyException,
333 MultiplyDefinedException, IOException, MismatchException {
334 return versionDocument(aStep, base, new Document.Properties()
335 .setDescription(reason));
339 * Create a new version of a document in the given study step.
344 * the base document published version
346 * properties of the new version
347 * @return the new version publication
348 * @throws MissedPropertyException
349 * if a mandatory property is missed
350 * @throws InvalidPropertyException
351 * if some property doesn't exist
352 * @throws MultiplyDefinedException
353 * if some property is defined several times
354 * @throws IOException
355 * if a file system error occurs
356 * @throws MismatchException
357 * if the document is not applicable to the given study step
360 public Publication versionDocument(final Step aStep,
361 final Publication base, final Document.Properties dprop)
362 throws MissedPropertyException, InvalidPropertyException,
363 MultiplyDefinedException, IOException, MismatchException {
364 Document previous = base.value();
366 // RKV: Keep the new file format if it is related to the same document type on this step.
367 String newFormat = dprop.getFormat();
369 dprop.setDocument(previous, getProjectSettings().getStep(
370 base.getStep().getNumber())); // Initializes the Step property
371 if (dprop.getStep().getNumber() != aStep.getNumber()) {
372 throw new MismatchException();
375 if (newFormat != null
376 && previous.getType().equals(
377 getProjectSettings().getDefaultDocumentType(
378 aStep.getStep(), newFormat))) {
379 dprop.setFormat(newFormat);
382 if (dprop.getAuthor() == null) {
383 dprop.setAuthor(previous.getAuthor());
385 String summary = dprop.getDescription();
387 // Creation of the document
388 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
389 .setStep(aStep.getStep()));
390 getDocumentService().generateDocumentId(newdoc, dprop);
391 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwner(),
393 getDocumentDAO().create(newdoc);
396 VersionsRelation aRel;
397 aRel = new VersionsRelation(newdoc, previous, summary);
398 // getVersionsRelationDAO().create(aRel);
399 newdoc.addRelation(aRel);
401 // Update of usedby relations, if exist
403 * RKV: Consider the new version as not used by old dependent documents. So these documents must be marked as outdated then. List<Relation>
404 * relist = previous.getRelations(UsedByRelation.class); Study scope = aStep.getOwnerStudy(); for (Iterator<Relation> i =
405 * relist.iterator(); i.hasNext();) { UsedByRelation relation = (UsedByRelation) i.next(); Document relatedoc = relation.getTo(); if
406 * (scope.shares(relatedoc)) { relatedoc.addRelation(new UsesRelation(relatedoc, newdoc)); } else { relation.moveTo(newdoc); } }
408 return new Publication(newdoc, aStep.getOwner());
412 * Get document types which are applicable for the given study step (activity).
416 * @return the list of document types
418 public List<DocumentType> getValidDocumentTypes(final Step aStep) {
419 return getDocumentTypeService().selectTypesOf(aStep.getStep());
423 * Add a document publication to the given step.
426 * the target study step
428 * the document publication to add
429 * @return true if publication succeeded
431 public boolean add(final Step aStep, final Publication newdoc) {
432 boolean res = aStep.getOwner().add(newdoc); // Updates the study in memory
434 aStep.getDocuments().add(0, newdoc); // Updates this step
435 getDocumentService().hold(newdoc.value()); // Increments the configuration tag count of document
436 // If not yet saved, the Publication MUST NOT be saved here, although this creates a temporary inconsistent state into the
437 // database (it will be saved later by cascading the update of owner scenario).
443 * Remove a document publication from the given step.
448 * the document publication to remove
449 * @return true if removing of the publication succeeded
451 public boolean remove(final Step aStep, final Publication oldoc) {
452 aStep.getDocuments().remove(oldoc); // Updates this step
453 // Synchronize with database
454 ProjectElement owner = getProjectElementDAO().merge(aStep.getOwner());
456 aStep.getOwner().remove(oldoc); // in transient copy
457 owner.remove(oldoc); // in persistent copy
459 getDocumentService().release(oldoc.value()); // Decrements the configuration tag count of document
460 // The publication becoming orphan, it should automatically be removed from the database when updating of owner scenario.
465 * Remove a document from the given step and from the database if it is no more used.
471 * @return true if removing of the document succeeded
474 public boolean removeDocument(final Step aStep, final long docId) {
475 Publication torem = aStep.getDocument(docId);
476 boolean res = (torem != null);
478 torem = getPublicationDAO().merge(torem);
479 remove(aStep, torem);
480 Document value = torem.value();
481 if (!value.isPublished() && !value.isVersioned()) { // The referenced document is no more used
482 List<Document> using = new ArrayList<Document>();
483 List<Relation> converts = new ArrayList<Relation>();
484 for (Relation link : value.getAllRelations()) {
485 if (link.getClass().equals(ConvertsRelation.class)) { // File conversion
487 } else if (link.getClass().equals(UsesRelation.class)) { // Document dependency
488 using.add((Document) link.getTo());
491 // value.getAllRelations().removeAll(converts);
492 // Remove relations from depending documents
493 if (LOG.isDebugEnabled()) {
494 LOG.debug("Remove " + using.size() + " UsedByRelation(s).");
496 for (Document doc : using) {
497 if (LOG.isDebugEnabled()) {
498 LOG.debug("Remove UsedByRelation from "
499 + doc.getTitle() + " to " + value.getTitle());
501 doc.removeRelation(UsedByRelation.class, value);
503 // Synchronize deleted objects with the database to avoid hibernate exception
504 // related with null value of not-nullable property because back reference from Document to Publication is not mapped:
505 // org.hibernate.PropertyValueException: not-null property references a null or transient value:
506 // org.splat.dal.bo.som.Publication.mydoc
507 getDocumentDAO().flush(); // To show to the database that files from ConvertsRelation(s) are deleted already
508 getDocumentDAO().delete(value); // The corresponding physical file is not removed from the vault
509 // Delete document's files
510 for (Relation link : converts) {
511 File file = (File) link.getTo();
512 getFileDAO().delete(file); // The corresponding physical file is not removed from the vault
520 * Get the documentService.
522 * @return the documentService
524 public DocumentService getDocumentService() {
525 return _documentService;
529 * Set the documentService.
531 * @param documentService
532 * the documentService to set
534 public void setDocumentService(final DocumentService documentService) {
535 _documentService = documentService;
539 * Get the simulationContextService.
541 * @return the simulationContextService
543 public SimulationContextService getSimulationContextService() {
544 return _simulationContextService;
548 * Set the simulationContextService.
550 * @param simulationContextService
551 * the simulationContextService to set
553 public void setSimulationContextService(
554 final SimulationContextService simulationContextService) {
555 _simulationContextService = simulationContextService;
559 * Get the documentDAO.
561 * @return the documentDAO
563 public DocumentDAO getDocumentDAO() {
568 * Set the documentDAO.
571 * the documentDAO to set
573 public void setDocumentDAO(final DocumentDAO documentDAO) {
574 _documentDAO = documentDAO;
578 * Get the simulationContextDAO.
580 * @return the simulationContextDAO
582 public SimulationContextDAO getSimulationContextDAO() {
583 return _simulationContextDAO;
587 * Set the simulationContextDAO.
589 * @param simulationContextDAO
590 * the simulationContextDAO to set
592 public void setSimulationContextDAO(
593 final SimulationContextDAO simulationContextDAO) {
594 _simulationContextDAO = simulationContextDAO;
598 * Get the projectElementDAO.
600 * @return the projectElementDAO
602 public ProjectElementDAO getProjectElementDAO() {
603 return _projectElementDAO;
607 * Set the projectElementDAO.
609 * @param projectElementDAO
610 * the projectElementDAO to set
612 public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
613 _projectElementDAO = projectElementDAO;
617 * Get the indexService.
619 * @return the indexService
621 public IndexService getIndexService() {
622 return _indexService;
626 * Set the indexService.
628 * @param indexService
629 * the indexService to set
631 public void setIndexService(final IndexService indexService) {
632 _indexService = indexService;
638 * @return the fileDAO
640 public FileDAO getFileDAO() {
650 public void setFileDAO(final FileDAO fileDAO) {
655 * Get the documentTypeService.
657 * @return the documentTypeService
659 public DocumentTypeService getDocumentTypeService() {
660 return _documentTypeService;
664 * Set the documentTypeService.
666 * @param documentTypeService
667 * the documentTypeService to set
669 public void setDocumentTypeService(
670 final DocumentTypeService documentTypeService) {
671 _documentTypeService = documentTypeService;
675 * Get the versionsRelationDAO.
677 * @return the versionsRelationDAO
679 public VersionsRelationDAO getVersionsRelationDAO() {
680 return _versionsRelationDAO;
684 * Set the versionsRelationDAO.
686 * @param versionsRelationDAO
687 * the versionsRelationDAO to set
689 public void setVersionsRelationDAO(
690 final VersionsRelationDAO versionsRelationDAO) {
691 _versionsRelationDAO = versionsRelationDAO;
695 * Get project settings.
697 * @return Project settings service
699 private ProjectSettingsService getProjectSettings() {
700 return _projectSettings;
704 * Set project settings service.
706 * @param projectSettingsService
707 * project settings service
709 public void setProjectSettings(
710 final ProjectSettingsService projectSettingsService) {
711 _projectSettings = projectSettingsService;
715 * Get the publicationDAO.
717 * @return the publicationDAO
719 public PublicationDAO getPublicationDAO() {
720 return _publicationDAO;
724 * Set the publicationDAO.
726 * @param publicationDAO
727 * the publicationDAO to set
729 public void setPublicationDAO(final PublicationDAO publicationDAO) {
730 this._publicationDAO = publicationDAO;
734 * Get the relationDAO.
736 * @return the relationDAO
738 public RelationDAO getRelationDAO() {
743 * Set the relationDAO.
746 * the relationDAO to set
748 public void setRelationDAO(final RelationDAO relationDAO) {
749 _relationDAO = relationDAO;