Java tutorial
/* * Copyright and authors: see LICENSE.txt in base repository. * * This software is a web portal for pipeline execution on distributed systems. * * This software is governed by the CeCILL-B license under French law and * abiding by the rules of distribution of free software. You can use, * modify and/ or redistribute the software under the terms of the CeCILL-B * license as circulated by CEA, CNRS and INRIA at the following URL * "http://www.cecill.info". * * As a counterpart to the access to the source code and rights to copy, * modify and redistribute granted by the license, users are provided only * with a limited warranty and the software's author, the holder of the * economic rights, and the successive licensors have only limited * liability. * * In this respect, the user's attention is drawn to the risks associated * with loading, using, modifying and/or developing or reproducing the * software by the user in light of its specific status of free software, * that may mean that it is complicated to manipulate, and that also * therefore means that it is reserved for developers and experienced * professionals having in-depth computer knowledge. Users are therefore * encouraged to load and test the software's suitability as regards their * requirements in conditions enabling the security of their systems and/or * data to be ensured and, more generally, to use and operate it in the * same conditions as regards security. * * The fact that you are presently reading this means that you have had * knowledge of the CeCILL-B license and that you accept its terms. */ package fr.insalyon.creatis.vip.application.server.business; import fr.insalyon.creatis.grida.client.GRIDAClient; import fr.insalyon.creatis.grida.client.GRIDAClientException; import fr.insalyon.creatis.grida.client.GRIDAPoolClient; import fr.insalyon.creatis.moteur.plugins.workflowsdb.bean.Input; import fr.insalyon.creatis.moteur.plugins.workflowsdb.bean.Output; import fr.insalyon.creatis.moteur.plugins.workflowsdb.bean.Processor; import fr.insalyon.creatis.moteur.plugins.workflowsdb.bean.Workflow; import fr.insalyon.creatis.moteur.plugins.workflowsdb.bean.WorkflowStatus; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.InputDAO; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.OutputDAO; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.ProcessorDAO; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.StatsDAO; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.WorkflowDAO; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.WorkflowsDBDAOException; import fr.insalyon.creatis.moteur.plugins.workflowsdb.dao.WorkflowsDBDAOFactory; import fr.insalyon.creatis.vip.application.client.ApplicationConstants; import fr.insalyon.creatis.vip.application.client.bean.AppVersion; import fr.insalyon.creatis.vip.application.client.bean.Descriptor; import fr.insalyon.creatis.vip.application.client.bean.InOutData; import fr.insalyon.creatis.vip.application.client.bean.Activity; import fr.insalyon.creatis.vip.application.client.bean.Engine; import fr.insalyon.creatis.vip.application.client.bean.Simulation; import fr.insalyon.creatis.vip.application.client.view.monitor.SimulationStatus; import fr.insalyon.creatis.vip.application.client.view.monitor.progress.ProcessorStatus; import fr.insalyon.creatis.vip.application.server.business.simulation.ParameterSweep; import fr.insalyon.creatis.vip.application.server.business.simulation.parser.GwendiaParser; import fr.insalyon.creatis.vip.application.server.business.simulation.parser.InputM2Parser; import fr.insalyon.creatis.vip.application.server.business.simulation.parser.ScuflParser; import fr.insalyon.creatis.vip.application.server.dao.ApplicationDAO; import fr.insalyon.creatis.vip.application.server.dao.ApplicationDAOFactory; import fr.insalyon.creatis.vip.application.server.dao.SimulationStatsDAO; import fr.insalyon.creatis.vip.application.server.dao.SimulationStatsDAOFactory; import fr.insalyon.creatis.vip.core.client.bean.User; import fr.insalyon.creatis.vip.core.client.view.CoreConstants; import fr.insalyon.creatis.vip.core.server.business.BusinessException; import fr.insalyon.creatis.vip.core.server.business.CoreUtil; import fr.insalyon.creatis.vip.core.server.business.Server; import fr.insalyon.creatis.vip.core.server.dao.CoreDAOFactory; import fr.insalyon.creatis.vip.core.server.dao.DAOException; import fr.insalyon.creatis.vip.datamanager.client.view.DataManagerException; import fr.insalyon.creatis.vip.datamanager.server.DataManagerUtil; import fr.insalyon.creatis.vip.datamanager.server.business.DataManagerBusiness; import java.io.File; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Random; import java.util.logging.Level; import org.apache.commons.io.FileUtils; import org.apache.commons.io.FilenameUtils; import org.apache.log4j.Logger; /** * * @author Rafael Ferreira da Silva */ public class WorkflowBusiness { private static final Logger logger = Logger.getLogger(WorkflowBusiness.class); private static ApplicationDAO applicationDB; private static SimulationStatsDAO simulationStatsDAO; private static WorkflowDAO workflowDAO; private static ProcessorDAO processorDAO; private static OutputDAO outputDAO; private static InputDAO inputDAO; private static StatsDAO statsDAO; private final EngineBusiness engineBusiness; public WorkflowBusiness() { engineBusiness = new EngineBusiness(); try { applicationDB = ApplicationDAOFactory.getDAOFactory().getApplicationDAO(); simulationStatsDAO = SimulationStatsDAOFactory.getInstance().getSimulationStatsDAO(); workflowDAO = WorkflowsDBDAOFactory.getInstance().getWorkflowDAO(); processorDAO = WorkflowsDBDAOFactory.getInstance().getProcessorDAO(); outputDAO = WorkflowsDBDAOFactory.getInstance().getOutputDAO(); inputDAO = WorkflowsDBDAOFactory.getInstance().getInputDAO(); statsDAO = WorkflowsDBDAOFactory.getInstance().getStatsDAO(); } catch (DAOException ex) { logger.error(ex); } catch (WorkflowsDBDAOException ex) { logger.error(ex); } } private Engine selectEngine(String applicationClass) throws BusinessException { long min = Integer.MAX_VALUE; Engine engineBean = null; try { List<Engine> availableEngines = ApplicationDAOFactory.getDAOFactory().getEngineDAO() .getByClass(applicationClass); for (Engine engine : availableEngines) { long runningWorkflows = workflowDAO.getNumberOfRunningPerEngine(engine.getEndpoint()); if (runningWorkflows < min) { min = runningWorkflows; engineBean = engine; } } } catch (DAOException ex) { throw new BusinessException(ex); } catch (WorkflowsDBDAOException ex) { java.util.logging.Logger.getLogger(WorkflowBusiness.class.getName()).log(Level.SEVERE, null, ex); } if (engineBean == null || engineBean.getEndpoint().isEmpty()) { throw new BusinessException("No available engines for class " + applicationClass); } else { return engineBean; } } private Engine selectRandomEngine(String applicationClass) throws BusinessException { Engine engineBean = null; try { List<Engine> availableEngines = ApplicationDAOFactory.getDAOFactory().getEngineDAO() .getByClass(applicationClass); Random randomizer = new Random(); engineBean = availableEngines.get(randomizer.nextInt(availableEngines.size())); } catch (DAOException ex) { throw new BusinessException(ex); } if (engineBean == null || engineBean.getEndpoint().isEmpty()) { throw new BusinessException("No available engines for class " + applicationClass); } return engineBean; } /** * * @param user * @param groups * @param parametersMap * @param applicationName * @param applicationVersion * @param applicationClass * @param simulationName * @return * @throws BusinessException */ public synchronized String launch(User user, List<String> groups, Map<String, String> parametersMap, String applicationName, String applicationVersion, String applicationClass, String simulationName) throws BusinessException { try { long runningWorkflows = workflowDAO.getNumberOfRunning(user.getFullName()); long runningSimulations = workflowDAO.getRunning().size(); if (runningSimulations >= Server.getInstance().getMaxPlatformRunningSimulations()) { logger.warn("Unable to launch execution '" + simulationName + "': max " + "number of running workflows reached in the platform."); throw new fr.insalyon.creatis.vip.core.server.business.BusinessException( "Max number of running executions reached."); } if (runningWorkflows >= user.getMaxRunningSimulations()) { logger.warn("Unable to launch execution '" + simulationName + "': max " + "number of running workflows reached for user '" + user + "'."); throw new fr.insalyon.creatis.vip.core.server.business.BusinessException( "Max number of running executions reached.<br />You already have " + runningWorkflows + " running executions."); } List<ParameterSweep> parameters = new ArrayList<ParameterSweep>(); for (String name : parametersMap.keySet()) { ParameterSweep ps = new ParameterSweep(name); String valuesStr = parametersMap.get(name); if (valuesStr.contains(ApplicationConstants.SEPARATOR_INPUT)) { String[] values = valuesStr.split(ApplicationConstants.SEPARATOR_INPUT); if (values.length != 3) { throw new fr.insalyon.creatis.vip.core.server.business.BusinessException("Error in range."); } Double start = Double.parseDouble(values[0]); Double stop = Double.parseDouble(values[1]); Double step = Double.parseDouble(values[2]); for (double d = start; d <= stop; d += step) { ps.addValue(d + ""); } } else if (valuesStr.contains(ApplicationConstants.SEPARATOR_LIST)) { String[] values = valuesStr.split(ApplicationConstants.SEPARATOR_LIST); for (String v : values) { String parsedPath = DataManagerUtil.parseBaseDir(user, v.trim()); if (!user.isSystemAdministrator()) { checkFolderACL(user, groups, parsedPath); } ps.addValue(parsedPath); } } else { String parsedPath = DataManagerUtil.parseBaseDir(user, valuesStr.trim()); if (!user.isSystemAdministrator()) { checkFolderACL(user, groups, parsedPath); } ps.addValue(parsedPath); } parameters.add(ps); } AppVersion version = applicationDB.getVersion(applicationName, applicationVersion); DataManagerBusiness dmBusiness = new DataManagerBusiness(); String workflowPath = dmBusiness.getRemoteFile(user, version.getLfn(), Server.getInstance().getConfigurationFolder() + "workflows/" + FilenameUtils.getName(version.getLfn())); //selectRandomEngine could also be used; TODO: make this choice configurable Engine engine = selectEngine(applicationClass); WorkflowExecutionBusiness executionBusiness = new WorkflowExecutionBusiness(engine.getEndpoint()); Workflow workflow = null; try { workflow = executionBusiness.launch(applicationName, applicationVersion, applicationClass, user, simulationName, workflowPath, parameters); } catch (BusinessException be) { be.printStackTrace(); logger.error("BusinessException caught on launch workflow, engine " + engine.getName() + " will be disabled"); } finally { if (workflow == null) { engine.setStatus("disabled"); this.engineBusiness.update(engine); for (User u : CoreDAOFactory.getDAOFactory().getUsersGroupsDAO() .getUsersFromGroup(CoreConstants.GROUP_SUPPORT)) { logger.info("Sending warning email to user " + u.toString() + " having email address " + u.getEmail()); CoreUtil.sendEmail("Urgent: VIP engine disabled", "Engine " + engine.getName() + " has just been disabled. Please check that there is at least one active engine left.", new String[] { u.getEmail() }, true, user.getEmail()); } throw new BusinessException( "Workflow is null, engine " + engine.getName() + " has been disabled"); } else { logger.info("Launched workflow " + workflow.toString()); } } workflowDAO.add(workflow); return workflow.getId(); } catch (WorkflowsDBDAOException | DAOException | DataManagerException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param user * @param lastDate * @return * @throws BusinessException */ public List<Simulation> getSimulations(User user, Date lastDate) throws BusinessException { try { return parseWorkflows(workflowDAO.get(user != null ? user.getFullName() : null, lastDate)); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * Get the simulation information * * @param userName * @param application * @param status * @param startDate * @param endDate * @return * @throws BusinessException */ public List<Simulation> getSimulations(String userName, String application, String status, String appClass, Date startDate, Date endDate) throws BusinessException { try { if (endDate != null) { Calendar calendar = Calendar.getInstance(); calendar.setTime(endDate); calendar.add(Calendar.DATE, 1); endDate = calendar.getTime(); } WorkflowStatus wStatus = null; if (status != null) { wStatus = WorkflowStatus.valueOf(status); } List<Simulation> simulations = parseWorkflows( workflowDAO.get(userName, application, wStatus, appClass, startDate, endDate)); checkRunningSimulations(simulations); return simulations; } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * Get the simulation information * * @param users list of users * @param application * @param status Simulation status to filter the request * @param startDate * @param endDate * @return * @throws BusinessException */ public List<Simulation> getSimulations(List<String> users, String application, String status, String appClass, Date startDate, Date endDate) throws BusinessException { try { if (endDate != null) { Calendar calendar = Calendar.getInstance(); calendar.setTime(endDate); calendar.add(Calendar.DATE, 1); endDate = calendar.getTime(); } WorkflowStatus wStatus = null; if (status != null) { wStatus = WorkflowStatus.valueOf(status); } List<Simulation> simulations = parseWorkflows( workflowDAO.get(users, application, wStatus, appClass, startDate, endDate)); checkRunningSimulations(simulations); return simulations; } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param user * @param applicationName * @param applicationVersion * @return * @throws BusinessException */ public Descriptor getApplicationDescriptor(User user, String applicationName, String applicationVersion) throws BusinessException { try { AppVersion version = applicationDB.getVersion(applicationName, applicationVersion); DataManagerBusiness dmBusiness = new DataManagerBusiness(); String localDirectory = Server.getInstance().getConfigurationFolder() + "workflows/" + FilenameUtils.getPath(version.getLfn()) + "/" + FilenameUtils.getName(version.getLfn()); String workflowPath = dmBusiness.getRemoteFile(user, version.getLfn(), localDirectory); return workflowPath.endsWith(".gwendia") ? new GwendiaParser().parse(workflowPath) : new ScuflParser().parse(workflowPath); } catch (org.xml.sax.SAXException ex) { logger.error(ex); throw new BusinessException(ex); } catch (fr.insalyon.creatis.vip.core.server.dao.DAOException ex) { logger.error(ex); throw new BusinessException(ex); } catch (java.io.IOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param simulationID * @throws BusinessException */ public void kill(String simulationID) throws BusinessException { try { Workflow workflow = workflowDAO.get(simulationID); workflow.setStatus(WorkflowStatus.Killed); workflowDAO.update(workflow); WorkflowExecutionBusiness executionBusiness = new WorkflowExecutionBusiness(workflow.getEngine()); executionBusiness.kill(simulationID); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param simulationID * @param email * @param deleteFiles * @throws BusinessException */ public void clean(String simulationID, String email, boolean deleteFiles) throws BusinessException { try { Workflow workflow = workflowDAO.get(simulationID); workflow.setStatus(WorkflowStatus.Cleaned); workflowDAO.update(workflow); if (deleteFiles) { GRIDAPoolClient client = CoreUtil.getGRIDAPoolClient(); for (Output output : outputDAO.get(simulationID)) { client.delete(output.getOutputID().getPath(), email); } } inputDAO.removeById(simulationID); outputDAO.removeById(simulationID); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } catch (GRIDAClientException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param simulationId * @param email * @throws BusinessException */ public void clean(String simulationId, String email) throws BusinessException { clean(simulationId, email, true); } /** * * @param simulationID * @throws BusinessException */ public void purge(String simulationID) throws BusinessException { try { workflowDAO.removeById(simulationID); processorDAO.removeById(simulationID); inputDAO.removeById(simulationID); outputDAO.removeById(simulationID); statsDAO.removeById(simulationID); String workflowsPath = Server.getInstance().getWorkflowsPath(); File workflowDir = new File(workflowsPath, simulationID); FileUtils.deleteQuietly(workflowDir); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param simulationID * @param currentUserFolder * @return * @throws BusinessException */ public Map<String, String> relaunch(String simulationID, String currentUserFolder) throws BusinessException { //TODO fix Map<String, String> inputs = new InputM2Parser(currentUserFolder) .parse(Server.getInstance().getWorkflowsPath() + "/" + simulationID + "/input-m2.xml"); return inputs; } /** * * @param simulationID * @return * @throws BusinessException */ public Simulation getSimulation(String simulationID) throws BusinessException { Simulation simulation = null; try { Workflow workflow = workflowDAO.get(simulationID); if (workflow == null) { throw new BusinessException("Cannot find execution with id " + simulationID); } simulation = new Simulation(workflow.getApplication(), workflow.getApplicationVersion(), workflow.getApplicationClass(), workflow.getId(), workflow.getUsername(), workflow.getStartedTime(), workflow.getDescription(), workflow.getStatus().name(), workflow.getEngine()); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } return simulation; } /** * * @param simulationID * @param currentUserFolder * @return * @throws BusinessException */ public List<InOutData> getOutputData(String simulationID, String currentUserFolder) throws BusinessException { List<InOutData> list = new ArrayList<InOutData>(); try { for (Output output : outputDAO.get(simulationID)) { String path = DataManagerUtil.parseRealDir(output.getOutputID().getPath(), currentUserFolder); list.add(new InOutData(path, output.getOutputID().getProcessor(), output.getType().name())); } } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } catch (DataManagerException ex) { logger.error(ex); throw new BusinessException(ex); } return list; } /** * * @param simulationID * @param currentUserFolder * @return * @throws BusinessException */ public List<InOutData> getInputData(String simulationID, String currentUserFolder) throws BusinessException { try { List<InOutData> list = new ArrayList<InOutData>(); for (Input input : inputDAO.get(simulationID)) { String path = DataManagerUtil.parseRealDir(input.getInputID().getPath(), currentUserFolder); list.add(new InOutData(path, input.getInputID().getProcessor(), input.getType().name())); } return list; } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } catch (DataManagerException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param path * @throws BusinessException */ public void deleteLogData(String path) throws BusinessException { try { File file = new File(Server.getInstance().getWorkflowsPath(), path); if (file.isDirectory()) { FileUtils.deleteDirectory(file); } else if (!file.delete()) { logger.error("Unable to delete data: " + path); throw new BusinessException("Unable to delete data: " + path); } } catch (java.io.IOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param simulationID * @return * @throws BusinessException */ public List<Activity> getProcessors(String simulationID) throws BusinessException { try { List<Activity> list = new ArrayList<Activity>(); for (Processor processor : processorDAO.get(simulationID)) { ProcessorStatus status = ProcessorStatus.Unstarted; if (processor.getCompleted() + processor.getQueued() + processor.getFailed() > 0) { // if (failed > 0) { // status = ProcessorStatus.Failed; // } else if (processor.getQueued() > 0) { status = ProcessorStatus.Active; } else { status = ProcessorStatus.Completed; } } list.add(new Activity(processor.getProcessorID().getProcessor(), status, processor.getCompleted(), processor.getQueued(), processor.getFailed())); } return list; } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param simulationIDList * @param type * @return * @throws BusinessException */ public List<String> getPerformanceStats(List<Simulation> simulationIDList, int type) throws BusinessException, WorkflowsDBDAOException { List<String> workflowIDList = new ArrayList<String>(); List<String> stats = new ArrayList<String>(); if (simulationIDList != null) { for (int i = 0; i < simulationIDList.size(); i++) { //logger.error("Stat module, id is "+simulationIDList.get(i).getID()); workflowIDList.add(simulationIDList.get(i).getID()); } } else { throw new BusinessException("Execution list is null!"); } if (workflowIDList != null && !workflowIDList.isEmpty()) { try { switch (type) { case 1: stats = simulationStatsDAO.getBySimulationID(workflowIDList); break; case 2: stats = simulationStatsDAO.getWorkflowsPerUser(workflowIDList); break; case 3: stats = simulationStatsDAO.getApplications(workflowIDList); break; case 4: stats = simulationStatsDAO.getClasses(workflowIDList); } } catch (DAOException ex) { logger.error(ex); throw new BusinessException(ex); } } else { throw new BusinessException("Empty workflow list!"); } return stats; } /** * * @param user * @param inputs * @throws BusinessException */ public void validateInputs(User user, List<String> inputs) throws BusinessException { try { GRIDAClient client = CoreUtil.getGRIDAClient(); StringBuilder sb = new StringBuilder(); for (String input : inputs) { if (!client.exist(DataManagerUtil.parseBaseDir(user, input))) { if (sb.length() > 0) { sb.append(", "); } sb.append(DataManagerUtil.parseBaseDir(user, input)); } } if (sb.length() > 0) { logger.error("The following data does not exist: " + sb.toString()); throw new fr.insalyon.creatis.vip.core.server.business.BusinessException( "The following data does not exist: " + sb.toString()); } } catch (DataManagerException ex) { logger.error(ex); throw new BusinessException(ex); } catch (GRIDAClientException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param currentUser * @param newUser * @throws BusinessException */ public void updateUser(String currentUser, String newUser) throws BusinessException { try { workflowDAO.updateUsername(newUser, currentUser); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @return @throws BusinessException */ public List<Simulation> getRunningSimulations() throws BusinessException { try { return parseWorkflows(workflowDAO.getRunning()); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } /** * * @param user * @param groups * @param path * @throws BusinessException */ private void checkFolderACL(User user, List<String> groups, String path) throws BusinessException { if (path.startsWith(Server.getInstance().getDataManagerUsersHome())) { path = path.replace(Server.getInstance().getDataManagerUsersHome() + "/", ""); if (!path.startsWith(user.getFolder())) { logger.error("User '" + user + "' tried to access data from another user: " + path + ""); throw new BusinessException("Access denied to another user's home."); } } else if (path.startsWith(Server.getInstance().getDataManagerGroupsHome())) { path = path.replace(Server.getInstance().getDataManagerGroupsHome() + "/", ""); if (path.indexOf("/") != -1) { path = path.substring(0, path.indexOf("/")); } if (!DataManagerUtil.getPaths(groups).contains(path)) { logger.error("User '" + user + "' tried to access data from a non-autorized group: " + path + ""); throw new BusinessException("Access denied to group '" + path + "'."); } } } /** * * @param list * @return */ private List<Simulation> parseWorkflows(List<Workflow> list) { List<Simulation> simulationsList = new ArrayList<Simulation>(); for (Workflow workflow : list) { simulationsList.add(new Simulation(workflow.getApplication(), workflow.getApplicationVersion(), workflow.getApplicationClass(), workflow.getId(), workflow.getUsername(), workflow.getStartedTime(), workflow.getDescription(), workflow.getStatus().name(), workflow.getEngine())); } return simulationsList; } /** * * @param simulations * @throws BusinessException * @throws WorkflowsDBDAOException */ private void checkRunningSimulations(List<Simulation> simulations) throws BusinessException, WorkflowsDBDAOException { for (Simulation simulation : simulations) { if (simulation.getStatus() == SimulationStatus.Running || simulation.getStatus() == SimulationStatus.Unknown) { WorkflowExecutionBusiness executionBusiness = new WorkflowExecutionBusiness(simulation.getEngine()); SimulationStatus simulationStatus = executionBusiness.getStatus(simulation.getID()); if (simulationStatus != SimulationStatus.Running && simulationStatus != SimulationStatus.Unknown) { simulation.setStatus(simulationStatus); Workflow workflow = workflowDAO.get(simulation.getID()); workflow.setStatus(WorkflowStatus.valueOf(simulationStatus.name())); workflowDAO.update(workflow); } } } } public void markCompleted(String simulationID) throws BusinessException { try { Workflow workflow = workflowDAO.get(simulationID); workflow.setStatus(WorkflowStatus.Completed); workflowDAO.update(workflow); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } public void changeSimulationUser(String simulationId, String user) throws BusinessException { try { Workflow workflow = workflowDAO.get(simulationId); workflow.setUsername(user); workflowDAO.update(workflow); } catch (WorkflowsDBDAOException ex) { logger.error(ex); throw new BusinessException(ex); } } }