KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > nio > channels > spi > AbstractSelectableChannel


1 /*
2  * @(#)AbstractSelectableChannel.java 1.25 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.nio.channels.spi;
9
10 import java.io.IOException JavaDoc;
11 import java.nio.channels.*;
12
13
14 /**
15  * Base implementation class for selectable channels.
16  *
17  * <p> This class defines methods that handle the mechanics of channel
18  * registration, deregistration, and closing. It maintains the current
19  * blocking mode of this channel as well as its current set of selection keys.
20  * It performs all of the synchronization required to implement the {@link
21  * java.nio.channels.SelectableChannel} specification. Implementations of the
22  * abstract protected methods defined in this class need not synchronize
23  * against other threads that might be engaged in the same operations. </p>
24  *
25  *
26  * @author Mark Reinhold
27  * @author Mike McCloskey
28  * @author JSR-51 Expert Group
29  * @version 1.25, 03/12/19
30  * @since 1.4
31  */

32
33 public abstract class AbstractSelectableChannel
34     extends SelectableChannel
35 {
36
37     // The provider that created this channel
38
private final SelectorProvider JavaDoc provider;
39
40     // Keys that have been created by registering this channel with selectors.
41
// They are saved because if this channel is closed the keys must be
42
// deregistered. Protected by keyLock.
43
//
44
private SelectionKey[] keys = null;
45     private int keyCount = 0;
46
47     // Lock for key set and count
48
private final Object JavaDoc keyLock = new Object JavaDoc();
49
50     // Lock for registration and configureBlocking operations
51
private final Object JavaDoc regLock = new Object JavaDoc();
52
53     // Blocking mode, protected by regLock
54
boolean blocking = true;
55
56     /**
57      * Initializes a new instance of this class.
58      */

59     protected AbstractSelectableChannel(SelectorProvider JavaDoc provider) {
60     this.provider = provider;
61     }
62
63     /**
64      * Returns the provider that created this channel.
65      *
66      * @return The provider that created this channel
67      */

68     public final SelectorProvider JavaDoc provider() {
69     return provider;
70     }
71
72
73     // -- Utility methods for the key set --
74

75     private void addKey(SelectionKey k) {
76     synchronized (keyLock) {
77         int i = 0;
78         if ((keys != null) && (keyCount < keys.length)) {
79         // Find empty element of key array
80
for (i = 0; i < keys.length; i++)
81             if (keys[i] == null)
82             break;
83         } else if (keys == null) {
84                 keys = new SelectionKey[3];
85             } else {
86         // Grow key array
87
int n = keys.length * 2;
88         SelectionKey[] ks = new SelectionKey[n];
89         for (i = 0; i < keys.length; i++)
90             ks[i] = keys[i];
91         keys = ks;
92         i = keyCount;
93         }
94         keys[i] = k;
95         keyCount++;
96     }
97     }
98
99     private SelectionKey findKey(Selector sel) {
100     synchronized (keyLock) {
101             if (keys == null)
102                 return null;
103         for (int i = 0; i < keys.length; i++)
104                 if ((keys[i] != null) && (keys[i].selector() == sel))
105                     return keys[i];
106         return null;
107     }
108     }
109
110     void removeKey(SelectionKey k) { // package-private
111
synchronized (keyLock) {
112         for (int i = 0; i < keys.length; i++)
113         if (keys[i] == k) {
114             keys[i] = null;
115             keyCount--;
116         }
117         ((AbstractSelectionKey JavaDoc)k).invalidate();
118     }
119     }
120
121     private boolean haveValidKeys() {
122     synchronized (keyLock) {
123         if (keyCount == 0)
124         return false;
125         for (int i = 0; i < keys.length; i++) {
126         if ((keys[i] != null) && keys[i].isValid())
127             return true;
128         }
129         return false;
130     }
131     }
132
133
134     // -- Registration --
135

136     public final boolean isRegistered() {
137     synchronized (keyLock) {
138         return keyCount != 0;
139     }
140     }
141
142     public final SelectionKey keyFor(Selector sel) {
143     return findKey(sel);
144     }
145
146     /**
147      * Registers this channel with the given selector, returning a selection key.
148      *
149      * <p> This method first verifies that this channel is open and that the
150      * given initial interest set is valid.
151      *
152      * <p> If this channel is already registered with the given selector then
153      * the selection key representing that registration is returned after
154      * setting its interest set to the given value.
155      *
156      * <p> Otherwise this channel has not yet been registered with the given
157      * selector, so the {@link AbstractSelector#register register} method of
158      * the selector is invoked while holding the appropriate locks. The
159      * resulting key is added to this channel's key set before being returned.
160      * </p>
161      */

162     public final SelectionKey register(Selector sel, int ops,
163                        Object JavaDoc att)
164     throws ClosedChannelException
165     {
166     if (!isOpen())
167         throw new ClosedChannelException();
168     if ((ops & ~validOps()) != 0)
169         throw new IllegalArgumentException JavaDoc();
170     synchronized (regLock) {
171         if (blocking)
172         throw new IllegalBlockingModeException();
173         SelectionKey k = findKey(sel);
174             if (k != null) {
175                 k.interestOps(ops);
176         k.attach(att);
177             }
178         if (k == null) {
179         // New registration
180
k = ((AbstractSelector JavaDoc)sel).register(this, ops, att);
181         addKey(k);
182         }
183             return k;
184         }
185     }
186
187
188     // -- Closing --
189

190     /**
191      * Closes this channel.
192      *
193      * <p> This method, which is specified in the {@link
194      * AbstractInterruptibleChannel} class and is invoked by the {@link
195      * java.nio.channels.Channel#close close} method, in turn invokes the
196      * {@link #implCloseSelectableChannel implCloseSelectableChannel} method in
197      * order to perform the actual work of closing this channel. It then
198      * cancels all of this channel's keys. </p>
199      */

200     protected final void implCloseChannel() throws IOException JavaDoc {
201     implCloseSelectableChannel();
202     synchronized (keyLock) {
203             int count = (keys == null) ? 0 : keys.length;
204         for (int i = 0; i < count; i++) {
205         SelectionKey k = keys[i];
206         if (k != null)
207             k.cancel();
208         }
209     }
210     }
211
212     /**
213      * Closes this selectable channel.
214      *
215      * <p> This method is invoked by the {@link java.nio.channels.Channel#close
216      * close} method in order to perform the actual work of closing the
217      * channel. This method is only invoked if the channel has not yet been
218      * closed, and it is never invoked more than once.
219      *
220      * <p> An implementation of this method must arrange for any other thread
221      * that is blocked in an I/O operation upon this channel to return
222      * immediately, either by throwing an exception or by returning normally.
223      * </p>
224      */

225     protected abstract void implCloseSelectableChannel() throws IOException JavaDoc;
226
227
228     // -- Blocking --
229

230     public final boolean isBlocking() {
231     synchronized (regLock) {
232         return blocking;
233     }
234     }
235
236     public final Object JavaDoc blockingLock() {
237     return regLock;
238     }
239
240     /**
241      * Adjusts this channel's blocking mode.
242      *
243      * <p> If the given blocking mode is different from the current blocking
244      * mode then this method invokes the {@link #implConfigureBlocking
245      * implConfigureBlocking} method, while holding the appropriate locks, in
246      * order to change the mode. </p>
247      */

248     public final SelectableChannel configureBlocking(boolean block)
249     throws IOException JavaDoc
250     {
251         if (!isOpen())
252             throw new ClosedChannelException();
253     synchronized (regLock) {
254         if (blocking == block)
255         return this;
256         if (block && haveValidKeys())
257         throw new IllegalBlockingModeException();
258         implConfigureBlocking(block);
259         blocking = block;
260     }
261     return this;
262     }
263
264     /**
265      * Adjusts this channel's blocking mode.
266      *
267      * <p> This method is invoked by the {@link #configureBlocking
268      * configureBlocking} method in order to perform the actual work of
269      * changing the blocking mode. This method is only invoked if the new mode
270      * is different from the current mode. </p>
271      *
272      * @throws IOException
273      * If an I/O error occurs
274      */

275     protected abstract void implConfigureBlocking(boolean block)
276     throws IOException JavaDoc;
277
278 }
279
Popular Tags