package org.activiti.crystalball.simulator;
/*
* #%L
* simulator
* %%
* Copyright (C) 2012 - 2013 crystalball
* %%
* 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.
* #L%
*/
import org.activiti.crystalball.simulator.evaluator.HistoryEvaluator;
import org.activiti.crystalball.simulator.impl.AcquireJobNotificationEventHandler;
import org.activiti.crystalball.simulator.impl.NoopEventHandler;
import org.activiti.crystalball.simulator.impl.persistence.entity.ResultEntity;
import org.activiti.crystalball.simulator.impl.persistence.entity.SimulationRunEntity;
import org.activiti.engine.ProcessEngine;
import org.activiti.engine.impl.jobexecutor.JobExecutor;
import org.activiti.engine.impl.util.ClockUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.FactoryBean;
import java.util.*;
public class SimulationRun {
private static Logger log = LoggerFactory.getLogger(SimulationRun.class.getName());
/** Map for eventType -> event handlers to execute events on simulation engine */
private Map<String, SimulationEventHandler> customEventHandlerMap;
private List<HistoryEvaluator> historyEvaluators;
/** simulation run event handlers - e.g. specific handlers for managing simulation time events*/
private HashMap<String, SimulationEventHandler> eventHandlerMap;
protected FactoryBean<ProcessEngine> processEngineFactory;
protected FactoryBean<EventCalendar> eventCalendarFactory;
public SimulationRun() {
}
public SimulationRun(FactoryBean<EventCalendar> eventCalendarFactory, FactoryBean<ProcessEngine> processEngineFactory, Map<String, SimulationEventHandler> eventHandlerMap, List<HistoryEvaluator> historyEvaluators) {
this.eventCalendarFactory = eventCalendarFactory;
this.processEngineFactory = processEngineFactory;
this.eventHandlerMap = new HashMap<String, SimulationEventHandler>();
// init internal event handler map.
eventHandlerMap.put( SimulationEvent.TYPE_END_SIMULATION, new NoopEventHandler() );
this.customEventHandlerMap = eventHandlerMap;
this.historyEvaluators = historyEvaluators;
}
public SimulationRun(FactoryBean<EventCalendar> eventCalendarFactory, FactoryBean<ProcessEngine> processEngineFactory, Map<String, SimulationEventHandler> customEventHandlerMap, List<HistoryEvaluator> historyEvaluators, JobExecutor jobExecutor) {
this(eventCalendarFactory, processEngineFactory, customEventHandlerMap, historyEvaluators);
// init internal event handler map.
eventHandlerMap.put( SimulationEvent.TYPE_ACQUIRE_JOB_NOTIFICATION_EVENT, new AcquireJobNotificationEventHandler(jobExecutor) );
}
public List<ResultEntity> execute(Date simDate, Date dueDate) throws Exception {
// init new process engine
ProcessEngine processEngine = processEngineFactory.getObject();
// add context in which simulation run is executed
SimulationRunContext.setEventCalendar(eventCalendarFactory.getObject());
SimulationRunContext.setProcessEngine(processEngine);
// run simulation
// init context and task calendar and simulation time is set to current
ClockUtil.setCurrentTime( simDate);
if (dueDate != null)
SimulationRunContext.getEventCalendar().addEvent(new SimulationEvent( dueDate.getTime(), SimulationEvent.TYPE_END_SIMULATION, null));
initHandlers();
SimulationEvent event = SimulationRunContext.getEventCalendar().removeFirstEvent();
if (event != null)
ClockUtil.setCurrentTime( new Date(event.getSimulationTime()));
while( !simulationEnd( dueDate, event) ) {
execute( event);
event = SimulationRunContext.getEventCalendar().removeFirstEvent();
if (event != null)
ClockUtil.setCurrentTime( new Date( event.getSimulationTime()));
}
List<ResultEntity> simulationResults = evaluate(null);
// remove simulation from simulation context
SimulationRunContext.removeEventCalendar();
SimulationRunContext.removeProcessEngine();
processEngine.close();
return simulationResults;
}
/**
* execute simulation run in persistent mode - all results are stored in the database
* @param simulationRun
* @throws Exception
*/
public void execute(SimulationRunEntity simulationRun) throws Exception {
// init new process engine
ProcessEngine processEngine = processEngineFactory.getObject();
// add context in which simulation run is executed
SimulationRunContext.setEventCalendar(eventCalendarFactory.getObject());
SimulationRunContext.setProcessEngine(processEngine);
// run simulation
// init context and task calendar and simulation time is set to current
ClockUtil.setCurrentTime( simulationRun.getSimulation().getStart());
if (simulationRun.getSimulation().getSeed() != null)
SimUtils.setSeed(simulationRun.getSimulation().getSeed() + Long.parseLong(simulationRun.getId()));
Date endDate = simulationRun.getSimulation().getEnd();
if (simulationRun.getSimulation().getEnd() != null)
SimulationRunContext.getEventCalendar().addEvent(new SimulationEvent( endDate.getTime(), SimulationEvent.TYPE_END_SIMULATION, null));
initHandlers();
SimulationEvent event = SimulationRunContext.getEventCalendar().removeFirstEvent();
if (event != null)
ClockUtil.setCurrentTime( new Date(event.getSimulationTime()));
while( !simulationEnd( endDate, event) ) {
execute( event);
event = SimulationRunContext.getEventCalendar().removeFirstEvent();
if (event != null)
ClockUtil.setCurrentTime( new Date( event.getSimulationTime()));
}
evaluate(simulationRun);
// remove simulation from simulation context
SimulationRunContext.removeEventCalendar();
SimulationRunContext.removeProcessEngine();
processEngine.close();
}
private void initHandlers() {
for( SimulationEventHandler handler : eventHandlerMap.values()) {
handler.init();
}
for( SimulationEventHandler handler : customEventHandlerMap.values()) {
handler.init();
}
}
private static boolean simulationEnd(Date dueDate, SimulationEvent event) {
if ( dueDate != null)
return event == null || ( ClockUtil.getCurrentTime().after( dueDate ));
return event == null;
}
/**
* evaluate sim. results
* @param context
* @return
*/
private List<ResultEntity> evaluate(SimulationRunEntity simulationRun) {
List<ResultEntity> resultList = new ArrayList<ResultEntity>();
for ( HistoryEvaluator evaluator : historyEvaluators ) {
evaluator.evaluate( simulationRun);
}
return resultList;
}
private void execute(SimulationEvent event) {
// set simulation time to the next event for process engine too
log.info( "Simulation time:" + ClockUtil.getCurrentTime());
// internal handlers first
SimulationEventHandler handler = eventHandlerMap.get( event.getType() );
if ( handler != null) {
log.debug("Handling event of type[{}] internaly.", event.getType());
handler.handle( event);
} else {
handler = customEventHandlerMap.get( event.getType() );
if ( handler != null) {
log.debug("Handling event of type[{}].", event.getType());
handler.handle( event);
} else
log.warn("Event type[{}] does not have any handler assigned.", event.getType());
}
}
public Map<String, SimulationEventHandler> getEventHandlerMap() {
return customEventHandlerMap;
}
public void setEventHandlerMap(
Map<String, SimulationEventHandler> eventHandlerMap) {
this.customEventHandlerMap = eventHandlerMap;
}
public ProcessEngine getProcessEngine() throws Exception {
return processEngineFactory.getObject();
}
}