diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/AbstractSimulationRun.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/AbstractSimulationRun.java index 68ee2c6cc04a3b4c4fd1968f995e5f4c5c6a9215..64e68c4a1540f1e541fc45d737a7cb31bd891abb 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/AbstractSimulationRun.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/AbstractSimulationRun.java @@ -14,15 +14,15 @@ package org.activiti.crystalball.simulator; */ -import org.activiti.engine.delegate.VariableScope; -import org.activiti.engine.impl.ProcessEngineImpl; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.Date; import java.util.HashMap; import java.util.Map; +import org.activiti.engine.ProcessEngine; +import org.activiti.engine.delegate.VariableScope; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * This class implements all methods for Simulation run * @@ -37,7 +37,7 @@ public abstract class AbstractSimulationRun implements SimulationRun, Simulation * Map for eventType -> event handlers to execute events on simulation engine */ protected Map eventHandlerMap = new HashMap(); - protected ProcessEngineImpl processEngine; + protected ProcessEngine processEngine; public AbstractSimulationRun(Map eventHandlers) { if (eventHandlers != null && !eventHandlers.isEmpty()) { diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/EventCalendar.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/EventCalendar.java index ca9c697291923869eda96ce6fea75d4397c33c41..804a8d99dff02afb2e4b01860eab874557f87a82 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/EventCalendar.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/EventCalendar.java @@ -1,5 +1,7 @@ package org.activiti.crystalball.simulator; +import java.util.List; + /* Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at @@ -27,6 +29,8 @@ public interface EventCalendar { SimulationEvent removeFirstEvent(); void addEvent(SimulationEvent event); + + List getEvents(); void clear(); } diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/ReplaySimulationRun.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/ReplaySimulationRun.java index 004d8b507fc44d281fdcb6708fc04ca1240e6ea9..1ada2b3e2b9f1784670a5ef72fb17d83b6305390 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/ReplaySimulationRun.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/ReplaySimulationRun.java @@ -14,11 +14,12 @@ package org.activiti.crystalball.simulator; */ -import org.activiti.engine.delegate.VariableScope; -import org.activiti.engine.impl.ProcessEngineImpl; - import java.util.Map; +import org.activiti.engine.ProcessEngine; +import org.activiti.engine.delegate.VariableScope; +import org.activiti.engine.impl.cfg.ProcessEngineConfigurationImpl; + /** * This class provides simulation run for replay purposes * replay uses real time and running engine to execute simulation events. @@ -29,11 +30,11 @@ public class ReplaySimulationRun extends AbstractSimulationRun { private final EventCalendar eventCalendar; - public ReplaySimulationRun(ProcessEngineImpl processEngine, Map customEventHandlerMap) { + public ReplaySimulationRun(ProcessEngine processEngine, Map customEventHandlerMap) { this(processEngine, new SimpleEventCalendar(processEngine.getProcessEngineConfiguration().getClock(), new SimulationEventComparator()), customEventHandlerMap); } - public ReplaySimulationRun(ProcessEngineImpl processEngine, EventCalendar eventCalendar, Map customEventHandlerMap) { + public ReplaySimulationRun(ProcessEngine processEngine, EventCalendar eventCalendar, Map customEventHandlerMap) { super(customEventHandlerMap); this.processEngine = processEngine; this.eventCalendar = eventCalendar; @@ -43,7 +44,8 @@ public class ReplaySimulationRun extends AbstractSimulationRun { protected void initSimulationRunContext(VariableScope execution) { SimulationRunContext.setEventCalendar(eventCalendar); SimulationRunContext.setProcessEngine(processEngine); - SimulationRunContext.setSimulationRunId(processEngine.getProcessEngineConfiguration().getIdGenerator().getNextId()); + ProcessEngineConfigurationImpl configuration = (ProcessEngineConfigurationImpl) processEngine.getProcessEngineConfiguration(); + SimulationRunContext.setSimulationRunId(configuration.getIdGenerator().getNextId()); } /** diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimpleEventCalendar.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimpleEventCalendar.java index e8b54c48abb3891afe3cde3aedc3e7b5c4ce6ea1..e96c3a74278a427f2de1f819513b0d81a755a648 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimpleEventCalendar.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimpleEventCalendar.java @@ -14,15 +14,16 @@ package org.activiti.crystalball.simulator; */ -import org.activiti.engine.runtime.ClockReader; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.util.ArrayList; import java.util.Collection; import java.util.Comparator; import java.util.List; +import org.activiti.engine.ActivitiException; +import org.activiti.engine.runtime.ClockReader; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * @author martin.grofcik */ @@ -63,8 +64,9 @@ public class SimpleEventCalendar implements EventCalendar { SimulationEvent minEvent = eventList.remove( minIndex ); - if (minEvent.hasSimulationTime() && minEvent.getSimulationTime() < this.clockReader.getCurrentTime().getTime()) - throw new RuntimeException("Unable to execute event from the past"); + if (minEvent.hasSimulationTime() && minEvent.getSimulationTime() < this.clockReader.getCurrentTime().getTime()) { + throw new ActivitiException("Unable to execute event from the past"); + } if (eventList.isEmpty()) { minIndex = NULL; @@ -80,6 +82,11 @@ public class SimpleEventCalendar implements EventCalendar { } return minEvent; } + + @Override + public List getEvents() { + return eventList; + } @Override public void addEvent(SimulationEvent event) { diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimulationRunContext.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimulationRunContext.java index 78c64b5aa55f8982f6415fc725b1314703b3cb89..bf5e2ea5cb53827d0d1c3c8af80c713af1288130 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimulationRunContext.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/SimulationRunContext.java @@ -12,16 +12,16 @@ */ package org.activiti.crystalball.simulator; +import java.util.Stack; + import org.activiti.engine.HistoryService; +import org.activiti.engine.ProcessEngine; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.delegate.VariableScope; -import org.activiti.engine.impl.ProcessEngineImpl; import org.activiti.engine.runtime.Clock; -import java.util.Stack; - /** * Context in which simulation is run. * It contains references to process engine, event calendar. @@ -33,7 +33,7 @@ public abstract class SimulationRunContext { // // Process engine on which simulation will be executed // - protected static ThreadLocal> processEngineThreadLocal = new ThreadLocal>(); + protected static ThreadLocal> processEngineThreadLocal = new ThreadLocal>(); // // Simulation objects @@ -51,18 +51,18 @@ public abstract class SimulationRunContext { protected static ThreadLocal> executionThreadLocal = new ThreadLocal>(); public static RuntimeService getRuntimeService() { - Stack stack = getStack(processEngineThreadLocal); + Stack stack = getStack(processEngineThreadLocal); if (stack.isEmpty()) { return null; } return stack.peek().getRuntimeService(); } - public static void setProcessEngine(ProcessEngineImpl processEngine) { + public static void setProcessEngine(ProcessEngine processEngine) { getStack(processEngineThreadLocal).push(processEngine); } - public static ProcessEngineImpl getProcessEngine() { + public static ProcessEngine getProcessEngine() { return getStack(processEngineThreadLocal).peek(); } @@ -71,7 +71,7 @@ public abstract class SimulationRunContext { } public static TaskService getTaskService() { - Stack stack = getStack(processEngineThreadLocal); + Stack stack = getStack(processEngineThreadLocal); if (stack.isEmpty()) { return null; } @@ -107,7 +107,7 @@ public abstract class SimulationRunContext { } public static HistoryService getHistoryService() { - Stack stack = getStack(processEngineThreadLocal); + Stack stack = getStack(processEngineThreadLocal); if (stack.isEmpty()) { return null; } @@ -116,7 +116,7 @@ public abstract class SimulationRunContext { public static RepositoryService getRepositoryService() { - Stack stack = getStack(processEngineThreadLocal); + Stack stack = getStack(processEngineThreadLocal); if (stack.isEmpty()) { return null; } diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogProcessInstanceCreateTransformer.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogProcessInstanceCreateTransformer.java index 972bc0e2e0dcd2a6c8e8f21f02a92e5d832ff1da..0c58223b1b6b58aec60dd7d9c2f97278fe0e0bcb 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogProcessInstanceCreateTransformer.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogProcessInstanceCreateTransformer.java @@ -66,10 +66,10 @@ public class EventLogProcessInstanceCreateTransformer extends EventLog2Simulatio simEventProperties.put(variablesKey, variableMap); simEventProperties.put(PROCESS_INSTANCE_ID, processInstanceId); - return new SimulationEvent.Builder(simulationEventType). - priority((int) event.getLogNumber()). - properties(simEventProperties). - build(); + return new SimulationEvent.Builder(simulationEventType) + .priority((int) event.getLogNumber()) + .properties(simEventProperties) + .build(); } return null; } diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogUserTaskCompleteTransformer.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogUserTaskCompleteTransformer.java index 69466b84f91ea1336c518f37816d3e2cf80fc243..724f3884c30b9c2b270fa0a79e2c9339f7c4966d 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogUserTaskCompleteTransformer.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/delegate/event/impl/EventLogUserTaskCompleteTransformer.java @@ -73,11 +73,10 @@ public class EventLogUserTaskCompleteTransformer extends EventLog2SimulationEven properties.put(VARIABLES_LOCAL_SCOPE, localScope); } - return - new SimulationEvent.Builder(this.simulationEventType). - priority((int) event.getLogNumber()). - properties(properties). - build(); + return new SimulationEvent.Builder(this.simulationEventType) + .priority((int) event.getLogNumber()) + .properties(properties) + .build(); } return null; } diff --git a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/impl/StartReplayLogEventHandler.java b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/impl/StartReplayLogEventHandler.java index 0a9176a679dbc0d3f7e9ad743d7de9f3842efc79..c414ccd92e2f09d24b0627e143f9fde93c8e4b63 100644 --- a/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/impl/StartReplayLogEventHandler.java +++ b/modules/activiti-crystalball/src/main/java/org/activiti/crystalball/simulator/impl/StartReplayLogEventHandler.java @@ -59,7 +59,7 @@ public class StartReplayLogEventHandler implements SimulationEventHandler { public void handle(SimulationEvent event) { // start process now String processDefinitionId = (String) event.getProperty(processToStartIdKey); - String businessKey = (String) event.getProperty(this.businessKey); + String eventBusinessKey = (String) event.getProperty(this.businessKey); Map variables = new HashMap(); Map processVariables = (Map) event.getProperty(variablesKey); if (processVariables != null) { @@ -68,7 +68,13 @@ public class StartReplayLogEventHandler implements SimulationEventHandler { variables.put(PROCESS_INSTANCE_ID, processInstanceId); variables.put(SIMULATION_RUN_ID, SimulationRunContext.getSimulationRunId()); - log.debug("Starting new processDefId[{}] businessKey[{}] with variables[{}]", processDefinitionId, businessKey, variables); - SimulationRunContext.getRuntimeService().startProcessInstanceById(processDefinitionId, businessKey, variables); + String startBusinessKey = null; + if (eventBusinessKey != null) { + startBusinessKey = eventBusinessKey; + } else { + startBusinessKey = this.businessKey; + } + log.debug("Starting new processDefId[{}] businessKey[{}] with variables[{}]", processDefinitionId, startBusinessKey, variables); + SimulationRunContext.getRuntimeService().startProcessInstanceById(processDefinitionId, startBusinessKey, variables); } } diff --git a/modules/activiti-crystalball/src/test/java/org/activiti/crystalball/simulator/impl/replay/ReplayRunTest.java b/modules/activiti-crystalball/src/test/java/org/activiti/crystalball/simulator/impl/replay/ReplayRunTest.java index 3f48d2aa26cc952298778b795b88254a19eebbdf..41e85e24b7e4d95e8382cf6f483ae382b5717cb6 100644 --- a/modules/activiti-crystalball/src/test/java/org/activiti/crystalball/simulator/impl/replay/ReplayRunTest.java +++ b/modules/activiti-crystalball/src/test/java/org/activiti/crystalball/simulator/impl/replay/ReplayRunTest.java @@ -122,7 +122,7 @@ public class ReplayRunTest { ProcessEngineConfigurationImpl configuration = new org.activiti.engine.impl.cfg.StandaloneInMemProcessEngineConfiguration(); configuration. setHistory("full"). - setDatabaseSchemaUpdate("create-drop"). + setDatabaseSchemaUpdate("drop-create"). setJobExecutorActivate(false); configuration.setCustomDefaultBpmnParseHandlers(Arrays.asList(new AddListenerUserTaskParseHandler(TaskListener.EVENTNAME_CREATE, new UserTaskExecutionListener(USER_TASK_COMPLETED_EVENT_TYPE, USER_TASK_COMPLETED_EVENT_TYPE, listener.getSimulationEvents())))); configuration.setEventListeners(Arrays.asList(listener)); diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/ManagementService.java b/modules/activiti-engine/src/main/java/org/activiti/engine/ManagementService.java index 983d740c1f50b6cff517c454ebbf662073f42edd..37704d51efd8274f0a67260aa03fbb1fd0102ee5 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/ManagementService.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/ManagementService.java @@ -144,6 +144,17 @@ public interface ManagementService { */ List getEventLogEntries(Long startLogNr, Long pageSize); + /** + * [EXPERIMENTAL] + * + * Returns a list of event log entries for a specific process instance id. + * Note that the event logging must specifically must be enabled in the process engine configuration. + * + * Passing null as arguments will effectively fetch ALL event log entries. + * Be careful, as this list might be huge! + */ + List getEventLogEntriesByProcessInstanceId(String processInstanceId); + /** * Delete a EventLogEntry. * Typically only used in testing, as deleting log entries defeats the whole purpose of keeping a log. diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ManagementServiceImpl.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ManagementServiceImpl.java index 2aca9424c499a689aa5ff73419d19347deecbba1..df85b1943beb963e2e4dc1bd2434bf0eb1c4672a 100755 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ManagementServiceImpl.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/ManagementServiceImpl.java @@ -12,10 +12,25 @@ */ package org.activiti.engine.impl; +import java.sql.Connection; +import java.util.List; +import java.util.Map; + import org.activiti.engine.ActivitiIllegalArgumentException; import org.activiti.engine.ManagementService; import org.activiti.engine.event.EventLogEntry; -import org.activiti.engine.impl.cmd.*; +import org.activiti.engine.impl.cmd.CancelJobCmd; +import org.activiti.engine.impl.cmd.CustomSqlExecution; +import org.activiti.engine.impl.cmd.DeleteEventLogEntry; +import org.activiti.engine.impl.cmd.ExecuteCustomSqlCmd; +import org.activiti.engine.impl.cmd.ExecuteJobsCmd; +import org.activiti.engine.impl.cmd.GetEventLogEntriesCmd; +import org.activiti.engine.impl.cmd.GetJobExceptionStacktraceCmd; +import org.activiti.engine.impl.cmd.GetPropertiesCmd; +import org.activiti.engine.impl.cmd.GetTableCountCmd; +import org.activiti.engine.impl.cmd.GetTableMetaDataCmd; +import org.activiti.engine.impl.cmd.GetTableNameCmd; +import org.activiti.engine.impl.cmd.SetJobRetriesCmd; import org.activiti.engine.impl.db.DbSqlSession; import org.activiti.engine.impl.db.DbSqlSessionFactory; import org.activiti.engine.impl.interceptor.Command; @@ -25,10 +40,6 @@ import org.activiti.engine.management.TableMetaData; import org.activiti.engine.management.TablePageQuery; import org.activiti.engine.runtime.JobQuery; -import java.sql.Connection; -import java.util.List; -import java.util.Map; - /** * @author Tom Baeyens @@ -118,6 +129,11 @@ public class ManagementServiceImpl extends ServiceImpl implements ManagementServ return commandExecutor.execute(new GetEventLogEntriesCmd(startLogNr, pageSize)); } + @Override + public List getEventLogEntriesByProcessInstanceId(String processInstanceId) { + return commandExecutor.execute(new GetEventLogEntriesCmd(processInstanceId)); + } + @Override public void deleteEventLogEntry(long logNr) { commandExecutor.execute(new DeleteEventLogEntry(logNr)); diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/GetEventLogEntriesCmd.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/GetEventLogEntriesCmd.java index aeeaab0af216da88b2f2a519806d5f688560d57b..5d0a7f43b367916f2df7275de303d00b5d54d559 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/GetEventLogEntriesCmd.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/cmd/GetEventLogEntriesCmd.java @@ -11,6 +11,7 @@ import org.activiti.engine.impl.interceptor.CommandContext; */ public class GetEventLogEntriesCmd implements Command> { + protected String processInstanceId = null; protected Long startLogNr = null; protected Long pageSize = null; @@ -18,6 +19,10 @@ public class GetEventLogEntriesCmd implements Command> { } + public GetEventLogEntriesCmd(String processInstanceId) { + this.processInstanceId = processInstanceId; + } + public GetEventLogEntriesCmd(Long startLogNr, Long pageSize) { this.startLogNr = startLogNr; this.pageSize = pageSize; @@ -25,12 +30,17 @@ public class GetEventLogEntriesCmd implements Command> { @Override public List execute(CommandContext commandContext) { - if (startLogNr == null) { - return commandContext.getEventLogEntryEntityManager().findAllEventLogEntries(); - } - return commandContext.getEventLogEntryEntityManager().findEventLogEntries( - startLogNr, - pageSize != null ? pageSize : -1); + if (processInstanceId != null) { + return commandContext.getEventLogEntryEntityManager().findEventLogEntriesByProcessInstanceId(processInstanceId); + + } else if (startLogNr != null) { + return commandContext.getEventLogEntryEntityManager().findEventLogEntries( + startLogNr, + pageSize != null ? pageSize : -1); + + } else { + return commandContext.getEventLogEntryEntityManager().findAllEventLogEntries(); + } } } diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/db/DbSqlSessionFactory.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/db/DbSqlSessionFactory.java index 09bdd77916026e6c2b3a4a56b77550c574ff80e8..4b5b75ac04b1343a24f572f7c869c4a4c997b875 100755 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/db/DbSqlSessionFactory.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/db/DbSqlSessionFactory.java @@ -91,6 +91,7 @@ public class DbSqlSessionFactory implements SessionFactory { addDatabaseSpecificStatement("postgres", "insertEventLogEntry", "insertEventLogEntry_postgres"); addDatabaseSpecificStatement("postgres", "selectAllEventLogEntries", "selectAllEventLogEntries_postgres"); addDatabaseSpecificStatement("postgres", "selectEventLogEntries", "selectEventLogEntries_postgres"); + addDatabaseSpecificStatement("postgres", "selectEventLogEntriesByProcessInstanceId", "selectEventLogEntriesByProcessInstanceId_postgres"); // oracle databaseSpecificLimitBeforeStatements.put("oracle", "select * from ( select a.*, ROWNUM rnum from ("); diff --git a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/EventLogEntryEntityManager.java b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/EventLogEntryEntityManager.java index 9f20ece73baade96991e432d887ec573f168f3de..1e0f6e7068f7f789df1f6354bcf828de3176a131 100644 --- a/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/EventLogEntryEntityManager.java +++ b/modules/activiti-engine/src/main/java/org/activiti/engine/impl/persistence/entity/EventLogEntryEntityManager.java @@ -45,6 +45,13 @@ public class EventLogEntryEntityManager extends AbstractManager { return getDbSqlSession().selectList("selectEventLogEntries", params); } + @SuppressWarnings("unchecked") + public List findEventLogEntriesByProcessInstanceId(String processInstanceId) { + Map params = new HashMap(2); + params.put("processInstanceId", processInstanceId); + return getDbSqlSession().selectList("selectEventLogEntriesByProcessInstanceId", params); + } + public void deleteEventLogEntry(long logNr) { getDbSqlSession().getSqlSession().delete("deleteEventLogEntry", logNr); } diff --git a/modules/activiti-engine/src/main/resources/org/activiti/db/mapping/entity/EventLogEntry.xml b/modules/activiti-engine/src/main/resources/org/activiti/db/mapping/entity/EventLogEntry.xml index 5acc014df1e29305fbee5d90fd6e751ba1cf17d4..f3cef4e1f39949f7e94d56fe8283699f941e9176 100644 --- a/modules/activiti-engine/src/main/resources/org/activiti/db/mapping/entity/EventLogEntry.xml +++ b/modules/activiti-engine/src/main/resources/org/activiti/db/mapping/entity/EventLogEntry.xml @@ -114,6 +114,17 @@ ORDER BY LOG_NR_ + + + diff --git a/modules/activiti-explorer/pom.xml b/modules/activiti-explorer/pom.xml index 708fdb15d97d6dade4cdd78416c878266fd6668f..5a6a69cd12004761427caa1813791c6fed96822d 100644 --- a/modules/activiti-explorer/pom.xml +++ b/modules/activiti-explorer/pom.xml @@ -125,6 +125,10 @@ org.activiti activiti-simple-workflow + + org.activiti + activiti-crystalball + diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ExplorerApp.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ExplorerApp.java index 1940b7a4a30fe33262360d10a753261ec836a3da..2debc12c0cd3dc64103b68961fcd6b4c78c541f3 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ExplorerApp.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ExplorerApp.java @@ -18,6 +18,8 @@ import java.util.Locale; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import org.activiti.crystalball.simulator.SimulationDebugger; +import org.activiti.crystalball.simulator.SimulationEvent; import org.activiti.engine.ActivitiException; import org.activiti.engine.impl.identity.Authentication; import org.activiti.explorer.identity.LoggedInUser; @@ -64,6 +66,11 @@ public class ExplorerApp extends Application implements HttpServletRequestListen protected List adminGroups; protected List userGroups; + protected String crystalBallCurrentDefinitionId = null; + protected String crystalBallCurrentInstanceId = null; + protected List crystalBallSimulationEvents = null; + protected transient SimulationDebugger crystalBallSimulationDebugger = null; + public void init() { setMainWindow(mainWindow); mainWindow.showLoginPage(); @@ -301,5 +308,37 @@ public class ExplorerApp extends Application implements HttpServletRequestListen public void setSimpleWorkflowJsonConverter(SimpleWorkflowJsonConverter simpleWorkflowJsonConverter) { this.simpleWorkflowJsonConverter = simpleWorkflowJsonConverter; } + + public String getCrystalBallCurrentDefinitionId() { + return crystalBallCurrentDefinitionId; + } + + public void setCrystalBallCurrentDefinitionId(String crystalBallCurrentDefinitionId) { + this.crystalBallCurrentDefinitionId = crystalBallCurrentDefinitionId; + } + + public String getCrystalBallCurrentInstanceId() { + return crystalBallCurrentInstanceId; + } + + public void setCrystalBallCurrentInstanceId(String crystalBallCurrentInstanceId) { + this.crystalBallCurrentInstanceId = crystalBallCurrentInstanceId; + } + + public List getCrystalBallSimulationEvents() { + return crystalBallSimulationEvents; + } + + public void setCrystalBallSimulationEvents(List crystalBallSimulationEvents) { + this.crystalBallSimulationEvents = crystalBallSimulationEvents; + } + + public SimulationDebugger getCrystalBallSimulationDebugger() { + return crystalBallSimulationDebugger; + } + + public void setCrystalBallSimulationDebugger(SimulationDebugger crystalBallSimulationDebugger) { + this.crystalBallSimulationDebugger = crystalBallSimulationDebugger; + } } diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java index 4c100854d8f504db9d60f93ee9647657275ee0ff..e95b1c4c7114313bad8dc4b82d7c3177fb3414c5 100644 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/Messages.java @@ -257,6 +257,7 @@ public interface Messages { String PROCESS_STARTED_NOTIFICATION = "process.started.notification"; String PROCESS_INSTANCE_STARTED_ON = "process.instance.started.on"; String PROCESS_INSTANCE_STARTED = "process.instance.started"; + String PROCESS_INSTANCE_ENDED = "process.instance.ended"; String PROCESS_INSTANCE_HEADER_TASKS = "process.instance.header.tasks"; String PROCESS_INSTANCE_NO_TASKS = "process.instance.no.tasks"; String PROCESS_INSTANCE_HEADER_VARIABLES = "process.instance.header.variables"; @@ -463,6 +464,12 @@ public interface Messages { String EMAIL_RECEIVED_DATE = "email.received.date"; String EMAIL_HTML_CONTENT = "email.html.content"; String EMAIL_RECIPIENTS = "email.recipients"; + + // Crystalball + String CRYSTALBALL_BUTTON_REPLAY = "crystalball.button.replay"; + String CRYSTALBALL_BUTTON_NEXTEVENT = "crystalball.button.nextevent"; + String CRYSTALBALL_EVENT_TYPE = "crystalball.event.type"; + String CRYSTALBALL_EVENT_EXECUTED = "crystalball.event.executed"; // Time formatting String TIME_UNIT_MOMENTS = "time.unit.moments"; diff --git a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/crystalball/EventOverviewPanel.java b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/crystalball/EventOverviewPanel.java index 9c6d1654e94d7d8b01cf90ddf7cf5ed80d2ad2ee..b157ca89f7953cc53770c2a39b9722c2c7f7d967 100755 --- a/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/crystalball/EventOverviewPanel.java +++ b/modules/activiti-explorer/src/main/java/org/activiti/explorer/ui/management/crystalball/EventOverviewPanel.java @@ -12,16 +12,33 @@ */ package org.activiti.explorer.ui.management.crystalball; +import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.activiti.crystalball.simulator.ReplaySimulationRun; +import org.activiti.crystalball.simulator.SimpleEventCalendar; +import org.activiti.crystalball.simulator.SimulationDebugger; +import org.activiti.crystalball.simulator.SimulationEvent; +import org.activiti.crystalball.simulator.SimulationEventComparator; +import org.activiti.crystalball.simulator.SimulationEventHandler; +import org.activiti.crystalball.simulator.SimulationRunContext; +import org.activiti.crystalball.simulator.delegate.event.Function; +import org.activiti.crystalball.simulator.delegate.event.impl.EventLogProcessInstanceCreateTransformer; +import org.activiti.crystalball.simulator.delegate.event.impl.EventLogTransformer; +import org.activiti.crystalball.simulator.delegate.event.impl.EventLogUserTaskCompleteTransformer; +import org.activiti.crystalball.simulator.impl.StartReplayLogEventHandler; +import org.activiti.crystalball.simulator.impl.replay.ReplayUserTaskCompleteEventHandler; import org.activiti.engine.HistoryService; import org.activiti.engine.IdentityService; +import org.activiti.engine.ManagementService; import org.activiti.engine.ProcessEngines; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; +import org.activiti.engine.event.EventLogEntry; import org.activiti.engine.history.HistoricProcessInstance; +import org.activiti.engine.impl.el.NoExecutionVariableScope; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.explorer.ExplorerApp; import org.activiti.explorer.I18nManager; @@ -51,10 +68,20 @@ public class EventOverviewPanel extends DetailPanel { private static final long serialVersionUID = 1L; + // Process instance start event + private static final String PROCESS_INSTANCE_START_EVENT_TYPE = "PROCESS_INSTANCE_START"; + private static final String PROCESS_DEFINITION_ID_KEY = "processDefinitionId"; + private static final String VARIABLES_KEY = "variables"; + // User task completed event + private static final String USER_TASK_COMPLETED_EVENT_TYPE = "USER_TASK_COMPLETED"; + + private static final String SIMULATION_BUSINESS_KEY = "testBusinessKey"; + protected transient HistoryService historyService; protected transient RepositoryService repositoryService; protected transient RuntimeService runtimeService; protected transient IdentityService identityService; + protected transient ManagementService managementService; protected I18nManager i18nManager; protected VariableRendererManager variableRendererManager; @@ -63,18 +90,24 @@ public class EventOverviewPanel extends DetailPanel { protected Button replayButton; protected Table instanceTable; protected HorizontalLayout eventLayout; + protected Button stepButton; + protected Button showProcessInstanceButton; protected Table eventTable; protected Label noMembersTable; protected List definitionList; protected Map definitionMap = new HashMap(); protected List instanceList; + protected List simulationEvents; + protected HistoricProcessInstance replayHistoricInstance; + protected SimulationDebugger simulationDebugger; public EventOverviewPanel() { this.runtimeService = ProcessEngines.getDefaultProcessEngine().getRuntimeService(); this.historyService = ProcessEngines.getDefaultProcessEngine().getHistoryService(); this.repositoryService = ProcessEngines.getDefaultProcessEngine().getRepositoryService(); this.identityService = ProcessEngines.getDefaultProcessEngine().getIdentityService(); + this.managementService = ProcessEngines.getDefaultProcessEngine().getManagementService(); this.variableRendererManager = ExplorerApp.get().getVariableRendererManager(); this.definitionList = repositoryService.createProcessDefinitionQuery().orderByProcessDefinitionName().asc().list(); this.instanceList = historyService.createHistoricProcessInstanceQuery().orderByProcessInstanceStartTime().desc().list(); @@ -82,6 +115,7 @@ public class EventOverviewPanel extends DetailPanel { initializeDefinitionMap(); init(); + initializeCurrentValues(); } protected void initializeDefinitionMap() { @@ -90,6 +124,34 @@ public class EventOverviewPanel extends DetailPanel { } } + protected void initializeCurrentValues() { + if (ExplorerApp.get().getCrystalBallSimulationDebugger() != null) { + this.simulationDebugger = ExplorerApp.get().getCrystalBallSimulationDebugger(); + this.simulationEvents = ExplorerApp.get().getCrystalBallSimulationEvents(); + + String selectedDefinitionId = ExplorerApp.get().getCrystalBallCurrentDefinitionId(); + if (selectedDefinitionId != null) { + definitionSelect.setValue(selectedDefinitionId); + } + + String selectedInstanceId = ExplorerApp.get().getCrystalBallCurrentInstanceId(); + if (selectedInstanceId != null) { + instanceTable.setValue(selectedInstanceId); + } + + List replayProcessInstanceList = historyService.createHistoricProcessInstanceQuery() + .processInstanceBusinessKey(SIMULATION_BUSINESS_KEY) + .orderByProcessInstanceStartTime() + .desc() + .list(); + if (replayProcessInstanceList != null && replayProcessInstanceList.size() > 0) { + replayHistoricInstance = replayProcessInstanceList.get(0); + } + + refreshEvents(); + } + } + protected void init() { setSizeFull(); addStyleName(Reindeer.PANEL_LIGHT); @@ -99,6 +161,15 @@ public class EventOverviewPanel extends DetailPanel { } protected void initProcessInstances() { + HorizontalLayout instancesHeader = new HorizontalLayout(); + instancesHeader.setSpacing(false); + instancesHeader.setMargin(false); + instancesHeader.setWidth(100, UNITS_PERCENTAGE); + instancesHeader.addStyleName(ExplorerLayout.STYLE_DETAIL_BLOCK); + addDetailComponent(instancesHeader); + + initProcessInstanceTitle(instancesHeader); + HorizontalLayout selectLayout = new HorizontalLayout(); selectLayout.setSpacing(true); selectLayout.setMargin(true); @@ -118,14 +189,16 @@ public class EventOverviewPanel extends DetailPanel { @Override public void valueChange(ValueChangeEvent event) { if (definitionSelect.getValue() != null) { - refreshInstances((String) definitionSelect.getValue()); + String selectedDefinitionId = (String) definitionSelect.getValue(); + ExplorerApp.get().setCrystalBallCurrentDefinitionId(selectedDefinitionId); + refreshInstances(selectedDefinitionId); } } }); selectLayout.addComponent(definitionSelect); - replayButton = new Button("Replay"); + replayButton = new Button(i18nManager.getMessage(Messages.CRYSTALBALL_BUTTON_REPLAY)); replayButton.setEnabled(false); replayButton.addListener(new ClickListener() { @@ -133,7 +206,41 @@ public class EventOverviewPanel extends DetailPanel { @Override public void buttonClick(ClickEvent event) { - + if (instanceTable.getValue() != null) { + String processInstanceId = (String) instanceTable.getValue(); + ExplorerApp.get().setCrystalBallCurrentInstanceId(processInstanceId); + List eventLogEntries = managementService.getEventLogEntriesByProcessInstanceId(processInstanceId); + if (eventLogEntries == null || eventLogEntries.size() == 0) return; + EventLogTransformer transformer = new EventLogTransformer(getTransformers()); + simulationEvents = transformer.transform(eventLogEntries); + ExplorerApp.get().setCrystalBallSimulationEvents(simulationEvents); + + SimpleEventCalendar eventCalendar = new SimpleEventCalendar( + ProcessEngines.getDefaultProcessEngine().getProcessEngineConfiguration().getClock(), + new SimulationEventComparator()); + eventCalendar.addEvents(simulationEvents); + + // replay process instance run + simulationDebugger = new ReplaySimulationRun(ProcessEngines.getDefaultProcessEngine(), + eventCalendar, getReplayHandlers(processInstanceId)); + ExplorerApp.get().setCrystalBallSimulationDebugger(simulationDebugger); + + simulationDebugger.init(new NoExecutionVariableScope()); + + simulationDebugger.step(); + + // replay process was started + List replayProcessInstanceList = historyService.createHistoricProcessInstanceQuery() + .processInstanceBusinessKey(SIMULATION_BUSINESS_KEY) + .orderByProcessInstanceStartTime() + .desc() + .list(); + if (replayProcessInstanceList != null && replayProcessInstanceList.size() > 0) { + replayHistoricInstance = replayProcessInstanceList.get(0); + } + + refreshEvents(); + } } }); selectLayout.addComponent(replayButton); @@ -147,7 +254,7 @@ public class EventOverviewPanel extends DetailPanel { } protected void initProcessInstanceTitle(HorizontalLayout instancesHeader) { - Label titleHeader = new Label(i18nManager.getMessage(Messages.ADMIN_DEFINITIONS)); + Label titleHeader = new Label(i18nManager.getMessage(Messages.PROCESS_INSTANCES)); titleHeader.addStyleName(ExplorerLayout.STYLE_H3); instancesHeader.addComponent(titleHeader); } @@ -171,7 +278,7 @@ public class EventOverviewPanel extends DetailPanel { instanceTable.addContainerProperty("id", String.class, null, i18nManager.getMessage(Messages.PROCESS_INSTANCE_ID), null, Table.ALIGN_LEFT); instanceTable.addContainerProperty("definitionName", String.class, null, i18nManager.getMessage(Messages.PROCESS_INSTANCE_NAME), null, Table.ALIGN_LEFT); instanceTable.addContainerProperty("started", String.class, null, i18nManager.getMessage(Messages.PROCESS_INSTANCE_STARTED), null, Table.ALIGN_LEFT); - instanceTable.addContainerProperty("ended", String.class, null, i18nManager.getMessage(Messages.PROCESS_INSTANCE_STARTED), null, Table.ALIGN_LEFT); + instanceTable.addContainerProperty("ended", String.class, null, i18nManager.getMessage(Messages.PROCESS_INSTANCE_ENDED), null, Table.ALIGN_LEFT); fillInstanceValues(); @@ -224,12 +331,43 @@ public class EventOverviewPanel extends DetailPanel { protected void initEvents() { HorizontalLayout eventsHeader = new HorizontalLayout(); eventsHeader.setSpacing(true); - eventsHeader.setWidth(100, UNITS_PERCENTAGE); + eventsHeader.setWidth(80, UNITS_PERCENTAGE); eventsHeader.addStyleName(ExplorerLayout.STYLE_DETAIL_BLOCK); addDetailComponent(eventsHeader); initEventTitle(eventsHeader); + stepButton = new Button(i18nManager.getMessage(Messages.CRYSTALBALL_BUTTON_NEXTEVENT)); + stepButton.setEnabled(false); + stepButton.addListener(new ClickListener() { + private static final long serialVersionUID = 1L; + + @Override + public void buttonClick(ClickEvent event) { + if (SimulationRunContext.getEventCalendar().getEvents().size() > 0) { + simulationDebugger.step(); + refreshEvents(); + } + } + }); + eventsHeader.addComponent(stepButton); + eventsHeader.setComponentAlignment(stepButton, Alignment.MIDDLE_LEFT); + + showProcessInstanceButton = new Button(); + showProcessInstanceButton.addStyleName(Reindeer.BUTTON_LINK); + showProcessInstanceButton.addListener(new ClickListener() { + private static final long serialVersionUID = 1L; + + public void buttonClick(ClickEvent event) { + if (replayHistoricInstance != null) { + ExplorerApp.get().getViewManager().showMyProcessInstancesPage(replayHistoricInstance.getId()); + } + } + }); + + eventsHeader.addComponent(showProcessInstanceButton); + eventsHeader.setComponentAlignment(showProcessInstanceButton, Alignment.MIDDLE_LEFT); + eventLayout = new HorizontalLayout(); eventLayout.setWidth(100, UNITS_PERCENTAGE); addDetailComponent(eventLayout); @@ -244,6 +382,7 @@ public class EventOverviewPanel extends DetailPanel { protected void initEventsTable() { eventTable = new Table(); + eventTable.setVisible(false); eventTable.setWidth(100, UNITS_PERCENTAGE); eventTable.setHeight(250, UNITS_PIXELS); @@ -252,17 +391,51 @@ public class EventOverviewPanel extends DetailPanel { eventTable.setSelectable(true); eventTable.setSortDisabled(false); - eventTable.addContainerProperty("id", String.class, null, i18nManager.getMessage(Messages.PROCESS_INSTANCE_ID), null, Table.ALIGN_LEFT); - eventTable.addContainerProperty("name", String.class, null, i18nManager.getMessage(Messages.PROCESS_INSTANCE_NAME), null, Table.ALIGN_LEFT); - eventTable.addContainerProperty("nr of instances", String.class, null, i18nManager.getMessage(Messages.ADMIN_NR_INSTANCES), null, Table.ALIGN_LEFT); - - /*for (ManagementProcessDefinition managementDefinition : runningDefinitions.values()) { - eventTable.addItem(new String[]{managementDefinition.processDefinition.getId(), - managementDefinition.processDefinition.getName(), - String.valueOf(managementDefinition.runningInstances.size())}, - managementDefinition.processDefinition.getId()); - }*/ + eventTable.addContainerProperty("type", String.class, null, i18nManager.getMessage(Messages.CRYSTALBALL_EVENT_TYPE), null, Table.ALIGN_LEFT); + eventTable.addContainerProperty("executed", String.class, null, i18nManager.getMessage(Messages.CRYSTALBALL_EVENT_EXECUTED), null, Table.ALIGN_LEFT); eventLayout.addComponent(eventTable); } + + protected void refreshEvents() { + stepButton.setEnabled(false); + showProcessInstanceButton.setVisible(false); + eventTable.removeAllItems(); + fillEventValues(); + } + + protected void fillEventValues() { + for (SimulationEvent originalEvent : simulationEvents) { + boolean executed = true; + for (SimulationEvent event : SimulationRunContext.getEventCalendar().getEvents()) { + if (originalEvent.equals(event)) { + executed = false; + stepButton.setEnabled(true); + showProcessInstanceButton.setCaption(i18nManager.getMessage( + Messages.TASK_PART_OF_PROCESS, definitionMap.get(replayHistoricInstance.getProcessDefinitionId()))); + showProcessInstanceButton.setVisible(true); + break; + } + } + + Object itemId = eventTable.addItem(); + eventTable.getItem(itemId).getItemProperty("type").setValue(originalEvent.getType()); + eventTable.getItem(itemId).getItemProperty("executed").setValue(executed); + } + eventTable.setVisible(true); + } + + protected List> getTransformers() { + List> transformers = new ArrayList>(); + transformers.add(new EventLogProcessInstanceCreateTransformer(PROCESS_INSTANCE_START_EVENT_TYPE, PROCESS_DEFINITION_ID_KEY, SIMULATION_BUSINESS_KEY, VARIABLES_KEY)); + transformers.add(new EventLogUserTaskCompleteTransformer(USER_TASK_COMPLETED_EVENT_TYPE)); + return transformers; + } + + protected Map getReplayHandlers(String processInstanceId) { + Map handlers = new HashMap(); + handlers.put(PROCESS_INSTANCE_START_EVENT_TYPE, new StartReplayLogEventHandler(processInstanceId, PROCESS_DEFINITION_ID_KEY, SIMULATION_BUSINESS_KEY, VARIABLES_KEY)); + handlers.put(USER_TASK_COMPLETED_EVENT_TYPE, new ReplayUserTaskCompleteEventHandler()); + return handlers; + } } diff --git a/modules/activiti-explorer/src/main/resources/messages.properties b/modules/activiti-explorer/src/main/resources/messages.properties index 5171f4a8878643bb0b2d570439624a8744efa3bc..dfa1a4d8d44c75549ab2fb1e9941a30f3a98938e 100644 --- a/modules/activiti-explorer/src/main/resources/messages.properties +++ b/modules/activiti-explorer/src/main/resources/messages.properties @@ -238,6 +238,7 @@ process.start.time = Started {0} process.started.notification = Process {0} has been started process.instance.started.on = Started {0} process.instance.started = Started +process.instance.ended = Ended process.instance.header.tasks = Tasks process.instance.no.tasks=There are no tasks for this process instance. process.instance.header.variables = Variables @@ -438,6 +439,12 @@ email.subject = Subject email.sent.date = Date sent email.received.date = Date received +#Crystalball +crystalball.button.replay=Replay +crystalball.button.nextevent=Execute next event +crystalball.event.type=Event type +crystalball.event.executed=Executed + # Time formatting time.unit.moments=moments time.unit.minute=one minute diff --git a/pom.xml b/pom.xml index afe31a5786306706ee4fc3ad984c7976ac9ae191..ca737fe876a335bc619f936ba3c67f3a94e9a4cd 100755 --- a/pom.xml +++ b/pom.xml @@ -225,6 +225,11 @@ activiti-rest ${project.version} + + org.activiti + activiti-crystalball + ${project.version} + org.activiti activiti-webapp-rest2 @@ -699,6 +704,7 @@ modules/activiti-cdi modules/activiti-osgi modules/activiti-ldap + modules/activiti-crystalball @@ -862,6 +868,7 @@ modules/activiti-diagram-rest modules/activiti-bpmn-layout modules/activiti-simple-workflow + modules/activiti-crystalball true