This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 53058
Collapse All | Expand All

(-)src/org/openide/util/lookup/AbstractLookup.java (-22 / +38 lines)
Lines 529-534 Link Here
529
        protected abstract boolean creatorOf (Object obj);
529
        protected abstract boolean creatorOf (Object obj);
530
    }
530
    }
531
531
532
    /** Generic support for listeners, so it can be used in other results 
533
     * as well.
534
     * @param add true to add it, false to modify
535
     * @param l listener to modify
536
     * @param ref the value of the reference to listener or listener list
537
     * @return new value to the reference to listener or list
538
     */
539
    static Object modifyListenerList (boolean add, LookupListener l, Object ref) {
540
        if (add) {
541
            if (ref == null) {
542
                return l;
543
            }
544
545
            if (ref instanceof LookupListener) {
546
                ArrayList arr = new ArrayList ();
547
                arr.add (ref);
548
                ref = arr;
549
            }
550
            ((ArrayList)ref).add (l);
551
            return ref;
552
        } else {
553
            // remove
554
            if (ref == null) return null;
555
            if (ref == l) return null;
556
            ArrayList arr = (ArrayList)ref;
557
            arr.remove (l);
558
            if (arr.size () == 1) {
559
                return arr.iterator().next ();
560
            } else {
561
                return arr;
562
            }
563
564
        }
565
566
    }
567
532
    
568
    
533
    /** Result based on one instance returned.
569
    /** Result based on one instance returned.
534
     */
570
     */
Lines 608-643 Link Here
608
            }
644
            }
609
        }
645
        }
610
        
646
        
611
        
612
        /** Ok, register listeners to all classes and super classes.
647
        /** Ok, register listeners to all classes and super classes.
613
         */
648
         */
614
        public synchronized void addLookupListener (LookupListener l) {
649
        public synchronized void addLookupListener (LookupListener l) {
615
            if (listeners == null) {
650
            listeners = modifyListenerList (true, l, listeners);
616
                listeners = l;
617
                return;
618
            }
619
            
620
            if (listeners instanceof LookupListener) {
621
                ArrayList arr = new ArrayList ();
622
                arr.add (listeners);
623
                listeners = arr;
624
            }
625
            ((ArrayList)listeners).add (l);
626
        }    
651
        }    
627
        
652
        
628
        /** Ok, register listeners to all classes and super classes.
653
        /** Ok, register listeners to all classes and super classes.
629
         */
654
         */
630
        public synchronized void removeLookupListener (LookupListener l) {
655
        public synchronized void removeLookupListener (LookupListener l) {
631
            if (listeners == null) return;
656
            listeners = modifyListenerList (false, l, listeners);
632
            if (listeners == l) {
633
                listeners = null;
634
                return;
635
            }
636
            ArrayList arr = (ArrayList)listeners;
637
            arr.remove (l);
638
            if (arr.size () == 1) {
639
                listeners = arr.iterator().next ();
640
            }
641
        }    
657
        }    
642
        
658
        
643
        
659
        
