1 30 31 34 package com.nightlabs.notification; 35 36 import java.lang.reflect.InvocationTargetException ; 37 import java.util.Collection ; 38 import java.util.Collections ; 39 import java.util.HashMap ; 40 import java.util.HashSet ; 41 import java.util.Iterator ; 42 import java.util.LinkedList ; 43 import java.util.List ; 44 import java.util.Map ; 45 import java.util.Set ; 46 import java.util.WeakHashMap ; 47 48 import javax.swing.SwingUtilities ; 49 50 import com.nightlabs.util.RWLock; 51 52 53 61 public class NotificationManager 62 { 63 private static final boolean USE_WEAK_REFERENCES = true; 64 65 69 protected NotificationManager() 70 { 71 } 72 73 private LinkedList interceptors = new LinkedList (); 74 private RWLock interceptorsMutex = new RWLock("interceptorsMutex"); 75 76 public void addInterceptor(Interceptor m) 77 { 78 interceptorsMutex.acquireWriteLock(); 79 try { 80 interceptors.add(m); 81 } finally { 82 interceptorsMutex.releaseLock(); 83 } 84 } 85 86 public void addInterceptorAsFirst(Interceptor m) 87 { 88 interceptorsMutex.acquireWriteLock(); 89 try { 90 interceptors.addFirst(m); 91 } finally { 92 interceptorsMutex.releaseLock(); 93 } 94 } 95 96 public void addInterceptorAsLast(Interceptor m) 97 { 98 interceptorsMutex.acquireWriteLock(); 99 try { 100 interceptors.addLast(m); 101 } finally { 102 interceptorsMutex.releaseLock(); 103 } 104 } 105 106 public void removeInterceptor(Interceptor m) 107 { 108 interceptorsMutex.acquireWriteLock(); 109 try { 110 interceptors.remove(m); 111 } finally { 112 interceptorsMutex.releaseLock(); 113 } 114 } 115 116 127 protected String getNotificationModeForListener(NotificationListener listener) 128 { 129 if (listener == null) 130 throw new IllegalArgumentException ("listener must not be null!"); 131 132 if (listener instanceof NotificationListenerCallerThread) 133 return NotificationListenerCallerThread.class.getName(); 134 135 if (listener instanceof NotificationListenerWorkerThreadAsync) 136 return NotificationListenerWorkerThreadAsync.class.getName(); 137 138 if (listener instanceof NotificationListenerAWTThreadSync) 139 return NotificationListenerAWTThreadSync.class.getName(); 140 141 if (listener instanceof NotificationListenerAWTThreadAsync) 142 return NotificationListenerAWTThreadAsync.class.getName(); 143 144 throw new ClassCastException ("Listener is not supported! It must implement one of the sub-interfaces of NotificationListener!"); 145 } 146 147 162 175 private Map notificationListenersByZone = new HashMap (); 176 private RWLock notificationListenersByZoneMutex = new RWLock("notificationListenersByZoneMutex"); 177 178 181 private Collection zones = null; 182 183 186 protected Collection getZones() 187 { 188 if (zones == null) { 189 notificationListenersByZoneMutex.acquireReadLock(); 190 try { 191 zones = Collections.unmodifiableSet( 192 new HashSet (notificationListenersByZone.keySet())); 193 } finally { 194 notificationListenersByZoneMutex.releaseLock(); 195 } 196 } 197 return zones; 198 } 199 200 204 public void removeNotificationListener( 205 Class subjectClass, NotificationListener listener) 206 { 207 removeNotificationListener((String )null, subjectClass, listener); 208 } 209 public void removeNotificationListener( 210 String zone, Class subjectClass, NotificationListener listener) 211 { 212 notificationListenersByZoneMutex.acquireWriteLock(); 213 try { 214 zones = null; 215 216 String notificationMode = getNotificationModeForListener(listener); 217 218 Map notificationListenersBySubjectClass = (Map ) notificationListenersByZone.get(zone); 219 if (notificationListenersBySubjectClass != null) { 220 Map mapListeners = (Map ) notificationListenersBySubjectClass.get(subjectClass); 221 if (mapListeners != null) { 222 223 Map mapModes = (Map ) mapListeners.get(listener); 224 if (mapModes != null) { 225 226 NotificationListenerMeta meta = (NotificationListenerMeta) mapModes.get(notificationMode); 227 if (meta != null) { 228 if (meta.decCounter() < 1) { 229 mapModes.remove(notificationMode); 230 meta = null; 231 } 232 } 234 if (mapModes.isEmpty()) { 235 mapListeners.remove(listener); 236 } 237 238 } 240 if (mapListeners.isEmpty()) { 241 notificationListenersBySubjectClass.remove(subjectClass); 242 } 243 } 245 if (notificationListenersBySubjectClass.isEmpty()) { 246 notificationListenersByZone.remove(zone); 247 } 248 } 250 } finally { 251 notificationListenersByZoneMutex.releaseLock(); 252 } 253 } 254 255 259 public void addNotificationListener( 260 Class subjectClass, NotificationListener listener) 261 { 262 addNotificationListener((String )null, subjectClass, listener); 263 } 264 265 public void addNotificationListener( 266 String zone, Class subjectClass, NotificationListener listener) 267 { 268 notificationListenersByZoneMutex.acquireWriteLock(); 269 try { 270 zones = null; 271 272 String notificationMode = getNotificationModeForListener(listener); 273 274 Map notificationListenersBySubjectClass = (Map ) notificationListenersByZone.get(zone); 275 if (notificationListenersBySubjectClass == null) { 276 notificationListenersBySubjectClass = new HashMap (); 277 notificationListenersByZone.put(zone, notificationListenersBySubjectClass); 278 } 279 280 Map mapListeners = (Map ) notificationListenersBySubjectClass.get(subjectClass); 281 if (mapListeners == null) { 282 if (USE_WEAK_REFERENCES) 283 mapListeners = new WeakHashMap (); 284 else 285 mapListeners = new HashMap (); 286 287 notificationListenersBySubjectClass.put(subjectClass, mapListeners); 288 } 289 290 Map mapModes = (Map ) mapListeners.get(listener); 291 if (mapModes == null) { 292 mapModes = new HashMap (); 293 mapListeners.put(listener, mapModes); 294 } 295 296 NotificationListenerMeta meta = (NotificationListenerMeta) mapModes.get(notificationMode); 297 if (meta != null && meta.getNotificationListener() == null) 298 meta = null; 299 300 if (meta == null) { 301 meta = new NotificationListenerMeta(zone, subjectClass, listener, notificationMode); 302 mapModes.put(notificationMode, meta); 303 } 304 meta.incCounter(); 305 306 } finally { 307 notificationListenersByZoneMutex.releaseLock(); 308 } 309 } 310 311 public void addNotificationListener( 312 List subjectClasses, NotificationListener listener) 313 { 314 addNotificationListener((String )null, subjectClasses, listener); 315 } 316 public void addNotificationListener( 317 String zone, List subjectClasses, NotificationListener listener) 318 { 319 for (Iterator it = subjectClasses.iterator(); it.hasNext(); ) 320 addNotificationListener(zone, (Class )it.next(), listener); 321 } 322 323 public void addNotificationListener( 324 Class [] subjectClasses, NotificationListener listener) 325 { 326 addNotificationListener((String )null, subjectClasses, listener); 327 } 328 public void addNotificationListener( 329 String zone, Class [] subjectClasses, NotificationListener listener) 330 { 331 for (int i = 0; i < subjectClasses.length; ++i) 332 addNotificationListener(zone, subjectClasses[i], listener); 333 } 334 335 public void removeNotificationListener( 336 Collection subjectClasses, NotificationListener listener) 337 { 338 removeNotificationListener((String )null, subjectClasses, listener); 339 } 340 public void removeNotificationListener( 341 String zone, Collection subjectClasses, NotificationListener listener) 342 { 343 for (Iterator it = subjectClasses.iterator(); it.hasNext(); ) 344 removeNotificationListener(zone, (Class )it.next(), listener); 345 } 346 347 public void removeNotificationListener( 348 Class [] subjectClasses, NotificationListener listener) 349 { 350 removeNotificationListener((String )null, subjectClasses, listener); 351 } 352 public void removeNotificationListener( 353 String zone, Class [] subjectClasses, NotificationListener listener) 354 { 355 for (int i = 0; i < subjectClasses.length; ++i) 356 removeNotificationListener(zone, subjectClasses[i], listener); 357 } 358 359 373 protected static class SubjectBundle 374 { 375 public Set subjectCarriers = new HashSet (); 376 } 379 380 public void notify(NotificationEvent event) 381 { 382 if (event == null) 383 throw new NullPointerException ("Parameter 'event' must not be null!"); 384 385 if (!interceptors.isEmpty()) 386 intercept(event); 387 388 notify(event, null); 389 } 390 391 protected NotificationEvent intercept(NotificationEvent event) 392 { 393 interceptorsMutex.acquireReadLock(); 394 try { 395 for (Iterator it = interceptors.iterator(); it.hasNext(); ) { 396 Interceptor interceptor = (Interceptor) it.next(); 397 NotificationEvent newEvent = interceptor.intercept(event); 398 if (newEvent != null) 399 event = newEvent; 400 } 401 } finally { 402 interceptorsMutex.releaseLock(); 403 } 404 return event; 405 } 406 407 408 418 protected void notify(NotificationEvent event, NotificationListener onlyThisNotificationListener) 419 { 420 if (event == null) 421 throw new NullPointerException ("Parameter 'event' must not be null!"); 422 423 notificationListenersByZoneMutex.acquireReadLock(); 424 try { 425 426 Collection zones; 427 if (event.getZone() == null) { 428 zones = notificationListenersByZone.keySet(); 430 } 431 else { 432 zones = new LinkedList (); 435 zones.add(event.getZone()); 436 zones.add(null); 437 } 438 439 449 Map listenerSubjects = new HashMap (); 455 456 for (Iterator itZones = zones.iterator(); itZones.hasNext(); ) { 457 String zone = (String ) itZones.next(); 458 459 Map notificationListenersBySubjectClass = (Map ) notificationListenersByZone.get(zone); 460 if (notificationListenersBySubjectClass == null) 461 continue; 462 463 for (Iterator itSubjects = event.getSubjectCarriers().iterator(); itSubjects.hasNext(); ) { 464 SubjectCarrier subjectCarrier = (SubjectCarrier) itSubjects.next(); 465 466 for (Iterator itSubjectClasses = subjectCarrier.getSubjectClasses().iterator(); itSubjectClasses.hasNext(); ) { 467 Class subjectClass = (Class ) itSubjectClasses.next(); 468 boolean inheritanceIgnored = subjectCarrier.isInheritanceIgnored(); 469 boolean interfacesIgnored = subjectCarrier.isInterfacesIgnored(); 470 boolean breakOnFirstFound = subjectCarrier.isBreakOnFirstFound(); 471 boolean doBreak = false; 472 Class clazz = subjectClass; 473 do { 474 Map mapListeners = (Map ) notificationListenersBySubjectClass.get(clazz); 475 if (mapListeners == null && !interfacesIgnored) { 476 Class [] interfaces = clazz.getInterfaces(); 477 for (int i = 0; i < interfaces.length; i++) { 478 mapListeners = (Map ) notificationListenersBySubjectClass.get(interfaces[i]); 479 if ( mapListeners != null) 480 break; 481 } 482 } 483 if (mapListeners != null) { 484 for (Iterator itListeners = mapListeners.values().iterator(); itListeners.hasNext(); ) { 485 Map mapModes = (Map ) itListeners.next(); 486 if (doBreak) 487 break; 488 for (Iterator itModes = mapModes.values().iterator(); itModes.hasNext(); ) { 489 NotificationListenerMeta meta = (NotificationListenerMeta) itModes.next(); 490 NotificationListener listener = meta.getNotificationListener(); 491 492 if (onlyThisNotificationListener != null && 493 onlyThisNotificationListener != listener) 494 listener = null; 495 496 if (listener != null) { 497 Map m = (Map ) listenerSubjects.get(listener); 498 if (m == null) { 499 m = new HashMap (); 500 listenerSubjects.put(listener, m); 501 } 502 SubjectBundle subjectBundle = (SubjectBundle) m.get(meta.getNotificationMode()); 503 if (subjectBundle == null) { 504 subjectBundle = new SubjectBundle(); 505 m.put(meta.getNotificationMode(), subjectBundle); 506 } 507 subjectBundle.subjectCarriers.add(subjectCarrier); 508 if (breakOnFirstFound) { 509 doBreak = true; 510 break; 511 } 512 } } } } 521 if (doBreak) 522 break; 523 if (inheritanceIgnored) 524 clazz = null; 525 else 526 clazz = clazz.getSuperclass(); 527 } while (clazz != null); 528 529 } } 532 for (Iterator itListeners = listenerSubjects.entrySet().iterator(); itListeners.hasNext(); ) { 533 Map.Entry meListener = (Map.Entry )itListeners.next(); 534 NotificationListener listener = (NotificationListener) meListener.getKey(); 535 Map mapModeSubjects = (Map ) meListener.getValue(); 536 for (Iterator itModes = mapModeSubjects.entrySet().iterator(); itModes.hasNext(); ) { 537 Map.Entry meMode = (Map.Entry ) itModes.next(); 538 String notificationMode = (String ) meMode.getKey(); 539 SubjectBundle subjectBundle = (SubjectBundle) meMode.getValue(); 540 541 NotificationEvent newEvent; 542 if (subjectBundle.subjectCarriers.size() == event.getSubjectCarriers().size()) 543 newEvent = event; 544 else 545 newEvent = new NotificationEvent( 546 event.getSource(), event.getZone(), 547 null, null, subjectBundle.subjectCarriers); 548 549 performNotification(notificationMode, listener, newEvent); 550 } 551 } 552 } 554 } finally { 555 notificationListenersByZoneMutex.releaseLock(); 556 } 557 } 558 559 564 protected void performNotification( 565 String notificationMode, 566 final NotificationListener listener, final NotificationEvent event) 567 { 568 if (NotificationListenerCallerThread.class.getName().equals(notificationMode)) { 569 listener.notify(event); 570 } 571 else if (NotificationListenerWorkerThreadAsync.class.getName().equals(notificationMode)) { 572 Thread worker = new Thread () { 573 public void run() { 574 listener.notify(event); 575 } 576 }; 577 worker.start(); 578 } 579 else if (NotificationListenerAWTThreadSync.class.getName().equals(notificationMode)) { 580 try { 581 SwingUtilities.invokeAndWait(new Runnable () { 582 public void run() { 583 listener.notify(event); 584 } 585 }); 586 } catch (InterruptedException e) { 587 throw new RuntimeException (e); 588 } catch (InvocationTargetException e) { 589 throw new RuntimeException (e); 590 } 591 } 592 else if (NotificationListenerAWTThreadAsync.class.getName().equals(notificationMode)) { 593 SwingUtilities.invokeLater(new Runnable () { 594 public void run() { 595 listener.notify(event); 596 } 597 }); 598 } 599 else 600 throw new IllegalArgumentException ("unknown notificationMode: " + notificationMode); 601 } 602 } 603 | Popular Tags |