package jadex.commons.service.clock;
import jadex.commons.Future;
import jadex.commons.IChangeListener;
import jadex.commons.IFuture;
import jadex.commons.concurrent.IResultListener;
import jadex.commons.concurrent.IThreadPool;
import jadex.commons.service.BasicService;
import jadex.commons.service.IServiceProvider;
import jadex.commons.service.SServiceProvider;
import jadex.commons.service.threadpool.IThreadPoolService;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
/**
* A clock service abstracts away from clock implementations.
* The clock service is meant to be kept constant during runtime.
*/
public class ClockService extends BasicService implements IClockService
{
//-------- attributes --------
/** The clock. */
protected IClock clock;
/** The threadpool. */
protected IThreadPoolService threadpool;
/** The clock listeners. */
protected List listeners;
/** The provider. */
protected IServiceProvider provider;
/** The clock type. */
protected ClockCreationInfo cinfo;
//-------- constructors --------
/**
* Create a new clock service.
*/
public ClockService(ClockCreationInfo cinfo, IServiceProvider provider)
{
this(cinfo, provider, null);
}
/**
* Create a new clock service.
*/
public ClockService(ClockCreationInfo cinfo, IServiceProvider provider, Map properties)
{
super(provider.getId(), IClockService.class, properties);
this.cinfo = cinfo;
this.provider = provider;
this.listeners = Collections.synchronizedList(new ArrayList());
}
/**
* Get the current time.
* @return The current time.
*/
public long getTime()
{
return clock.getTime();
}
/**
* Get the current tick.
* @return The current tick.
*/
public double getTick()
{
return clock.getTick();
}
/**
* Get the clocks start time.
* @return The start time.
*/
public long getStarttime()
{
return clock.getStarttime();
}
/**
* Get the clock delta.
* @return The clock delta.
*/
public long getDelta()
{
return clock.getDelta();
}
/**
* Set the clock delta.
* param delta The new clock delta.
*/
public void setDelta(long delta)
{
clock.setDelta(delta);
}
/**
* Get the clock state.
* @return The clock state.
*/
public String getState()
{
return clock.getState();
}
/**
* Get the clocks dilation.
* @return The clocks dilation.
* // Hack!!! only for continuous clock.
*/
public double getDilation()
{
return ((ContinuousClock)clock).getDilation();
}
/**
* Set the clocks dilation.
* @param dilation The clocks dilation.
* // Hack. Remove? only for continuous
*/
public void setDilation(double dilation)
{
((ContinuousClock)clock).setDilation(dilation);
}
/**
* Get the clock type.
* @return The clock type.
*/
public String getClockType()
{
return clock.getType();
}
/**
* Create a new timer.
* The unit of the timespan value depends on the clock implementation.
* For system clocks, the time value should adhere to the time representation
* as used by {@link System#currentTimeMillis()}.
*
* @param timespan The relative timespan after which the timed object should be notified.
* @param to The timed object.
*/
public ITimer createTimer(long time, ITimedObject to)
{
return clock.createTimer(time, to);
}
/**
* Create a new tick timer.
* todo: @param tickcount The number of ticks.
* @param to The timed object.
*/
public ITimer createTickTimer(ITimedObject to)
{
return clock.createTickTimer(to);
}
/**
* Get the next timer.
* @return The next timer.
*/
public ITimer getNextTimer()
{
return clock.getNextTimer();
}
/**
* Get all active timers.
* @return The active timers.
*/
public ITimer[] getTimers()
{
return clock.getTimers();
}
/**
* Add a change listener.
* @param listener The change listener.
*/
public void addChangeListener(IChangeListener listener)
{
this.listeners.add(listener);
clock.addChangeListener(listener);
}
/**
* Remove a change listener.
* @param listener The change listener.
*/
public void removeChangeListener(IChangeListener listener)
{
this.listeners.remove(listener);
clock.removeChangeListener(listener);
}
/**
* Advance one event.
* @return True, if clock could be advanced.
*/
public boolean advanceEvent()
{
if(clock instanceof ISimulationClock)
return ((ISimulationClock)clock).advanceEvent();
else
throw new RuntimeException("AdvanceEvent only possible for simulation clocks: "+clock);
}
/**
* Start the clock.
*/
public void start()
{
clock.start();
}
/**
* Stop the clock.
*/
public synchronized void stop()
{
clock.stop();
}
//-------- IPlatformService interface --------
/**
* Start the service.
*/
public IFuture startService()
{
// System.out.println("start clock: "+this);
final Future ret = new Future();
SServiceProvider.getServiceUpwards(provider, IThreadPoolService.class)
.addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
threadpool = (IThreadPoolService)result;
clock = createClock(cinfo, threadpool);
clock.start();
ClockService.super.startService().addResultListener(new IResultListener()
{
public void resultAvailable(Object source, Object result)
{
ret.setResult(ClockService.this);
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
});
}
public void exceptionOccurred(Object source, Exception exception)
{
ret.setException(exception);
}
});
return ret;
}
/**
* Shutdown the service.
* @param listener The listener.
*/
public IFuture shutdownService()
{
clock.dispose();
return super.shutdownService();
}
//--------- methods --------
/**
* Get the clock.
* @return The clock.
* /
public synchronized IClock getClock()
{
return clock;
}*/
/**
* Set the clock.
* @param clock The new clock.
*/
public void setClock(String type, IThreadPool tp)
{
IClock clock;
if(IClock.TYPE_CONTINUOUS.equals(type))
clock = new ContinuousClock(this.clock, tp);
else if(IClock.TYPE_SYSTEM.equals(type))
clock = new SystemClock(this.clock, tp);
else if(IClock.TYPE_TIME_DRIVEN.equals(type))
clock = new SimulationTickClock(this.clock);
else if(IClock.TYPE_EVENT_DRIVEN.equals(type))
clock = new SimulationEventClock(this.clock);
else
throw new RuntimeException("Unknown clock type: "+type);
this.clock.dispose();
this.clock = clock;
for(int i=0; i<listeners.size(); i++)
{
this.clock.addChangeListener((IChangeListener)listeners.get(i));
}
}
/**
* Create a clock.
*/
public static IClock createClock(ClockCreationInfo cinfo, IThreadPool tp)
{
IClock ret;
if(IClock.TYPE_CONTINUOUS.equals(cinfo.getClockType()))
{
ret = new ContinuousClock(cinfo.getName(), cinfo.getStart(), cinfo.getDilation(), tp);
}
else if(IClock.TYPE_SYSTEM.equals(cinfo.getClockType()))
{
ret = new SystemClock(cinfo.getName(), cinfo.getDelta(), tp);
}
else if(IClock.TYPE_TIME_DRIVEN.equals(cinfo.getClockType()))
{
ret = new SimulationTickClock(cinfo.getName(), cinfo.getStart(), cinfo.getDelta());
}
else if(IClock.TYPE_EVENT_DRIVEN.equals(cinfo.getClockType()))
{
ret = new SimulationEventClock(cinfo.getName(), cinfo.getStart(), cinfo.getDelta());
}
else
{
throw new RuntimeException("Unknown clock type: "+cinfo.getClockType());
}
return ret;
}
}