(-)src/org/openide/util/lookup/ExcludingLookup.java (+239 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 *
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.util.lookup;
15
16
import java.util.*;
17
18
import org.openide.util.Lookup;
19
import org.openide.util.LookupListener;
20
21
/** Allows exclusion of certain instances from lookup.
22
 *
23
 * @author Jaroslav Tulach
24
 */
25
final class ExcludingLookup extends org.openide.util.Lookup {
26
    /** the other lookup that we delegate to */
27
    private Lookup delegate;
28
    /** classes to exclude (Class[]) or just one class (Class) */
29
    private Object classes;
30
31
    /** 
32
     * Creates new Result object with supplied instances parameter.
33
     * @param instances to be used to return from the lookup
34
     */
35
    ExcludingLookup(Lookup delegate, Class[] classes) {
36
        this.delegate = delegate;
37
        if (classes.length == 1) {
38
            this.classes = classes[0];
39
        } else {
40
            this.classes = classes;
41
        }
42
    }
43
    
44
    public String toString() {
45
        return "ExcludingLookup: " + delegate + " excludes: " + Arrays.asList (classes()); // NOI18N
46
    }
47
    
48
    public Result lookup(Template template) {
49
        if (template == null) {
50
            throw new NullPointerException();
51
        }
52
        if (areSubclassesOfThisClassAlwaysExcluded (template.getType ())) {
53
            // empty result
54
            return Lookup.EMPTY.lookup (template);
55
        }
56
        return new R (delegate.lookup (template));
57
    }
58
    
59
    public Object lookup(Class clazz) {
60
        if (areSubclassesOfThisClassAlwaysExcluded (clazz)) {
61
            return null;
62
        }
63
        
64
        Object res = delegate.lookup (clazz);
65
        if (res == null) {
66
            return null;
67
        }
68
        
69
        Class[] arr = classes();
70
        for (int i = 0; i < arr.length; i++) {
71
            if (arr[i].isInstance (res)) {
72
                return null;
73
            }
74
        }
75
        return res;
76
    }
77
78
    public org.openide.util.Lookup.Item lookupItem (org.openide.util.Lookup.Template template) {
79
        org.openide.util.Lookup.Item retValue = delegate.lookupItem (template);
80
        if (retValue == null) return null;
81
        
82
        Class[] arr = classes();
83
        for (int i = 0; i < arr.length; i++) {
84
            if (acceptFilter (arr[i], retValue, 2)) {
85
                return null;
86
            }
87
        }
88
        
89
        return retValue;
90
    }
91
    
92
    /** @return true if the instance of class c shall never be returned from this lookup
93
     */
94
    private boolean areSubclassesOfThisClassAlwaysExcluded (Class c) {
95
        Class[] arr = classes ();
96
        for (int i = 0; i < arr.length; i++) {
97
            if (arr[i].isAssignableFrom (c)) {
98
                return true;
99
            }
100
        }
101
        return false;
102
    }
103
    
104
    /** Returns the array of classes this lookup filters.
105
     */
106
    private Class[] classes () {
107
        if (classes instanceof Class[]) {
108
            return (Class[])classes;
109
        } else {
110
            return new Class[] { (Class)classes };
111
        }
112
    }
113
    
114
    /** based on type decides whether the class accepts or not anObject
115
     */
116
    static boolean acceptFilter (Class filter, Object anObject, int type) {
117
        switch (type) {
118
            case 0: return filter.isInstance (anObject);
119
            case 1: return filter.isAssignableFrom ((Class)anObject);
120
            case 2: {
121
                Item item = (Item)anObject;
122
                return filter.isAssignableFrom (item.getType ());
123
            }
124
            default: throw new IllegalStateException ("Type: " + type);
125
        }
126
    }
127
128
    /** Filters collection accroding to set of given filters.
129
     */
130
    static java.util.Collection filter (Class[] arr, java.util.Collection c, int type) {
131
        java.util.Collection ret = null;
132
133
        TWICE: for (;;) {
134
            Iterator it = c.iterator ();
135
            BIG: while (it.hasNext ()) {
136
                Object res = it.next ();
137
                for (int i = 0; i < arr.length; i++) {
138
                    if (acceptFilter (arr[i], res, type)) {
139
                        if (ret == null) {
140
                            // we need to restart the scanning again 
141
                            // as there is an active filter
142
                            if (type == 1) {
143
                                ret = new java.util.HashSet ();
144
                            } else {
145
                                ret = new ArrayList (c.size ());
146
                            }
147
                            continue TWICE;
148
                        }
149
                        continue BIG;
150
                    }
151
                }
152
                if (ret != null) {
153
                    // if we are running the second round from TWICE
154
                    ret.add (res);
155
                }
156
            }
157
            // ok, processed
158
            break TWICE;
159
        }
160
161
        return ret != null ? ret : c;
162
    }
163
        
164
    
165
    /** Delegating result that filters unwanted items and instances.
166
     */
167
    private final class R extends WaitableResult implements LookupListener {
168
        private Result result;
169
        private Object listeners;
170
        
171
        R (Result delegate) {
172
            this.result = delegate;
173
        }
174
        
175
        protected void beforeLookup (Template t) {
176
            if (result instanceof WaitableResult) {
177
                ((WaitableResult)result).beforeLookup (t);
178
            }
179
        }
180
        
181
        public void addLookupListener (LookupListener l) {
182
            boolean add;
183
            synchronized (this) {
184
                listeners = AbstractLookup.modifyListenerList (true, l, listeners);
185
                add = listeners != null;
186
            }
187
            if (add) {
188
                result.addLookupListener (this);
189
            }
190
        }    
191
        
192
        public void removeLookupListener (LookupListener l) {
193
            boolean remove;
194
            synchronized (this) {
195
                listeners = AbstractLookup.modifyListenerList (false, l, listeners);
196
                remove = listeners == null;
197
            }
198
            if (remove) {
199
                result.removeLookupListener (this);
200
            }
201
        }    
202
        
203
        public java.util.Collection allInstances() {
204
            return filter (classes (), result.allInstances (), 0);
205
        }
206
        
207
        public Set allClasses () {
208
            return (Set)filter (classes (), result.allClasses (), 1);
209
        }
210
        
211
        public Collection allItems () {
212
            return filter (classes (), result.allItems (), 2);
213
        }
214
215
        public void resultChanged (org.openide.util.LookupEvent ev) {
216
            if (ev.getSource () == result) {
217
                LookupListener[] arr;
218
                synchronized (this) {
219
                    if (listeners == null) return;
220
221
                    if (listeners instanceof LookupListener) {
222
                        arr = new LookupListener[] { (LookupListener) listeners };
223
                    } else {
224
                        ArrayList l = (ArrayList)listeners;
225
                        arr = (LookupListener[])l.toArray (
226
                            new LookupListener[l.size ()]
227
                        );
228
                    }
229
                }
230
231
                final LookupListener[] ll = arr;
232
                final org.openide.util.LookupEvent newev = new org.openide.util.LookupEvent (this);
233
                for (int i = 0; i < ll.length; i++) {
234
                    ll[i].resultChanged(newev);
235
                }
236
            }
237
        }
238
    }
239
}
(-)src/org/openide/util/lookup/Lookups.java (-1 / +21 lines)
Lines 7-13 Link Here
7
 * http://www.sun.com/
7
 * http://www.sun.com/
8
 *
8
 *
9
 * The Original Code is NetBeans. The Initial Developer of the Original
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2003 Sun
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2005 Sun
11
 * Microsystems, Inc. All Rights Reserved.
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
12
 */
13
13
Lines 128-133 Link Here
128
     */
128
     */
129
     public static Lookup metaInfServices(ClassLoader classLoader) {
129
     public static Lookup metaInfServices(ClassLoader classLoader) {
130
        return new MetaInfServicesLookup(classLoader);
130
        return new MetaInfServicesLookup(classLoader);
131
     }
132
     
133
     /** Creates a lookup that wraps another one and filters out all instances
134
      * of classe specified as second argument. If you have a lookup and 
135
      * wnat to remove all instances of ActionMap you can use:
136
      * <pre>
137
      * Lookups.exclude (lookup, new Class[] { ActionMap.class });
138
      * </pre>
139
      * To create empty lookup (well, just an example, otherwise use {@link Lookup#EMPTY}) one could use:
140
      * <pre>
141
      * Lookup.exclude (anyLookup, new Class[] { Object.class });
142
      * </pre>
143
      * as any instance in any lookup is of type Object and thus would be excluded.
144
      *
145
      * @param lookup the original lookup that should be filtered
146
      * @param classes array of classes those instances should be excluded
147
      * @since JST-PENDING
148
      */
149
     public static Lookup exclude (Lookup lookup, Class[] classes) {
150
         return new ExcludingLookup (lookup, classes);
131
     }
151
     }
132
152
133
    /** Creates <code>Lookup.Item</code> representing the instance passed in.
153
    /** Creates <code>Lookup.Item</code> representing the instance passed in.
(-)test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java (+154 lines)
Added Link Here
1
/*
2
 *                 Sun Public License Notice
3
 * 
4
 * The contents of this file are subject to the Sun Public License
5
 * Version 1.0 (the "License"). You may not use this file except in
6
 * compliance with the License. A copy of the License is available at
7
 * http://www.sun.com/
8
 * 
9
 * The Original Code is NetBeans. The Initial Developer of the Original
10
 * Code is Sun Microsystems, Inc. Portions Copyright 1997-2000 Sun
11
 * Microsystems, Inc. All Rights Reserved.
12
 */
13
14
package org.openide.util.lookup;
15
16
import org.openide.filesystems.*;
17
import org.openide.loaders.*;
18
import org.openide.util.*;
19
20
import java.lang.ref.WeakReference;
21
import java.util.*;
22
import junit.framework.*;
23
import org.netbeans.junit.*;
24
25
/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
26
 */
27
public class ExcludingLookupTest extends AbstractLookupBaseHid
28
implements AbstractLookupBaseHid.Impl {
29
    public ExcludingLookupTest(java.lang.String testName) {
30
        super(testName, null);
31
    }
32
    
33
    public Lookup createLookup (final Lookup lookup) {
34
        return Lookups.exclude (lookup, new Class[0]);
35
    }
36
    
37
    public Lookup createInstancesLookup (InstanceContent ic) {
38
        return new AbstractLookup (ic);
39
    }
40
41
    public void clearCaches () {
42
    }    
43
    
44
    public void testWeCanRemoveInteger () throws Exception {
45
        doBasicFilteringTest (Integer.class, Integer.class, 0);
46
    }
47
    
48
    public void testWeCanRemoveIntegersEvenByAskingForRemoveOfAllNumbers () throws Exception {
49
        doBasicFilteringTest (Number.class, Integer.class, 0);
50
    }
51
    public void testFunWithInterfaces () throws Exception {
52
        doBasicFilteringTest (java.io.Serializable.class, Integer.class, 0);
53
    }
54
    public void testFunWithInterfaces2 () throws Exception {
55
        doBasicFilteringTest (java.io.Serializable.class, Object.class, 1);
56
    }
57
    
58
    public void testIntegersQueriedThruObject () throws Exception {
59
        doBasicFilteringTest (Number.class, Object.class, 1);
60
    }
61
    
62
    private void doBasicFilteringTest (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
63
        Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
64
        Lookup.Template t = new Lookup.Template (theQuery);
65
        Lookup.Result res = lookup.lookup (t);
66
        
67
        LL ll = new LL ();
68
        res.addLookupListener (ll);
69
        assertEquals ("Nothing is there", 0, res.allItems ().size ());
70
        
71
        Object inst = new Integer (3);
72
        ic.add (inst);
73
        
74
        assertEquals ("Filtered out", null, lookup.lookup (theQuery));
75
        assertEquals ("Filtered out2", null, lookup.lookupItem (t));
76
        assertEquals ("Nothing is there - 2", 0, res.allItems ().size ());
77
        assertEquals ("Nothing is there - 2a", 0, res.allInstances ().size ());
78
        assertEquals ("Nothing is there - 2b", 0, res.allClasses ().size ());
79
        assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
80
        
81
        ic.remove (inst);
82
        assertEquals ("Filtered out3", null, lookup.lookupItem (t));
83
        assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
84
        assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
85
        assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
86
        assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
87
        assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
88
        
89
    }
90
    
91
    public void testSizeOfTheLookup () throws Exception {
92
        Class exclude = String.class;
93
        
94
        Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { exclude });
95
96
        assertSize ("Should be pretty lightweight", Collections.singleton (lookup), 16, 
97
                new Object[] { this.instanceLookup, exclude });
98
    }
99
    public void testSizeOfTheLookupForMultipleFiltersIsHigher () throws Exception {
100
        Class exclude = String.class;
101
        Class exclude2 = Integer.class;
102
        Class[] arr = new Class[] { exclude, exclude2 };
103
        
104
        Lookup lookup = Lookups.exclude (this.instanceLookup, arr);
105
106
        assertSize ("Is fatter", Collections.singleton (lookup), 40, 
107
                new Object[] { this.instanceLookup, exclude, exclude2 });
108
        assertSize ("But only due to the array", Collections.singleton (lookup), 16, 
109
                new Object[] { this.instanceLookup, exclude, exclude2, arr });
110
    }
111
    
112
    public void testFilteringOfSomething () throws Exception {
113
        doFilteringOfSomething (Runnable.class, java.io.Serializable.class, 1);
114
    }
115
    
116
    private void doFilteringOfSomething (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
117
        Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
118
        Lookup.Template t = new Lookup.Template (theQuery);
119
        Lookup.Result res = lookup.lookup (t);
120
        
121
        LL ll = new LL ();
122
        res.addLookupListener (ll);
123
        assertEquals ("Nothing is there", 0, res.allItems ().size ());
124
        
125
        Object inst = new Integer (3);
126
        ic.add (inst);
127
        
128
        assertEquals ("Accepted", inst, lookup.lookup (theQuery));
129
        assertNotNull ("Accepted too", lookup.lookupItem (t));
130
        assertEquals ("One is there - 2", 1, res.allItems ().size ());
131
        assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
132
        assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
133
        assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
134
135
        Object inst2 = new Thread (); // implements Runnable
136
        ic.add (inst2);
137
        assertEquals ("Accepted - 2", inst, lookup.lookup (theQuery));
138
        assertNotNull ("Accepted too -2", lookup.lookupItem (t));
139
        assertEquals ("One is there - 3", 1, res.allItems ().size ());
140
        assertEquals ("One is there - 3a", 1, res.allInstances ().size ());
141
        assertEquals ("One is there - 3b", 1, res.allClasses ().size ());
142
        assertEquals ("Right # of events", 0, ll.getCount ());
143
        
144
        
145
        ic.remove (inst);
146
        assertEquals ("Filtered out3", null, lookup.lookupItem (t));
147
        assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
148
        assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
149
        assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
150
        assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
151
        assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
152
    }
153
    
154
}

Return to bug 53058