net.sourceforge.jtds.util.TimerThread Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of jtds Show documentation
Show all versions of jtds Show documentation
jTDS is an open source 100% pure Java (type 4) JDBC 3.0 driver
for Microsoft SQL Server (6.5, 7, 2000, 2005, 2008, 2012) and Sybase ASE
(10, 11, 12, 15). jTDS is based on FreeTDS and is currently the fastest
production-ready JDBC driver for SQL Server and Sybase. jTDS is 100% JDBC
3.0 compatible, supporting forward-only and scrollable/updateable ResultSets
and implementing all the DatabaseMetaData and ResultSetMetaData methods.
// jTDS JDBC Driver for Microsoft SQL Server and Sybase
// Copyright (C) 2004 The jTDS Project
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library 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
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
package net.sourceforge.jtds.util;
import java.util.LinkedList;
import java.util.ListIterator;
/**
* Simple timer class used to implement login and query timeouts.
*
* This thread runs as a Daemon thread to ensure that the java VM will exit
* correctly when normal execution is complete.
*
* It provides both a singleton implementation and a default constructor for
* the case when more than one timer thread is desired.
*
* @author Alin Sinpalean
* @author Mike Hutchinson
* @version $Id: TimerThread.java,v 1.5.2.1 2009/07/23 16:18:51 ickzon Exp $
*/
public class TimerThread extends Thread {
/**
* Interface to be implemented by classes that request timer services.
*/
public interface TimerListener {
/**
* Event to be fired when the timeout expires.
*/
void timerExpired();
}
/**
* Internal class associating a login or query timeout value with a target
* TimerListener
.
*/
private static class TimerRequest {
/** The time when this timeout will expire. */
final long time;
/** Target to notify when the timeout expires. */
final TimerListener target;
/**
* Create a TimerRequest
.
*
* @param timeout the desired timeout in milliseconds
* @param target the target object; one of SharedSocket
or
* TdsCore
* @throws IllegalArgumentException if the timeout is negative or 0
*/
TimerRequest(int timeout, TimerListener target) {
if (timeout <= 0) {
throw new IllegalArgumentException("Invalid timeout parameter "
+ timeout);
}
this.time = System.currentTimeMillis() + (timeout);
this.target = target;
}
}
/** Singleton instance. */
private static TimerThread instance;
/** List of TimerRequest
s to execute, ordered by time. */
private final LinkedList timerList = new LinkedList();
/** Time when the first request time out should occur. */
private long nextTimeout;
/**
* Singleton getter.
*/
public static synchronized TimerThread getInstance() {
if (instance == null) {
instance = new TimerThread();
instance.start();
}
return instance;
}
/**
* Construct a new TimerThread
instance.
*/
public TimerThread() {
// Set the thread name
super("jTDS TimerThread");
// Ensure that this thread does not prevent the VM from exiting
this.setDaemon(true);
}
/**
* Execute the TimerThread
main loop.
*/
public void run() {
synchronized (timerList) {
while (true) {
try {
if (nextTimeout == 0) {
// If nextTimeout == 0 (i.e. there are no more requests
// in the queue) wait indefinitely -- wait(0)
timerList.wait(0);
} else {
long ms = nextTimeout - System.currentTimeMillis();
if (ms > 0) {
// positive timeout, wait appropriately
timerList.wait(ms);
}
}
// Fire expired timeout requests
long time = System.currentTimeMillis();
while (!timerList.isEmpty()) {
// Examine the head of the list and see
// if the timer has expired.
TimerRequest t = (TimerRequest) timerList.getFirst();
if (t.time > time) {
break; // No timers have expired
}
// Notify target of timeout
t.target.timerExpired();
// Remove the fired timeout request
timerList.removeFirst();
}
// Determine next timeout
updateNextTimeout();
} catch (InterruptedException e) {
// nop
}
}
}
}
/**
* Add a timer request to the queue.
*
* The queue is ordered by time so that the head of the list is always the
* first timer to expire.
*
* @param timeout the interval in milliseconds after which the timer will
* expire
* @param l TimerListener
to be notified on timeout
* @return a handle to the timer request, that can later be used with
* cancelTimer
*/
public Object setTimer(int timeout, TimerListener l) {
// Create a new timer request
TimerRequest t = new TimerRequest(timeout, l);
synchronized (timerList) {
if (timerList.isEmpty()) {
// List was empty, just add new request
timerList.add(t);
} else {
// Tiny optimization; new requests will usually go to the end
TimerRequest crt = (TimerRequest) timerList.getLast();
if (t.time >= crt.time) {
timerList.addLast(t);
} else {
// Iterate the list and insert it into the right place
for (ListIterator li = timerList.listIterator(); li.hasNext(); ) {
crt = (TimerRequest) li.next();
if (t.time < crt.time) {
li.previous();
li.add(t);
break;
}
}
}
}
// If this request is now the first in the list, interrupt timer
if (timerList.getFirst() == t) {
nextTimeout = t.time;
this.interrupt();
}
}
// Return the created request as timer handle
return t;
}
/**
* Remove a redundant timer before it expires.
*
* @param handle handle to the request to be removed from the queue (a
* TimerRequest
instance)
* @return true
if timer had not expired
*/
public boolean cancelTimer(Object handle) {
TimerRequest t = (TimerRequest) handle;
synchronized (timerList) {
boolean result = timerList.remove(t);
if (nextTimeout == t.time) {
updateNextTimeout();
}
return result;
}
}
/**
* Check whether a timer has expired.
*
* @param handle handle to the request to be checked for expiry (a
* TimerRequest
instance)
* @return true
if timer has expired
*/
public boolean hasExpired(Object handle) {
TimerRequest t = (TimerRequest) handle;
synchronized (timerList) {
return !timerList.contains(t);
}
}
/** Internal method that updates the value of {@link #nextTimeout}. */
private void updateNextTimeout() {
nextTimeout = timerList.isEmpty() ? 0
: ((TimerRequest) timerList.getFirst()).time;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy