diff --git a/src/main/java/lu/jpt/csparqltest/Main.java b/src/main/java/lu/jpt/csparqltest/Main.java index 39525cc..8e2eeff 100644 --- a/src/main/java/lu/jpt/csparqltest/Main.java +++ b/src/main/java/lu/jpt/csparqltest/Main.java @@ -6,12 +6,11 @@ import org.apache.log4j.PropertyConfigurator; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import eu.larkc.csparql.cep.api.RdfStream; import eu.larkc.csparql.core.engine.ConsoleFormatter; import eu.larkc.csparql.core.engine.CsparqlEngine; import eu.larkc.csparql.core.engine.CsparqlEngineImpl; import eu.larkc.csparql.core.engine.CsparqlQueryResultProxy; -import lu.jpt.csparqltest.carexample.CarStreamGenerator; +import lu.jpt.csparqltest.rentacar.RentACarSimulation; public class Main { @@ -37,15 +36,16 @@ public class Main { //logger.debug("Engine from: " + engine.getClass().getProtectionDomain().getCodeSource()); // Create and register stream generator at specific URI - RdfStream carStreamGenerator = new CarStreamGenerator("http://myexample.org/cars"); - engine.registerStream(carStreamGenerator); + RentACarSimulation simulation = new RentACarSimulation(); + engine.registerStream(simulation.getCarStream()); + engine.registerStream(simulation.getDriverStream()); - // Run stream generator - final Thread t = new Thread((Runnable) carStreamGenerator); - t.start(); + // Run simulation that is feeding the streams + Thread simulationThread = new Thread(simulation); + simulationThread.start(); // Now build a query to run - interchangeable - String query = Main.getBreakingDownCarsQuery(); + String query = Main.getSPO(); // Create a result proxy by registering the query at the engine CsparqlQueryResultProxy resultProxy = null; @@ -68,14 +68,29 @@ public class Main { // Unregister the resultProxy (and thus the query) from the engine engine.unregisterQuery(resultProxy.getId()); - // Softly stop the stream generator and unregister it from the engine - ((CarStreamGenerator) carStreamGenerator).pleaseStop(); - engine.unregisterStream(carStreamGenerator.getIRI()); + // Softly stop the simulation and unregister its streams + simulation.pleaseStopSimulation(); + simulationThread.interrupt(); + engine.unregisterStream(simulation.getCarStream().getIRI()); + engine.unregisterStream(simulation.getDriverStream().getIRI()); // That's it! System.exit(0); } + private static String getSPO() { + return "REGISTER QUERY BasicCarInfo AS " + + "PREFIX f: " + + "PREFIX xsd: " + + "PREFIX car: " + + "SELECT ?s ?p ?o " + + "FROM STREAM [RANGE 5s STEP 1s] " + + "FROM STREAM [RANGE 5s STEP 1s] " + + "WHERE { " + + " ?s ?p ?o . " + + "}"; + } + private static String getBasicCarInfoQuery() { return "REGISTER QUERY BasicCarInfo AS " + "PREFIX f: " diff --git a/src/main/java/lu/jpt/csparqltest/rentacar/Car.java b/src/main/java/lu/jpt/csparqltest/rentacar/Car.java new file mode 100644 index 0000000..2ca7b2a --- /dev/null +++ b/src/main/java/lu/jpt/csparqltest/rentacar/Car.java @@ -0,0 +1,111 @@ +package lu.jpt.csparqltest.rentacar; + +import java.util.ArrayList; +import java.util.List; + +import eu.larkc.csparql.cep.api.RdfQuadruple; +import lu.jpt.csparqltest.util.RandomHelper; + +public class Car { + // Fix knowledge about the available car types: + private static final String[] CAR_TYPENAME = {"A", "B", "C"}; + private static final int[] MIN_RPM = {2000, 800, 1400}; + private static final int[] MAX_RPM = {4300, 1900, 2500}; + private static final double[] MIN_TIRE_PRESSURE = {2.9, 3.5, 2.6}; + private static final double[] MAX_TIRE_PRESSURE = {3.2, 3.8, 3.0}; + // Sitzplätze? Reservierungen für X Personen? + + private int id; + private final String IRI; + + private List quads; + + // Car-specific attributes + private final int CAR_TYPE; + + private boolean motorOn; + private int motorRpm; + private int motorMinRpm; + private int motorMaxRpm; + private int speed; + private double tirePressure; + + + public Car(int id, String baseIri) { + this.id = id; + this.IRI = baseIri; + this.quads = new ArrayList(); + this.CAR_TYPE = RandomHelper.nextInt(2); + this.initializeCarType(this.CAR_TYPE); + } + + private void initializeCarType(int carType) { + this.motorOn = false; + this.motorRpm = 0; + this.motorMinRpm = Car.MAX_RPM[carType]; + this.motorMaxRpm = Car.MAX_RPM[carType]; + this.speed = 0; + this.tirePressure = (Car.MIN_TIRE_PRESSURE[carType] + Car.MAX_TIRE_PRESSURE[carType]) / 2.0; + } + + public void turnOn() { + + } + + public void turnOff() { + + } + + public void setHandBrake(boolean on) { + + } + + public void accelerate() { + + } + + public void slowDown() { + + } + + public void crash() { + + } + + public void load() { + + } + + public void unload() { + + } + + /** + * Update internal stuff according to state + */ + public void tick() { + + } + + public int getID() { + return this.id; + } + + public String getIri() { + return this.IRI + "#" + this.id; + } + + public List getQuadruples() { + List result = this.quads; + this.quads = new ArrayList(); + return result; + } + + public String toString() { + StringBuilder sb = new StringBuilder("[#"); + sb.append(this.id); + sb.append("]"); + return sb.toString(); + } + +} diff --git a/src/main/java/lu/jpt/csparqltest/rentacar/CarPool.java b/src/main/java/lu/jpt/csparqltest/rentacar/CarPool.java new file mode 100644 index 0000000..6a00d87 --- /dev/null +++ b/src/main/java/lu/jpt/csparqltest/rentacar/CarPool.java @@ -0,0 +1,50 @@ +package lu.jpt.csparqltest.rentacar; + +import java.util.ArrayList; +import java.util.List; +import java.util.Random; + +public class CarPool { + + private List cars; + private List availableCars; + private Random rand; + + public CarPool(int numberOfCars, String carIri) { + this.rand = new Random(); + this.cars = new ArrayList(); + this.availableCars = new ArrayList(); + for(int i = 0; i < numberOfCars; i++) { + Car newCar = new Car(i, carIri); + this.cars.add(newCar); + this.availableCars.add(newCar); + } + } + + /** + * Fetch a random car from the car pool + * @return Car the random car + */ + public Car takeRandomCar() { + Car randomCar = this.availableCars.get(this.rand.nextInt(this.availableCars.size())); + this.availableCars.remove(randomCar); + return randomCar; + } + + /** + * Return the car back into the car pool + * @param returnedCar The returned car + */ + public void returnCar(Car returnedCar) { + this.availableCars.add(returnedCar); + } + + /** + * Return a copy of the list of cars for simulation purposes. + * @return List List of cars in the CarPool + */ + public List getCars() { + return new ArrayList(this.cars); + } + +} diff --git a/src/main/java/lu/jpt/csparqltest/rentacar/Driver.java b/src/main/java/lu/jpt/csparqltest/rentacar/Driver.java new file mode 100644 index 0000000..a88c443 --- /dev/null +++ b/src/main/java/lu/jpt/csparqltest/rentacar/Driver.java @@ -0,0 +1,89 @@ +package lu.jpt.csparqltest.rentacar; + +import java.util.ArrayList; +import java.util.List; + +import eu.larkc.csparql.cep.api.RdfQuadruple; +import lu.jpt.csparqltest.util.RandomHelper; + +public class Driver { + + private int id; + private final String IRI; + private CarPool carPool; + + private int carUseCycles; + private Car car; + + private List quads; + + public Driver(int id, CarPool carPool, String baseIri) { + this.id = id; + this.carPool = carPool; + this.IRI = baseIri; + this.car = null; + this.quads = new ArrayList(); + // Pick a random behaviour and stick to it. + } + + public int getID() { + return this.id; + } + + public String getIri() { + return this.IRI + "#" + this.id; + } + + /** + * Simulation triggers this from the outside to make the driver do something + * given a car is available. + */ + public void tick() { + if(car == null) { + // Nothing to do, maybe randomly take a car + if(RandomHelper.isLuckyByChance(0.4)) { + this.assignCar(this.carPool.takeRandomCar(), RandomHelper.getRandomNumberWithin(5,20)); + } + } else { + // Do random things with the car + this.useCar(this.car); + // Decrement use cycles + this.carUseCycles--; + if(this.carUseCycles == 0) { + this.returnCar(); + } + } + } + + public void assignCar(Car car, int useCycles) { + this.car = car; + this.carUseCycles = useCycles; + this.quads.add(new RdfQuadruple(this.getIri(), this.IRI+"#took", this.car.getIri(), System.currentTimeMillis())); + this.quads.add(new RdfQuadruple(this.getIri(), this.IRI+"#usagePeriod", useCycles+"^^http://www.w3.org/2001/XMLSchema#integer", System.currentTimeMillis())); + } + + private void useCar(Car car) { + // Whatever, hit the gas, slam the breaks, drift around, drive casually + + } + + private void returnCar() { + this.quads.add(new RdfQuadruple(this.getIri(), this.IRI+"#returned", this.car.getIri(), System.currentTimeMillis())); + this.car = null; + } + + public List getQuadruples() { + List result = this.quads; + this.quads = new ArrayList(); + return result; + } + + public String toString() { + StringBuilder sb = new StringBuilder("[#"); + sb.append(this.id); + sb.append("]"); + return sb.toString(); + } + + +} diff --git a/src/main/java/lu/jpt/csparqltest/rentacar/RentACarSimulation.java b/src/main/java/lu/jpt/csparqltest/rentacar/RentACarSimulation.java new file mode 100644 index 0000000..a827906 --- /dev/null +++ b/src/main/java/lu/jpt/csparqltest/rentacar/RentACarSimulation.java @@ -0,0 +1,98 @@ +package lu.jpt.csparqltest.rentacar; + +import java.util.ArrayList; +import java.util.List; + +import eu.larkc.csparql.cep.api.RdfQuadruple; +import eu.larkc.csparql.cep.api.RdfStream; + +public class RentACarSimulation implements Runnable { + + public static final String BASE_IRI = "http://myexample.org"; + public static final String CAR_IRI = BASE_IRI + "/car"; + public static final String DRIVER_IRI = BASE_IRI + "/driver"; + + private CarPool carPool; + private List drivers; + + private volatile boolean runSimulation; + + private RdfStream carStream; + private RdfStream driverStream; + + + public RentACarSimulation() { + int numberOfCars = 6; + int numberOfCustomers = 1; + // Create a car pool and drivers + this.carPool = new CarPool(numberOfCars, CAR_IRI); + this.drivers = new ArrayList(); + for(int i = 0; i < numberOfCustomers; i++) { + this.drivers.add(new Driver(i, this.carPool, DRIVER_IRI)); + } + // Create streams + this.carStream = new RdfStream(CAR_IRI); + this.driverStream = new RdfStream(DRIVER_IRI); + // Green light for simulation + this.runSimulation = true; + } + + public RdfStream getCarStream() { + return this.carStream; + } + + public RdfStream getDriverStream() { + return this.driverStream; + } + + /** + * All the simulation is happening within its own Thread + */ + @Override + public void run() { + // Run the simulation as long as needed + while(this.runSimulation) { + // A driver will autonomously pick a car, use it for some time and leave it. + for(Driver driver : this.drivers) { + driver.tick(); + } + for(Car car: this.carPool.getCars()) { + car.tick(); + } + // Push the new data into the stream(s) + this.pushDataToStream(); + // Now wait a short while + try { + Thread.sleep(1000); + } catch (InterruptedException e) { + // We got interrupted, so what. + } + } + } + + /** + * Push all the data into the corresponding streams for processing. + */ + private void pushDataToStream() { + for(Driver d : this.drivers) { + List quads = d.getQuadruples(); + for(RdfQuadruple q : quads) { + this.driverStream.put(q); + } + } + for(Car c : this.carPool.getCars()) { + List quads = c.getQuadruples(); + for(RdfQuadruple q : quads) { + this.carStream.put(q); + } + } + } + + /** + * Tells the simulation to stop + */ + public void pleaseStopSimulation() { + this.runSimulation = false; + } + +} diff --git a/src/main/java/lu/jpt/csparqltest/util/RandomHelper.java b/src/main/java/lu/jpt/csparqltest/util/RandomHelper.java new file mode 100644 index 0000000..ebc2b79 --- /dev/null +++ b/src/main/java/lu/jpt/csparqltest/util/RandomHelper.java @@ -0,0 +1,24 @@ +package lu.jpt.csparqltest.util; + +import java.util.Random; + +public class RandomHelper { + + private static Random myRandom = new Random(); + + + private RandomHelper() {} + + public static int nextInt(int bound) { + return RandomHelper.myRandom.nextInt(bound); + } + + public static int getRandomNumberWithin(int min, int max) { + return min + RandomHelper.myRandom.nextInt((max + 1) - min); + } + + public static boolean isLuckyByChance(double chance) { + return RandomHelper.myRandom.nextDouble() < chance; + } + +}