blob: d3a8a595c873ba943f18b31e7aaf6813cee25074 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package java.nio.channels.spi;
import java.io.IOException;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* {@code AbstractSelector} is the base implementation class for selectors.
* It realizes the interruption of selection by {@code begin} and
* {@code end}. It also holds the cancellation and the deletion of the key
* set.
*/
public abstract class AbstractSelector extends Selector {
private final AtomicBoolean isOpen = new AtomicBoolean(true);
private SelectorProvider provider = null;
/*
* Set of cancelled keys.
*/
private Set<SelectionKey> cancelledKeysSet = new HashSet<SelectionKey>();
/**
* Constructs a new {@code AbstractSelector}.
*
* @param selectorProvider
* the selector provider that creates this selector.
*/
protected AbstractSelector(SelectorProvider selectorProvider) {
provider = selectorProvider;
}
/**
* Closes this selector. This method does nothing if this selector is
* already closed. The actual closing must be implemented by subclasses in
* {@code implCloseSelector()}.
*
* @throws IOException
* if an I/O error occurs.
*/
@Override
public final void close() throws IOException {
if (isOpen.getAndSet(false)) {
implCloseSelector();
}
}
/**
* Implements the closing of this channel.
*
* @throws IOException
* if an I/O error occurs.
*/
protected abstract void implCloseSelector() throws IOException;
/**
* Indicates whether this selector is open.
*
* @return {@code true} if this selector is not closed, {@code false}
* otherwise.
*/
@Override
public final boolean isOpen() {
return isOpen.get();
}
/**
* Gets this selector's provider.
*
* @return the provider of this selector.
*/
@Override
public final SelectorProvider provider() {
return provider;
}
/**
* Returns this channel's set of canceled selection keys.
*
* @return the set of canceled selection keys.
*/
protected final Set<SelectionKey> cancelledKeys() {
return cancelledKeysSet;
}
/**
* Registers a channel with this selector.
*
* @param channel
* the channel to be registered.
* @param operations
* the {@link SelectionKey interest set} of {@code channel}.
* @param attachment
* the attachment for the selection key.
* @return the key related to the channel and this selector.
*/
protected abstract SelectionKey register(AbstractSelectableChannel channel,
int operations, Object attachment);
/**
* Deletes the key from the channel's key set.
*
* @param key
* the key.
*/
protected final void deregister(AbstractSelectionKey key) {
((AbstractSelectableChannel) key.channel()).deregister(key);
key.isValid = false;
}
/**
* Indicates the beginning of a code section that includes an I/O operation
* that is potentially blocking. After this operation, the application
* should invoke the corresponding {@code end(boolean)} method.
*/
protected final void begin() {
// FIXME: be accommodate before VM actually provides
// setInterruptAction method
if (AbstractInterruptibleChannel.setInterruptAction != null) {
try {
AbstractInterruptibleChannel.setInterruptAction.invoke(Thread
.currentThread(), new Object[] { new Runnable() {
public void run() {
AbstractSelector.this.wakeup();
}
} });
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/**
* Indicates the end of a code section that has been started with
* {@code begin()} and that includes a potentially blocking I/O operation.
*/
protected final void end() {
// FIXME: be accommodate before VM actually provides
// setInterruptAction method
if (AbstractInterruptibleChannel.setInterruptAction != null) {
try {
AbstractInterruptibleChannel.setInterruptAction.invoke(Thread
.currentThread(), new Object[] { null });
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
/*
* package private method for AbstractSelectionKey.cancel()
*/
void cancel(SelectionKey key) {
synchronized (cancelledKeysSet) {
cancelledKeysSet.add(key);
}
}
}