/*
* JacORB - a free Java ORB
*
* Copyright (C) 2012 Gerald Brose / The JacORB Team.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 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
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public
* License along with this library; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
package org.jacorb.util;
import java.nio.channels.SelectionKey;
import java.nio.channels.SocketChannel;
/**
* defines a single request to be registered with the selector.
* this can be a timed event, I/O event, or I/O event with an
* expiration.
* @author Ciju John {@literal <johnc@ociweb.com>}}
*/
public class SelectorRequest
{
/**
* the types of events to be waited for.
*/
public enum Type
{
CONNECT, ACCEPT, READ, WRITE, TIMER
}
/**
* the current status of the request.
*/
public enum Status
{
PENDING, ASSIGNED, READY, EXPIRED, FAILED, IOERROR, FINISHED, SHUTDOWN, CLOSED
}
public final Type type;
public Status status = null;
public final SocketChannel channel;
public SelectionKey key = null;
public final int op;
public SelectorRequestCallback callback;
public final long nanoDeadline;
// private final ReentrantLock lock = new ReentrantLock();
private final Object lock = new Object();
/**
* Constructs a new SelectorRequest for an I/O event
* @param type is the kind of event to wait for
* @param channel is the I/O on which the event is expected
* @param callback is the object to be notified when the event occurs
* @param nanoDeadline is an expiration time. It is an absolute time based upon System.nanoTime().
* A deadline of '0' is used for no deadline.
*/
public SelectorRequest (Type type,
SocketChannel channel,
SelectorRequestCallback callback,
long nanoDeadline)
{
this.type = type;
switch (type)
{
case CONNECT:
op = SelectionKey.OP_CONNECT;
break;
case READ:
op = SelectionKey.OP_READ;
break;
case WRITE:
op = SelectionKey.OP_WRITE;
break;
default:
op = 0;
}
this.channel = channel;
this.callback = callback;
this.nanoDeadline = (nanoDeadline == 0 ? Long.MAX_VALUE : nanoDeadline);
}
/**
* Constructs a new SelectorRequest for an timer event
* @param callback is the object to be notified when the event occurs
* @param nanoDeadline is an expiration time. It is an absolute time based upon System.nanoTime().
* A deadline of '0' is used for no deadline.
*/
public SelectorRequest (SelectorRequestCallback callback, long nanoDeadline)
{
type = Type.TIMER;
op = 0;
channel = null;
this.callback = callback;
this.nanoDeadline = (nanoDeadline == 0 ? Long.MAX_VALUE : nanoDeadline);
}
/**
* Called by the SelectorManager to notify a change of status. Will wake up
* a thread blocked in waitOnCOmpletion
*/
public void setStatus (Status status)
{
synchronized (lock)
{
this.status = status;
// the below might just need to be notify()
lock.notify();
}
}
/**
* determines if the current status is one of the final statuses
* @return false if the status is PENDING, ASSIGNED, or READY, true for all others
*/
public boolean isFinalized ()
{
return status != null &&
status != Status.PENDING &&
status != Status.ASSIGNED &&
status != Status.READY;
}
/**
* a blocking call to wait for a status change or a timeout.
* @param nanoDeadline is an explicit timeout for waiting on a change
* @return this requester's status after a notification or a timeout.
*/
public Status waitOnCompletion (long nanoDeadline)
{
long myNanoDeadline = (nanoDeadline == 0 ? Long.MAX_VALUE : nanoDeadline);
synchronized (lock)
{
while (myNanoDeadline > System.nanoTime() && !isFinalized())
{
long remaining = myNanoDeadline - System.nanoTime();
long millis = remaining / 1000000;
int nanos = (int)(remaining - (millis * 1000000));
try
{
lock.wait (millis, nanos);
}
catch (InterruptedException e)
{
// ignored
}
catch (IllegalArgumentException ex)
{
// indicates we have run out of time if the value
// of timeout is negative or the value of nanos is
// not in the range 0-999999.
break;
}
}
}
return status;
}
}