KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > openide > util > Lookup


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
20 package org.openide.util;
21
22 import java.util.Collection JavaDoc;
23 import java.util.Collections JavaDoc;
24 import java.util.Iterator JavaDoc;
25 import java.util.Set JavaDoc;
26 import org.openide.util.lookup.Lookups;
27 import org.openide.util.lookup.ProxyLookup;
28
29 /**
30  * A general registry permitting clients to find instances of services
31  * (implementation of a given interface).
32  * This class is inspired by the
33  * <a HREF="http://www.jini.org/">Jini</a>
34  * registration and lookup mechanism. The difference is that the methods do
35  * not throw checked exceptions (as they usually work only locally and not over the network)
36  * and that the Lookup API concentrates on the lookup, not on the registration
37  * (although {@link Lookup#getDefault} is strongly encouraged to support
38  * {@link Lookups#metaInfServices} for registration in addition to whatever
39  * else it decides to support).
40  * <p>
41  * For a general talk about the idea behind the lookup pattern please see
42  * <UL>
43  * <LI><a HREF="lookup/doc-files/index.html">The Solution to Communication Between Components</a>
44  * page
45  * <LI>the introduction to the <a HREF="lookup/doc-files/lookup-api.html">lookup API via
46  * use cases</a>
47  * <LI>the examples of <a HREF="lookup/doc-files/lookup-spi.html">how to write your own lookup</a>
48  * </UL>
49  *
50  * @see org.openide.util.lookup.AbstractLookup
51  * @see Lookups
52  * @see LookupListener
53  * @see LookupEvent
54  * @author Jaroslav Tulach
55  */

