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.Publication;
24 import org.splat.dal.bo.som.Scenario;
25 import org.splat.dal.bo.som.SimulationContext;
26 import org.splat.dal.bo.som.UsedByRelation;
27 import org.splat.dal.bo.som.UsesRelation;
28 import org.splat.dal.bo.som.VersionsRelation;
29 import org.splat.dal.dao.kernel.RelationDAO;
30 import org.splat.dal.dao.som.DocumentDAO;
31 import org.splat.dal.dao.som.FileDAO;
32 import org.splat.dal.dao.som.ProjectElementDAO;
33 import org.splat.dal.dao.som.PublicationDAO;
34 import org.splat.dal.dao.som.SimulationContextDAO;
35 import org.splat.dal.dao.som.VersionsRelationDAO;
36 import org.splat.exception.DocumentIsUsedException;
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 if (LOG.isDebugEnabled()) {
245 LOG.debug("Local index before: "
246 + aStep.getOwnerStudy().getLastLocalIndex());
248 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
249 .setStep(aStep.getStep()));
250 getDocumentService().generateDocumentId(newdoc, dprop);
252 // Creation of the save directory
253 java.io.File wdir = getDocumentService().getSaveDirectory(newdoc);
254 if ((!wdir.exists()) && (!wdir.mkdirs())) {
255 throw new IOException(
256 "Cannot create the repository vault directory");
259 // Identification and save
260 if (LOG.isDebugEnabled()) {
261 LOG.debug("Local index after: "
262 + aStep.getOwnerStudy().getLastLocalIndex());
264 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwnerStudy());
265 getDocumentDAO().create(newdoc);
267 return new Publication(newdoc, aStep.getOwner());
273 * @see org.splat.service.StepService#assignDocument(org.splat.som.Step, org.splat.dal.bo.som.Document.Properties)
275 public Publication assignDocument(final Step aStep,
276 final Document.Properties dprop) throws MissedPropertyException,
277 InvalidPropertyException, NotApplicableException {
278 String refid = dprop.getReference();
279 Publication res = null;
281 Document slot = getDocumentService().selectDocument(refid,
282 new Revision().toString());
283 if ((slot != null) && (slot.isUndefined())) {
284 getDocumentService().initialize(slot,
285 dprop.setOwner(aStep.getOwnerStudy()));
286 res = new Publication(slot, aStep.getOwner());
293 * Create a new version of a document in the given study step.
298 * the base document published version
299 * @return the new version publication
300 * @throws MissedPropertyException
301 * if a mandatory property is missed
302 * @throws InvalidPropertyException
303 * if some property doesn't exist
304 * @throws MultiplyDefinedException
305 * if some property is defined several times
306 * @throws IOException
307 * if a file system error occurs
308 * @throws MismatchException
309 * if the document is not applicable to the given study step
311 public Publication versionDocument(final Step aStep, final Publication base)
312 throws MissedPropertyException, InvalidPropertyException,
313 MultiplyDefinedException, IOException, MismatchException {
314 return versionDocument(aStep, base, new Document.Properties());
318 * Create a new version of a document in the given study step.
323 * the base document published version
325 * the comment for the new version
326 * @return the new version publication
327 * @throws MissedPropertyException
328 * if a mandatory property is missed
329 * @throws InvalidPropertyException
330 * if some property doesn't exist
331 * @throws MultiplyDefinedException
332 * if some property is defined several times
333 * @throws IOException
334 * if a file system error occurs
335 * @throws MismatchException
336 * if the document is not applicable to the given study step
338 public Publication versionDocument(final Step aStep,
339 final Publication base, final String reason)
340 throws MissedPropertyException, InvalidPropertyException,
341 MultiplyDefinedException, IOException, MismatchException {
342 return versionDocument(aStep, base, new Document.Properties()
343 .setDescription(reason));
347 * Create a new version of a document in the given study step.
352 * the base document published version
354 * properties of the new version
355 * @return the new version publication
356 * @throws MissedPropertyException
357 * if a mandatory property is missed
358 * @throws InvalidPropertyException
359 * if some property doesn't exist
360 * @throws MultiplyDefinedException
361 * if some property is defined several times
362 * @throws IOException
363 * if a file system error occurs
364 * @throws MismatchException
365 * if the document is not applicable to the given study step
368 public Publication versionDocument(final Step aStep,
369 final Publication base, final Document.Properties dprop)
370 throws MissedPropertyException, InvalidPropertyException,
371 MultiplyDefinedException, IOException, MismatchException {
372 Document previous = base.value();
374 // RKV: Keep the new file format if it is related to the same document type on this step.
375 String newFormat = dprop.getFormat();
377 dprop.setDocument(previous, getProjectSettings().getStep(
378 base.getStep().getNumber())); // Initializes the Step property
379 if (dprop.getStep().getNumber() != aStep.getNumber()) {
380 throw new MismatchException();
383 if (newFormat != null
384 /*&& previous.getType().equals(
385 getProjectSettings().getDefaultDocumentType(
386 aStep.getStep(), newFormat))*/) {
387 dprop.setFormat(newFormat);
390 if (dprop.getAuthor() == null) {
391 dprop.setAuthor(previous.getAuthor());
393 String summary = dprop.getDescription();
395 // Creation of the document
396 Document newdoc = new Document(dprop.setOwner(aStep.getOwner())
397 .setStep(aStep.getStep()));
398 getDocumentService().generateDocumentId(newdoc, dprop);
399 getDocumentService().buildReferenceFrom(newdoc, aStep.getOwner(),
401 getDocumentDAO().create(newdoc);
404 VersionsRelation aRel;
405 aRel = new VersionsRelation(newdoc, previous, summary);
406 // getVersionsRelationDAO().create(aRel);
407 newdoc.addRelation(aRel);
409 // Update of usedby relations, if exist
411 * RKV: Consider the new version as not used by old dependent documents. So these documents must be marked as outdated then. List<Relation>
412 * relist = previous.getRelations(UsedByRelation.class); Study scope = aStep.getOwnerStudy(); for (Iterator<Relation> i =
413 * relist.iterator(); i.hasNext();) { UsedByRelation relation = (UsedByRelation) i.next(); Document relatedoc = relation.getTo(); if
414 * (scope.shares(relatedoc)) { relatedoc.addRelation(new UsesRelation(relatedoc, newdoc)); } else { relation.moveTo(newdoc); } }
416 return new Publication(newdoc, aStep.getOwner());
420 * Get document types which are applicable for the given study step (activity).
424 * @return the list of document types
426 public List<DocumentType> getValidDocumentTypes(final Step aStep) {
427 return getDocumentTypeService().selectTypesOf(aStep.getStep());
431 * Add a document publication to the given step.
434 * the target study step
436 * the document publication to add
437 * @return true if publication succeeded
439 public boolean add(final Step aStep, final Publication newdoc) {
440 boolean res = aStep.getOwner().add(newdoc); // Updates the study in memory
442 aStep.getDocuments().add(0, newdoc); // Updates this step
443 getDocumentService().hold(newdoc.value()); // Increments the configuration tag count of document
444 // If not yet saved, the Publication MUST NOT be saved here, although this creates a temporary inconsistent state into the
445 // database (it will be saved later by cascading the update of owner scenario).
451 * Remove a document publication from the given step.
456 * the document publication to remove
457 * @return true if removing of the publication succeeded
459 public boolean remove(final Step aStep, final Publication oldoc) {
460 aStep.getDocuments().remove(oldoc); // Updates this step
461 aStep.getOwner().remove(oldoc); // remove from the parent project element
462 getProjectElementDAO().merge(aStep.getOwner());
463 getDocumentService().release(oldoc.value()); // Decrements the configuration tag count of document
464 // The publication becoming orphan, it should automatically be removed from the database when updating of owner scenario.
469 * Remove a document from the given step and from the database if it is no more used.
475 * @return true if removing of the document succeeded
476 * @throws DocumentIsUsedException
477 * if the document is used by other documents
480 public boolean removeDocument(final Step aStep, final long docId)
481 throws DocumentIsUsedException {
482 Publication torem = aStep.getDocument(docId);
483 boolean res = (torem != null);
485 if (!torem.value().getRelations(UsedByRelation.class).isEmpty()) {
486 throw new DocumentIsUsedException(torem.value().getTitle());
488 remove(aStep, torem);
489 Document value = torem.value();
490 if (!value.isPublished() && !value.isVersioned()) { // The referenced document is no more used
491 List<Document> using = new ArrayList<Document>();
492 List<File> files = new ArrayList<File>();
493 for (Relation link : value.getAllRelations()) {
494 if (link.getClass().equals(ConvertsRelation.class)) { // File conversion
495 files.add((File) link.getTo());
496 } else if (link.getClass().equals(UsesRelation.class)) { // Document dependency
497 using.add((Document) link.getTo());
500 // Remove relations from depending documents
501 if (LOG.isDebugEnabled()) {
502 LOG.debug("Remove " + using.size() + " UsedByRelation(s).");
504 for (Document doc : using) {
505 if (LOG.isDebugEnabled()) {
506 LOG.debug("Remove UsedByRelation from "
507 + doc.getTitle() + " to " + value.getTitle());
508 LOG.debug("Nb relations of doc " + doc.getTitle()
509 + " before: " + doc.getAllRelations().size());
511 doc.removeRelation(UsedByRelation.class, value);
512 if (LOG.isDebugEnabled()) {
513 LOG.debug("Nb relations of doc " + doc.getTitle()
514 + " after: " + doc.getAllRelations().size());
516 getDocumentDAO().merge(doc);
518 // Synchronize deleted objects with the database to avoid hibernate exception
519 // org.hibernate.PropertyValueException: not-null property references a null or transient value
520 getDocumentDAO().flush();
521 // The corresponding physical file is not removed from the vault
522 getDocumentDAO().delete(getDocumentDAO().merge(torem.value()));
523 // Delete document's files
524 for (File file : files) {
525 getFileDAO().delete(getFileDAO().merge(file)); // The corresponding physical file is not removed from the vault
533 * Get the documentService.
535 * @return the documentService
537 public DocumentService getDocumentService() {
538 return _documentService;
542 * Set the documentService.
544 * @param documentService
545 * the documentService to set
547 public void setDocumentService(final DocumentService documentService) {
548 _documentService = documentService;
552 * Get the simulationContextService.
554 * @return the simulationContextService
556 public SimulationContextService getSimulationContextService() {
557 return _simulationContextService;
561 * Set the simulationContextService.
563 * @param simulationContextService
564 * the simulationContextService to set
566 public void setSimulationContextService(
567 final SimulationContextService simulationContextService) {
568 _simulationContextService = simulationContextService;
572 * Get the documentDAO.
574 * @return the documentDAO
576 public DocumentDAO getDocumentDAO() {
581 * Set the documentDAO.
584 * the documentDAO to set
586 public void setDocumentDAO(final DocumentDAO documentDAO) {
587 _documentDAO = documentDAO;
591 * Get the simulationContextDAO.
593 * @return the simulationContextDAO
595 public SimulationContextDAO getSimulationContextDAO() {
596 return _simulationContextDAO;
600 * Set the simulationContextDAO.
602 * @param simulationContextDAO
603 * the simulationContextDAO to set
605 public void setSimulationContextDAO(
606 final SimulationContextDAO simulationContextDAO) {
607 _simulationContextDAO = simulationContextDAO;
611 * Get the projectElementDAO.
613 * @return the projectElementDAO
615 public ProjectElementDAO getProjectElementDAO() {
616 return _projectElementDAO;
620 * Set the projectElementDAO.
622 * @param projectElementDAO
623 * the projectElementDAO to set
625 public void setProjectElementDAO(final ProjectElementDAO projectElementDAO) {
626 _projectElementDAO = projectElementDAO;
630 * Get the indexService.
632 * @return the indexService
634 public IndexService getIndexService() {
635 return _indexService;
639 * Set the indexService.
641 * @param indexService
642 * the indexService to set
644 public void setIndexService(final IndexService indexService) {
645 _indexService = indexService;
651 * @return the fileDAO
653 public FileDAO getFileDAO() {
663 public void setFileDAO(final FileDAO fileDAO) {
668 * Get the documentTypeService.
670 * @return the documentTypeService
672 public DocumentTypeService getDocumentTypeService() {
673 return _documentTypeService;
677 * Set the documentTypeService.
679 * @param documentTypeService
680 * the documentTypeService to set
682 public void setDocumentTypeService(
683 final DocumentTypeService documentTypeService) {
684 _documentTypeService = documentTypeService;
688 * Get the versionsRelationDAO.
690 * @return the versionsRelationDAO
692 public VersionsRelationDAO getVersionsRelationDAO() {
693 return _versionsRelationDAO;
697 * Set the versionsRelationDAO.
699 * @param versionsRelationDAO
700 * the versionsRelationDAO to set
702 public void setVersionsRelationDAO(
703 final VersionsRelationDAO versionsRelationDAO) {
704 _versionsRelationDAO = versionsRelationDAO;
708 * Get project settings.
710 * @return Project settings service
712 private ProjectSettingsService getProjectSettings() {
713 return _projectSettings;
717 * Set project settings service.
719 * @param projectSettingsService
720 * project settings service
722 public void setProjectSettings(
723 final ProjectSettingsService projectSettingsService) {
724 _projectSettings = projectSettingsService;
728 * Get the publicationDAO.
730 * @return the publicationDAO
732 public PublicationDAO getPublicationDAO() {
733 return _publicationDAO;
737 * Set the publicationDAO.
739 * @param publicationDAO
740 * the publicationDAO to set
742 public void setPublicationDAO(final PublicationDAO publicationDAO) {
743 this._publicationDAO = publicationDAO;
747 * Get the relationDAO.
749 * @return the relationDAO
751 public RelationDAO getRelationDAO() {
756 * Set the relationDAO.
759 * the relationDAO to set
761 public void setRelationDAO(final RelationDAO relationDAO) {
762 _relationDAO = relationDAO;