// **********************************************************************
//
// Copyright (c) 2003-2010 ZeroC, Inc. All rights reserved.
//
// This copy of Ice is licensed to you under the terms described in the
// ICE_LICENSE file included in this distribution.
//
// **********************************************************************
package IceInternal;
//
// NOTE: We don't use the java.util.Timer class for few reasons. The
// Java TimerTask is a class not an interface making it more difficult
// to use. The API is also a bit different, cancel() is a TimerTask
// method not a Timer method and calling purge() on the timer on a
// regular basis is required to allow canceled timer task objects to
// be garbage collected.
//
public final class Timer extends Thread
{
//
// Renamed from destroy to _destroy to avoid a deprecation warning caused
// by the destroy method inherited from Thread.
//
public void
_destroy()
{
synchronized(this)
{
if(_instance == null)
{
return;
}
_instance = null;
notify();
_tokens.clear();
_tasks.clear();
}
while(true)
{
try
{
join();
break;
}
catch(java.lang.InterruptedException ex)
{
}
}
}
synchronized public void
schedule(TimerTask task, long delay)
{
if(_instance == null)
{
throw new Ice.CommunicatorDestroyedException();
}
final Token token = new Token(IceInternal.Time.currentMonotonicTimeMillis() + delay, ++_tokenId, 0, task);
Token previous = _tasks.put(task, token);
assert previous == null;
_tokens.add(token);
if(token.scheduledTime < _wakeUpTime)
{
notify();
}
}
synchronized public void
scheduleRepeated(TimerTask task, long period)
{
if(_instance == null)
{
throw new Ice.CommunicatorDestroyedException();
}
final Token token = new Token(IceInternal.Time.currentMonotonicTimeMillis() + period, ++_tokenId, period, task);
Token previous = _tasks.put(task, token);
assert previous == null;
_tokens.add(token);
if(token.scheduledTime < _wakeUpTime)
{
notify();
}
}
synchronized public boolean
cancel(TimerTask task)
{
if(_instance == null)
{
return false;
}
Token token = _tasks.remove(task);
if(token == null)
{
return false;
}
_tokens.remove(token);
return true;
}
//
// Only for use by Instance.
//
Timer(IceInternal.Instance instance)
{
_instance = instance;
String threadName = _instance.initializationData().properties.getProperty("Ice.ProgramName");
if(threadName.length() > 0)
{
threadName += "-";
}
setName(threadName + "Ice.Timer");
start();
}
protected synchronized void
finalize()
throws Throwable
{
IceUtilInternal.Assert.FinalizerAssert(_instance == null);
super.finalize();
}
public void
run()
{
Token token = null;
while(true)
{
synchronized(this)
{
if(_instance != null)
{
//
// If the task we just ran is a repeated task, schedule it
// again for executation if it wasn't canceled.
//
if(token != null && token.delay > 0)
{
if(_tasks.containsKey(token.task))
{
token.scheduledTime = IceInternal.Time.currentMonotonicTimeMillis() + token.delay;
_tokens.add(token);
}
}
}
token = null;
if(_instance == null)
{
break;
}
if(_tokens.isEmpty())
{
_wakeUpTime = Long.MAX_VALUE;
while(true)
{
try
{
wait();
break;
}
catch(java.lang.InterruptedException ex)
{
}
}
}
if(_instance == null)
{
break;
}
while(!_tokens.isEmpty() && _instance != null)
{
long now = IceInternal.Time.currentMonotonicTimeMillis();
Token first = _tokens.first();
if(first.scheduledTime <= now)
{
_tokens.remove(first);
token = first;
if(token.delay == 0)
{
_tasks.remove(token.task);
}
break;
}
_wakeUpTime = first.scheduledTime;
while(true)
{
try
{
wait(first.scheduledTime - now);
break;
}
catch(java.lang.InterruptedException ex)
{
}
}
}
if(_instance == null)
{
break;
}
}
if(token != null)
{
try
{
token.task.runTimerTask();
}
catch(Exception ex)
{
synchronized(this)
{
if(_instance != null)
{
String s = "unexpected exception from task run method in timer thread:\n" + Ex.toString(ex);
_instance.initializationData().logger.error(s);
}
}
}
}
}
}
static private class Token implements Comparable<Token>
{
public
Token(long scheduledTime, int id, long delay, TimerTask task)
{
this.scheduledTime = scheduledTime;
this.id = id;
this.delay = delay;
this.task = task;
}
public int
compareTo(Token r)
{
//
// Token are sorted by scheduled time and token id.
//
if(scheduledTime < r.scheduledTime)
{
return -1;
}
else if(scheduledTime > r.scheduledTime)
{
return 1;
}
if(id < r.id)
{
return -1;
}
else if(id > r.id)
{
return 1;
}
return 0;
}
public boolean
equals(Object obj)
{
if(this == obj)
{
return true;
}
if(obj instanceof Token)
{
return compareTo((Token)obj) == 0;
}
return false;
}
public int
hashCode()
{
return id ^ (int)scheduledTime;
}
long scheduledTime;
int id; // Since we can't compare references, we need to use another id.
long delay;
TimerTask task;
}
private final java.util.SortedSet<Token> _tokens = new java.util.TreeSet<Token>();
private final java.util.Map<TimerTask, Token> _tasks = new java.util.HashMap<TimerTask, Token>();
private Instance _instance;
private long _wakeUpTime = Long.MAX_VALUE;
private int _tokenId = 0;
}