/**
* Copyright (C) 2008 Hal Hildebrand. All rights reserved.
*
* This file is part of the Prime Mover Event Driven Simulation Framework.
*
* This program is free software: you can redistribute it and/or modify it under
* the terms of the GNU Affero General Public License as published by the Free
* Software Foundation, either version 3 of the License, or (at your option) any
* later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more
* details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.hellblazer.primeMover.runtime;
import static com.hellblazer.primeMover.runtime.BlockingSleep.BLOCKING_SLEEP_INSTANCE;
import static com.hellblazer.primeMover.runtime.BlockingSleep.SLEEP_EVENT;
import static com.hellblazer.primeMover.runtime.Framework.postContinuingEvent;
import static com.hellblazer.primeMover.runtime.SimulationEnd.END_SIMULATION_METHOD;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import com.hellblazer.primeMover.Blocking;
import com.hellblazer.primeMover.Controller;
import com.hellblazer.primeMover.SynchronousQueue;
/**
* The implementation of the static API to the simulation kernel.
*
* @author <a href="mailto:hal.hildebrand@gmail.com">Hal Hildebrand</a>
*/
final public class Kairos {
private static Method RUN_METHOD = getRunMethod();
/**
* Advance the simulation time, blocking the event invoking this API until
* such time is reached in the simulation
*
* @param duration
* - the duration to advance the simulation
*/
@Blocking
public static void blockingSleep(long duration) {
try {
postContinuingEvent(BLOCKING_SLEEP_INSTANCE,
new Object[] { duration }, SLEEP_EVENT);
} catch (Throwable e) {
throw new IllegalStateException(
"No exception should have been thrown",
e);
}
}
/**
* Schedule the call of the static event in the simulation at the indicated
* simulation time
*
* @param time
* @param event
* @param arguments
*/
public static void callStatic(long time, Method method, Object... arguments) {
int modifiers = method.getModifiers();
if (Modifier.isStatic(modifiers) && Modifier.isPublic(modifiers)) {
getController().postEvent(time, new StaticEntityReference(method),
0, arguments);
} else {
throw new IllegalArgumentException(
"Must be a public static event: "
+ method.toGenericString());
}
}
/**
* Schedule the call of the static event in the simulation at the current
* time
*
* @param event
* @param arguments
*/
public static void callStatic(Method method, Object... arguments) {
callStatic(currentTime(), method, arguments);
}
/**
* Create a channel
*
* @return
*/
public static <T> SynchronousQueue<T> createChannel(Class<T> elementType) {
return new SynchronousQueueImpl.entity<T>(Framework.getController());
}
/**
* Answer the current time of the simulation
*
* @return
*/
public static long currentTime() {
return getController().getCurrentTime();
}
/**
* End the simulation at the current time
*/
public static void endSimulation() {
endSimulationAt(currentTime() + 1);
}
/**
* End the simulation at the indicated time
*
* @param time
*/
public static void endSimulationAt(long time) {
callStatic(time, END_SIMULATION_METHOD);
}
/**
* @return the current controller of the thread
* @throws IllegalStateException
* - if there is no controller set for the current thread
*/
public static Controller getController() {
return Framework.getController();
}
private static Method getRunMethod() {
try {
return Framework.class.getDeclaredMethod("run", Runnable.class);
} catch (Exception e) {
throw new IllegalStateException(
"Unable to acquire run(Runnable) event",
e);
}
}
/**
* @return the current controller of the thread, or null if none.
*/
public static Controller queryController() {
return Framework.queryController();
}
/**
* Execute a runnable at the currently scheduled simulatioin time.
*
* @param r
* - the Runnable to schedule
*/
public static void run(Runnable r) {
callStatic(RUN_METHOD, r);
}
/**
* Execute a runnable at the indicated instant in the simulation
*
* @param r
* - the Runnable to schedule
* @param instant
* - the instant in time the runnable is scheduled
*/
public static void runAt(Runnable r, long instant) {
callStatic(instant, RUN_METHOD, r);
}
/**
* Set the current thread's simulation controller
*
* @param controller
*/
public static void setController(Controller controller) {
if (!(controller instanceof Devi)) {
throw new IllegalArgumentException(
"Controller must be instanceof Devi");
}
Framework.setController((Devi) controller);
}
/**
* Answer true if the simulation is running
*
* @return
*/
public static boolean simulationIsRunning() {
return Framework.simulationIsRunning();
}
/**
* Advance the simulation time. Do not block the event invoking this API
*
* @param duration
* - the measure of time to advance the simulation
*/
public static void sleep(long duration) {
getController().advance(duration);
}
private Kairos() {
}
}