Commit 1a2d5e25 authored by hengwen's avatar hengwen

Refactor and docs

parent 1c10ec40
......@@ -16,6 +16,7 @@ import server.restful.model.VehicleModel;
import server.restful.registry.RemoteService;
import server.restful.registry.ServiceRegistry;
import java.io.File;
import java.io.IOException;
import java.util.*;
import java.util.concurrent.CompletableFuture;
......@@ -23,35 +24,26 @@ import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class SimulationService implements Runnable {
private static Map<Integer, SimulationService> instances;
private SimulationModel simulation;
private String uuid;
private SLMontiSimAdapter adapter;
private Map<Integer, SimulatorService> simulators;
private List<VehicleService> vehicles;
private ServiceRegistry registry;
private SimulationStatus status;
private Properties prop;
private Logger logger = LoggerFactory.getLogger(SimulationService.class);
// a map of {simID: result}
Map<Integer, List<VehicleModel>> results;
public SimulationService(int simulationID) {
if (instances == null){
instances = new HashMap<>();
if (results == null) {
results = new HashMap<>();
}
instances.put(simulationID, this);
status = SimulationStatus.READY;
uuid = UUID.randomUUID().toString();
simulation = SimulationDAO.getByID(simulationID);
if (results == null){
results = new HashMap<>();
}
try {
prop = new Properties();
......@@ -66,6 +58,19 @@ public class SimulationService implements Runnable {
this.registry = registry;
}
/**
* Assemble and start the simulation task. This includes
* 1. Read and parse the scenario file.
* 2. Find all the map files.
* 3. Reserve a sub-simulator for each map.
* 6. Transfer map data to all sub-simulators.
* 4. Reserve rmi-server(autopilot) for each vehicle.
* 5. Create vehicles in sub-simulators.
* 6. Run and sync all sub-simulators.
*
* @param registry
* @throws Exception
*/
synchronized public void startSimulation(ServiceRegistry registry) throws Exception {
// prepare map, read scenario
MapModel map = getSimulationMap();
......@@ -81,19 +86,20 @@ public class SimulationService implements Runnable {
vehicles = new ArrayList<>();
simulators = new HashMap<>();
// create vehicles defined in scenario file
for (ExplicitVehicle v: adapter.getVehicles().get()) {
// create vehicles from scenario file
for (ExplicitVehicle v : adapter.getVehicles().get()) {
Path2D sourceTarget = v.getPath();
VehicleService vehicle = new VehicleService(
mapService,
sourceTarget.getStartX(), sourceTarget.getStartY(),
sourceTarget.getDestX(), sourceTarget.getDestY(),
this
this
);
// construct one simulator per sector, by iterating all vehicles the sectors the will need
for (Integer sectorIdx : vehicle.getSectors()) {
// construct one simulator per sector by iterating over all vehicles for the sectors they need
for (Integer sectorIdx : vehicle.getSectors()) {
if (!simulators.containsKey(sectorIdx)) {
// find and reserve a simulator from service registry
RemoteService remoteSimulator = registry.getSimulator();
simulators.put(sectorIdx, new SimulatorService(
uuid, remoteSimulator.getHost(),
......@@ -106,7 +112,7 @@ public class SimulationService implements Runnable {
vehicles.add(vehicle);
}
// setup all remote simulators
// reset setup all sub simulators and transfer map data to them
for (SimulatorService svc : simulators.values()) {
svc.reset();
svc.setMap();
......@@ -118,10 +124,11 @@ public class SimulationService implements Runnable {
}
// run simulation in each simulators until finish
int stepDurationMs = Integer.parseInt(prop.getProperty("simulation_step_ms", "500"));
ExecutorService pool = Executors.newCachedThreadPool();
while (!isSimulationFinished()) {
// start all simulators
runALoop(pool);
runStep(pool, stepDurationMs);
for (VehicleService v : vehicles) {
// collect result, switch simulator if necessary
v.runStep();
......@@ -136,7 +143,7 @@ public class SimulationService implements Runnable {
SimulationDAO.storeSimulationResult(simulation.getId(), results.get(simulation.getId()));
}
public MapModel getSimulationMap(){
public MapModel getSimulationMap() {
ScenarioModel scenario = ScenarioDAO.getByID(simulation.getScenarioID());
adapter = new SLMontiSimAdapter(SimLangTool.parseIntoContainer(scenario.getPath()));
MapModel map = MapDAO.getByName(adapter.getMapName() + ".osm");
......@@ -159,37 +166,18 @@ public class SimulationService implements Runnable {
/**
* Start all simulators to simulator a period of time
*
* @param pool
*/
private void runALoop(ExecutorService pool) {
private void runStep(ExecutorService pool, int stepDurationMs) {
List<Runnable> tasks = new ArrayList<>();
for (SimulatorService sim : simulators.values()) {
tasks.add(new SimulationRunner(
sim,
Integer.parseInt(prop.getProperty("simulation_step_ms", "500")))
);
tasks.add(new SimulationRunner(sim, stepDurationMs));
}
CompletableFuture<?>[] futures = tasks.stream().map(task -> CompletableFuture.runAsync(task, pool)).toArray(CompletableFuture[]::new);
CompletableFuture.allOf(futures).join();
}
@Override
public void run() {
status = SimulationStatus.RUNNING;
try {
startSimulation(registry);
status = SimulationStatus.FINISHED;
} catch (ServiceRegistry.NoServiceException e){
status = SimulationStatus.FAILED;
logger.error("Resource not enough, please make sure there are enough simulators and rmi servers online.", e);
} catch (Exception e) {
status = SimulationStatus.FAILED;
logger.error(e.getMessage(), e);
} finally {
registry.releaseAll();
}
}
class SimulationRunner implements Runnable {
private SimulatorService simulator;
private int duration;
......@@ -205,6 +193,31 @@ public class SimulationService implements Runnable {
}
}
@Override
public void run() {
try {
startSimulation(registry);
} catch (ServiceRegistry.NoServiceException e) {
logger.error("Resource not enough, please make sure there are enough simulators and rmi servers online.", e);
} catch (Exception e) {
logger.error(e.getMessage(), e);
} finally {
registry.releaseAll();
}
}
/**
* @param id id of simulation to check(databaase id)
* @return true if simulation is finished and the result is available in storage
*/
public static boolean isSimulationFinished(int id) {
SimulationModel simulationModel = SimulationDAO.getByID(id);
if (simulationModel == null || simulationModel.getResultPath() == null) {
return false;
}
return new File(simulationModel.getResultPath()).exists();
}
public SimulatorService getSimulatorBySectorIdx(int idx) {
return simulators.get(idx);
}
......@@ -213,24 +226,8 @@ public class SimulationService implements Runnable {
return results.get(simulation.getId());
}
public static List<VehicleModel> getResult(int simID) {
return new SimulationService(-1).results.get(simID);
}
public Properties getProp() {
return prop;
}
public static Map<Integer, SimulationService> getInstances() {
return instances;
}
public SimulationStatus getStatus() {
return status;
}
public enum SimulationStatus {
READY, RUNNING, FAILED, FINISHED
}
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment