1 19 20 package org.openide.util; 21 22 import java.awt.event.FocusEvent ; 23 import java.awt.event.FocusListener ; 24 import java.beans.PropertyChangeEvent ; 25 import java.beans.PropertyChangeListener ; 26 import java.beans.PropertyVetoException ; 27 import java.beans.VetoableChangeListener ; 28 import java.lang.ref.Reference ; 29 import java.lang.ref.SoftReference ; 30 import java.lang.ref.WeakReference ; 31 import java.lang.reflect.Constructor ; 32 import java.lang.reflect.InvocationHandler ; 33 import java.lang.reflect.Method ; 34 import java.lang.reflect.Modifier ; 35 import java.lang.reflect.Proxy ; 36 import java.util.EventListener ; 37 import java.util.EventObject ; 38 import java.util.logging.Level ; 39 import java.util.logging.Logger ; 40 import java.util.Map ; 41 import java.util.WeakHashMap ; 42 import javax.swing.event.ChangeEvent ; 43 import javax.swing.event.ChangeListener ; 44 import javax.swing.event.DocumentEvent ; 45 import javax.swing.event.DocumentListener ; 46 47 53 abstract class WeakListenerImpl implements java.util.EventListener { 54 55 private ListenerReference ref; 56 57 58 Class listenerClass; 59 60 61 private Reference <Object > source; 62 63 68 protected WeakListenerImpl(Class listenerClass, java.util.EventListener l) { 69 this.listenerClass = listenerClass; 70 ref = new ListenerReference(l, this); 71 } 72 73 89 protected final void setSource(Object source) { 90 if (source == null) { 91 this.source = null; 92 } else { 93 this.source = new WeakReference <Object >(source); 94 } 95 } 96 97 101 protected abstract String removeMethodName(); 102 103 107 protected final java.util.EventListener get(java.util.EventObject ev) { 108 Object l = ref.get(); 110 if (l == null) { 112 ref.requestCleanUp((ev == null) ? null : ev.getSource()); 113 } 114 115 return (EventListener ) l; 116 } 117 118 Object getImplementator() { 119 return this; 120 } 121 122 public String toString() { 123 Object listener = ref.get(); 124 125 return getClass().getName() + "[" + ((listener == null) ? "null" : (listener.getClass().getName() + "]")); 126 } 127 128 public static <T extends EventListener > T create(Class <T> lType, Class <? super T> apiType, T l, Object source) { 129 ProxyListener pl = new ProxyListener(lType, apiType, l); 130 pl.setSource(source); 131 132 return lType.cast(pl.proxy); 133 } 134 135 137 static class PropertyChange extends WeakListenerImpl implements PropertyChangeListener { 138 141 public PropertyChange(PropertyChangeListener l) { 142 super(PropertyChangeListener .class, l); 143 } 144 145 149 PropertyChange(Class clazz, PropertyChangeListener l) { 150 super(clazz, l); 151 } 152 153 157 public void propertyChange(PropertyChangeEvent ev) { 158 PropertyChangeListener l = (PropertyChangeListener ) super.get(ev); 159 160 if (l != null) { 161 l.propertyChange(ev); 162 } 163 } 164 165 169 protected String removeMethodName() { 170 return "removePropertyChangeListener"; } 172 } 173 174 176 static class VetoableChange extends WeakListenerImpl implements VetoableChangeListener { 177 180 public VetoableChange(VetoableChangeListener l) { 181 super(VetoableChangeListener .class, l); 182 } 183 184 188 public void vetoableChange(PropertyChangeEvent ev) 189 throws PropertyVetoException { 190 VetoableChangeListener l = (VetoableChangeListener ) super.get(ev); 191 192 if (l != null) { 193 l.vetoableChange(ev); 194 } 195 } 196 197 201 protected String removeMethodName() { 202 return "removeVetoableChangeListener"; } 204 } 205 206 210 static final class Document extends WeakListenerImpl implements DocumentListener { 211 214 public Document(final DocumentListener l) { 215 super(DocumentListener .class, l); 216 } 217 218 221 public void changedUpdate(DocumentEvent ev) { 222 final DocumentListener l = docGet(ev); 223 224 if (l != null) { 225 l.changedUpdate(ev); 226 } 227 } 228 229 232 public void insertUpdate(DocumentEvent ev) { 233 final DocumentListener l = docGet(ev); 234 235 if (l != null) { 236 l.insertUpdate(ev); 237 } 238 } 239 240 243 public void removeUpdate(DocumentEvent ev) { 244 final DocumentListener l = docGet(ev); 245 246 if (l != null) { 247 l.removeUpdate(ev); 248 } 249 } 250 251 255 protected String removeMethodName() { 256 return "removeDocumentListener"; } 258 259 263 private DocumentListener docGet(DocumentEvent ev) { 264 DocumentListener l = (DocumentListener ) super.ref.get(); 265 266 if (l == null) { 267 super.ref.requestCleanUp(ev.getDocument()); 268 } 269 270 return l; 271 } 272 } 273 275 279 static final class Change extends WeakListenerImpl implements ChangeListener { 280 283 public Change(ChangeListener l) { 284 super(ChangeListener .class, l); 285 } 286 287 290 public void stateChanged(final ChangeEvent ev) { 291 ChangeListener l = (ChangeListener ) super.get(ev); 292 293 if (l != null) { 294 l.stateChanged(ev); 295 } 296 } 297 298 302 protected String removeMethodName() { 303 return "removeChangeListener"; } 305 } 306 307 311 static final class Focus extends WeakListenerImpl implements FocusListener { 312 315 public Focus(FocusListener l) { 316 super(FocusListener .class, l); 317 } 318 319 321 public void focusGained(FocusEvent ev) { 322 FocusListener l = (FocusListener ) super.get(ev); 323 324 if (l != null) { 325 l.focusGained(ev); 326 } 327 } 328 329 331 public void focusLost(FocusEvent ev) { 332 FocusListener l = (FocusListener ) super.get(ev); 333 334 if (l != null) { 335 l.focusLost(ev); 336 } 337 } 338 339 343 protected String removeMethodName() { 344 return "removeFocusListener"; } 346 } 347 348 350 private static class ProxyListener extends WeakListenerImpl implements InvocationHandler { 351 352 private static Method equalsMth; 353 354 355 private static final Map <Class , Reference <Constructor >> constructors = new WeakHashMap <Class , Reference <Constructor >>(); 356 357 358 public final Object proxy; 359 360 362 public ProxyListener(Class c, Class api, java.util.EventListener listener) { 363 super(api, listener); 364 365 try { 366 Reference ref = (Reference ) constructors.get(c); 367 Constructor proxyConstructor = (ref == null) ? null : (Constructor ) ref.get(); 368 369 if (proxyConstructor == null) { 370 Class <?> proxyClass = Proxy.getProxyClass(c.getClassLoader(), new Class [] { c }); 371 proxyConstructor = proxyClass.getConstructor(new Class [] { InvocationHandler .class }); 372 constructors.put(c, new SoftReference <Constructor >(proxyConstructor)); 373 } 374 375 Object p; 376 377 try { 378 p = proxyConstructor.newInstance(new Object [] { this }); 379 } catch (java.lang.NoClassDefFoundError err) { 380 p = Proxy.newProxyInstance(c.getClassLoader(), new Class [] { c }, this); 384 } 385 386 proxy = p; 387 } catch (Exception ex) { 388 throw (IllegalStateException ) new IllegalStateException (ex.toString()).initCause(ex); 389 } 390 } 391 392 393 private static Method getEquals() { 394 if (equalsMth == null) { 395 try { 396 equalsMth = Object .class.getMethod("equals", new Class [] { Object .class }); } catch (NoSuchMethodException e) { 398 e.printStackTrace(); 399 } 400 } 401 402 return equalsMth; 403 } 404 405 public java.lang.Object invoke(Object proxy, Method method, Object [] args) 406 throws Throwable { 407 if (method.getDeclaringClass() == Object .class) { 408 if (method == getEquals()) { 410 boolean ret = equals(args[0]); 411 412 return (ret ? Boolean.TRUE : Boolean.FALSE); 413 } 414 415 return method.invoke(this, args); 416 } 417 418 EventObject ev = ((args != null) && (args[0] instanceof EventObject )) ? (EventObject ) args[0] : null; 420 421 Object listener = super.get(ev); 422 423 if (listener != null) { 424 return method.invoke(listener, args); 425 } else { 426 return null; 427 } 428 } 429 430 432 protected String removeMethodName() { 433 String name = listenerClass.getName(); 434 435 int dot = name.lastIndexOf('.'); 437 name = name.substring(dot + 1); 438 439 int i = name.lastIndexOf('$'); 443 if (i >= 0) { 444 name = name.substring(i + 1); 445 } 446 447 return "remove".concat(name); } 449 450 452 public String toString() { 453 return super.toString() + "[" + listenerClass + "]"; } 455 456 458 public boolean equals(Object obj) { 459 return (proxy == obj) || (this == obj); 460 } 461 462 Object getImplementator() { 463 return proxy; 464 } 465 } 466 467 469 private static final class ListenerReference extends WeakReference <Object > implements Runnable { 470 private static Class lastClass; 471 private static String lastMethodName; 472 private static Method lastRemove; 473 private static Object LOCK = new Object (); 474 WeakListenerImpl weakListener; 475 476 public ListenerReference(Object ref, WeakListenerImpl weakListener) { 477 super(ref, Utilities.activeReferenceQueue()); 478 this.weakListener = weakListener; 479 } 480 481 484 public synchronized void requestCleanUp(Object source) { 485 if (weakListener == null) { 486 return; 488 } 489 490 if (weakListener.source != source) { 491 weakListener.source = new WeakReference <Object > (source) { 494 ListenerReference doNotGCRef = new ListenerReference(new Object (), weakListener); 495 }; 496 } 497 } 498 499 public void run() { 500 Object [] params = new Object [1]; 502 Class [] types = new Class [1]; 503 Object src = null; Method remove = null; 505 506 WeakListenerImpl ref; 507 508 synchronized (this) { 509 ref = weakListener; 510 511 if ((ref.source == null) || ((src = ref.source.get()) == null)) { 512 return; 513 } 514 515 weakListener = null; 517 } 518 519 Class methodClass; 520 if (src instanceof Class ) { 521 methodClass = (Class ) src; 523 } else { 524 methodClass = src.getClass(); 525 } 526 String methodName = ref.removeMethodName(); 527 528 synchronized (LOCK) { 529 if ((lastClass == methodClass) && (lastMethodName == methodName) && (lastRemove != null)) { 530 remove = lastRemove; 531 } 532 } 533 534 if (remove == null) { 536 types[0] = ref.listenerClass; 537 remove = getRemoveMethod(methodClass, methodName, types[0]); 538 539 if (remove == null) { 540 Logger.getAnonymousLogger().warning( 541 "Can't remove " + ref.listenerClass.getName() + " using method " + methodName + " from " + src 544 ); 546 return; 547 } else { 548 synchronized (LOCK) { 549 lastClass = methodClass; 550 lastMethodName = methodName; 551 lastRemove = remove; 552 } 553 } 554 } 555 556 params[0] = ref.getImplementator(); 558 try { 559 remove.invoke(src, params); 560 } catch (Exception ex) { Logger.getAnonymousLogger().warning( 562 "Problem encountered while calling " + methodClass + "." + methodName + "(...) on " + src 563 ); Logger.getAnonymousLogger().log(Level.WARNING, null, ex); 565 } 566 } 567 568 569 private Method getRemoveMethod(Class <?> methodClass, String methodName, Class listenerClass) { 570 final Class <?>[] clarray = new Class <?>[] { listenerClass }; 571 Method m = null; 572 573 try { 574 m = methodClass.getMethod(methodName, clarray); 575 } catch (NoSuchMethodException e) { 576 do { 577 try { 578 m = methodClass.getDeclaredMethod(methodName, clarray); 579 } catch (NoSuchMethodException ex) { 580 } 581 582 methodClass = methodClass.getSuperclass(); 583 } while ((m == null) && (methodClass != Object .class)); 584 } 585 586 if ( 587 (m != null) && 588 (!Modifier.isPublic(m.getModifiers()) || !Modifier.isPublic(m.getDeclaringClass().getModifiers())) 589 ) { 590 m.setAccessible(true); 591 } 592 593 return m; 594 } 595 } 596 } 597 | Popular Tags |