/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Oracle designates this
* particular file as subject to the "Classpath" exception as provided
* by Oracle in the LICENSE file that accompanied this code.
*
* This code 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 General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
/**
* Base implementation class for selectable channels.
*
* <p> This class defines methods that handle the mechanics of channel
* registration, deregistration, and closing. It maintains the current
* blocking mode of this channel as well as its current set of selection keys.
* It performs all of the synchronization required to implement the {@link
* java.nio.channels.SelectableChannel} specification. Implementations of the
* abstract protected methods defined in this class need not synchronize
* against other threads that might be engaged in the same operations. </p>
*
*
* @author Mark Reinhold
* @author Mike McCloskey
* @author JSR-51 Expert Group
* @since 1.4
*/
public abstract class AbstractSelectableChannel
extends SelectableChannel
{
// The provider that created this channel
// Keys that have been created by registering this channel with selectors.
// They are saved because if this channel is closed the keys must be
// deregistered. Protected by keyLock.
//
// Lock for key set and count
// Lock for registration and configureBlocking operations
// Blocking mode, protected by regLock
boolean blocking = true;
/**
* Initializes a new instance of this class.
*/
}
/**
* Returns the provider that created this channel.
*
* @return The provider that created this channel
*/
return provider;
}
// -- Utility methods for the key set --
int i = 0;
// Find empty element of key array
break;
} else {
// Grow key array
i = keyCount;
}
keys[i] = k;
keyCount++;
}
synchronized (keyLock) {
return null;
return keys[i];
return null;
}
}
synchronized (keyLock) {
if (keys[i] == k) {
keyCount--;
}
((AbstractSelectionKey)k).invalidate();
}
}
private boolean haveValidKeys() {
synchronized (keyLock) {
if (keyCount == 0)
return false;
return true;
}
return false;
}
}
// -- Registration --
public final boolean isRegistered() {
synchronized (keyLock) {
return keyCount != 0;
}
}
}
/**
* Registers this channel with the given selector, returning a selection key.
*
* <p> This method first verifies that this channel is open and that the
* given initial interest set is valid.
*
* <p> If this channel is already registered with the given selector then
* the selection key representing that registration is returned after
* setting its interest set to the given value.
*
* <p> Otherwise this channel has not yet been registered with the given
* selector, so the {@link AbstractSelector#register register} method of
* the selector is invoked while holding the appropriate locks. The
* resulting key is added to this channel's key set before being returned.
* </p>
*
* @throws ClosedSelectorException {@inheritDoc}
*
* @throws IllegalBlockingModeException {@inheritDoc}
*
* @throws IllegalSelectorException {@inheritDoc}
*
* @throws CancelledKeyException {@inheritDoc}
*
* @throws IllegalArgumentException {@inheritDoc}
*/
throws ClosedChannelException
{
synchronized (regLock) {
if (!isOpen())
throw new ClosedChannelException();
throw new IllegalArgumentException();
if (blocking)
throw new IllegalBlockingModeException();
if (k != null) {
k.interestOps(ops);
}
if (k == null) {
// New registration
synchronized (keyLock) {
if (!isOpen())
throw new ClosedChannelException();
addKey(k);
}
}
return k;
}
}
// -- Closing --
/**
* Closes this channel.
*
* <p> This method, which is specified in the {@link
* AbstractInterruptibleChannel} class and is invoked by the {@link
* java.nio.channels.Channel#close close} method, in turn invokes the
* {@link #implCloseSelectableChannel implCloseSelectableChannel} method in
* order to perform the actual work of closing this channel. It then
* cancels all of this channel's keys. </p>
*/
synchronized (keyLock) {
for (int i = 0; i < count; i++) {
SelectionKey k = keys[i];
if (k != null)
k.cancel();
}
}
}
/**
* Closes this selectable channel.
*
* <p> This method is invoked by the {@link java.nio.channels.Channel#close
* close} method in order to perform the actual work of closing the
* channel. This method is only invoked if the channel has not yet been
* closed, and it is never invoked more than once.
*
* <p> An implementation of this method must arrange for any other thread
* that is blocked in an I/O operation upon this channel to return
* immediately, either by throwing an exception or by returning normally.
* </p>
*/
// -- Blocking --
public final boolean isBlocking() {
synchronized (regLock) {
return blocking;
}
}
return regLock;
}
/**
* Adjusts this channel's blocking mode.
*
* <p> If the given blocking mode is different from the current blocking
* mode then this method invokes the {@link #implConfigureBlocking
* implConfigureBlocking} method, while holding the appropriate locks, in
* order to change the mode. </p>
*/
throws IOException
{
synchronized (regLock) {
if (!isOpen())
throw new ClosedChannelException();
return this;
if (block && haveValidKeys())
throw new IllegalBlockingModeException();
}
return this;
}
/**
* Adjusts this channel's blocking mode.
*
* <p> This method is invoked by the {@link #configureBlocking
* configureBlocking} method in order to perform the actual work of
* changing the blocking mode. This method is only invoked if the new mode
* is different from the current mode. </p>
*
* @throws IOException
* If an I/O error occurs
*/
throws IOException;
}