1.1 --- a/lookup/src/main/java/org/openide/util/Lookup.java Wed Jan 27 17:46:23 2010 -0500
1.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
1.3 @@ -1,544 +0,0 @@
1.4 -/*
1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
1.6 - *
1.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
1.8 - *
1.9 - * The contents of this file are subject to the terms of either the GNU
1.10 - * General Public License Version 2 only ("GPL") or the Common
1.11 - * Development and Distribution License("CDDL") (collectively, the
1.12 - * "License"). You may not use this file except in compliance with the
1.13 - * License. You can obtain a copy of the License at
1.14 - * http://www.netbeans.org/cddl-gplv2.html
1.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
1.16 - * specific language governing permissions and limitations under the
1.17 - * License. When distributing the software, include this License Header
1.18 - * Notice in each file and include the License file at
1.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
1.20 - * particular file as subject to the "Classpath" exception as provided
1.21 - * by Sun in the GPL Version 2 section of the License file that
1.22 - * accompanied this code. If applicable, add the following below the
1.23 - * License Header, with the fields enclosed by brackets [] replaced by
1.24 - * your own identifying information:
1.25 - * "Portions Copyrighted [year] [name of copyright owner]"
1.26 - *
1.27 - * Contributor(s):
1.28 - *
1.29 - * The Original Software is NetBeans. The Initial Developer of the Original
1.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
1.31 - * Microsystems, Inc. All Rights Reserved.
1.32 - *
1.33 - * If you wish your version of this file to be governed by only the CDDL
1.34 - * or only the GPL Version 2, indicate your decision by adding
1.35 - * "[Contributor] elects to include this software in this distribution
1.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
1.37 - * single choice of license, a recipient has the option to distribute
1.38 - * your version of this file under either the CDDL, the GPL Version 2 or
1.39 - * to extend the choice of license to its licensees as provided above.
1.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
1.41 - * Version 2 license, then the option applies only if the new code is
1.42 - * made subject to such option by the copyright holder.
1.43 - */
1.44 -
1.45 -package org.openide.util;
1.46 -
1.47 -import java.util.ArrayList;
1.48 -import java.util.Collection;
1.49 -import java.util.Collections;
1.50 -import java.util.Iterator;
1.51 -import java.util.List;
1.52 -import java.util.Set;
1.53 -import org.openide.util.lookup.Lookups;
1.54 -import org.openide.util.lookup.ProxyLookup;
1.55 -import org.openide.util.lookup.ServiceProvider;
1.56 -
1.57 -/**
1.58 - * A general registry permitting clients to find instances of services
1.59 - * (implementation of a given interface).
1.60 - * This class is inspired by the
1.61 - * <a href="http://www.jini.org/">Jini</a>
1.62 - * registration and lookup mechanism. The difference is that the methods do
1.63 - * not throw checked exceptions (as they usually work only locally and not over the network)
1.64 - * and that the Lookup API concentrates on the lookup, not on the registration
1.65 - * (although {@link Lookup#getDefault} is strongly encouraged to support
1.66 - * {@link Lookups#metaInfServices} for registration in addition to whatever
1.67 - * else it decides to support).
1.68 - * <p>
1.69 - * For a general talk about the idea behind the lookup pattern please see
1.70 - * <UL>
1.71 - * <LI><a href="lookup/doc-files/index.html">The Solution to Communication Between Components</a>
1.72 - * page
1.73 - * <LI>the introduction to the <a href="lookup/doc-files/lookup-api.html">lookup API via
1.74 - * use cases</a>
1.75 - * <LI>the examples of <a href="lookup/doc-files/lookup-spi.html">how to write your own lookup</a>
1.76 - * </UL>
1.77 - *
1.78 - * @see org.openide.util.lookup.AbstractLookup
1.79 - * @see Lookups
1.80 - * @see LookupListener
1.81 - * @see LookupEvent
1.82 - * @author Jaroslav Tulach
1.83 - */
1.84 -public abstract class Lookup {
1.85 - /** A dummy lookup that never returns any results.
1.86 - */
1.87 - public static final Lookup EMPTY = new Empty();
1.88 -
1.89 - /** default instance */
1.90 - private static Lookup defaultLookup;
1.91 -
1.92 - /** Empty constructor for use by subclasses. */
1.93 - public Lookup() {
1.94 - }
1.95 -
1.96 - /** Static method to obtain the global lookup in the whole system.
1.97 - * The actual returned implementation can be different in different
1.98 - * systems, but the default one is based on
1.99 - * {@link org.openide.util.lookup.Lookups#metaInfServices}
1.100 - * with the context classloader of the first caller. Each system is
1.101 - * adviced to honor this and include some form of <code>metaInfServices</code>
1.102 - * implementation in the returned lookup as usage of <code>META-INF/services</code>
1.103 - * is a JDK standard.
1.104 - *
1.105 - * @return the global lookup in the system
1.106 - * @see ServiceProvider
1.107 - */
1.108 - public static synchronized Lookup getDefault() {
1.109 - if (defaultLookup != null) {
1.110 - return defaultLookup;
1.111 - }
1.112 -
1.113 - // You can specify a Lookup impl using a system property if you like.
1.114 - String className = System.getProperty("org.openide.util.Lookup" // NOI18N
1.115 - );
1.116 -
1.117 - if ("-".equals(className)) { // NOI18N
1.118 -
1.119 - // Suppress even MetaInfServicesLookup.
1.120 - return EMPTY;
1.121 - }
1.122 -
1.123 - ClassLoader l = Thread.currentThread().getContextClassLoader();
1.124 -
1.125 - try {
1.126 - if (className != null) {
1.127 - defaultLookup = (Lookup) Class.forName(className, true, l).newInstance();
1.128 -
1.129 - return defaultLookup;
1.130 - }
1.131 - } catch (Exception e) {
1.132 - // do not use ErrorManager because we are in the startup code
1.133 - // and ErrorManager might not be ready
1.134 - e.printStackTrace();
1.135 - }
1.136 -
1.137 - // OK, none specified (successfully) in a system property.
1.138 - // Try MetaInfServicesLookup as a default, which may also
1.139 - // have a org.openide.util.Lookup line specifying the lookup.
1.140 - Lookup misl = Lookups.metaInfServices(l);
1.141 - defaultLookup = misl.lookup(Lookup.class);
1.142 -
1.143 - if (defaultLookup != null) {
1.144 - return defaultLookup;
1.145 - }
1.146 -
1.147 - // You may also specify a Lookup.Provider.
1.148 - Lookup.Provider prov = misl.lookup(Lookup.Provider.class);
1.149 -
1.150 - if (prov != null) {
1.151 - defaultLookup = Lookups.proxy(prov);
1.152 -
1.153 - return defaultLookup;
1.154 - }
1.155 -
1.156 - DefLookup def = new DefLookup();
1.157 - def.init(l, misl, false);
1.158 - defaultLookup = def;
1.159 - def.init(l, misl, true);
1.160 - return defaultLookup;
1.161 - }
1.162 -
1.163 - private static final class DefLookup extends ProxyLookup {
1.164 - public DefLookup() {
1.165 - super(new Lookup[0]);
1.166 - }
1.167 -
1.168 - public void init(ClassLoader loader, Lookup metaInfLookup, boolean addPath) {
1.169 - // Had no such line, use simple impl.
1.170 - // It does however need to have ClassLoader available or many things will break.
1.171 - // Use the thread context classloader in effect now.
1.172 - Lookup clLookup = Lookups.singleton(loader);
1.173 - List<Lookup> arr = new ArrayList<Lookup>();
1.174 - arr.add(metaInfLookup);
1.175 - arr.add(clLookup);
1.176 - String paths = System.getProperty("org.openide.util.Lookup.paths"); // NOI18N
1.177 - if (addPath && paths != null) {
1.178 - for (String p : paths.split(":")) { // NOI18N
1.179 - arr.add(Lookups.forPath(p));
1.180 - }
1.181 - }
1.182 - setLookups(arr.toArray(new Lookup[0]));
1.183 - }
1.184 - }
1.185 -
1.186 - /** Called from MockServices to reset default lookup in case services change
1.187 - */
1.188 - private static void resetDefaultLookup() {
1.189 - if (defaultLookup instanceof DefLookup) {
1.190 - DefLookup def = (DefLookup)defaultLookup;
1.191 - ClassLoader l = Thread.currentThread().getContextClassLoader();
1.192 - def.init(l, Lookups.metaInfServices(l), true);
1.193 - }
1.194 - }
1.195 -
1.196 - /** Look up an object matching a given interface.
1.197 - * This is the simplest method to use.
1.198 - * If more than one object matches, the first will be returned.
1.199 - * The template class may be a class or interface; the instance is
1.200 - * guaranteed to be assignable to it.
1.201 - *
1.202 - * @param clazz class of the object we are searching for
1.203 - * @return an object implementing the given class or <code>null</code> if no such
1.204 - * implementation is found
1.205 - */
1.206 - public abstract <T> T lookup(Class<T> clazz);
1.207 -
1.208 - /** The general lookup method. Callers can get list of all instances and classes
1.209 - * that match the given <code>template</code>, request more info about
1.210 - * them in form of {@link Lookup.Item} and attach a listener to
1.211 - * this be notified about changes. The general interface does not
1.212 - * specify whether subsequent calls with the same template produce new
1.213 - * instance of the {@link Lookup.Result} or return shared instance. The
1.214 - * prefered behaviour however is to return shared one.
1.215 - *
1.216 - * @param template a template describing the services to look for
1.217 - * @return an object containing the results
1.218 - */
1.219 - public abstract <T> Result<T> lookup(Template<T> template);
1.220 -
1.221 - /** Look up the first item matching a given template.
1.222 - * Includes not only the instance but other associated information.
1.223 - * @param template the template to check
1.224 - * @return a matching item or <code>null</code>
1.225 - *
1.226 - * @since 1.8
1.227 - */
1.228 - public <T> Item<T> lookupItem(Template<T> template) {
1.229 - Result<T> res = lookup(template);
1.230 - Iterator<? extends Item<T>> it = res.allItems().iterator();
1.231 - return it.hasNext() ? it.next() : null;
1.232 - }
1.233 -
1.234 - /**
1.235 - * Find a result corresponding to a given class.
1.236 - * Equivalent to calling {@link #lookup(Lookup.Template)} but slightly more convenient.
1.237 - * Subclasses may override this method to produce the same semantics more efficiently.
1.238 - * @param clazz the supertype of the result
1.239 - * @return a live object representing instances of that type
1.240 - * @since org.openide.util 6.10
1.241 - */
1.242 - public <T> Lookup.Result<T> lookupResult(Class<T> clazz) {
1.243 - return lookup(new Lookup.Template<T>(clazz));
1.244 - }
1.245 -
1.246 - /**
1.247 - * Find all instances corresponding to a given class.
1.248 - * Equivalent to calling {@link #lookupResult} and asking for {@link Lookup.Result#allInstances} but slightly more convenient.
1.249 - * Subclasses may override this method to produce the same semantics more efficiently.
1.250 - * <div class="nonnormative">
1.251 - * <p>Example usage:</p>
1.252 - * <pre>
1.253 - * for (MyService svc : Lookup.getDefault().lookupAll(MyService.class)) {
1.254 - * svc.useMe();
1.255 - * }
1.256 - * </pre>
1.257 - * </div>
1.258 - * @param clazz the supertype of the result
1.259 - * @return all currently available instances of that type
1.260 - * @since org.openide.util 6.10
1.261 - */
1.262 - public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
1.263 - return lookupResult(clazz).allInstances();
1.264 - }
1.265 -
1.266 - /**
1.267 - * Objects implementing interface Lookup.Provider are capable of
1.268 - * and willing to provide a lookup (usually bound to the object).
1.269 - * @since 3.6
1.270 - */
1.271 - public interface Provider {
1.272 - /**
1.273 - * Returns lookup associated with the object.
1.274 - * @return fully initialized lookup instance provided by this object
1.275 - */
1.276 - Lookup getLookup();
1.277 - }
1.278 -
1.279 - /*
1.280 - * I expect this class to grow in the future, but for now, it is
1.281 - * enough to start with something simple.
1.282 - */
1.283 -
1.284 - /** Template defining a pattern to filter instances by.
1.285 - */
1.286 - public static final class Template<T> extends Object {
1.287 - /** cached hash code */
1.288 - private int hashCode;
1.289 -
1.290 - /** type of the service */
1.291 - private Class<T> type;
1.292 -
1.293 - /** identity to search for */
1.294 - private String id;
1.295 -
1.296 - /** instance to search for */
1.297 - private T instance;
1.298 -
1.299 - /** General template to find all possible instances.
1.300 - * @deprecated Use <code>new Template (Object.class)</code> which
1.301 - * is going to be better typed with JDK1.5 templates and should produce
1.302 - * the same result.
1.303 - */
1.304 - @Deprecated
1.305 - public Template() {
1.306 - this(null);
1.307 - }
1.308 -
1.309 - /** Create a simple template matching by class.
1.310 - * @param type the class of service we are looking for (subclasses will match)
1.311 - */
1.312 - public Template(Class<T> type) {
1.313 - this(type, null, null);
1.314 - }
1.315 -
1.316 - /** Constructor to create new template.
1.317 - * @param type the class of service we are looking for or <code>null</code> to leave unspecified
1.318 - * @param id the ID of the item/service we are looking for or <code>null</code> to leave unspecified
1.319 - * @param instance a specific known instance to look for or <code>null</code> to leave unspecified
1.320 - */
1.321 - public Template(Class<T> type, String id, T instance) {
1.322 - this.type = extractType(type);
1.323 - this.id = id;
1.324 - this.instance = instance;
1.325 - }
1.326 -
1.327 - @SuppressWarnings("unchecked")
1.328 - private Class<T> extractType(Class<T> type) {
1.329 - return (type == null) ? (Class<T>)Object.class : type;
1.330 - }
1.331 -
1.332 - /** Get the class (or superclass or interface) to search for.
1.333 - * If it was not specified in the constructor, <code>Object</code> is used as
1.334 - * this will match any instance.
1.335 - * @return the class to search for
1.336 - */
1.337 - public Class<T> getType() {
1.338 - return type;
1.339 - }
1.340 -
1.341 - /** Get the persistent identifier being searched for, if any.
1.342 - * @return the ID or <code>null</code>
1.343 - * @see Lookup.Item#getId
1.344 - *
1.345 - * @since 1.8
1.346 - */
1.347 - public String getId() {
1.348 - return id;
1.349 - }
1.350 -
1.351 - /** Get the specific instance being searched for, if any.
1.352 - * Most useful for finding an <code>Item</code> when the instance
1.353 - * is already known.
1.354 - *
1.355 - * @return the object to find or <code>null</code>
1.356 - *
1.357 - * @since 1.8
1.358 - */
1.359 - public T getInstance() {
1.360 - return instance;
1.361 - }
1.362 -
1.363 - /* Computes hashcode for this template. The hashcode is cached.
1.364 - * @return hashcode
1.365 - */
1.366 - @Override
1.367 - public int hashCode() {
1.368 - if (hashCode != 0) {
1.369 - return hashCode;
1.370 - }
1.371 -
1.372 - hashCode = ((type == null) ? 1 : type.hashCode()) + ((id == null) ? 2 : id.hashCode()) +
1.373 - ((instance == null) ? 3 : 0);
1.374 -
1.375 - return hashCode;
1.376 - }
1.377 -
1.378 - /* Checks whether two templates represent the same query.
1.379 - * @param obj another template to check
1.380 - * @return true if so, false otherwise
1.381 - */
1.382 - @Override
1.383 - public boolean equals(Object obj) {
1.384 - if (!(obj instanceof Template)) {
1.385 - return false;
1.386 - }
1.387 -
1.388 - Template t = (Template) obj;
1.389 -
1.390 - if (hashCode() != t.hashCode()) {
1.391 - // this is an optimalization - the hashCodes should have been
1.392 - // precomputed
1.393 - return false;
1.394 - }
1.395 -
1.396 - if (type != t.type) {
1.397 - return false;
1.398 - }
1.399 -
1.400 - if (id == null) {
1.401 - if (t.id != null) {
1.402 - return false;
1.403 - }
1.404 - } else {
1.405 - if (!id.equals(t.id)) {
1.406 - return false;
1.407 - }
1.408 - }
1.409 -
1.410 - if (instance == null) {
1.411 - return (t.instance == null);
1.412 - } else {
1.413 - return instance.equals(t.instance);
1.414 - }
1.415 - }
1.416 -
1.417 - /* for debugging */
1.418 - @Override
1.419 - public String toString() {
1.420 - return "Lookup.Template[type=" + type + ",id=" + id + ",instance=" + instance + "]"; // NOI18N
1.421 - }
1.422 - }
1.423 -
1.424 - /** Result of a lookup request.
1.425 - * Allows access to all matching instances at once.
1.426 - * Also permits listening to changes in the result.
1.427 - * Result can contain duplicate items.
1.428 - */
1.429 - public static abstract class Result<T> extends Object {
1.430 - /** Registers a listener that is invoked when there is a possible
1.431 - * change in this result.
1.432 - *
1.433 - * @param l the listener to add
1.434 - */
1.435 - public abstract void addLookupListener(LookupListener l);
1.436 -
1.437 - /** Unregisters a listener previously added.
1.438 - * @param l the listener to remove
1.439 - */
1.440 - public abstract void removeLookupListener(LookupListener l);
1.441 -
1.442 - /** Get all instances in the result. The return value type
1.443 - * should be List instead of Collection, but it is too late to change it.
1.444 - * @return unmodifiable collection of all instances that will never change its content
1.445 - */
1.446 - public abstract Collection<? extends T> allInstances();
1.447 -
1.448 - /** Get all classes represented in the result.
1.449 - * That is, the set of concrete classes
1.450 - * used by instances present in the result.
1.451 - * All duplicate classes will be omitted.
1.452 - * @return unmodifiable set of <code>Class</code> objects that will never change its content
1.453 - *
1.454 - * @since 1.8
1.455 - */
1.456 - public Set<Class<? extends T>> allClasses() {
1.457 - return Collections.emptySet();
1.458 - }
1.459 -
1.460 - /** Get all registered items.
1.461 - * This should include all pairs of instances together
1.462 - * with their classes, IDs, and so on. The return value type
1.463 - * should be List instead of Collection, but it is too late to change it.
1.464 - * @return unmodifiable collection of {@link Lookup.Item} that will never change its content
1.465 - *
1.466 - * @since 1.8
1.467 - */
1.468 - public Collection<? extends Item<T>> allItems() {
1.469 - return Collections.emptyList();
1.470 - }
1.471 - }
1.472 -
1.473 - /** A single item in a lookup result.
1.474 - * This wrapper provides unified access to not just the instance,
1.475 - * but its class, a possible persistent identifier, and so on.
1.476 - *
1.477 - * @since 1.25
1.478 - */
1.479 - public static abstract class Item<T> extends Object {
1.480 - /** Get the instance itself.
1.481 - * @return the instance or null if the instance cannot be created
1.482 - */
1.483 - public abstract T getInstance();
1.484 -
1.485 - /** Get the implementing class of the instance.
1.486 - * @return the class of the item
1.487 - */
1.488 - public abstract Class<? extends T> getType();
1.489 -
1.490 - // XXX can it be null??
1.491 -
1.492 - /** Get a persistent indentifier for the item.
1.493 - * This identifier should uniquely represent the item
1.494 - * within its containing lookup (and if possible within the
1.495 - * global lookup as a whole). For example, it might represent
1.496 - * the source of the instance as a file name. The ID may be
1.497 - * persisted and in a later session used to find the same instance
1.498 - * as was encountered earlier, by means of passing it into a
1.499 - * lookup template.
1.500 - *
1.501 - * @return a string ID of the item
1.502 - */
1.503 - public abstract String getId();
1.504 -
1.505 - /** Get a human presentable name for the item.
1.506 - * This might be used when summarizing all the items found in a
1.507 - * lookup result in some part of a GUI.
1.508 - * @return the string suitable for presenting the object to a user
1.509 - */
1.510 - public abstract String getDisplayName();
1.511 -
1.512 - /* show ID for debugging */
1.513 - @Override
1.514 - public String toString() {
1.515 - return getId();
1.516 - }
1.517 - }
1.518 -
1.519 - //
1.520 - // Implementation of the default lookup
1.521 - //
1.522 - private static final class Empty extends Lookup {
1.523 - private static final Result NO_RESULT = new Result() {
1.524 - public void addLookupListener(LookupListener l) {
1.525 - }
1.526 -
1.527 - public void removeLookupListener(LookupListener l) {
1.528 - }
1.529 -
1.530 - public Collection allInstances() {
1.531 - return Collections.EMPTY_SET;
1.532 - }
1.533 - };
1.534 -
1.535 - Empty() {
1.536 - }
1.537 -
1.538 - public <T> T lookup(Class<T> clazz) {
1.539 - return null;
1.540 - }
1.541 -
1.542 - @SuppressWarnings("unchecked")
1.543 - public <T> Result<T> lookup(Template<T> template) {
1.544 - return NO_RESULT;
1.545 - }
1.546 - }
1.547 -}