#58941: The array passed to setLookups was thought as not modifiable and if someone modified it and setLookups once again things were obviously broken. Making clone of the array in setLookups and also creating clone in getLookups. Testing both cases. version-2-3-29
authorjtulach@netbeans.org
Sun, 12 Jun 2005 15:44:26 +0000
changeset 30a47f57229ef1
parent 29 83f96b019cf9
child 31 e2c036c6788c
#58941: The array passed to setLookups was thought as not modifiable and if someone modified it and setLookups once again things were obviously broken. Making clone of the array in setLookups and also creating clone in getLookups. Testing both cases.
openide.util/src/org/openide/util/lookup/ProxyLookup.java
openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java
     1.1 --- a/openide.util/src/org/openide/util/lookup/ProxyLookup.java	Fri Jun 10 16:14:59 2005 +0000
     1.2 +++ b/openide.util/src/org/openide/util/lookup/ProxyLookup.java	Sun Jun 12 15:44:26 2005 +0000
     1.3 @@ -29,8 +29,11 @@
     1.4   * @since 1.9
     1.5   */
     1.6  public class ProxyLookup extends Lookup {
     1.7 -    /** lookups to delegate to */
     1.8 -    private Lookup[] lookups;
     1.9 +    /** empty array of lookups for potential use */
    1.10 +    private static final Lookup[] EMPTY_ARR = new Lookup[0];
    1.11 +    
    1.12 +    /** lookups to delegate to (either Lookup or array of Lookups) */
    1.13 +    private Object lookups;
    1.14  
    1.15      /** map of templates to currently active results */
    1.16      private HashMap results;
    1.17 @@ -39,7 +42,7 @@
    1.18       * @param lookups the initial delegates
    1.19       */
    1.20      public ProxyLookup(Lookup[] lookups) {
    1.21 -        this.lookups = lookups;
    1.22 +        this.setLookupsNoFire(lookups);
    1.23      }
    1.24  
    1.25      /**
    1.26 @@ -48,11 +51,11 @@
    1.27       * @since 3.27
    1.28       */
    1.29      protected ProxyLookup() {
    1.30 -        this(new Lookup[0]);
    1.31 +        this(EMPTY_ARR);
    1.32      }
    1.33  
    1.34      public String toString() {
    1.35 -        return "ProxyLookup(class=" + getClass() + ")->" + Arrays.asList(lookups); // NOI18N
    1.36 +        return "ProxyLookup(class=" + getClass() + ")->" + Arrays.asList(getLookups(false)); // NOI18N
    1.37      }
    1.38  
    1.39      /** Getter for the delegates.
    1.40 @@ -60,7 +63,39 @@
    1.41      * @since 1.19
    1.42      */
    1.43      protected final Lookup[] getLookups() {
    1.44 -        return lookups;
    1.45 +        return getLookups(true);
    1.46 +    }
    1.47 +
    1.48 +    /** getter for the delegates, that can but need not do a clone.
    1.49 +     * @param clone true if clone of internal array is requested
    1.50 +     */
    1.51 +    private final Lookup[] getLookups(boolean clone) {
    1.52 +        Object l = this.lookups;
    1.53 +        if (l instanceof Lookup) {
    1.54 +            return new Lookup[] { (Lookup)l };
    1.55 +        } else {
    1.56 +            Lookup[] arr = (Lookup[])l;
    1.57 +            if (clone) {
    1.58 +                arr = (Lookup[])arr.clone();
    1.59 +            }
    1.60 +            return arr;
    1.61 +        }
    1.62 +    }
    1.63 +    
    1.64 +    /** Called from setLookups and constructor. 
    1.65 +     * @param lookups the lookups to setup
    1.66 +     */
    1.67 +    private void setLookupsNoFire(Lookup[] lookups) {
    1.68 +        if (lookups.length == 1) {
    1.69 +            this.lookups = lookups[0];
    1.70 +            assert this.lookups != null : "Cannot assign null delegate";
    1.71 +        } else {
    1.72 +            if (lookups.length == 0) {
    1.73 +                this.lookups = EMPTY_ARR;
    1.74 +            } else {
    1.75 +                this.lookups = lookups.clone();
    1.76 +            }
    1.77 +        }
    1.78      }
    1.79  
    1.80      /** Change the delegates. To forbid anybody else then the creator
    1.81 @@ -76,12 +111,12 @@
    1.82          Lookup[] old;
    1.83  
    1.84          synchronized (this) {
    1.85 -            current = new HashSet(Arrays.asList(this.lookups));
    1.86 +            old = getLookups(false);
    1.87 +            current = new HashSet(Arrays.asList(old));
    1.88              newL = new HashSet(Arrays.asList(lookups));
    1.89  
    1.90 -            old = this.lookups;
    1.91 -            this.lookups = lookups;
    1.92 -
    1.93 +            setLookupsNoFire(lookups);
    1.94 +            
    1.95              if ((results == null) || results.isEmpty()) {
    1.96                  // no affected results => exit
    1.97                  return;
    1.98 @@ -139,7 +174,7 @@
    1.99      public final Object lookup(Class clazz) {
   1.100          beforeLookup(new Template(clazz));
   1.101  
   1.102 -        Lookup[] lookups = this.lookups;
   1.103 +        Lookup[] lookups = this.getLookups(false);
   1.104  
   1.105          for (int i = 0; i < lookups.length; i++) {
   1.106              Object o = lookups[i].lookup(clazz);
   1.107 @@ -159,7 +194,7 @@
   1.108      public final Item lookupItem(Template template) {
   1.109          beforeLookup(template);
   1.110  
   1.111 -        Lookup[] lookups = this.lookups;
   1.112 +        Lookup[] lookups = this.getLookups(false);
   1.113  
   1.114          for (int i = 0; i < lookups.length; i++) {
   1.115              Item o = lookups[i].lookupItem(template);
   1.116 @@ -250,10 +285,11 @@
   1.117                  }
   1.118              }
   1.119  
   1.120 -            Result[] arr = new Result[lookups.length];
   1.121 +            Lookup[] myLkps = getLookups(false);
   1.122 +            Result[] arr = new Result[myLkps.length];
   1.123  
   1.124              for (int i = 0; i < arr.length; i++) {
   1.125 -                arr[i] = lookups[i].lookup(template);
   1.126 +                arr[i] = myLkps[i].lookup(template);
   1.127              }
   1.128  
   1.129              synchronized (this) {
     2.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java	Fri Jun 10 16:14:59 2005 +0000
     2.2 +++ b/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java	Sun Jun 12 15:44:26 2005 +0000
     2.3 @@ -142,4 +142,64 @@
     2.4              p.setLookups (new Lookup[] { a1, a2, a3 });
     2.5          }
     2.6      }
     2.7 +    
     2.8 +    public void testProxyLookupTemplateCaching(){
     2.9 +        Lookup lookups[] = new Lookup[1];
    2.10 +        doProxyLookupTemplateCaching(lookups, false);
    2.11 +    }
    2.12 +    
    2.13 +    public void testProxyLookupTemplateCachingOnSizeTwoArray() {
    2.14 +        Lookup lookups[] = new Lookup[2];
    2.15 +        lookups[1] = Lookup.EMPTY;
    2.16 +        doProxyLookupTemplateCaching(lookups, false);
    2.17 +    }
    2.18 +    public void testProxyLookupShallNotAllowModificationOfGetLookups(){
    2.19 +        Lookup lookups[] = new Lookup[1];
    2.20 +        doProxyLookupTemplateCaching(lookups, true);
    2.21 +    }
    2.22 +    
    2.23 +    public void testProxyLookupShallNotAllowModificationOfGetLookupsOnSizeTwoArray() {
    2.24 +        Lookup lookups[] = new Lookup[2];
    2.25 +        lookups[1] = Lookup.EMPTY;
    2.26 +        doProxyLookupTemplateCaching(lookups, true);
    2.27 +    }
    2.28 +    
    2.29 +    /** Index 0 of lookups will be modified, the rest is up to the 
    2.30 +     * setup code.
    2.31 +     */
    2.32 +    private void doProxyLookupTemplateCaching(Lookup[] lookups, boolean reget) {
    2.33 +        // Create MyProxyLookup with one lookup containing the String object
    2.34 +        InstanceContent ic = new InstanceContent();
    2.35 +        ic.add(new String("Hello World")); //NOI18N
    2.36 +        lookups[0] = new AbstractLookup(ic);
    2.37 +        ProxyLookup proxy = new ProxyLookup(lookups);
    2.38 +        if (reget) {
    2.39 +            lookups = proxy.getLookups();
    2.40 +        }
    2.41 +        
    2.42 +        // Performing template lookup for String object
    2.43 +        Lookup.Result result = proxy.lookup(new Lookup.Template(String.class, null, null));
    2.44 +        int stringTemplateResultSize = result.allInstances().size();
    2.45 +        assertEquals ("Ensure, there is only one instance of String.class in proxyLookup:", //NOI18N
    2.46 +                1, stringTemplateResultSize);
    2.47 +        
    2.48 +        // Changing lookup in proxy lookup, now it will contain 
    2.49 +        // StringBuffer Object instead of String
    2.50 +        InstanceContent ic2 = new InstanceContent();
    2.51 +        ic2.add(new Integer(1234567890));
    2.52 +        lookups[0] = new AbstractLookup(ic2);
    2.53 +        proxy.setLookups(lookups);
    2.54 +        
    2.55 +        assertEquals ("the old result is updated", 0, result.allInstances().size());
    2.56 +
    2.57 +        // Instance of String.class should not appear in proxyLookup
    2.58 +        Lookup.Result r2 = proxy.lookup(new Lookup.Template(String.class, null, null));
    2.59 +        assertEquals ("Instance of String.class should not appear in proxyLookup:", //NOI18N
    2.60 +                0, r2.allInstances().size());
    2.61 +
    2.62 +        Lookup.Result r3 = proxy.lookup(new Lookup.Template(Integer.class, null, null));
    2.63 +        assertEquals ("There is only one instance of Integer.class in proxyLookup:", //NOI18N
    2.64 +                1, r3.allInstances().size());
    2.65 +        
    2.66 +    }
    2.67  }