001 /* AbstractSelectableChannel.java 002 Copyright (C) 2002, 2003, 2004 Free Software Foundation, Inc. 003 004 This file is part of GNU Classpath. 005 006 GNU Classpath is free software; you can redistribute it and/or modify 007 it under the terms of the GNU General Public License as published by 008 the Free Software Foundation; either version 2, or (at your option) 009 any later version. 010 011 GNU Classpath is distributed in the hope that it will be useful, but 012 WITHOUT ANY WARRANTY; without even the implied warranty of 013 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 General Public License for more details. 015 016 You should have received a copy of the GNU General Public License 017 along with GNU Classpath; see the file COPYING. If not, write to the 018 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 019 02110-1301 USA. 020 021 Linking this library statically or dynamically with other modules is 022 making a combined work based on this library. Thus, the terms and 023 conditions of the GNU General Public License cover the whole 024 combination. 025 026 As a special exception, the copyright holders of this library give you 027 permission to link this library with independent modules to produce an 028 executable, regardless of the license terms of these independent 029 modules, and to copy and distribute the resulting executable under 030 terms of your choice, provided that you also meet, for each linked 031 independent module, the terms and conditions of the license of that 032 module. An independent module is a module which is not derived from 033 or based on this library. If you modify this library, you may extend 034 this exception to your version of the library, but you are not 035 obligated to do so. If you do not wish to do so, delete this 036 exception statement from your version. */ 037 038 039 package java.nio.channels.spi; 040 041 import java.io.IOException; 042 import java.nio.channels.ClosedChannelException; 043 import java.nio.channels.SelectableChannel; 044 import java.nio.channels.SelectionKey; 045 import java.nio.channels.Selector; 046 import java.nio.channels.IllegalBlockingModeException; 047 import java.util.Iterator; 048 import java.util.LinkedList; 049 import java.util.ListIterator; 050 051 public abstract class AbstractSelectableChannel extends SelectableChannel 052 { 053 private boolean blocking = true; 054 private Object LOCK = new Object(); 055 private SelectorProvider provider; 056 private LinkedList keys = new LinkedList(); 057 058 /** 059 * Initializes the channel 060 * 061 * @param provider the provider that created this channel 062 */ 063 protected AbstractSelectableChannel(SelectorProvider provider) 064 { 065 this.provider = provider; 066 } 067 068 /** 069 * Retrieves the object upon which the configureBlocking and register 070 * methods synchronize. 071 * 072 * @return the blocking lock 073 */ 074 public final Object blockingLock() 075 { 076 return LOCK; 077 } 078 079 /** 080 * Adjusts this channel's blocking mode. 081 * 082 * @param blocking true if blocking should be enabled, false otherwise 083 * 084 * @return this channel 085 * 086 * @exception IOException If an error occurs 087 */ 088 public final SelectableChannel configureBlocking(boolean blocking) 089 throws IOException 090 { 091 synchronized (blockingLock()) 092 { 093 if (this.blocking != blocking) 094 { 095 implConfigureBlocking(blocking); 096 this.blocking = blocking; 097 } 098 } 099 100 return this; 101 } 102 103 /** 104 * Closes this channel. 105 * 106 * @exception IOException If an error occurs 107 */ 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 */ 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 */ 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 */ 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 */ 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 */ 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 */ 192 public final SelectorProvider provider() 193 { 194 return provider; 195 } 196 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 */ 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 261 void addSelectionKey(SelectionKey key) 262 { 263 keys.add(key); 264 } 265 266 // This method gets called by AbstractSelector.deregister(). 267 void removeSelectionKey(SelectionKey key) 268 { 269 keys.remove(key); 270 } 271 }