#62194: Race condition that could result in getLoader be null fixed.
1.1 --- a/openide.util/src/org/openide/util/IconManager.java Fri Nov 04 09:23:48 2005 +0000
1.2 +++ b/openide.util/src/org/openide/util/IconManager.java Fri Nov 04 10:54:10 2005 +0000
1.3 @@ -42,7 +42,7 @@
1.4 * @see "#20072"
1.5 */
1.6 private static final Set extraInitialSlashes = new HashSet(); // Set<String>
1.7 - private static ClassLoader currentLoader = null;
1.8 + private static volatile Object currentLoader;
1.9 private static Lookup.Result loaderQuery = null;
1.10 private static boolean noLoaderWarned = false;
1.11 private static final Component component = new Component() {
1.12 @@ -50,38 +50,50 @@
1.13
1.14 private static final MediaTracker tracker = new MediaTracker(component);
1.15 private static int mediaTrackerID;
1.16 +
1.17 + private static ErrorManager ERR = ErrorManager.getDefault ().getInstance (IconManager.class.getName());
1.18
1.19 /**
1.20 * Get the class loader from lookup.
1.21 * Since this is done very frequently, it is wasteful to query lookup each time.
1.22 * Instead, remember the last result and just listen for changes.
1.23 */
1.24 - private static ClassLoader getLoader() {
1.25 - if (currentLoader == null) {
1.26 - if (loaderQuery == null) {
1.27 - loaderQuery = Lookup.getDefault().lookup(new Lookup.Template(ClassLoader.class));
1.28 - loaderQuery.addLookupListener(
1.29 - new LookupListener() {
1.30 - public void resultChanged(LookupEvent ev) {
1.31 - currentLoader = null;
1.32 - }
1.33 + static ClassLoader getLoader() {
1.34 + Object is = currentLoader;
1.35 + if (is instanceof ClassLoader) {
1.36 + return (ClassLoader)is;
1.37 + }
1.38 +
1.39 + currentLoader = Thread.currentThread();
1.40 +
1.41 + if (loaderQuery == null) {
1.42 + loaderQuery = Lookup.getDefault().lookup(new Lookup.Template(ClassLoader.class));
1.43 + loaderQuery.addLookupListener(
1.44 + new LookupListener() {
1.45 + public void resultChanged(LookupEvent ev) {
1.46 + ERR.log("Loader cleared"); // NOI18N
1.47 + currentLoader = null;
1.48 }
1.49 + }
1.50 + );
1.51 + }
1.52 +
1.53 + Iterator it = loaderQuery.allInstances().iterator();
1.54 + if (it.hasNext()) {
1.55 + ClassLoader toReturn = (ClassLoader) it.next();
1.56 + if (currentLoader == Thread.currentThread()) {
1.57 + currentLoader = toReturn;
1.58 + }
1.59 + ERR.log("Loader computed: " + currentLoader); // NOI18N
1.60 + return toReturn;
1.61 + } else { if (!noLoaderWarned) {
1.62 + noLoaderWarned = true;
1.63 + ERR.log(
1.64 + ErrorManager.WARNING, "No ClassLoader instance found in " + Lookup.getDefault() // NOI18N
1.65 );
1.66 }
1.67 -
1.68 - Iterator it = loaderQuery.allInstances().iterator();
1.69 -
1.70 - if (it.hasNext()) {
1.71 - currentLoader = (ClassLoader) it.next();
1.72 - } else if (!noLoaderWarned) {
1.73 - noLoaderWarned = true;
1.74 - ErrorManager.getDefault().log(
1.75 - ErrorManager.WARNING, "No ClassLoader instance found in " + Lookup.getDefault()
1.76 - );
1.77 - }
1.78 + return null;
1.79 }
1.80 -
1.81 - return currentLoader;
1.82 }
1.83
1.84 static Image getIcon(String resource, boolean localized) {
1.85 @@ -241,7 +253,7 @@
1.86
1.87 if (img != null) {
1.88 if (warn && extraInitialSlashes.add(name)) {
1.89 - ErrorManager.getDefault().log(
1.90 + ERR.log(
1.91 ErrorManager.WARNING, "Initial slashes in Utilities.loadImage deprecated (cf. #20072): " +
1.92 name
1.93 ); // NOI18N
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/openide.util/test/unit/src/org/openide/util/IconManagerGetLoaderTest.java Fri Nov 04 10:54:10 2005 +0000
2.3 @@ -0,0 +1,123 @@
2.4 +/*
2.5 + * Sun Public License Notice
2.6 + *
2.7 + * The contents of this file are subject to the Sun Public License
2.8 + * Version 1.0 (the "License"). You may not use this file except in
2.9 + * compliance with the License. A copy of the License is available at
2.10 + * http://www.sun.com/
2.11 + *
2.12 + * The Original Code is NetBeans. The Initial Developer of the Original
2.13 + * Code is Sun Microsystems, Inc. Portions Copyright 1997-2004 Sun
2.14 + * Microsystems, Inc. All Rights Reserved.
2.15 + */
2.16 +package org.openide.util;
2.17 +
2.18 +import java.net.URL;
2.19 +import java.net.URLClassLoader;
2.20 +import junit.framework.*;
2.21 +import org.openide.ErrorManager;
2.22 +import java.awt.Component;
2.23 +import java.awt.Image;
2.24 +import java.awt.MediaTracker;
2.25 +import java.awt.Toolkit;
2.26 +import java.awt.image.BufferedImage;
2.27 +import java.awt.image.ImageObserver;
2.28 +import java.lang.ref.*;
2.29 +import java.util.*;
2.30 +
2.31 +/**
2.32 + *
2.33 + * @author Jaroslav Tulach
2.34 + */
2.35 +public class IconManagerGetLoaderTest extends TestCase {
2.36 + static {
2.37 + System.setProperty("org.openide.util.Lookup", "org.openide.util.IconManagerGetLoaderTest$Lkp");
2.38 + }
2.39 +
2.40 +
2.41 + public IconManagerGetLoaderTest (String testName) {
2.42 + super (testName);
2.43 + }
2.44 +
2.45 + protected void setUp () throws Exception {
2.46 + }
2.47 +
2.48 + protected void tearDown () throws Exception {
2.49 + }
2.50 +
2.51 + public static Test suite () {
2.52 + TestSuite suite = new TestSuite(IconManagerGetLoaderTest.class);
2.53 + return suite;
2.54 + }
2.55 +
2.56 +
2.57 + public void testWrongImplOfGetLoaderIssue62194() throws Exception {
2.58 + ClassLoader l = IconManager.getLoader ();
2.59 + assertTrue("Error manager race condition activated", ErrMgr.switchDone);
2.60 + assertEquals("c1 the original one", Lkp.c1, l);
2.61 +
2.62 + ClassLoader n = IconManager.getLoader ();
2.63 + assertEquals("c2 the new one", Lkp.c2, n);
2.64 + }
2.65 +
2.66 +
2.67 +
2.68 + public static final class Lkp extends org.openide.util.lookup.AbstractLookup {
2.69 + private ErrMgr err = new ErrMgr();
2.70 + private org.openide.util.lookup.InstanceContent ic;
2.71 + static ClassLoader c1 = new URLClassLoader(new URL[0]);
2.72 + static ClassLoader c2 = new URLClassLoader(new URL[0]);
2.73 +
2.74 + public Lkp () {
2.75 + this (new org.openide.util.lookup.InstanceContent ());
2.76 + }
2.77 +
2.78 + private Lkp (org.openide.util.lookup.InstanceContent ic) {
2.79 + super (ic);
2.80 + this.ic = ic;
2.81 +
2.82 + turn(c1);
2.83 + }
2.84 +
2.85 + public void turn (ClassLoader c) {
2.86 + ArrayList l = new ArrayList();
2.87 + l.add(err);
2.88 + l.add(c);
2.89 + ic.set (l, null);
2.90 + }
2.91 + }
2.92 +
2.93 +
2.94 + private static class ErrMgr extends ErrorManager {
2.95 + public static boolean switchDone;
2.96 +
2.97 + public Throwable attachAnnotations (Throwable t, ErrorManager.Annotation[] arr) {
2.98 + return null;
2.99 + }
2.100 +
2.101 + public ErrorManager.Annotation[] findAnnotations (Throwable t) {
2.102 + return null;
2.103 + }
2.104 +
2.105 + public Throwable annotate (Throwable t, int severity, String message, String localizedMessage, Throwable stackTrace, Date date) {
2.106 + return null;
2.107 + }
2.108 +
2.109 + public void notify (int severity, Throwable t) {
2.110 + }
2.111 +
2.112 + public void log (int severity, String s) {
2.113 + if (s.startsWith ("Loader computed")) {
2.114 + switchDone = true;
2.115 + Lkp lkp = (Lkp)org.openide.util.Lookup.getDefault ();
2.116 + lkp.turn (Lkp.c2);
2.117 + }
2.118 + }
2.119 +
2.120 + public ErrorManager getInstance (String name) {
2.121 + return this;
2.122 + }
2.123 +
2.124 + }
2.125 +
2.126 +}