1 56 57 package org.objectstyle.cayenne.event; 58 59 import java.util.ArrayList ; 60 import java.util.Collections ; 61 import java.util.EventObject ; 62 import java.util.Iterator ; 63 import java.util.LinkedList ; 64 import java.util.List ; 65 import java.util.Map ; 66 import java.util.WeakHashMap ; 67 68 import org.apache.log4j.Logger; 69 import org.objectstyle.cayenne.CayenneRuntimeException; 70 import org.objectstyle.cayenne.util.Invocation; 71 import org.objectstyle.cayenne.util.Util; 72 73 82 public class EventManager extends Object { 83 private static Logger logObj = Logger.getLogger(EventManager.class); 84 85 private static final EventManager defaultManager = new EventManager(); 86 87 public static final int DEFAULT_DISPATCH_THREAD_COUNT = 5; 88 89 protected Map subjects; 91 protected List eventQueue; 92 protected boolean singleThread; 93 94 99 public static EventManager getDefaultManager() { 100 return defaultManager; 101 } 102 103 public EventManager() { 104 this(DEFAULT_DISPATCH_THREAD_COUNT); 105 } 106 107 110 public EventManager(int dispatchThreadCount) { 111 super(); 112 this.subjects = Collections.synchronizedMap(new WeakHashMap ()); 113 this.eventQueue = Collections.synchronizedList(new LinkedList ()); 114 this.singleThread = dispatchThreadCount <= 0; 115 116 for (int i = 0; i < dispatchThreadCount; i++) { 118 new DispatchThread("EventDispatchThread-" + i).start(); 119 } 120 } 121 122 129 public List getEventQueue() { 130 synchronized(eventQueue) { 131 return new ArrayList (eventQueue); 132 } 133 } 134 135 141 public void addListener( 142 Object listener, 143 String methodName, 144 Class eventParameterClass, 145 EventSubject subject) { 146 this.addListener(listener, methodName, eventParameterClass, subject, null, true); 147 } 148 149 public void addNonBlockingListener( 150 Object listener, 151 String methodName, 152 Class eventParameterClass, 153 EventSubject subject) { 154 155 if (singleThread) { 156 throw new IllegalStateException ("EventManager is configured to be single-threaded."); 157 } 158 159 this.addListener(listener, methodName, eventParameterClass, subject, null, false); 160 } 161 162 175 public void addListener( 176 Object listener, 177 String methodName, 178 Class eventParameterClass, 179 EventSubject subject, 180 Object sender) { 181 addListener(listener, methodName, eventParameterClass, subject, sender, true); 182 } 183 184 public void addNonBlockingListener( 185 Object listener, 186 String methodName, 187 Class eventParameterClass, 188 EventSubject subject, 189 Object sender) { 190 191 if (singleThread) { 192 throw new IllegalStateException ("EventManager is configured to be single-threaded."); 193 } 194 195 addListener(listener, methodName, eventParameterClass, subject, sender, false); 196 } 197 198 protected void addListener( 199 Object listener, 200 String methodName, 201 Class eventParameterClass, 202 EventSubject subject, 203 Object sender, 204 boolean blocking) { 205 206 if (listener == null) { 207 throw new IllegalArgumentException ("Listener must not be null."); 208 } 209 210 if (eventParameterClass == null) { 211 throw new IllegalArgumentException ("Event class must not be null."); 212 } 213 214 if (subject == null) { 215 throw new IllegalArgumentException ("Subject must not be null."); 216 } 217 218 224 225 try { 226 Invocation invocation = 227 (blocking) 228 ? new Invocation(listener, methodName, eventParameterClass) 229 : new NonBlockingInvocation(listener, methodName, eventParameterClass); 230 dispatchQueueForSubject(subject, true).addInvocation(invocation, sender); 231 } 232 catch (NoSuchMethodException nsm) { 233 throw new CayenneRuntimeException("Error adding listener, method name: " + methodName, nsm); 234 } 235 } 236 237 245 public boolean removeListener(Object listener) { 246 if (listener == null) { 247 return false; 248 } 249 250 boolean didRemove = false; 251 252 synchronized (subjects) { 253 if (!subjects.isEmpty()) { 254 Iterator subjectIter = subjects.keySet().iterator(); 255 while (subjectIter.hasNext()) { 256 didRemove 257 |= this.removeListener(listener, (EventSubject) subjectIter.next()); 258 } 259 } 260 } 261 262 return didRemove; 263 } 264 265 268 public boolean removeAllListeners(EventSubject subject) { 269 if (subject != null) { 270 synchronized (subjects) { 271 return subjects.remove(subject) != null; 272 } 273 } 274 275 return false; 276 } 277 278 286 public boolean removeListener(Object listener, EventSubject subject) { 287 return this.removeListener(listener, subject, null); 288 } 289 290 301 public boolean removeListener(Object listener, EventSubject subject, Object sender) { 302 if (listener == null || subject == null) { 303 return false; 304 } 305 306 DispatchQueue subjectQueue = dispatchQueueForSubject(subject, false); 307 if (subjectQueue == null) { 308 return false; 309 } 310 311 return subjectQueue.removeInvocations(listener, sender); 312 } 313 314 323 public void postEvent(EventObject event, EventSubject subject) { 324 dispatchEvent(new Dispatch(event, subject)); 325 } 326 327 338 public void postNonBlockingEvent(EventObject event, EventSubject subject) { 339 if (singleThread) { 340 throw new IllegalStateException ("EventManager is configured to be single-threaded."); 341 } 342 343 synchronized (eventQueue) { 345 eventQueue.add(new Dispatch(event, subject)); 346 eventQueue.notifyAll(); 347 } 348 } 349 350 private void dispatchEvent(Dispatch dispatch) { 351 DispatchQueue dispatchQueue = dispatchQueueForSubject(dispatch.subject, false); 352 if (dispatchQueue != null) { 353 dispatchQueue.dispatchEvent(dispatch); 354 } 355 } 356 357 private DispatchQueue dispatchQueueForSubject(EventSubject subject, boolean create) { 359 synchronized (subjects) { 360 DispatchQueue listenersStore = (DispatchQueue) subjects.get(subject); 361 if (create && listenersStore == null) { 362 listenersStore = new DispatchQueue(); 363 subjects.put(subject, listenersStore); 364 } 365 return listenersStore; 366 } 367 } 368 369 class Dispatch { 371 EventObject [] eventArgument; 372 EventSubject subject; 373 374 Dispatch(EventObject event, EventSubject subject) { 375 this(new EventObject [] { event }, subject); 376 } 377 378 Dispatch(EventObject [] eventArgument, EventSubject subject) { 379 this.eventArgument = eventArgument; 380 this.subject = subject; 381 } 382 383 Object getSender() { 384 return eventArgument[0].getSource(); 385 } 386 387 void fire() { 388 EventManager.this.dispatchEvent(Dispatch.this); 389 } 390 391 boolean fire(Invocation invocation) { 392 if (invocation instanceof NonBlockingInvocation) { 393 394 if (invocation.getTarget() == null) { 396 return false; 397 } 398 399 synchronized (eventQueue) { 401 eventQueue.add( 402 new InvocationDispatch(eventArgument, subject, invocation)); 403 eventQueue.notifyAll(); 404 } 405 406 return true; 407 } 408 else { 409 return invocation.fire(eventArgument); 410 } 411 } 412 } 413 414 class InvocationDispatch extends Dispatch { 416 Invocation target; 417 418 InvocationDispatch( 419 EventObject [] eventArgument, 420 EventSubject subject, 421 Invocation target) { 422 super(eventArgument, subject); 423 this.target = target; 424 } 425 426 void fire() { 427 target.fire(eventArgument); 430 } 431 } 432 433 final class NonBlockingInvocation extends Invocation { 436 437 public NonBlockingInvocation( 438 Object target, 439 String methodName, 440 Class parameterType) 441 throws NoSuchMethodException { 442 super(target, methodName, parameterType); 443 } 444 } 445 446 final class DispatchThread extends Thread { 447 DispatchThread(String name) { 448 super(name); 449 setDaemon(true); 450 } 451 452 public void run() { 453 while (true) { 454 455 Dispatch dispatch = null; 458 459 synchronized (EventManager.this.eventQueue) { 460 if (EventManager.this.eventQueue.size() > 0) { 461 dispatch = (Dispatch) EventManager.this.eventQueue.remove(0); 462 } 463 else { 464 try { 465 EventManager.this.eventQueue.wait(); 466 } 467 catch (InterruptedException e) { 468 } 470 } 471 } 472 473 if (dispatch != null) { 475 try { 478 dispatch.fire(); 479 } 480 catch (Throwable th) { 481 logObj.debug( 483 "Event dispatch error, ignoring.", 484 Util.unwindException(th)); 485 } 486 } 487 } 488 } 489 } 490 } 491 | Popular Tags |