KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > lookup > ExcludingLookup


1 /*
2  * The contents of this file are subject to the terms of the Common Development
3  * and Distribution License (the License). You may not use this file except in
4  * compliance with the License.
5  *
6  * You can obtain a copy of the License at http://www.netbeans.org/cddl.html
7  * or http://www.netbeans.org/cddl.txt.
8  *
9  * When distributing Covered Code, include this CDDL Header Notice in each file
10  * and include the License file at http://www.netbeans.org/cddl.txt.
11  * If applicable, add the following below the CDDL Header, with the fields
12  * enclosed by brackets [] replaced by your own identifying information:
13  * "Portions Copyrighted [year] [name of copyright owner]"
14  *
15  * The Original Software is NetBeans. The Initial Developer of the Original
16  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17  * Microsystems, Inc. All Rights Reserved.
18  */

19 package org.openide.util.lookup;
20
21 import org.openide.util.Lookup;
22 import org.openide.util.LookupListener;
23
24 import java.util.*;
25
26
27 /** Allows exclusion of certain instances from lookup.
28  *
29  * @author Jaroslav Tulach
30  */

31 final class ExcludingLookup extends org.openide.util.Lookup {
32     /** the other lookup that we delegate to */
33     private Lookup delegate;
34
35     /** classes to exclude (Class[]) or just one class (Class) */
36     private Object JavaDoc classes;
37
38     /**
39      * Creates new Result object with supplied instances parameter.
40      * @param instances to be used to return from the lookup
41      */

42     ExcludingLookup(Lookup delegate, Class JavaDoc[] classes) {
43         this.delegate = delegate;
44
45         if (classes.length == 1) {
46             this.classes = classes[0];
47         } else {
48             this.classes = classes;
49         }
50     }
51
52     public String JavaDoc toString() {
53         return "ExcludingLookup: " + delegate + " excludes: " + Arrays.asList(classes()); // NOI18N
54
}
55
56     public <T> Result<T> lookup(Template<T> template) {
57         if (template == null) {
58             throw new NullPointerException JavaDoc();
59         }
60
61         if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
62             // empty result
63
return Lookup.EMPTY.lookup(template);
64         }
65
66         return new R<T>(template.getType(), delegate.lookup(template));
67     }
68
69     public <T> T lookup(Class JavaDoc<T> clazz) {
70         if (areSubclassesOfThisClassAlwaysExcluded(clazz)) {
71             return null;
72         }
73
74         T res = delegate.lookup(clazz);
75
76         if (isObjectAccessible(clazz, res, 0)) {
77             return res;
78         } else {
79             return null;
80         }
81     }
82
83     public <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
84         if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
85             return null;
86         }
87
88         Lookup.Item<T> retValue = delegate.lookupItem(template);
89
90         if (isObjectAccessible(template.getType(), retValue, 2)) {
91             return retValue;
92         } else {
93             return null;
94         }
95     }
96
97     /** @return true if the instance of class c shall never be returned from this lookup
98      */

99     private boolean areSubclassesOfThisClassAlwaysExcluded(Class JavaDoc<?> c) {
100         Class JavaDoc<?>[] arr = classes();
101
102         for (int i = 0; i < arr.length; i++) {
103             if (arr[i].isAssignableFrom(c)) {
104                 return true;
105             }
106         }
107
108         return false;
109     }
110
111     /** Returns the array of classes this lookup filters.
112      */

113     final Class JavaDoc<?>[] classes() {
114         if (classes instanceof Class JavaDoc[]) {
115             return (Class JavaDoc[]) classes;
116         } else {
117             return new Class JavaDoc[] { (Class JavaDoc) classes };
118         }
119     }
120
121     /** Does a check whether two classes are accessible (in the super/sub class)
122      * releation ship without walking thru any of the classes mentioned in the
123      * barrier.
124      */

125     private static boolean isAccessible(Class JavaDoc<?>[] barriers, Class JavaDoc<?> from, Class JavaDoc<?> to) {
126         if ((to == null) || !from.isAssignableFrom(to)) {
127             // no way to reach each other by walking up
128
return false;
129         }
130
131         for (int i = 0; i < barriers.length; i++) {
132             if (to == barriers[i]) {
133                 return false;
134             }
135         }
136
137         if (from == to) {
138             return true;
139         }
140
141         //
142
// depth first search
143
//
144
if (isAccessible(barriers, from, to.getSuperclass())) {
145             return true;
146         }
147
148         Class JavaDoc[] interfaces = to.getInterfaces();
149
150         for (int i = 0; i < interfaces.length; i++) {
151             if (isAccessible(barriers, from, interfaces[i])) {
152                 return true;
153             }
154         }
155
156         return false;
157     }
158
159     /** based on type decides whether the class accepts or not anObject
160      * @param from the base type of the query
161      * @param to depending on value of type either Object, Class or Item
162      * @param type 0,1,2 for Object, Class or Item
163      * @return true if we can access the to from from by walking around the bariers
164      */

