X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=Workspace%2FSiman-Common%2Fsrc%2Forg%2Fsplat%2Fservice%2FScenarioServiceImpl.java;h=794dd9029d8a799238c577c7524ad9a97a886a60;hb=7680c3b72fcb15167bdceff688a859bd517446c1;hp=464eff57440108fcbfc1ddab8534fe110a243ce4;hpb=0ee2ca9df4723c0c0547f387fd01dd5b43f10d8b;p=tools%2Fsiman.git diff --git a/Workspace/Siman-Common/src/org/splat/service/ScenarioServiceImpl.java b/Workspace/Siman-Common/src/org/splat/service/ScenarioServiceImpl.java index 464eff5..794dd90 100644 --- a/Workspace/Siman-Common/src/org/splat/service/ScenarioServiceImpl.java +++ b/Workspace/Siman-Common/src/org/splat/service/ScenarioServiceImpl.java @@ -10,28 +10,67 @@ package org.splat.service; import java.io.IOException; +import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; +import java.util.HashMap; import java.util.Iterator; import java.util.List; +import java.util.Map; +import java.util.Set; -import org.apache.log4j.Logger; +import org.hibernate.criterion.DetachedCriteria; +import org.hibernate.criterion.Order; +import org.hibernate.criterion.Projections; +import org.hibernate.criterion.Restrictions; +import org.hibernate.transform.Transformers; +import org.splat.common.properties.MessageKeyEnum; +import org.splat.dal.bo.kernel.Relation; +import org.splat.dal.bo.kernel.Role; import org.splat.dal.bo.kernel.User; +import org.splat.dal.bo.som.ConvertsRelation; +import org.splat.dal.bo.som.Document; +import org.splat.dal.bo.som.DocumentType; +import org.splat.dal.bo.som.File; import org.splat.dal.bo.som.KnowledgeElement; import org.splat.dal.bo.som.KnowledgeElementType; +import org.splat.dal.bo.som.ProgressState; +import org.splat.dal.bo.som.ProjectElement; import org.splat.dal.bo.som.Publication; import org.splat.dal.bo.som.Scenario; import org.splat.dal.bo.som.SimulationContext; +import org.splat.dal.bo.som.SimulationContextType; import org.splat.dal.bo.som.Study; +import org.splat.dal.bo.som.UsedByRelation; +import org.splat.dal.bo.som.UsesRelation; +import org.splat.dal.bo.som.ValidationCycle; +import org.splat.dal.bo.som.Document.Properties; +import org.splat.dal.dao.kernel.RoleDAO; import org.splat.dal.dao.kernel.UserDAO; import org.splat.dal.dao.som.KnowledgeElementDAO; import org.splat.dal.dao.som.KnowledgeElementTypeDAO; import org.splat.dal.dao.som.ScenarioDAO; import org.splat.dal.dao.som.StudyDAO; +import org.splat.dal.dao.som.ValidationCycleDAO; +import org.splat.exception.InvalidParameterException; +import org.splat.i18n.I18nUtils; import org.splat.kernel.InvalidPropertyException; +import org.splat.kernel.MismatchException; import org.splat.kernel.MissedPropertyException; import org.splat.kernel.MultiplyDefinedException; +import org.splat.kernel.NotApplicableException; +import org.splat.log.AppLogger; +import org.splat.service.dto.DocumentDTO; +import org.splat.service.dto.FileDTO; +import org.splat.service.dto.ScenarioDTO; +import org.splat.service.dto.StepDTO; import org.splat.service.technical.IndexService; +import org.splat.service.technical.ProjectSettingsService; +import org.splat.service.technical.RepositoryService; +import org.splat.service.technical.StepsConfigService; import org.splat.som.Step; +import org.splat.util.BeanHelper; +import org.splat.util.IOUtils; import org.springframework.transaction.annotation.Transactional; /** @@ -42,11 +81,15 @@ import org.springframework.transaction.annotation.Transactional; public class ScenarioServiceImpl implements ScenarioService { /** - * Logger for this class. + * The logger for the service. */ - protected final static Logger logger = Logger + public final static AppLogger LOG = AppLogger .getLogger(ScenarioServiceImpl.class); + /** + * " to " literal. + */ + private static final String TO = " to "; /** * Injected index service. */ @@ -96,6 +139,11 @@ public class ScenarioServiceImpl implements ScenarioService { */ private UserDAO _userDAO; + /** + * Injected role DAO. + */ + private RoleDAO _roleDAO; + /** * Injected knowledge element type DAO. */ @@ -106,6 +154,36 @@ public class ScenarioServiceImpl implements ScenarioService { */ private SimulationContextService _simulationContextService; + /** + * Injected simulation context type service. + */ + private SimulationContextTypeService _simulationContextTypeService; + + /** + * Injected project service. + */ + private ProjectSettingsService _projectSettings; + + /** + * Injected document type service. + */ + private DocumentTypeService _documentTypeService; + + /** + * Injected validation cycle DAO. + */ + private ValidationCycleDAO _validationCycleDAO; + + /** + * Injected project settings service. + */ + private StepsConfigService _stepsConfigService; + + /** + * Injected repository service. + */ + private RepositoryService _repositoryService; + /** * Get the projectElementService. * @@ -122,7 +200,7 @@ public class ScenarioServiceImpl implements ScenarioService { * the projectElementService to set */ public void setProjectElementService( - ProjectElementService projectElementService) { + final ProjectElementService projectElementService) { _projectElementService = projectElementService; } @@ -141,7 +219,8 @@ public class ScenarioServiceImpl implements ScenarioService { * @param publicationService * the publicationService to set */ - public void setPublicationService(PublicationService publicationService) { + public void setPublicationService( + final PublicationService publicationService) { _publicationService = publicationService; } @@ -160,10 +239,382 @@ public class ScenarioServiceImpl implements ScenarioService { * @param stepService * the stepService to set */ - public void setStepService(StepService stepService) { + public void setStepService(final StepService stepService) { _stepService = stepService; } + /** + * {@inheritDoc} + * + * @see org.splat.service.ScenarioService#getStudyScenarios(java.lang.Long) + */ + @Override + @Transactional(readOnly = true) + public List getStudyScenarios(final Long studyId) { + DetachedCriteria query = DetachedCriteria + .forClass(Scenario.class, "scen") + .add(Restrictions.eq("owner.rid", studyId)) + .setProjection( + Projections.projectionList().add( + Projections.property("scen.title"), "title") + .add(Projections.property("scen.rid"), "index")) + .setResultTransformer( + Transformers.aliasToBean(ScenarioDTO.class)); + return getScenarioDAO().getFilteredDTOList(query); + } + + /** + * {@inheritDoc} + * + * @see org.splat.service.ScenarioService#copyStudyContent(long, long, int, long) + */ + @Override + @Transactional + public void copyStudyContent(final long fromStudyId, final long fromScenId, + final int finalStepNum, final long toStudyId) + throws InvalidParameterException, MissedPropertyException, + InvalidPropertyException, MultiplyDefinedException, + NotApplicableException, IOException { + Study fromStudy = getStudyService().selectStudy(fromStudyId); + if (fromStudy == null) { + throw new InvalidParameterException(MessageKeyEnum.STD_000002 + .toString(), String.valueOf(fromStudyId)); + } + Scenario fromScen = null; + for (Scenario scen : fromStudy.getScenariiList()) { + if (scen.getIndex() == fromScenId) { + fromScen = scen; + break; + } + } + + Study toStudy = getStudyService().selectStudy(toStudyId); + if (toStudy == null) { + throw new InvalidParameterException(MessageKeyEnum.STD_000002 + .toString(), String.valueOf(toStudy)); + } + + // Check if the step is applied to a scenario and scenario is defined + if (fromScen == null + && getStepsConfigService().stepInvolves(finalStepNum, + Scenario.class)) { + throw new InvalidParameterException(MessageKeyEnum.SCN_000006 + .toString(), String.valueOf(fromScenId)); + } + + // Copy validation cycles + copyValidationCycles(fromStudy, toStudy); + + // Copy content of the study up to the given step + Map oldToNewPub = new HashMap(); + copyDocs(fromStudy, toStudy, finalStepNum, oldToNewPub); + if (fromScen != null) { + copyDocs(fromScen, toStudy.getScenariiList().get(0), finalStepNum, + oldToNewPub); + } + copyDependencies(fromStudy, finalStepNum, oldToNewPub); + if (fromScen != null) { + copyDependencies(fromScen, finalStepNum, oldToNewPub); + } + } + + /** + * Copy validation cycles from study to study. + * + * @param fromStudy + * the source study + * @param toStudy + * the destination study + */ + private void copyValidationCycles(final Study fromStudy, final Study toStudy) { + for (ValidationCycle fromCycle : fromStudy.getValidationCycles() + .values()) { + if (fromCycle.isAssigned()) { + ValidationCycle cycle = fromCycle.clone(toStudy); + getValidationCycleDAO().create(cycle); + toStudy.addRelation(cycle.getContext()); + toStudy.getValidationCycles().put( + cycle.getDocumentType().getName(), cycle); // Replaces the cycle if exists as default, + } + } + } + + /** + * Copy dependencies between documents from the given project element up to
+ * the given step according to the given map of old publications to new publications. + * + * @param from + * the source project element + * @param finalStepNum + * the final step for copy processing + * @param oldToNewPub + * the old to new publications map + */ + private void copyDependencies(final ProjectElement from, + final int finalStepNum, + final Map oldToNewPub) { + // Copy dependencies between copied documents + for (Publication pub : from.getDocums()) { + // If the document in the step before the final one + if (pub.value().getStep() <= finalStepNum) { + Publication newPub = oldToNewPub.get(pub); + for (Publication used : pub.getRelations(UsesRelation.class)) { + newPub.addDependency(oldToNewPub.get(used)); + } + } + } + } + + /** + * Copy documents with dependencies up to the given step. + * + * @param from + * the source project element + * @param to + * the destination project element + * @param finalStepNum + * the final step for copy process + * @param oldToNewPub2 + * @throws MissedPropertyException + * if document creation is failed + * @throws InvalidPropertyException + * if document creation is failed + * @throws MultiplyDefinedException + * if document creation is failed + * @throws IOException + * if document file creation is failed + * @throws NotApplicableException + * if document state is not applicable + * @param oldToNewPub + * the old to new publications map + * + */ + private void copyDocs(final ProjectElement from, final ProjectElement to, + final int finalStepNum, + final Map oldToNewPub) + throws MissedPropertyException, InvalidPropertyException, + MultiplyDefinedException, NotApplicableException, IOException { + Map steps = getProjectElementService().getStepsMap(to); + // Copy publications without old versions and relations to not copied steps documents + for (Publication pub : from.getDocums()) { + // If the document in the step before the final one + if (pub.value().getStep() <= finalStepNum) { + // Copy the document + oldToNewPub.put(pub, createDoc(pub.value(), steps.get(pub + .value().getStep()))); + } + } + } + + /** + * Create a copy of the given document and publish it in the given step. + * + * @param fromDoc + * the source document + * @param step + * the destination step + * @return the created publication + * @throws MissedPropertyException + * if document creation is failed + * @throws InvalidPropertyException + * if document creation is failed + * @throws MultiplyDefinedException + * if document creation is failed + * @throws IOException + * if document file creation is failed + * @throws NotApplicableException + * if document state is not applicable + */ + private Publication createDoc(final Document fromDoc, final Step step) + throws MissedPropertyException, InvalidPropertyException, + MultiplyDefinedException, IOException, NotApplicableException { + + java.io.File srcFile = fromDoc.getSourceFile().asFile(); + // Creation of the document + Document.Properties dprop = new Document.Properties().setName( + fromDoc.getTitle()).setType(fromDoc.getType()).setFormat( + fromDoc.getFormat()).setAuthor(fromDoc.getAuthor()); + + java.io.File tmpDir = getRepositoryService().getDownloadDirectory( + step.getOwnerStudy().getAuthor()); + + // Remove local file index prefix to get original filename. + java.io.File upfile = new java.io.File(tmpDir.getPath() + + "/" + + srcFile.getName().substring( + srcFile.getName().indexOf('_') + 1)); + // Copy the source file into the temporary folder with original filename. + copyFile(srcFile, upfile); + + dprop.setLocalPath(upfile.getPath()); + Publication addoc = getStepService().createDocument(step, dprop); + + // Move the temporary file into the repository + moveFile(upfile, addoc.getSourceFile().asFile()); + + getPublicationService().saveAs(addoc, fromDoc.getProgressState()); + + // Copy attached files + for (Relation rel : fromDoc.getRelations(ConvertsRelation.class)) { + File attach = ((ConvertsRelation) rel).getTo(); + ConvertsRelation export = getPublicationService().attach(addoc, + attach.getFormat()); + // Copy the source document attachment file to the new study vault + copyFile(attach.asFile(), export.getTo().asFile()); + } + return addoc; + } + + /** + * Copy a file. Print info message. + * + * @param upfile + * the source file. + * @param file + * the target file + * @throws IOException + * if failed + */ + private void copyFile(final java.io.File upfile, final java.io.File file) + throws IOException { + if (LOG.isInfoEnabled()) { + LOG.info("Copy " + upfile.getAbsolutePath() + TO + file.getPath()); + } + IOUtils.copy(upfile, file); + } + + /** + * Copy a file. Print info message. + * + * @param upfile + * the source file. + * @param file + * the target file + * @return true if renamed otherwise return false + */ + private boolean moveFile(final java.io.File upfile, final java.io.File file) { + if (LOG.isInfoEnabled()) { + LOG.info("Move " + upfile.getAbsolutePath() + TO + file.getPath()); + } + return upfile.renameTo(file); + } + + /** + * {@inheritDoc} + * + * @see org.splat.service.ScenarioService#getScenarioInfo(long) + */ + @Transactional(readOnly = true) + public List getScenarioInfo(final long scenarioId) { + List res = new ArrayList(); + // Get the scenario from the database by id + Scenario scen = getScenarioDAO().get(scenarioId); + if (LOG.isDebugEnabled()) { + LOG.debug("Scenario[" + scenarioId + "]: Number of publications: " + + scen.getDocums().size()); + } + // Get activities of the scenario + Step[] steps = getProjectElementService().getSteps(scen); + StepDTO stepDTO; + DocumentDTO docDTO; + String docType, fileFormat; + String processing; + boolean doImport; + // For each activity create a step DTO and add it to the result list + for (Step step : steps) { + stepDTO = BeanHelper.copyBean(step.getStep(), StepDTO.class); + res.add(stepDTO); + if (LOG.isDebugEnabled()) { + LOG.debug("Step[" + stepDTO.getNumber() + + "]: Number of documents: " + + step.getDocuments().size()); + } + // For each publication of the activity create a document DTO. + // Each file is considered as a source file. + for (Publication tag : step.getDocuments()) { + docDTO = stepDTO.addDoc(tag.value().getIndex(), tag.value() + .getTitle()); + char aState = tag.getIsnew(); + docType = tag.value().getType().getName(); + // For each file of the document create a file DTO + // Process source file of the document + fileFormat = tag.value().getFile().getFormat(); + doImport = getProjectSettings().doImport(docType, fileFormat); + if (doImport && (!tag.isOutdated())) { + processing = "file-import"; + } else { + processing = "file-download"; + } + File aFile = tag.value().getFile(); + docDTO.addFile(aFile.getIndex(), aFile.getRelativePath(), + aState, processing, false); + // Process all exported files + for (Relation rel : tag.value().getRelations( + ConvertsRelation.class)) { + aFile = ((ConvertsRelation) rel).getTo(); + fileFormat = aFile.getFormat(); + doImport = getProjectSettings().doImport(docType, + fileFormat); + if (doImport && (!tag.isOutdated())) { + processing = "file-import"; + } else { + processing = "file-download"; + } + docDTO.addFile(aFile.getIndex(), aFile.getRelativePath(), + aState, processing, false); + } + } + } + return res; + } + + /** + * {@inheritDoc} + * + * @see org.splat.service.ScenarioService#createStudy(java.lang.String, java.lang.String, java.lang.String, java.lang.String) + */ + @Transactional + public long createStudy(final String username, final String title, + final String productName, final String description) + throws InvalidPropertyException, MissedPropertyException, + MultiplyDefinedException { + long id = 0; + + // Find the author + User author = getUserService().selectUser(username); + if (author == null) { + // User is not found + throw new InvalidPropertyException(MessageKeyEnum.USR_000001 + .toString(), username); + } + + // Set the study properties + Study.Properties sprop = new Study.Properties(); + sprop.setTitle(title).setManager(author); + sprop.setDescription(description); + + // Find the product simulation context + SimulationContextType productContextType = getSimulationContextService() + .selectType("product"); + SimulationContext.Properties cprop = new SimulationContext.Properties(); + cprop.setType(productContextType).setValue(productName); + SimulationContext productCtx = getSimulationContextService() + .selectSimulationContext(productContextType, productName); + if (productCtx != null) { + cprop.setIndex(productCtx.getIndex()); + } + + // Set a first scenario properties + Scenario.Properties oprop = new Scenario.Properties(); + oprop.setTitle(I18nUtils.getMessageLocaleDefault("label.scenario") + + " 1"); + + Study study = createStudy(sprop, oprop, cprop); + id = study.getIndex(); + + return id; + } + /** * Create a new study with one scenario and "product" simulation context. * @@ -182,9 +633,11 @@ public class ScenarioServiceImpl implements ScenarioService { * if some property occurs several times */ @Transactional - public Study createStudy(Study.Properties sprop, Scenario.Properties oprop, - SimulationContext.Properties cprop) throws MissedPropertyException, - InvalidPropertyException, MultiplyDefinedException { + public Study createStudy(final Study.Properties sprop, + final Scenario.Properties oprop, + final SimulationContext.Properties cprop) + throws MissedPropertyException, InvalidPropertyException, + MultiplyDefinedException { Study study = getStudyService().createStudy(sprop); addScenario(study, oprop); if (cprop.getIndex() == 0) { // Input of new project context @@ -199,6 +652,41 @@ public class ScenarioServiceImpl implements ScenarioService { return study; } + /** + * {@inheritDoc} + * + * @see org.splat.service.ScenarioService#assignStudyContext(java.lang.Long, java.lang.String, java.lang.String) + */ + @Transactional + public void assignStudyContext(final Long studyId, final String ctxType, + final String ctxValue) throws MissedPropertyException, + InvalidPropertyException, MultiplyDefinedException { + // Find the study by the given id + Study study = getStudyDAO().get(studyId); + if (study == null) { + throw new InvalidPropertyException(MessageKeyEnum.STD_000002 + .toString(), studyId); + } + // Find the context type by its name + SimulationContextType celt = getSimulationContextService().selectType( + ctxType); + if (celt == null) { + // Creation of a new context type + celt = getSimulationContextTypeService().createType(ctxType, + getProjectElementService().getFirstStep(study).getStep()); + } + // Find the given context value of the given type + SimulationContext context = getSimulationContextService() + .selectSimulationContext(celt, ctxValue); + if (context == null) { // Input of a new project context + SimulationContext.Properties cprop = new SimulationContext.Properties(); + cprop.setType(celt).setValue(ctxValue); + getStudyService().addProjectContext(study, cprop); + } else { // Selection of existing project context + getStudyService().addProjectContext(study, context); + } + } + /** * {@inheritDoc} * @@ -206,76 +694,463 @@ public class ScenarioServiceImpl implements ScenarioService { * org.splat.dal.bo.som.KnowledgeElement.Properties) */ @Transactional - public KnowledgeElement addKnowledgeElement(Scenario aScenarioDTO, - KnowledgeElement.Properties kprop) throws MissedPropertyException, - InvalidPropertyException, MultiplyDefinedException { + public KnowledgeElement addKnowledgeElement(final Scenario aScenarioDTO, + final KnowledgeElement.Properties kprop) + throws MissedPropertyException, InvalidPropertyException, + MultiplyDefinedException { KnowledgeElement kelm = null; - try { - long aScenarioId = aScenarioDTO.getIndex(); - if (logger.isDebugEnabled()) { - logger.debug("Add a knowledge element to the scenario #" - + aScenarioId); - } - // Get the persistent scenario. - Scenario aScenario = getScenarioDAO().get(aScenarioId); - // Get persistent objects for creating a new knowledge. - // TODO: Actions must use DTO instead of persistent objects. - getUserDAO().merge(kprop.getAuthor()); - getKnowledgeElementTypeDAO().merge(kprop.getType()); - // Create a transient knowledge element related to the given scenario. - kelm = new KnowledgeElement(kprop.setOwnerScenario(aScenario)); - // Save the new knowledge in the database. - getKnowledgeElementDAO().create(kelm); - // Update scenario transient data. - if (kelm.getType().equals("usecase")) { - aScenarioDTO.setUcase(kelm); - } else if (aScenarioDTO.getKnowledgeElementsList() != null) { // If null, knowl will be initialized when needed - aScenarioDTO.getKnowledgeElementsList().add(kelm); + // try { + long aScenarioId = aScenarioDTO.getIndex(); + if (LOG.isDebugEnabled()) { + LOG + .debug("Add a knowledge element to the scenario #" + + aScenarioId); + } + // Get the persistent scenario. + Scenario aScenario = getScenarioDAO().get(aScenarioId); + // Get persistent objects for creating a new knowledge. + // TODO: Actions must use DTO instead of persistent objects. + getUserDAO().merge(kprop.getAuthor()); + getKnowledgeElementTypeDAO().merge(kprop.getType()); + // Create a transient knowledge element related to the given scenario. + kelm = new KnowledgeElement(kprop.setOwnerScenario(aScenario)); + // Save the new knowledge in the database. + getKnowledgeElementDAO().create(kelm); + // Update scenario transient data. + if (kelm.getType().equals("usecase")) { + aScenarioDTO.setUcase(kelm); + } else if (aScenarioDTO.getKnowledgeElementsList() != null) { // If null, knowl will be initialized when needed + aScenarioDTO.getKnowledgeElementsList().add(kelm); + } + + // Load the workflow for the parent study to take into account + // all study actors durng reindexing. + getStudyService().loadWorkflow(aScenario.getOwnerStudy()); + + // // Update the lucene index of knowledge elements. + // getIndexService().add(kelm); + if (LOG.isDebugEnabled()) { + LOG.debug("A knowledge element #" + kelm.getIndex() + + " is added to the scenario #" + aScenario.getIndex()); + } + // } catch (IOException error) { + // LOG.error("Unable to index the knowedge element '" + // + kelm.getIndex() + "', reason:", error); + // kelm = null; + // } + + return kelm; + } + + /** + * {@inheritDoc} + * + * @see org.splat.service.ScenarioService#checkin(long, long, java.util.List) + */ + @Transactional + public void checkin(final long scenId, final long userId, + final List scInfo) throws InvalidPropertyException, + MissedPropertyException, MultiplyDefinedException, + MismatchException, IOException, NotApplicableException { + // Get the scenario from the database by id + Scenario aScenario = getScenarioDAO().get(scenId); + // Get the user who perform this check-in operation + User aUser = getUserService().selectUser(userId); + // Get activities of the scenario + Step[] steps = getProjectElementService().getSteps(aScenario); + // Find result document types + List resTypes = getDocumentTypeService() + .selectResultTypes(); + + // Keep newly created documents to create uses relations to results of a previous step. + // For each processed existing document keep its new version + Map newVersion = new HashMap(); + // Created publications of new created versions of existing documents + List newVers = new ArrayList(); + // The list of publications of new created documents not existing before the checkin + List newDocs = new ArrayList(); + // For each step DTO + DocumentType resType; + Date aDate = new Date(); // The timestamp of the checkin operation + for (StepDTO stepDTO : scInfo) { + if (LOG.isDebugEnabled()) { + LOG.debug("Checkin the step:\n" + stepDTO); } - // Update the lucene index of knowledge elements. - getIndexService().add(kelm); - if (logger.isDebugEnabled()) { - logger.debug("A knowledge element #" + kelm.getIndex() - + " is added to the scenario #" + aScenario.getIndex()); + // Find a result document type of the step + int i = 0; + resType = null; + do { + if (resTypes.get(i).isResultOf( + getProjectSettings().getStep(stepDTO.getNumber()))) { + resType = resTypes.get(i); + } + i++; + } while ((resType == null) && (i < resTypes.size())); + + // Find the appropriate scenario step + Step step = findStep(stepDTO, steps); + + // Process each document of the step + for (DocumentDTO doc : stepDTO.getDocs()) { + checkinDoc(step, doc, aUser, resType, aDate, newVersion, + newVers, newDocs); } - } catch (IOException error) { - logger.error("Unable to index the knowedge element '" - + kelm.getIndex() + "', reason:", error); - kelm = null; } - return kelm; + // Set uses/used relations + updateRelationsAfterCheckin(aScenario, newVersion, newVers, newDocs); + + // Mark the scenario as checked in + checkin(aScenario); } /** - * Update the scenario in the database. + * Updated uses/used relations after checkin operation:
+ *
    + *
  • For each new version copy uses relations from the previous version.
  • + *
  • Outdate documents which depend from the previous version and were not checked in during this operation.
  • + *
  • For each new document create uses relation to the last versions of results of the previous step.
  • + *
* * @param aScenario - * the scenario to update - * @return true if updating succeeded + * the checked in scenario + * @param newVersion + * the mapping of documents existed before the checkin to their new created versions + * @param newVers + * the list of publications of new created versions of documents existed before the checkin + * @param newDocs + * the list of publications of new created documents not existed before the checkin */ - @Transactional - private boolean update(Scenario aScenario) { - boolean isOk = false; - try { - getScenarioDAO().update(aScenario); // Update of relational base - isOk = true; - } catch (Exception error) { - logger.error("Unable to re-index the knowledge element '" - + aScenario.getIndex() + "', reason:", error); + private void updateRelationsAfterCheckin(final Scenario aScenario, + final Map newVersion, + final List newVers, final List newDocs) { + // For each new version copy uses relations from the previous version. + for (Publication newVer : newVers) { + // For each Uses relation of the previous version + Document prevDoc = newVer.value().getPreviousVersion();// prevVersion.get(newVer); + if (LOG.isDebugEnabled()) { + LOG.debug("Previous version for publication #" + + newVer.getIndex() + " is found: " + prevDoc); + } + List usesRelations = prevDoc + .getRelations(UsesRelation.class); + for (Relation rel : usesRelations) { + // If used document has been also versioned then refer to its new version. + Document usedDoc = ((UsesRelation) rel).getTo(); + if (newVersion.containsKey(usedDoc)) { + usedDoc = newVersion.get(usedDoc); + } + // Build the appropriate relation for the new version. + newVer.addDependency(usedDoc); + } + // Outdate documents which depend from the previous version and + // were not checked in during this operation. + // 1. Get all usedBy relations of the previous document version + for (Relation rel : prevDoc.getRelations(UsedByRelation.class)) { + Document using = ((UsedByRelation) rel).getTo(); + // Check that not checked in dependent documents became outdated + Publication usingPub = aScenario.getPublication(using); + if (usingPub != null) { // if the document using the old version is still published + usingPub.setIsnew('O'); + } + } + } + + // For each new document create uses relation to the last versions of + // results of the previous step. + for (Publication newPub : newDocs) { + // Find used document type according to the configuration. + Set usedTypes = newPub.value().getType() + .getDefaultUses(); + // Find documents of used type in the previous study step. + for (Publication pub : aScenario.getDocums()) { + if ((pub.getStep().getNumber() <= newPub.getStep().getNumber()) + && (!pub.isOutdated()) + && usedTypes.contains(pub.value().getType())) { + // Create uses relation from the new document + // to the found document in the previous step. + newPub.addDependency(pub); + } + } } - return isOk; + } + + /** + * Pure checkin of the document without creation of uses/usedBy relations. For an existing document a new version is created. New + * documents become published in the given step of the appropriate scenario. The appropriate uploaded file is attached to the created + * document and the document is published in the scenario. The publication of the old version is removed from the scenario. + * + * @param step + * the destination scenario step + * @param doc + * the DTO of the document to checkin + * @param aUser + * the user who performs checkin + * @param resType + * the result document type of the given step + * @param aDate + * timestamp of the checkin operation + * @param newVersion + * the mapping of existing documents to their new created versions + * @param newVers + * the list of publications of new created versions of existing documents + * @param newDocs + * the list of publications of new created documents not existing before the checkin + * @throws InvalidPropertyException + * if the scenario hasn't some of given steps or documents + * @throws IOException + * if a file can't be moved into the vault + * @throws MismatchException + * if version creation in some of steps is failed + * @throws MissedPropertyException + * if some mandatory property is missed when new document or new document version is created + * @throws MultiplyDefinedException + * if some property is defined several times when new document or new document version is created + * @throws NotApplicableException + * if failed saving of a new publication with a given state + */ + private void checkinDoc(final Step step, final DocumentDTO doc, + final User aUser, final DocumentType resType, final Date aDate, + final Map newVersion, + final List newVers, final List newDocs) + throws InvalidPropertyException, MismatchException, + MissedPropertyException, MultiplyDefinedException, IOException, + NotApplicableException { + if (doc.getFiles().size() > 0) { + Document.Properties dprop = new Document.Properties(); + // NOTE: Process only the first attached file for each document + FileDTO file = doc.getFiles().get(0); + dprop.setLocalPath(file.getPath()); + + // Get document title as the file name + java.io.File upfile = new java.io.File(file.getPath()); + String fileFormat = upfile.getName().substring( + upfile.getName().lastIndexOf('.') + 1); + + // Attach the file via ConvertsRelation, create a new document or + // create a new version of the document + dprop.setAuthor(aUser).setDate(aDate).setFormat(fileFormat); + + if (doc.getId() > 0) { + checkinExistingDoc(step, doc, dprop, fileFormat, upfile, + newVersion, newVers); + } else { + + // Otherwise create a new document of the result type + // If result type is not found try to get type by file extension + if (resType == null) { + dprop.setType(getProjectSettings().getDefaultDocumentType( + step.getStep(), fileFormat)); + } else { + dprop.setType(resType); + } + // New document title generation as _N + String docname = dprop.getType().getName(); + int i = 1; + for (Publication scenPub : step.getOwner().getDocums()) { + if (scenPub.value().getTitle().startsWith(docname)) { + i++; + } + } + docname += "_" + i; // The generated new document title + + dprop.setDescription("Checked in").setName(docname); + Publication newPub = getStepService().createDocument(step, + dprop); + + // Remember the new document + newDocs.add(newPub); + + saveFile(newPub, step, upfile); + } + } + } + + /** + * Check in existing document. + * + * @param step + * study step to check in + * @param doc + * document DTO to check in + * @param dprop + * document properties + * @param fileFormat + * checked in file format + * @param upfile + * the file to check in + * @param newVersion + * the map of created versions during this check in + * @param newVers + * the list of new versions created during this check in + * @throws InvalidPropertyException + * if publication of the document is not found in the step + * @throws MismatchException + * if the found publication does not point to a document + * @throws IOException + * if can not move the file into the vault + * @throws MultiplyDefinedException + * thrown by versionDocument + * @throws MissedPropertyException + * thrown by versionDocument + * @throws NotApplicableException + * if failed saving of a new publication with a given state + */ + private void checkinExistingDoc(final Step step, final DocumentDTO doc, + final Properties dprop, final String fileFormat, + final java.io.File upfile, + final Map newVersion, + final List newVers) throws InvalidPropertyException, + MismatchException, MissedPropertyException, + MultiplyDefinedException, IOException, NotApplicableException { + // If the document already exists then + // Attach the file via ConvertsRelation if the extension of the + // new file differs from the old one. + // If file format (i.e. extension) is the same then create a new + // version of the document. + // Find the document publication + Publication pub = step.getDocument(doc.getId()); + if (pub == null) { + throw new InvalidPropertyException(MessageKeyEnum.SCN_000002 + .toString(), doc.getId()); + } + if (pub.value() == null) { + throw new MismatchException(MessageKeyEnum.SCN_000002.toString(), + doc.getId()); + } + if (LOG.isDebugEnabled()) { + LOG.debug("Old format: " + pub.value().getFormat() + + " => New format: " + fileFormat); + } + // If formats are same then create a new document version + if (pub.value().getFormat() != null + && pub.value().getFormat().equals(fileFormat)) { + Publication newPub = getStepService().versionDocument(step, pub, + dprop); + if (LOG.isDebugEnabled()) { + LOG.debug("Created document type: " + + newPub.value().getType().getName() + ", format: " + + newPub.value().getFormat()); + } + // Remeber the link from the old document to the new document version + newVersion.put(pub.value(), newPub.value()); + // Remember the new version publication + newVers.add(newPub); + + saveFile(newPub, step, upfile); + + } else { // If formats are different then attach the new file via ConvertsRelation + File attach = pub.value().getAttachedFile(fileFormat); + if (attach == null) { + // If there is no attachment with this extension then attach the new one + ConvertsRelation export = getPublicationService().attach(pub, + fileFormat); + moveFile(upfile, export.getTo().asFile()); + } else { + // If an attachment with this extension already exists then + // replace it by the new one + moveFile(upfile,attach.asFile()); + // Update attached file modification date + attach.setDate(new Date()); + } + } + } + + /** + * Save the file in the vault and create its publication in the step. + * + * @param newPub + * the new publication to save + * @param step + * the study step to publish the document + * @param upfile + * the downloaded file + * @throws IOException + * if a file can't be moved into the vault + * @throws NotApplicableException + * if failed saving of a new publication with a given state + */ + private void saveFile(final Publication newPub, final Step step, + final java.io.File upfile) throws IOException, + NotApplicableException { + // Attach the file to the created document + java.io.File updir = newPub.getSourceFile().asFile(); + if (updir.exists()) { + if (updir.delete()) { + LOG.info(MessageKeyEnum.SCN_000003.toString(), updir + .getAbsoluteFile(), step.getOwner().getIndex()); + } else { + throw new IOException( + "Can't delete the existing destination file to move file from " + + upfile.getAbsolutePath() + TO + + updir.getAbsolutePath()); + } + } + if (moveFile(upfile, updir)) { + // Save the new publication in the scenario. + // The old publication is removed from the scenario here. + getPublicationService().saveAs(newPub, ProgressState.inWORK); // May throw FileNotFound if rename was not done + } else { + throw new IOException("Can't move file from " + + upfile.getAbsolutePath() + TO + updir.getAbsolutePath()); + } + } + + /** + * Find appropriate step in the array of scenario steps according to the given step DTO. + * + * @param stepDTO + * the stepDTO + * @param steps + * scenario steps + * @return appropriate scenario step + * @throws InvalidPropertyException + * if appropriate step is not found + */ + private Step findStep(final StepDTO stepDTO, final Step[] steps) + throws InvalidPropertyException { + int i = 0; + Step step = null; + do { + if (steps[i].getNumber() == stepDTO.getNumber()) { + step = steps[i]; + } + i++; + } while ((step == null) && (i < steps.length)); + + if (step == null) { + throw new InvalidPropertyException(MessageKeyEnum.SCN_000001 + .toString(), stepDTO.getNumber()); + } + return step; } /** * {@inheritDoc} * - * @see org.splat.service.ScenarioService#checkin(org.splat.dal.bo.som.Scenario) + * @see org.splat.service.ScenarioService#checkin(long) + */ + @Transactional + public void checkin(final long scenarioId) throws InvalidPropertyException { + Scenario aScenario = getScenarioDAO().get(scenarioId); + if (aScenario == null) { + // Scenario not found + throw new InvalidPropertyException(MessageKeyEnum.SCN_000006 + .toString(), scenarioId); + } + checkin(aScenario); + } + + /** + * Mark the scenario as checked in. + * + * @param aScenario + * the scenario to check in. */ - public void checkin(Scenario aScenario) { + private void checkin(final Scenario aScenario) { aScenario.setUser(null); aScenario.setLastModificationDate(Calendar.getInstance().getTime()); - getScenarioDAO().update(aScenario); + // getScenarioDAO().update(aScenario); } /** @@ -283,14 +1158,61 @@ public class ScenarioServiceImpl implements ScenarioService { * * @see org.splat.service.ScenarioService#checkout(org.splat.dal.bo.som.Scenario, org.splat.dal.bo.kernel.User) */ - public boolean checkout(Scenario aScenario, User user) { - if (!getStudyService().isStaffedBy(aScenario.getOwnerStudy(), user)) - return false; + public boolean checkout(final Scenario aScenario, final User user) { + boolean res = getStudyService().isStaffedBy(aScenario.getOwnerStudy(), + user); + if (res) { + aScenario.setUser(user); + aScenario.setLastModificationDate(Calendar.getInstance().getTime()); + // RKV: getScenarioDAO().update(aScenario); + } + return res; + } - aScenario.setUser(user); - aScenario.setLastModificationDate(Calendar.getInstance().getTime()); - getScenarioDAO().update(aScenario); - return true; + /** + * Mark the given scenario as checked out by the given user. + * + * @param scenarioId + * the scenario id + * @param userId + * the id of the user performing the check out + * @throws InvalidPropertyException + * if the user or the scenario is not found in the database + * @throws NotApplicableException + * if the given user can not check out the scenario + */ + @Transactional + public void checkout(final long scenarioId, final long userId) + throws InvalidPropertyException, NotApplicableException { + User aUser = getUserService().selectUser(userId); + if (aUser == null) { + // User not found + throw new InvalidPropertyException(MessageKeyEnum.USR_000001 + .toString(), userId); + } + Scenario aScenario = getScenarioDAO().get(scenarioId); + if (aScenario == null) { + // Scenario not found + throw new InvalidPropertyException(MessageKeyEnum.SCN_000006 + .toString(), scenarioId); + } + boolean res = getStudyService().isStaffedBy(aScenario.getOwnerStudy(), + aUser); + if (res) { + if (aScenario.isCheckedout() + && (!aScenario.getUser().getUsername().equals( + aUser.getUsername()))) { + throw new NotApplicableException(MessageKeyEnum.SCN_000008 + .toString(), scenarioId, aScenario.getUser() + .getUsername()); + } + aScenario.setUser(aUser); + aScenario.setLastModificationDate(Calendar.getInstance().getTime()); + } else { + // User doesn't participate in the scenario + throw new NotApplicableException(MessageKeyEnum.SCN_000007 + .toString(), aUser.getUsername(), scenarioId); + } } /** @@ -298,14 +1220,15 @@ public class ScenarioServiceImpl implements ScenarioService { * * @see org.splat.service.ScenarioService#copyContentsUpTo(org.splat.dal.bo.som.Scenario, org.splat.som.Step) */ - public void copyContentsUpTo(Scenario scenario, Step lastep) { + public void copyContentsUpTo(final Scenario scenario, final Step lastep) { Scenario base = (Scenario) lastep.getOwner(); Step[] from = getProjectElementService().getSteps(base); Step[] to = getProjectElementService().getSteps(scenario); for (int i = 0; i < from.length; i++) { Step step = from[i]; - if (step.getNumber() > lastep.getNumber()) + if (step.getNumber() > lastep.getNumber()) { break; + } List docs = step.getAllDocuments(); for (Iterator j = docs.iterator(); j.hasNext();) { @@ -326,7 +1249,7 @@ public class ScenarioServiceImpl implements ScenarioService { * * @see org.splat.service.ScenarioService#isEmpty(org.splat.dal.bo.som.Scenario) */ - public boolean isEmpty(Scenario scenario) { + public boolean isEmpty(final Scenario scenario) { Step[] mystep = getProjectElementService().getSteps(scenario); boolean isEmp = true; for (int i = 0; i < mystep.length; i++) { @@ -342,14 +1265,16 @@ public class ScenarioServiceImpl implements ScenarioService { * @param scenario * @return */ - public boolean isFinished(Scenario scenario) { + public boolean isFinished(final Scenario scenario) { Step[] mystep = getProjectElementService().getSteps(scenario); boolean notempty = false; // If this is empty, this is not finished for (int i = 0; i < mystep.length; i++) { - if (!mystep[i].isStarted()) + if (!mystep[i].isStarted()) { continue; - if (!mystep[i].isFinished()) + } + if (!mystep[i].isFinished()) { return false; + } notempty = true; } return notempty; @@ -361,15 +1286,17 @@ public class ScenarioServiceImpl implements ScenarioService { * @see org.splat.service.StudyService#addScenario(org.splat.dal.bo.som.Study, org.splat.dal.bo.som.Scenario.Properties) */ @Transactional - public Scenario addScenario(Study aStudy, Scenario.Properties sprop) - throws MissedPropertyException, InvalidPropertyException, - MultiplyDefinedException { - if (sprop.getManager() == null) + public Scenario addScenario(final Study aStudy, + final Scenario.Properties sprop) throws MissedPropertyException, + InvalidPropertyException, MultiplyDefinedException { + if (sprop.getManager() == null) { sprop.setManager(aStudy.getAuthor()); + } Scenario scenario = new Scenario(sprop.setOwnerStudy(aStudy)); - if (sprop.getBaseStep() != null) + if (sprop.getBaseStep() != null) { copyContentsUpTo(scenario, sprop.getBaseStep()); + } Scenario previous = sprop.getInsertAfter(); if (previous == null) { @@ -387,7 +1314,13 @@ public class ScenarioServiceImpl implements ScenarioService { KnowledgeElementType ucase = getKnowledgeElementTypeService() .selectType("usecase"); KnowledgeElement.Properties kprop = new KnowledgeElement.Properties(); - User admin = getUserService().selectUser(1); // First user created when creating the database + // TODO: Get appropriate user by its role: UserService.getAdmin(); + // User admin = getUserService().selectUser(1); // First user created when creating the database + Role adminRole = getRoleDAO().getFilteredList( + Restrictions.like("role", "%sysadmin%")).get(0); + User admin = getUserDAO().getFilteredList( + Restrictions.eq("role", adminRole), Order.asc("rid")).get(0); // First sysadmin in the database + kprop.setType(ucase).setTitle(aStudy.getTitle()).setValue( scenario.getTitle()).setAuthor(admin); // Internal Knowledge Element required by the validation process of // knowledges @@ -404,26 +1337,38 @@ public class ScenarioServiceImpl implements ScenarioService { * the knowledge element to remove * @return true if removal succeeded */ - public boolean removeKnowledgeElement(Scenario scenario, - KnowledgeElement kelm) { + @Transactional + public boolean removeKnowledgeElement(final Scenario scenario, + final KnowledgeElement kelm) { KnowledgeElement torem = scenario.getKnowledgeElement(kelm.getIndex()); - if (torem == null) - return false; - boolean done = scenario.getKnowledgeElements().remove(torem); - if (done) { - // Update of my transient data - // RKV: These transient data are not used indeed. - // RKV: List kelms = scenario.getKnowledgeByType().get( - // RKV: kelm.getType().getIndex()); - // RKV: kelms.remove(torem); - if (scenario.getKnowledgeElementsList() != null) - scenario.getKnowledgeElementsList().remove(torem); - getScenarioDAO().update(scenario); - // TODO: If the owner study is not private, remove the knowledge from the Lucene index - return true; - } else { - return false; + boolean isOk = (torem != null); + if (isOk) { + isOk = scenario.getKnowledgeElements().remove(torem); + if (isOk) { + getScenarioDAO().merge(scenario); + // Update of my transient data + // RKV: These transient data are not used indeed. + // RKV: List kelms = scenario.getKnowledgeByType().get( + // RKV: kelm.getType().getIndex()); + // RKV: kelms.remove(torem); + if (scenario.getKnowledgeElementsList() != null) { + scenario.getKnowledgeElementsList().remove(torem); + } + // TODO: If the owner study is not private, remove the knowledge from the Lucene index + } } + return isOk; + } + + /** + * + * {@inheritDoc} + * + * @see org.splat.service.ScenarioService#renameScenario(java.lang.String) + */ + @Transactional + public void renameScenario(final Scenario scenario) { + getScenarioDAO().merge(scenario); } /** @@ -441,7 +1386,8 @@ public class ScenarioServiceImpl implements ScenarioService { * @param knowledgeElementDAO * the knowledgeElementDAO to set */ - public void setKnowledgeElementDAO(KnowledgeElementDAO knowledgeElementDAO) { + public void setKnowledgeElementDAO( + final KnowledgeElementDAO knowledgeElementDAO) { _knowledgeElementDAO = knowledgeElementDAO; } @@ -460,7 +1406,7 @@ public class ScenarioServiceImpl implements ScenarioService { * @param indexService * the indexService to set */ - public void setIndexService(IndexService indexService) { + public void setIndexService(final IndexService indexService) { _indexService = indexService; } @@ -479,7 +1425,7 @@ public class ScenarioServiceImpl implements ScenarioService { * @param scenarioDAO * the scenarioDAO to set */ - public void setScenarioDAO(ScenarioDAO scenarioDAO) { + public void setScenarioDAO(final ScenarioDAO scenarioDAO) { _scenarioDAO = scenarioDAO; } @@ -498,7 +1444,7 @@ public class ScenarioServiceImpl implements ScenarioService { * @param studyDAO * the studyDAO to set */ - public void setStudyDAO(StudyDAO studyDAO) { + public void setStudyDAO(final StudyDAO studyDAO) { _studyDAO = studyDAO; } @@ -518,7 +1464,7 @@ public class ScenarioServiceImpl implements ScenarioService { * the knowledgeElementTypeService to set */ public void setKnowledgeElementTypeService( - KnowledgeElementTypeService knowledgeElementTypeService) { + final KnowledgeElementTypeService knowledgeElementTypeService) { _knowledgeElementTypeService = knowledgeElementTypeService; } @@ -537,7 +1483,7 @@ public class ScenarioServiceImpl implements ScenarioService { * @param studyService * the studyService to set */ - public void setStudyService(StudyService studyService) { + public void setStudyService(final StudyService studyService) { _studyService = studyService; } @@ -556,7 +1502,7 @@ public class ScenarioServiceImpl implements ScenarioService { * @param userService * the userService to set */ - public void setUserService(UserService userService) { + public void setUserService(final UserService userService) { _userService = userService; } @@ -575,7 +1521,7 @@ public class ScenarioServiceImpl implements ScenarioService { * @param userDAO * the userDAO to set */ - public void setUserDAO(UserDAO userDAO) { + public void setUserDAO(final UserDAO userDAO) { _userDAO = userDAO; } @@ -595,7 +1541,7 @@ public class ScenarioServiceImpl implements ScenarioService { * the knowledgeElementTypeDAO to set */ public void setKnowledgeElementTypeDAO( - KnowledgeElementTypeDAO knowledgeElementTypeDAO) { + final KnowledgeElementTypeDAO knowledgeElementTypeDAO) { _knowledgeElementTypeDAO = knowledgeElementTypeDAO; } @@ -615,8 +1561,146 @@ public class ScenarioServiceImpl implements ScenarioService { * the simulationContextService to set */ public void setSimulationContextService( - SimulationContextService simulationContextService) { + final SimulationContextService simulationContextService) { _simulationContextService = simulationContextService; } + /** + * Get project settings. + * + * @return Project settings service + */ + private ProjectSettingsService getProjectSettings() { + return _projectSettings; + } + + /** + * Set project settings service. + * + * @param projectSettingsService + * project settings service + */ + public void setProjectSettings( + final ProjectSettingsService projectSettingsService) { + _projectSettings = projectSettingsService; + } + + /** + * Get the documentTypeService. + * + * @return the documentTypeService + */ + public DocumentTypeService getDocumentTypeService() { + return _documentTypeService; + } + + /** + * Set the documentTypeService. + * + * @param documentTypeService + * the documentTypeService to set + */ + public void setDocumentTypeService( + final DocumentTypeService documentTypeService) { + _documentTypeService = documentTypeService; + } + + /** + * Get the roleDAO. + * + * @return the roleDAO + */ + public RoleDAO getRoleDAO() { + return _roleDAO; + } + + /** + * Set the roleDAO. + * + * @param roleDAO + * the roleDAO to set + */ + public void setRoleDAO(final RoleDAO roleDAO) { + _roleDAO = roleDAO; + } + + /** + * Get the simulationContextTypeService. + * + * @return the simulationContextTypeService + */ + public SimulationContextTypeService getSimulationContextTypeService() { + return _simulationContextTypeService; + } + + /** + * Set the simulationContextTypeService. + * + * @param simulationContextTypeService + * the simulationContextTypeService to set + */ + public void setSimulationContextTypeService( + final SimulationContextTypeService simulationContextTypeService) { + _simulationContextTypeService = simulationContextTypeService; + } + + /** + * Get the validationCycleDAO. + * + * @return the validationCycleDAO + */ + public ValidationCycleDAO getValidationCycleDAO() { + return _validationCycleDAO; + } + + /** + * Set the validationCycleDAO. + * + * @param validationCycleDAO + * the validationCycleDAO to set + */ + public void setValidationCycleDAO( + final ValidationCycleDAO validationCycleDAO) { + _validationCycleDAO = validationCycleDAO; + } + + /** + * Get steps config. + * + * @return steps config service + */ + private StepsConfigService getStepsConfigService() { + return _stepsConfigService; + } + + /** + * Set steps config service. + * + * @param stepsConfigService + * steps config service + */ + public void setStepsConfigService( + final StepsConfigService stepsConfigService) { + _stepsConfigService = stepsConfigService; + } + + /** + * Get the repositoryService. + * + * @return the repositoryService + */ + public RepositoryService getRepositoryService() { + return _repositoryService; + } + + /** + * Set the repositoryService. + * + * @param repositoryService + * the repositoryService to set + */ + public void setRepositoryService(final RepositoryService repositoryService) { + _repositoryService = repositoryService; + } + }