1 19 20 21 package org.apache.cayenne.event; 22 23 import java.util.ArrayList ; 24 import java.util.Collections ; 25 import java.util.EventObject ; 26 import java.util.Iterator ; 27 import java.util.LinkedList ; 28 import java.util.List ; 29 import java.util.Map ; 30 import java.util.WeakHashMap ; 31 32 import org.apache.cayenne.CayenneRuntimeException; 33 import org.apache.cayenne.util.Invocation; 34 35 44 public class EventManager extends Object { 45 46 private static volatile EventManager defaultManager; 47 48 public static final int DEFAULT_DISPATCH_THREAD_COUNT = 5; 49 50 protected Map subjects; 52 protected List eventQueue; 53 protected boolean singleThread; 54 55 62 public static EventManager getDefaultManager() { 63 if (defaultManager == null) { 64 synchronized (EventManager.class) { 65 if (defaultManager == null) { 66 defaultManager = new EventManager(2); 67 } 68 } 69 } 70 return defaultManager; 71 } 72 73 76 public EventManager() { 77 this(DEFAULT_DISPATCH_THREAD_COUNT); 78 } 79 80 85 public EventManager(int dispatchThreadCount) { 86 this.subjects = Collections.synchronizedMap(new WeakHashMap ()); 87 this.eventQueue = Collections.synchronizedList(new LinkedList ()); 88 this.singleThread = dispatchThreadCount <= 0; 89 90 for (int i = 0; i < dispatchThreadCount; i++) { 92 new DispatchThread("EventDispatchThread-" + i).start(); 93 } 94 } 95 96 103 public boolean isSingleThreaded() { 104 return singleThread; 105 } 106 107 114 public List getEventQueue() { 115 synchronized (eventQueue) { 116 return new ArrayList (eventQueue); 117 } 118 } 119 120 126 public void addListener( 127 Object listener, 128 String methodName, 129 Class eventParameterClass, 130 EventSubject subject) { 131 this.addListener(listener, methodName, eventParameterClass, subject, null, true); 132 } 133 134 public void addNonBlockingListener( 135 Object listener, 136 String methodName, 137 Class eventParameterClass, 138 EventSubject subject) { 139 140 if (singleThread) { 141 throw new IllegalStateException ( 142 "EventManager is configured to be single-threaded."); 143 } 144 145 this.addListener(listener, methodName, eventParameterClass, subject, null, false); 146 } 147 148 160 public void addListener( 161 Object listener, 162 String methodName, 163 Class eventParameterClass, 164 EventSubject subject, 165 Object sender) { 166 addListener(listener, methodName, eventParameterClass, subject, sender, true); 167 } 168 169 public void addNonBlockingListener( 170 Object listener, 171 String methodName, 172 Class eventParameterClass, 173 EventSubject subject, 174 Object sender) { 175 176 if (singleThread) { 177 throw new IllegalStateException ( 178 "EventManager is configured to be single-threaded."); 179 } 180 181 addListener(listener, methodName, eventParameterClass, subject, sender, false); 182 } 183 184 protected void addListener( 185 Object listener, 186 String methodName, 187 Class eventParameterClass, 188 EventSubject subject, 189 Object sender, 190 boolean blocking) { 191 192 if (listener == null) { 193 throw new IllegalArgumentException ("Listener must not be null."); 194 } 195 196 if (eventParameterClass == null) { 197 throw new IllegalArgumentException ("Event class must not be null."); 198 } 199 200 if (subject == null) { 201 throw new IllegalArgumentException ("Subject must not be null."); 202 } 203 204 try { 205 Invocation invocation = (blocking) ? new Invocation( 206 listener, 207 methodName, 208 eventParameterClass) : new NonBlockingInvocation( 209 listener, 210 methodName, 211 eventParameterClass); 212 dispatchQueueForSubject(subject, true).addInvocation(invocation, sender); 213 } 214 catch (NoSuchMethodException nsm) { 215 throw new CayenneRuntimeException("Error adding listener, method name: " 216 + methodName, nsm); 217 } 218 } 219 220 228 public boolean removeListener(Object listener) { 229 if (listener == null) { 230 return false; 231 } 232 233 boolean didRemove = false; 234 235 synchronized (subjects) { 236 if (!subjects.isEmpty()) { 237 Iterator subjectIter = subjects.keySet().iterator(); 238 while (subjectIter.hasNext()) { 239 didRemove |= this.removeListener(listener, (EventSubject) subjectIter 240 .next()); 241 } 242 } 243 } 244 245 return didRemove; 246 } 247 248 251 public boolean removeAllListeners(EventSubject subject) { 252 if (subject != null) { 253 synchronized (subjects) { 254 return subjects.remove(subject) != null; 255 } 256 } 257 258 return false; 259 } 260 261 269 public boolean removeListener(Object listener, EventSubject subject) { 270 return this.removeListener(listener, subject, null); 271 } 272 273 284 public boolean removeListener(Object listener, EventSubject subject, Object sender) { 285 if (listener == null || subject == null) { 286 return false; 287 } 288 289 DispatchQueue subjectQueue = dispatchQueueForSubject(subject, false); 290 if (subjectQueue == null) { 291 return false; 292 } 293 294 return subjectQueue.removeInvocations(listener, sender); 295 } 296 297 306 public void postEvent(EventObject event, EventSubject subject) { 307 dispatchEvent(new Dispatch(event, subject)); 308 } 309 310 320 public void postNonBlockingEvent(EventObject event, EventSubject subject) { 321 if (singleThread) { 322 throw new IllegalStateException ( 323 "EventManager is configured to be single-threaded."); 324 } 325 326 synchronized (eventQueue) { 328 eventQueue.add(new Dispatch(event, subject)); 329 eventQueue.notifyAll(); 330 } 331 } 332 333 private void dispatchEvent(Dispatch dispatch) { 334 DispatchQueue dispatchQueue = dispatchQueueForSubject(dispatch.subject, false); 335 if (dispatchQueue != null) { 336 dispatchQueue.dispatchEvent(dispatch); 337 } 338 } 339 340 private DispatchQueue dispatchQueueForSubject(EventSubject subject, boolean create) { 342 synchronized (subjects) { 343 DispatchQueue listenersStore = (DispatchQueue) subjects.get(subject); 344 if (create && listenersStore == null) { 345 listenersStore = new DispatchQueue(); 346 subjects.put(subject, listenersStore); 347 } 348 return listenersStore; 349 } 350 } 351 352 class Dispatch { 354 355 EventObject [] eventArgument; 356 EventSubject subject; 357 358 Dispatch(EventObject event, EventSubject subject) { 359 this(new EventObject [] { 360 event 361 }, subject); 362 } 363 364 Dispatch(EventObject [] eventArgument, EventSubject subject) { 365 this.eventArgument = eventArgument; 366 this.subject = subject; 367 } 368 369 Object getSender() { 370 return eventArgument[0].getSource(); 371 } 372 373 void fire() { 374 EventManager.this.dispatchEvent(Dispatch.this); 375 } 376 377 boolean fire(Invocation invocation) { 378 if (invocation instanceof NonBlockingInvocation) { 379 380 if (invocation.getTarget() == null) { 382 return false; 383 } 384 385 synchronized (eventQueue) { 387 eventQueue.add(new InvocationDispatch( 388 eventArgument, 389 subject, 390 invocation)); 391 eventQueue.notifyAll(); 392 } 393 394 return true; 395 } 396 else { 397 return invocation.fire(eventArgument); 398 } 399 } 400 } 401 402 class InvocationDispatch extends Dispatch { 404 405 Invocation target; 406 407 InvocationDispatch(EventObject [] eventArgument, EventSubject subject, 408 Invocation target) { 409 super(eventArgument, subject); 410 this.target = target; 411 } 412 413 void fire() { 414 target.fire(eventArgument); 417 } 418 } 419 420 final class NonBlockingInvocation extends Invocation { 423 424 public NonBlockingInvocation(Object target, String methodName, Class parameterType) 425 throws NoSuchMethodException { 426 super(target, methodName, parameterType); 427 } 428 } 429 430 final class DispatchThread extends Thread { 431 432 DispatchThread(String name) { 433 super(name); 434 setDaemon(true); 435 } 436 437 public void run() { 438 while (true) { 439 440 Dispatch dispatch = null; 443 444 synchronized (EventManager.this.eventQueue) { 445 if (EventManager.this.eventQueue.size() > 0) { 446 dispatch = (Dispatch) EventManager.this.eventQueue.remove(0); 447 } 448 else { 449 try { 450 EventManager.this.eventQueue.wait(); 451 } 452 catch (InterruptedException e) { 453 } 455 } 456 } 457 458 if (dispatch != null) { 460 try { 463 dispatch.fire(); 464 } 465 catch (Throwable th) { 466 } 468 } 469 } 470 } 471 } 472 } 473 | Popular Tags |