#62194: Race condition that could result in getLoader be null fixed. javaee5_before_merge6_new lookup_without_ise_67404_root
authorjtulach@netbeans.org
Fri, 04 Nov 2005 10:54:10 +0000
changeset 81e6f7a0000931
parent 80 4599f7b5249c
child 82 6108ee974f4b
#62194: Race condition that could result in getLoader be null fixed.
openide.util/src/org/openide/util/IconManager.java
openide.util/test/unit/src/org/openide/util/IconManagerGetLoaderTest.java
     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 +}