165     private final boolean isObjectAccessible(Class JavaDoc from, Object JavaDoc to, int type) {
166         if (to == null) {
167             return false;
168         }
169
170         return isObjectAccessible(classes(), from, to, type);
171     }
172
173     /** based on type decides whether the class accepts or not anObject
174      * @param barriers classes to avoid when testing reachability
175      * @param from the base type of the query
176      * @param to depending on value of type either Object, Class or Item
177      * @param type 0,1,2 for Object, Class or Item
178      * @return true if we can access the to from from by walking around the bariers
179      */

180     static final boolean isObjectAccessible(Class JavaDoc[] barriers, Class JavaDoc from, Object JavaDoc to, int type) {
181         if (to == null) {
182             return false;
183         }
184
185         switch (type) {
186         case 0:
187             return isAccessible(barriers, from, to.getClass());
188
189         case 1:
190             return isAccessible(barriers, from, (Class JavaDoc) to);
191
192         case 2: {
193             Item item = (Item) to;
194
195             return isAccessible(barriers, from, item.getType());
196         }
197
198         default:
199             throw new IllegalStateException JavaDoc("Type: " + type);
200         }
201     }
202
203     /** Filters collection accroding to set of given filters.
204      */

205     final <E, T extends Collection<E>> T filter(
206         Class JavaDoc<?>[] arr, Class JavaDoc<?> from, T c, int type, T prototype
207     ) {
208         T ret = null;
209
210
211 // optimistic strategy expecting we will not need to filter
212
TWICE:
213         for (;;) {
214             Iterator<E> it = c.iterator();
215 BIG:
216             while (it.hasNext()) {
217                 E res = it.next();
218
219                 if (!isObjectAccessible(arr, from, res, type)) {
220                     if (ret == null) {
221                         // we need to restart the scanning again
222
// as there is an active filter
223
ret = prototype;
224                         continue TWICE;
225                     }
226
227                     continue BIG;
228                 }
229
230                 if (ret != null) {
231                     // if we are running the second round from TWICE
232
ret.add(res);
233                 }
234             }
235
236             // ok, processed
237
break TWICE;
238         }
239
240         return (ret != null) ? ret : c;
241     }
242
243     /** Delegating result that filters unwanted items and instances.
244      */

245     private final class R<T> extends WaitableResult<T> implements LookupListener {
246         private Result<T> result;
247         private Object JavaDoc listeners;
248         private Class JavaDoc<?> from;
249
250         R(Class JavaDoc<?> from, Result<T> delegate) {
251             this.from = from;
252             this.result = delegate;
253         }
254
255         protected void beforeLookup(Template t) {
256             if (result instanceof WaitableResult) {
257                 ((WaitableResult) result).beforeLookup(t);
258             }
259         }
260
261         public void addLookupListener(LookupListener l) {
262             boolean add;
263
264             synchronized (this) {
265                 listeners = AbstractLookup.modifyListenerList(true, l, listeners);
266                 add = listeners != null;
267             }
268
269             if (add) {
270                 result.addLookupListener(this);
271             }
272         }
273
274         public void removeLookupListener(LookupListener l) {
275             boolean remove;
276
277             synchronized (this) {
278                 listeners = AbstractLookup.modifyListenerList(false, l, listeners);
279                 remove = listeners == null;
280             }
281
282             if (remove) {
283                 result.removeLookupListener(this);
284             }
285         }
286
287         public Collection<? extends T> allInstances() {
288             return openCol(result.allInstances(), 0);
289         }
290
291         private <S> Collection<S> openCol(Collection<S> c, int type) {
292             return filter(classes(), from, c, type, new ArrayList<S>(c.size()));
293         }
294
295         public Set<Class JavaDoc<? extends T>> allClasses() {
296             return filter(classes(), from, result.allClasses(), 1, new HashSet<Class JavaDoc<? extends T>>());
297         }
298
299         public Collection<? extends Item<T>> allItems() {
300             return openCol(result.allItems(), 2);
301         }
302
303         public void resultChanged(org.openide.util.LookupEvent ev) {
304             if (ev.getSource() == result) {
305                 collectFires(null);
306             }
307         }
308
309         protected void collectFires(Collection<Object JavaDoc> evAndListeners) {
310             LookupListener[] arr;
311
312             synchronized (this) {
313                 if (listeners == null) {
314                     return;
315                 }
316
317                 if (listeners instanceof LookupListener) {
318                     arr = new LookupListener[] { (LookupListener) listeners };
319                 } else {
320                     ArrayList<?> l = (ArrayList<?>) listeners;
321                     arr = l.toArray(new LookupListener[l.size()]);
322                 }
323             }
324
325             final LookupListener[] ll = arr;
326             final org.openide.util.LookupEvent newev = new org.openide.util.LookupEvent(this);
327             AbstractLookup.notifyListeners(ll, newev, evAndListeners);
328         }
329     }
330 }
331
Popular Tags