1 /* AbstractSelectableChannel.java 2 Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 39 package java.nio.channels.spi; 40 41 import java.io.IOException; 42 import java.nio.channels.ClosedChannelException; 43 import java.nio.channels.SelectableChannel; 44 import java.nio.channels.SelectionKey; 45 import java.nio.channels.Selector; 46 import java.nio.channels.IllegalBlockingModeException; 47 import java.util.Iterator; 48 import java.util.LinkedList; 49 import java.util.ListIterator; 50 51 public abstract class AbstractSelectableChannel extends SelectableChannel 52 { 53 private boolean blocking = true; 54 private Object LOCK = new Object(); 55 private SelectorProvider provider; 56 private LinkedList keys = new LinkedList(); 57 58 /** 59 * Initializes the channel 60 * 61 * @param provider the provider that created this channel 62 */ AbstractSelectableChannel(SelectorProvider provider)63 protected AbstractSelectableChannel(SelectorProvider provider) 64 { 65 this.provider = provider; 66 } 67 68 /** 69 * Retrieves the object upon which the configureBlocking and register 70 * methods synchronize. 71 * 72 * @return the blocking lock 73 */ blockingLock()74 public final Object blockingLock() 75 { 76 return LOCK; 77 } 78 79 /** 80 * Adjusts this channel's blocking mode. 81 * 82 * @param blocking true if blocking should be enabled, false otherwise 83 * 84 * @return this channel 85 * 86 * @exception IOException If an error occurs 87 */ configureBlocking(boolean blocking)88 public final SelectableChannel configureBlocking(boolean blocking) 89 throws IOException 90 { 91 synchronized (blockingLock()) 92 { 93 if (this.blocking != blocking) 94 { 95 implConfigureBlocking(blocking); 96 this.blocking = blocking; 97 } 98 } 99 100 return this; 101 } 102 103 /** 104 * Closes this channel. 105 * 106 * @exception IOException If an error occurs 107 */ implCloseChannel()108 protected final void implCloseChannel() throws IOException 109 { 110 try 111 { 112 implCloseSelectableChannel(); 113 } 114 finally 115 { 116 for (Iterator it = keys.iterator(); it.hasNext(); ) 117 ((SelectionKey) it.next()).cancel(); 118 } 119 } 120 121 /** 122 * Closes this selectable channel. 123 * 124 * @exception IOException If an error occurs 125 */ implCloseSelectableChannel()126 protected abstract void implCloseSelectableChannel() 127 throws IOException; 128 129 /** 130 * Adjusts this channel's blocking mode. 131 * 132 * @param blocking true if blocking should be enabled, false otherwise 133 * 134 * @exception IOException If an error occurs 135 */ implConfigureBlocking(boolean blocking)136 protected abstract void implConfigureBlocking(boolean blocking) 137 throws IOException; 138 139 /** 140 * Tells whether or not every I/O operation on this channel will block 141 * until it completes. 142 * 143 * @return true of this channel is blocking, false otherwise 144 */ isBlocking()145 public final boolean isBlocking() 146 { 147 return blocking; 148 } 149 150 /** 151 * Tells whether or not this channel is currently registered with 152 * any selectors. 153 * 154 * @return true if this channel is registered, false otherwise 155 */ isRegistered()156 public final boolean isRegistered() 157 { 158 return ! keys.isEmpty(); 159 } 160 161 /** 162 * Retrieves the key representing the channel's registration with the 163 * given selector. 164 * 165 * @param selector the selector to get a selection key for 166 * 167 * @return the selection key this channel is registered with 168 */ keyFor(Selector selector)169 public final SelectionKey keyFor(Selector selector) 170 { 171 if (! isOpen()) 172 return null; 173 174 try 175 { 176 synchronized (blockingLock()) 177 { 178 return locate(selector); 179 } 180 } 181 catch (Exception e) 182 { 183 return null; 184 } 185 } 186 187 /** 188 * Returns the provider that created this channel. 189 * 190 * @return the selector provider that created this channel 191 */ provider()192 public final SelectorProvider provider() 193 { 194 return provider; 195 } 196 locate(Selector selector)197 private SelectionKey locate(Selector selector) 198 { 199 ListIterator it = keys.listIterator(); 200 201 while (it.hasNext()) 202 { 203 SelectionKey key = (SelectionKey) it.next(); 204 205 if (key.selector() == selector) 206 return key; 207 } 208 209 return null; 210 } 211 212 /** 213 * Registers this channel with the given selector, returning a selection key. 214 * 215 * @param selin the seletor to use 216 * @param ops the interested operations 217 * @param att an attachment for the returned selection key 218 * 219 * @return the registered selection key 220 * 221 * @exception ClosedChannelException If the channel is already closed. 222 * @exception IllegalBlockingModeException If the channel is configured in 223 * blocking mode. 224 */ register(Selector selin, int ops, Object att)225 public final SelectionKey register(Selector selin, int ops, Object att) 226 throws ClosedChannelException 227 { 228 if (! isOpen()) 229 throw new ClosedChannelException(); 230 231 if ((ops & ~validOps()) != 0) 232 throw new IllegalArgumentException(); 233 234 SelectionKey key = null; 235 AbstractSelector selector = (AbstractSelector) selin; 236 237 synchronized (blockingLock()) 238 { 239 if (blocking) 240 throw new IllegalBlockingModeException(); 241 242 key = locate(selector); 243 244 if (key != null && key.isValid()) 245 { 246 key.interestOps(ops); 247 key.attach(att); 248 } 249 else 250 { 251 key = selector.register(this, ops, att); 252 253 if (key != null) 254 addSelectionKey(key); 255 } 256 } 257 258 return key; 259 } 260 addSelectionKey(SelectionKey key)261 void addSelectionKey(SelectionKey key) 262 { 263 keys.add(key); 264 } 265 266 // This method gets called by AbstractSelector.deregister(). removeSelectionKey(SelectionKey key)267 void removeSelectionKey(SelectionKey key) 268 { 269 keys.remove(key); 270 } 271 } 272