View Javadoc
1 /************************************************************ 2 * Copyright * 3 * Portions of this software are Copyright (c) 1993 - 2002, * 4 * Chad Z. Hower (Kudzu) and the Indy Pit Crew * 5 * - http://www.nevrona.com/Indy/ * 6 ************************************************************/ 7 package org.indy; 8 9 import java.net.InetAddress; 10 import java.net.UnknownHostException; 11 12 import java.text.MessageFormat; 13 14 import java.util.Collection; 15 import java.util.HashSet; 16 import java.util.Iterator; 17 18 import org.indy.io.IndyUnknownHostException; 19 20 21 /*** 22 * <code>IndyComponent</code> is the ancestor of all Indy components 23 * which implement client or server functionality.<p> 24 * 25 * <code>IndyComponent</code> provides a convinient method to acess the local 26 * machine's host name with {@link getLocalName()}, and is also responsible for 27 * firing events to registered instances of {@link IndyComponentListener} to signal state change, input, 28 * and output operations in the component. 29 * 30 *@author OTG 31 *@version 1.0 32 *@see IndyComponentListener 33 */ 34 public abstract class IndyComponent extends BaseComponent { 35 /*** 36 * Cached version of local host name for internal use 37 */ 38 private static String cachedHostName; 39 40 /*** 41 * Internal collection to hold component listeners. Currently uses a hash set to prevent duplicates. 42 */ 43 private Collection listeners = new HashSet(); 44 45 /*** 46 * Internal array of workInfos, to be the same size as there are elements in {@link WorkMode}. 47 * Used to support nesting of work events. 48 * 49 * @todo Find a better way of doing this? 50 */ 51 private final WorkInfo[] workInfos = { new WorkInfo(), new WorkInfo() }; 52 53 /*** 54 * Returns the local host name of this machine. 55 * <p> 56 * NOTE: This value is lazily created and then cached, so that, at present, 57 * changes to the host name will not update. 58 * <p> 59 * This method provides a shortcut for 60 * <pre> 61 * java.net.InetAddress.getLocalHost().getHostName(); 62 * </pre> 63 * 64 *@return The host name of the local machine. 65 *@throws IndyUnknownHostException if, for some reason, the local host can not be resolved 66 *@throws SecurityExeption if a security manager exists and <code>checkConnect</code> doesn't allow this operation. 67 */ 68 public final static String getLocalName() throws IndyUnknownHostException { 69 try { 70 if (cachedHostName == null) { 71 cachedHostName = InetAddress.getLocalHost().getHostName(); 72 } 73 } 74 catch (UnknownHostException ex) { 75 throw new IndyUnknownHostException(ex); 76 } 77 78 return cachedHostName; 79 } 80 81 /*** 82 * Returns this instance's <code>workInfo</code> object for the appropriate work mode. 83 * 84 *@param workMode The work mode to retreive the workInfo for 85 *@return The workInfo in question. 86 */ 87 private WorkInfo workInfoForType(WorkMode workMode) { 88 return workInfos[workMode.type()]; 89 } 90 91 /*** 92 * Fires a status event with the given {@link Status}. 93 * 94 * This is a shortcut for 95 * <pre> 96 * doStatus(status, new Object[0]); 97 * </pre> 98 * 99 *@param status The <code>Status</code> that represents the state being changed to. 100 *@see Status 101 */ 102 protected final void doStatus(Status status) { 103 doStatus(status, new Object[0]); 104 } 105 106 /*** 107 * Fires a state change event for a given {@link Status}, 108 * taking an array of arguments for message formatting. 109 * 110 * The message formatting uses java.text.MessageFormat, and the appropriate resource string 111 * for the <code>Status</code> in question. 112 * 113 *@param status The <code>Status</code> being changed to. 114 *@param args Arguments to format the state change message with. 115 */ 116 protected final void doStatus(Status status, Object[] args) { 117 String msg = MessageFormat.format(status.toString(), args); 118 119 Iterator i = listeners.iterator(); 120 121 while (i.hasNext()) { 122 ((IndyComponentListener) i.next()).onStatus(this, status, msg); 123 } 124 } 125 126 /*** 127 * Registers an {@link IndyComponentListener} to receive events from this component instance. 128 * 129 *@param listener The <code>IndyComponentListener</code> to receive events from this component. 130 *@see IndyComponentListener 131 */ 132 public void addComponentListener(IndyComponentListener listener) { 133 listeners.add(listener); 134 } 135 136 /*** 137 * Unregisters an {@link IndyComponentListener} from this component. 138 * 139 *@param listener The <code>IndyComponentListener</code> to remove. 140 *@see IndyComponentListener 141 */ 142 public void removeComponentListener(IndyComponentListener listener) { 143 listeners.remove(listener); 144 } 145 146 /*** 147 * Called to indicate the beginning of work of the given {@link WorkMode}. 148 * Calls can be nested, but each begin must have a corresponding end. 149 * 150 * Only the first beginWork in any nested set for a given <code>WorkMode</code> will fire a {@link IndyComponentListener#onBeginWork(IndyComponent,WorkMode,int)} 151 * event. 152 * 153 *@param workMode The <code>WorkMode</code> of this work. 154 *@param size The size of the work - viz. how many bytes are being read, written or processed. 155 *@see doBeginWork(WorkMode) 156 *@see doEndWork(WorkMode) 157 *@see doWork(WorkMode,int) 158 *@see IndyComponentListener 159 *@see IndyComponentListener#onBeginWork(IndyComponent,WorkMode,int) 160 */ 161 protected void doBeginWork(WorkMode workMode, int size) { 162 if (!(workMode.type() > workInfos.length - 1)) { 163 workInfoForType(workMode).level++; 164 165 if (workInfoForType(workMode).level == 1) { 166 workInfoForType(workMode).max = size; 167 workInfoForType(workMode).current = 0; 168 169 Iterator i = listeners.iterator(); 170 171 while (i.hasNext()) { 172 ((IndyComponentListener) i.next()).onBeginWork(this, workMode, size); 173 } 174 } 175 } 176 } 177 178 /*** 179 * Calls to signal the beginning of work of a given {@link WorkMode}. 180 * 181 * See {@link doBeginWork(WorkMode,int} for more details. 182 * 183 * This method is a shortcut for 184 * <pre> 185 * doBeginWork(workMode,0); 186 * </pre> 187 * 188 *@param workMode The <code>WorkMode</code> describing the type of operation underway. 189 *@see doBeginWork(WorkMode,int) 190 *@see doEndWork(WorkMode) 191 *@see doWork(WorkMode,int) 192 *@see IndyComponentListener 193 *@see IndyComponentListener#onBeginWork(IndyComponent,WorkMode,int) 194 */ 195 protected final void doBeginWork(WorkMode workMode) { 196 doBeginWork(workMode, 0); 197 } 198 199 /*** 200 * Signals that a piece of work of the given {@link WorkMode} is underway 201 * to the tune of <code>count</code> bytes. 202 * 203 * This call will have no effect unless a corresponding call to begin work has been made; 204 * otherwise a {@link IndyComponentListener#onWork(IndyComponent, WorkMode, int) onWork} 205 * event will be fired to all interested parties. 206 * 207 *@param workMode The <code>WorkMode</code> that this work represents. 208 *@param count The number of bytes being processed. 209 *@see doBeginWork(WorkMode,int) 210 *@see doEndWork(WorkMode,int) 211 *@see WorkMode 212 *@see IndyComponentListener 213 *@see IndyComponentListener#onWork(IndyComponent, IndyComponent.WorkMode, int) 214 *@todo Should this throw exceptions if count is > workInfo.max? Or if there has been no doBeginWork call? 215 */ 216 protected final void doWork(WorkMode workMode, int count) { 217 if (!(workMode.type() > workInfos.length - 1)) { 218 if (workInfoForType(workMode).level > 0) { 219 workInfoForType(workMode).current += count; 220 221 Iterator i = listeners.iterator(); 222 223 while (i.hasNext()) { 224 ((IndyComponentListener) i.next()).onWork(this, workMode, count); 225 } 226 } 227 } 228 } 229 230 /*** 231 * Signals that a piece of work begun by {@link doBeginWork(WorkMode,int) doBeginWork} 232 * has ended. 233 * 234 * Each call to <code>doBeginWork</code> should have a corresponding call to <code>doEndWork</code>, 235 * and, as with <code>doBeginWork</code> only the innovation representing the outermost portion of 236 * work in a nested call will trigger an event, in this case {@link IndyComponentListener#onEndWork(IndyComponent,WorkMode)}. 237 * 238 *@param workMode The <code>WorkMode</code> for which work is ending. 239 *@see doBeginWork(WorkMode,int) 240 *@see doBeginWork(WorkMode) 241 *@see doWork(WorkMode,int) 242 *@see WorkMode 243 *@see IndyComponentListener 244 *@see IndyComponentListener#onEndWork(IndyComponent,WorkMode) 245 */ 246 protected final void doEndWork(WorkMode workMode) { 247 if (!(workMode.type() > workInfos.length - 1)) { 248 if (workInfoForType(workMode).level == 1) { 249 Iterator i = listeners.iterator(); 250 251 while (i.hasNext()) { 252 ((IndyComponentListener) i.next()).onEndWork(this, workMode); 253 } 254 } 255 256 workInfoForType(workMode).level--; 257 } 258 } 259 260 /*** 261 * An enumerated class representing the possible work types for siganalling work events 262 * in an <code>IndyComponent<code>. <p> 263 * 264 *@author OTG 265 *@version 1.0 266 *@see IndyComponent 267 *@see IndyComponent#doBeginWork(WorkMode,int) 268 *@see IndyComponent#doBeginWork(WorkMode) 269 *@see IndyComponent#doWork(WorkMode,int) 270 *@see IndyComponent#doEndWork(WorkMode) 271 *@see IndyComponentListener 272 *@see IndyComponentListener#onBeginWork(IndyComponent,WorkMode,int) 273 *@see IndyComponenyListener#onWork(IndyComponent,WorkMode,int) 274 *@see IndyComponenyListener#onEndWork(IndyComponent,WorkMode) 275 */ 276 public static final class WorkMode { 277 /*** 278 * The component is reading data from the peer connection. 279 */ 280 public final static WorkMode READ = new WorkMode(0); 281 282 /*** 283 * The component is writing data to the peer connection 284 */ 285 public final static WorkMode WRITE = new WorkMode(1); 286 private int _type; 287 288 private WorkMode(int type) { 289 _type = type; 290 } 291 292 /*** 293 * A hack to allow the use of the workInfo[] for tracking work. 294 */ 295 private int type() { 296 return _type; 297 } 298 } 299 300 /*** 301 * Used internally in {@link IndyComponent} for tracking calls to <code>doBeginWork</code>,<code>doWork</code> and <code>doEndWork</code> 302 * 303 * @author OTG 304 * @version 1.0 305 */ 306 private class WorkInfo { 307 /*** 308 * The current bytes worked upon in this chunk of work 309 */ 310 private int current; 311 312 /*** 313 * The nesting level of this chunk of work 314 */ 315 private int level; 316 317 /*** 318 * The overall number of bytes associated with this chunk of work 319 */ 320 private int max; 321 } 322 }

This page was automatically generated by Maven