/* 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 * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ 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.engine.runtime.ProcessInstance; import org.activiti.explorer.ExplorerApp; import org.activiti.explorer.I18nManager; import org.activiti.explorer.Messages; import org.activiti.explorer.ui.custom.DetailPanel; import org.activiti.explorer.ui.mainlayout.ExplorerLayout; import org.activiti.explorer.ui.variable.VariableRendererManager; import com.vaadin.data.Item; import com.vaadin.data.Property; import com.vaadin.data.Property.ValueChangeEvent; import com.vaadin.data.Property.ValueChangeListener; import com.vaadin.ui.Alignment; import com.vaadin.ui.Button; import com.vaadin.ui.Button.ClickEvent; import com.vaadin.ui.Button.ClickListener; import com.vaadin.ui.HorizontalLayout; import com.vaadin.ui.Label; import com.vaadin.ui.NativeSelect; import com.vaadin.ui.Table; import com.vaadin.ui.themes.Reindeer; /** * @author Tijs Rademakers */ 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; protected HorizontalLayout instanceLayout; protected NativeSelect definitionSelect; protected Button replayButton; protected Table instanceTable; protected HorizontalLayout eventLayout; protected Button stepButton; protected Button showProcessInstanceButton; protected Table eventTable; protected Label noMembersTable; protected List<ProcessDefinition> definitionList; protected Map<String, ProcessDefinition> definitionMap = new HashMap<String, ProcessDefinition>(); protected List<HistoricProcessInstance> instanceList; protected List<SimulationEvent> 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(); this.i18nManager = ExplorerApp.get().getI18nManager(); initializeDefinitionMap(); init(); initializeCurrentValues(); } protected void initializeDefinitionMap() { for (ProcessDefinition definition : definitionList) { definitionMap.put(definition.getId(), definition); } } 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<HistoricProcessInstance> replayProcessInstanceList = historyService.createHistoricProcessInstanceQuery() .processInstanceBusinessKey(SIMULATION_BUSINESS_KEY) .orderByProcessInstanceStartTime() .desc() .list(); if (replayProcessInstanceList != null && !replayProcessInstanceList.isEmpty()) { replayHistoricInstance = replayProcessInstanceList.get(0); } refreshEvents(); } } protected void init() { setSizeFull(); addStyleName(Reindeer.PANEL_LIGHT); initProcessInstances(); initEvents(); } 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); selectLayout.setWidth(50, UNITS_PERCENTAGE); addDetailComponent(selectLayout); definitionSelect = new NativeSelect(i18nManager.getMessage(Messages.DEPLOYMENT_HEADER_DEFINITIONS)); definitionSelect.setImmediate(true); for (ProcessDefinition definition : definitionList) { definitionSelect.addItem(definition.getId()); definitionSelect.setItemCaption(definition.getId(), definition.getName()); } definitionSelect.addListener(new ValueChangeListener() { private static final long serialVersionUID = 1L; @Override public void valueChange(ValueChangeEvent event) { if (definitionSelect.getValue() != null) { String selectedDefinitionId = (String) definitionSelect.getValue(); ExplorerApp.get().setCrystalBallCurrentDefinitionId(selectedDefinitionId); refreshInstances(selectedDefinitionId); } } }); selectLayout.addComponent(definitionSelect); replayButton = new Button(i18nManager.getMessage(Messages.CRYSTALBALL_BUTTON_REPLAY)); replayButton.setEnabled(false); replayButton.addListener(new ClickListener() { private static final long serialVersionUID = 1L; @Override public void buttonClick(ClickEvent event) { if (instanceTable.getValue() != null) { String processInstanceId = (String) instanceTable.getValue(); ExplorerApp.get().setCrystalBallCurrentInstanceId(processInstanceId); List<EventLogEntry> eventLogEntries = managementService.getEventLogEntriesByProcessInstanceId(processInstanceId); if (eventLogEntries == null || eventLogEntries.isEmpty()) 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<HistoricProcessInstance> replayProcessInstanceList = historyService.createHistoricProcessInstanceQuery() .processInstanceBusinessKey(SIMULATION_BUSINESS_KEY) .orderByProcessInstanceStartTime() .desc() .list(); if (replayProcessInstanceList != null && !replayProcessInstanceList.isEmpty()) { replayHistoricInstance = replayProcessInstanceList.get(0); } refreshEvents(); } } }); selectLayout.addComponent(replayButton); selectLayout.setComponentAlignment(replayButton, Alignment.MIDDLE_LEFT); instanceLayout = new HorizontalLayout(); instanceLayout.setWidth(100, UNITS_PERCENTAGE); addDetailComponent(instanceLayout); initInstancesTable(); } protected void initProcessInstanceTitle(HorizontalLayout instancesHeader) { Label titleHeader = new Label(i18nManager.getMessage(Messages.PROCESS_INSTANCES)); titleHeader.addStyleName(ExplorerLayout.STYLE_H3); instancesHeader.addComponent(titleHeader); } protected void initInstancesTable() { if (instanceList == null || instanceList.isEmpty()) { noMembersTable = new Label(i18nManager.getMessage(Messages.ADMIN_RUNNING_NONE_FOUND)); instanceLayout.addComponent(noMembersTable); } else { instanceTable = new Table(); instanceTable.setWidth(100, UNITS_PERCENTAGE); instanceTable.setHeight(200, UNITS_PIXELS); instanceTable.setEditable(false); instanceTable.setImmediate(true); instanceTable.setSelectable(true); instanceTable.setSortDisabled(false); 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_ENDED), null, Table.ALIGN_LEFT); fillInstanceValues(); instanceTable.addListener(new Property.ValueChangeListener() { private static final long serialVersionUID = 1L; public void valueChange(ValueChangeEvent event) { Item item = instanceTable.getItem(event.getProperty().getValue()); if (item != null) { replayButton.setEnabled(true); } else { replayButton.setEnabled(false); } } }); instanceLayout.addComponent(instanceTable); } } protected void refreshInstances(String processDefinitionId) { instanceList = historyService.createHistoricProcessInstanceQuery() .processDefinitionId(processDefinitionId) .orderByProcessInstanceStartTime() .desc() .list(); instanceTable.removeAllItems(); fillInstanceValues(); } protected void fillInstanceValues() { for (HistoricProcessInstance processInstance : instanceList) { ProcessDefinition definition = definitionMap.get(processInstance.getProcessDefinitionId()); String definitionName = ""; if (definition != null) { if (definition.getName() != null) { definitionName = definition.getName(); } else { definitionName = definition.getId(); } definitionName += " (v" + definition.getVersion() + ")"; } instanceTable.addItem(new String[]{ processInstance.getId(), definitionName, processInstance.getStartTime().toString(), processInstance.getEndTime() != null ? processInstance.getEndTime().toString() : ""}, processInstance.getId()); } } protected void initEvents() { HorizontalLayout eventsHeader = new HorizontalLayout(); eventsHeader.setSpacing(true); 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().isEmpty()) { 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); initEventsTable(); } protected void initEventTitle(HorizontalLayout eventsHeader) { Label usersHeader = new Label(i18nManager.getMessage(Messages.ADMIN_DEFINITIONS)); usersHeader.addStyleName(ExplorerLayout.STYLE_H3); eventsHeader.addComponent(usersHeader); } protected void initEventsTable() { eventTable = new Table(); eventTable.setVisible(false); eventTable.setWidth(100, UNITS_PERCENTAGE); eventTable.setHeight(250, UNITS_PIXELS); eventTable.setEditable(false); eventTable.setImmediate(true); eventTable.setSelectable(true); eventTable.setSortDisabled(false); 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; if (SimulationRunContext.getEventCalendar() != null && SimulationRunContext.getEventCalendar().getEvents() != null) { for (SimulationEvent event : SimulationRunContext.getEventCalendar().getEvents()) { if (originalEvent.equals(event)) { executed = false; stepButton.setEnabled(true); break; } } } Object itemId = eventTable.addItem(); eventTable.getItem(itemId).getItemProperty("type").setValue(originalEvent.getType()); eventTable.getItem(itemId).getItemProperty("executed").setValue(executed); } if (replayHistoricInstance != null && replayHistoricInstance.getId() != null) { ProcessInstance testInstance = runtimeService.createProcessInstanceQuery().processInstanceId(replayHistoricInstance.getId()).singleResult(); if (testInstance != null) { showProcessInstanceButton.setCaption(i18nManager.getMessage( Messages.TASK_PART_OF_PROCESS, definitionMap.get(replayHistoricInstance.getProcessDefinitionId()))); showProcessInstanceButton.setVisible(true); } } eventTable.setVisible(true); } protected List<Function<EventLogEntry, SimulationEvent>> getTransformers() { List<Function<EventLogEntry, SimulationEvent>> transformers = new ArrayList<Function<EventLogEntry, SimulationEvent>>(); 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<String, SimulationEventHandler> getReplayHandlers(String processInstanceId) { Map<String, SimulationEventHandler> handlers = new HashMap<String, SimulationEventHandler>(); 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; } }