1/*
2 *  Licensed to the Apache Software Foundation (ASF) under one or more
3 *  contributor license agreements.  See the NOTICE file distributed with
4 *  this work for additional information regarding copyright ownership.
5 *  The ASF licenses this file to You under the Apache License, Version 2.0
6 *  (the "License"); you may not use this file except in compliance with
7 *  the License.  You may obtain a copy of the License at
8 *
9 *     http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *  Unless required by applicable law or agreed to in writing, software
12 *  distributed under the License is distributed on an "AS IS" BASIS,
13 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *  See the License for the specific language governing permissions and
15 *  limitations under the License.
16 */
17
18package java.nio.channels.spi;
19
20import java.io.IOException;
21import java.nio.channels.SelectionKey;
22import java.nio.channels.Selector;
23import java.util.HashSet;
24import java.util.Set;
25import java.util.concurrent.atomic.AtomicBoolean;
26
27/**
28 * {@code AbstractSelector} is the base implementation class for selectors.
29 * It realizes the interruption of selection by {@code begin} and
30 * {@code end}. It also holds the cancellation and the deletion of the key
31 * set.
32 */
33public abstract class AbstractSelector extends Selector {
34    private final AtomicBoolean isOpen = new AtomicBoolean(true);
35
36    private SelectorProvider provider = null;
37
38    private final Set<SelectionKey> cancelledKeysSet = new HashSet<SelectionKey>();
39
40    private final Runnable wakeupRunnable = new Runnable() {
41        @Override public void run() {
42            wakeup();
43        }
44    };
45
46    protected AbstractSelector(SelectorProvider selectorProvider) {
47        provider = selectorProvider;
48    }
49
50    /**
51     * Closes this selector. This method does nothing if this selector is
52     * already closed. The actual closing must be implemented by subclasses in
53     * {@code implCloseSelector()}.
54     */
55    @Override
56    public final void close() throws IOException {
57        if (isOpen.getAndSet(false)) {
58            implCloseSelector();
59        }
60    }
61
62    /**
63     * Implements the closing of this channel.
64     */
65    protected abstract void implCloseSelector() throws IOException;
66
67    /**
68     * Returns true if this selector is open.
69     */
70    @Override
71    public final boolean isOpen() {
72        return isOpen.get();
73    }
74
75    /**
76     * Returns this selector's provider.
77     */
78    @Override
79    public final SelectorProvider provider() {
80        return provider;
81    }
82
83    /**
84     * Returns this channel's set of canceled selection keys.
85     */
86    protected final Set<SelectionKey> cancelledKeys() {
87        return cancelledKeysSet;
88    }
89
90    /**
91     * Registers {@code channel} with this selector.
92     *
93     * @param operations the {@link SelectionKey interest set} of {@code
94     *     channel}.
95     * @param attachment the attachment for the selection key.
96     * @return the key related to the channel and this selector.
97     */
98    protected abstract SelectionKey register(AbstractSelectableChannel channel,
99            int operations, Object attachment);
100
101    /**
102     * Deletes the key from the channel's key set.
103     */
104    protected final void deregister(AbstractSelectionKey key) {
105        ((AbstractSelectableChannel) key.channel()).deregister(key);
106        key.isValid = false;
107    }
108
109    /**
110     * Indicates the beginning of a code section that includes an I/O operation
111     * that is potentially blocking. After this operation, the application
112     * should invoke the corresponding {@code end(boolean)} method.
113     */
114    protected final void begin() {
115        Thread.currentThread().pushInterruptAction$(wakeupRunnable);
116    }
117
118    /**
119     * Indicates the end of a code section that has been started with
120     * {@code begin()} and that includes a potentially blocking I/O operation.
121     */
122    protected final void end() {
123        Thread.currentThread().popInterruptAction$(wakeupRunnable);
124    }
125
126    void cancel(SelectionKey key) {
127        synchronized (cancelledKeysSet) {
128            cancelledKeysSet.add(key);
129        }
130    }
131}
132