/* * 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); } } }