56 public abstract class Lookup {
57     /** A dummy lookup that never returns any results.
58      */

59     public static final Lookup EMPTY = new Empty();
60
61     /** default instance */
62     private static Lookup defaultLookup;
63
64     /** Empty constructor for use by subclasses. */
65     public Lookup() {
66     }
67
68     /** Static method to obtain the global lookup in the whole system.
69      * The actual returned implementation can be different in different
70      * systems, but the default one is based on
71      * {@link org.openide.util.lookup.Lookups#metaInfServices}
72      * with the context classloader of the first caller. Each system is
73      * adviced to honor this and include some form of <code>metaInfServices</code>
74      * implementation in the returned lookup as usage of <code>META-INF/services</code>
75      * is a JDK standard.
76      *
77      * @return the global lookup in the system
78      */

79     public static synchronized Lookup getDefault() {
80         if (defaultLookup != null) {
81             return defaultLookup;
82         }
83
84         // You can specify a Lookup impl using a system property if you like.
85
String JavaDoc className = System.getProperty("org.openide.util.Lookup" // NOI18N
86
);
87
88         if ("-".equals(className)) { // NOI18N
89

90             // Suppress even MetaInfServicesLookup.
91
return EMPTY;
92         }
93
94         ClassLoader JavaDoc l = Thread.currentThread().getContextClassLoader();
95
96         try {
97             if (className != null) {
98                 defaultLookup = (Lookup) Class.forName(className, true, l).newInstance();
99
100                 return defaultLookup;
101             }
102         } catch (Exception JavaDoc e) {
103             // do not use ErrorManager because we are in the startup code
104
// and ErrorManager might not be ready
105
e.printStackTrace();
106         }
107
108         // OK, none specified (successfully) in a system property.
109
// Try MetaInfServicesLookup as a default, which may also
110
// have a org.openide.util.Lookup line specifying the lookup.
111
Lookup misl = Lookups.metaInfServices(l);
112         defaultLookup = misl.lookup(Lookup.class);
113
114         if (defaultLookup != null) {
115             return defaultLookup;
116         }
117
118         // You may also specify a Lookup.Provider.
119
Lookup.Provider prov = misl.lookup(Lookup.Provider.class);
120
121         if (prov != null) {
122             defaultLookup = Lookups.proxy(prov);
123
124             return defaultLookup;
125         }
126
127         DefLookup def = new DefLookup();
128         def.init(l, misl);
129         return defaultLookup = def;
130     }
131     
132     private static final class DefLookup extends ProxyLookup {
133         public DefLookup() {
134             super(new Lookup[0]);
135         }
136         
137         public void init(ClassLoader JavaDoc loader, Lookup metaInfLookup) {
138             // Had no such line, use simple impl.
139
// It does however need to have ClassLoader available or many things will break.
140
// Use the thread context classloader in effect now.
141
Lookup clLookup = Lookups.singleton(loader);
142             setLookups(new Lookup[] { metaInfLookup, clLookup });
143         }
144     }
145     
146     /** Called from MockServices to reset default lookup in case services change
147      */

148     private static void resetDefaultLookup() {
149         if (defaultLookup instanceof DefLookup) {
150             DefLookup def = (DefLookup)defaultLookup;
151             ClassLoader JavaDoc l = Thread.currentThread().getContextClassLoader();
152             def.init(l, Lookups.metaInfServices(l));
153         }
154     }
155
156     /** Look up an object matching a given interface.
157      * This is the simplest method to use.
158      * If more than one object matches, the first will be returned.
159      * The template class may be a class or interface; the instance is
160      * guaranteed to be assignable to it.
161      *
162      * @param clazz class of the object we are searching for
163      * @return an object implementing the given class or <code>null</code> if no such
164      * implementation is found
165      */

166     public abstract <T> T lookup(Class JavaDoc<T> clazz);
167
168     /** The general lookup method. Callers can get list of all instances and classes
169      * that match the given <code>template</code>, request more info about
170      * them in form of {@link Lookup.Item} and attach a listener to
171      * this be notified about changes. The general interface does not
172      * specify whether subsequent calls with the same template produce new
173      * instance of the {@link Lookup.Result} or return shared instance. The
174      * prefered behaviour however is to return shared one.
175      *
176      * @param template a template describing the services to look for
177      * @return an object containing the results
178      */

179     public abstract <T> Result<T> lookup(Template<T> template);
180
181     /** Look up the first item matching a given template.
182      * Includes not only the instance but other associated information.
183      * @param template the template to check
184      * @return a matching item or <code>null</code>
185      *
186      * @since 1.8
187      */

188     public <T> Item<T> lookupItem(Template<T> template) {
189         Result<T> res = lookup(template);
190         Iterator JavaDoc<? extends Item<T>> it = res.allItems().iterator();
191         return it.hasNext() ? it.next() : null;
192     }
193
194     /**
195      * Find a result corresponding to a given class.
196      * Equivalent to calling {@link #lookup(Lookup.Template)} but slightly more convenient.
197      * Subclasses may override this method to produce the same semantics more efficiently.
198      * @param clazz the supertype of the result
199      * @return a live object representing instances of that type
200      * @since org.openide.util 6.10
201      */

202     public <T> Lookup.Result<T> lookupResult(Class JavaDoc<T> clazz) {
203         return lookup(new Lookup.Template<T>(clazz));
204     }
205
206     /**
207      * Find all instances corresponding to a given class.
208      * Equivalent to calling {@link #lookupResult} and asking for {@link Lookup.Result#allInstances} but slightly more convenient.
209      * Subclasses may override this method to produce the same semantics more efficiently.
210      * @param clazz the supertype of the result
211      * @return all currently available instances of that type
212      * @since org.openide.util 6.10
213      */

214     public <T> Collection JavaDoc<? extends T> lookupAll(Class JavaDoc<T> clazz) {
215         return lookupResult(clazz).allInstances();
216     }
217
218     /**
219      * Objects implementing interface Lookup.Provider are capable of
220      * and willing to provide a lookup (usually bound to the object).
221      * @since 3.6
222      */

223     public interface Provider {
224         /**
225          * Returns lookup associated with the object.
226          * @return fully initialized lookup instance provided by this object
227          */

228         Lookup getLookup();
229     }
230
231     /*
232      * I expect this class to grow in the future, but for now, it is
233      * enough to start with something simple.
234      */

235
236     /** Template defining a pattern to filter instances by.
237      */

238     public static final class Template<T> extends Object JavaDoc {
239         /** cached hash code */
240         private int hashCode;
241
242         /** type of the service */
243         private Class JavaDoc<T> type;
244
245         /** identity to search for */
246         private String JavaDoc id;
247
248         /** instance to search for */
249         private T instance;
250
251         /** General template to find all possible instances.
252          * @deprecated Use <code>new Template (Object.class)</code> which
253          * is going to be better typed with JDK1.5 templates and should produce
254          * the same result.
255          */

256         @Deprecated JavaDoc
257         public Template() {
258             this(null);
259         }
260
261         /** Create a simple template matching by class.
262          * @param type the class of service we are looking for (subclasses will match)
263          */

264         public Template(Class JavaDoc<T> type) {
265             this(type, null, null);
266         }
267
268         /** Constructor to create new template.
269          * @param type the class of service we are looking for or <code>null</code> to leave unspecified
270          * @param id the ID of the item/service we are looking for or <code>null</code> to leave unspecified
271          * @param instance a specific known instance to look for or <code>null</code> to leave unspecified
272          */

273         public Template(Class JavaDoc<T> type, String JavaDoc id, T instance) {
274             this.type = extractType(type);
275             this.id = id;
276             this.instance = instance;
277         }
278
279         @SuppressWarnings JavaDoc("unchecked")
280         private Class JavaDoc<T> extractType(Class JavaDoc<T> type) {
281             return (type == null) ? (Class JavaDoc<T>)Object JavaDoc.class : type;
282         }
283
284         /** Get the class (or superclass or interface) to search for.
285          * If it was not specified in the constructor, <code>Object</code> is used as
286          * this will match any instance.
287          * @return the class to search for
288          */

289         public Class JavaDoc<T> getType() {
290             return type;
291         }
292
293         /** Get the persistent identifier being searched for, if any.
294          * @return the ID or <code>null</code>
295          * @see Lookup.Item#getId
296          *
297          * @since 1.8
298          */

299         public String JavaDoc getId() {
300             return id;
301         }
302
303         /** Get the specific instance being searched for, if any.
304          * Most useful for finding an <code>Item</code> when the instance
305          * is already known.
306          *
307          * @return the object to find or <code>null</code>
308          *
309          * @since 1.8
310          */

311         public T getInstance() {
312             return instance;
313         }
314
315         /* Computes hashcode for this template. The hashcode is cached.
316          * @return hashcode
317          */

318         public int hashCode() {
319             if (hashCode != 0) {
320                 return hashCode;
321             }
322
323             hashCode = ((type == null) ? 1 : type.hashCode()) + ((id == null) ? 2 : id.hashCode()) +
324                 ((instance == null) ? 3 : 0);
325
326             return hashCode;
327         }
328
329         /* Checks whether two templates represent the same query.
330          * @param obj another template to check
331          * @return true if so, false otherwise
332          */

333         public boolean equals(Object JavaDoc obj) {
334             if (!(obj instanceof Template)) {
335                 return false;
336             }
337
338             Template t = (Template) obj;
339
340             if (hashCode() != t.hashCode()) {
341                 // this is an optimalization - the hashCodes should have been
342
// precomputed
343
return false;
344             }
345
346             if (type != t.type) {
347                 return false;
348             }
349
350             if (id == null) {
351                 if (t.id != null) {
352                     return false;
353                 }
354             } else {
355                 if (!id.equals(t.id)) {
356                     return false;
357                 }
358             }
359
360             if (instance == null) {
361                 return (t.instance == null);
362             } else {
363                 return instance.equals(t.instance);
364             }
365         }
366
367         /* for debugging */
368         public String JavaDoc toString() {
369             return "Lookup.Template[type=" + type + ",id=" + id + ",instance=" + instance + "]"; // NOI18N
370
}
371     }
372
373     /** Result of a lookup request.
374      * Allows access to all matching instances at once.
375      * Also permits listening to changes in the result.
376      * Result can contain duplicate items.
377      */

378     public static abstract class Result<T> extends Object JavaDoc {
379         /** Registers a listener that is invoked when there is a possible
380          * change in this result.
381          *
382          * @param l the listener to add
383          */

384         public abstract void addLookupListener(LookupListener l);
385
386         /** Unregisters a listener previously added.
387          * @param l the listener to remove
388          */

389         public abstract void removeLookupListener(LookupListener l);
390
391         /** Get all instances in the result. The return value type
392          * should be List instead of Collection, but it is too late to change it.
393          * @return unmodifiable collection of all instances that will never change its content
394          */

395         public abstract Collection JavaDoc<? extends T> allInstances();
396
397         /** Get all classes represented in the result.
398          * That is, the set of concrete classes
399          * used by instances present in the result.
400          * All duplicate classes will be omitted.
401          * @return unmodifiable set of <code>Class</code> objects that will never change its content
402          *
403          * @since 1.8
404          */

405         public Set JavaDoc<Class JavaDoc<? extends T>> allClasses() {
406             return Collections.emptySet();
407         }
408
409         /** Get all registered items.
410          * This should include all pairs of instances together
411          * with their classes, IDs, and so on. The return value type
412          * should be List instead of Collection, but it is too late to change it.
413          * @return unmodifiable collection of {@link Lookup.Item} that will never change its content
414          *
415          * @since 1.8
416          */

417         public Collection JavaDoc<? extends Item<T>> allItems() {
418             return Collections.emptyList();
419         }
420     }
421
422     /** A single item in a lookup result.
423      * This wrapper provides unified access to not just the instance,
424      * but its class, a possible persistent identifier, and so on.
425      *
426      * @since 1.25
427      */

428     public static abstract class Item<T> extends Object JavaDoc {
429         /** Get the instance itself.
430          * @return the instance or null if the instance cannot be created
431          */

432         public abstract T getInstance();
433
434         /** Get the implementing class of the instance.
435          * @return the class of the item
436          */

437         public abstract Class JavaDoc<? extends T> getType();
438
439         // XXX can it be null??
440

441         /** Get a persistent indentifier for the item.
442          * This identifier should uniquely represent the item
443          * within its containing lookup (and if possible within the
444          * global lookup as a whole). For example, it might represent
445          * the source of the instance as a file name. The ID may be
446          * persisted and in a later session used to find the same instance
447          * as was encountered earlier, by means of passing it into a
448          * lookup template.
449          *
450          * @return a string ID of the item
451          */

452         public abstract String JavaDoc getId();
453
454         /** Get a human presentable name for the item.
455          * This might be used when summarizing all the items found in a
456          * lookup result in some part of a GUI.
457          * @return the string suitable for presenting the object to a user
458          */

459         public abstract String JavaDoc getDisplayName();
460
461         /* show ID for debugging */
462         public String JavaDoc toString() {
463             return getId();
464         }
465     }
466
467     //
468
// Implementation of the default lookup
469
//
470
private static final class Empty extends Lookup {
471         private static final Result NO_RESULT = new Result() {
472                 public void addLookupListener(LookupListener l) {
473                 }
474
475                 public void removeLookupListener(LookupListener l) {
476                 }
477
478                 public Collection JavaDoc allInstances() {
479                     return Collections.EMPTY_SET;
480                 }
481             };
482
483         Empty() {
484         }
485
486         public <T> T lookup(Class JavaDoc<T> clazz) {
487             return null;
488         }
489
490         @SuppressWarnings JavaDoc("unchecked")
491         public <T> Result<T> lookup(Template<T> template) {
492             return NO_RESULT;
493         }
494     }
495 }
496
Popular Tags