1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/openide.util.lookup/build.xml Sat Oct 31 15:28:13 2009 +0100
1.3 @@ -0,0 +1,5 @@
1.4 +<?xml version="1.0" encoding="UTF-8"?>
1.5 +<project basedir="." default="netbeans" name="openide.util.lookup">
1.6 + <description>Builds, tests, and runs the project org.openide.util.lookup</description>
1.7 + <import file="../nbbuild/templates/projectized.xml"/>
1.8 +</project>
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/openide.util.lookup/manifest.mf Sat Oct 31 15:28:13 2009 +0100
2.3 @@ -0,0 +1,5 @@
2.4 +Manifest-Version: 1.0
2.5 +OpenIDE-Module: org.openide.util.lookup
2.6 +OpenIDE-Module-Localizing-Bundle: org/openide/util/lookup/Bundle.properties
2.7 +OpenIDE-Module-Specification-Version: 8.0
2.8 +
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/openide.util.lookup/nbproject/project.properties Sat Oct 31 15:28:13 2009 +0100
3.3 @@ -0,0 +1,43 @@
3.4 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3.5 +#
3.6 +# Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
3.7 +#
3.8 +# The contents of this file are subject to the terms of either the GNU
3.9 +# General Public License Version 2 only ("GPL") or the Common
3.10 +# Development and Distribution License("CDDL") (collectively, the
3.11 +# "License"). You may not use this file except in compliance with the
3.12 +# License. You can obtain a copy of the License at
3.13 +# http://www.netbeans.org/cddl-gplv2.html
3.14 +# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
3.15 +# specific language governing permissions and limitations under the
3.16 +# License. When distributing the software, include this License Header
3.17 +# Notice in each file and include the License file at
3.18 +# nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
3.19 +# particular file as subject to the "Classpath" exception as provided
3.20 +# by Sun in the GPL Version 2 section of the License file that
3.21 +# accompanied this code. If applicable, add the following below the
3.22 +# License Header, with the fields enclosed by brackets [] replaced by
3.23 +# your own identifying information:
3.24 +# "Portions Copyrighted [year] [name of copyright owner]"
3.25 +#
3.26 +# Contributor(s):
3.27 +#
3.28 +# The Original Software is NetBeans. The Initial Developer of the Original
3.29 +# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
3.30 +# Microsystems, Inc. All Rights Reserved.
3.31 +#
3.32 +# If you wish your version of this file to be governed by only the CDDL
3.33 +# or only the GPL Version 2, indicate your decision by adding
3.34 +# "[Contributor] elects to include this software in this distribution
3.35 +# under the [CDDL or GPL Version 2] license." If you do not indicate a
3.36 +# single choice of license, a recipient has the option to distribute
3.37 +# your version of this file under either the CDDL, the GPL Version 2 or
3.38 +# to extend the choice of license to its licensees as provided above.
3.39 +# However, if you add GPL Version 2 code and therefore, elected the GPL
3.40 +# Version 2 license, then the option applies only if the new code is
3.41 +# made subject to such option by the copyright holder.
3.42 +
3.43 +module.jar.dir=lib
3.44 +is.autoload=true
3.45 +javac.source=1.5
3.46 +javac.compilerargs=-Xlint -Xlint:-serial
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/openide.util.lookup/nbproject/project.xml Sat Oct 31 15:28:13 2009 +0100
4.3 @@ -0,0 +1,28 @@
4.4 +<?xml version="1.0" encoding="UTF-8"?>
4.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
4.6 + <type>org.netbeans.modules.apisupport.project</type>
4.7 + <configuration>
4.8 + <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
4.9 + <code-name-base>org.openide.util.lookup</code-name-base>
4.10 + <module-dependencies/>
4.11 + <test-dependencies>
4.12 + <test-type>
4.13 + <name>unit</name>
4.14 + <test-dependency>
4.15 + <code-name-base>org.netbeans.libs.junit4</code-name-base>
4.16 + <compile-dependency/>
4.17 + </test-dependency>
4.18 + <test-dependency>
4.19 + <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
4.20 + <recursive/>
4.21 + <compile-dependency/>
4.22 + </test-dependency>
4.23 + </test-type>
4.24 + </test-dependencies>
4.25 + <public-packages>
4.26 + <package>org.openide.util</package>
4.27 + <package>org.openide.util.lookup</package>
4.28 + </public-packages>
4.29 + </data>
4.30 + </configuration>
4.31 +</project>
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/ActiveQueue.java Sat Oct 31 15:28:13 2009 +0100
5.3 @@ -0,0 +1,108 @@
5.4 +package org.netbeans.modules.openide.util;
5.5 +
5.6 +import java.lang.ref.Reference;
5.7 +import java.lang.ref.ReferenceQueue;
5.8 +import java.util.logging.Level;
5.9 +import java.util.logging.Logger;
5.10 +
5.11 +/**
5.12 + * Implementation of the active reference queue.
5.13 + */
5.14 +public final class ActiveQueue extends ReferenceQueue<Object> implements Runnable {
5.15 +
5.16 + private static final Logger LOGGER = Logger.getLogger(ActiveQueue.class.getName().replace('$', '.'));
5.17 + private static ActiveQueue activeReferenceQueue;
5.18 +
5.19 + /** number of known outstanding references */
5.20 + private int count;
5.21 + private boolean deprecated;
5.22 +
5.23 + ActiveQueue(boolean deprecated) {
5.24 + super();
5.25 + this.deprecated = deprecated;
5.26 + }
5.27 +
5.28 + public static synchronized ReferenceQueue<Object> queue() {
5.29 + if (activeReferenceQueue == null) {
5.30 + activeReferenceQueue = new ActiveQueue(false);
5.31 + }
5.32 +
5.33 + activeReferenceQueue.ping();
5.34 +
5.35 + return activeReferenceQueue;
5.36 + }
5.37 +
5.38 + @Override
5.39 + public Reference<Object> poll() {
5.40 + throw new UnsupportedOperationException();
5.41 + }
5.42 +
5.43 + @Override
5.44 + public Reference<Object> remove(long timeout) throws IllegalArgumentException, InterruptedException {
5.45 + throw new InterruptedException();
5.46 + }
5.47 +
5.48 + @Override
5.49 + public Reference<Object> remove() throws InterruptedException {
5.50 + throw new InterruptedException();
5.51 + }
5.52 +
5.53 + public void run() {
5.54 + while (true) {
5.55 + try {
5.56 + Reference<?> ref = super.remove(0);
5.57 + LOGGER.finer("dequeued reference");
5.58 + if (!(ref instanceof Runnable)) {
5.59 + LOGGER.warning("A reference not implementing runnable has been added to the Utilities.activeReferenceQueue(): " + ref.getClass());
5.60 + continue;
5.61 + }
5.62 + if (deprecated) {
5.63 + LOGGER.warning("Utilities.ACTIVE_REFERENCE_QUEUE has been deprecated for " + ref.getClass() + " use Utilities.activeReferenceQueue");
5.64 + }
5.65 + // do the cleanup
5.66 + try {
5.67 + ((Runnable) ref).run();
5.68 + } catch (ThreadDeath td) {
5.69 + throw td;
5.70 + } catch (Throwable t) {
5.71 + // Should not happen.
5.72 + // If it happens, it is a bug in client code, notify!
5.73 + LOGGER.log(Level.WARNING, null, t);
5.74 + } finally {
5.75 + // to allow GC
5.76 + ref = null;
5.77 + }
5.78 + } catch (InterruptedException ex) {
5.79 + // Can happen during VM shutdown, it seems. Ignore.
5.80 + continue;
5.81 + }
5.82 + synchronized (this) {
5.83 + assert count > 0;
5.84 + count--;
5.85 + if (count == 0) {
5.86 + // We have processed all we have to process (for now at least).
5.87 + // Could be restarted later if ping() called again.
5.88 + // This could also happen in case someone called queue() once and tried
5.89 + // to use it for several references; in that case run() might never be called on
5.90 + // the later ones to be collected. Can't really protect against that situation.
5.91 + // See issue #86625 for details.
5.92 + LOGGER.fine("stopping thread");
5.93 + break;
5.94 + }
5.95 + }
5.96 + }
5.97 + }
5.98 +
5.99 + synchronized void ping() {
5.100 + if (count == 0) {
5.101 + Thread t = new Thread(this, "Active Reference Queue Daemon");
5.102 + t.setPriority(Thread.MIN_PRIORITY);
5.103 + t.setDaemon(true);
5.104 + t.start();
5.105 + LOGGER.fine("starting thread");
5.106 + } else {
5.107 + LOGGER.finer("enqueuing reference");
5.108 + }
5.109 + count++;
5.110 + }
5.111 +}
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/NamedServicesProvider.java Sat Oct 31 15:28:13 2009 +0100
6.3 @@ -0,0 +1,81 @@
6.4 +/*
6.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
6.6 + *
6.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
6.8 + *
6.9 + * The contents of this file are subject to the terms of either the GNU
6.10 + * General Public License Version 2 only ("GPL") or the Common
6.11 + * Development and Distribution License("CDDL") (collectively, the
6.12 + * "License"). You may not use this file except in compliance with the
6.13 + * License. You can obtain a copy of the License at
6.14 + * http://www.netbeans.org/cddl-gplv2.html
6.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
6.16 + * specific language governing permissions and limitations under the
6.17 + * License. When distributing the software, include this License Header
6.18 + * Notice in each file and include the License file at
6.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
6.20 + * particular file as subject to the "Classpath" exception as provided
6.21 + * by Sun in the GPL Version 2 section of the License file that
6.22 + * accompanied this code. If applicable, add the following below the
6.23 + * License Header, with the fields enclosed by brackets [] replaced by
6.24 + * your own identifying information:
6.25 + * "Portions Copyrighted [year] [name of copyright owner]"
6.26 + *
6.27 + * Contributor(s):
6.28 + *
6.29 + * The Original Software is NetBeans. The Initial Developer of the Original
6.30 + * Software is Sun Microsystems, Inc.
6.31 + *
6.32 + * Portions Copyrighted 2006 Sun Microsystems, Inc.
6.33 + */
6.34 +
6.35 +package org.netbeans.modules.openide.util;
6.36 +
6.37 +import java.lang.ref.Reference;
6.38 +import java.lang.ref.WeakReference;
6.39 +import java.util.Collections;
6.40 +import java.util.HashMap;
6.41 +import java.util.Map;
6.42 +import org.openide.util.Lookup;
6.43 +import org.openide.util.lookup.Lookups;
6.44 +
6.45 +/** Interface for core/startup and core/settings
6.46 + * to provide lookup over system filesystem.
6.47 + *
6.48 + * @author Jaroslav Tulach
6.49 + */
6.50 +public abstract class NamedServicesProvider {
6.51 +
6.52 + private static final Map<String,Reference<Lookup>> map = Collections.synchronizedMap(new HashMap<String,Reference<Lookup>>());
6.53 +
6.54 + public abstract Lookup create(String path);
6.55 +
6.56 + public static Lookup find(String path) {
6.57 + if (!path.endsWith("/")) {
6.58 + path = path + "/";
6.59 + }
6.60 +
6.61 + Reference<Lookup> ref = map.get(path);
6.62 + Lookup lkp = ref == null ? null : ref.get();
6.63 + if (lkp != null) {
6.64 + return lkp;
6.65 + }
6.66 + NamedServicesProvider prov = Lookup.getDefault().lookup(NamedServicesProvider.class);
6.67 + if (prov != null) {
6.68 + lkp = prov.create(path);
6.69 + } else {
6.70 + ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
6.71 + if (l == null) {
6.72 + l = Thread.currentThread().getContextClassLoader();
6.73 + if (l == null) {
6.74 + l = NamedServicesProvider.class.getClassLoader();
6.75 + }
6.76 + }
6.77 + lkp = Lookups.metaInfServices(l, "META-INF/namedservices/" + path);
6.78 + }
6.79 +
6.80 + map.put(path, new WeakReference<Lookup>(lkp));
6.81 + return lkp;
6.82 + }
6.83 +
6.84 +}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/openide.util.lookup/src/org/openide/util/Lookup.java Sat Oct 31 15:28:13 2009 +0100
7.3 @@ -0,0 +1,544 @@
7.4 +/*
7.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7.6 + *
7.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
7.8 + *
7.9 + * The contents of this file are subject to the terms of either the GNU
7.10 + * General Public License Version 2 only ("GPL") or the Common
7.11 + * Development and Distribution License("CDDL") (collectively, the
7.12 + * "License"). You may not use this file except in compliance with the
7.13 + * License. You can obtain a copy of the License at
7.14 + * http://www.netbeans.org/cddl-gplv2.html
7.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
7.16 + * specific language governing permissions and limitations under the
7.17 + * License. When distributing the software, include this License Header
7.18 + * Notice in each file and include the License file at
7.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
7.20 + * particular file as subject to the "Classpath" exception as provided
7.21 + * by Sun in the GPL Version 2 section of the License file that
7.22 + * accompanied this code. If applicable, add the following below the
7.23 + * License Header, with the fields enclosed by brackets [] replaced by
7.24 + * your own identifying information:
7.25 + * "Portions Copyrighted [year] [name of copyright owner]"
7.26 + *
7.27 + * Contributor(s):
7.28 + *
7.29 + * The Original Software is NetBeans. The Initial Developer of the Original
7.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
7.31 + * Microsystems, Inc. All Rights Reserved.
7.32 + *
7.33 + * If you wish your version of this file to be governed by only the CDDL
7.34 + * or only the GPL Version 2, indicate your decision by adding
7.35 + * "[Contributor] elects to include this software in this distribution
7.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
7.37 + * single choice of license, a recipient has the option to distribute
7.38 + * your version of this file under either the CDDL, the GPL Version 2 or
7.39 + * to extend the choice of license to its licensees as provided above.
7.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
7.41 + * Version 2 license, then the option applies only if the new code is
7.42 + * made subject to such option by the copyright holder.
7.43 + */
7.44 +
7.45 +package org.openide.util;
7.46 +
7.47 +import java.util.ArrayList;
7.48 +import java.util.Collection;
7.49 +import java.util.Collections;
7.50 +import java.util.Iterator;
7.51 +import java.util.List;
7.52 +import java.util.Set;
7.53 +import org.openide.util.lookup.Lookups;
7.54 +import org.openide.util.lookup.ProxyLookup;
7.55 +import org.openide.util.lookup.ServiceProvider;
7.56 +
7.57 +/**
7.58 + * A general registry permitting clients to find instances of services
7.59 + * (implementation of a given interface).
7.60 + * This class is inspired by the
7.61 + * <a href="http://www.jini.org/">Jini</a>
7.62 + * registration and lookup mechanism. The difference is that the methods do
7.63 + * not throw checked exceptions (as they usually work only locally and not over the network)
7.64 + * and that the Lookup API concentrates on the lookup, not on the registration
7.65 + * (although {@link Lookup#getDefault} is strongly encouraged to support
7.66 + * {@link Lookups#metaInfServices} for registration in addition to whatever
7.67 + * else it decides to support).
7.68 + * <p>
7.69 + * For a general talk about the idea behind the lookup pattern please see
7.70 + * <UL>
7.71 + * <LI><a href="lookup/doc-files/index.html">The Solution to Communication Between Components</a>
7.72 + * page
7.73 + * <LI>the introduction to the <a href="lookup/doc-files/lookup-api.html">lookup API via
7.74 + * use cases</a>
7.75 + * <LI>the examples of <a href="lookup/doc-files/lookup-spi.html">how to write your own lookup</a>
7.76 + * </UL>
7.77 + *
7.78 + * @see org.openide.util.lookup.AbstractLookup
7.79 + * @see Lookups
7.80 + * @see LookupListener
7.81 + * @see LookupEvent
7.82 + * @author Jaroslav Tulach
7.83 + */
7.84 +public abstract class Lookup {
7.85 + /** A dummy lookup that never returns any results.
7.86 + */
7.87 + public static final Lookup EMPTY = new Empty();
7.88 +
7.89 + /** default instance */
7.90 + private static Lookup defaultLookup;
7.91 +
7.92 + /** Empty constructor for use by subclasses. */
7.93 + public Lookup() {
7.94 + }
7.95 +
7.96 + /** Static method to obtain the global lookup in the whole system.
7.97 + * The actual returned implementation can be different in different
7.98 + * systems, but the default one is based on
7.99 + * {@link org.openide.util.lookup.Lookups#metaInfServices}
7.100 + * with the context classloader of the first caller. Each system is
7.101 + * adviced to honor this and include some form of <code>metaInfServices</code>
7.102 + * implementation in the returned lookup as usage of <code>META-INF/services</code>
7.103 + * is a JDK standard.
7.104 + *
7.105 + * @return the global lookup in the system
7.106 + * @see ServiceProvider
7.107 + */
7.108 + public static synchronized Lookup getDefault() {
7.109 + if (defaultLookup != null) {
7.110 + return defaultLookup;
7.111 + }
7.112 +
7.113 + // You can specify a Lookup impl using a system property if you like.
7.114 + String className = System.getProperty("org.openide.util.Lookup" // NOI18N
7.115 + );
7.116 +
7.117 + if ("-".equals(className)) { // NOI18N
7.118 +
7.119 + // Suppress even MetaInfServicesLookup.
7.120 + return EMPTY;
7.121 + }
7.122 +
7.123 + ClassLoader l = Thread.currentThread().getContextClassLoader();
7.124 +
7.125 + try {
7.126 + if (className != null) {
7.127 + defaultLookup = (Lookup) Class.forName(className, true, l).newInstance();
7.128 +
7.129 + return defaultLookup;
7.130 + }
7.131 + } catch (Exception e) {
7.132 + // do not use ErrorManager because we are in the startup code
7.133 + // and ErrorManager might not be ready
7.134 + e.printStackTrace();
7.135 + }
7.136 +
7.137 + // OK, none specified (successfully) in a system property.
7.138 + // Try MetaInfServicesLookup as a default, which may also
7.139 + // have a org.openide.util.Lookup line specifying the lookup.
7.140 + Lookup misl = Lookups.metaInfServices(l);
7.141 + defaultLookup = misl.lookup(Lookup.class);
7.142 +
7.143 + if (defaultLookup != null) {
7.144 + return defaultLookup;
7.145 + }
7.146 +
7.147 + // You may also specify a Lookup.Provider.
7.148 + Lookup.Provider prov = misl.lookup(Lookup.Provider.class);
7.149 +
7.150 + if (prov != null) {
7.151 + defaultLookup = Lookups.proxy(prov);
7.152 +
7.153 + return defaultLookup;
7.154 + }
7.155 +
7.156 + DefLookup def = new DefLookup();
7.157 + def.init(l, misl, false);
7.158 + defaultLookup = def;
7.159 + def.init(l, misl, true);
7.160 + return defaultLookup;
7.161 + }
7.162 +
7.163 + private static final class DefLookup extends ProxyLookup {
7.164 + public DefLookup() {
7.165 + super(new Lookup[0]);
7.166 + }
7.167 +
7.168 + public void init(ClassLoader loader, Lookup metaInfLookup, boolean addPath) {
7.169 + // Had no such line, use simple impl.
7.170 + // It does however need to have ClassLoader available or many things will break.
7.171 + // Use the thread context classloader in effect now.
7.172 + Lookup clLookup = Lookups.singleton(loader);
7.173 + List<Lookup> arr = new ArrayList<Lookup>();
7.174 + arr.add(metaInfLookup);
7.175 + arr.add(clLookup);
7.176 + String paths = System.getProperty("org.openide.util.Lookup.paths"); // NOI18N
7.177 + if (addPath && paths != null) {
7.178 + for (String p : paths.split(":")) { // NOI18N
7.179 + arr.add(Lookups.forPath(p));
7.180 + }
7.181 + }
7.182 + setLookups(arr.toArray(new Lookup[0]));
7.183 + }
7.184 + }
7.185 +
7.186 + /** Called from MockServices to reset default lookup in case services change
7.187 + */
7.188 + private static void resetDefaultLookup() {
7.189 + if (defaultLookup instanceof DefLookup) {
7.190 + DefLookup def = (DefLookup)defaultLookup;
7.191 + ClassLoader l = Thread.currentThread().getContextClassLoader();
7.192 + def.init(l, Lookups.metaInfServices(l), true);
7.193 + }
7.194 + }
7.195 +
7.196 + /** Look up an object matching a given interface.
7.197 + * This is the simplest method to use.
7.198 + * If more than one object matches, the first will be returned.
7.199 + * The template class may be a class or interface; the instance is
7.200 + * guaranteed to be assignable to it.
7.201 + *
7.202 + * @param clazz class of the object we are searching for
7.203 + * @return an object implementing the given class or <code>null</code> if no such
7.204 + * implementation is found
7.205 + */
7.206 + public abstract <T> T lookup(Class<T> clazz);
7.207 +
7.208 + /** The general lookup method. Callers can get list of all instances and classes
7.209 + * that match the given <code>template</code>, request more info about
7.210 + * them in form of {@link Lookup.Item} and attach a listener to
7.211 + * this be notified about changes. The general interface does not
7.212 + * specify whether subsequent calls with the same template produce new
7.213 + * instance of the {@link Lookup.Result} or return shared instance. The
7.214 + * prefered behaviour however is to return shared one.
7.215 + *
7.216 + * @param template a template describing the services to look for
7.217 + * @return an object containing the results
7.218 + */
7.219 + public abstract <T> Result<T> lookup(Template<T> template);
7.220 +
7.221 + /** Look up the first item matching a given template.
7.222 + * Includes not only the instance but other associated information.
7.223 + * @param template the template to check
7.224 + * @return a matching item or <code>null</code>
7.225 + *
7.226 + * @since 1.8
7.227 + */
7.228 + public <T> Item<T> lookupItem(Template<T> template) {
7.229 + Result<T> res = lookup(template);
7.230 + Iterator<? extends Item<T>> it = res.allItems().iterator();
7.231 + return it.hasNext() ? it.next() : null;
7.232 + }
7.233 +
7.234 + /**
7.235 + * Find a result corresponding to a given class.
7.236 + * Equivalent to calling {@link #lookup(Lookup.Template)} but slightly more convenient.
7.237 + * Subclasses may override this method to produce the same semantics more efficiently.
7.238 + * @param clazz the supertype of the result
7.239 + * @return a live object representing instances of that type
7.240 + * @since org.openide.util 6.10
7.241 + */
7.242 + public <T> Lookup.Result<T> lookupResult(Class<T> clazz) {
7.243 + return lookup(new Lookup.Template<T>(clazz));
7.244 + }
7.245 +
7.246 + /**
7.247 + * Find all instances corresponding to a given class.
7.248 + * Equivalent to calling {@link #lookupResult} and asking for {@link Lookup.Result#allInstances} but slightly more convenient.
7.249 + * Subclasses may override this method to produce the same semantics more efficiently.
7.250 + * <div class="nonnormative">
7.251 + * <p>Example usage:</p>
7.252 + * <pre>
7.253 + * for (MyService svc : Lookup.getDefault().lookupAll(MyService.class)) {
7.254 + * svc.useMe();
7.255 + * }
7.256 + * </pre>
7.257 + * </div>
7.258 + * @param clazz the supertype of the result
7.259 + * @return all currently available instances of that type
7.260 + * @since org.openide.util 6.10
7.261 + */
7.262 + public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
7.263 + return lookupResult(clazz).allInstances();
7.264 + }
7.265 +
7.266 + /**
7.267 + * Objects implementing interface Lookup.Provider are capable of
7.268 + * and willing to provide a lookup (usually bound to the object).
7.269 + * @since 3.6
7.270 + */
7.271 + public interface Provider {
7.272 + /**
7.273 + * Returns lookup associated with the object.
7.274 + * @return fully initialized lookup instance provided by this object
7.275 + */
7.276 + Lookup getLookup();
7.277 + }
7.278 +
7.279 + /*
7.280 + * I expect this class to grow in the future, but for now, it is
7.281 + * enough to start with something simple.
7.282 + */
7.283 +
7.284 + /** Template defining a pattern to filter instances by.
7.285 + */
7.286 + public static final class Template<T> extends Object {
7.287 + /** cached hash code */
7.288 + private int hashCode;
7.289 +
7.290 + /** type of the service */
7.291 + private Class<T> type;
7.292 +
7.293 + /** identity to search for */
7.294 + private String id;
7.295 +
7.296 + /** instance to search for */
7.297 + private T instance;
7.298 +
7.299 + /** General template to find all possible instances.
7.300 + * @deprecated Use <code>new Template (Object.class)</code> which
7.301 + * is going to be better typed with JDK1.5 templates and should produce
7.302 + * the same result.
7.303 + */
7.304 + @Deprecated
7.305 + public Template() {
7.306 + this(null);
7.307 + }
7.308 +
7.309 + /** Create a simple template matching by class.
7.310 + * @param type the class of service we are looking for (subclasses will match)
7.311 + */
7.312 + public Template(Class<T> type) {
7.313 + this(type, null, null);
7.314 + }
7.315 +
7.316 + /** Constructor to create new template.
7.317 + * @param type the class of service we are looking for or <code>null</code> to leave unspecified
7.318 + * @param id the ID of the item/service we are looking for or <code>null</code> to leave unspecified
7.319 + * @param instance a specific known instance to look for or <code>null</code> to leave unspecified
7.320 + */
7.321 + public Template(Class<T> type, String id, T instance) {
7.322 + this.type = extractType(type);
7.323 + this.id = id;
7.324 + this.instance = instance;
7.325 + }
7.326 +
7.327 + @SuppressWarnings("unchecked")
7.328 + private Class<T> extractType(Class<T> type) {
7.329 + return (type == null) ? (Class<T>)Object.class : type;
7.330 + }
7.331 +
7.332 + /** Get the class (or superclass or interface) to search for.
7.333 + * If it was not specified in the constructor, <code>Object</code> is used as
7.334 + * this will match any instance.
7.335 + * @return the class to search for
7.336 + */
7.337 + public Class<T> getType() {
7.338 + return type;
7.339 + }
7.340 +
7.341 + /** Get the persistent identifier being searched for, if any.
7.342 + * @return the ID or <code>null</code>
7.343 + * @see Lookup.Item#getId
7.344 + *
7.345 + * @since 1.8
7.346 + */
7.347 + public String getId() {
7.348 + return id;
7.349 + }
7.350 +
7.351 + /** Get the specific instance being searched for, if any.
7.352 + * Most useful for finding an <code>Item</code> when the instance
7.353 + * is already known.
7.354 + *
7.355 + * @return the object to find or <code>null</code>
7.356 + *
7.357 + * @since 1.8
7.358 + */
7.359 + public T getInstance() {
7.360 + return instance;
7.361 + }
7.362 +
7.363 + /* Computes hashcode for this template. The hashcode is cached.
7.364 + * @return hashcode
7.365 + */
7.366 + @Override
7.367 + public int hashCode() {
7.368 + if (hashCode != 0) {
7.369 + return hashCode;
7.370 + }
7.371 +
7.372 + hashCode = ((type == null) ? 1 : type.hashCode()) + ((id == null) ? 2 : id.hashCode()) +
7.373 + ((instance == null) ? 3 : 0);
7.374 +
7.375 + return hashCode;
7.376 + }
7.377 +
7.378 + /* Checks whether two templates represent the same query.
7.379 + * @param obj another template to check
7.380 + * @return true if so, false otherwise
7.381 + */
7.382 + @Override
7.383 + public boolean equals(Object obj) {
7.384 + if (!(obj instanceof Template)) {
7.385 + return false;
7.386 + }
7.387 +
7.388 + Template t = (Template) obj;
7.389 +
7.390 + if (hashCode() != t.hashCode()) {
7.391 + // this is an optimalization - the hashCodes should have been
7.392 + // precomputed
7.393 + return false;
7.394 + }
7.395 +
7.396 + if (type != t.type) {
7.397 + return false;
7.398 + }
7.399 +
7.400 + if (id == null) {
7.401 + if (t.id != null) {
7.402 + return false;
7.403 + }
7.404 + } else {
7.405 + if (!id.equals(t.id)) {
7.406 + return false;
7.407 + }
7.408 + }
7.409 +
7.410 + if (instance == null) {
7.411 + return (t.instance == null);
7.412 + } else {
7.413 + return instance.equals(t.instance);
7.414 + }
7.415 + }
7.416 +
7.417 + /* for debugging */
7.418 + @Override
7.419 + public String toString() {
7.420 + return "Lookup.Template[type=" + type + ",id=" + id + ",instance=" + instance + "]"; // NOI18N
7.421 + }
7.422 + }
7.423 +
7.424 + /** Result of a lookup request.
7.425 + * Allows access to all matching instances at once.
7.426 + * Also permits listening to changes in the result.
7.427 + * Result can contain duplicate items.
7.428 + */
7.429 + public static abstract class Result<T> extends Object {
7.430 + /** Registers a listener that is invoked when there is a possible
7.431 + * change in this result.
7.432 + *
7.433 + * @param l the listener to add
7.434 + */
7.435 + public abstract void addLookupListener(LookupListener l);
7.436 +
7.437 + /** Unregisters a listener previously added.
7.438 + * @param l the listener to remove
7.439 + */
7.440 + public abstract void removeLookupListener(LookupListener l);
7.441 +
7.442 + /** Get all instances in the result. The return value type
7.443 + * should be List instead of Collection, but it is too late to change it.
7.444 + * @return unmodifiable collection of all instances that will never change its content
7.445 + */
7.446 + public abstract Collection<? extends T> allInstances();
7.447 +
7.448 + /** Get all classes represented in the result.
7.449 + * That is, the set of concrete classes
7.450 + * used by instances present in the result.
7.451 + * All duplicate classes will be omitted.
7.452 + * @return unmodifiable set of <code>Class</code> objects that will never change its content
7.453 + *
7.454 + * @since 1.8
7.455 + */
7.456 + public Set<Class<? extends T>> allClasses() {
7.457 + return Collections.emptySet();
7.458 + }
7.459 +
7.460 + /** Get all registered items.
7.461 + * This should include all pairs of instances together
7.462 + * with their classes, IDs, and so on. The return value type
7.463 + * should be List instead of Collection, but it is too late to change it.
7.464 + * @return unmodifiable collection of {@link Lookup.Item} that will never change its content
7.465 + *
7.466 + * @since 1.8
7.467 + */
7.468 + public Collection<? extends Item<T>> allItems() {
7.469 + return Collections.emptyList();
7.470 + }
7.471 + }
7.472 +
7.473 + /** A single item in a lookup result.
7.474 + * This wrapper provides unified access to not just the instance,
7.475 + * but its class, a possible persistent identifier, and so on.
7.476 + *
7.477 + * @since 1.25
7.478 + */
7.479 + public static abstract class Item<T> extends Object {
7.480 + /** Get the instance itself.
7.481 + * @return the instance or null if the instance cannot be created
7.482 + */
7.483 + public abstract T getInstance();
7.484 +
7.485 + /** Get the implementing class of the instance.
7.486 + * @return the class of the item
7.487 + */
7.488 + public abstract Class<? extends T> getType();
7.489 +
7.490 + // XXX can it be null??
7.491 +
7.492 + /** Get a persistent indentifier for the item.
7.493 + * This identifier should uniquely represent the item
7.494 + * within its containing lookup (and if possible within the
7.495 + * global lookup as a whole). For example, it might represent
7.496 + * the source of the instance as a file name. The ID may be
7.497 + * persisted and in a later session used to find the same instance
7.498 + * as was encountered earlier, by means of passing it into a
7.499 + * lookup template.
7.500 + *
7.501 + * @return a string ID of the item
7.502 + */
7.503 + public abstract String getId();
7.504 +
7.505 + /** Get a human presentable name for the item.
7.506 + * This might be used when summarizing all the items found in a
7.507 + * lookup result in some part of a GUI.
7.508 + * @return the string suitable for presenting the object to a user
7.509 + */
7.510 + public abstract String getDisplayName();
7.511 +
7.512 + /* show ID for debugging */
7.513 + @Override
7.514 + public String toString() {
7.515 + return getId();
7.516 + }
7.517 + }
7.518 +
7.519 + //
7.520 + // Implementation of the default lookup
7.521 + //
7.522 + private static final class Empty extends Lookup {
7.523 + private static final Result NO_RESULT = new Result() {
7.524 + public void addLookupListener(LookupListener l) {
7.525 + }
7.526 +
7.527 + public void removeLookupListener(LookupListener l) {
7.528 + }
7.529 +
7.530 + public Collection allInstances() {
7.531 + return Collections.EMPTY_SET;
7.532 + }
7.533 + };
7.534 +
7.535 + Empty() {
7.536 + }
7.537 +
7.538 + public <T> T lookup(Class<T> clazz) {
7.539 + return null;
7.540 + }
7.541 +
7.542 + @SuppressWarnings("unchecked")
7.543 + public <T> Result<T> lookup(Template<T> template) {
7.544 + return NO_RESULT;
7.545 + }
7.546 + }
7.547 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/openide.util.lookup/src/org/openide/util/LookupEvent.java Sat Oct 31 15:28:13 2009 +0100
8.3 @@ -0,0 +1,57 @@
8.4 +/*
8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
8.6 + *
8.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
8.8 + *
8.9 + * The contents of this file are subject to the terms of either the GNU
8.10 + * General Public License Version 2 only ("GPL") or the Common
8.11 + * Development and Distribution License("CDDL") (collectively, the
8.12 + * "License"). You may not use this file except in compliance with the
8.13 + * License. You can obtain a copy of the License at
8.14 + * http://www.netbeans.org/cddl-gplv2.html
8.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
8.16 + * specific language governing permissions and limitations under the
8.17 + * License. When distributing the software, include this License Header
8.18 + * Notice in each file and include the License file at
8.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
8.20 + * particular file as subject to the "Classpath" exception as provided
8.21 + * by Sun in the GPL Version 2 section of the License file that
8.22 + * accompanied this code. If applicable, add the following below the
8.23 + * License Header, with the fields enclosed by brackets [] replaced by
8.24 + * your own identifying information:
8.25 + * "Portions Copyrighted [year] [name of copyright owner]"
8.26 + *
8.27 + * Contributor(s):
8.28 + *
8.29 + * The Original Software is NetBeans. The Initial Developer of the Original
8.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
8.31 + * Microsystems, Inc. All Rights Reserved.
8.32 + *
8.33 + * If you wish your version of this file to be governed by only the CDDL
8.34 + * or only the GPL Version 2, indicate your decision by adding
8.35 + * "[Contributor] elects to include this software in this distribution
8.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
8.37 + * single choice of license, a recipient has the option to distribute
8.38 + * your version of this file under either the CDDL, the GPL Version 2 or
8.39 + * to extend the choice of license to its licensees as provided above.
8.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
8.41 + * Version 2 license, then the option applies only if the new code is
8.42 + * made subject to such option by the copyright holder.
8.43 + */
8.44 +package org.openide.util;
8.45 +
8.46 +import java.util.*;
8.47 +
8.48 +
8.49 +/** An event describing the change in the lookup's result.
8.50 + *
8.51 + * @author Jaroslav Tulach
8.52 + */
8.53 +public final class LookupEvent extends EventObject {
8.54 + /** Create a new lookup event.
8.55 + * @param source the lookup result which has changed
8.56 + */
8.57 + public LookupEvent(Lookup.Result source) {
8.58 + super(source);
8.59 + }
8.60 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/openide.util.lookup/src/org/openide/util/LookupListener.java Sat Oct 31 15:28:13 2009 +0100
9.3 @@ -0,0 +1,59 @@
9.4 +/*
9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
9.6 + *
9.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
9.8 + *
9.9 + * The contents of this file are subject to the terms of either the GNU
9.10 + * General Public License Version 2 only ("GPL") or the Common
9.11 + * Development and Distribution License("CDDL") (collectively, the
9.12 + * "License"). You may not use this file except in compliance with the
9.13 + * License. You can obtain a copy of the License at
9.14 + * http://www.netbeans.org/cddl-gplv2.html
9.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
9.16 + * specific language governing permissions and limitations under the
9.17 + * License. When distributing the software, include this License Header
9.18 + * Notice in each file and include the License file at
9.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
9.20 + * particular file as subject to the "Classpath" exception as provided
9.21 + * by Sun in the GPL Version 2 section of the License file that
9.22 + * accompanied this code. If applicable, add the following below the
9.23 + * License Header, with the fields enclosed by brackets [] replaced by
9.24 + * your own identifying information:
9.25 + * "Portions Copyrighted [year] [name of copyright owner]"
9.26 + *
9.27 + * Contributor(s):
9.28 + *
9.29 + * The Original Software is NetBeans. The Initial Developer of the Original
9.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
9.31 + * Microsystems, Inc. All Rights Reserved.
9.32 + *
9.33 + * If you wish your version of this file to be governed by only the CDDL
9.34 + * or only the GPL Version 2, indicate your decision by adding
9.35 + * "[Contributor] elects to include this software in this distribution
9.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
9.37 + * single choice of license, a recipient has the option to distribute
9.38 + * your version of this file under either the CDDL, the GPL Version 2 or
9.39 + * to extend the choice of license to its licensees as provided above.
9.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
9.41 + * Version 2 license, then the option applies only if the new code is
9.42 + * made subject to such option by the copyright holder.
9.43 + */
9.44 +package org.openide.util;
9.45 +
9.46 +import java.util.*;
9.47 +
9.48 +
9.49 +/** General listener for changes in lookup.
9.50 + *
9.51 + * @author Jaroslav Tulach
9.52 + */
9.53 +public interface LookupListener extends EventListener {
9.54 + /** A change in lookup occured. Please note that this method
9.55 + * should never block since it might be called from lookup implementation
9.56 + * internal threads. If you block here you are in risk that the thread
9.57 + * you wait for might in turn to wait for the lookup internal thread to
9.58 + * finish its work.
9.59 + * @param ev event describing the change
9.60 + */
9.61 + public void resultChanged(LookupEvent ev);
9.62 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ALPairComparator.java Sat Oct 31 15:28:13 2009 +0100
10.3 @@ -0,0 +1,88 @@
10.4 +/*
10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
10.6 + *
10.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
10.8 + *
10.9 + * The contents of this file are subject to the terms of either the GNU
10.10 + * General Public License Version 2 only ("GPL") or the Common
10.11 + * Development and Distribution License("CDDL") (collectively, the
10.12 + * "License"). You may not use this file except in compliance with the
10.13 + * License. You can obtain a copy of the License at
10.14 + * http://www.netbeans.org/cddl-gplv2.html
10.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
10.16 + * specific language governing permissions and limitations under the
10.17 + * License. When distributing the software, include this License Header
10.18 + * Notice in each file and include the License file at
10.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
10.20 + * particular file as subject to the "Classpath" exception as provided
10.21 + * by Sun in the GPL Version 2 section of the License file that
10.22 + * accompanied this code. If applicable, add the following below the
10.23 + * License Header, with the fields enclosed by brackets [] replaced by
10.24 + * your own identifying information:
10.25 + * "Portions Copyrighted [year] [name of copyright owner]"
10.26 + *
10.27 + * Contributor(s):
10.28 + *
10.29 + * The Original Software is NetBeans. The Initial Developer of the Original
10.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
10.31 + * Microsystems, Inc. All Rights Reserved.
10.32 + *
10.33 + * If you wish your version of this file to be governed by only the CDDL
10.34 + * or only the GPL Version 2, indicate your decision by adding
10.35 + * "[Contributor] elects to include this software in this distribution
10.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
10.37 + * single choice of license, a recipient has the option to distribute
10.38 + * your version of this file under either the CDDL, the GPL Version 2 or
10.39 + * to extend the choice of license to its licensees as provided above.
10.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
10.41 + * Version 2 license, then the option applies only if the new code is
10.42 + * made subject to such option by the copyright holder.
10.43 + */
10.44 +package org.openide.util.lookup;
10.45 +
10.46 +import java.util.Comparator;
10.47 +import org.openide.util.lookup.AbstractLookup.Pair;
10.48 +
10.49 +
10.50 +/** Implementation of comparator for AbstractLookup.Pair
10.51 + *
10.52 + * @author Jaroslav Tulach
10.53 + */
10.54 +final class ALPairComparator implements Comparator<Pair<?>> {
10.55 + public static final Comparator<Pair<?>> DEFAULT = new ALPairComparator();
10.56 +
10.57 + /** Creates a new instance of ALPairComparator */
10.58 + private ALPairComparator() {
10.59 + }
10.60 +
10.61 + /** Compares two items.
10.62 + */
10.63 + public int compare(Pair<?> i1, Pair<?> i2) {
10.64 + int result = i1.getIndex() - i2.getIndex();
10.65 +
10.66 + if (result == 0) {
10.67 + if (i1 != i2) {
10.68 + java.io.ByteArrayOutputStream bs = new java.io.ByteArrayOutputStream();
10.69 + java.io.PrintStream ps = new java.io.PrintStream(bs);
10.70 +
10.71 + ps.println(
10.72 + "Duplicate pair in tree" + // NOI18N
10.73 + "Pair1: " + i1 + " pair2: " + i2 + " index1: " + i1.getIndex() + " index2: " +
10.74 + i2.getIndex() // NOI18N
10.75 + +" item1: " + i1.getInstance() + " item2: " + i2.getInstance() // NOI18N
10.76 + +" id1: " + Integer.toHexString(System.identityHashCode(i1)) // NOI18N
10.77 + +" id2: " + Integer.toHexString(System.identityHashCode(i2)) // NOI18N
10.78 + );
10.79 +
10.80 + // print (ps, false);
10.81 + ps.close();
10.82 +
10.83 + throw new IllegalStateException(bs.toString());
10.84 + }
10.85 +
10.86 + return 0;
10.87 + }
10.88 +
10.89 + return result;
10.90 + }
10.91 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/AbstractLookup.java Sat Oct 31 15:28:13 2009 +0100
11.3 @@ -0,0 +1,1467 @@
11.4 +/*
11.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
11.6 + *
11.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
11.8 + *
11.9 + * The contents of this file are subject to the terms of either the GNU
11.10 + * General Public License Version 2 only ("GPL") or the Common
11.11 + * Development and Distribution License("CDDL") (collectively, the
11.12 + * "License"). You may not use this file except in compliance with the
11.13 + * License. You can obtain a copy of the License at
11.14 + * http://www.netbeans.org/cddl-gplv2.html
11.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
11.16 + * specific language governing permissions and limitations under the
11.17 + * License. When distributing the software, include this License Header
11.18 + * Notice in each file and include the License file at
11.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
11.20 + * particular file as subject to the "Classpath" exception as provided
11.21 + * by Sun in the GPL Version 2 section of the License file that
11.22 + * accompanied this code. If applicable, add the following below the
11.23 + * License Header, with the fields enclosed by brackets [] replaced by
11.24 + * your own identifying information:
11.25 + * "Portions Copyrighted [year] [name of copyright owner]"
11.26 + *
11.27 + * Contributor(s):
11.28 + *
11.29 + * The Original Software is NetBeans. The Initial Developer of the Original
11.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
11.31 + * Microsystems, Inc. All Rights Reserved.
11.32 + *
11.33 + * If you wish your version of this file to be governed by only the CDDL
11.34 + * or only the GPL Version 2, indicate your decision by adding
11.35 + * "[Contributor] elects to include this software in this distribution
11.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
11.37 + * single choice of license, a recipient has the option to distribute
11.38 + * your version of this file under either the CDDL, the GPL Version 2 or
11.39 + * to extend the choice of license to its licensees as provided above.
11.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
11.41 + * Version 2 license, then the option applies only if the new code is
11.42 + * made subject to such option by the copyright holder.
11.43 + */
11.44 +package org.openide.util.lookup;
11.45 +
11.46 +import java.io.PrintStream;
11.47 +import org.openide.util.Lookup;
11.48 +import org.openide.util.LookupEvent;
11.49 +import org.openide.util.LookupListener;
11.50 +
11.51 +import java.io.IOException;
11.52 +import java.io.ObjectOutputStream;
11.53 +import java.io.Serializable;
11.54 +
11.55 +import java.lang.ref.ReferenceQueue;
11.56 +import java.lang.ref.WeakReference;
11.57 +import java.util.ArrayList;
11.58 +import java.util.Arrays;
11.59 +import java.util.Collection;
11.60 +import java.util.Collections;
11.61 +import java.util.Enumeration;
11.62 +import java.util.HashMap;
11.63 +import java.util.HashSet;
11.64 +import java.util.Iterator;
11.65 +import java.util.LinkedHashSet;
11.66 +import java.util.Map;
11.67 +import java.util.Set;
11.68 +import java.util.TreeSet;
11.69 +
11.70 +import java.util.concurrent.Executor;
11.71 +import org.netbeans.modules.openide.util.ActiveQueue;
11.72 +
11.73 +
11.74 +/** Implementation of the lookup from OpenAPIs that is based on the
11.75 + * introduction of Item. This class should provide the default way
11.76 + * of how to store (Class, Object) pairs in the lookups. It offers
11.77 + * protected methods for subclasses to register the pairs.
11.78 + * <p>Serializable since 3.27.
11.79 + * @author Jaroslav Tulach
11.80 + * @since 1.9
11.81 + */
11.82 +public class AbstractLookup extends Lookup implements Serializable {
11.83 + static final long serialVersionUID = 5L;
11.84 +
11.85 + /** lock for initialization of the maps of lookups */
11.86 + private static final Object treeLock = new Object();
11.87 +
11.88 + /** the tree that registers all items (or Integer as a treshold size) */
11.89 + private Object tree;
11.90 +
11.91 + /** count of items in to lookup */
11.92 + private int count;
11.93 +
11.94 + /** Constructor to create this lookup and associate it with given
11.95 + * Content. The content than allows the creator to invoke protected
11.96 + * methods which are not accessible for any other user of the lookup.
11.97 + *
11.98 + * @param content the content to assciate with
11.99 + *
11.100 + * @since 1.25
11.101 + */
11.102 + public AbstractLookup(Content content) {
11.103 + content.attach(this);
11.104 + }
11.105 +
11.106 + /** Constructor for testing purposes that allows specification of storage
11.107 + * as mechanism as well.
11.108 + */
11.109 + AbstractLookup(Content content, Storage<?> storage) {
11.110 + this(content);
11.111 + this.tree = storage;
11.112 + initialize();
11.113 + }
11.114 +
11.115 + /** Constructor for testing purposes that allows specification of storage
11.116 + * as mechanism as well.
11.117 + * @param trashhold number of Pair to "remain small"
11.118 + */
11.119 + AbstractLookup(Content content, Integer trashhold) {
11.120 + this(content);
11.121 + this.tree = trashhold;
11.122 + }
11.123 +
11.124 + /** Default constructor for subclasses that do not need to provide a content
11.125 + */
11.126 + protected AbstractLookup() {
11.127 + }
11.128 +
11.129 + @Override
11.130 + public String toString() {
11.131 + if (tree instanceof Storage) {
11.132 + return "AbstractLookup" + lookup(new Lookup.Template<Object>(Object.class)).allItems(); // NOI18N
11.133 + } else {
11.134 + return super.toString();
11.135 + }
11.136 + }
11.137 +
11.138 + /** Entres the storage management system.
11.139 + */
11.140 + @SuppressWarnings("unchecked")
11.141 + private <T> AbstractLookup.Storage<T> enterStorage() {
11.142 + for (;;) {
11.143 + synchronized (treeLock) {
11.144 + if (tree instanceof AbstractLookup.Storage) {
11.145 + if (tree instanceof DelegatingStorage) {
11.146 + // somebody is using the lookup right now
11.147 + DelegatingStorage del = (DelegatingStorage) tree;
11.148 +
11.149 + // check whether there is not access from the same
11.150 + // thread (can throw exception)
11.151 + del.checkForTreeModification();
11.152 +
11.153 + try {
11.154 + treeLock.wait();
11.155 + } catch (InterruptedException ex) {
11.156 + // ignore and go on
11.157 + }
11.158 +
11.159 + continue;
11.160 + } else {
11.161 + // ok, tree is initialized and nobody is using it yet
11.162 + tree = new DelegatingStorage((Storage<T>) tree);
11.163 +
11.164 + return (Storage<T>) tree;
11.165 + }
11.166 + }
11.167 +
11.168 + // first time initialization of the tree
11.169 + if (tree instanceof Integer) {
11.170 + tree = new ArrayStorage((Integer) tree);
11.171 + } else {
11.172 + tree = new ArrayStorage();
11.173 + }
11.174 + }
11.175 +
11.176 + // the tree has not yet been initilized, initialize and go on again
11.177 + initialize();
11.178 + }
11.179 + }
11.180 +
11.181 + /** Exists tree ownership.
11.182 + */
11.183 + private AbstractLookup.Storage exitStorage() {
11.184 + synchronized (treeLock) {
11.185 + AbstractLookup.Storage stor = ((DelegatingStorage) tree).exitDelegate();
11.186 + tree = stor;
11.187 + treeLock.notifyAll();
11.188 +
11.189 + return stor;
11.190 + }
11.191 + }
11.192 +
11.193 + /** Method for subclasses to initialize them selves.
11.194 + */
11.195 + protected void initialize() {
11.196 + }
11.197 +
11.198 + /** Notifies subclasses that a query is about to be processed.
11.199 + * @param template the template
11.200 + */
11.201 + protected void beforeLookup(Template<?> template) {
11.202 + }
11.203 +
11.204 + /** The method to add instance to the lookup with.
11.205 + * @param pair class/instance pair
11.206 + */
11.207 + protected final void addPair(Pair<?> pair) {
11.208 + addPairImpl(pair, null);
11.209 + }
11.210 +
11.211 + /** The method to add instance to the lookup with.
11.212 + * @param pair class/instance pair
11.213 + * @param notifyIn the executor that will handle the notification of events
11.214 + * @since 7.16
11.215 + */
11.216 + protected final void addPair(Pair<?> pair, Executor notifyIn) {
11.217 + addPairImpl(pair, notifyIn);
11.218 + }
11.219 +
11.220 + private final <Transaction> void addPairImpl(Pair<?> pair, Executor notifyIn) {
11.221 + HashSet<R> toNotify = new HashSet<R>();
11.222 +
11.223 + AbstractLookup.Storage<Transaction> t = enterStorage();
11.224 + Transaction transaction = null;
11.225 +
11.226 + try {
11.227 + transaction = t.beginTransaction(-2);
11.228 +
11.229 + if (t.add(pair, transaction)) {
11.230 + try {
11.231 + pair.setIndex(t, count++);
11.232 + } catch (IllegalStateException ex) {
11.233 + // remove the pair
11.234 + t.remove(pair, transaction);
11.235 +
11.236 + // rethrow the exception
11.237 + throw ex;
11.238 + }
11.239 +
11.240 + // if the pair is newly added and was not there before
11.241 + t.endTransaction(transaction, toNotify);
11.242 + } else {
11.243 + // just finish the process by calling endTransaction
11.244 + t.endTransaction(transaction, new HashSet<R>());
11.245 + }
11.246 + } finally {
11.247 + exitStorage();
11.248 + }
11.249 +
11.250 + notifyIn(notifyIn, toNotify);
11.251 + }
11.252 +
11.253 + /** Remove instance.
11.254 + * @param pair class/instance pair
11.255 + */
11.256 + protected final void removePair(Pair<?> pair) {
11.257 + removePairImpl(pair, null);
11.258 + }
11.259 + /** Remove instance.
11.260 + * @param pair class/instance pair
11.261 + * @param notifyIn the executor that will handle the notification of events
11.262 + * @since 7.16
11.263 + */
11.264 + protected final void removePair(Pair<?> pair, Executor notifyIn) {
11.265 + removePairImpl(pair, notifyIn);
11.266 + }
11.267 +
11.268 + private <Transaction> void removePairImpl(Pair<?> pair, Executor notifyIn) {
11.269 + HashSet<R> toNotify = new HashSet<R>();
11.270 +
11.271 + AbstractLookup.Storage<Transaction> t = enterStorage();
11.272 + Transaction transaction = null;
11.273 +
11.274 + try {
11.275 + transaction = t.beginTransaction(-1);
11.276 + t.remove(pair, transaction);
11.277 + t.endTransaction(transaction, toNotify);
11.278 + } finally {
11.279 + exitStorage();
11.280 + }
11.281 +
11.282 + notifyIn(notifyIn, toNotify);
11.283 + }
11.284 +
11.285 + /** Changes all pairs in the lookup to new values.
11.286 + * @param collection the collection of (Pair) objects
11.287 + */
11.288 + protected final void setPairs(Collection<? extends Pair> collection) {
11.289 + setPairs(collection, null);
11.290 + }
11.291 +
11.292 + /** Changes all pairs in the lookup to new values, notifies listeners
11.293 + * using provided executor.
11.294 + *
11.295 + * @param collection the collection of (Pair) objects
11.296 + * @param notifyIn the executor that will handle the notification of events
11.297 + * @since 7.16
11.298 + */
11.299 + protected final void setPairs(Collection<? extends Pair> collection, Executor notifyIn) {
11.300 + HashSet<R> listeners = setPairsAndCollectListeners(collection);
11.301 + notifyIn(notifyIn, listeners);
11.302 + }
11.303 +
11.304 + private final void notifyIn(Executor notifyIn, final HashSet<R> listeners) {
11.305 + NotifyListeners notify = new NotifyListeners(listeners);
11.306 + if (notify.shallRun()) {
11.307 + if (notifyIn == null) {
11.308 + notify.run();
11.309 + } else {
11.310 + notifyIn.execute(notify);
11.311 + }
11.312 + }
11.313 + }
11.314 +
11.315 + /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
11.316 + * @return a LinkedHashSet that can be modified
11.317 + */
11.318 + final LinkedHashSet<Pair<?>> getPairsAsLHS() {
11.319 + AbstractLookup.Storage<?> t = enterStorage();
11.320 +
11.321 + try {
11.322 + Enumeration<Pair<Object>> en = t.lookup(Object.class);
11.323 + TreeSet<Pair<?>> arr = new TreeSet<Pair<?>>(ALPairComparator.DEFAULT);
11.324 + while (en.hasMoreElements()) {
11.325 + Pair<Object> item = en.nextElement();
11.326 + arr.add(item);
11.327 + }
11.328 + return new LinkedHashSet<Pair<?>>(arr);
11.329 + } finally {
11.330 + exitStorage();
11.331 + }
11.332 + }
11.333 +
11.334 + /** Collects listeners without notification. Needed in MetaInfServicesLookup
11.335 + * right now, but maybe will become an API later.
11.336 + */
11.337 + final <Transaction> HashSet<R> setPairsAndCollectListeners(Collection<? extends Pair> collection) {
11.338 + HashSet<R> toNotify = new HashSet<R>(27);
11.339 +
11.340 + AbstractLookup.Storage<Transaction> t = enterStorage();
11.341 + Transaction transaction = null;
11.342 +
11.343 + try {
11.344 + // map between the Items and their indexes (Integer)
11.345 + HashMap<Item<?>,Info> shouldBeThere = new HashMap<Item<?>,Info>(collection.size() * 2);
11.346 +
11.347 + count = 0;
11.348 +
11.349 + Iterator it = collection.iterator();
11.350 + transaction = t.beginTransaction(collection.size());
11.351 +
11.352 + while (it.hasNext()) {
11.353 + Pair item = (Pair) it.next();
11.354 +
11.355 + if (t.add(item, transaction)) {
11.356 + // the item has not been there yet
11.357 + //t.endTransaction(transaction, toNotify);
11.358 + }
11.359 +
11.360 + // remeber the item, because it should not be removed
11.361 + shouldBeThere.put(item, new Info(count++, transaction));
11.362 +
11.363 + // arr.clear ();
11.364 + }
11.365 +
11.366 + // Object transaction = t.beginTransaction ();
11.367 + // deletes all objects that should not be there and
11.368 + t.retainAll(shouldBeThere, transaction);
11.369 +
11.370 + // collect listeners
11.371 + t.endTransaction(transaction, toNotify);
11.372 +
11.373 + /*
11.374 + // check consistency
11.375 + Enumeration en = t.lookup (java.lang.Object.class);
11.376 + boolean[] max = new boolean[count];
11.377 + int mistake = -1;
11.378 + while (en.hasMoreElements ()) {
11.379 + Pair item = (Pair)en.nextElement ();
11.380 +
11.381 + if (max[item.index]) {
11.382 + mistake = item.index;
11.383 + }
11.384 + max[item.index] = true;
11.385 + }
11.386 +
11.387 + if (mistake != -1) {
11.388 + System.err.println ("Mistake at: " + mistake);
11.389 + tree.print (System.err, true);
11.390 + }
11.391 + */
11.392 + } finally {
11.393 + exitStorage();
11.394 + }
11.395 +
11.396 + return toNotify;
11.397 + }
11.398 +
11.399 + private final void writeObject(ObjectOutputStream oos)
11.400 + throws IOException {
11.401 + AbstractLookup.Storage s = enterStorage();
11.402 +
11.403 + try {
11.404 + // #36830: Serializing only InheritanceTree no ArrayStorage
11.405 + s.beginTransaction(Integer.MAX_VALUE);
11.406 +
11.407 + // #32040: don't write half-made changes
11.408 + oos.defaultWriteObject();
11.409 + } finally {
11.410 + exitStorage();
11.411 + }
11.412 + }
11.413 +
11.414 + public final <T> T lookup(Class<T> clazz) {
11.415 + Lookup.Item<T> item = lookupItem(new Lookup.Template<T>(clazz));
11.416 + return (item == null) ? null : item.getInstance();
11.417 + }
11.418 +
11.419 + @Override
11.420 + public final <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
11.421 + AbstractLookup.this.beforeLookup(template);
11.422 +
11.423 + ArrayList<Pair<T>> list = null;
11.424 + AbstractLookup.Storage<?> t = enterStorage();
11.425 +
11.426 + try {
11.427 + Enumeration<Pair<T>> en;
11.428 +
11.429 + try {
11.430 + en = t.lookup(template.getType());
11.431 +
11.432 + return findSmallest(en, template, false);
11.433 + } catch (AbstractLookup.ISE ex) {
11.434 + // not possible to enumerate the exception, ok, copy it
11.435 + // to create new
11.436 + list = new ArrayList<Pair<T>>();
11.437 + en = t.lookup(null); // this should get all the items without any checks
11.438 +
11.439 + // the checks will be done out side of the storage
11.440 + while (en.hasMoreElements()) {
11.441 + list.add(en.nextElement());
11.442 + }
11.443 + }
11.444 + } finally {
11.445 + exitStorage();
11.446 + }
11.447 +
11.448 + return findSmallest(Collections.enumeration(list), template, true);
11.449 + }
11.450 +
11.451 + private static <T> Pair<T> findSmallest(Enumeration<Pair<T>> en, Lookup.Template<T> template, boolean deepCheck) {
11.452 + int smallest = InheritanceTree.unsorted(en) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
11.453 + Pair<T> res = null;
11.454 +
11.455 + while (en.hasMoreElements()) {
11.456 + Pair<T> item = en.nextElement();
11.457 +
11.458 + if (matches(template, item, deepCheck)) {
11.459 + if (smallest == Integer.MIN_VALUE) {
11.460 + // ok, sorted enumeration the first that matches is fine
11.461 + return item;
11.462 + } else {
11.463 + // check for the smallest item
11.464 + if (smallest > item.getIndex()) {
11.465 + smallest = item.getIndex();
11.466 + res = item;
11.467 + }
11.468 + }
11.469 + }
11.470 + }
11.471 +
11.472 + return res;
11.473 + }
11.474 +
11.475 + public final <T> Lookup.Result<T> lookup(Lookup.Template<T> template) {
11.476 + for (;;) {
11.477 + AbstractLookup.ISE toRun = null;
11.478 +
11.479 + AbstractLookup.Storage<?> t = enterStorage();
11.480 +
11.481 + try {
11.482 + R<T> r = new R<T>();
11.483 + ReferenceToResult<T> newRef = new ReferenceToResult<T>(r, this, template);
11.484 + newRef.next = t.registerReferenceToResult(newRef);
11.485 +
11.486 + return r;
11.487 + } catch (AbstractLookup.ISE ex) {
11.488 + toRun = ex;
11.489 + } finally {
11.490 + exitStorage();
11.491 + }
11.492 +
11.493 + toRun.recover(this);
11.494 +
11.495 + // and try again
11.496 + }
11.497 + }
11.498 +
11.499 + /** Notifies listeners.
11.500 + * @param allAffectedResults set of R
11.501 + */
11.502 + static final class NotifyListeners implements Runnable {
11.503 + private final ArrayList<Object> evAndListeners;
11.504 +
11.505 + public NotifyListeners(Set<R> allAffectedResults) {
11.506 + if (allAffectedResults.isEmpty()) {
11.507 + evAndListeners = null;
11.508 + return;
11.509 + }
11.510 +
11.511 + evAndListeners = new ArrayList<Object>();
11.512 + {
11.513 + for (R<?> result : allAffectedResults) {
11.514 + result.collectFires(evAndListeners);
11.515 + }
11.516 + }
11.517 + }
11.518 +
11.519 + public boolean shallRun() {
11.520 + return evAndListeners != null && !evAndListeners.isEmpty();
11.521 + }
11.522 +
11.523 + public void run() {
11.524 + Iterator it = evAndListeners.iterator();
11.525 + while (it.hasNext()) {
11.526 + LookupEvent ev = (LookupEvent)it.next();
11.527 + LookupListener l = (LookupListener)it.next();
11.528 + l.resultChanged(ev);
11.529 + }
11.530 + }
11.531 + }
11.532 +
11.533 + /**
11.534 + * Call resultChanged on all listeners.
11.535 + * @param listeners array of listeners in the format used by
11.536 + * javax.swing.EventListenerList. It means that there are Class
11.537 + * objects on even positions and the listeners on odd positions
11.538 + * @param ev the event to fire
11.539 + */
11.540 + static void notifyListeners(Object[] listeners, LookupEvent ev, Collection<Object> evAndListeners) {
11.541 + for (int i = listeners.length - 1; i >= 0; i--) {
11.542 + if (! (listeners[i] instanceof LookupListener)) {
11.543 + continue;
11.544 + }
11.545 + LookupListener ll = (LookupListener)listeners[i];
11.546 +
11.547 + try {
11.548 + if (evAndListeners != null) {
11.549 + if (ll instanceof WaitableResult) {
11.550 + WaitableResult<?> wr = (WaitableResult<?>)ll;
11.551 + wr.collectFires(evAndListeners);
11.552 + } else {
11.553 + evAndListeners.add(ev);
11.554 + evAndListeners.add(ll);
11.555 + }
11.556 + } else {
11.557 + ll.resultChanged(ev);
11.558 + }
11.559 + } catch (StackOverflowError err) {
11.560 + throw new CycleError(evAndListeners); // NOI18N
11.561 + } catch (RuntimeException e) {
11.562 + // Such as e.g. occurred in #32040. Do not halt other things.
11.563 + e.printStackTrace();
11.564 + }
11.565 + }
11.566 + }
11.567 +
11.568 + private static class CycleError extends StackOverflowError {
11.569 + private final Collection<Object> print;
11.570 + public CycleError(Collection<Object> evAndListeners) {
11.571 + this.print = evAndListeners;
11.572 + }
11.573 +
11.574 + @Override
11.575 + public String getMessage() {
11.576 + StringBuilder sb = new StringBuilder();
11.577 + sb.append("StackOverflowError, here are the listeners:\n"); // NOI18N
11.578 + for (Object o : print) {
11.579 + sb.append('\n').append(o);
11.580 + if (sb.length() > 10000) {
11.581 + break;
11.582 + }
11.583 + }
11.584 + return sb.toString();
11.585 + }
11.586 + } // end of CycleError
11.587 +
11.588 + /** A method that defines matching between Item and Template.
11.589 + * @param t template providing the criteria
11.590 + * @param item the item to match
11.591 + * @param deepCheck true if type of the pair should be tested, false if it is already has been tested
11.592 + * @return true if item matches the template requirements, false if not
11.593 + */
11.594 + static boolean matches(Template<?> t, Pair<?> item, boolean deepCheck) {
11.595 + String id = t.getId();
11.596 +
11.597 + if (id != null && !id.equals(item.getId())) {
11.598 + return false;
11.599 + }
11.600 +
11.601 + Object instance = t.getInstance();
11.602 +
11.603 + if ((instance != null) && !item.creatorOf(instance)) {
11.604 + return false;
11.605 + }
11.606 +
11.607 + if (deepCheck) {
11.608 + return item.instanceOf(t.getType());
11.609 + } else {
11.610 + return true;
11.611 + }
11.612 + }
11.613 +
11.614 + /**
11.615 + * Compares the array elements for equality.
11.616 + * @return true if all elements in the arrays are equal
11.617 + * (by calling equals(Object x) method)
11.618 + */
11.619 + private static boolean compareArrays(Object[] a, Object[] b) {
11.620 + // handle null values
11.621 + if (a == null) {
11.622 + return (b == null);
11.623 + } else {
11.624 + if (b == null) {
11.625 + return false;
11.626 + }
11.627 + }
11.628 +
11.629 + if (a.length != b.length) {
11.630 + return false;
11.631 + }
11.632 +
11.633 + for (int i = 0; i < a.length; i++) {
11.634 + // handle null values for individual elements
11.635 + if (a[i] == null) {
11.636 + if (b[i] != null) {
11.637 + return false;
11.638 + }
11.639 +
11.640 + // both are null --> ok, take next
11.641 + continue;
11.642 + } else {
11.643 + if (b[i] == null) {
11.644 + return false;
11.645 + }
11.646 + }
11.647 +
11.648 + // perform the comparison
11.649 + if (!a[i].equals(b[i])) {
11.650 + return false;
11.651 + }
11.652 + }
11.653 +
11.654 + return true;
11.655 + }
11.656 +
11.657 + /** Method to be called when a result is cleared to signal that the list
11.658 + * of all result should be checked for clearing.
11.659 + * @param template the template the result was for
11.660 + * @return true if the hash map with all items has been cleared
11.661 + */
11.662 + <T> boolean cleanUpResult(Lookup.Template<T> template) {
11.663 + AbstractLookup.Storage<?> t = enterStorage();
11.664 +
11.665 + try {
11.666 + return t.cleanUpResult(template) == null;
11.667 + } finally {
11.668 + exitStorage();
11.669 + }
11.670 + }
11.671 +
11.672 + /** Storage check for tests. */
11.673 + static boolean isSimple(AbstractLookup l) {
11.674 + return DelegatingStorage.isSimple((Storage)l.tree);
11.675 + }
11.676 +
11.677 + /** Generic support for listeners, so it can be used in other results
11.678 + * as well.
11.679 + * @param add true to add it, false to modify
11.680 + * @param l listener to modify
11.681 + * @param ref the value of the reference to listener or listener list
11.682 + * @return new value to the reference to listener or list
11.683 + */
11.684 + @SuppressWarnings("unchecked")
11.685 + static Object modifyListenerList(boolean add, LookupListener l, Object ref) {
11.686 + if (add) {
11.687 + if (ref == null) {
11.688 + return l;
11.689 + }
11.690 +
11.691 + if (ref instanceof LookupListener) {
11.692 + ArrayList arr = new ArrayList();
11.693 + arr.add(ref);
11.694 + ref = arr;
11.695 + }
11.696 +
11.697 + ((ArrayList) ref).add(l);
11.698 +
11.699 + return ref;
11.700 + } else {
11.701 + // remove
11.702 + if (ref == null) {
11.703 + return null;
11.704 + }
11.705 +
11.706 + if (ref == l) {
11.707 + return null;
11.708 + }
11.709 +
11.710 + ArrayList arr = (ArrayList) ref;
11.711 + arr.remove(l);
11.712 +
11.713 + if (arr.size() == 1) {
11.714 + return arr.iterator().next();
11.715 + } else {
11.716 + return arr;
11.717 + }
11.718 + }
11.719 + }
11.720 +
11.721 + private static ReferenceQueue<Object> activeQueue() {
11.722 + return ActiveQueue.queue();
11.723 + }
11.724 +
11.725 + /** Storage to keep the internal structure of Pairs and to answer
11.726 + * different queries.
11.727 + */
11.728 + interface Storage<Transaction> {
11.729 + /** Initializes a modification operation by creating an object
11.730 + * that will be passsed to all add, remove, retainAll methods
11.731 + * and should collect enough information about the change to
11.732 + * notify listeners about the transaction later
11.733 + *
11.734 + * @param ensure the amount of items that will appear in the storage
11.735 + * after the modifications (-1 == remove one, -2 == add one, >= 0
11.736 + * the amount of objects at the end
11.737 + * @return a token to identify the transaction
11.738 + */
11.739 + public Transaction beginTransaction(int ensure);
11.740 +
11.741 + /** Collects all affected results R that were modified in the
11.742 + * given transaction.
11.743 + *
11.744 + * @param modified place to add results R to
11.745 + * @param transaction the transaction indentification
11.746 + */
11.747 + public void endTransaction(Transaction transaction, Set<R> modifiedResults);
11.748 +
11.749 + /** Adds an item into the storage.
11.750 + * @param item to add
11.751 + * @param transaction transaction token
11.752 + * @return true if the Item has been added for the first time or false if some other
11.753 + * item equal to this one already existed in the lookup
11.754 + */
11.755 + public boolean add(AbstractLookup.Pair<?> item, Transaction transaction);
11.756 +
11.757 + /** Removes an item.
11.758 + */
11.759 + public void remove(AbstractLookup.Pair item, Transaction transaction);
11.760 +
11.761 + /** Removes all items that are not present in the provided collection.
11.762 + * @param retain collection of Pairs to keep them in
11.763 + * @param transaction the transaction context
11.764 + */
11.765 + public void retainAll(Map retain, Transaction transaction);
11.766 +
11.767 + /** Queries for instances of given class.
11.768 + * @param clazz the class to check
11.769 + * @return enumeration of Item
11.770 + * @see #unsorted
11.771 + */
11.772 + public <T> Enumeration<Pair<T>> lookup(Class<T> clazz);
11.773 +
11.774 + /** Registers another reference to a result with the storage. This method
11.775 + * has also a special meaning.
11.776 + *
11.777 + * @param newRef the new reference to remember
11.778 + * @return the previous reference that was kept (null if newRef is the first one)
11.779 + * the applications is expected to link from newRef to this returned
11.780 + * value to form a linked list
11.781 + */
11.782 + public ReferenceToResult<?> registerReferenceToResult(ReferenceToResult<?> newRef);
11.783 +
11.784 + /** Given the provided template, Do cleanup the results.
11.785 + * @param templ template of a result(s) that should be checked
11.786 + * @return null if all references for this template were cleared or one of them
11.787 + */
11.788 + public ReferenceToResult<?> cleanUpResult(Lookup.Template<?> templ);
11.789 + }
11.790 +
11.791 + /** Extension to the default lookup item that offers additional information
11.792 + * for the data structures use in AbstractLookup
11.793 + */
11.794 + public static abstract class Pair<T> extends Lookup.Item<T> implements Serializable {
11.795 + private static final long serialVersionUID = 1L;
11.796 +
11.797 + /** possition of this item in the lookup, manipulated in addPair, removePair, setPairs methods */
11.798 + private int index = -1;
11.799 +
11.800 + /** For use by subclasses. */
11.801 + protected Pair() {
11.802 + }
11.803 +
11.804 + final int getIndex() {
11.805 + return index;
11.806 + }
11.807 +
11.808 + final void setIndex(AbstractLookup.Storage<?> tree, int x) {
11.809 + if (tree == null) {
11.810 + this.index = x;
11.811 +
11.812 + return;
11.813 + }
11.814 +
11.815 + if (this.index == -1) {
11.816 + this.index = x;
11.817 + } else {
11.818 + throw new IllegalStateException("You cannot use " + this + " in more than one AbstractLookup. Prev: " + this.index + " new: " + x); // NOI18N
11.819 + }
11.820 + }
11.821 +
11.822 + /** Tests whether this item can produce object
11.823 + * of class c.
11.824 + */
11.825 + protected abstract boolean instanceOf(Class<?> c);
11.826 +
11.827 + /** Method that can test whether an instance of a class has been created
11.828 + * by this item.
11.829 + *
11.830 + * @param obj the instance
11.831 + * @return if the item has already create an instance and it is the same
11.832 + * as obj.
11.833 + */
11.834 + protected abstract boolean creatorOf(Object obj);
11.835 + }
11.836 +
11.837 + /** Result based on one instance returned.
11.838 + */
11.839 + static final class R<T> extends WaitableResult<T> {
11.840 + /** reference our result is attached to (do not modify) */
11.841 + public ReferenceToResult<T> reference;
11.842 +
11.843 + /** listeners on the results or pointer to one listener */
11.844 + private Object listeners;
11.845 +
11.846 + public R() {
11.847 + }
11.848 +
11.849 + /** Checks whether we have simple behaviour of complex.
11.850 + */
11.851 + private boolean isSimple() {
11.852 + Storage s = (Storage) reference.lookup.tree;
11.853 +
11.854 + return DelegatingStorage.isSimple(s);
11.855 + }
11.856 +
11.857 + //
11.858 + // Handling cache management for both cases, no caches
11.859 + // for simple (but mark that we needed them, so refresh can
11.860 + // be done in cloneList) and complex when all 3 types
11.861 + // of result are cached
11.862 + //
11.863 + private Object getFromCache(int indx) {
11.864 + if (isSimple()) {
11.865 + return null;
11.866 + }
11.867 +
11.868 + Object maybeArray = reference.caches;
11.869 +
11.870 + if (maybeArray instanceof Object[]) {
11.871 + return ((Object[]) maybeArray)[indx];
11.872 + }
11.873 +
11.874 + return null;
11.875 + }
11.876 +
11.877 + @SuppressWarnings("unchecked")
11.878 + private Set<Class<? extends T>> getClassesCache() {
11.879 + return (Set<Class<? extends T>>) getFromCache(0);
11.880 + }
11.881 +
11.882 + private void setClassesCache(Set s) {
11.883 + if (isSimple()) {
11.884 + // mark it as being used
11.885 + reference.caches = reference;
11.886 +
11.887 + return;
11.888 + }
11.889 +
11.890 + if (!(reference.caches instanceof Object[])) {
11.891 + reference.caches = new Object[3];
11.892 + }
11.893 +
11.894 + ((Object[]) reference.caches)[0] = s;
11.895 + }
11.896 +
11.897 + @SuppressWarnings("unchecked")
11.898 + private Collection<T> getInstancesCache() {
11.899 + return (Collection<T>) getFromCache(1);
11.900 + }
11.901 +
11.902 + private void setInstancesCache(Collection c) {
11.903 + if (isSimple()) {
11.904 + // mark it as being used
11.905 + reference.caches = reference;
11.906 +
11.907 + return;
11.908 + }
11.909 +
11.910 + if (!(reference.caches instanceof Object[])) {
11.911 + reference.caches = new Object[3];
11.912 + }
11.913 +
11.914 + ((Object[]) reference.caches)[1] = c;
11.915 + }
11.916 +
11.917 + @SuppressWarnings("unchecked")
11.918 + private Pair<T>[] getItemsCache() {
11.919 + return (Pair<T>[]) getFromCache(2);
11.920 + }
11.921 +
11.922 + private void setItemsCache(Collection<?> c) {
11.923 + if (isSimple()) {
11.924 + // mark it as being used
11.925 + reference.caches = reference;
11.926 +
11.927 + return;
11.928 + }
11.929 +
11.930 + if (!(reference.caches instanceof Object[])) {
11.931 + reference.caches = new Object[3];
11.932 + }
11.933 +
11.934 + ((Object[]) reference.caches)[2] = c.toArray(new Pair[0]);
11.935 + }
11.936 +
11.937 + private void clearCaches() {
11.938 + if (reference.caches instanceof Object[]) {
11.939 + reference.caches = new Object[3];
11.940 + }
11.941 + }
11.942 +
11.943 + /** Ok, register listeners to all classes and super classes.
11.944 + */
11.945 + public synchronized void addLookupListener(LookupListener l) {
11.946 + listeners = modifyListenerList(true, l, listeners);
11.947 + }
11.948 +
11.949 + /** Ok, register listeners to all classes and super classes.
11.950 + */
11.951 + public synchronized void removeLookupListener(LookupListener l) {
11.952 + listeners = modifyListenerList(false, l, listeners);
11.953 + }
11.954 +
11.955 + /** Delete all cached values, the template changed.
11.956 + */
11.957 + protected void collectFires(Collection<Object> evAndListeners) {
11.958 + Object[] previousItems = getItemsCache();
11.959 + clearCaches();
11.960 +
11.961 + if (previousItems != null) {
11.962 + Object[] newArray = allItemsWithoutBeforeLookup().toArray();
11.963 +
11.964 + if (compareArrays(previousItems, newArray)) {
11.965 + // do not fire any change if nothing has been changed
11.966 + return;
11.967 + }
11.968 + }
11.969 +
11.970 + LookupListener[] arr;
11.971 +
11.972 + synchronized (this) {
11.973 + if (listeners == null) {
11.974 + return;
11.975 + }
11.976 +
11.977 + if (listeners instanceof LookupListener) {
11.978 + arr = new LookupListener[] { (LookupListener) listeners };
11.979 + } else {
11.980 + ArrayList<?> l = (ArrayList<?>) listeners;
11.981 + arr = l.toArray(new LookupListener[l.size()]);
11.982 + }
11.983 + }
11.984 +
11.985 + final LookupListener[] ll = arr;
11.986 + final LookupEvent ev = new LookupEvent(this);
11.987 + notifyListeners(ll, ev, evAndListeners);
11.988 + }
11.989 +
11.990 + public Collection<T> allInstances() {
11.991 + reference.lookup.beforeLookup(reference.template);
11.992 +
11.993 + Collection<T> s = getInstancesCache();
11.994 +
11.995 + if (s != null) {
11.996 + return s;
11.997 + }
11.998 +
11.999 + Collection<Pair<T>> items = allItemsWithoutBeforeLookup();
11.1000 + ArrayList<T> list = new ArrayList<T>(items.size());
11.1001 +
11.1002 + Iterator<Pair<T>> it = items.iterator();
11.1003 +
11.1004 + while (it.hasNext()) {
11.1005 + Pair<T> item = it.next();
11.1006 + T obj = item.getInstance();
11.1007 +
11.1008 + if (reference.template.getType().isInstance(obj)) {
11.1009 + list.add(obj);
11.1010 + }
11.1011 + }
11.1012 +
11.1013 + s = Collections.unmodifiableList(list);
11.1014 + setInstancesCache(s);
11.1015 +
11.1016 + return s;
11.1017 + }
11.1018 +
11.1019 + /** Set of all classes.
11.1020 + *
11.1021 + */
11.1022 + @Override
11.1023 + public Set<Class<? extends T>> allClasses() {
11.1024 + reference.lookup.beforeLookup(reference.template);
11.1025 +
11.1026 + Set<Class<? extends T>> s = getClassesCache();
11.1027 +
11.1028 + if (s != null) {
11.1029 + return s;
11.1030 + }
11.1031 +
11.1032 + s = new HashSet<Class<? extends T>>();
11.1033 +
11.1034 + for (Pair<T> item : allItemsWithoutBeforeLookup()) {
11.1035 + Class<? extends T> clazz = item.getType();
11.1036 +
11.1037 + if (clazz != null) {
11.1038 + s.add(clazz);
11.1039 + }
11.1040 + }
11.1041 +
11.1042 + s = Collections.unmodifiableSet(s);
11.1043 + setClassesCache(s);
11.1044 +
11.1045 + return s;
11.1046 + }
11.1047 +
11.1048 + /** Items are stored directly in the allItems.
11.1049 + */
11.1050 + @Override
11.1051 + public Collection<? extends Item<T>> allItems() {
11.1052 + reference.lookup.beforeLookup(reference.template);
11.1053 +
11.1054 + return allItemsWithoutBeforeLookup();
11.1055 + }
11.1056 +
11.1057 + /** Implements the search for allItems, but without asking for before lookup */
11.1058 + private Collection<Pair<T>> allItemsWithoutBeforeLookup() {
11.1059 + Pair<T>[] c = getItemsCache();
11.1060 +
11.1061 + if (c != null) {
11.1062 + return Collections.unmodifiableList(Arrays.asList(c));
11.1063 + }
11.1064 +
11.1065 + ArrayList<Pair<Object>> saferCheck = null;
11.1066 + AbstractLookup.Storage<?> t = reference.lookup.enterStorage();
11.1067 +
11.1068 + try {
11.1069 + try {
11.1070 + return Collections.unmodifiableCollection(initItems(t));
11.1071 + } catch (AbstractLookup.ISE ex) {
11.1072 + // do less effective evaluation of items outside of the
11.1073 + // locked storage
11.1074 + saferCheck = new ArrayList<Pair<Object>>();
11.1075 +
11.1076 + Enumeration<Pair<Object>> en = t.lookup(null); // get all Pairs
11.1077 +
11.1078 + while (en.hasMoreElements()) {
11.1079 + Pair<Object> i = en.nextElement();
11.1080 + saferCheck.add(i);
11.1081 + }
11.1082 + }
11.1083 + } finally {
11.1084 + reference.lookup.exitStorage();
11.1085 + }
11.1086 + return extractPairs(saferCheck);
11.1087 + }
11.1088 +
11.1089 + @SuppressWarnings("unchecked")
11.1090 + private Collection<Pair<T>> extractPairs(final ArrayList<Pair<Object>> saferCheck) {
11.1091 + TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
11.1092 + for (Pair<Object> i : saferCheck) {
11.1093 + if (matches(reference.template, i, false)) {
11.1094 + items.add((Pair<T>)i);
11.1095 + }
11.1096 + }
11.1097 + return Collections.unmodifiableCollection(items);
11.1098 + }
11.1099 +
11.1100 + /** Initializes items.
11.1101 + */
11.1102 + private Collection<Pair<T>> initItems(Storage<?> t) {
11.1103 + // manipulation with the tree must be synchronized
11.1104 + Enumeration<Pair<T>> en = t.lookup(reference.template.getType());
11.1105 +
11.1106 + // InheritanceTree is comparator for AbstractLookup.Pairs
11.1107 + TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
11.1108 +
11.1109 + while (en.hasMoreElements()) {
11.1110 + Pair<T> i = en.nextElement();
11.1111 +
11.1112 + if (matches(reference.template, i, false)) {
11.1113 + items.add(i);
11.1114 + }
11.1115 + }
11.1116 +
11.1117 + // create a correctly sorted copy using the tree as the comparator
11.1118 + setItemsCache(items);
11.1119 +
11.1120 + return items;
11.1121 + }
11.1122 +
11.1123 + /** Used by proxy results to synchronize before lookup.
11.1124 + */
11.1125 + protected void beforeLookup(Lookup.Template t) {
11.1126 + if (t.getType() == reference.template.getType()) {
11.1127 + reference.lookup.beforeLookup(t);
11.1128 + }
11.1129 + }
11.1130 +
11.1131 + /* Do not need to implement it, the default way is ok.
11.1132 + public boolean equals(java.lang.Object obj) {
11.1133 + return obj == this;
11.1134 + }
11.1135 + */
11.1136 + @Override
11.1137 + public String toString() {
11.1138 + return super.toString() + " for " + reference.template;
11.1139 + }
11.1140 + }
11.1141 + // end of R
11.1142 +
11.1143 + /** A class that can be used by the creator of the AbstractLookup to
11.1144 + * control its content. It can be passed to AbstractLookup constructor
11.1145 + * and used to add and remove pairs.
11.1146 + *
11.1147 + * @since 1.25
11.1148 + */
11.1149 + public static class Content extends Object implements Serializable {
11.1150 + private static final long serialVersionUID = 1L;
11.1151 +
11.1152 + // one of them is always null (except attach stage)
11.1153 +
11.1154 + /** abstract lookup we are connected to */
11.1155 + private AbstractLookup al;
11.1156 + private transient Object notifyIn;
11.1157 +
11.1158 + /** Default constructor.
11.1159 + */
11.1160 + public Content() {
11.1161 + this(null);
11.1162 + }
11.1163 +
11.1164 + /** Creates a content associated with an executor to handle dispatch
11.1165 + * of changes.
11.1166 + * @param notifyIn the executor to notify changes in
11.1167 + * @since 7.16
11.1168 + */
11.1169 + public Content(Executor notifyIn) {
11.1170 + this.notifyIn = notifyIn;
11.1171 + }
11.1172 +
11.1173 + /** for testing purposes */
11.1174 + final void attachExecutor(Executor notifyIn) {
11.1175 + this.notifyIn = notifyIn;
11.1176 + }
11.1177 +
11.1178 + /** A lookup attaches to this object.
11.1179 + */
11.1180 + final synchronized void attach(AbstractLookup al) {
11.1181 + if (this.al == null) {
11.1182 + this.al = al;
11.1183 +
11.1184 + ArrayList<Pair> ep = getEarlyPairs();
11.1185 + if (ep != null) {
11.1186 + notifyIn = null;
11.1187 + setPairs(ep);
11.1188 + }
11.1189 + } else {
11.1190 + throw new IllegalStateException(
11.1191 + "Trying to use content for " + al + " but it is already used for " + this.al
11.1192 + ); // NOI18N
11.1193 + }
11.1194 + }
11.1195 +
11.1196 + /** The method to add instance to the lookup with.
11.1197 + * @param pair class/instance pair
11.1198 + */
11.1199 + public final void addPair(Pair<?> pair) {
11.1200 + AbstractLookup a = al;
11.1201 + Executor e = getExecutor();
11.1202 +
11.1203 + if (a != null || e != null) {
11.1204 + a.addPair(pair, e);
11.1205 + } else {
11.1206 + if (notifyIn == null) {
11.1207 + notifyIn = new ArrayList<Pair>(3);
11.1208 + }
11.1209 +
11.1210 + getEarlyPairs().add(pair);
11.1211 + }
11.1212 + }
11.1213 +
11.1214 + /** Remove instance.
11.1215 + * @param pair class/instance pair
11.1216 + */
11.1217 + public final void removePair(Pair<?> pair) {
11.1218 + AbstractLookup a = al;
11.1219 + Executor e = getExecutor();
11.1220 +
11.1221 + if (a != null || e != null) {
11.1222 + a.removePair(pair, e);
11.1223 + } else {
11.1224 + if (notifyIn == null) {
11.1225 + notifyIn = new ArrayList<Pair>(3);
11.1226 + }
11.1227 +
11.1228 + getEarlyPairs().remove(pair);
11.1229 + }
11.1230 + }
11.1231 +
11.1232 + /** Changes all pairs in the lookup to new values.
11.1233 + * @param c the collection of (Pair) objects
11.1234 + */
11.1235 + public final void setPairs(Collection<? extends Pair> c) {
11.1236 + AbstractLookup a = al;
11.1237 + Executor e = getExecutor();
11.1238 +
11.1239 + if (a != null || e != null) {
11.1240 + a.setPairs(c, e);
11.1241 + } else {
11.1242 + notifyIn = new ArrayList<Pair>(c);
11.1243 + }
11.1244 + }
11.1245 +
11.1246 + @SuppressWarnings("unchecked")
11.1247 + private ArrayList<Pair> getEarlyPairs() {
11.1248 + Object o = notifyIn;
11.1249 + return o instanceof ArrayList ? (ArrayList<Pair>)o : null;
11.1250 + }
11.1251 +
11.1252 + private Executor getExecutor() {
11.1253 + Object o = notifyIn;
11.1254 + return o instanceof Executor ? (Executor)o : null;
11.1255 + }
11.1256 + }
11.1257 + // end of Content
11.1258 +
11.1259 + /** Just a holder for index & modified values.
11.1260 + */
11.1261 + final static class Info extends Object {
11.1262 + public int index;
11.1263 + public Object transaction;
11.1264 +
11.1265 + public Info(int i, Object t) {
11.1266 + index = i;
11.1267 + transaction = t;
11.1268 + }
11.1269 + }
11.1270 +
11.1271 + /** Reference to a result R
11.1272 + */
11.1273 + static final class ReferenceToResult<T> extends WeakReference<R<T>> implements Runnable {
11.1274 + /** next refernece in chain, modified only from AbstractLookup or this */
11.1275 + private ReferenceToResult<?> next;
11.1276 +
11.1277 + /** the template for the result */
11.1278 + public final Template<T> template;
11.1279 +
11.1280 + /** the lookup we are attached to */
11.1281 + public final AbstractLookup lookup;
11.1282 +
11.1283 + /** caches for results */
11.1284 + public Object caches;
11.1285 +
11.1286 + /** Creates a weak refernece to a new result R in context of lookup
11.1287 + * for given template
11.1288 + */
11.1289 + private ReferenceToResult(R<T> result, AbstractLookup lookup, Template<T> template) {
11.1290 + super(result, activeQueue());
11.1291 + this.template = template;
11.1292 + this.lookup = lookup;
11.1293 + getResult().reference = this;
11.1294 + }
11.1295 +
11.1296 + /** Returns the result or null
11.1297 + */
11.1298 + R<T> getResult() {
11.1299 + return get();
11.1300 + }
11.1301 +
11.1302 + /** Cleans the reference. Implements Runnable interface, do not call
11.1303 + * directly.
11.1304 + */
11.1305 + public void run() {
11.1306 + lookup.cleanUpResult(this.template);
11.1307 + }
11.1308 +
11.1309 + /** Clones the reference list to given Storage.
11.1310 + * @param storage storage to clone to
11.1311 + */
11.1312 + public void cloneList(AbstractLookup.Storage<?> storage) {
11.1313 + ReferenceIterator it = new ReferenceIterator(this);
11.1314 +
11.1315 + while (it.next()) {
11.1316 + ReferenceToResult<?> current = it.current();
11.1317 + ReferenceToResult<?> newRef = current.cloneRef();
11.1318 + newRef.next = storage.registerReferenceToResult(newRef);
11.1319 + newRef.caches = current.caches;
11.1320 +
11.1321 + if (current.caches == current) {
11.1322 + current.getResult().initItems(storage);
11.1323 + }
11.1324 + }
11.1325 + }
11.1326 +
11.1327 + private ReferenceToResult<T> cloneRef() {
11.1328 + return new ReferenceToResult<T>(getResult(), lookup, template);
11.1329 + }
11.1330 + }
11.1331 + // end of ReferenceToResult
11.1332 +
11.1333 + /** Supporting class to iterate over linked list of ReferenceToResult
11.1334 + * Use:
11.1335 + * <PRE>
11.1336 + * ReferenceIterator it = new ReferenceIterator (this.ref);
11.1337 + * while (it.next ()) {
11.1338 + * it.current (): // do some work
11.1339 + * }
11.1340 + * this.ref = it.first (); // remember the first one
11.1341 + */
11.1342 + static final class ReferenceIterator extends Object {
11.1343 + private ReferenceToResult<?> first;
11.1344 + private ReferenceToResult<?> current;
11.1345 +
11.1346 + /** hard reference to current result, so it is not GCed meanwhile */
11.1347 + private R<?> currentResult;
11.1348 +
11.1349 + /** Initializes the iterator with first reference.
11.1350 + */
11.1351 + public ReferenceIterator(ReferenceToResult<?> first) {
11.1352 + this.first = first;
11.1353 + }
11.1354 +
11.1355 + /** Moves the current to next possition */
11.1356 + public boolean next() {
11.1357 + ReferenceToResult<?> prev;
11.1358 + ReferenceToResult<?> ref;
11.1359 +
11.1360 + if (current == null) {
11.1361 + ref = first;
11.1362 + prev = null;
11.1363 + } else {
11.1364 + prev = current;
11.1365 + ref = current.next;
11.1366 + }
11.1367 +
11.1368 + while (ref != null) {
11.1369 + R<?> result = ref.get();
11.1370 +
11.1371 + if (result == null) {
11.1372 + if (prev == null) {
11.1373 + // move the head
11.1374 + first = ref.next;
11.1375 + } else {
11.1376 + // skip over this reference
11.1377 + prev.next = ref.next;
11.1378 + }
11.1379 +
11.1380 + prev = ref;
11.1381 + ref = ref.next;
11.1382 + } else {
11.1383 + // we have found next item
11.1384 + currentResult = result;
11.1385 + current = ref;
11.1386 +
11.1387 + return true;
11.1388 + }
11.1389 + }
11.1390 +
11.1391 + currentResult = null;
11.1392 + current = null;
11.1393 +
11.1394 + return false;
11.1395 + }
11.1396 +
11.1397 + /** Access to current reference.
11.1398 + */
11.1399 + public ReferenceToResult<?> current() {
11.1400 + return current;
11.1401 + }
11.1402 +
11.1403 + /** Access to reference that is supposed to be the first one.
11.1404 + */
11.1405 + public ReferenceToResult<?> first() {
11.1406 + return first;
11.1407 + }
11.1408 + }
11.1409 +
11.1410 + /** Signals that a lookup is being modified from a lookup query.
11.1411 + *
11.1412 + * @author Jaroslav Tulach
11.1413 + */
11.1414 + static final class ISE extends IllegalStateException {
11.1415 + static final long serialVersionUID = 100L;
11.1416 +
11.1417 + /** list of jobs to execute. */
11.1418 + private java.util.List<Job> jobs;
11.1419 +
11.1420 + /** @param msg message
11.1421 + */
11.1422 + public ISE(String msg) {
11.1423 + super(msg);
11.1424 + }
11.1425 +
11.1426 + /** Registers a job to be executed partially out and partially in
11.1427 + * the lock over storage.
11.1428 + */
11.1429 + public void registerJob(Job job) {
11.1430 + if (jobs == null) {
11.1431 + jobs = new java.util.ArrayList<Job>();
11.1432 + }
11.1433 +
11.1434 + jobs.add(job);
11.1435 + }
11.1436 +
11.1437 + /** Executes the jobs outside, and then inside a locked session.
11.1438 + */
11.1439 + public void recover(AbstractLookup lookup) {
11.1440 + if (jobs == null) {
11.1441 + // no recovery plan, throw itself
11.1442 + throw this;
11.1443 + }
11.1444 +
11.1445 + for (Job j : jobs) {
11.1446 + j.before();
11.1447 + }
11.1448 +
11.1449 + AbstractLookup.Storage s = lookup.enterStorage();
11.1450 +
11.1451 + try {
11.1452 + for (Job j : jobs) {
11.1453 + j.inside();
11.1454 + }
11.1455 + } finally {
11.1456 + lookup.exitStorage();
11.1457 + }
11.1458 + }
11.1459 +
11.1460 + /** A job to be executed partially outside and partially inside
11.1461 + * the storage lock.
11.1462 + */
11.1463 + static interface Job {
11.1464 + public void before();
11.1465 +
11.1466 + public void inside();
11.1467 + }
11.1468 + }
11.1469 + // end of ISE
11.1470 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ArrayStorage.java Sat Oct 31 15:28:13 2009 +0100
12.3 @@ -0,0 +1,477 @@
12.4 +/*
12.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
12.6 + *
12.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
12.8 + *
12.9 + * The contents of this file are subject to the terms of either the GNU
12.10 + * General Public License Version 2 only ("GPL") or the Common
12.11 + * Development and Distribution License("CDDL") (collectively, the
12.12 + * "License"). You may not use this file except in compliance with the
12.13 + * License. You can obtain a copy of the License at
12.14 + * http://www.netbeans.org/cddl-gplv2.html
12.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
12.16 + * specific language governing permissions and limitations under the
12.17 + * License. When distributing the software, include this License Header
12.18 + * Notice in each file and include the License file at
12.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
12.20 + * particular file as subject to the "Classpath" exception as provided
12.21 + * by Sun in the GPL Version 2 section of the License file that
12.22 + * accompanied this code. If applicable, add the following below the
12.23 + * License Header, with the fields enclosed by brackets [] replaced by
12.24 + * your own identifying information:
12.25 + * "Portions Copyrighted [year] [name of copyright owner]"
12.26 + *
12.27 + * Contributor(s):
12.28 + *
12.29 + * The Original Software is NetBeans. The Initial Developer of the Original
12.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
12.31 + * Microsystems, Inc. All Rights Reserved.
12.32 + *
12.33 + * If you wish your version of this file to be governed by only the CDDL
12.34 + * or only the GPL Version 2, indicate your decision by adding
12.35 + * "[Contributor] elects to include this software in this distribution
12.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
12.37 + * single choice of license, a recipient has the option to distribute
12.38 + * your version of this file under either the CDDL, the GPL Version 2 or
12.39 + * to extend the choice of license to its licensees as provided above.
12.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
12.41 + * Version 2 license, then the option applies only if the new code is
12.42 + * made subject to such option by the copyright holder.
12.43 + */
12.44 +package org.openide.util.lookup;
12.45 +
12.46 +import org.openide.util.Lookup;
12.47 +
12.48 +
12.49 +
12.50 +import java.util.*;
12.51 +import org.openide.util.lookup.AbstractLookup.Pair;
12.52 +
12.53 +
12.54 +/** ArrayStorage of Pairs from AbstractLookup.
12.55 + * @author Jaroslav Tulach
12.56 + */
12.57 +final class ArrayStorage extends Object
12.58 +implements AbstractLookup.Storage<ArrayStorage.Transaction> {
12.59 + /** default trashold */
12.60 + static final Integer DEFAULT_TRASH = new Integer(11);
12.61 +
12.62 + /** list of items */
12.63 + private Object content;
12.64 +
12.65 + /** linked list of refernces to results */
12.66 + private transient AbstractLookup.ReferenceToResult<?> results;
12.67 +
12.68 + /** Constructor
12.69 + */
12.70 + public ArrayStorage() {
12.71 + this(DEFAULT_TRASH);
12.72 + }
12.73 +
12.74 + /** Constructs new ArrayStorage */
12.75 + public ArrayStorage(Integer treshhold) {
12.76 + this.content = treshhold;
12.77 + }
12.78 +
12.79 + /** Adds an item into the tree.
12.80 + * @param item to add
12.81 + * @return true if the Item has been added for the first time or false if some other
12.82 + * item equal to this one already existed in the lookup
12.83 + */
12.84 + public boolean add(AbstractLookup.Pair<?> item, Transaction changed) {
12.85 + Object[] arr = changed.current;
12.86 +
12.87 + if (changed.arr == null) {
12.88 + // just simple add of one item
12.89 + for (int i = 0; i < arr.length; i++) {
12.90 + if (arr[i] == null) {
12.91 + arr[i] = item;
12.92 + changed.add(item);
12.93 +
12.94 + return true;
12.95 + }
12.96 +
12.97 + if (arr[i].equals(item)) {
12.98 + // reassign the item number
12.99 + item.setIndex(null, ((AbstractLookup.Pair) arr[i]).getIndex());
12.100 +
12.101 + // already there, but update it
12.102 + arr[i] = item;
12.103 +
12.104 + return false;
12.105 + }
12.106 + }
12.107 +
12.108 + // cannot happen as the beginTransaction ensured we can finish
12.109 + // correctly
12.110 + throw new IllegalStateException();
12.111 + } else {
12.112 + // doing remainAll after that, let Transaction hold the new array
12.113 + int newIndex = changed.addPair(item);
12.114 +
12.115 + for (int i = 0; i < arr.length; i++) {
12.116 + if (arr[i] == null) {
12.117 + changed.add(item);
12.118 +
12.119 + return true;
12.120 + }
12.121 +
12.122 + if (arr[i].equals(item)) {
12.123 + // already there
12.124 + if (i != newIndex) {
12.125 + // change in index
12.126 + changed.add(item);
12.127 +
12.128 + return false;
12.129 + } else {
12.130 + // no change
12.131 + return false;
12.132 + }
12.133 + }
12.134 + }
12.135 +
12.136 + // if not found in the original array
12.137 + changed.add(item);
12.138 +
12.139 + return true;
12.140 + }
12.141 + }
12.142 +
12.143 + /** Removes an item.
12.144 + */
12.145 + public void remove(AbstractLookup.Pair item, Transaction changed) {
12.146 + Object[] arr = changed.current;
12.147 + if (arr == null) {
12.148 + return;
12.149 + }
12.150 +
12.151 + int found = -1;
12.152 +
12.153 + for (int i = 0; i < arr.length;) {
12.154 + if (arr[i] == null) {
12.155 + // end of task
12.156 + return;
12.157 + }
12.158 +
12.159 + if ((found == -1) && arr[i].equals(item)) {
12.160 + // already there
12.161 + Pair<?> p = (Pair<?>)arr[i];
12.162 + p.setIndex(null, -1);
12.163 + changed.add(p);
12.164 + found = i;
12.165 + }
12.166 +
12.167 + i++;
12.168 +
12.169 + if (found != -1) {
12.170 + if (i < arr.length && !(arr[i] instanceof Integer)) {
12.171 + // moving the array
12.172 + arr[i - 1] = arr[i];
12.173 + } else {
12.174 + arr[i - 1] = null;
12.175 + }
12.176 + }
12.177 + }
12.178 + }
12.179 +
12.180 + /** Removes all items that are not present in the provided collection.
12.181 + * @param retain Pair -> AbstractLookup.Info map
12.182 + * @param notify set of Classes that has possibly changed
12.183 + */
12.184 + public void retainAll(Map retain, Transaction changed) {
12.185 + Object[] arr = changed.current;
12.186 +
12.187 + for (int from = 0; from < arr.length; from++) {
12.188 + if (!(arr[from] instanceof AbstractLookup.Pair)) {
12.189 + // end of content
12.190 + break;
12.191 + }
12.192 +
12.193 + AbstractLookup.Pair p = (AbstractLookup.Pair) arr[from];
12.194 +
12.195 + AbstractLookup.Info info = (AbstractLookup.Info) retain.get(p);
12.196 +
12.197 + if (info == null) {
12.198 + // was removed
12.199 +
12.200 + /*
12.201 + if (info != null) {
12.202 + if (info.index < arr.length) {
12.203 + newArr[info.index] = p;
12.204 + }
12.205 +
12.206 + if (p.getIndex() != info.index) {
12.207 + p.setIndex (null, info.index);
12.208 + changed.add (p);
12.209 + }
12.210 + } else {
12.211 + // removed
12.212 + */
12.213 + changed.add(p);
12.214 + }
12.215 + }
12.216 + }
12.217 +
12.218 + /** Queries for instances of given class.
12.219 + * @param clazz the class to check
12.220 + * @return enumeration of Item
12.221 + * @see #unsorted
12.222 + */
12.223 + public <T> Enumeration<Pair<T>> lookup(final Class<T> clazz) {
12.224 + if (content instanceof Object[]) {
12.225 + final Enumeration<Object> all = InheritanceTree.arrayEn((Object[]) content);
12.226 + class JustPairs implements Enumeration<Pair<T>> {
12.227 + private Pair<T> next;
12.228 +
12.229 + @SuppressWarnings("unchecked")
12.230 + private Pair<T> findNext() {
12.231 + for (;;) {
12.232 + if (next != null) {
12.233 + return next;
12.234 + }
12.235 + if (!all.hasMoreElements()) {
12.236 + return null;
12.237 + }
12.238 + Object o = all.nextElement();
12.239 + boolean ok;
12.240 + if (o instanceof AbstractLookup.Pair) {
12.241 + ok = (clazz == null) || ((AbstractLookup.Pair<?>) o).instanceOf(clazz);
12.242 + } else {
12.243 + ok = false;
12.244 + }
12.245 +
12.246 + next = ok ? (Pair<T>) o : null;
12.247 + }
12.248 + }
12.249 +
12.250 + public boolean hasMoreElements() {
12.251 + return findNext() != null;
12.252 + }
12.253 +
12.254 + public Pair<T> nextElement() {
12.255 + Pair<T> r = findNext();
12.256 + if (r == null) {
12.257 + throw new NoSuchElementException();
12.258 + }
12.259 + next = null;
12.260 + return r;
12.261 + }
12.262 + } // end of JustPairs
12.263 + return new JustPairs();
12.264 + } else {
12.265 + return InheritanceTree.emptyEn();
12.266 + }
12.267 + }
12.268 +
12.269 + /** Associates another result with this storage.
12.270 + */
12.271 + public AbstractLookup.ReferenceToResult registerReferenceToResult(AbstractLookup.ReferenceToResult<?> newRef) {
12.272 + AbstractLookup.ReferenceToResult prev = this.results;
12.273 + this.results = newRef;
12.274 +
12.275 + return prev;
12.276 + }
12.277 +
12.278 + /** Cleanup the references
12.279 + */
12.280 + public AbstractLookup.ReferenceToResult cleanUpResult(Lookup.Template<?> templ) {
12.281 + AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
12.282 +
12.283 + while (it.next()) {
12.284 + // empty
12.285 + }
12.286 +
12.287 + return this.results = it.first();
12.288 + }
12.289 +
12.290 + /** We use a hash set of all modified Pair to handle the transaction */
12.291 + public Transaction beginTransaction(int ensure) {
12.292 + return new Transaction(ensure, content);
12.293 + }
12.294 +
12.295 + /** Extract all results.
12.296 + */
12.297 + public void endTransaction(Transaction changed, Set<AbstractLookup.R> modified) {
12.298 + AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
12.299 +
12.300 + if (changed.arr == null) {
12.301 + // either add or remove, only check the content of check HashSet
12.302 + while (it.next()) {
12.303 + AbstractLookup.ReferenceToResult ref = it.current();
12.304 + Iterator<Pair<?>> pairs = changed.iterator();
12.305 +
12.306 + while (pairs.hasNext()) {
12.307 + AbstractLookup.Pair p = (AbstractLookup.Pair) pairs.next();
12.308 +
12.309 + if (AbstractLookup.matches(ref.template, p, true)) {
12.310 + modified.add(ref.getResult());
12.311 + }
12.312 + }
12.313 + }
12.314 + } else {
12.315 + // do full check of changes
12.316 + while (it.next()) {
12.317 + AbstractLookup.ReferenceToResult ref = it.current();
12.318 +
12.319 + int oldIndex = -1;
12.320 + int newIndex = -1;
12.321 +
12.322 + for (;;) {
12.323 + oldIndex = findMatching(ref.template, changed.current, oldIndex);
12.324 + newIndex = findMatching(ref.template, changed.arr, newIndex);
12.325 +
12.326 + if ((oldIndex == -1) && (newIndex == -1)) {
12.327 + break;
12.328 + }
12.329 +
12.330 + if (
12.331 + (oldIndex == -1) || (newIndex == -1) ||
12.332 + !changed.current[oldIndex].equals(changed.arr[newIndex])
12.333 + ) {
12.334 + modified.add(ref.getResult());
12.335 +
12.336 + break;
12.337 + }
12.338 + }
12.339 + }
12.340 + }
12.341 +
12.342 + this.results = it.first();
12.343 + this.content = changed.newContent(this.content);
12.344 + }
12.345 +
12.346 + private static int findMatching(Lookup.Template t, Object[] arr, int from) {
12.347 + while (++from < arr.length) {
12.348 + if (arr[from] instanceof AbstractLookup.Pair) {
12.349 + if (AbstractLookup.matches(t, (AbstractLookup.Pair) arr[from], true)) {
12.350 + return from;
12.351 + }
12.352 + }
12.353 + }
12.354 +
12.355 + return -1;
12.356 + }
12.357 +
12.358 + /** HashSet with additional field for new array which is callocated
12.359 + * in case we are doing replace to hold all new items.
12.360 + */
12.361 + static final class Transaction extends HashSet<Pair<?>> {
12.362 + /** array with current objects */
12.363 + public final Object[] current;
12.364 +
12.365 + /** array with new objects */
12.366 + public final Object[] arr;
12.367 +
12.368 + /** number of objects in the array */
12.369 + private int cnt;
12.370 +
12.371 + public Transaction(int ensure, Object currentContent) {
12.372 + Integer trashold;
12.373 + Object[] _arr;
12.374 +
12.375 + if (currentContent instanceof Integer) {
12.376 + trashold = (Integer) currentContent;
12.377 + _arr = null;
12.378 + } else {
12.379 + _arr = (Object[]) currentContent;
12.380 +
12.381 + if (_arr[_arr.length - 1] instanceof Integer) {
12.382 + trashold = (Integer) _arr[_arr.length - 1];
12.383 + } else {
12.384 + // nowhere to grow we have reached the limit
12.385 + trashold = null;
12.386 + }
12.387 + }
12.388 +
12.389 + int maxSize = (trashold == null) ? _arr.length : trashold.intValue();
12.390 +
12.391 + if (ensure > maxSize) {
12.392 + throw new UnsupportedOperationException();
12.393 + }
12.394 +
12.395 + if (ensure == -1) {
12.396 + // remove => it is ok
12.397 + this.current = currentContent instanceof Integer ? null : (Object[]) currentContent;
12.398 + this.arr = null;
12.399 +
12.400 + return;
12.401 + }
12.402 +
12.403 + if (ensure == -2) {
12.404 + // adding one
12.405 + if (_arr == null) {
12.406 + // first time add, let's allocate the array
12.407 + _arr = new Object[2];
12.408 + _arr[1] = trashold;
12.409 + } else {
12.410 + if (_arr[_arr.length - 1] instanceof AbstractLookup.Pair) {
12.411 + // we are full
12.412 + throw new UnsupportedOperationException();
12.413 + } else {
12.414 + // ensure we have allocated enough space
12.415 + if (_arr.length < 2 || _arr[_arr.length - 2] != null) {
12.416 + // double the array
12.417 + int newSize = (_arr.length - 1) * 2;
12.418 +
12.419 + if (newSize <= 1) {
12.420 + newSize = 2;
12.421 + }
12.422 +
12.423 + if (newSize > maxSize) {
12.424 + newSize = maxSize;
12.425 +
12.426 + if (newSize <= _arr.length) {
12.427 + // no space to get in
12.428 + throw new UnsupportedOperationException();
12.429 + }
12.430 +
12.431 + _arr = new Object[newSize];
12.432 + } else {
12.433 + // still a lot of space
12.434 + _arr = new Object[newSize + 1];
12.435 + _arr[newSize] = trashold;
12.436 + }
12.437 +
12.438 + // copy content of original array without the last Integer into
12.439 + // the new one
12.440 + System.arraycopy(currentContent, 0, _arr, 0, ((Object[]) currentContent).length - 1);
12.441 + }
12.442 + }
12.443 + }
12.444 +
12.445 + this.current = _arr;
12.446 + this.arr = null;
12.447 + } else {
12.448 + // allocate array for complete replacement
12.449 + if (ensure == maxSize) {
12.450 + this.arr = new Object[ensure];
12.451 + } else {
12.452 + this.arr = new Object[ensure + 1];
12.453 + this.arr[ensure] = trashold;
12.454 + }
12.455 +
12.456 + this.current = (currentContent instanceof Object[]) ? (Object[]) currentContent : new Object[0];
12.457 + }
12.458 + }
12.459 +
12.460 + public int addPair(AbstractLookup.Pair<?> p) {
12.461 + p.setIndex(null, cnt);
12.462 + arr[cnt++] = p;
12.463 +
12.464 + return p.getIndex();
12.465 + }
12.466 +
12.467 + public Object newContent(Object prev) {
12.468 + if (arr == null) {
12.469 + if (current == null) {
12.470 + return prev;
12.471 + } else {
12.472 + return current;
12.473 + }
12.474 + } else {
12.475 + return arr;
12.476 + }
12.477 + }
12.478 + }
12.479 + // end of Transaction
12.480 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/Bundle.properties Sat Oct 31 15:28:13 2009 +0100
13.3 @@ -0,0 +1,1 @@
13.4 +OpenIDE-Module-Name=Lookup
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/DelegatingStorage.java Sat Oct 31 15:28:13 2009 +0100
14.3 @@ -0,0 +1,180 @@
14.4 +/*
14.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
14.6 + *
14.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
14.8 + *
14.9 + * The contents of this file are subject to the terms of either the GNU
14.10 + * General Public License Version 2 only ("GPL") or the Common
14.11 + * Development and Distribution License("CDDL") (collectively, the
14.12 + * "License"). You may not use this file except in compliance with the
14.13 + * License. You can obtain a copy of the License at
14.14 + * http://www.netbeans.org/cddl-gplv2.html
14.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
14.16 + * specific language governing permissions and limitations under the
14.17 + * License. When distributing the software, include this License Header
14.18 + * Notice in each file and include the License file at
14.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
14.20 + * particular file as subject to the "Classpath" exception as provided
14.21 + * by Sun in the GPL Version 2 section of the License file that
14.22 + * accompanied this code. If applicable, add the following below the
14.23 + * License Header, with the fields enclosed by brackets [] replaced by
14.24 + * your own identifying information:
14.25 + * "Portions Copyrighted [year] [name of copyright owner]"
14.26 + *
14.27 + * Contributor(s):
14.28 + *
14.29 + * The Original Software is NetBeans. The Initial Developer of the Original
14.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
14.31 + * Microsystems, Inc. All Rights Reserved.
14.32 + *
14.33 + * If you wish your version of this file to be governed by only the CDDL
14.34 + * or only the GPL Version 2, indicate your decision by adding
14.35 + * "[Contributor] elects to include this software in this distribution
14.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
14.37 + * single choice of license, a recipient has the option to distribute
14.38 + * your version of this file under either the CDDL, the GPL Version 2 or
14.39 + * to extend the choice of license to its licensees as provided above.
14.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
14.41 + * Version 2 license, then the option applies only if the new code is
14.42 + * made subject to such option by the copyright holder.
14.43 + */
14.44 +package org.openide.util.lookup;
14.45 +
14.46 +import org.openide.util.Lookup;
14.47 +
14.48 +import java.io.*;
14.49 +
14.50 +import java.lang.ref.WeakReference;
14.51 +
14.52 +import java.util.*;
14.53 +import org.openide.util.lookup.AbstractLookup.Pair;
14.54 +
14.55 +
14.56 +/** Storages that can switch between another storages.
14.57 + * @author Jaroslav Tulach
14.58 + */
14.59 +final class DelegatingStorage<Transaction> extends Object
14.60 +implements Serializable, AbstractLookup.Storage<Transaction> {
14.61 + /** object to delegate to */
14.62 + private AbstractLookup.Storage<Transaction> delegate;
14.63 +
14.64 + /** thread just accessing the storage */
14.65 + private Thread owner;
14.66 +
14.67 + public DelegatingStorage(AbstractLookup.Storage<Transaction> d) {
14.68 + this.delegate = d;
14.69 + this.owner = Thread.currentThread();
14.70 + }
14.71 +
14.72 + /** Never serialize yourself, always put there the delegate */
14.73 + public Object writeReplace() {
14.74 + return this.delegate;
14.75 + }
14.76 +
14.77 + /** Method to check whether there is not multiple access from the same thread.
14.78 + */
14.79 + public void checkForTreeModification() {
14.80 + if (Thread.currentThread() == owner) {
14.81 + throw new AbstractLookup.ISE("You are trying to modify lookup from lookup query!"); // NOI18N
14.82 + }
14.83 + }
14.84 +
14.85 + /** Checks whether we have simple behaviour or complex.
14.86 + */
14.87 + public static boolean isSimple(AbstractLookup.Storage s) {
14.88 + if (s instanceof DelegatingStorage) {
14.89 + return ((DelegatingStorage) s).delegate instanceof ArrayStorage;
14.90 + } else {
14.91 + return s instanceof ArrayStorage;
14.92 + }
14.93 + }
14.94 +
14.95 + /** Exits from the owners ship of the storage.
14.96 + */
14.97 + public AbstractLookup.Storage<Transaction> exitDelegate() {
14.98 + if (Thread.currentThread() != owner) {
14.99 + throw new IllegalStateException("Onwer: " + owner + " caller: " + Thread.currentThread()); // NOI18N
14.100 + }
14.101 +
14.102 + AbstractLookup.Storage<Transaction> d = delegate;
14.103 + delegate = null;
14.104 +
14.105 + return d;
14.106 + }
14.107 +
14.108 + public boolean add(AbstractLookup.Pair<?> item, Transaction transaction) {
14.109 + return delegate.add(item, transaction);
14.110 + }
14.111 +
14.112 + public void remove(org.openide.util.lookup.AbstractLookup.Pair item, Transaction transaction) {
14.113 + delegate.remove(item, transaction);
14.114 + }
14.115 +
14.116 + public void retainAll(Map retain, Transaction transaction) {
14.117 + delegate.retainAll(retain, transaction);
14.118 + }
14.119 +
14.120 + /** A special method to change the backing storage.
14.121 + * In fact it is not much typesafe as it changes the
14.122 + * type of Transaction but we know that nobody is currently
14.123 + * holding a transaction object, so there cannot be inconsitencies.
14.124 + */
14.125 + @SuppressWarnings("unchecked")
14.126 + private void changeDelegate(InheritanceTree st) {
14.127 + delegate = (AbstractLookup.Storage<Transaction>)st;
14.128 + }
14.129 +
14.130 + public Transaction beginTransaction(int ensure) {
14.131 + try {
14.132 + return delegate.beginTransaction(ensure);
14.133 + } catch (UnsupportedOperationException ex) {
14.134 + // let's convert to InheritanceTree
14.135 + ArrayStorage arr = (ArrayStorage) delegate;
14.136 + InheritanceTree inh = new InheritanceTree();
14.137 + changeDelegate(inh);
14.138 +
14.139 + //
14.140 + // Copy content
14.141 + //
14.142 + Enumeration<Pair<Object>> en = arr.lookup(Object.class);
14.143 +
14.144 + while (en.hasMoreElements()) {
14.145 + if (!inh.add(en.nextElement(), new ArrayList<Class>())) {
14.146 + throw new IllegalStateException("All objects have to be accepted"); // NOI18N
14.147 + }
14.148 + }
14.149 +
14.150 + //
14.151 + // Copy listeners
14.152 + //
14.153 + AbstractLookup.ReferenceToResult<?> ref = arr.cleanUpResult(null);
14.154 +
14.155 + if (ref != null) {
14.156 + ref.cloneList(inh);
14.157 + }
14.158 +
14.159 + // we have added the current content and now we can start transaction
14.160 + return delegate.beginTransaction(ensure);
14.161 + }
14.162 + }
14.163 +
14.164 + public org.openide.util.lookup.AbstractLookup.ReferenceToResult cleanUpResult(
14.165 + org.openide.util.Lookup.Template templ
14.166 + ) {
14.167 + return delegate.cleanUpResult(templ);
14.168 + }
14.169 +
14.170 + public void endTransaction(Transaction transaction, Set<AbstractLookup.R> modified) {
14.171 + delegate.endTransaction(transaction, modified);
14.172 + }
14.173 +
14.174 + public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
14.175 + return delegate.lookup(clazz);
14.176 + }
14.177 +
14.178 + public org.openide.util.lookup.AbstractLookup.ReferenceToResult registerReferenceToResult(
14.179 + org.openide.util.lookup.AbstractLookup.ReferenceToResult newRef
14.180 + ) {
14.181 + return delegate.registerReferenceToResult(newRef);
14.182 + }
14.183 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ExcludingLookup.java Sat Oct 31 15:28:13 2009 +0100
15.3 @@ -0,0 +1,428 @@
15.4 +/*
15.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
15.6 + *
15.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
15.8 + *
15.9 + * The contents of this file are subject to the terms of either the GNU
15.10 + * General Public License Version 2 only ("GPL") or the Common
15.11 + * Development and Distribution License("CDDL") (collectively, the
15.12 + * "License"). You may not use this file except in compliance with the
15.13 + * License. You can obtain a copy of the License at
15.14 + * http://www.netbeans.org/cddl-gplv2.html
15.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
15.16 + * specific language governing permissions and limitations under the
15.17 + * License. When distributing the software, include this License Header
15.18 + * Notice in each file and include the License file at
15.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
15.20 + * particular file as subject to the "Classpath" exception as provided
15.21 + * by Sun in the GPL Version 2 section of the License file that
15.22 + * accompanied this code. If applicable, add the following below the
15.23 + * License Header, with the fields enclosed by brackets [] replaced by
15.24 + * your own identifying information:
15.25 + * "Portions Copyrighted [year] [name of copyright owner]"
15.26 + *
15.27 + * Contributor(s):
15.28 + *
15.29 + * The Original Software is NetBeans. The Initial Developer of the Original
15.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
15.31 + * Microsystems, Inc. All Rights Reserved.
15.32 + *
15.33 + * If you wish your version of this file to be governed by only the CDDL
15.34 + * or only the GPL Version 2, indicate your decision by adding
15.35 + * "[Contributor] elects to include this software in this distribution
15.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
15.37 + * single choice of license, a recipient has the option to distribute
15.38 + * your version of this file under either the CDDL, the GPL Version 2 or
15.39 + * to extend the choice of license to its licensees as provided above.
15.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
15.41 + * Version 2 license, then the option applies only if the new code is
15.42 + * made subject to such option by the copyright holder.
15.43 + */
15.44 +package org.openide.util.lookup;
15.45 +
15.46 +import java.lang.ref.Reference;
15.47 +import java.lang.ref.WeakReference;
15.48 +import org.openide.util.Lookup;
15.49 +import org.openide.util.LookupListener;
15.50 +
15.51 +import java.util.*;
15.52 +import org.openide.util.LookupEvent;
15.53 +
15.54 +
15.55 +/** Allows exclusion of certain instances from lookup.
15.56 + *
15.57 + * @author Jaroslav Tulach
15.58 + */
15.59 +final class ExcludingLookup extends org.openide.util.Lookup {
15.60 + /** the other lookup that we delegate to */
15.61 + private Lookup delegate;
15.62 +
15.63 + /** classes to exclude (Class[]) or just one class (Class) */
15.64 + private Object classes;
15.65 +
15.66 + /**
15.67 + * Creates new Result object with supplied instances parameter.
15.68 + * @param instances to be used to return from the lookup
15.69 + */
15.70 + ExcludingLookup(Lookup delegate, Class[] classes) {
15.71 + this.delegate = delegate;
15.72 +
15.73 + for (Class c : classes) {
15.74 + if (c == null) {
15.75 + throw new NullPointerException();
15.76 + }
15.77 + }
15.78 + if (classes.length == 1) {
15.79 + this.classes = classes[0];
15.80 + } else {
15.81 + this.classes = classes;
15.82 + }
15.83 + }
15.84 +
15.85 + @Override
15.86 + public String toString() {
15.87 + return "ExcludingLookup: " + delegate + " excludes: " + Arrays.asList(classes()); // NOI18N
15.88 + }
15.89 +
15.90 + public <T> Result<T> lookup(Template<T> template) {
15.91 + if (template == null) {
15.92 + throw new NullPointerException();
15.93 + }
15.94 +
15.95 + if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
15.96 + // empty result
15.97 + return Lookup.EMPTY.lookup(template);
15.98 + }
15.99 +
15.100 + return new R<T>(template.getType(), delegate.lookup(template));
15.101 + }
15.102 +
15.103 + public <T> T lookup(Class<T> clazz) {
15.104 + if (areSubclassesOfThisClassAlwaysExcluded(clazz)) {
15.105 + return null;
15.106 + }
15.107 +
15.108 + T res = delegate.lookup(clazz);
15.109 +
15.110 + if (isObjectAccessible(clazz, res, 0)) {
15.111 + return res;
15.112 + } else {
15.113 + return null;
15.114 + }
15.115 + }
15.116 +
15.117 + @Override
15.118 + public <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
15.119 + if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
15.120 + return null;
15.121 + }
15.122 +
15.123 + Lookup.Item<T> retValue = delegate.lookupItem(template);
15.124 +
15.125 + if (isObjectAccessible(template.getType(), retValue, 2)) {
15.126 + return retValue;
15.127 + } else {
15.128 + return null;
15.129 + }
15.130 + }
15.131 +
15.132 + /** @return true if the instance of class c shall never be returned from this lookup
15.133 + */
15.134 + private boolean areSubclassesOfThisClassAlwaysExcluded(Class<?> c) {
15.135 + Class<?>[] arr = classes();
15.136 +
15.137 + for (int i = 0; i < arr.length; i++) {
15.138 + if (arr[i].isAssignableFrom(c)) {
15.139 + return true;
15.140 + }
15.141 + }
15.142 +
15.143 + return false;
15.144 + }
15.145 +
15.146 + /** Returns the array of classes this lookup filters.
15.147 + */
15.148 + final Class<?>[] classes() {
15.149 + if (classes instanceof Class[]) {
15.150 + return (Class[]) classes;
15.151 + } else {
15.152 + return new Class[] { (Class) classes };
15.153 + }
15.154 + }
15.155 +
15.156 + /** Does a check whether two classes are accessible (in the super/sub class)
15.157 + * releation ship without walking thru any of the classes mentioned in the
15.158 + * barrier.
15.159 + */
15.160 + private static boolean isAccessible(Class<?>[] barriers, Class<?> from, Class<?> to) {
15.161 + if ((to == null) || !from.isAssignableFrom(to)) {
15.162 + // no way to reach each other by walking up
15.163 + return false;
15.164 + }
15.165 +
15.166 + for (int i = 0; i < barriers.length; i++) {
15.167 + if (to == barriers[i]) {
15.168 + return false;
15.169 + }
15.170 + }
15.171 +
15.172 + if (from == to) {
15.173 + return true;
15.174 + }
15.175 +
15.176 + //
15.177 + // depth first search
15.178 + //
15.179 + if (isAccessible(barriers, from, to.getSuperclass())) {
15.180 + return true;
15.181 + }
15.182 +
15.183 + Class[] interfaces = to.getInterfaces();
15.184 +
15.185 + for (int i = 0; i < interfaces.length; i++) {
15.186 + if (isAccessible(barriers, from, interfaces[i])) {
15.187 + return true;
15.188 + }
15.189 + }
15.190 +
15.191 + return false;
15.192 + }
15.193 +
15.194 + /** based on type decides whether the class accepts or not anObject
15.195 + * @param from the base type of the query
15.196 + * @param to depending on value of type either Object, Class or Item
15.197 + * @param type 0,1,2 for Object, Class or Item
15.198 + * @return true if we can access the to from from by walking around the bariers
15.199 + */
15.200 + private final boolean isObjectAccessible(Class from, Object to, int type) {
15.201 + if (to == null) {
15.202 + return false;
15.203 + }
15.204 +
15.205 + return isObjectAccessible(classes(), from, to, type);
15.206 + }
15.207 +
15.208 + /** based on type decides whether the class accepts or not anObject
15.209 + * @param barriers classes to avoid when testing reachability
15.210 + * @param from the base type of the query
15.211 + * @param to depending on value of type either Object, Class or Item
15.212 + * @param type 0,1,2 for Object, Class or Item
15.213 + * @return true if we can access the to from from by walking around the bariers
15.214 + */
15.215 + static final boolean isObjectAccessible(Class[] barriers, Class from, Object to, int type) {
15.216 + if (to == null) {
15.217 + return false;
15.218 + }
15.219 +
15.220 + switch (type) {
15.221 + case 0:
15.222 + return isAccessible(barriers, from, to.getClass());
15.223 +
15.224 + case 1:
15.225 + return isAccessible(barriers, from, (Class) to);
15.226 +
15.227 + case 2: {
15.228 + Item item = (Item) to;
15.229 +
15.230 + return isAccessible(barriers, from, item.getType());
15.231 + }
15.232 +
15.233 + default:
15.234 + throw new IllegalStateException("Type: " + type);
15.235 + }
15.236 + }
15.237 +
15.238 + /** Filters collection accroding to set of given filters.
15.239 + */
15.240 + final <E, T extends Collection<E>> T filter(
15.241 + Class<?>[] arr, Class<?> from, T c, int type, T prototype
15.242 + ) {
15.243 + T ret = null;
15.244 +
15.245 +
15.246 +// optimistic strategy expecting we will not need to filter
15.247 +TWICE:
15.248 + for (;;) {
15.249 + Iterator<E> it = c.iterator();
15.250 +BIG:
15.251 + while (it.hasNext()) {
15.252 + E res = it.next();
15.253 +
15.254 + if (!isObjectAccessible(arr, from, res, type)) {
15.255 + if (ret == null) {
15.256 + // we need to restart the scanning again
15.257 + // as there is an active filter
15.258 + ret = prototype;
15.259 + continue TWICE;
15.260 + }
15.261 +
15.262 + continue BIG;
15.263 + }
15.264 +
15.265 + if (ret != null) {
15.266 + // if we are running the second round from TWICE
15.267 + ret.add(res);
15.268 + }
15.269 + }
15.270 +
15.271 + // ok, processed
15.272 + break TWICE;
15.273 + }
15.274 +
15.275 + return (ret != null) ? ret : c;
15.276 + }
15.277 +
15.278 + /** Delegating result that filters unwanted items and instances.
15.279 + */
15.280 + private final class R<T> extends WaitableResult<T> implements LookupListener {
15.281 + private Result<T> result;
15.282 + private WeakResult<T> weak;
15.283 + private Object listeners;
15.284 + private Class<?> from;
15.285 +
15.286 + R(Class<?> from, Result<T> delegate) {
15.287 + this.from = from;
15.288 + this.result = delegate;
15.289 + this.weak = new WeakResult<T>(this, delegate);
15.290 + }
15.291 +
15.292 + protected void beforeLookup(Template t) {
15.293 + if (result instanceof WaitableResult) {
15.294 + ((WaitableResult) result).beforeLookup(t);
15.295 + }
15.296 + }
15.297 +
15.298 + public void addLookupListener(LookupListener l) {
15.299 + boolean add;
15.300 +
15.301 + synchronized (this) {
15.302 + listeners = AbstractLookup.modifyListenerList(true, l, listeners);
15.303 + add = listeners != null;
15.304 + }
15.305 +
15.306 + if (add) {
15.307 + result.addLookupListener(weak);
15.308 + }
15.309 + }
15.310 +
15.311 + public void removeLookupListener(LookupListener l) {
15.312 + boolean remove;
15.313 +
15.314 + synchronized (this) {
15.315 + listeners = AbstractLookup.modifyListenerList(false, l, listeners);
15.316 + remove = listeners == null;
15.317 + }
15.318 +
15.319 + if (remove) {
15.320 + result.removeLookupListener(weak);
15.321 + }
15.322 + }
15.323 +
15.324 + public Collection<? extends T> allInstances() {
15.325 + return openCol(result.allInstances(), 0);
15.326 + }
15.327 +
15.328 + private <S> Collection<S> openCol(Collection<S> c, int type) {
15.329 + return filter(classes(), from, c, type, new ArrayList<S>(c.size()));
15.330 + }
15.331 +
15.332 + @Override
15.333 + public Set<Class<? extends T>> allClasses() {
15.334 + return filter(classes(), from, result.allClasses(), 1, new HashSet<Class<? extends T>>());
15.335 + }
15.336 +
15.337 + @Override
15.338 + public Collection<? extends Item<T>> allItems() {
15.339 + return openCol(result.allItems(), 2);
15.340 + }
15.341 +
15.342 + public void resultChanged(org.openide.util.LookupEvent ev) {
15.343 + if (ev.getSource() == result) {
15.344 + collectFires(null);
15.345 + }
15.346 + }
15.347 +
15.348 + protected void collectFires(Collection<Object> evAndListeners) {
15.349 + LookupListener[] arr;
15.350 +
15.351 + synchronized (this) {
15.352 + if (listeners == null) {
15.353 + return;
15.354 + }
15.355 +
15.356 + if (listeners instanceof LookupListener) {
15.357 + arr = new LookupListener[] { (LookupListener) listeners };
15.358 + } else {
15.359 + ArrayList<?> l = (ArrayList<?>) listeners;
15.360 + arr = l.toArray(new LookupListener[l.size()]);
15.361 + }
15.362 + }
15.363 +
15.364 + final LookupListener[] ll = arr;
15.365 + final org.openide.util.LookupEvent newev = new org.openide.util.LookupEvent(this);
15.366 + AbstractLookup.notifyListeners(ll, newev, evAndListeners);
15.367 + }
15.368 + } // end of R
15.369 +
15.370 + private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
15.371 + private Lookup.Result source;
15.372 + private Reference<R<T>> result;
15.373 +
15.374 + public WeakResult(R<T> r, Lookup.Result<T> s) {
15.375 + this.result = new WeakReference<R<T>>(r);
15.376 + this.source = s;
15.377 + }
15.378 +
15.379 + protected void beforeLookup(Lookup.Template t) {
15.380 + R r = (R)result.get();
15.381 + if (r != null) {
15.382 + r.beforeLookup(t);
15.383 + } else {
15.384 + source.removeLookupListener(this);
15.385 + }
15.386 + }
15.387 +
15.388 + protected void collectFires(Collection<Object> evAndListeners) {
15.389 + R<T> r = result.get();
15.390 + if (r != null) {
15.391 + r.collectFires(evAndListeners);
15.392 + } else {
15.393 + source.removeLookupListener(this);
15.394 + }
15.395 + }
15.396 +
15.397 + public void addLookupListener(LookupListener l) {
15.398 + assert false;
15.399 + }
15.400 +
15.401 + public void removeLookupListener(LookupListener l) {
15.402 + assert false;
15.403 + }
15.404 +
15.405 + public Collection<T> allInstances() {
15.406 + assert false;
15.407 + return null;
15.408 + }
15.409 +
15.410 + public void resultChanged(LookupEvent ev) {
15.411 + R r = (R)result.get();
15.412 + if (r != null) {
15.413 + r.resultChanged(ev);
15.414 + } else {
15.415 + source.removeLookupListener(this);
15.416 + }
15.417 + }
15.418 +
15.419 + @Override
15.420 + public Collection<? extends Item<T>> allItems() {
15.421 + assert false;
15.422 + return null;
15.423 + }
15.424 +
15.425 + @Override
15.426 + public Set<Class<? extends T>> allClasses() {
15.427 + assert false;
15.428 + return null;
15.429 + }
15.430 + } // end of WeakResult
15.431 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/InheritanceTree.java Sat Oct 31 15:28:13 2009 +0100
16.3 @@ -0,0 +1,1276 @@
16.4 +/*
16.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
16.6 + *
16.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
16.8 + *
16.9 + * The contents of this file are subject to the terms of either the GNU
16.10 + * General Public License Version 2 only ("GPL") or the Common
16.11 + * Development and Distribution License("CDDL") (collectively, the
16.12 + * "License"). You may not use this file except in compliance with the
16.13 + * License. You can obtain a copy of the License at
16.14 + * http://www.netbeans.org/cddl-gplv2.html
16.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16.16 + * specific language governing permissions and limitations under the
16.17 + * License. When distributing the software, include this License Header
16.18 + * Notice in each file and include the License file at
16.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
16.20 + * particular file as subject to the "Classpath" exception as provided
16.21 + * by Sun in the GPL Version 2 section of the License file that
16.22 + * accompanied this code. If applicable, add the following below the
16.23 + * License Header, with the fields enclosed by brackets [] replaced by
16.24 + * your own identifying information:
16.25 + * "Portions Copyrighted [year] [name of copyright owner]"
16.26 + *
16.27 + * Contributor(s):
16.28 + *
16.29 + * The Original Software is NetBeans. The Initial Developer of the Original
16.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
16.31 + * Microsystems, Inc. All Rights Reserved.
16.32 + *
16.33 + * If you wish your version of this file to be governed by only the CDDL
16.34 + * or only the GPL Version 2, indicate your decision by adding
16.35 + * "[Contributor] elects to include this software in this distribution
16.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
16.37 + * single choice of license, a recipient has the option to distribute
16.38 + * your version of this file under either the CDDL, the GPL Version 2 or
16.39 + * to extend the choice of license to its licensees as provided above.
16.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
16.41 + * Version 2 license, then the option applies only if the new code is
16.42 + * made subject to such option by the copyright holder.
16.43 + */
16.44 +package org.openide.util.lookup;
16.45 +
16.46 +import org.openide.util.Lookup;
16.47 +import org.openide.util.lookup.AbstractLookup.Pair;
16.48 +import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
16.49 +import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
16.50 +
16.51 +import java.io.*;
16.52 +
16.53 +import java.lang.ref.WeakReference;
16.54 +
16.55 +import java.util.*;
16.56 +
16.57 +
16.58 +/** A tree to represent classes with inheritance. Description of the
16.59 + * data structure by Petr Nejedly:
16.60 + * <P>
16.61 + * So pretend I'm Lookup implementation. I've got a bunch of Items (e.g.
16.62 + * setPairs() method),
16.63 + * didn't do anything on them yet (no startup penalty) so I know nothing
16.64 + * about them.
16.65 + * Then I'll be asked for all instances implementing given interface or a
16.66 + * class. I surely need
16.67 + * to check all the Items now, as I don't know anything abou them. I surely
16.68 + * don't want to call
16.69 + * Item.getClass() as it will dismiss the whole effort. So all I have is
16.70 + * Item.instanceOf()
16.71 + * and I'll call it on every Item. I'll cache results, so the next time
16.72 + * you'll ask me for
16.73 + * the same interface/class, I'll answer immediatelly. But what if you ask
16.74 + * me for another
16.75 + * interface/class? I'll have to scan all Items for it again, unless I can
16.76 + * be sure some
16.77 + * of them can't implement it. The only source of this knowledge are the
16.78 + * previous questions
16.79 + * and my rulings on them. Here the algorithm have to be split into two
16.80 + * paths. If you
16.81 + * previously asked me for interfaces only, I'll have no hint for
16.82 + * subsequent queries,
16.83 + * but if you asked me for a class in history, and then for another class
16.84 + * and these classes
16.85 + * are not in inheritance relation (I can check hierarchy of lookup
16.86 + * arguments, because
16.87 + * they are already resolved/loaded) I can tell that those returned in
16.88 + * previous query can't
16.89 + * implement the newly asked class (they are in different hierarchy branch)
16.90 + * and I need to
16.91 + * ask less Items.
16.92 + * <P>
16.93 + * So if we use mostly classes for asking for services (and it is a trend
16.94 + * to use
16.95 + * abstract classes for this purpose in IDE anyway), this could be usable.
16.96 + * <P>
16.97 + * The data structure for separating the Items based on previous queries is
16.98 + * simple
16.99 + * tree, with every node tagged with one class. The tree's root is,
16.100 + * naturally,
16.101 + * java.lang.Object, is marked invited and initially contains all the
16.102 + * Items.
16.103 + * For every class query, the missing part of class hierarchy tree is
16.104 + * created,
16.105 + * the node of the class looked up is marked as invited and all Items from
16.106 + * nearest
16.107 + * invited parent (sperclass) are dragged to this node. The result are then
16.108 + * all
16.109 + * Items from this node and all the nodes deeper in hierarchy. Because it
16.110 + * may
16.111 + * be too complicated to walk through the children nodes, the results could
16.112 + * be
16.113 + * cached in the map.
16.114 + * For interface lookup, there is a little hint in reality (interfaces
16.115 + * and superinterfaces), but it would be harder to exploit it, so we could
16.116 + * fall-back
16.117 + * to walking through all the Items and cache results.
16.118 + *
16.119 + *
16.120 + * @author Jaroslav Tulach
16.121 + */
16.122 +final class InheritanceTree extends Object
16.123 +implements Serializable, AbstractLookup.Storage<ArrayList<Class>> {
16.124 + private static final long serialVersionUID = 1L;
16.125 +
16.126 + /** the root item (represents Object) */
16.127 + private transient Node object;
16.128 +
16.129 + /** Map of queried interfaces.
16.130 + * <p>Type: <code>Map<Class, (Collection<AbstractLookup.Pair> | AbstractLookup.Pair)></code>
16.131 + */
16.132 + private transient Map<Class,Object> interfaces;
16.133 +
16.134 + /** Map (Class, ReferenceToResult) of all listeners that are waiting in
16.135 + * changes in class Class
16.136 + */
16.137 + private transient Map<Class,ReferenceToResult> reg;
16.138 +
16.139 + /** Constructor
16.140 + */
16.141 + public InheritanceTree() {
16.142 + object = new Node(java.lang.Object.class);
16.143 + }
16.144 +
16.145 + private void writeObject(ObjectOutputStream oos) throws IOException {
16.146 + oos.writeObject(object);
16.147 +
16.148 + if (interfaces != null) {
16.149 + Iterator it = interfaces.entrySet().iterator();
16.150 +
16.151 + while (it.hasNext()) {
16.152 + Map.Entry e = (Map.Entry) it.next();
16.153 + Class c = (Class) e.getKey();
16.154 + oos.writeObject(c.getName());
16.155 +
16.156 + Object o = e.getValue();
16.157 +
16.158 + if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
16.159 + throw new ClassCastException(String.valueOf(o));
16.160 + }
16.161 +
16.162 + oos.writeObject(o);
16.163 + }
16.164 + }
16.165 +
16.166 + oos.writeObject(null);
16.167 + }
16.168 +
16.169 + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
16.170 + object = (Node) ois.readObject();
16.171 + interfaces = new WeakHashMap<Class,Object>();
16.172 +
16.173 + String clazz;
16.174 + ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
16.175 +
16.176 + while ((clazz = (String) ois.readObject()) != null) {
16.177 + Object o = ois.readObject();
16.178 +
16.179 + if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
16.180 + throw new ClassCastException(String.valueOf(o));
16.181 + }
16.182 +
16.183 + Class c = Class.forName(clazz, false, l);
16.184 + interfaces.put(c, o);
16.185 + }
16.186 + }
16.187 +
16.188 + /** Adds an item into the tree.
16.189 + * @param item to add
16.190 + * @return true if the Item has been added for the first time or false if some other
16.191 + * item equal to this one already existed in the lookup
16.192 + */
16.193 + public boolean add(AbstractLookup.Pair<?> item, ArrayList<Class> affected) {
16.194 + Node node = registerClass(object, item);
16.195 +
16.196 + affected.add(node.getType());
16.197 +
16.198 + if (node.assignItem(this, item)) {
16.199 + // this is the first item added to n.items
16.200 + // ok, we have to test interfaces too
16.201 + } else {
16.202 + // equal item is already there => stop processing
16.203 + return false;
16.204 + }
16.205 +
16.206 + boolean registeredAsInterface = registerInterface(item, affected);
16.207 +
16.208 + return registeredAsInterface;
16.209 + }
16.210 +
16.211 + /** Removes an item.
16.212 + */
16.213 + public void remove(AbstractLookup.Pair item, ArrayList<Class> affected) {
16.214 + Node n = removeClass(object, item);
16.215 +
16.216 + if (n != null) {
16.217 + affected.add(n.getType());
16.218 + }
16.219 +
16.220 + removeInterface(item, affected);
16.221 + }
16.222 +
16.223 + /** Removes all items that are not present in the provided collection.
16.224 + * @param retain collection of Pairs to keep them in
16.225 + * @param notify set of Classes that has possibly changed
16.226 + */
16.227 + public void retainAll(Map retain, ArrayList<Class> notify) {
16.228 + retainAllInterface(retain, notify);
16.229 + retainAllClasses(object, retain, notify);
16.230 + }
16.231 +
16.232 + /** Queries for instances of given class.
16.233 + * @param clazz the class to check
16.234 + * @return enumeration of Item
16.235 + * @see #unsorted
16.236 + */
16.237 + @SuppressWarnings("unchecked")
16.238 + public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
16.239 + if ((clazz != null) && clazz.isInterface()) {
16.240 + return (Enumeration)searchInterface(clazz);
16.241 + } else {
16.242 + return (Enumeration)searchClass(object, clazz);
16.243 + }
16.244 + }
16.245 +
16.246 + /** A method to check whether the enumeration returned from
16.247 + * lookup method is sorted or is not
16.248 + * @param en enumeration to check
16.249 + * @return true if it is unsorted and needs to be sorted to find
16.250 + * pair with smallest index
16.251 + */
16.252 + public static boolean unsorted(Enumeration en) {
16.253 + return en instanceof NeedsSortEnum;
16.254 + }
16.255 +
16.256 + /** Prints debug messages.
16.257 + * @param out stream to output to
16.258 + * @param instances print also instances of the
16.259 + */
16.260 + public void print(java.io.PrintStream out, boolean instances) {
16.261 + printNode(object, "", out, instances); // NOI18N
16.262 + }
16.263 +
16.264 + //
16.265 + // methods to work on classes which are not interfaces
16.266 + //
16.267 +
16.268 + /** Searches the subtree and register the item where necessary.
16.269 + * @return the node that should contain the item
16.270 + */
16.271 + private static Node registerClass(Node n, AbstractLookup.Pair item) {
16.272 + if (!n.accepts(item)) {
16.273 + return null;
16.274 + }
16.275 +
16.276 + if (n.children != null) {
16.277 + Iterator it = n.children.iterator();
16.278 +
16.279 + for (;;) {
16.280 + Node ch = extractNode(it);
16.281 +
16.282 + if (ch == null) {
16.283 + break;
16.284 + }
16.285 +
16.286 + Node result = registerClass(ch, item);
16.287 +
16.288 + if (result != null) {
16.289 + // it is in subclass, in case of classes, it cannot
16.290 + // be any other class
16.291 + return result;
16.292 + }
16.293 + }
16.294 + }
16.295 +
16.296 + // ok, nobody of our subclasses wants the class, I'll take it
16.297 + return n;
16.298 + }
16.299 +
16.300 + /** Removes the item from the tree of objects.
16.301 + * @return most narrow class that this item was removed from
16.302 + */
16.303 + private static Node removeClass(Node n, AbstractLookup.Pair item) {
16.304 + if (!n.accepts(item)) {
16.305 + return null;
16.306 + }
16.307 +
16.308 + if ((n.items != null) && n.items.remove(item)) {
16.309 + // this node really contains the item
16.310 + return n;
16.311 + }
16.312 +
16.313 + if (n.children != null) {
16.314 + Iterator it = n.children.iterator();
16.315 +
16.316 + for (;;) {
16.317 + Node ch = extractNode(it);
16.318 +
16.319 + if (ch == null) {
16.320 + break;
16.321 + }
16.322 +
16.323 + Node result = removeClass(ch, item);
16.324 +
16.325 + // If the children node was emptied, remove it if possible.
16.326 + if (((ch.items == null) || ch.items.isEmpty()) && ((ch.children == null) || ch.children.isEmpty())) {
16.327 + it.remove();
16.328 + }
16.329 +
16.330 + if (result != null) {
16.331 + // it is in subclass, in case of classes, it cannot
16.332 + // be any other class
16.333 + return result;
16.334 + }
16.335 + }
16.336 + }
16.337 +
16.338 + // nobody found
16.339 + return null;
16.340 + }
16.341 +
16.342 + /** Finds a node that represents a class.
16.343 + * @param n node to search from
16.344 + * @param clazz the clazz to find
16.345 + * @return node that represents clazz in the tree or null if the clazz is not
16.346 + * represented under the node n
16.347 + */
16.348 + private Node classToNode(final Node n, final Class<?> clazz) {
16.349 + if (!n.accepts(clazz)) {
16.350 + // nothing from us
16.351 + return null;
16.352 + }
16.353 +
16.354 + if (n.getType() == clazz) {
16.355 + // we have found what we need
16.356 + return n;
16.357 + }
16.358 +
16.359 + if (n.children != null) {
16.360 + // have to proceed to children
16.361 + Iterator it = n.children.iterator();
16.362 +
16.363 + for (;;) {
16.364 + final Node ch = extractNode(it);
16.365 +
16.366 + if (ch == null) {
16.367 + break;
16.368 + }
16.369 +
16.370 + Node found = classToNode(ch, clazz);
16.371 +
16.372 + if ((found != null) && ch.deserialized()) {
16.373 + class VerifyJob implements AbstractLookup.ISE.Job {
16.374 + private AbstractLookup.Pair<?>[] pairs;
16.375 + private boolean[] answers;
16.376 +
16.377 + public VerifyJob(Collection<Pair> items) {
16.378 + if (items != null) {
16.379 + pairs = items.toArray(new AbstractLookup.Pair[0]);
16.380 + }
16.381 + }
16.382 +
16.383 + public void before() {
16.384 + // make sure the node is converted into deserialized state
16.385 + ch.deserialized();
16.386 +
16.387 + if (pairs != null) {
16.388 + answers = new boolean[pairs.length];
16.389 +
16.390 + for (int i = 0; i < pairs.length; i++) {
16.391 + answers[i] = pairs[i].instanceOf(clazz);
16.392 + }
16.393 + }
16.394 + }
16.395 +
16.396 + public void inside() {
16.397 + if (pairs != null) {
16.398 + for (int i = 0; i < pairs.length; i++) {
16.399 + if (answers[i]) {
16.400 + ch.assignItem(InheritanceTree.this, pairs[i]);
16.401 + n.items.remove(pairs[i]);
16.402 + }
16.403 + }
16.404 + }
16.405 +
16.406 + if (n.children != null) {
16.407 + // consolidate all nodes that represent the same class
16.408 + HashMap<Class,Node> nodes = new HashMap<Class,Node>(n.children.size() * 3);
16.409 +
16.410 + Iterator child = n.children.iterator();
16.411 +
16.412 + while (child.hasNext()) {
16.413 + Node node = extractNode(child);
16.414 + if (node == null) {
16.415 + continue;
16.416 + }
16.417 + Node prev = nodes.put(node.getType(), node);
16.418 +
16.419 + if (prev != null) {
16.420 + child.remove();
16.421 + nodes.put(node.getType(), prev);
16.422 +
16.423 + // mark as being deserialized
16.424 + prev.markDeserialized();
16.425 +
16.426 + if (prev.children == null) {
16.427 + prev.children = node.children;
16.428 + } else {
16.429 + if (node.children != null) {
16.430 + prev.children.addAll(node.children);
16.431 + }
16.432 + }
16.433 +
16.434 + if (node.items != null) {
16.435 + Iterator items = node.items.iterator();
16.436 +
16.437 + while (items.hasNext()) {
16.438 + AbstractLookup.Pair item = (AbstractLookup.Pair) items.next();
16.439 + prev.assignItem(InheritanceTree.this, item);
16.440 + }
16.441 + }
16.442 + }
16.443 + }
16.444 + }
16.445 + }
16.446 + }
16.447 +
16.448 + VerifyJob verify = new VerifyJob(n.items);
16.449 +
16.450 + try {
16.451 + verify.before();
16.452 + } catch (AbstractLookup.ISE ex) {
16.453 + // mark deserialized again
16.454 + ch.markDeserialized();
16.455 + ex.registerJob(verify);
16.456 + throw ex;
16.457 + }
16.458 +
16.459 + verify.inside();
16.460 +
16.461 + found = classToNode(ch, clazz);
16.462 + }
16.463 +
16.464 + if (found != null) {
16.465 + // class found in one of subnodes
16.466 + return found;
16.467 + }
16.468 + }
16.469 + }
16.470 +
16.471 + class TwoJobs implements AbstractLookup.ISE.Job {
16.472 + private AbstractLookup.Pair[] pairs;
16.473 + private boolean[] answers;
16.474 + private Node newNode;
16.475 +
16.476 + public void before() {
16.477 + // have to create new subnode and possibly reparent one of my own
16.478 + // but all changes can be done only if we will not be interrupted from
16.479 + // outside - e.g. instanceOf methods will not throw exception
16.480 + // first of all let's compute the answers to method instanceOf
16.481 + AbstractLookup.Pair[] arr = null;
16.482 + boolean[] boolArr = null;
16.483 +
16.484 + if (n.items != null) {
16.485 + arr = new AbstractLookup.Pair[n.items.size()];
16.486 + boolArr = new boolean[n.items.size()];
16.487 +
16.488 + int i = 0;
16.489 + Iterator<Pair> it = n.items.iterator();
16.490 +
16.491 + while (it.hasNext()) {
16.492 + AbstractLookup.Pair<?> item = it.next();
16.493 + arr[i] = item;
16.494 + boolArr[i] = item.instanceOf(clazz);
16.495 + i++;
16.496 + }
16.497 + }
16.498 +
16.499 + pairs = arr;
16.500 + answers = boolArr;
16.501 + }
16.502 +
16.503 + public void inside() {
16.504 + // test if the query has not chagned since
16.505 + if (pairs != null) {
16.506 + if (!Arrays.equals(n.items.toArray(), pairs)) {
16.507 + // ok, let try once more
16.508 + return;
16.509 + }
16.510 + }
16.511 +
16.512 + internal();
16.513 + }
16.514 +
16.515 + public void internal() {
16.516 + ArrayList<Node> reparent = null;
16.517 +
16.518 + if (n.children == null) {
16.519 + n.children = new ArrayList<Node>();
16.520 + } else {
16.521 + // scan thru all my nodes if some of them are not a subclass
16.522 + // of clazz => then they would need to become child of newNode
16.523 + Iterator it = n.children.iterator();
16.524 +
16.525 + for (;;) {
16.526 + Node r = extractNode(it);
16.527 +
16.528 + if (r == null) {
16.529 + break;
16.530 + }
16.531 +
16.532 + if (clazz.isAssignableFrom(r.getType())) {
16.533 + if (reparent == null) {
16.534 + reparent = new ArrayList<Node>();
16.535 + }
16.536 +
16.537 + reparent.add(r);
16.538 + it.remove();
16.539 + }
16.540 + }
16.541 + }
16.542 +
16.543 + newNode = new Node(clazz);
16.544 + n.children.add(newNode);
16.545 +
16.546 + if (reparent != null) {
16.547 + // reassing reparent node as a child of newNode
16.548 + newNode.children = reparent;
16.549 + }
16.550 +
16.551 + // now take all my items that are instances of that class and
16.552 + // reasign them
16.553 + if (n.items != null) {
16.554 + Iterator it = n.items.iterator();
16.555 + int i = 0;
16.556 +
16.557 + while (it.hasNext()) {
16.558 + AbstractLookup.Pair item = (AbstractLookup.Pair) it.next();
16.559 +
16.560 + if (answers[i]) { // answers[i] is precomputed value of item.instanceOf (clazz))
16.561 + it.remove();
16.562 + newNode.assignItem(InheritanceTree.this, pairs[i]);
16.563 + }
16.564 +
16.565 + i++;
16.566 + }
16.567 + }
16.568 + }
16.569 + }
16.570 +
16.571 + TwoJobs j = new TwoJobs();
16.572 +
16.573 + try {
16.574 + j.before();
16.575 + } catch (AbstractLookup.ISE ex) {
16.576 + // ok, it is not possible to call instanceOf now, let's
16.577 + // schedule it for later
16.578 + // so register recovery job
16.579 + ex.registerJob(j);
16.580 + throw ex;
16.581 + }
16.582 +
16.583 + j.internal();
16.584 +
16.585 + // newNode represents my clazz
16.586 + return j.newNode;
16.587 + }
16.588 +
16.589 + /** Search for a requested class.
16.590 + * @return enumeration of Pair
16.591 + */
16.592 + private Enumeration<Pair> searchClass(Node n, Class<?> clazz) {
16.593 + if (clazz != null) {
16.594 + n = classToNode(n, clazz);
16.595 + }
16.596 +
16.597 + if (n == null) {
16.598 + // not for us
16.599 + return emptyEn();
16.600 + } else {
16.601 + return nodeToEnum(n);
16.602 + }
16.603 + }
16.604 +
16.605 + /** Retains all classes. Removes nodes which items and children are emptied, works
16.606 + * recursivelly from specified root node.
16.607 + * @param node root node from which to start to process the tree
16.608 + * @param retain a map from (Item, AbstractLookup.Info) that describes which items to retain
16.609 + * and witch integer to assign them
16.610 + * @param notify collection of classes will be changed
16.611 + * @return <code>true<code> if some items were changed and node items and children are emptied,
16.612 + * those nodes, excluding root, will be removed from tree */
16.613 + private boolean retainAllClasses(Node node, Map retain, Collection<Class> notify) {
16.614 + boolean retained = false;
16.615 +
16.616 + if ((node.items != null) && (retain != null)) {
16.617 + Iterator<Pair> it = node.items.iterator();
16.618 +
16.619 + while (it.hasNext()) {
16.620 + AbstractLookup.Pair<?> item = it.next();
16.621 + AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(item);
16.622 +
16.623 + if (n == null) {
16.624 + // remove this item, it should not be there
16.625 + it.remove();
16.626 + retained = true;
16.627 + } else {
16.628 + // change the index
16.629 + if (item.getIndex() != n.index) {
16.630 + item.setIndex(null, n.index);
16.631 +
16.632 + // notify.addAll ((ArrayList)n.transaction);
16.633 + }
16.634 + }
16.635 + }
16.636 +
16.637 + if (retained && (notify != null)) {
16.638 + // type of this node has been changed
16.639 + notify.add(node.getType());
16.640 + }
16.641 + }
16.642 +
16.643 + if (node.children != null) {
16.644 + for (Iterator it = node.children.iterator();;) {
16.645 + Node ch = extractNode(it);
16.646 +
16.647 + if (ch == null) {
16.648 + break;
16.649 + }
16.650 +
16.651 + boolean result = retainAllClasses(ch, retain, notify);
16.652 +
16.653 + if (result) {
16.654 + // The children node was emptied and has no children -> remove it.
16.655 + it.remove();
16.656 + }
16.657 + }
16.658 + }
16.659 +
16.660 + return retained && node.items.isEmpty() && ((node.children == null) || node.children.isEmpty());
16.661 + }
16.662 +
16.663 + /** A method that creates enumeration of all items under given node.
16.664 + *
16.665 + * @param n node to create enumeration for
16.666 + * @return enumeration of Pairs
16.667 + */
16.668 + private static Enumeration<Pair> nodeToEnum(Node n) {
16.669 + if (n.children == null) {
16.670 + // create a simple enumeration because we do not have children
16.671 + Enumeration<Pair> e;
16.672 + if (n.items == null) {
16.673 + e = emptyEn();
16.674 + } else {
16.675 + e = Collections.enumeration(n.items);
16.676 + }
16.677 + return e;
16.678 + }
16.679 +
16.680 + // create enumeration of Items
16.681 + return new NeedsSortEnum(n);
16.682 + }
16.683 +
16.684 + //
16.685 + // Methods to work on interfaces
16.686 + //
16.687 +
16.688 + /** Registers an item with interfaces.
16.689 + * @param item item to register
16.690 + * @param affected list of classes that were affected
16.691 + * @return false if similar item has already been registered
16.692 + */
16.693 + @SuppressWarnings("unchecked")
16.694 + private boolean registerInterface(AbstractLookup.Pair<?> item, Collection<Class> affected) {
16.695 + if (interfaces == null) {
16.696 + return true;
16.697 + }
16.698 +
16.699 + Iterator<Map.Entry<Class,Object>> it = interfaces.entrySet().iterator();
16.700 +
16.701 + while (it.hasNext()) {
16.702 + Map.Entry<Class,Object> entry = it.next();
16.703 + Class<?> iface = entry.getKey();
16.704 +
16.705 + if (item.instanceOf(iface)) {
16.706 + Object value = entry.getValue();
16.707 +
16.708 + if (value instanceof Collection) {
16.709 + Collection<Object> set = (Collection<Object>) value;
16.710 +
16.711 + if (!set.add(item)) {
16.712 + // item is already there, probably (if everything is correct) is registered in
16.713 + // all other ifaces too, so stop additional testing
16.714 + return false;
16.715 + }
16.716 + } else {
16.717 + // there is just one pair right now
16.718 + if (value.equals(item)) {
16.719 + // item is there => stop processing (same as above)
16.720 + return false;
16.721 + }
16.722 +
16.723 + // otherwise replace the single item with ArrayList
16.724 + ArrayList<Object> ll = new ArrayList<Object>(3);
16.725 + ll.add(value);
16.726 + ll.add(item);
16.727 + entry.setValue(ll);
16.728 + }
16.729 +
16.730 + affected.add(iface);
16.731 + }
16.732 + }
16.733 +
16.734 + return true;
16.735 + }
16.736 +
16.737 + /** Removes interface.
16.738 + * @param item item to register
16.739 + * @param affected list of classes that were affected
16.740 + */
16.741 + @SuppressWarnings("unchecked")
16.742 + private void removeInterface(AbstractLookup.Pair item, Collection affected) {
16.743 + if (interfaces == null) {
16.744 + return;
16.745 + }
16.746 +
16.747 + Iterator it = interfaces.entrySet().iterator();
16.748 +
16.749 + while (it.hasNext()) {
16.750 + Map.Entry entry = (Map.Entry) it.next();
16.751 + Object value = entry.getValue();
16.752 +
16.753 + if (value instanceof Collection) {
16.754 + Collection set = (Collection) value;
16.755 +
16.756 + if (set.remove(item)) {
16.757 + if (set.size() == 1) {
16.758 + // if there is just one item remaining change to single item mode
16.759 + entry.setValue(set.iterator().next());
16.760 + }
16.761 +
16.762 + // adds the Class the item was register to into affected
16.763 + affected.add(entry.getKey());
16.764 + }
16.765 + } else {
16.766 + // single item value
16.767 + if (value.equals(item)) {
16.768 + // Emptied -> remove.
16.769 + it.remove();
16.770 +
16.771 + affected.add(entry.getKey());
16.772 + }
16.773 + }
16.774 + }
16.775 + }
16.776 +
16.777 + /** Retains some items.
16.778 + * @param retainItems items to retain and their mapping to index numbers
16.779 + * (AbstractLookup.Pair -> AbstractLookup.Info)
16.780 + * @param affected list of classes that were affected
16.781 + */
16.782 + @SuppressWarnings("unchecked")
16.783 + private void retainAllInterface(Map retainItems, Collection affected) {
16.784 + if (interfaces == null) {
16.785 + return;
16.786 + }
16.787 +
16.788 + Iterator it = interfaces.entrySet().iterator();
16.789 +
16.790 + while (it.hasNext()) {
16.791 + Map.Entry entry = (Map.Entry) it.next();
16.792 + Object value = entry.getValue();
16.793 +
16.794 + HashMap<?,?> retain = new HashMap(retainItems);
16.795 +
16.796 + Iterator elems;
16.797 + boolean multi = value instanceof Collection;
16.798 +
16.799 + if (multi) {
16.800 + // collection mode
16.801 + elems = ((Collection) value).iterator();
16.802 + } else {
16.803 + // single item mode
16.804 + elems = Collections.singleton(value).iterator();
16.805 + }
16.806 +
16.807 + boolean changed = false;
16.808 + boolean reordered = false;
16.809 +
16.810 + while (elems.hasNext()) {
16.811 + AbstractLookup.Pair p = (AbstractLookup.Pair) elems.next();
16.812 +
16.813 + AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(p);
16.814 +
16.815 + if (n == null) {
16.816 + if (multi) {
16.817 + // remove it
16.818 + elems.remove();
16.819 + }
16.820 +
16.821 + changed = true;
16.822 + } else {
16.823 + if (p.getIndex() != n.index) {
16.824 + // improve the index
16.825 + p.setIndex(null, n.index);
16.826 +
16.827 + // affected.addAll ((ArrayList)n.transaction);
16.828 + reordered = true;
16.829 + }
16.830 + }
16.831 + }
16.832 +
16.833 + if (reordered && value instanceof List) {
16.834 + // if reordered, than update the order in the collection
16.835 + List l = (List) value;
16.836 + Collections.sort(l, ALPairComparator.DEFAULT);
16.837 + }
16.838 +
16.839 + if (changed) {
16.840 + if (multi) {
16.841 + Collection c = (Collection) value;
16.842 +
16.843 + if (c.size() == 1) {
16.844 + // back to single item mode
16.845 + entry.setValue(c.iterator().next());
16.846 + }
16.847 + } else {
16.848 + // remove in single mode => remove completely
16.849 + it.remove();
16.850 + }
16.851 +
16.852 + // adds the Class the item was register to into affected
16.853 + affected.add(entry.getKey());
16.854 + }
16.855 + }
16.856 + }
16.857 +
16.858 + /** Searches for a clazz between interfaces.
16.859 + * @param clazz class to search for
16.860 + * @return enumeration of Items
16.861 + */
16.862 + @SuppressWarnings("unchecked")
16.863 + private Enumeration<Pair> searchInterface(final Class<?> clazz) {
16.864 + if (interfaces == null) {
16.865 + // first call for interface, only initialize
16.866 + interfaces = new WeakHashMap();
16.867 + }
16.868 +
16.869 + Object obj = interfaces.get(clazz);
16.870 +
16.871 + if (obj == null) {
16.872 + // set of items
16.873 + AbstractLookup.Pair one = null;
16.874 + ArrayList items = null;
16.875 +
16.876 + Enumeration en = lookup(Object.class);
16.877 +
16.878 + while (en.hasMoreElements()) {
16.879 + AbstractLookup.Pair it = (AbstractLookup.Pair) en.nextElement();
16.880 +
16.881 + if (it.instanceOf(clazz)) {
16.882 + // ok, this item implements given clazz
16.883 + if (one == null) {
16.884 + one = it;
16.885 + } else {
16.886 + if (items == null) {
16.887 + items = new ArrayList(3);
16.888 + items.add(one);
16.889 + }
16.890 +
16.891 + items.add(it);
16.892 + }
16.893 + }
16.894 + }
16.895 +
16.896 + if ((items == null) && (one != null)) {
16.897 + // single item mode
16.898 + interfaces.put(clazz, one);
16.899 +
16.900 + return singletonEn(one);
16.901 + } else {
16.902 + if (items == null) {
16.903 + items = new ArrayList(2);
16.904 + }
16.905 +
16.906 + interfaces.put(clazz, items);
16.907 +
16.908 + return Collections.enumeration(items);
16.909 + }
16.910 + } else {
16.911 + if (obj instanceof Collection) {
16.912 + return Collections.enumeration((Collection) obj);
16.913 + } else {
16.914 + // single item mode
16.915 + return singletonEn((Pair)obj);
16.916 + }
16.917 + }
16.918 + }
16.919 +
16.920 + /** Extracts a node from an iterator, returning null if no next element found
16.921 + */
16.922 + private static Node extractNode(Iterator it) {
16.923 + while (it.hasNext()) {
16.924 + Node n = (Node) it.next();
16.925 +
16.926 + if (n.get() == null) {
16.927 + it.remove();
16.928 + } else {
16.929 + return n;
16.930 + }
16.931 + }
16.932 +
16.933 + return null;
16.934 + }
16.935 +
16.936 + /** Prints debug info about the node.
16.937 + * @param n node to print
16.938 + * @param sp spaces to add
16.939 + * @param out where
16.940 + * @param instances print also instances
16.941 + */
16.942 + private static void printNode(Node n, String sp, java.io.PrintStream out, boolean instances) {
16.943 + int i;
16.944 + Iterator it;
16.945 +
16.946 + Class type = n.getType();
16.947 +
16.948 + out.print(sp);
16.949 + out.println("Node for: " + type + "\t" + ((type == null) ? null : type.getClassLoader())); // NOI18N
16.950 +
16.951 + if (n.items != null) {
16.952 + i = 0;
16.953 + it = new ArrayList<Pair>(n.items).iterator();
16.954 +
16.955 + while (it.hasNext()) {
16.956 + AbstractLookup.Pair p = (AbstractLookup.Pair) it.next();
16.957 + out.print(sp);
16.958 + out.print(" item (" + i++ + "): ");
16.959 + out.print(p); // NOI18N
16.960 + out.print(" id: " + Integer.toHexString(System.identityHashCode(p))); // NOI18N
16.961 + out.print(" index: "); // NOI18N
16.962 + out.print(p.getIndex());
16.963 +
16.964 + if (instances) {
16.965 + out.print(" I: " + p.getInstance());
16.966 + }
16.967 +
16.968 + out.println();
16.969 + }
16.970 + }
16.971 +
16.972 + if (n.children != null) {
16.973 + i = 0;
16.974 + it = n.children.iterator();
16.975 +
16.976 + while (it.hasNext()) {
16.977 + Node ch = (Node) it.next();
16.978 + printNode(ch, sp + " ", out, instances); // NOI18N
16.979 + }
16.980 + }
16.981 + }
16.982 +
16.983 + public ReferenceToResult registerReferenceToResult(ReferenceToResult<?> newRef) {
16.984 + if (reg == null) {
16.985 + reg = new HashMap<Class,ReferenceToResult>();
16.986 + }
16.987 +
16.988 + Class<? extends Object> clazz = newRef.template.getType();
16.989 +
16.990 + // initialize the data structures if not yet
16.991 + lookup(clazz);
16.992 +
16.993 + // newRef will be the new head of the list
16.994 + return reg.put(clazz, newRef);
16.995 + }
16.996 +
16.997 + public ReferenceToResult cleanUpResult(Lookup.Template templ) {
16.998 + collectListeners(null, templ.getType());
16.999 +
16.1000 + return (reg == null) ? null : reg.get(templ.getType());
16.1001 + }
16.1002 +
16.1003 + public ArrayList<Class> beginTransaction(int ensure) {
16.1004 + return new ArrayList<Class>();
16.1005 + }
16.1006 +
16.1007 + public void endTransaction(ArrayList<Class> list, Set<AbstractLookup.R> allAffectedResults) {
16.1008 + if (list.size() == 1) {
16.1009 + // probably the most common case
16.1010 + collectListeners(allAffectedResults, list.get(0));
16.1011 + } else {
16.1012 + Iterator it = list.iterator();
16.1013 +
16.1014 + while (it.hasNext()) {
16.1015 + collectListeners(allAffectedResults, (Class) it.next());
16.1016 + }
16.1017 + }
16.1018 + }
16.1019 +
16.1020 + /** Notifies all listeners that are interested in changes in this class.
16.1021 + * Should be called from synchronized places.
16.1022 + * @param allAffectedResults adds Results into this set
16.1023 + * @param c the class that has changed
16.1024 + */
16.1025 + private void collectListeners(Set<AbstractLookup.R> allAffectedResults, Class c) {
16.1026 + if (reg == null) {
16.1027 + return;
16.1028 + }
16.1029 +
16.1030 + while (c != null) {
16.1031 + ReferenceToResult first = reg.get(c);
16.1032 + ReferenceIterator it = new ReferenceIterator(first);
16.1033 +
16.1034 + while (it.next()) {
16.1035 + AbstractLookup.R result = it.current().getResult();
16.1036 +
16.1037 + if (allAffectedResults != null) {
16.1038 + // add result
16.1039 + allAffectedResults.add(result);
16.1040 + }
16.1041 + }
16.1042 +
16.1043 + if (first != it.first()) {
16.1044 + if (it.first() == null) {
16.1045 + // we do not need have more results on this object
16.1046 + reg.remove(c);
16.1047 + } else {
16.1048 + // move the head of the list
16.1049 + reg.put(c, it.first());
16.1050 + }
16.1051 + }
16.1052 +
16.1053 + c = c.getSuperclass();
16.1054 + }
16.1055 +
16.1056 + if (reg.isEmpty()) {
16.1057 + // clean up the list of all results if we do not need them anymore
16.1058 + reg = null;
16.1059 + }
16.1060 + }
16.1061 +
16.1062 + /** Node in the tree.
16.1063 + */
16.1064 + static final class Node extends WeakReference<Class> implements Serializable {
16.1065 + static final long serialVersionUID = 3L;
16.1066 +
16.1067 + /** children nodes */
16.1068 + public ArrayList<Node> children;
16.1069 +
16.1070 + /** list of items assigned to this node (suspect to be subclasses) */
16.1071 + public Collection<Pair> items;
16.1072 +
16.1073 + /** Constructor.
16.1074 + */
16.1075 + public Node(Class clazz) {
16.1076 + super(clazz);
16.1077 + }
16.1078 +
16.1079 + /** Returns true if the object was deserialized also clears the serialized flag.
16.1080 + * @return true if so.
16.1081 + */
16.1082 + public boolean deserialized() {
16.1083 + if ((items == null) || items instanceof LinkedHashSet) {
16.1084 + return false;
16.1085 + }
16.1086 +
16.1087 + if (items.isEmpty()) {
16.1088 + items = null;
16.1089 + } else {
16.1090 + items = new LinkedHashSet<Pair>(items);
16.1091 + }
16.1092 +
16.1093 + return true;
16.1094 + }
16.1095 +
16.1096 + /** Marks this item as being deserialized.
16.1097 + */
16.1098 + public void markDeserialized() {
16.1099 + if (items == null || items == Collections.EMPTY_LIST) {
16.1100 + items = Collections.emptyList();
16.1101 + } else {
16.1102 + items = Collections.synchronizedCollection(items);
16.1103 + }
16.1104 + }
16.1105 +
16.1106 + /** Getter for the type associated with this node.
16.1107 + */
16.1108 + public Class<?> getType() {
16.1109 + Class<?> c = get();
16.1110 +
16.1111 + // if garbage collected, then return a garbage
16.1112 + return (c == null) ? Void.TYPE : c;
16.1113 + }
16.1114 +
16.1115 + /** Checks whether a node can represent an class.
16.1116 + */
16.1117 + public boolean accepts(Class<?> clazz) {
16.1118 + if (getType() == Object.class) {
16.1119 + return true;
16.1120 + }
16.1121 +
16.1122 + return getType().isAssignableFrom(clazz);
16.1123 + }
16.1124 +
16.1125 + /** Checks whether item is instance of this node.
16.1126 + */
16.1127 + public boolean accepts(AbstractLookup.Pair<?> item) {
16.1128 + if (getType() == Object.class) {
16.1129 + // Object.class
16.1130 + return true;
16.1131 + }
16.1132 +
16.1133 + return item.instanceOf(getType());
16.1134 + }
16.1135 +
16.1136 + /** Assings an item to this node.
16.1137 + * @param item the item
16.1138 + * @return true if item has been added as new
16.1139 + */
16.1140 + public boolean assignItem(InheritanceTree tree, AbstractLookup.Pair<?> item) {
16.1141 + if ((items == null) || (items == Collections.EMPTY_LIST)) {
16.1142 + items = new LinkedHashSet<Pair>();
16.1143 + items.add(item);
16.1144 +
16.1145 + return true;
16.1146 + }
16.1147 +
16.1148 + if (items.contains(item)) {
16.1149 + Iterator<Pair> it = items.iterator();
16.1150 + Pair old;
16.1151 + for (;;) {
16.1152 + old = it.next();
16.1153 + if (item.equals(old)) {
16.1154 + break;
16.1155 + }
16.1156 + }
16.1157 +
16.1158 + if (old != item) {
16.1159 + // replace the items there
16.1160 + item.setIndex(tree, old.getIndex());
16.1161 + }
16.1162 +
16.1163 + it.remove();
16.1164 + items.add(item);
16.1165 +
16.1166 + return false;
16.1167 + }
16.1168 +
16.1169 + items.add(item);
16.1170 +
16.1171 + return true;
16.1172 + }
16.1173 +
16.1174 + private Object writeReplace() {
16.1175 + return new R(this);
16.1176 + }
16.1177 +
16.1178 + @Override
16.1179 + public String toString() {
16.1180 + return "Node for " + get();
16.1181 + }
16.1182 + }
16.1183 + // End of class Node.
16.1184 +
16.1185 + private static final class R implements Serializable {
16.1186 + static final long serialVersionUID = 1L;
16.1187 + private static ClassLoader l;
16.1188 + private String clazzName;
16.1189 + private transient Class<?> clazz;
16.1190 + private ArrayList<Node> children;
16.1191 + private Collection<Pair> items;
16.1192 +
16.1193 + public R(Node n) {
16.1194 + this.clazzName = n.getType().getName();
16.1195 + this.children = n.children;
16.1196 +
16.1197 + if (n.items instanceof LinkedHashSet || (n.items == null)) {
16.1198 + this.items = n.items;
16.1199 + } else {
16.1200 + this.items = new LinkedHashSet<Pair>(n.items);
16.1201 + }
16.1202 + }
16.1203 +
16.1204 + private void readObject(ObjectInputStream ois)
16.1205 + throws IOException, ClassNotFoundException {
16.1206 + ois.defaultReadObject();
16.1207 +
16.1208 + if (l == null) {
16.1209 + l = Lookup.getDefault().lookup(ClassLoader.class);
16.1210 + }
16.1211 +
16.1212 + clazz = Class.forName(clazzName, false, l);
16.1213 + }
16.1214 +
16.1215 + private Object readResolve() throws ObjectStreamException {
16.1216 + Node n = new Node(clazz);
16.1217 + n.children = children;
16.1218 + n.items = items;
16.1219 + n.markDeserialized();
16.1220 +
16.1221 + return n;
16.1222 + }
16.1223 + }
16.1224 + // end of R
16.1225 +
16.1226 + static Enumeration<Object> arrayEn(Object[] object) {
16.1227 + return Collections.enumeration(Arrays.asList(object));
16.1228 + }
16.1229 + static <T> Enumeration<T> singletonEn(T object) {
16.1230 + return Collections.enumeration(Collections.singleton(object));
16.1231 + }
16.1232 + static <T> Enumeration<T> emptyEn() {
16.1233 + return Collections.enumeration(Collections.<T>emptyList());
16.1234 + }
16.1235 +
16.1236 + /** Just a marker class to be able to do instanceof and find out
16.1237 + * that this enumeration is not sorted
16.1238 + */
16.1239 + private static final class NeedsSortEnum extends LinkedList<Node>
16.1240 + implements Enumeration<Pair> {
16.1241 + private Enumeration<Pair> en;
16.1242 +
16.1243 + public NeedsSortEnum(Node n) {
16.1244 + add(n);
16.1245 + }
16.1246 +
16.1247 + private boolean ensureNext() {
16.1248 + for (;;) {
16.1249 + if (en != null && en.hasMoreElements()) {
16.1250 + return true;
16.1251 + }
16.1252 + if (isEmpty()) {
16.1253 + return false;
16.1254 + }
16.1255 +
16.1256 + Node n2 = poll();
16.1257 + if (n2.children != null) {
16.1258 + addAll(n2.children);
16.1259 + }
16.1260 +
16.1261 + if (n2.items != null && !n2.items.isEmpty()) {
16.1262 + en = Collections.enumeration(n2.items);
16.1263 + }
16.1264 + }
16.1265 + }
16.1266 +
16.1267 + public boolean hasMoreElements() {
16.1268 + return ensureNext();
16.1269 + }
16.1270 +
16.1271 + public Pair nextElement() {
16.1272 + if (!ensureNext()) {
16.1273 + throw new NoSuchElementException();
16.1274 + }
16.1275 + return en.nextElement();
16.1276 + }
16.1277 + }
16.1278 + // end of NeedsSortEnum
16.1279 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/InstanceContent.java Sat Oct 31 15:28:13 2009 +0100
17.3 @@ -0,0 +1,378 @@
17.4 +/*
17.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
17.6 + *
17.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
17.8 + *
17.9 + * The contents of this file are subject to the terms of either the GNU
17.10 + * General Public License Version 2 only ("GPL") or the Common
17.11 + * Development and Distribution License("CDDL") (collectively, the
17.12 + * "License"). You may not use this file except in compliance with the
17.13 + * License. You can obtain a copy of the License at
17.14 + * http://www.netbeans.org/cddl-gplv2.html
17.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
17.16 + * specific language governing permissions and limitations under the
17.17 + * License. When distributing the software, include this License Header
17.18 + * Notice in each file and include the License file at
17.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17.20 + * particular file as subject to the "Classpath" exception as provided
17.21 + * by Sun in the GPL Version 2 section of the License file that
17.22 + * accompanied this code. If applicable, add the following below the
17.23 + * License Header, with the fields enclosed by brackets [] replaced by
17.24 + * your own identifying information:
17.25 + * "Portions Copyrighted [year] [name of copyright owner]"
17.26 + *
17.27 + * Contributor(s):
17.28 + *
17.29 + * The Original Software is NetBeans. The Initial Developer of the Original
17.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
17.31 + * Microsystems, Inc. All Rights Reserved.
17.32 + *
17.33 + * If you wish your version of this file to be governed by only the CDDL
17.34 + * or only the GPL Version 2, indicate your decision by adding
17.35 + * "[Contributor] elects to include this software in this distribution
17.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
17.37 + * single choice of license, a recipient has the option to distribute
17.38 + * your version of this file under either the CDDL, the GPL Version 2 or
17.39 + * to extend the choice of license to its licensees as provided above.
17.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
17.41 + * Version 2 license, then the option applies only if the new code is
17.42 + * made subject to such option by the copyright holder.
17.43 + */
17.44 +package org.openide.util.lookup;
17.45 +
17.46 +import org.openide.util.lookup.AbstractLookup.Pair;
17.47 +
17.48 +import java.lang.ref.WeakReference;
17.49 +
17.50 +import java.util.*;
17.51 +import java.util.concurrent.Executor;
17.52 +import org.openide.util.Lookup.Item;
17.53 +
17.54 +
17.55 +/** A special content implementation that can be passed to AbstractLookup
17.56 + * and provides methods for registration of instances and lazy instances.
17.57 + * <PRE>
17.58 + * InstanceContent ic = new InstanceContent ();
17.59 + * AbstractLookup al = new AbstractLookup (ic);
17.60 + *
17.61 + * ic.add (new Object ());
17.62 + * ic.add (new Dimension (...));
17.63 + *
17.64 + * Dimension theDim = (Dimension)al.lookup (Dimension.class);
17.65 + * </PRE>
17.66 + *
17.67 + * @author Jaroslav Tulach
17.68 + *
17.69 + * @since 1.25
17.70 + */
17.71 +public final class InstanceContent extends AbstractLookup.Content {
17.72 + /**
17.73 + * Create a new, empty content.
17.74 + */
17.75 + public InstanceContent() {
17.76 + }
17.77 +
17.78 + /** Creates a content associated with an executor to handle dispatch
17.79 + * of changes.
17.80 + * @param notifyIn the executor to notify changes in
17.81 + * @since 7.16
17.82 + */
17.83 + public InstanceContent(Executor notifyIn) {
17.84 + super(notifyIn);
17.85 + }
17.86 + /** The method to add instance to the lookup with.
17.87 + * @param inst instance
17.88 + */
17.89 + public final void add(Object inst) {
17.90 + addPair(new SimpleItem<Object>(inst));
17.91 + }
17.92 +
17.93 + /** Adds a convertible instance into the lookup. The <code>inst</code>
17.94 + * argument is just a key, not the actual value to appear in the lookup.
17.95 + * The value will be created on demand, later when it is really needed
17.96 + * by calling <code>convertor</code> methods.
17.97 + * <p>
17.98 + * This method is useful to delay creation of heavy weight objects.
17.99 + * Instead just register lightweight key and a convertor.
17.100 + * <p>
17.101 + * To remove registered object from lookup use {@link #remove(java.lang.Object, org.openide.util.lookup.InstanceContent.Convertor)}
17.102 + * with the same arguments.
17.103 + *
17.104 + * @param inst instance
17.105 + * @param conv convertor which postponing an instantiation,
17.106 + * if <code>conv==null</code> then the instance is registered directly.
17.107 + */
17.108 + public final <T,R> void add(T inst, Convertor<T,R> conv) {
17.109 + addPair(new ConvertingItem<T,R>(inst, conv));
17.110 + }
17.111 +
17.112 + /** Remove instance.
17.113 + * @param inst instance
17.114 + */
17.115 + public final void remove(Object inst) {
17.116 + removePair(new SimpleItem<Object>(inst));
17.117 + }
17.118 +
17.119 + /** Remove instance added with a convertor.
17.120 + * @param inst instance
17.121 + * @param conv convertor, if <code>conv==null</code> it is same like
17.122 + * remove(Object)
17.123 + */
17.124 + public final <T,R> void remove(T inst, Convertor<T,R> conv) {
17.125 + removePair(new ConvertingItem<T,R>(inst, conv));
17.126 + }
17.127 +
17.128 + /** Changes all pairs in the lookup to new values. Converts collection of
17.129 + * instances to collection of pairs.
17.130 + * @param col the collection of (Item) objects
17.131 + * @param conv the convertor to use or null
17.132 + */
17.133 + public final <T,R> void set(Collection<T> col, Convertor<T,R> conv) {
17.134 + ArrayList<Pair<?>> l = new ArrayList<Pair<?>>(col.size());
17.135 + Iterator<T> it = col.iterator();
17.136 +
17.137 + if (conv == null) {
17.138 + while (it.hasNext()) {
17.139 + l.add(new SimpleItem<T>(it.next()));
17.140 + }
17.141 + } else {
17.142 + while (it.hasNext()) {
17.143 + l.add(new ConvertingItem<T,R>(it.next(), conv));
17.144 + }
17.145 + }
17.146 +
17.147 + setPairs(l);
17.148 + }
17.149 +
17.150 + /** Convertor postpones an instantiation of an object.
17.151 + * @since 1.25
17.152 + */
17.153 + public static interface Convertor<T,R> {
17.154 + /** Convert obj to other object. There is no need to implement
17.155 + * cache mechanism. It is provided by
17.156 + * {@link Item#getInstance()} method itself. However the
17.157 + * method can be called more than once because instance is held
17.158 + * just by weak reference.
17.159 + *
17.160 + * @param obj the registered object
17.161 + * @return the object converted from this object
17.162 + */
17.163 + public R convert(T obj);
17.164 +
17.165 + /** Return type of converted object. Accessible via
17.166 + * {@link Item#getType()}
17.167 + * @param obj the registered object
17.168 + * @return the class that will be produced from this object (class or
17.169 + * superclass of convert (obj))
17.170 + */
17.171 + public Class<? extends R> type(T obj);
17.172 +
17.173 + /** Computes the ID of the resulted object. Accessible via
17.174 + * {@link Item#getId()}.
17.175 + * @param obj the registered object
17.176 + * @return the ID for the object
17.177 + */
17.178 + public String id(T obj);
17.179 +
17.180 + /** The human presentable name for the object. Accessible via
17.181 + * {@link Item#getDisplayName()}.
17.182 + * @param obj the registered object
17.183 + * @return the name representing the object for the user
17.184 + */
17.185 + public String displayName(T obj);
17.186 + }
17.187 +
17.188 + /** Instance of one item representing an object.
17.189 + */
17.190 + final static class SimpleItem<T> extends Pair<T> {
17.191 + private T obj;
17.192 +
17.193 + /** Create an item.
17.194 + * @obj object to register
17.195 + */
17.196 + public SimpleItem(T obj) {
17.197 + if (obj == null) {
17.198 + throw new NullPointerException();
17.199 + }
17.200 + this.obj = obj;
17.201 + }
17.202 +
17.203 + /** Tests whether this item can produce object
17.204 + * of class c.
17.205 + */
17.206 + public boolean instanceOf(Class<?> c) {
17.207 + return c.isInstance(obj);
17.208 + }
17.209 +
17.210 + /** Get instance of registered object. If convertor is specified then
17.211 + * method InstanceLookup.Convertor.convertor is used and weak reference
17.212 + * to converted object is saved.
17.213 + * @return the instance of the object.
17.214 + */
17.215 + public T getInstance() {
17.216 + return obj;
17.217 + }
17.218 +
17.219 + @Override
17.220 + public boolean equals(Object o) {
17.221 + if (o instanceof SimpleItem) {
17.222 + return obj.equals(((SimpleItem) o).obj);
17.223 + } else {
17.224 + return false;
17.225 + }
17.226 + }
17.227 +
17.228 + @Override
17.229 + public int hashCode() {
17.230 + return obj.hashCode();
17.231 + }
17.232 +
17.233 + /** An identity of the item.
17.234 + * @return string representing the item, that can be used for
17.235 + * persistance purposes to locate the same item next time
17.236 + */
17.237 + public String getId() {
17.238 + return "IL[" + obj.toString(); // NOI18N
17.239 + }
17.240 +
17.241 + /** Getter for display name of the item.
17.242 + */
17.243 + public String getDisplayName() {
17.244 + return obj.toString();
17.245 + }
17.246 +
17.247 + /** Method that can test whether an instance of a class has been created
17.248 + * by this item.
17.249 + *
17.250 + * @param obj the instance
17.251 + * @return if the item has already create an instance and it is the same
17.252 + * as obj.
17.253 + */
17.254 + protected boolean creatorOf(Object obj) {
17.255 + return obj == this.obj;
17.256 + }
17.257 +
17.258 + /** The class of this item.
17.259 + * @return the correct class
17.260 + */
17.261 + @SuppressWarnings("unchecked")
17.262 + public Class<? extends T> getType() {
17.263 + return (Class<? extends T>)obj.getClass();
17.264 + }
17.265 + }
17.266 + // end of SimpleItem
17.267 +
17.268 + /** Instance of one item registered in the map.
17.269 + */
17.270 + final static class ConvertingItem<T,R> extends Pair<R> {
17.271 + /** registered object */
17.272 + private T obj;
17.273 +
17.274 + /** Reference to converted object. */
17.275 + private WeakReference<R> ref;
17.276 +
17.277 + /** convertor to use */
17.278 + private Convertor<? super T,R> conv;
17.279 +
17.280 + /** Create an item.
17.281 + * @obj object to register
17.282 + * @conv a convertor, can be <code>null</code>.
17.283 + */
17.284 + public ConvertingItem(T obj, Convertor<? super T,R> conv) {
17.285 + this.obj = obj;
17.286 + this.conv = conv;
17.287 + }
17.288 +
17.289 + /** Tests whether this item can produce object
17.290 + * of class c.
17.291 + */
17.292 + public boolean instanceOf(Class<?> c) {
17.293 + return c.isAssignableFrom(getType());
17.294 + }
17.295 +
17.296 + /** Returns converted object or null if obj has not been converted yet
17.297 + * or reference was cleared by garbage collector.
17.298 + */
17.299 + private R getConverted() {
17.300 + if (ref == null) {
17.301 + return null;
17.302 + }
17.303 +
17.304 + return ref.get();
17.305 + }
17.306 +
17.307 + /** Get instance of registered object. If convertor is specified then
17.308 + * method InstanceLookup.Convertor.convertor is used and weak reference
17.309 + * to converted object is saved.
17.310 + * @return the instance of the object.
17.311 + */
17.312 + public synchronized R getInstance() {
17.313 + R converted = getConverted();
17.314 +
17.315 + if (converted == null) {
17.316 + converted = conv.convert(obj);
17.317 + ref = new WeakReference<R>(converted);
17.318 + }
17.319 +
17.320 + return converted;
17.321 + }
17.322 +
17.323 + @Override
17.324 + public boolean equals(Object o) {
17.325 + if (o instanceof ConvertingItem) {
17.326 + return obj.equals(((ConvertingItem) o).obj);
17.327 + } else {
17.328 + return false;
17.329 + }
17.330 + }
17.331 +
17.332 + @Override
17.333 + public int hashCode() {
17.334 + return obj.hashCode();
17.335 + }
17.336 +
17.337 + /** An identity of the item.
17.338 + * @return string representing the item, that can be used for
17.339 + * persistance purposes to locate the same item next time
17.340 + */
17.341 + public String getId() {
17.342 + return conv.id(obj);
17.343 + }
17.344 +
17.345 + /** Getter for display name of the item.
17.346 + */
17.347 + public String getDisplayName() {
17.348 + return conv.displayName(obj);
17.349 + }
17.350 +
17.351 + /** Method that can test whether an instance of a class has been created
17.352 + * by this item.
17.353 + *
17.354 + * @param obj the instance
17.355 + * @return if the item has already create an instance and it is the same
17.356 + * as obj.
17.357 + */
17.358 + protected boolean creatorOf(Object obj) {
17.359 + if (conv == null) {
17.360 + return obj == this.obj;
17.361 + } else {
17.362 + return obj == getConverted();
17.363 + }
17.364 + }
17.365 +
17.366 + /** The class of this item.
17.367 + * @return the correct class
17.368 + */
17.369 + @SuppressWarnings("unchecked")
17.370 + public Class<? extends R> getType() {
17.371 + R converted = getConverted();
17.372 +
17.373 + if (converted == null) {
17.374 + return conv.type(obj);
17.375 + }
17.376 +
17.377 + return (Class<? extends R>)converted.getClass();
17.378 + }
17.379 + }
17.380 + // end of ConvertingItem
17.381 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/Lookups.java Sat Oct 31 15:28:13 2009 +0100
18.3 @@ -0,0 +1,317 @@
18.4 +/*
18.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
18.6 + *
18.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
18.8 + *
18.9 + * The contents of this file are subject to the terms of either the GNU
18.10 + * General Public License Version 2 only ("GPL") or the Common
18.11 + * Development and Distribution License("CDDL") (collectively, the
18.12 + * "License"). You may not use this file except in compliance with the
18.13 + * License. You can obtain a copy of the License at
18.14 + * http://www.netbeans.org/cddl-gplv2.html
18.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
18.16 + * specific language governing permissions and limitations under the
18.17 + * License. When distributing the software, include this License Header
18.18 + * Notice in each file and include the License file at
18.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
18.20 + * particular file as subject to the "Classpath" exception as provided
18.21 + * by Sun in the GPL Version 2 section of the License file that
18.22 + * accompanied this code. If applicable, add the following below the
18.23 + * License Header, with the fields enclosed by brackets [] replaced by
18.24 + * your own identifying information:
18.25 + * "Portions Copyrighted [year] [name of copyright owner]"
18.26 + *
18.27 + * Contributor(s):
18.28 + *
18.29 + * The Original Software is NetBeans. The Initial Developer of the Original
18.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
18.31 + * Microsystems, Inc. All Rights Reserved.
18.32 + *
18.33 + * If you wish your version of this file to be governed by only the CDDL
18.34 + * or only the GPL Version 2, indicate your decision by adding
18.35 + * "[Contributor] elects to include this software in this distribution
18.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
18.37 + * single choice of license, a recipient has the option to distribute
18.38 + * your version of this file under either the CDDL, the GPL Version 2 or
18.39 + * to extend the choice of license to its licensees as provided above.
18.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
18.41 + * Version 2 license, then the option applies only if the new code is
18.42 + * made subject to such option by the copyright holder.
18.43 + */
18.44 +
18.45 +package org.openide.util.lookup;
18.46 +
18.47 +import java.util.Arrays;
18.48 +import org.netbeans.modules.openide.util.NamedServicesProvider;
18.49 +import org.openide.util.Lookup;
18.50 +
18.51 +/**
18.52 + * Static factory methods for creating common lookup implementations.
18.53 + *
18.54 + * @author David Strupl
18.55 + * @since 2.21
18.56 + */
18.57 +public class Lookups {
18.58 +
18.59 + /** static methods only */
18.60 + private Lookups() {}
18.61 +
18.62 + /**
18.63 + * Creates a singleton lookup. It means lookup that contains only
18.64 + * one object specified via the supplied parameter. The lookup will
18.65 + * either return the object or null if the supplied template does
18.66 + * not match the class. If the specified argument is null the method
18.67 + * will end with NullPointerException.
18.68 + * @return Fully initialized lookup object ready to use
18.69 + * @throws NullPointerException if the supplied argument is null
18.70 + * @since 2.21
18.71 + */
18.72 + public static Lookup singleton(Object objectToLookup) {
18.73 + if (objectToLookup == null) {
18.74 + throw new NullPointerException();
18.75 + }
18.76 +
18.77 + return new SingletonLookup(objectToLookup);
18.78 + }
18.79 +
18.80 + /**
18.81 + * Creates a lookup that contains an array of objects specified via the
18.82 + * parameter. The resulting lookup is fixed in the following sense: it
18.83 + * contains only fixed set of objects passed in by the array parameter.
18.84 + * Its contents never changes so registering listeners on such lookup
18.85 + * does not have any observable effect (the listeners are never called).
18.86 + *
18.87 + * @param objectsToLookup list of objects to include
18.88 + * @return Fully initialized lookup object ready to use
18.89 + * @throws NullPointerException if the supplied argument is null
18.90 + * @since 2.21
18.91 + *
18.92 + */
18.93 + public static Lookup fixed(Object... objectsToLookup) {
18.94 + if (objectsToLookup == null) {
18.95 + throw new NullPointerException();
18.96 + }
18.97 +
18.98 + if (objectsToLookup.length == 0) {
18.99 + return Lookup.EMPTY;
18.100 + }
18.101 +
18.102 + if (objectsToLookup.length == 1) {
18.103 + return singleton(objectsToLookup[0]);
18.104 + }
18.105 +
18.106 + return new SimpleLookup(Arrays.asList(objectsToLookup));
18.107 + }
18.108 +
18.109 + /**
18.110 + * Creates a lookup that contains an array of objects specified via the
18.111 + * parameter. The resulting lookup is fixed in the following sense: it
18.112 + * contains only fixed set of objects passed in by the array parameter.
18.113 + * The objects returned from this lookup are converted to real objects
18.114 + * before they are returned by the lookup.
18.115 + * Its contents never changes so registering listeners on such lookup
18.116 + * does not have any observable effect (the listeners are never called).
18.117 + *
18.118 + * @return Fully initialized lookup object ready to use
18.119 + * @throws NullPointerException if the any of the arguments is null
18.120 + * @since 2.21
18.121 + *
18.122 + */
18.123 + public static <T,R> Lookup fixed(T[] keys, InstanceContent.Convertor<? super T,R> convertor) {
18.124 + if (keys == null) {
18.125 + throw new NullPointerException();
18.126 + }
18.127 +
18.128 + if (convertor == null) {
18.129 + throw new NullPointerException();
18.130 + }
18.131 +
18.132 + return new SimpleLookup(Arrays.asList(keys), convertor);
18.133 + }
18.134 +
18.135 + /** Creates a lookup that delegates to another one but that one can change
18.136 + * from time to time. The returned lookup checks every time somebody calls
18.137 + * <code>lookup</code> or <code>lookupItem</code> method whether the
18.138 + * provider still returns the same lookup. If not, it updates state of
18.139 + * all {@link org.openide.util.Lookup.Result}s
18.140 + * that it created (and that still exists).
18.141 + * <P>
18.142 + * The user of this method has to implement its provider's <code>getLookup</code>
18.143 + * method (must be thread safe and fast, will be called often and from any thread)
18.144 + * pass it to this method and use the returned lookup. Whenever the user
18.145 + * changes the return value from the <code>getLookup</code> method and wants
18.146 + * to notify listeners on the lookup about that it should trigger the event
18.147 + * firing, for example by calling <code>lookup.lookup (Object.class)</code>
18.148 + * directly on the lookup returned by this method
18.149 + * that forces a check of the return value of {@link org.openide.util.Lookup.Provider#getLookup}</code>.
18.150 + *
18.151 + * @param provider the provider that returns a lookup to delegate to
18.152 + * @return lookup delegating to the lookup returned by the provider
18.153 + * @since 3.9
18.154 + */
18.155 + public static Lookup proxy(Lookup.Provider provider) {
18.156 + return new SimpleProxyLookup(provider);
18.157 + }
18.158 +
18.159 + /** Returns a lookup that implements the JDK1.3 JAR services mechanism and delegates
18.160 + * to META-INF/services/name.of.class files.
18.161 + * <p>Some extensions to the JAR services specification are implemented:
18.162 + * <ol>
18.163 + * <li>An entry may be followed by a line of the form <code>#position=<i>integer</i></code>
18.164 + * to specify ordering. (Smaller numbers first, entries with unspecified position last.)
18.165 + * <li>A line of the form <code>#-<i>classname</i></code> suppresses an entry registered
18.166 + * in another file, so can be used to supersede one implementation with another.
18.167 + * </ol>
18.168 + * <p>Note: It is not dynamic - so if you need to change the classloader or JARs,
18.169 + * wrap it in a {@link ProxyLookup} and change the delegate when necessary.
18.170 + * Existing instances will be kept if the implementation classes are unchanged,
18.171 + * so there is "stability" in doing this provided some parent loaders are the same
18.172 + * as the previous ones.
18.173 + * @since 3.35
18.174 + * @see ServiceProvider
18.175 + */
18.176 + public static Lookup metaInfServices(ClassLoader classLoader) {
18.177 + return new MetaInfServicesLookup(classLoader, "META-INF/services/"); // NOI18N
18.178 + }
18.179 +
18.180 + /** Returns a lookup that behaves exactly like {@link #metaInfServices(ClassLoader)}
18.181 + * except that it does not read data from <code>META-INF/services/</code>, but instead
18.182 + * from the specified prefix.
18.183 + * @param classLoader class loader to use for loading
18.184 + * @param prefix prefix to prepend to the class name when searching
18.185 + * @since 7.9
18.186 + */
18.187 + public static Lookup metaInfServices(ClassLoader classLoader, String prefix) {
18.188 + return new MetaInfServicesLookup(classLoader, prefix);
18.189 + }
18.190 +
18.191 + /** Creates a <q>named</q> lookup.
18.192 + * It is a lookup identified by a given path.
18.193 + * Two lookups with the same path should have the same content.
18.194 + * <p>It is expected that each <q>named</q> lookup
18.195 + * will contain a superset of what would be created by:
18.196 + * <code>{@linkplain #metaInfServices(ClassLoader,String) metaInfServices}(theRightLoader, "META-INF/namedservices/" + path + "/")</code>
18.197 + *
18.198 + * <p class="nonnormative">Various environments can add their own
18.199 + * extensions to its content. As such
18.200 + * {@link Lookups#forPath(java.lang.String)} can combine lookups
18.201 + * from several sources. In current NetBeans Runtime Container, two lookups are used:
18.202 + * </p>
18.203 + * <ul class="nonnormative">
18.204 + * <li><code>Lookups.metaInfServices("META-INF/namedservices/" + path)</code></li>
18.205 + * <li><code>org.openide.loaders.FolderLookup(path)</code></li>
18.206 + * </ul>
18.207 + * <p class="nonnormative">
18.208 + * Please note that these lookups differ in the way they inspect sub-folders.
18.209 + * The first lookup just returns instances from the given path, ignoring
18.210 + * sub-folders, the second one retrieves instances from the whole sub-tree.
18.211 + * </p>
18.212 + * <p>
18.213 + * Read more about the <a href="../doc-files/api.html#folderlookup">usage of this method</a>.
18.214 + *
18.215 + * @param path the path identifying the lookup, e.g. <code>Projects/Actions</code>
18.216 + * @return lookup associated with this path
18.217 + * @since 7.9
18.218 + */
18.219 + public static Lookup forPath(String path) {
18.220 + return NamedServicesProvider.find(path);
18.221 + }
18.222 +
18.223 + /** Creates a lookup that wraps another one and filters out instances
18.224 + * of specified classes. If you have a lookup and
18.225 + * you want to remove all instances of ActionMap you can use:
18.226 + * <pre>
18.227 + * l = Lookups.exclude(lookup, ActionMap.class);
18.228 + * </pre>
18.229 + * Then anybody who asks for <code>l.lookup(ActionMap.class)</code> or
18.230 + * subclass will get <code>null</code>. Even if the original lookup contains the
18.231 + * value.
18.232 + * To create empty lookup (well, just an example, otherwise use {@link Lookup#EMPTY}) one could use:
18.233 + * <pre>
18.234 + * Lookup.exclude(anyLookup, Object.class);
18.235 + * </pre>
18.236 + * as any instance in any lookup is of type Object and thus would be excluded.
18.237 + * <p>
18.238 + * The complete behavior can be described as <code>classes</code> being
18.239 + * a barrier. For an object not to be excluded, there has to be an inheritance
18.240 + * path between the queried class and the actual class of the instance,
18.241 + * that is not blocked by any of the excluded classes:
18.242 + * <pre>
18.243 + * interface A {}
18.244 + * interface B {}
18.245 + * class C implements A, B {}
18.246 + * Object c = new C();
18.247 + * Lookup l1 = Lookups.singleton(c);
18.248 + * Lookup l2 = Lookups.exclude(l1, A.class);
18.249 + * assertNull("A is directly excluded", l2.lookup(A.class));
18.250 + * assertEquals("Returns C as A.class is not between B and C", c, l2.lookup(B.class));
18.251 + * </pre>
18.252 + * For more info check the
18.253 + * <a href="http://hg.netbeans.org/main-golden/annotate/4883eaeda744/openide.util/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java">
18.254 + * excluding lookup tests</a> and the discussion in issue
18.255 + * <a href="http://openide.netbeans.org/issues/show_bug.cgi?id=53058">53058</a>.
18.256 + *
18.257 + * @param lookup the original lookup that should be filtered
18.258 + * @param classes array of classes those instances should be excluded
18.259 + * @since 5.4
18.260 + */
18.261 + public static Lookup exclude(Lookup lookup, Class... classes) {
18.262 + return new ExcludingLookup(lookup, classes);
18.263 + }
18.264 +
18.265 + /** Creates <code>Lookup.Item</code> representing the instance passed in.
18.266 + *
18.267 + * @param instance the object for which Lookup.Item should be creted
18.268 + * @param id unique identification of the object, for details see {@link org.openide.util.Lookup.Item#getId},
18.269 + * can be <code>null</code>
18.270 + * @return lookup item representing instance
18.271 + * @since 4.8
18.272 + */
18.273 + public static <T> Lookup.Item<T> lookupItem(T instance, String id) {
18.274 + return new LookupItem<T>(instance, id);
18.275 + }
18.276 +
18.277 + private static class LookupItem<T> extends Lookup.Item<T> {
18.278 + private String id;
18.279 + private T instance;
18.280 +
18.281 + public LookupItem(T instance) {
18.282 + this(instance, null);
18.283 + }
18.284 +
18.285 + public LookupItem(T instance, String id) {
18.286 + this.id = id;
18.287 + this.instance = instance;
18.288 + }
18.289 +
18.290 + public String getDisplayName() {
18.291 + return getId();
18.292 + }
18.293 +
18.294 + public String getId() {
18.295 + return (id == null) ? instance.toString() : id;
18.296 + }
18.297 +
18.298 + public T getInstance() {
18.299 + return instance;
18.300 + }
18.301 +
18.302 + @SuppressWarnings("unchecked")
18.303 + public Class<? extends T> getType() {
18.304 + return (Class<? extends T>)instance.getClass();
18.305 + }
18.306 +
18.307 + public @Override boolean equals(Object object) {
18.308 + if (object instanceof LookupItem) {
18.309 + return instance == ((LookupItem) object).getInstance();
18.310 + }
18.311 +
18.312 + return false;
18.313 + }
18.314 +
18.315 + public @Override int hashCode() {
18.316 + return instance.hashCode();
18.317 + }
18.318 + }
18.319 + // End of LookupItem class
18.320 +}
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/MetaInfServicesLookup.java Sat Oct 31 15:28:13 2009 +0100
19.3 @@ -0,0 +1,560 @@
19.4 +/*
19.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
19.6 + *
19.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
19.8 + *
19.9 + * The contents of this file are subject to the terms of either the GNU
19.10 + * General Public License Version 2 only ("GPL") or the Common
19.11 + * Development and Distribution License("CDDL") (collectively, the
19.12 + * "License"). You may not use this file except in compliance with the
19.13 + * License. You can obtain a copy of the License at
19.14 + * http://www.netbeans.org/cddl-gplv2.html
19.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
19.16 + * specific language governing permissions and limitations under the
19.17 + * License. When distributing the software, include this License Header
19.18 + * Notice in each file and include the License file at
19.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
19.20 + * particular file as subject to the "Classpath" exception as provided
19.21 + * by Sun in the GPL Version 2 section of the License file that
19.22 + * accompanied this code. If applicable, add the following below the
19.23 + * License Header, with the fields enclosed by brackets [] replaced by
19.24 + * your own identifying information:
19.25 + * "Portions Copyrighted [year] [name of copyright owner]"
19.26 + *
19.27 + * Contributor(s):
19.28 + *
19.29 + * The Original Software is NetBeans. The Initial Developer of the Original
19.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
19.31 + * Microsystems, Inc. All Rights Reserved.
19.32 + *
19.33 + * If you wish your version of this file to be governed by only the CDDL
19.34 + * or only the GPL Version 2, indicate your decision by adding
19.35 + * "[Contributor] elects to include this software in this distribution
19.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
19.37 + * single choice of license, a recipient has the option to distribute
19.38 + * your version of this file under either the CDDL, the GPL Version 2 or
19.39 + * to extend the choice of license to its licensees as provided above.
19.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
19.41 + * Version 2 license, then the option applies only if the new code is
19.42 + * made subject to such option by the copyright holder.
19.43 + */
19.44 +
19.45 +package org.openide.util.lookup;
19.46 +
19.47 +import java.io.BufferedReader;
19.48 +import java.io.IOException;
19.49 +import java.io.InputStream;
19.50 +import java.io.InputStreamReader;
19.51 +import java.lang.ref.Reference;
19.52 +import java.lang.ref.WeakReference;
19.53 +import java.lang.reflect.Method;
19.54 +import java.net.URL;
19.55 +import java.util.ArrayList;
19.56 +import java.util.Collection;
19.57 +import java.util.Enumeration;
19.58 +import java.util.HashSet;
19.59 +import java.util.LinkedHashSet;
19.60 +import java.util.List;
19.61 +import java.util.Map;
19.62 +import java.util.WeakHashMap;
19.63 +import java.util.concurrent.Executor;
19.64 +import java.util.logging.Level;
19.65 +import java.util.logging.Logger;
19.66 +import org.openide.util.Lookup;
19.67 +import org.openide.util.RequestProcessor;
19.68 +
19.69 +/**
19.70 + * @author Jaroslav Tulach, Jesse Glick
19.71 + * @see Lookups#metaInfServices(ClassLoader,String)
19.72 + * @see "#14722"
19.73 + */
19.74 +final class MetaInfServicesLookup extends AbstractLookup {
19.75 +
19.76 + private static final Logger LOGGER = Logger.getLogger(MetaInfServicesLookup.class.getName());
19.77 + static final Executor RP = new RequestProcessor(MetaInfServicesLookup.class.getName(), 1);
19.78 + private static int knownInstancesCount;
19.79 + private static final List<Reference<Object>> knownInstances;
19.80 + static {
19.81 + knownInstances = new ArrayList<Reference<Object>>();
19.82 + for (int i = 0; i < 512; i++) {
19.83 + knownInstances.add(null);
19.84 + }
19.85 + }
19.86 +
19.87 + /** A set of all requested classes.
19.88 + * Note that classes that we actually succeeded on can never be removed
19.89 + * from here because we hold a strong reference to the loader.
19.90 + * However we also hold classes which are definitely not loadable by
19.91 + * our loader.
19.92 + */
19.93 + private final Map<Class,Object> classes = new WeakHashMap<Class,Object>();
19.94 +
19.95 + /** class loader to use */
19.96 + private final ClassLoader loader;
19.97 + /** prefix to prepend */
19.98 + private final String prefix;
19.99 +
19.100 + /** Create a lookup reading from a specified classloader.
19.101 + */
19.102 + public MetaInfServicesLookup(ClassLoader loader, String prefix) {
19.103 + this.loader = loader;
19.104 + this.prefix = prefix;
19.105 +
19.106 + LOGGER.log(Level.FINE, "Created: {0}", this);
19.107 + }
19.108 +
19.109 + @Override
19.110 + public String toString() {
19.111 + return "MetaInfServicesLookup[" + loader + "]"; // NOI18N
19.112 + }
19.113 +
19.114 + /* Tries to load appropriate resources from manifest files.
19.115 + */
19.116 + @Override
19.117 + protected final void beforeLookup(Lookup.Template t) {
19.118 + Class c = t.getType();
19.119 +
19.120 + Collection<AbstractLookup.Pair<?>> toAdd = null;
19.121 + synchronized (this) {
19.122 + if (classes.get(c) == null) { // NOI18N
19.123 + toAdd = new ArrayList<Pair<?>>();
19.124 + } else {
19.125 + // ok, nothing needs to be done
19.126 + return;
19.127 + }
19.128 + }
19.129 + if (toAdd != null) {
19.130 + search(c, toAdd);
19.131 + }
19.132 + synchronized (this) {
19.133 + if (classes.put(c, "") == null) { // NOI18N
19.134 + // Added new class, search for it.
19.135 + LinkedHashSet<AbstractLookup.Pair<?>> arr = getPairsAsLHS();
19.136 + arr.addAll(toAdd);
19.137 + setPairs(arr, RP);
19.138 + }
19.139 + }
19.140 + }
19.141 +
19.142 + /** Finds all pairs and adds them to the collection.
19.143 + *
19.144 + * @param clazz class to find
19.145 + * @param result collection to add Pair to
19.146 + */
19.147 + private void search(Class<?> clazz, Collection<AbstractLookup.Pair<?>> result) {
19.148 + if (LOGGER.isLoggable(Level.FINER)) {
19.149 + LOGGER.log(Level.FINER, "Searching for " + clazz.getName() + " in " + clazz.getClassLoader() + " from " + this);
19.150 + }
19.151 +
19.152 + String res = prefix + clazz.getName(); // NOI18N
19.153 + Enumeration<URL> en;
19.154 +
19.155 + try {
19.156 + en = loader.getResources(res);
19.157 + } catch (IOException ioe) {
19.158 + // do not use ErrorManager because we are in the startup code
19.159 + // and ErrorManager might not be ready
19.160 + ioe.printStackTrace();
19.161 +
19.162 + return;
19.163 + }
19.164 +
19.165 + // Do not create multiple instances in case more than one JAR
19.166 + // has the same entry in it (and they load to the same class).
19.167 + // Probably would not happen, assuming JARs only list classes
19.168 + // they own, but just in case...
19.169 + List<Item> foundClasses = new ArrayList<Item>();
19.170 + Collection<Class> removeClasses = new ArrayList<Class>();
19.171 +
19.172 + boolean foundOne = false;
19.173 +
19.174 + while (en.hasMoreElements()) {
19.175 + if (!foundOne) {
19.176 + foundOne = true;
19.177 +
19.178 + // Double-check that in fact we can load the *interface* class.
19.179 + // For example, say class I is defined in two JARs, J1 and J2.
19.180 + // There is also an implementation M1 defined in J1, and another
19.181 + // implementation M2 defined in J2.
19.182 + // Classloaders C1 and C2 are made from J1 and J2.
19.183 + // A MetaInfServicesLookup is made from C1. Then the user asks to
19.184 + // lookup I as loaded from C2. J1 has the services line and lists
19.185 + // M1, and we can in fact make it. However it is not of the desired
19.186 + // type to be looked up. Don't do this check, which could be expensive,
19.187 + // unless we expect to be getting some results, however.
19.188 + Class realMcCoy = null;
19.189 +
19.190 + try {
19.191 + realMcCoy = loader.loadClass(clazz.getName());
19.192 + } catch (ClassNotFoundException cnfe) {
19.193 + // our loader does not know about it, OK
19.194 + }
19.195 +
19.196 + if (realMcCoy != clazz) {
19.197 + // Either the interface class is not available at all in our loader,
19.198 + // or it is not the same version as we expected. Don't provide results.
19.199 + if (LOGGER.isLoggable(Level.WARNING)) {
19.200 + if (realMcCoy != null) {
19.201 + LOGGER.log(Level.WARNING,
19.202 + clazz.getName() + " is not the real McCoy! Actually found it in " +
19.203 + realMcCoy.getClassLoader()
19.204 + ); // NOI18N
19.205 + } else {
19.206 + LOGGER.log(Level.WARNING, clazz.getName() + " could not be found in " + loader); // NOI18N
19.207 + }
19.208 + }
19.209 +
19.210 + return;
19.211 + }
19.212 + }
19.213 +
19.214 + URL url = en.nextElement();
19.215 + Item currentItem = null;
19.216 +
19.217 + try {
19.218 + InputStream is = url.openStream();
19.219 +
19.220 + try {
19.221 + BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // NOI18N
19.222 +
19.223 + while (true) {
19.224 + String line = reader.readLine();
19.225 +
19.226 + if (line == null) {
19.227 + break;
19.228 + }
19.229 +
19.230 + line = line.trim();
19.231 +
19.232 + // is it position attribute?
19.233 + if (line.startsWith("#position=")) {
19.234 + if (currentItem == null) {
19.235 + LOGGER.log(Level.WARNING, "Found line '{0}' in {1} but there is no item to associate it with", new Object[] {line, url});
19.236 + continue;
19.237 + }
19.238 +
19.239 + try {
19.240 + currentItem.position = Integer.parseInt(line.substring(10));
19.241 + } catch (NumberFormatException e) {
19.242 + // do not use ErrorManager because we are in the startup code
19.243 + // and ErrorManager might not be ready
19.244 + e.printStackTrace();
19.245 + }
19.246 + }
19.247 +
19.248 + if (currentItem != null) {
19.249 + insertItem(currentItem, foundClasses);
19.250 + currentItem = null;
19.251 + }
19.252 +
19.253 + // Ignore blank lines and comments.
19.254 + if (line.length() == 0) {
19.255 + continue;
19.256 + }
19.257 +
19.258 + boolean remove = false;
19.259 +
19.260 + if (line.charAt(0) == '#') {
19.261 + if ((line.length() == 1) || (line.charAt(1) != '-')) {
19.262 + continue;
19.263 + }
19.264 +
19.265 + // line starting with #- is a sign to remove that class from lookup
19.266 + remove = true;
19.267 + line = line.substring(2);
19.268 + }
19.269 +
19.270 + Class inst = null;
19.271 +
19.272 + try {
19.273 + // Most lines are fully-qualified class names.
19.274 + inst = Class.forName(line, false, loader);
19.275 + } catch (ClassNotFoundException cnfe) {
19.276 + if (remove) {
19.277 + // if we are removing somthing and the something
19.278 + // cannot be found it is ok to do nothing
19.279 + continue;
19.280 + } else {
19.281 + // but if we are not removing just rethrow
19.282 + throw cnfe;
19.283 + }
19.284 + }
19.285 +
19.286 + if (!clazz.isAssignableFrom(inst)) {
19.287 + throw new ClassNotFoundException(clazzToString(inst) + " not a subclass of " + clazzToString(clazz)); // NOI18N
19.288 + }
19.289 +
19.290 + if (remove) {
19.291 + removeClasses.add(inst);
19.292 + } else {
19.293 + // create new item here, but do not put it into
19.294 + // foundClasses array yet because following line
19.295 + // might specify its position
19.296 + currentItem = new Item();
19.297 + currentItem.clazz = inst;
19.298 + }
19.299 + }
19.300 +
19.301 + if (currentItem != null) {
19.302 + insertItem(currentItem, foundClasses);
19.303 + currentItem = null;
19.304 + }
19.305 + } finally {
19.306 + is.close();
19.307 + }
19.308 + } catch (ClassNotFoundException ex) {
19.309 + LOGGER.log(Level.WARNING, null, ex);
19.310 + } catch (IOException ex) {
19.311 + LOGGER.log(Level.WARNING, null, ex);
19.312 + }
19.313 + }
19.314 +
19.315 + LOGGER.log(Level.FINER, "Found impls of {0}: {1} and removed: {2} from: {3}", new Object[] {clazz.getName(), foundClasses, removeClasses, this});
19.316 +
19.317 + foundClasses.removeAll(removeClasses);
19.318 +
19.319 + for (Item item : foundClasses) {
19.320 + if (removeClasses.contains(item.clazz)) {
19.321 + continue;
19.322 + }
19.323 +
19.324 + result.add(new P(item.clazz));
19.325 + }
19.326 + }
19.327 + private static String clazzToString(Class clazz) {
19.328 + return clazz.getName() + "@" + clazz.getClassLoader() + ":" + clazz.getProtectionDomain().getCodeSource().getLocation(); // NOI18N
19.329 + }
19.330 +
19.331 + /**
19.332 + * Insert item to the list according to item.position value.
19.333 + */
19.334 + private void insertItem(Item item, List<Item> list) {
19.335 + // no position? -> add it to the end
19.336 + if (item.position == -1) {
19.337 + list.add(item);
19.338 +
19.339 + return;
19.340 + }
19.341 +
19.342 + int index = -1;
19.343 + for (Item i : list) {
19.344 + index++;
19.345 +
19.346 + if (i.position == -1) {
19.347 + list.add(index, item);
19.348 +
19.349 + return;
19.350 + } else {
19.351 + if (i.position > item.position) {
19.352 + list.add(index, item);
19.353 +
19.354 + return;
19.355 + }
19.356 + }
19.357 + }
19.358 +
19.359 + list.add(item);
19.360 + }
19.361 +
19.362 + private static class Item {
19.363 + private Class clazz;
19.364 + private int position = -1;
19.365 + @Override
19.366 + public String toString() {
19.367 + return "MetaInfServicesLookup.Item[" + clazz.getName() + "]"; // NOI18N
19.368 + }
19.369 + }
19.370 +
19.371 + /** Pair that holds name of a class and maybe the instance.
19.372 + */
19.373 + private static final class P extends AbstractLookup.Pair<Object> {
19.374 + /** May be one of three things:
19.375 + * 1. The implementation class which was named in the services file.
19.376 + * 2. An instance of it.
19.377 + * 3. Null, if creation of the instance resulted in an error.
19.378 + */
19.379 + private Object object;
19.380 +
19.381 + public P(Class<?> clazz) {
19.382 + this.object = clazz;
19.383 + }
19.384 +
19.385 + /** Finds the class.
19.386 + */
19.387 + private Class<? extends Object> clazz() {
19.388 + Object o = object;
19.389 +
19.390 + if (o instanceof Class) {
19.391 + return (Class<? extends Object>) o;
19.392 + } else if (o != null) {
19.393 + return o.getClass();
19.394 + } else {
19.395 + // Broken.
19.396 + return Object.class;
19.397 + }
19.398 + }
19.399 +
19.400 + @Override
19.401 + public boolean equals(Object o) {
19.402 + if (o instanceof P) {
19.403 + return ((P) o).clazz().equals(clazz());
19.404 + }
19.405 +
19.406 + return false;
19.407 + }
19.408 +
19.409 + @Override
19.410 + public int hashCode() {
19.411 + return clazz().hashCode();
19.412 + }
19.413 +
19.414 + protected boolean instanceOf(Class<?> c) {
19.415 + return c.isAssignableFrom(clazz());
19.416 + }
19.417 +
19.418 + public Class<?> getType() {
19.419 + return clazz();
19.420 + }
19.421 +
19.422 + public Object getInstance() {
19.423 + Object o = object; // keeping local copy to avoid another
19.424 +
19.425 + // thread to modify it under my hands
19.426 + if (o instanceof Class) {
19.427 + synchronized (o) { // o is Class and we will not create
19.428 + // 2 instances of the same class
19.429 +
19.430 + try {
19.431 + Class<?> c = ((Class) o);
19.432 + o = null;
19.433 +
19.434 + synchronized (knownInstances) { // guards only the static cache
19.435 + int size = knownInstances.size();
19.436 + int index = c.hashCode() % size;
19.437 + for (int i = 0; i < size; i++) {
19.438 + Reference<Object> ref = knownInstances.get(index);
19.439 + Object obj = ref == null ? null : ref.get();
19.440 + if (obj == null) {
19.441 + break;
19.442 + }
19.443 + if (c == obj.getClass()) {
19.444 + o = obj;
19.445 + break;
19.446 + }
19.447 + if (++index == size) {
19.448 + index = 0;
19.449 + }
19.450 + }
19.451 + }
19.452 +
19.453 + if (o == null) {
19.454 + o = createInstance(c);
19.455 +
19.456 + synchronized (knownInstances) { // guards only the static cache
19.457 + hashPut(o);
19.458 +
19.459 + int size = knownInstances.size();
19.460 + if (knownInstancesCount > size * 2 / 3) {
19.461 + LOGGER.log(Level.CONFIG, "Cache of size {0} is 2/3 full. Rehashing.", size);
19.462 + HashSet<Reference<Object>> all = new HashSet<Reference<Object>>();
19.463 + all.addAll(knownInstances);
19.464 + for (int i = 0; i < size; i++) {
19.465 + knownInstances.set(i, null);
19.466 + }
19.467 + for (int i = 0; i < size; i++) {
19.468 + knownInstances.add(null);
19.469 + }
19.470 + knownInstancesCount = 0;
19.471 + for (Reference<Object> r : all) {
19.472 + if (r == null) {
19.473 + continue;
19.474 + }
19.475 + Object instance = r.get();
19.476 + if (instance == null) {
19.477 + continue;
19.478 + }
19.479 + hashPut(instance);
19.480 + }
19.481 + }
19.482 +
19.483 + }
19.484 + }
19.485 +
19.486 + // Do not assign to instance var unless there is a complete synch
19.487 + // block between the newInstance and this line. Otherwise we could
19.488 + // be assigning a half-constructed instance that another thread
19.489 + // could see and return immediately.
19.490 + object = o;
19.491 + } catch (Exception ex) {
19.492 + LOGGER.log(Level.WARNING, "Cannot create " + object, ex);
19.493 + object = null;
19.494 + } catch (ExceptionInInitializerError x) { // #174055
19.495 + LOGGER.log(Level.WARNING, "Cannot create " + object, x);
19.496 + object = null;
19.497 + }
19.498 + }
19.499 + }
19.500 +
19.501 + return object;
19.502 + }
19.503 +
19.504 + public String getDisplayName() {
19.505 + return clazz().getName();
19.506 + }
19.507 +
19.508 + public String getId() {
19.509 + return clazz().getName();
19.510 + }
19.511 +
19.512 + protected boolean creatorOf(Object obj) {
19.513 + return obj == object;
19.514 + }
19.515 +
19.516 + private static void hashPut(Object o) {
19.517 + Class<?> c = o.getClass();
19.518 + int size = knownInstances.size();
19.519 + int index = c.hashCode() % size;
19.520 + for (int i = 0; i < size; i++) {
19.521 + Reference<Object> ref = knownInstances.get(index);
19.522 + Object obj = ref == null ? null : ref.get();
19.523 + if (obj == null) {
19.524 + knownInstances.set(index, new WeakReference<Object>(o));
19.525 + knownInstancesCount++;
19.526 + break;
19.527 + }
19.528 + if (++index == size) {
19.529 + index = 0;
19.530 + }
19.531 + }
19.532 + }
19.533 +
19.534 + private static boolean findSharedClassObjectSkip;
19.535 + private static Method findSharedClassObject;
19.536 + /** Basically does c.newInstance(), however the method is complicated
19.537 + * with a special behaviour for old and almost obsoleted NetBeans
19.538 + * class: SharedClassObject.
19.539 + */
19.540 + private static Object createInstance(Class<?> c) throws InstantiationException, IllegalAccessException {
19.541 + if (!findSharedClassObjectSkip) {
19.542 + try {
19.543 + if (findSharedClassObject == null) {
19.544 + Class<?> sco;
19.545 + try {
19.546 + sco = Class.forName("org.openide.util.SharedClassObject"); // NOI18N
19.547 + } catch (ClassNotFoundException ex) {
19.548 + findSharedClassObjectSkip = true;
19.549 + return c.newInstance();
19.550 + }
19.551 + findSharedClassObject = sco.getMethod("findObject", Class.class, boolean.class);
19.552 + }
19.553 + if (findSharedClassObject.getReturnType().isAssignableFrom(c)) {
19.554 + return findSharedClassObject.invoke(null, c, true);
19.555 + }
19.556 + } catch (Exception problem) {
19.557 + throw (InstantiationException)new InstantiationException(problem.getMessage()).initCause(problem);
19.558 + }
19.559 + }
19.560 + return c.newInstance();
19.561 + }
19.562 + }
19.563 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ProxyLookup.java Sat Oct 31 15:28:13 2009 +0100
20.3 @@ -0,0 +1,969 @@
20.4 +/*
20.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
20.6 + *
20.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
20.8 + *
20.9 + * The contents of this file are subject to the terms of either the GNU
20.10 + * General Public License Version 2 only ("GPL") or the Common
20.11 + * Development and Distribution License("CDDL") (collectively, the
20.12 + * "License"). You may not use this file except in compliance with the
20.13 + * License. You can obtain a copy of the License at
20.14 + * http://www.netbeans.org/cddl-gplv2.html
20.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
20.16 + * specific language governing permissions and limitations under the
20.17 + * License. When distributing the software, include this License Header
20.18 + * Notice in each file and include the License file at
20.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
20.20 + * particular file as subject to the "Classpath" exception as provided
20.21 + * by Sun in the GPL Version 2 section of the License file that
20.22 + * accompanied this code. If applicable, add the following below the
20.23 + * License Header, with the fields enclosed by brackets [] replaced by
20.24 + * your own identifying information:
20.25 + * "Portions Copyrighted [year] [name of copyright owner]"
20.26 + *
20.27 + * Contributor(s):
20.28 + *
20.29 + * The Original Software is NetBeans. The Initial Developer of the Original
20.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
20.31 + * Microsystems, Inc. All Rights Reserved.
20.32 + *
20.33 + * If you wish your version of this file to be governed by only the CDDL
20.34 + * or only the GPL Version 2, indicate your decision by adding
20.35 + * "[Contributor] elects to include this software in this distribution
20.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
20.37 + * single choice of license, a recipient has the option to distribute
20.38 + * your version of this file under either the CDDL, the GPL Version 2 or
20.39 + * to extend the choice of license to its licensees as provided above.
20.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
20.41 + * Version 2 license, then the option applies only if the new code is
20.42 + * made subject to such option by the copyright holder.
20.43 + */
20.44 +
20.45 +package org.openide.util.lookup;
20.46 +
20.47 +import java.lang.ref.Reference;
20.48 +import java.lang.ref.WeakReference;
20.49 +import java.util.ArrayList;
20.50 +import java.util.Arrays;
20.51 +import java.util.Collection;
20.52 +import java.util.Collections;
20.53 +import java.util.HashMap;
20.54 +import java.util.HashSet;
20.55 +import java.util.IdentityHashMap;
20.56 +import java.util.Iterator;
20.57 +import java.util.List;
20.58 +import java.util.Map;
20.59 +import java.util.Map.Entry;
20.60 +import java.util.Set;
20.61 +import java.util.concurrent.Executor;
20.62 +import javax.swing.event.EventListenerList;
20.63 +import org.openide.util.Lookup;
20.64 +import org.openide.util.LookupEvent;
20.65 +import org.openide.util.LookupListener;
20.66 +
20.67 +/** Implementation of lookup that can delegate to others.
20.68 + *
20.69 + * @author Jaroslav Tulach
20.70 + * @since 1.9
20.71 + */
20.72 +public class ProxyLookup extends Lookup {
20.73 + /** data representing the state of the lookup */
20.74 + private ImmutableInternalData data;
20.75 +
20.76 + /** Create a proxy to some other lookups.
20.77 + * @param lookups the initial delegates
20.78 + */
20.79 + public ProxyLookup(Lookup... lookups) {
20.80 + data = ImmutableInternalData.EMPTY.setLookupsNoFire(lookups, true);
20.81 + }
20.82 +
20.83 + /**
20.84 + * Create a lookup initially proxying to no others.
20.85 + * Permits serializable subclasses.
20.86 + * @since 3.27
20.87 + */
20.88 + protected ProxyLookup() {
20.89 + data = ImmutableInternalData.EMPTY;
20.90 + }
20.91 +
20.92 + @Override
20.93 + public synchronized String toString() {
20.94 + return "ProxyLookup(class=" + getClass() + ")->" + Arrays.asList(getData().getLookups(false)); // NOI18N
20.95 + }
20.96 +
20.97 + /** Getter for the delegates.
20.98 + * @return the array of lookups we delegate to
20.99 + * @since 1.19
20.100 + */
20.101 + protected final Lookup[] getLookups() {
20.102 + synchronized (ProxyLookup.this) {
20.103 + return getData().getLookups(true);
20.104 + }
20.105 + }
20.106 +
20.107 + private Set<Lookup> identityHashSet(Collection<Lookup> current) {
20.108 + Map<Lookup,Void> map = new IdentityHashMap<Lookup, Void>();
20.109 + for (Lookup lookup : current) {
20.110 + map.put(lookup, null);
20.111 + }
20.112 + return map.keySet();
20.113 + }
20.114 +
20.115 + /**
20.116 + * Changes the delegates.
20.117 + *
20.118 + * @param lookups the new lookups to delegate to
20.119 + * @since 1.19 protected
20.120 + */
20.121 + protected final void setLookups(Lookup... lookups) {
20.122 + setLookups(null, lookups);
20.123 + }
20.124 +
20.125 + /**
20.126 + * Changes the delegates immediatelly, notifies the listeners in provided
20.127 + * executor, potentially later.
20.128 + *
20.129 + * @param lookups the new lookups to delegate to
20.130 + * @param notifyIn executor to deliver the notification to listeners or null
20.131 + * @since 7.16
20.132 + */
20.133 + protected final void setLookups(Executor notifyIn, Lookup... lookups) {
20.134 + Collection<Reference<R>> arr;
20.135 + Set<Lookup> newL;
20.136 + Set<Lookup> current;
20.137 + Lookup[] old;
20.138 +
20.139 + Map<Result,LookupListener> toRemove = new IdentityHashMap<Lookup.Result, LookupListener>();
20.140 + Map<Result,LookupListener> toAdd = new IdentityHashMap<Lookup.Result, LookupListener>();
20.141 +
20.142 + ImmutableInternalData orig;
20.143 + synchronized (ProxyLookup.this) {
20.144 + orig = getData();
20.145 + ImmutableInternalData newData = getData().setLookupsNoFire(lookups, false);
20.146 + if (newData == getData()) {
20.147 + return;
20.148 + }
20.149 + arr = setData(newData, lookups, toAdd, toRemove);
20.150 + }
20.151 +
20.152 + // better to do this later than in synchronized block
20.153 + for (Map.Entry<Result, LookupListener> e : toRemove.entrySet()) {
20.154 + e.getKey().removeLookupListener(e.getValue());
20.155 + }
20.156 + for (Map.Entry<Result, LookupListener> e : toAdd.entrySet()) {
20.157 + e.getKey().addLookupListener(e.getValue());
20.158 + }
20.159 +
20.160 +
20.161 + // this cannot be done from the synchronized block
20.162 + final ArrayList<Object> evAndListeners = new ArrayList<Object>();
20.163 + for (Reference<R> ref : arr) {
20.164 + R<?> r = ref.get();
20.165 + if (r != null) {
20.166 + r.collectFires(evAndListeners);
20.167 + }
20.168 + }
20.169 +
20.170 + class Notify implements Runnable {
20.171 + public void run() {
20.172 + Iterator it = evAndListeners.iterator();
20.173 + while (it.hasNext()) {
20.174 + LookupEvent ev = (LookupEvent)it.next();
20.175 + LookupListener l = (LookupListener)it.next();
20.176 + l.resultChanged(ev);
20.177 + }
20.178 + }
20.179 + }
20.180 + Notify n = new Notify();
20.181 + if (notifyIn == null) {
20.182 + n.run();
20.183 + } else {
20.184 + notifyIn.execute(n);
20.185 + }
20.186 + }
20.187 +
20.188 + /** Notifies subclasses that a query is about to be processed.
20.189 + * Subclasses can update its state before the actual processing
20.190 + * begins. It is allowed to call <code>setLookups</code> method
20.191 + * to change/update the set of objects the proxy delegates to.
20.192 + *
20.193 + * @param template the template of the query
20.194 + * @since 1.31
20.195 + */
20.196 + protected void beforeLookup(Template<?> template) {
20.197 + }
20.198 +
20.199 + public final <T> T lookup(Class<T> clazz) {
20.200 + beforeLookup(new Template<T>(clazz));
20.201 +
20.202 + Lookup[] tmpLkps;
20.203 + synchronized (ProxyLookup.this) {
20.204 + tmpLkps = getData().getLookups(false);
20.205 + }
20.206 +
20.207 + for (int i = 0; i < tmpLkps.length; i++) {
20.208 + T o = tmpLkps[i].lookup(clazz);
20.209 +
20.210 + if (o != null) {
20.211 + return o;
20.212 + }
20.213 + }
20.214 +
20.215 + return null;
20.216 + }
20.217 +
20.218 + @Override
20.219 + public final <T> Item<T> lookupItem(Template<T> template) {
20.220 + beforeLookup(template);
20.221 +
20.222 + Lookup[] tmpLkps;
20.223 + synchronized (ProxyLookup.this) {
20.224 + tmpLkps = getData().getLookups(false);
20.225 + }
20.226 +
20.227 + for (int i = 0; i < tmpLkps.length; i++) {
20.228 + Item<T> o = tmpLkps[i].lookupItem(template);
20.229 +
20.230 + if (o != null) {
20.231 + return o;
20.232 + }
20.233 + }
20.234 +
20.235 + return null;
20.236 + }
20.237 +
20.238 + @SuppressWarnings("unchecked")
20.239 + private static <T> R<T> convertResult(R r) {
20.240 + return (R<T>)r;
20.241 + }
20.242 +
20.243 + public final <T> Result<T> lookup(Lookup.Template<T> template) {
20.244 + synchronized (ProxyLookup.this) {
20.245 + ImmutableInternalData[] res = { null };
20.246 + R<T> newR = getData().findResult(this, res, template);
20.247 + setData(res[0], getData().getLookups(false), null, null);
20.248 + return newR;
20.249 + }
20.250 + }
20.251 +
20.252 + /** Unregisters a template from the has map.
20.253 + */
20.254 + private final void unregisterTemplate(Template<?> template) {
20.255 + synchronized (ProxyLookup.this) {
20.256 + ImmutableInternalData id = getData();
20.257 + if (id == null) {
20.258 + return;
20.259 + }
20.260 + setData(id.removeTemplate(this, template), getData().getLookups(false), null, null);
20.261 + }
20.262 + }
20.263 +
20.264 + private ImmutableInternalData getData() {
20.265 + assert Thread.holdsLock(this);
20.266 + return data;
20.267 + }
20.268 +
20.269 + private Collection<Reference<R>> setData(
20.270 + ImmutableInternalData newData, Lookup[] current,
20.271 + Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
20.272 + ) {
20.273 + assert Thread.holdsLock(ProxyLookup.this);
20.274 + assert newData != null;
20.275 +
20.276 + ImmutableInternalData previous = this.getData();
20.277 +
20.278 + if (previous == newData) {
20.279 + return Collections.emptyList();
20.280 + }
20.281 +
20.282 + if (newData.isEmpty()) {
20.283 + this.setData(newData);
20.284 + // no affected results => exit
20.285 + return Collections.emptyList();
20.286 + }
20.287 +
20.288 + Collection<Reference<R>> arr = newData.references();
20.289 +
20.290 + Set<Lookup> removed = identityHashSet(previous.getLookupsList());
20.291 + Set<Lookup> currentSet = identityHashSet(Arrays.asList(current));
20.292 + Set<Lookup> newL = identityHashSet(currentSet);
20.293 + removed.removeAll(currentSet); // current contains just those lookups that have disappeared
20.294 + newL.removeAll(previous.getLookupsList()); // really new lookups
20.295 +
20.296 + for (Reference<R> ref : arr) {
20.297 + R<?> r = ref.get();
20.298 + if (r != null) {
20.299 + r.lookupChange(newData, current, previous, newL, removed, toAdd, toRemove);
20.300 + if (this.getData() != previous) {
20.301 + // the data were changed by an re-entrant call
20.302 + // skip any other change processing, as it is not needed
20.303 + // anymore
20.304 + }
20.305 + }
20.306 + }
20.307 + for (Reference<R> ref : arr) {
20.308 + R<?> r = ref.get();
20.309 + if (r != null) {
20.310 + r.data = newData;
20.311 + }
20.312 + }
20.313 + this.setData(newData);
20.314 + return arr;
20.315 + }
20.316 +
20.317 + private void setData(ImmutableInternalData data) {
20.318 + this.data = data;
20.319 + }
20.320 +
20.321 + /** Result of a lookup request. Allows access to single object
20.322 + * that was found (not too useful) and also to all objects found
20.323 + * (more useful).
20.324 + */
20.325 + private static final class R<T> extends WaitableResult<T> {
20.326 + /** weak listener & result */
20.327 + private final WeakResult<T> weakL;
20.328 +
20.329 + /** list of listeners added */
20.330 + private javax.swing.event.EventListenerList listeners;
20.331 +
20.332 + /** collection of Objects */
20.333 + private Collection[] cache;
20.334 +
20.335 +
20.336 + /** associated lookup */
20.337 + private ImmutableInternalData data;
20.338 +
20.339 + /** Constructor.
20.340 + */
20.341 + public R(ProxyLookup proxy, Lookup.Template<T> t) {
20.342 + this.weakL = new WeakResult<T>(proxy, this, t);
20.343 + }
20.344 +
20.345 + private ProxyLookup proxy() {
20.346 + return weakL.result.proxy;
20.347 + }
20.348 +
20.349 + @SuppressWarnings("unchecked")
20.350 + private Result<T>[] newResults(int len) {
20.351 + return new Result[len];
20.352 + }
20.353 +
20.354 + @Override
20.355 + protected void finalize() {
20.356 + weakL.result.run();
20.357 + }
20.358 +
20.359 + /** initializes the results
20.360 + */
20.361 + private Result<T>[] initResults() {
20.362 + BIG_LOOP: for (;;) {
20.363 + Lookup[] myLkps;
20.364 + ImmutableInternalData current;
20.365 + synchronized (proxy()) {
20.366 + if (weakL.getResults() != null) {
20.367 + return weakL.getResults();
20.368 + }
20.369 + myLkps = data.getLookups(false);
20.370 + current = data;
20.371 + }
20.372 +
20.373 + Result<T>[] arr = newResults(myLkps.length);
20.374 +
20.375 + for (int i = 0; i < arr.length; i++) {
20.376 + arr[i] = myLkps[i].lookup(weakL.result.template);
20.377 + }
20.378 +
20.379 + synchronized (proxy()) {
20.380 + if (current != data) {
20.381 + continue;
20.382 + }
20.383 +
20.384 + Lookup[] currentLkps = data.getLookups(false);
20.385 + if (currentLkps.length != myLkps.length) {
20.386 + continue BIG_LOOP;
20.387 + }
20.388 + for (int i = 0; i < currentLkps.length; i++) {
20.389 + if (currentLkps[i] != myLkps[i]) {
20.390 + continue BIG_LOOP;
20.391 + }
20.392 + }
20.393 +
20.394 + // some other thread might compute the result mean while.
20.395 + // if not finish the computation yourself
20.396 + if (weakL.getResults() != null) {
20.397 + return weakL.getResults();
20.398 + }
20.399 +
20.400 + for (int i = 0; i < arr.length; i++) {
20.401 + arr[i].addLookupListener(weakL);
20.402 + }
20.403 +
20.404 + weakL.setResults(arr);
20.405 +
20.406 + return arr;
20.407 + }
20.408 + }
20.409 + }
20.410 +
20.411 + /** Called when there is a change in the list of proxied lookups.
20.412 + * @param added set of added lookups
20.413 + * @param remove set of removed lookups
20.414 + * @param current array of current lookups
20.415 + */
20.416 + final void lookupChange(
20.417 + ImmutableInternalData newData, Lookup[] current, ImmutableInternalData oldData,
20.418 + Set<Lookup> added, Set<Lookup> removed,
20.419 + Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
20.420 + ) {
20.421 + if (weakL.getResults() == null) {
20.422 + // not computed yet, do not need to do anything
20.423 + return;
20.424 + }
20.425 +
20.426 + Lookup[] old = oldData.getLookups(false);
20.427 +
20.428 + // map (Lookup, Lookup.Result)
20.429 + Map<Lookup,Result<T>> map = new IdentityHashMap<Lookup,Result<T>>(old.length * 2);
20.430 +
20.431 + for (int i = 0; i < old.length; i++) {
20.432 + if (removed.contains(old[i])) {
20.433 + // removed lookup
20.434 + if (toRemove != null) {
20.435 + toRemove.put(weakL.getResults()[i], weakL);
20.436 + }
20.437 + } else {
20.438 + // remember the association
20.439 + map.put(old[i], weakL.getResults()[i]);
20.440 + }
20.441 + }
20.442 +
20.443 + Lookup.Result<T>[] arr = newResults(current.length);
20.444 +
20.445 + for (int i = 0; i < current.length; i++) {
20.446 + if (added.contains(current[i])) {
20.447 + // new lookup
20.448 + arr[i] = current[i].lookup(weakL.result.template);
20.449 + if (toAdd != null) {
20.450 + toAdd.put(arr[i], weakL);
20.451 + }
20.452 + } else {
20.453 + // old lookup
20.454 + arr[i] = map.get(current[i]);
20.455 +
20.456 + if (arr[i] == null) {
20.457 + // assert
20.458 + throw new IllegalStateException();
20.459 + }
20.460 + }
20.461 + }
20.462 +
20.463 + // remember the new results
20.464 + weakL.setResults(arr);
20.465 + }
20.466 +
20.467 + /** Just delegates.
20.468 + */
20.469 + public void addLookupListener(LookupListener l) {
20.470 + synchronized (proxy()) {
20.471 + if (listeners == null) {
20.472 + listeners = new EventListenerList();
20.473 + }
20.474 + }
20.475 +
20.476 + listeners.add(LookupListener.class, l);
20.477 + }
20.478 +
20.479 + /** Just delegates.
20.480 + */
20.481 + public void removeLookupListener(LookupListener l) {
20.482 + if (listeners != null) {
20.483 + listeners.remove(LookupListener.class, l);
20.484 + }
20.485 + }
20.486 +
20.487 + /** Access to all instances in the result.
20.488 + * @return collection of all instances
20.489 + */
20.490 + @SuppressWarnings("unchecked")
20.491 + public java.util.Collection<T> allInstances() {
20.492 + return computeResult(0);
20.493 + }
20.494 +
20.495 + /** Classes of all results. Set of the most concreate classes
20.496 + * that are registered in the system.
20.497 + * @return set of Class objects
20.498 + */
20.499 + @SuppressWarnings("unchecked")
20.500 + @Override
20.501 + public java.util.Set<Class<? extends T>> allClasses() {
20.502 + return (java.util.Set<Class<? extends T>>) computeResult(1);
20.503 + }
20.504 +
20.505 + /** All registered items. The collection of all pairs of
20.506 + * ii and their classes.
20.507 + * @return collection of Lookup.Item
20.508 + */
20.509 + @SuppressWarnings("unchecked")
20.510 + @Override
20.511 + public java.util.Collection<? extends Item<T>> allItems() {
20.512 + return computeResult(2);
20.513 + }
20.514 +
20.515 + /** Computes results from proxied lookups.
20.516 + * @param indexToCache 0 = allInstances, 1 = allClasses, 2 = allItems
20.517 + * @return the collection or set of the objects
20.518 + */
20.519 + private java.util.Collection computeResult(int indexToCache) {
20.520 + // results to use
20.521 + Lookup.Result<T>[] arr = myBeforeLookup();
20.522 +
20.523 + // if the call to beforeLookup resulted in deletion of caches
20.524 + synchronized (proxy()) {
20.525 + if (getCache() != null) {
20.526 + Collection result = getCache()[indexToCache];
20.527 + if (result != null) {
20.528 + return result;
20.529 + }
20.530 + }
20.531 + }
20.532 +
20.533 + // initialize the collection to hold result
20.534 + Collection<Object> compute;
20.535 + Collection<Object> ret;
20.536 +
20.537 + if (indexToCache == 1) {
20.538 + HashSet<Object> s = new HashSet<Object>();
20.539 + compute = s;
20.540 + ret = Collections.unmodifiableSet(s);
20.541 + } else {
20.542 + List<Object> l = new ArrayList<Object>(arr.length * 2);
20.543 + compute = l;
20.544 + ret = Collections.unmodifiableList(l);
20.545 + }
20.546 +
20.547 + // fill the collection
20.548 + for (int i = 0; i < arr.length; i++) {
20.549 + switch (indexToCache) {
20.550 + case 0:
20.551 + compute.addAll(arr[i].allInstances());
20.552 + break;
20.553 + case 1:
20.554 + compute.addAll(arr[i].allClasses());
20.555 + break;
20.556 + case 2:
20.557 + compute.addAll(arr[i].allItems());
20.558 + break;
20.559 + default:
20.560 + assert false : "Wrong index: " + indexToCache;
20.561 + }
20.562 + }
20.563 +
20.564 +
20.565 +
20.566 + synchronized (proxy()) {
20.567 + if (getCache() == null) {
20.568 + // initialize the cache to indicate this result is in use
20.569 + setCache(new Collection[3]);
20.570 + }
20.571 +
20.572 + if (arr == weakL.getResults()) {
20.573 + // updates the results, if the results have not been
20.574 + // changed during the computation of allInstances
20.575 + getCache()[indexToCache] = ret;
20.576 + }
20.577 + }
20.578 +
20.579 + return ret;
20.580 + }
20.581 +
20.582 + /** When the result changes, fire the event.
20.583 + */
20.584 + public void resultChanged(LookupEvent ev) {
20.585 + collectFires(null);
20.586 + }
20.587 +
20.588 + protected void collectFires(Collection<Object> evAndListeners) {
20.589 + // clear cached instances
20.590 + Collection oldItems;
20.591 + Collection oldInstances;
20.592 + synchronized (proxy()) {
20.593 + if (getCache() == null) {
20.594 + // nobody queried the result yet
20.595 + return;
20.596 + }
20.597 + oldInstances = getCache()[0];
20.598 + oldItems = getCache()[2];
20.599 +
20.600 +
20.601 + if (listeners == null || listeners.getListenerCount() == 0) {
20.602 + // clear the cache
20.603 + setCache(new Collection[3]);
20.604 + return;
20.605 + }
20.606 +
20.607 + // ignore events if they arrive as a result of call to allItems
20.608 + // or allInstances, bellow...
20.609 + setCache(null);
20.610 + }
20.611 +
20.612 + boolean modified = true;
20.613 +
20.614 + if (oldItems != null) {
20.615 + Collection newItems = allItems();
20.616 + if (oldItems.equals(newItems)) {
20.617 + modified = false;
20.618 + }
20.619 + } else {
20.620 + if (oldInstances != null) {
20.621 + Collection newInstances = allInstances();
20.622 + if (oldInstances.equals(newInstances)) {
20.623 + modified = false;
20.624 + }
20.625 + } else {
20.626 + synchronized (proxy()) {
20.627 + if (getCache() == null) {
20.628 + // we have to initialize the cache
20.629 + // to show that the result has been initialized
20.630 + setCache(new Collection[3]);
20.631 + }
20.632 + }
20.633 + }
20.634 + }
20.635 +
20.636 + if (modified) {
20.637 + LookupEvent ev = new LookupEvent(this);
20.638 + AbstractLookup.notifyListeners(listeners.getListenerList(), ev, evAndListeners);
20.639 + }
20.640 + }
20.641 +
20.642 + /** Implementation of my before lookup.
20.643 + * @return results to work on.
20.644 + */
20.645 + private Lookup.Result<T>[] myBeforeLookup() {
20.646 + Template<T> template = weakL.result.template;
20.647 +
20.648 + proxy().beforeLookup(template);
20.649 +
20.650 + Lookup.Result<T>[] arr = initResults();
20.651 +
20.652 + // invoke update on the results
20.653 + for (int i = 0; i < arr.length; i++) {
20.654 + if (arr[i] instanceof WaitableResult) {
20.655 + WaitableResult w = (WaitableResult) arr[i];
20.656 + w.beforeLookup(template);
20.657 + }
20.658 + }
20.659 +
20.660 + return arr;
20.661 + }
20.662 +
20.663 + /** Used by proxy results to synchronize before lookup.
20.664 + */
20.665 + protected void beforeLookup(Lookup.Template t) {
20.666 + if (t.getType() == weakL.result.template.getType()) {
20.667 + myBeforeLookup();
20.668 + }
20.669 + }
20.670 +
20.671 + private Collection[] getCache() {
20.672 + return cache;
20.673 + }
20.674 +
20.675 + private void setCache(Collection[] cache) {
20.676 + assert Thread.holdsLock(proxy());
20.677 + this.cache = cache;
20.678 + }
20.679 + }
20.680 + private static final class WeakRef<T> extends WeakReference<R> implements Runnable {
20.681 + final WeakResult<T> result;
20.682 + final ProxyLookup proxy;
20.683 + final Template<T> template;
20.684 +
20.685 + public WeakRef(R r, WeakResult<T> result, ProxyLookup proxy, Template<T> template) {
20.686 + super(r);
20.687 + this.result = result;
20.688 + this.template = template;
20.689 + this.proxy = proxy;
20.690 + }
20.691 +
20.692 + public void run() {
20.693 + result.removeListeners();
20.694 + proxy.unregisterTemplate(template);
20.695 + }
20.696 + }
20.697 +
20.698 +
20.699 + private static final class WeakResult<T> extends WaitableResult<T> implements LookupListener, Runnable {
20.700 + /** all results */
20.701 + private Lookup.Result<T>[] results;
20.702 + private final WeakRef<T> result;
20.703 +
20.704 + public WeakResult(ProxyLookup proxy, R r, Template<T> t) {
20.705 + this.result = new WeakRef<T>(r, this, proxy, t);
20.706 + }
20.707 +
20.708 + final void removeListeners() {
20.709 + Lookup.Result<T>[] arr = this.getResults();
20.710 + if (arr == null) {
20.711 + return;
20.712 + }
20.713 +
20.714 + for(int i = 0; i < arr.length; i++) {
20.715 + arr[i].removeLookupListener(this);
20.716 + }
20.717 + }
20.718 +
20.719 + protected void beforeLookup(Lookup.Template t) {
20.720 + R r = result.get();
20.721 + if (r != null) {
20.722 + r.beforeLookup(t);
20.723 + } else {
20.724 + removeListeners();
20.725 + }
20.726 + }
20.727 +
20.728 + protected void collectFires(Collection<Object> evAndListeners) {
20.729 + R<?> r = result.get();
20.730 + if (r != null) {
20.731 + r.collectFires(evAndListeners);
20.732 + } else {
20.733 + removeListeners();
20.734 + }
20.735 + }
20.736 +
20.737 + public void addLookupListener(LookupListener l) {
20.738 + assert false;
20.739 + }
20.740 +
20.741 + public void removeLookupListener(LookupListener l) {
20.742 + assert false;
20.743 + }
20.744 +
20.745 + public Collection<T> allInstances() {
20.746 + assert false;
20.747 + return null;
20.748 + }
20.749 +
20.750 + public void resultChanged(LookupEvent ev) {
20.751 + R r = result.get();
20.752 + if (r != null) {
20.753 + r.resultChanged(ev);
20.754 + } else {
20.755 + removeListeners();
20.756 + }
20.757 + }
20.758 +
20.759 + @Override
20.760 + public Collection<? extends Item<T>> allItems() {
20.761 + assert false;
20.762 + return null;
20.763 + }
20.764 +
20.765 + @Override
20.766 + public Set<Class<? extends T>> allClasses() {
20.767 + assert false;
20.768 + return null;
20.769 + }
20.770 +
20.771 + public void run() {
20.772 + removeListeners();
20.773 + }
20.774 +
20.775 + private Lookup.Result<T>[] getResults() {
20.776 + return results;
20.777 + }
20.778 +
20.779 + private void setResults(Lookup.Result<T>[] results) {
20.780 + this.results = results;
20.781 + }
20.782 + } // end of WeakResult
20.783 +
20.784 + static abstract class ImmutableInternalData extends Object {
20.785 + static final ImmutableInternalData EMPTY = new EmptyInternalData();
20.786 + static final Lookup[] EMPTY_ARR = new Lookup[0];
20.787 +
20.788 +
20.789 + protected ImmutableInternalData() {
20.790 + }
20.791 +
20.792 + public static ImmutableInternalData create(Object lkp, Map<Template, Reference<R>> results) {
20.793 + if (results.size() == 0 && lkp == EMPTY_ARR) {
20.794 + return EMPTY;
20.795 + }
20.796 + if (results.size() == 1) {
20.797 + Entry<Template,Reference<R>> e = results.entrySet().iterator().next();
20.798 + return new SingleInternalData(lkp, e.getKey(), e.getValue());
20.799 + }
20.800 +
20.801 + return new RealInternalData(lkp, results);
20.802 + }
20.803 +
20.804 + protected abstract boolean isEmpty();
20.805 + protected abstract Map<Template, Reference<R>> getResults();
20.806 + protected abstract Object getRawLookups();
20.807 +
20.808 + final Collection<Reference<R>> references() {
20.809 + return getResults().values();
20.810 + }
20.811 +
20.812 + final <T> ImmutableInternalData removeTemplate(ProxyLookup proxy, Template<T> template) {
20.813 + if (getResults().containsKey(template)) {
20.814 + HashMap<Template,Reference<R>> c = new HashMap<Template, Reference<ProxyLookup.R>>(getResults());
20.815 + Reference<R> ref = c.remove(template);
20.816 + if (ref != null && ref.get() != null) {
20.817 + // seems like there is a reference to a result for this template
20.818 + // thta is still alive
20.819 + return this;
20.820 + }
20.821 + return create(getRawLookups(), c);
20.822 + } else {
20.823 + return this;
20.824 + }
20.825 + }
20.826 +
20.827 + <T> R<T> findResult(ProxyLookup proxy, ImmutableInternalData[] newData, Template<T> template) {
20.828 + assert Thread.holdsLock(proxy);
20.829 +
20.830 + Map<Template,Reference<R>> map = getResults();
20.831 +
20.832 + Reference<R> ref = map.get(template);
20.833 + R r = (ref == null) ? null : ref.get();
20.834 +
20.835 + if (r != null) {
20.836 + newData[0] = this;
20.837 + return convertResult(r);
20.838 + }
20.839 +
20.840 + HashMap<Template, Reference<R>> res = new HashMap<Template, Reference<R>>(map);
20.841 + R<T> newR = new R<T>(proxy, template);
20.842 + res.put(template, new java.lang.ref.SoftReference<R>(newR));
20.843 + newR.data = newData[0] = create(getRawLookups(), res);
20.844 + return newR;
20.845 + }
20.846 + final ImmutableInternalData setLookupsNoFire(Lookup[] lookups, boolean skipCheck) {
20.847 + Object l;
20.848 +
20.849 + if (!skipCheck) {
20.850 + Lookup[] previous = getLookups(false);
20.851 + if (previous == lookups) {
20.852 + return this;
20.853 + }
20.854 +
20.855 + if (previous.length == lookups.length) {
20.856 + int same = 0;
20.857 + for (int i = 0; i < previous.length; i++) {
20.858 + if (lookups[i] != previous[i]) {
20.859 + break;
20.860 + }
20.861 + same++;
20.862 + }
20.863 + if (same == previous.length) {
20.864 + return this;
20.865 + }
20.866 + }
20.867 + }
20.868 +
20.869 + if (lookups.length == 1) {
20.870 + l = lookups[0];
20.871 + assert l != null : "Cannot assign null delegate";
20.872 + } else {
20.873 + if (lookups.length == 0) {
20.874 + l = EMPTY_ARR;
20.875 + } else {
20.876 + l = lookups.clone();
20.877 + }
20.878 + }
20.879 +
20.880 + if (isEmpty() && l == EMPTY_ARR) {
20.881 + return this;
20.882 + }
20.883 +
20.884 + return create(l, getResults());
20.885 + }
20.886 + final Lookup[] getLookups(boolean clone) {
20.887 + Object l = this.getRawLookups();
20.888 + if (l instanceof Lookup) {
20.889 + return new Lookup[] { (Lookup)l };
20.890 + } else {
20.891 + Lookup[] arr = (Lookup[])l;
20.892 + if (clone) {
20.893 + arr = arr.clone();
20.894 + }
20.895 + return arr;
20.896 + }
20.897 + }
20.898 + final List<Lookup> getLookupsList() {
20.899 + return Arrays.asList(getLookups(false));
20.900 + }
20.901 +
20.902 + } // end of ImmutableInternalData
20.903 +
20.904 + private static final class SingleInternalData extends ImmutableInternalData {
20.905 + /** lookups to delegate to (either Lookup or array of Lookups) */
20.906 + private final Object lookups;
20.907 + private final Template template;
20.908 + private final Reference<ProxyLookup.R> result;
20.909 +
20.910 + public SingleInternalData(Object lookups, Template<?> template, Reference<ProxyLookup.R> result) {
20.911 + this.lookups = lookups;
20.912 + this.template = template;
20.913 + this.result = result;
20.914 + }
20.915 +
20.916 + protected final boolean isEmpty() {
20.917 + return false;
20.918 + }
20.919 +
20.920 + protected Map<Template, Reference<R>> getResults() {
20.921 + return Collections.singletonMap(template, result);
20.922 + }
20.923 +
20.924 + protected Object getRawLookups() {
20.925 + return lookups;
20.926 + }
20.927 + }
20.928 + private static final class RealInternalData extends ImmutableInternalData {
20.929 + /** lookups to delegate to (either Lookup or array of Lookups) */
20.930 + private final Object lookups;
20.931 +
20.932 + /** map of templates to currently active results */
20.933 + private final Map<Template,Reference<R>> results;
20.934 +
20.935 + public RealInternalData(Object lookups, Map<Template, Reference<ProxyLookup.R>> results) {
20.936 + this.results = results;
20.937 + this.lookups = lookups;
20.938 + }
20.939 +
20.940 + protected final boolean isEmpty() {
20.941 + return false;
20.942 + }
20.943 +
20.944 + protected Map<Template, Reference<R>> getResults() {
20.945 + boolean strict = false;
20.946 + assert strict = true;
20.947 + return strict ? Collections.unmodifiableMap(results) : results;
20.948 + }
20.949 +
20.950 + protected Object getRawLookups() {
20.951 + return lookups;
20.952 + }
20.953 + }
20.954 +
20.955 + private static final class EmptyInternalData extends ImmutableInternalData {
20.956 + EmptyInternalData() {
20.957 + }
20.958 +
20.959 + protected final boolean isEmpty() {
20.960 + return true;
20.961 + }
20.962 +
20.963 + protected Map<Template, Reference<R>> getResults() {
20.964 + return Collections.emptyMap();
20.965 + }
20.966 +
20.967 + @Override
20.968 + protected Object getRawLookups() {
20.969 + return EMPTY_ARR;
20.970 + }
20.971 + } // end of EmptyInternalData
20.972 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ServiceProvider.java Sat Oct 31 15:28:13 2009 +0100
21.3 @@ -0,0 +1,102 @@
21.4 +/*
21.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
21.6 + *
21.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
21.8 + *
21.9 + * The contents of this file are subject to the terms of either the GNU
21.10 + * General Public License Version 2 only ("GPL") or the Common
21.11 + * Development and Distribution License("CDDL") (collectively, the
21.12 + * "License"). You may not use this file except in compliance with the
21.13 + * License. You can obtain a copy of the License at
21.14 + * http://www.netbeans.org/cddl-gplv2.html
21.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
21.16 + * specific language governing permissions and limitations under the
21.17 + * License. When distributing the software, include this License Header
21.18 + * Notice in each file and include the License file at
21.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
21.20 + * particular file as subject to the "Classpath" exception as provided
21.21 + * by Sun in the GPL Version 2 section of the License file that
21.22 + * accompanied this code. If applicable, add the following below the
21.23 + * License Header, with the fields enclosed by brackets [] replaced by
21.24 + * your own identifying information:
21.25 + * "Portions Copyrighted [year] [name of copyright owner]"
21.26 + *
21.27 + * If you wish your version of this file to be governed by only the CDDL
21.28 + * or only the GPL Version 2, indicate your decision by adding
21.29 + * "[Contributor] elects to include this software in this distribution
21.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
21.31 + * single choice of license, a recipient has the option to distribute
21.32 + * your version of this file under either the CDDL, the GPL Version 2 or
21.33 + * to extend the choice of license to its licensees as provided above.
21.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
21.35 + * Version 2 license, then the option applies only if the new code is
21.36 + * made subject to such option by the copyright holder.
21.37 + *
21.38 + * Contributor(s):
21.39 + *
21.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
21.41 + */
21.42 +
21.43 +package org.openide.util.lookup;
21.44 +
21.45 +import java.lang.annotation.ElementType;
21.46 +import java.lang.annotation.Retention;
21.47 +import java.lang.annotation.RetentionPolicy;
21.48 +import java.lang.annotation.Target;
21.49 +import org.openide.util.Lookup;
21.50 +
21.51 +/**
21.52 + * Declarative registration of a singleton service provider.
21.53 + * By marking an implementation class with this annotation,
21.54 + * you automatically register that implementation, normally in {@link Lookup#getDefault}.
21.55 + * The class must be public and have a public no-argument constructor.
21.56 + * <p>Example of usage:
21.57 + * <pre>
21.58 + * package my.module;
21.59 + * import org.netbeans.spi.whatever.Thing;
21.60 + * import org.openide.util.lookup.ServiceProvider;
21.61 + * @ServiceProvider(service=Thing.class)
21.62 + * public class MyThing implements Thing {...}
21.63 + * </pre>
21.64 + * <p>would result in a resource file <code>META-INF/services/org.netbeans.spi.whatever.Thing</code>
21.65 + * containing the single line of text: <code>my.module.MyThing</code>
21.66 + * @see Lookups#metaInfServices(ClassLoader)
21.67 + * @since org.openide.util 7.20
21.68 + */
21.69 +@Retention(RetentionPolicy.SOURCE)
21.70 +@Target(ElementType.TYPE)
21.71 +public @interface ServiceProvider {
21.72 +
21.73 + /**
21.74 + * The interface (or abstract class) to register this implementation under.
21.75 + * It is an error if the implementation class is not in fact assignable to the interface.
21.76 + * <p>If you need to register one class under multiple interfaces, use {@link ServiceProviders}.
21.77 + * <p>Requests to look up the specified interface should result in this implementation.
21.78 + * Requests for any other types may or may not result in this implementation even if the
21.79 + * implementation is assignable to those types.
21.80 + */
21.81 + Class<?> service();
21.82 +
21.83 + /**
21.84 + * An optional position in which to register this service relative to others.
21.85 + * Lower-numbered services are returned in the lookup result first.
21.86 + * Services with no specified position are returned last.
21.87 + */
21.88 + int position() default Integer.MAX_VALUE;
21.89 +
21.90 + /**
21.91 + * An optional list of implementations (given as fully-qualified class names) which this implementation supersedes.
21.92 + * If specified, those implementations will not be loaded even if they were registered.
21.93 + * Useful on occasion to cancel a generic implementation and replace it with a more advanced one.
21.94 + */
21.95 + String[] supersedes() default {};
21.96 +
21.97 + /**
21.98 + * An optional path to register this implementation in.
21.99 + * For example, <code>Projects/sometype/Nodes</code> could be used.
21.100 + * This style of registration would be recognized by {@link Lookups#forPath}
21.101 + * rather than {@link Lookup#getDefault}.
21.102 + */
21.103 + String path() default "";
21.104 +
21.105 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ServiceProviders.java Sat Oct 31 15:28:13 2009 +0100
22.3 @@ -0,0 +1,60 @@
22.4 +/*
22.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
22.6 + *
22.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
22.8 + *
22.9 + * The contents of this file are subject to the terms of either the GNU
22.10 + * General Public License Version 2 only ("GPL") or the Common
22.11 + * Development and Distribution License("CDDL") (collectively, the
22.12 + * "License"). You may not use this file except in compliance with the
22.13 + * License. You can obtain a copy of the License at
22.14 + * http://www.netbeans.org/cddl-gplv2.html
22.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
22.16 + * specific language governing permissions and limitations under the
22.17 + * License. When distributing the software, include this License Header
22.18 + * Notice in each file and include the License file at
22.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
22.20 + * particular file as subject to the "Classpath" exception as provided
22.21 + * by Sun in the GPL Version 2 section of the License file that
22.22 + * accompanied this code. If applicable, add the following below the
22.23 + * License Header, with the fields enclosed by brackets [] replaced by
22.24 + * your own identifying information:
22.25 + * "Portions Copyrighted [year] [name of copyright owner]"
22.26 + *
22.27 + * If you wish your version of this file to be governed by only the CDDL
22.28 + * or only the GPL Version 2, indicate your decision by adding
22.29 + * "[Contributor] elects to include this software in this distribution
22.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
22.31 + * single choice of license, a recipient has the option to distribute
22.32 + * your version of this file under either the CDDL, the GPL Version 2 or
22.33 + * to extend the choice of license to its licensees as provided above.
22.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
22.35 + * Version 2 license, then the option applies only if the new code is
22.36 + * made subject to such option by the copyright holder.
22.37 + *
22.38 + * Contributor(s):
22.39 + *
22.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
22.41 + */
22.42 +
22.43 +package org.openide.util.lookup;
22.44 +
22.45 +import java.lang.annotation.ElementType;
22.46 +import java.lang.annotation.Retention;
22.47 +import java.lang.annotation.RetentionPolicy;
22.48 +import java.lang.annotation.Target;
22.49 +
22.50 +/**
22.51 + * Similar to {@link ServiceProvider} but permits multiple registrations of one class.
22.52 + * @since org.openide.util 7.20
22.53 + */
22.54 +@Retention(RetentionPolicy.SOURCE)
22.55 +@Target(ElementType.TYPE)
22.56 +public @interface ServiceProviders {
22.57 +
22.58 + /**
22.59 + * List of service provider registrations.
22.60 + */
22.61 + ServiceProvider[] value();
22.62 +
22.63 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/SimpleLookup.java Sat Oct 31 15:28:13 2009 +0100
23.3 @@ -0,0 +1,250 @@
23.4 +/*
23.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
23.6 + *
23.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
23.8 + *
23.9 + * The contents of this file are subject to the terms of either the GNU
23.10 + * General Public License Version 2 only ("GPL") or the Common
23.11 + * Development and Distribution License("CDDL") (collectively, the
23.12 + * "License"). You may not use this file except in compliance with the
23.13 + * License. You can obtain a copy of the License at
23.14 + * http://www.netbeans.org/cddl-gplv2.html
23.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
23.16 + * specific language governing permissions and limitations under the
23.17 + * License. When distributing the software, include this License Header
23.18 + * Notice in each file and include the License file at
23.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
23.20 + * particular file as subject to the "Classpath" exception as provided
23.21 + * by Sun in the GPL Version 2 section of the License file that
23.22 + * accompanied this code. If applicable, add the following below the
23.23 + * License Header, with the fields enclosed by brackets [] replaced by
23.24 + * your own identifying information:
23.25 + * "Portions Copyrighted [year] [name of copyright owner]"
23.26 + *
23.27 + * Contributor(s):
23.28 + *
23.29 + * The Original Software is NetBeans. The Initial Developer of the Original
23.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
23.31 + * Microsystems, Inc. All Rights Reserved.
23.32 + *
23.33 + * If you wish your version of this file to be governed by only the CDDL
23.34 + * or only the GPL Version 2, indicate your decision by adding
23.35 + * "[Contributor] elects to include this software in this distribution
23.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
23.37 + * single choice of license, a recipient has the option to distribute
23.38 + * your version of this file under either the CDDL, the GPL Version 2 or
23.39 + * to extend the choice of license to its licensees as provided above.
23.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
23.41 + * Version 2 license, then the option applies only if the new code is
23.42 + * made subject to such option by the copyright holder.
23.43 + */
23.44 +package org.openide.util.lookup;
23.45 +
23.46 +import org.openide.util.Lookup;
23.47 +import org.openide.util.LookupListener;
23.48 +
23.49 +import java.util.*;
23.50 +
23.51 +
23.52 +/**
23.53 + * Simple lookup implementation. It can be used to create temporary lookups
23.54 + * that do not change over time. The result stores references to all objects
23.55 + * passed in the constructor. Those objecst are the only ones returned as
23.56 + * result.
23.57 + * @author David Strupl
23.58 + */
23.59 +class SimpleLookup extends org.openide.util.Lookup {
23.60 + /** This variable is initialized in constructor and thus null
23.61 + * value is not allowed as its value. */
23.62 + private Collection<Item<?>> allItems;
23.63 +
23.64 + /**
23.65 + * Creates new Result object with supplied instances parameter.
23.66 + * @param instances to be used to return from the lookup
23.67 + */
23.68 + SimpleLookup(Collection<Object> instances) {
23.69 + allItems = new ArrayList<Item<?>>(instances.size());
23.70 +
23.71 + for (Iterator i = instances.iterator(); i.hasNext();) {
23.72 + allItems.add(new InstanceContent.SimpleItem<Object>(i.next()));
23.73 + }
23.74 + }
23.75 +
23.76 + <T,R> SimpleLookup(Collection<T> keys, InstanceContent.Convertor<? super T,R> conv) {
23.77 + allItems = new ArrayList<Item<?>>(keys.size());
23.78 +
23.79 + for (T item : keys) {
23.80 + allItems.add(new InstanceContent.ConvertingItem<T,R>(item, conv));
23.81 + }
23.82 + }
23.83 +
23.84 + public String toString() {
23.85 + return "SimpleLookup" + lookup(new Template<Object>(Object.class)).allInstances();
23.86 + }
23.87 +
23.88 + public <T> Result<T> lookup(Template<T> template) {
23.89 + if (template == null) {
23.90 + throw new NullPointerException();
23.91 + }
23.92 +
23.93 + return new SimpleResult<T>(template);
23.94 + }
23.95 +
23.96 + public <T> T lookup(Class<T> clazz) {
23.97 + for (Iterator i = allItems.iterator(); i.hasNext();) {
23.98 + Object o = i.next();
23.99 +
23.100 + if (o instanceof AbstractLookup.Pair) {
23.101 + AbstractLookup.Pair<?> p = (AbstractLookup.Pair<?>)o;
23.102 + if (p.instanceOf(clazz)) {
23.103 + Object ret = p.getInstance();
23.104 + if (clazz.isInstance(ret)) {
23.105 + return clazz.cast(ret);
23.106 + }
23.107 + }
23.108 + }
23.109 + }
23.110 + return null;
23.111 + }
23.112 +
23.113 + /** A method that defines matching between Item and Template.
23.114 + * @param item the item to match
23.115 + * @return true if item matches the template requirements, false if not
23.116 + */
23.117 + private static boolean matches(Template<?> t, AbstractLookup.Pair<?> item) {
23.118 + if (!AbstractLookup.matches(t, item, true)) {
23.119 + return false;
23.120 + }
23.121 +
23.122 + Class<?> type = t.getType();
23.123 +
23.124 + if ((type != null) && !type.isAssignableFrom(item.getType())) {
23.125 + return false;
23.126 + }
23.127 +
23.128 + return true;
23.129 + }
23.130 +
23.131 + /**
23.132 + * Result used in SimpleLookup. It holds a reference to the collection
23.133 + * passed in constructor. As the contents of this lookup result never
23.134 + * changes the addLookupListener and removeLookupListener are empty.
23.135 + */
23.136 + private class SimpleResult<T> extends Lookup.Result<T> {
23.137 + /** can be null and is initialized lazily */
23.138 + private Set<Class<? extends T>> classes;
23.139 +
23.140 + /** can be null and is initialized lazily */
23.141 + private Collection<? extends Item<T>> items;
23.142 +
23.143 + /** Template used for this result. It is never null.*/
23.144 + private Template<T> template;
23.145 +
23.146 + /** can be null and is initialized lazily */
23.147 + private Collection<T> results;
23.148 +
23.149 + /** Just remembers the supplied argument in variable template.*/
23.150 + SimpleResult(Template<T> template) {
23.151 + this.template = template;
23.152 + }
23.153 +
23.154 + /**
23.155 + * Intentionally does nothing because the lookup does not change
23.156 + * and no notification is needed.
23.157 + */
23.158 + public void addLookupListener(LookupListener l) {
23.159 + }
23.160 +
23.161 + /**
23.162 + * Intentionally does nothing because the lookup does not change
23.163 + * and no notification is needed.
23.164 + */
23.165 + public void removeLookupListener(LookupListener l) {
23.166 + }
23.167 +
23.168 + /**
23.169 + * Lazy initializes the results collection. Uses a call to allItems
23.170 + * to obtain the instances.
23.171 + */
23.172 + public java.util.Collection<? extends T> allInstances() {
23.173 + synchronized (this) {
23.174 + if (results != null) {
23.175 + return results;
23.176 + }
23.177 + }
23.178 +
23.179 +
23.180 + Collection<T> res = new ArrayList<T>(allItems.size());
23.181 +
23.182 + for (Item<T> item : allItems()) {
23.183 + res.add(item.getInstance());
23.184 + }
23.185 +
23.186 + synchronized (this) {
23.187 + results = Collections.unmodifiableCollection(res);
23.188 + }
23.189 +
23.190 + return results;
23.191 + }
23.192 +
23.193 + /**
23.194 + * Lazy initializes variable classes. Uses a call to allItems to
23.195 + * compute the result.
23.196 + */
23.197 + public Set<Class<? extends T>> allClasses() {
23.198 + synchronized (this) {
23.199 + if (classes != null) {
23.200 + return classes;
23.201 + }
23.202 + }
23.203 +
23.204 + Set<Class<? extends T>> res = new HashSet<Class<? extends T>>();
23.205 +
23.206 + for (Item<T> item : allItems()) {
23.207 + res.add(item.getType());
23.208 + }
23.209 +
23.210 + synchronized (this) {
23.211 + classes = Collections.unmodifiableSet(res);
23.212 + }
23.213 +
23.214 + return classes;
23.215 + }
23.216 +
23.217 + /**
23.218 + * Lazy initializes variable items. Creates an item for each
23.219 + * element in the instances collection. It puts either SimpleItem
23.220 + * or ConvertingItem to the collection.
23.221 + */
23.222 + public Collection<? extends Item<T>> allItems() {
23.223 + synchronized (this) {
23.224 + if (items != null) {
23.225 + return items;
23.226 + }
23.227 + }
23.228 +
23.229 + Collection<Item<T>> res = new ArrayList<Item<T>>(allItems.size());
23.230 +
23.231 + for (Iterator<Item<?>> i = allItems.iterator(); i.hasNext();) {
23.232 + Item<?> o = i.next();
23.233 +
23.234 + if (o instanceof AbstractLookup.Pair) {
23.235 + if (matches(template, (AbstractLookup.Pair) o)) {
23.236 + res.add(cast(o));
23.237 + }
23.238 + }
23.239 + }
23.240 +
23.241 + synchronized (this) {
23.242 + items = Collections.unmodifiableCollection(res);
23.243 + }
23.244 +
23.245 + return items;
23.246 + }
23.247 +
23.248 + @SuppressWarnings("unchecked")
23.249 + private Item<T> cast(Item<?> i) {
23.250 + return (Item<T>)i;
23.251 + }
23.252 + }
23.253 +}
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/SimpleProxyLookup.java Sat Oct 31 15:28:13 2009 +0100
24.3 @@ -0,0 +1,359 @@
24.4 +/*
24.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
24.6 + *
24.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
24.8 + *
24.9 + * The contents of this file are subject to the terms of either the GNU
24.10 + * General Public License Version 2 only ("GPL") or the Common
24.11 + * Development and Distribution License("CDDL") (collectively, the
24.12 + * "License"). You may not use this file except in compliance with the
24.13 + * License. You can obtain a copy of the License at
24.14 + * http://www.netbeans.org/cddl-gplv2.html
24.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
24.16 + * specific language governing permissions and limitations under the
24.17 + * License. When distributing the software, include this License Header
24.18 + * Notice in each file and include the License file at
24.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
24.20 + * particular file as subject to the "Classpath" exception as provided
24.21 + * by Sun in the GPL Version 2 section of the License file that
24.22 + * accompanied this code. If applicable, add the following below the
24.23 + * License Header, with the fields enclosed by brackets [] replaced by
24.24 + * your own identifying information:
24.25 + * "Portions Copyrighted [year] [name of copyright owner]"
24.26 + *
24.27 + * Contributor(s):
24.28 + *
24.29 + * The Original Software is NetBeans. The Initial Developer of the Original
24.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
24.31 + * Microsystems, Inc. All Rights Reserved.
24.32 + *
24.33 + * If you wish your version of this file to be governed by only the CDDL
24.34 + * or only the GPL Version 2, indicate your decision by adding
24.35 + * "[Contributor] elects to include this software in this distribution
24.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
24.37 + * single choice of license, a recipient has the option to distribute
24.38 + * your version of this file under either the CDDL, the GPL Version 2 or
24.39 + * to extend the choice of license to its licensees as provided above.
24.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
24.41 + * Version 2 license, then the option applies only if the new code is
24.42 + * made subject to such option by the copyright holder.
24.43 + */
24.44 +package org.openide.util.lookup;
24.45 +
24.46 +import java.lang.ref.Reference;
24.47 +import java.lang.ref.WeakReference;
24.48 +import org.openide.util.Lookup;
24.49 +import org.openide.util.LookupEvent;
24.50 +import org.openide.util.LookupListener;
24.51 +
24.52 +import java.util.*;
24.53 +
24.54 +
24.55 +/**
24.56 + * Simple proxy lookup. Keeps reference to a lookup it delegates to and
24.57 + * forwards all requests.
24.58 + *
24.59 + * @author Jaroslav Tulach
24.60 + */
24.61 +final class SimpleProxyLookup extends org.openide.util.Lookup {
24.62 + /** the provider to check for the status */
24.63 + private Provider provider;
24.64 +
24.65 + /** the lookup we currently delegate to */
24.66 + private Lookup delegate;
24.67 +
24.68 + /** map of all templates to Reference (results) associated to this lookup */
24.69 + private WeakHashMap<Template<?>,Reference<ProxyResult<?>>> results;
24.70 +
24.71 + /**
24.72 + * @param provider provider to delegate to
24.73 + */
24.74 + SimpleProxyLookup(Provider provider) {
24.75 + this.provider = provider;
24.76 + }
24.77 +
24.78 + /** Checks whether we still delegate to the same lookup */
24.79 + private Lookup checkLookup() {
24.80 + Lookup l = provider.getLookup();
24.81 +
24.82 + // iterator over Reference (ProxyResult)
24.83 + Iterator<Reference<ProxyResult<?>>> toCheck = null;
24.84 +
24.85 + synchronized (this) {
24.86 + if (l != delegate) {
24.87 + this.delegate = l;
24.88 +
24.89 + if (results != null) {
24.90 + toCheck = new ArrayList<Reference<ProxyResult<?>>>(results.values()).iterator();
24.91 + }
24.92 + }
24.93 + }
24.94 +
24.95 + if (toCheck != null) {
24.96 + // update
24.97 + ArrayList<Object> evAndListeners = new ArrayList<Object>();
24.98 + for (Iterator<Reference<ProxyResult<?>>> it = toCheck; it.hasNext(); ) {
24.99 + java.lang.ref.Reference<ProxyResult<?>> ref = it.next();
24.100 + if (ref == null) {
24.101 + continue;
24.102 + }
24.103 +
24.104 + ProxyResult<?> p = ref.get();
24.105 +
24.106 + if (p != null && p.updateLookup(l)) {
24.107 + p.collectFires(evAndListeners);
24.108 + }
24.109 + }
24.110 +
24.111 + for (Iterator it = evAndListeners.iterator(); it.hasNext(); ) {
24.112 + LookupEvent ev = (LookupEvent)it.next();
24.113 + LookupListener ll = (LookupListener)it.next();
24.114 + ll.resultChanged(ev);
24.115 + }
24.116 + }
24.117 +
24.118 + return delegate;
24.119 + }
24.120 +
24.121 + @SuppressWarnings("unchecked")
24.122 + private static <T> ProxyResult<T> cast(ProxyResult<?> p) {
24.123 + return (ProxyResult<T>)p;
24.124 + }
24.125 +
24.126 + public <T> Result<T> lookup(Template<T> template) {
24.127 + synchronized (this) {
24.128 + if (results == null) {
24.129 + results = new WeakHashMap<Template<?>,Reference<ProxyResult<?>>>();
24.130 + } else {
24.131 + Reference<ProxyResult<?>> ref = results.get(template);
24.132 +
24.133 + if (ref != null) {
24.134 + ProxyResult<?> p = ref.get();
24.135 +
24.136 + if (p != null) {
24.137 + return cast(p);
24.138 + }
24.139 + }
24.140 + }
24.141 +
24.142 + ProxyResult<T> p = new ProxyResult<T>(template);
24.143 + Reference<ProxyResult<?>> ref = new WeakReference<ProxyResult<?>>(p);
24.144 + results.put(template, ref);
24.145 +
24.146 + return p;
24.147 + }
24.148 + }
24.149 +
24.150 + public <T> T lookup(Class<T> clazz) {
24.151 + if (clazz == null) {
24.152 + checkLookup();
24.153 + return null;
24.154 + }
24.155 + return checkLookup().lookup(clazz);
24.156 + }
24.157 +
24.158 + public <T> Item<T> lookupItem(Template<T> template) {
24.159 + return checkLookup().lookupItem(template);
24.160 + }
24.161 +
24.162 + /**
24.163 + * Result used in SimpleLookup. It holds a reference to the collection
24.164 + * passed in constructor. As the contents of this lookup result never
24.165 + * changes the addLookupListener and removeLookupListener are empty.
24.166 + */
24.167 + private final class ProxyResult<T> extends WaitableResult<T> implements LookupListener {
24.168 + /** Template used for this result. It is never null.*/
24.169 + private Template<T> template;
24.170 +
24.171 + /** result to delegate to */
24.172 + private Lookup.Result<T> delegate;
24.173 +
24.174 + /** listeners set */
24.175 + private javax.swing.event.EventListenerList listeners;
24.176 + private LookupListener lastListener;
24.177 +
24.178 + /** Just remembers the supplied argument in variable template.*/
24.179 + ProxyResult(Template<T> template) {
24.180 + this.template = template;
24.181 + }
24.182 +
24.183 + /** Checks state of the result
24.184 + */
24.185 + private Result<T> checkResult() {
24.186 + updateLookup(checkLookup());
24.187 +
24.188 + return this.delegate;
24.189 + }
24.190 +
24.191 + /** Updates the state of the lookup.
24.192 + * @return true if the lookup really changed
24.193 + */
24.194 + public boolean updateLookup(Lookup l) {
24.195 + Collection<? extends Item<T>> oldPairs = (delegate != null) ? delegate.allItems() : null;
24.196 +
24.197 + LookupListener removedListener;
24.198 +
24.199 + synchronized (this) {
24.200 + if ((delegate != null) && (lastListener != null)) {
24.201 + removedListener = lastListener;
24.202 + delegate.removeLookupListener(lastListener);
24.203 + } else {
24.204 + removedListener = null;
24.205 + }
24.206 + }
24.207 +
24.208 + // cannot call to foreign code
24.209 + Lookup.Result<T> res = l.lookup(template);
24.210 +
24.211 + synchronized (this) {
24.212 + if (removedListener == lastListener) {
24.213 + delegate = res;
24.214 + lastListener = new WeakResult<T>(this, delegate);
24.215 + delegate.addLookupListener(lastListener);
24.216 + }
24.217 + }
24.218 +
24.219 + if (oldPairs == null) {
24.220 + // nobody knows about a change
24.221 + return false;
24.222 + }
24.223 +
24.224 + Collection<? extends Item<T>> newPairs = delegate.allItems();
24.225 +
24.226 + // See #34961 for explanation.
24.227 + if (!(oldPairs instanceof List)) {
24.228 + if (oldPairs == Collections.EMPTY_SET) {
24.229 + // avoid allocation
24.230 + oldPairs = Collections.emptyList();
24.231 + } else {
24.232 + oldPairs = new ArrayList<Item<T>>(oldPairs);
24.233 + }
24.234 + }
24.235 +
24.236 + if (!(newPairs instanceof List)) {
24.237 + newPairs = new ArrayList<Item<T>>(newPairs);
24.238 + }
24.239 +
24.240 + return !oldPairs.equals(newPairs);
24.241 + }
24.242 +
24.243 + public synchronized void addLookupListener(LookupListener l) {
24.244 + if (listeners == null) {
24.245 + listeners = new javax.swing.event.EventListenerList();
24.246 + }
24.247 +
24.248 + listeners.add(LookupListener.class, l);
24.249 + }
24.250 +
24.251 + public synchronized void removeLookupListener(LookupListener l) {
24.252 + if (listeners != null) {
24.253 + listeners.remove(LookupListener.class, l);
24.254 + }
24.255 + }
24.256 +
24.257 + public java.util.Collection<? extends T> allInstances() {
24.258 + return checkResult().allInstances();
24.259 + }
24.260 +
24.261 + public Set<Class<? extends T>> allClasses() {
24.262 + return checkResult().allClasses();
24.263 + }
24.264 +
24.265 + public Collection<? extends Item<T>> allItems() {
24.266 + return checkResult().allItems();
24.267 + }
24.268 +
24.269 + protected void beforeLookup(Lookup.Template t) {
24.270 + Lookup.Result r = checkResult();
24.271 +
24.272 + if (r instanceof WaitableResult) {
24.273 + ((WaitableResult) r).beforeLookup(t);
24.274 + }
24.275 + }
24.276 +
24.277 + /** A change in lookup occured.
24.278 + * @param ev event describing the change
24.279 + *
24.280 + */
24.281 + public void resultChanged(LookupEvent anEvent) {
24.282 + collectFires(null);
24.283 + }
24.284 +
24.285 + protected void collectFires(Collection<Object> evAndListeners) {
24.286 + javax.swing.event.EventListenerList l = this.listeners;
24.287 +
24.288 + if (l == null) {
24.289 + return;
24.290 + }
24.291 +
24.292 + Object[] listeners = l.getListenerList();
24.293 +
24.294 + if (listeners.length == 0) {
24.295 + return;
24.296 + }
24.297 +
24.298 + LookupEvent ev = new LookupEvent(this);
24.299 + AbstractLookup.notifyListeners(listeners, ev, evAndListeners);
24.300 + }
24.301 + }
24.302 + // end of ProxyResult
24.303 + private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
24.304 + private Lookup.Result source;
24.305 + private Reference<ProxyResult<T>> result;
24.306 +
24.307 + public WeakResult(ProxyResult<T> r, Lookup.Result<T> s) {
24.308 + this.result = new WeakReference<ProxyResult<T>>(r);
24.309 + this.source = s;
24.310 + }
24.311 +
24.312 + protected void beforeLookup(Lookup.Template t) {
24.313 + ProxyResult r = (ProxyResult)result.get();
24.314 + if (r != null) {
24.315 + r.beforeLookup(t);
24.316 + } else {
24.317 + source.removeLookupListener(this);
24.318 + }
24.319 + }
24.320 +
24.321 + protected void collectFires(Collection<Object> evAndListeners) {
24.322 + ProxyResult<T> r = result.get();
24.323 + if (r != null) {
24.324 + r.collectFires(evAndListeners);
24.325 + } else {
24.326 + source.removeLookupListener(this);
24.327 + }
24.328 + }
24.329 +
24.330 + public void addLookupListener(LookupListener l) {
24.331 + assert false;
24.332 + }
24.333 +
24.334 + public void removeLookupListener(LookupListener l) {
24.335 + assert false;
24.336 + }
24.337 +
24.338 + public Collection<T> allInstances() {
24.339 + assert false;
24.340 + return null;
24.341 + }
24.342 +
24.343 + public void resultChanged(LookupEvent ev) {
24.344 + ProxyResult r = (ProxyResult)result.get();
24.345 + if (r != null) {
24.346 + r.resultChanged(ev);
24.347 + } else {
24.348 + source.removeLookupListener(this);
24.349 + }
24.350 + }
24.351 +
24.352 + public Collection<? extends Item<T>> allItems() {
24.353 + assert false;
24.354 + return null;
24.355 + }
24.356 +
24.357 + public Set<Class<? extends T>> allClasses() {
24.358 + assert false;
24.359 + return null;
24.360 + }
24.361 + } // end of WeakResult
24.362 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/SingletonLookup.java Sat Oct 31 15:28:13 2009 +0100
25.3 @@ -0,0 +1,173 @@
25.4 +/*
25.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
25.6 + *
25.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
25.8 + *
25.9 + * The contents of this file are subject to the terms of either the GNU
25.10 + * General Public License Version 2 only ("GPL") or the Common
25.11 + * Development and Distribution License("CDDL") (collectively, the
25.12 + * "License"). You may not use this file except in compliance with the
25.13 + * License. You can obtain a copy of the License at
25.14 + * http://www.netbeans.org/cddl-gplv2.html
25.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
25.16 + * specific language governing permissions and limitations under the
25.17 + * License. When distributing the software, include this License Header
25.18 + * Notice in each file and include the License file at
25.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
25.20 + * particular file as subject to the "Classpath" exception as provided
25.21 + * by Sun in the GPL Version 2 section of the License file that
25.22 + * accompanied this code. If applicable, add the following below the
25.23 + * License Header, with the fields enclosed by brackets [] replaced by
25.24 + * your own identifying information:
25.25 + * "Portions Copyrighted [year] [name of copyright owner]"
25.26 + *
25.27 + * If you wish your version of this file to be governed by only the CDDL
25.28 + * or only the GPL Version 2, indicate your decision by adding
25.29 + * "[Contributor] elects to include this software in this distribution
25.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
25.31 + * single choice of license, a recipient has the option to distribute
25.32 + * your version of this file under either the CDDL, the GPL Version 2 or
25.33 + * to extend the choice of license to its licensees as provided above.
25.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
25.35 + * Version 2 license, then the option applies only if the new code is
25.36 + * made subject to such option by the copyright holder.
25.37 + *
25.38 + * Contributor(s):
25.39 + *
25.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
25.41 + */
25.42 +
25.43 +package org.openide.util.lookup;
25.44 +
25.45 +import java.util.Collection;
25.46 +import java.util.Collections;
25.47 +import java.util.Set;
25.48 +import org.openide.util.Lookup;
25.49 +import org.openide.util.LookupListener;
25.50 +
25.51 +/**
25.52 + * Unmodifiable lookup that contains just one fixed object.
25.53 + *
25.54 + * @author Marian Petras
25.55 + */
25.56 +class SingletonLookup extends Lookup {
25.57 +
25.58 + private final Object objectToLookup;
25.59 + private final String id;
25.60 +
25.61 + SingletonLookup(Object objectToLookup) {
25.62 + this(objectToLookup, null);
25.63 + }
25.64 +
25.65 + SingletonLookup(Object objectToLookup, String id) {
25.66 + if (objectToLookup == null) {
25.67 + throw new IllegalArgumentException("null"); //NOI18N
25.68 + }
25.69 +
25.70 + this.objectToLookup = objectToLookup;
25.71 + this.id = id;
25.72 + }
25.73 +
25.74 + @Override
25.75 + public <T> T lookup(Class<T> clazz) {
25.76 + if (clazz == null) {
25.77 + throw new IllegalArgumentException("null"); //NOI18N
25.78 + }
25.79 +
25.80 + return (clazz.isInstance(objectToLookup))
25.81 + ? clazz.cast(objectToLookup)
25.82 + : null;
25.83 + }
25.84 +
25.85 + @Override
25.86 + public <T> Result<T> lookup(Template<T> template) {
25.87 + if (template == null) {
25.88 + throw new IllegalArgumentException("null"); //NOI18N
25.89 + }
25.90 +
25.91 + Lookup.Item<T> item = lookupItem(template);
25.92 + if (item != null) {
25.93 + return new SingletonResult<T>(item);
25.94 + } else {
25.95 + return Lookup.EMPTY.lookup(template);
25.96 + }
25.97 + }
25.98 +
25.99 + @Override
25.100 + public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
25.101 + if (clazz == null) {
25.102 + throw new IllegalArgumentException("null"); //NOI18N
25.103 + }
25.104 +
25.105 + return (clazz.isInstance(objectToLookup))
25.106 + ? Collections.singletonList(clazz.cast(objectToLookup))
25.107 + : Collections.<T>emptyList();
25.108 + }
25.109 +
25.110 + @Override
25.111 + @SuppressWarnings("unchecked")
25.112 + public <T> Item<T> lookupItem(Template<T> template) {
25.113 + if (template == null) {
25.114 + throw new IllegalArgumentException("null"); //NOI18N
25.115 + }
25.116 +
25.117 + String templateId = template.getId();
25.118 + if ((templateId != null) && !templateId.equals(id)) {
25.119 + return null;
25.120 + }
25.121 +
25.122 + Object templateInst = template.getInstance();
25.123 + if ((templateInst != null) && (objectToLookup != templateInst)) {
25.124 + return null;
25.125 + }
25.126 +
25.127 + Class<T> clazz = template.getType();
25.128 + if ((clazz != null) && !clazz.isInstance(objectToLookup)) {
25.129 + return null;
25.130 + }
25.131 +
25.132 + Lookup.Item<T> item;
25.133 + if (clazz != null) {
25.134 + item = Lookups.lookupItem(clazz.cast(objectToLookup), id);
25.135 + } else {
25.136 + item = Lookups.lookupItem((T) objectToLookup, id);
25.137 + }
25.138 + return item;
25.139 + }
25.140 +
25.141 + static class SingletonResult<T> extends Lookup.Result<T> {
25.142 +
25.143 + private final Lookup.Item<T> item;
25.144 +
25.145 + SingletonResult(Lookup.Item<T> item) {
25.146 + this.item = item;
25.147 + }
25.148 +
25.149 + @Override
25.150 + public void addLookupListener(LookupListener l) {
25.151 + // this result never changes - no need to register a listener
25.152 + }
25.153 +
25.154 + @Override
25.155 + public void removeLookupListener(LookupListener l) {
25.156 + // this result never changes - no need to register a listener
25.157 + }
25.158 +
25.159 + @Override
25.160 + public Set<Class<? extends T>> allClasses() {
25.161 + return Collections.<Class<? extends T>>singleton(item.getType());
25.162 + }
25.163 +
25.164 + @Override
25.165 + public Collection<? extends Item<T>> allItems() {
25.166 + return Collections.singletonList(item);
25.167 + }
25.168 +
25.169 + @Override
25.170 + public Collection<? extends T> allInstances() {
25.171 + return Collections.singletonList(item.getInstance());
25.172 + }
25.173 +
25.174 + }
25.175 +
25.176 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/WaitableResult.java Sat Oct 31 15:28:13 2009 +0100
26.3 @@ -0,0 +1,62 @@
26.4 +/*
26.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
26.6 + *
26.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
26.8 + *
26.9 + * The contents of this file are subject to the terms of either the GNU
26.10 + * General Public License Version 2 only ("GPL") or the Common
26.11 + * Development and Distribution License("CDDL") (collectively, the
26.12 + * "License"). You may not use this file except in compliance with the
26.13 + * License. You can obtain a copy of the License at
26.14 + * http://www.netbeans.org/cddl-gplv2.html
26.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
26.16 + * specific language governing permissions and limitations under the
26.17 + * License. When distributing the software, include this License Header
26.18 + * Notice in each file and include the License file at
26.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
26.20 + * particular file as subject to the "Classpath" exception as provided
26.21 + * by Sun in the GPL Version 2 section of the License file that
26.22 + * accompanied this code. If applicable, add the following below the
26.23 + * License Header, with the fields enclosed by brackets [] replaced by
26.24 + * your own identifying information:
26.25 + * "Portions Copyrighted [year] [name of copyright owner]"
26.26 + *
26.27 + * Contributor(s):
26.28 + *
26.29 + * The Original Software is NetBeans. The Initial Developer of the Original
26.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
26.31 + * Microsystems, Inc. All Rights Reserved.
26.32 + *
26.33 + * If you wish your version of this file to be governed by only the CDDL
26.34 + * or only the GPL Version 2, indicate your decision by adding
26.35 + * "[Contributor] elects to include this software in this distribution
26.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
26.37 + * single choice of license, a recipient has the option to distribute
26.38 + * your version of this file under either the CDDL, the GPL Version 2 or
26.39 + * to extend the choice of license to its licensees as provided above.
26.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
26.41 + * Version 2 license, then the option applies only if the new code is
26.42 + * made subject to such option by the copyright holder.
26.43 + */
26.44 +package org.openide.util.lookup;
26.45 +
26.46 +import java.util.Collection;
26.47 +import org.openide.util.Lookup;
26.48 +
26.49 +
26.50 +/** A special subclass of lookup that is able to wait before queries.
26.51 + *
26.52 + * @author Jaroslav Tulach
26.53 + */
26.54 +abstract class WaitableResult<T> extends Lookup.Result<T> {
26.55 + /** Used by proxy results to synchronize before lookup.
26.56 + */
26.57 + protected abstract void beforeLookup(Lookup.Template t);
26.58 +
26.59 + /** Needed to group notification of outside the package listeners
26.60 + * after all AbstractLookup and ProxyLookups have been updated.
26.61 + * @param evAndListeners LookupEvent, LookupListener, LookupEvent, LookupListener, etc.
26.62 + */
26.63 + protected abstract void collectFires(Collection<Object> evAndListeners);
26.64 +
26.65 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/doc-files/index.html Sat Oct 31 15:28:13 2009 +0100
27.3 @@ -0,0 +1,208 @@
27.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
27.5 +<!--
27.6 + - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
27.7 + -
27.8 + - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
27.9 + -
27.10 + - The contents of this file are subject to the terms of either the GNU
27.11 + - General Public License Version 2 only ("GPL") or the Common
27.12 + - Development and Distribution License("CDDL") (collectively, the
27.13 + - "License"). You may not use this file except in compliance with the
27.14 + - License. You can obtain a copy of the License at
27.15 + - http://www.netbeans.org/cddl-gplv2.html
27.16 + - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
27.17 + - specific language governing permissions and limitations under the
27.18 + - License. When distributing the software, include this License Header
27.19 + - Notice in each file and include the License file at
27.20 + - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
27.21 + - particular file as subject to the "Classpath" exception as provided
27.22 + - by Sun in the GPL Version 2 section of the License file that
27.23 + - accompanied this code. If applicable, add the following below the
27.24 + - License Header, with the fields enclosed by brackets [] replaced by
27.25 + - your own identifying information:
27.26 + - "Portions Copyrighted [year] [name of copyright owner]"
27.27 + -
27.28 + - Contributor(s):
27.29 + -
27.30 + - The Original Software is NetBeans. The Initial Developer of the Original
27.31 + - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
27.32 + - Microsystems, Inc. All Rights Reserved.
27.33 + -
27.34 + - If you wish your version of this file to be governed by only the CDDL
27.35 + - or only the GPL Version 2, indicate your decision by adding
27.36 + - "[Contributor] elects to include this software in this distribution
27.37 + - under the [CDDL or GPL Version 2] license." If you do not indicate a
27.38 + - single choice of license, a recipient has the option to distribute
27.39 + - your version of this file under either the CDDL, the GPL Version 2 or
27.40 + - to extend the choice of license to its licensees as provided above.
27.41 + - However, if you add GPL Version 2 code and therefore, elected the GPL
27.42 + - Version 2 license, then the option applies only if the new code is
27.43 + - made subject to such option by the copyright holder.
27.44 + -->
27.45 +<HTML>
27.46 +<HEAD>
27.47 +<TITLE>Lookup Library</TITLE>
27.48 +<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
27.49 +</HEAD>
27.50 +<BODY>
27.51 +
27.52 +<P>
27.53 +
27.54 +This is the home page of the <em>lookup library</em> implementation, which
27.55 +is intended to solve a general problem that every <cite>component-based system</CITE>
27.56 +has had to face: how different components <b>register</b> to the system
27.57 +and how other parts of the system can <b>look</b> them <b>up</B>.
27.58 +<P>
27.59 +There already are libraries trying to solve this problem, usually by querying for
27.60 +an interface and finding its appropriate implementaion. The most famous is
27.61 +<A href="http://www.jini.org/">Jini</A>, the platform for development of
27.62 +distributed network services. Our library does something similar, but tries
27.63 +to stay small and easy
27.64 +to use. The NetBeans <em>Lookup
27.65 +Library</EM>'s main focus is a modular application consisting of independent modules
27.66 +that want to communicate with each other. It does not try to solve networking or
27.67 +legacy application integration. It is simple but powerful.
27.68 +
27.69 +<H2>Why would you want to use it?</H2>
27.70 +
27.71 +A well-written modular program separates <em>development</EM>
27.72 +and <em>deployment</EM>.
27.73 +There are many situations where a component needs some functionality but
27.74 +does not actually care about the implementation. It is up to the <em>system
27.75 +adminstrator</em> that deploys (installs) the application to decide which
27.76 +implementation to use.
27.77 +<P>
27.78 +The most simple and most often used method for allowing other implementations
27.79 +to be plugged in is the <em>system property</em> pattern:
27.80 +
27.81 +<pre>
27.82 + <font class="keyword">public</font> <font class="type">Toolkit</font> <font class="function-name">getDefaultToolkit</font> () {
27.83 + java.awt.<font class="type">Toolkit</font> <font class="variable-name">t</font> = <font class="constant">null</font>;
27.84 + <font class="type">String</font> <font class="variable-name">classname</font> = System.getProperty (<font class="string">"java.awt.Toolkit"</font>);
27.85 + <font class="keyword">if</font> (classname != <font class="constant">null</font>) {
27.86 + <font class="keyword">try</font> {
27.87 + <font class="type">Class</font> <font class="variable-name">c</font> = Class.forName (classname);
27.88 + t = (java.awt.<font class="type">Toolkit</font>)c.newInstance ();
27.89 + } <font class="keyword">catch</font> (<font class="type">Exception</font> <font class="variable-name">ex</font>) {
27.90 + System.out.println (<font class="string">"Cannot initialize toolkit: "</font> + classname);
27.91 + ex.printStackTrace ();
27.92 + }
27.93 + }
27.94 + <font class="comment">// fallback </font>
27.95 + <font class="keyword">if</font> (t == <font class="constant">null</font>) {
27.96 + t = <font class="keyword">new</font> <font class="type">GenericAWTToolkit</font> ();
27.97 + }
27.98 + }
27.99 +</pre>
27.100 +
27.101 +
27.102 +The idea is simple. The <em>deployer</em> can start the Java VM with the flag
27.103 +<code>-Djava.awt.Toolkit=org.myorg.MyToolkit</code> where the <code>MyToolkit</code>
27.104 +is his class with default constructor and the code in the <code>getDefaultToolkit</CODE>
27.105 +method will instantiate the class and use it.
27.106 +<P>
27.107 +In principle this is general enough of a solution and works well, except that writing the
27.108 +code above is error prone and it also requires passing the arguments to the virtual machine.
27.109 +It would be much nicer if the registation could be done just by putting a JAR file with the <code>MyToolkit</code> class
27.110 +into the application classpath.
27.111 +<P>
27.112 +Actually this has been realized also by the JDK development team and addressed in
27.113 +JDK 1.3 as part of the <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Provider%20Configuration%20File">provider extension mechanism</A>.
27.114 +The <code>MyToolkit</code> could be registered by adding a file
27.115 +<code>/META-INF/services/java.awt.Toolkit</code> with one line
27.116 +<code>org.myorg.MyToolkit</code> into the JAR file that contains the
27.117 +<code>MyToolkit</CODE> implementation. The code in <code>getDefaultToolkit</CODE>
27.118 +will scan all JAR files in classpath and search for that file,
27.119 +create an instance of <code>MyToolkit</code> and use it.
27.120 +The deployer can influence which toolkit will be created by
27.121 +adding the right JAR files into the classpath.
27.122 +<P>
27.123 +Of course the code to access the <code>META-INF/services/</code> files is even
27.124 +more error prone than the <em>property pattern</EM>. And this is exactly the
27.125 +place where the <em>lookup library</em> can help. It provides an implementation of
27.126 +the search algorithm with an easy interface. Just write:
27.127 +<pre>
27.128 + <font class="keyword">import</font> <font class="type">java.awt.Toolkit</font>;
27.129 + <font class="keyword">import</font> <font class="type">org.openide.util.Lookup;</font>;
27.130 + <font class="type">Toolkit</font> <font class="variable-name">t</font> = (<font class="type">Toolkit</font>)Lookup.getDefault().<a href="@TOP@org/openide/util/Lookup.html#lookup(java.lang.Class)">lookup</a>(Toolkit.<font class="keyword">class</font>);
27.131 +</PRE>
27.132 +and if the JAR with <code>MyToolkit</CODE> is in the class path, the simple call
27.133 +above will do the rest.
27.134 +<P>
27.135 +So whenever one writes an application divided into several independent modules (jar files)
27.136 +that are being developed and deployed independently, there is a need for registering
27.137 +and discovering components. First of all, a set of interfaces can be defined to enable
27.138 +inter-module communication (like the abstract class <code>java.awt.Toolkit</CODE>).
27.139 +After that a set of modules providing implementation can written (<code>MyToolkit</code> and other concurent implementations)
27.140 +and after that, whenever a module trying to utilitize the functionality wants to access
27.141 +the <code>Toolkit</code> via lookup, the real implementation is returned.
27.142 +<P>
27.143 +It is the responsibility of lookup to find a suitable implementation of the
27.144 +requested service and return an object implementing the service. This is the
27.145 +the basic functionality and while the library provides you with a little bit
27.146 +more, even this simple usage might be extremaly useful: the client code knows
27.147 +nothing about the implementation and the implementation can be switched in
27.148 +deployment time by simply replacing one implementation jar with other. There
27.149 +is no code change required.
27.150 +
27.151 +<H2> Local lookup usage </H2>
27.152 +The example in previous paragraph demostrated the usage of lookup as a global
27.153 +registry (by using the <CODE>Lookup.getDefault()</CODE> call). One can also
27.154 +consider another scenario where the lookup can help.
27.155 +<P>
27.156 +Let's switch hats to be an API designer for a while. The goal is to introduce a
27.157 +new object into the system. But you either are not sure yet what all the roles
27.158 +of the new object will be or you (more importantly) want to be able to add (or
27.159 +change) roles of the object dynamically. So why not to introduce following
27.160 +method to the object's interface:
27.161 +<pre>
27.162 +<font class="keyword">public class </FONT> <font class="type">MorphingObject</FONT> {
27.163 + <font class="keyword">public</FONT> <font class="type"><a href="@TOP@org/openide/util/Lookup.html">Lookup</A></FONT> getLookup() {
27.164 + <font class="keyword">return</FONT> <font class="variable-name">myLookup;</FONT>
27.165 + }
27.166 + ...
27.167 +}
27.168 +</pre>
27.169 +By exposing the method getLookup you can attach different functionality to the
27.170 +MorphingObject at runtime and whoever gets a reference to your object can ask it
27.171 +whether the object supports a given interface like this:
27.172 +<pre>
27.173 +<font class="type">MorphingObject</FONT> <font class="variable-name">morph</FONT> = ...
27.174 +<font class="type">AnInterface</font> <font class="variable-name">impl</font> = (<font
27.175 +class="type">AnInterface</font>)morph.getLookup().<a
27.176 +href="@TOP@org/openide/util/Lookup.html#lookup(java.lang.Class)">lookup</a>(AnInterface.<font class="keyword">class</font>);
27.177 +<font class="keyword">if</font> (impl == <font class="constant">null</font>) {
27.178 + <font class="keyword">return;</font><font class="comment">/* AnInterface not supported now! */</font>
27.179 +}
27.180 +impl.useIt();
27.181 +</PRE>
27.182 +
27.183 +<H2>Additional functionality</H2>
27.184 +The NetBeans lookup library also provides:
27.185 +<UL>
27.186 +<LI>Support for dynamically changing the lookup content.</LI>
27.187 +<LI>The ability to return multiple results.</LI>
27.188 +<LI>Notification of changes. After retrieving the result, the client can attach a
27.189 +listener and be notified when the result of the lookup is changed.</LI>
27.190 +<LI>Lazy initialization of the implementation. The implementation objects are
27.191 +initialized only after someone asks for them. Even the implementation classes
27.192 +are not loaded if they are not going to be used! </LI>
27.193 +</UL>
27.194 +
27.195 +<H2>Further information</H2>
27.196 +<UL>
27.197 + <LI><A HREF="lookup-api.html">Lookup Library APIs</A> for those writing the client code.
27.198 +Specifying the query, getting the result and listenning on changes.</LI>
27.199 + <LI><A HREF="lookup-spi.html">Lookup Library SPIs</A> for those writing the
27.200 +implementaion code and registering it with lookup. Includes also writing own
27.201 +lookup implementation.</LI>
27.202 + <LI>Download <A HREF="http://www.netbeans.org/">NetBeans platform</A> which
27.203 +contains <code>org-openide-util.jar</code></LI>
27.204 + <A HREF="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/lookup/">
27.205 + implementation package (org.openide.util.lookup) </A>
27.206 + + classes Lookup, LookupEvent, LookupListener in
27.207 + <A href="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/">util package</A></LI>
27.208 + <li><a href="http://www.martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a> (Martin Fowler)</li>
27.209 +</UL>
27.210 +</BODY>
27.211 +</HTML>
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/doc-files/lookup-api.html Sat Oct 31 15:28:13 2009 +0100
28.3 @@ -0,0 +1,188 @@
28.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
28.5 +<!--
28.6 + - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
28.7 + -
28.8 + - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
28.9 + -
28.10 + - The contents of this file are subject to the terms of either the GNU
28.11 + - General Public License Version 2 only ("GPL") or the Common
28.12 + - Development and Distribution License("CDDL") (collectively, the
28.13 + - "License"). You may not use this file except in compliance with the
28.14 + - License. You can obtain a copy of the License at
28.15 + - http://www.netbeans.org/cddl-gplv2.html
28.16 + - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
28.17 + - specific language governing permissions and limitations under the
28.18 + - License. When distributing the software, include this License Header
28.19 + - Notice in each file and include the License file at
28.20 + - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
28.21 + - particular file as subject to the "Classpath" exception as provided
28.22 + - by Sun in the GPL Version 2 section of the License file that
28.23 + - accompanied this code. If applicable, add the following below the
28.24 + - License Header, with the fields enclosed by brackets [] replaced by
28.25 + - your own identifying information:
28.26 + - "Portions Copyrighted [year] [name of copyright owner]"
28.27 + -
28.28 + - Contributor(s):
28.29 + -
28.30 + - The Original Software is NetBeans. The Initial Developer of the Original
28.31 + - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28.32 + - Microsystems, Inc. All Rights Reserved.
28.33 + -
28.34 + - If you wish your version of this file to be governed by only the CDDL
28.35 + - or only the GPL Version 2, indicate your decision by adding
28.36 + - "[Contributor] elects to include this software in this distribution
28.37 + - under the [CDDL or GPL Version 2] license." If you do not indicate a
28.38 + - single choice of license, a recipient has the option to distribute
28.39 + - your version of this file under either the CDDL, the GPL Version 2 or
28.40 + - to extend the choice of license to its licensees as provided above.
28.41 + - However, if you add GPL Version 2 code and therefore, elected the GPL
28.42 + - Version 2 license, then the option applies only if the new code is
28.43 + - made subject to such option by the copyright holder.
28.44 + -->
28.45 +<HTML>
28.46 +<HEAD>
28.47 +<TITLE>Lookup Library API</TITLE>
28.48 +<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
28.49 +</HEAD>
28.50 +<BODY>
28.51 +<H1>Lookup library API</H1>
28.52 +<p>
28.53 +This document describes usage of the API provided by the Lookup Library. In this
28.54 +document we assume that someone has already provided us with a lookup
28.55 +implementation (for those seeking how to write a lookup implementation please
28.56 +check <A href="lookup-spi.html">the SPI document</A>).
28.57 +
28.58 +<H2> Getting the lookup </H2>
28.59 +
28.60 +The first question you might ask is this: how can I get hold of a
28.61 +lookup instance? There are basically two ways how you can get it.
28.62 +
28.63 +<H3> Global lookup </H3>
28.64 +As you can see in the
28.65 +
28.66 +<a href="@TOP@org/openide/util/Lookup.html">Lookup</a>
28.67 +
28.68 +Javadoc there is a static method
28.69 +
28.70 +<pre><a href="@TOP@org/openide/util/Lookup.html#getDefault()">public static Lookup getDefault()</a></pre>
28.71 +
28.72 +The object returned from this method is
28.73 +a global lookup that can serve as a central place for registering services.
28.74 +The default implementation is a lookup that implements
28.75 +<a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">
28.76 +the JDK JAR services</A>
28.77 +mechanism and delegates to <samp>META-INF/services/name.of.Class</samp> files.
28.78 +<P>
28.79 +If you want to add your class to this lookup just create a file in your
28.80 +jar file under the <code>META-INF</code> directory (e.g. <samp>META-INF/services/com.my.APIClass</samp>)
28.81 +and let the file contain only one line of text
28.82 +
28.83 +<pre>com.foo.impl.ImplOfTheAPI</pre>
28.84 +
28.85 +<p>(This is more easily done using the <code>@ServiceProvider</code> annotation.)</p>
28.86 +
28.87 +The following code will return you a newly created instance of
28.88 +<code>com.foo.impl.ImplOfTheAPI</code>:
28.89 +
28.90 +<PRE>
28.91 + <font class="keyword">import</FONT> org.openide.util.Lookup;
28.92 + return Lookup.getDefault().lookup(com.my.APIClass.class);
28.93 +</PRE>
28.94 +
28.95 +<H3> Local lookup </H3>
28.96 +
28.97 +This is just a reminder that whenever you find a method called getLookup
28.98 +or similar returning a lookup instance, the provided lookup is <EM>not</EM> the
28.99 +general lookup described in the previous paragraph. Rather, it is a private lookup
28.100 +implementation that is usually bound to the object you invoked the method on.
28.101 +
28.102 +<H2> Use of Lookup.Template and Lookup.Result </H2>
28.103 +
28.104 +There are more ways how you can ask lookup besides the variant with one class
28.105 +parameter. If you want more functionality, you have to implement the interface
28.106 +Lookup.Template and pass an instance of such object to the lookup call.
28.107 +<p>
28.108 +<EM>Note:</EM> If you use Lookup.Template, the object returned from the lookup is
28.109 +<EM>not</EM> the object you are looking for but rather a result object
28.110 +(Lookup.Result). You can call methods on such a result object to get the actual
28.111 +results.
28.112 +<p>
28.113 +Let's examine following example:
28.114 +
28.115 +<pre>
28.116 + <font class="keyword">import</FONT> org.openide.util.Lookup;
28.117 +
28.118 + <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
28.119 + Lookup.<font class="type">Template</font> <font class="variable-name">template</font> = <font class="keyword">new</font> Lookup.<font class="type">Template</font>(MyService.<font class="keyword">class</font>);
28.120 + Lookup.<font class="type">Result</font> <font class="variable-name">result</font> = lookup.lookup(template);
28.121 + <font class="type">Collection</font> <font class="variable-name">c</font> = result.allInstances();
28.122 + <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = c.iterator(); i.hasNext(); ) {
28.123 + <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
28.124 + s.callMyService();
28.125 + }
28.126 +</pre>
28.127 +
28.128 +In this example the call to method lookup(...) returns immediately because the
28.129 +result object can be constructed even without real results. The first time you
28.130 +ask for the result object by calling r.allInstances(), the lookup has to supply you
28.131 +the real results and this method can block until the required data are really
28.132 +available.
28.133 +<p>
28.134 +If you are not interested in all objects as in the previous example, you can use the
28.135 +template to ask for one resulting object (wrapped in special Item instance):
28.136 +<pre>
28.137 + <font class="keyword">import</FONT> org.openide.util.Lookup;
28.138 +
28.139 + <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
28.140 + Lookup.<font class="type">Template</font> <font class="variable-name">template</font> = <font class="keyword">new</font> Lookup.<font class="type">Template</font>(MyService.<font class="keyword">class</font>);
28.141 + Lookup.<font class="type">Item</font> <font class="variable-name">item</font> = lookup.lookupItem(template);
28.142 + <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)item.getInstance();
28.143 + s.callMyService();
28.144 +</pre>
28.145 +
28.146 +Again, the Item object can construct the real instance only if you call
28.147 +getInstance. The item can be useful even without calling getInstance - you can get
28.148 +its display name or an unique id. You can use this information, for example, for
28.149 +constructing menu items without the need to instantiate (or even load!)
28.150 +the class implementing the functionality. Only when the real functionality is
28.151 +needed (e.g. the user has selected the menu item) you can call getInstance
28.152 +and call the real meat of the implementation.
28.153 +
28.154 +<H2> Listenning on lookup changes </H2>
28.155 +There is one additional piece of functionality bound to the Lookup.Result object worth
28.156 +mentioning: you can attach a listener to it and be informed about any changes in
28.157 +the lookup. This might be extremly usefull when the lookup dynamically changes
28.158 +(from other threads). The listener can keep state of your object up-to-date even
28.159 +in cases where the lookup changes asynchronously.
28.160 +<p>
28.161 +So here is some sample code using the listenner:
28.162 +
28.163 +<pre>
28.164 + <font class="keyword">import</FONT> org.openide.util.Lookup;
28.165 + <font class="keyword">import</FONT> org.openide.util.LookupListener;
28.166 + <font class="keyword">import</FONT> org.openide.util.LookupEvent;
28.167 +
28.168 + <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
28.169 + Lookup.<font class="type">Template</font> <font class="variable-name">template</font> = <font class="keyword">new</font> Lookup.<font class="type">Template</font>(MyService.<font class="keyword">class</font>);
28.170 + <font class="keyword">final</font> <font class="variable-name">Lookup</font>.<font class="type">Result</font> <font class="variable-name">result</font> = lookup.lookup(template);
28.171 + result.addLookupListener(<font class="keyword">new</font> <font class="type">LookupListener</font>() {
28.172 + <font class="keyword">public</font> <font class="type">void</font> <font class="function-name">resultChanged</font>(<font class="type">LookupEvent</font> <font class="variable-name">e</font>) {
28.173 + reaction(result);
28.174 + }
28.175 + });
28.176 + reaction(result);
28.177 + }
28.178 + <font class="keyword">private</font> <font class="keyword">static</font> <font class="type">void</font> <font class="function-name">reaction</font>(Lookup.<font class="type">Result</font> <font class="variable-name">r</font>) {
28.179 + <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = r.allInstances().iterator(); i.hasNext(); ) {
28.180 + <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
28.181 + s.callMyService();
28.182 + }
28.183 + }
28.184 +</pre>
28.185 +
28.186 +Please note that we first attach a listener and then call the reaction method.
28.187 +This ensures that we always get the newest possible state. Also you must be
28.188 +careful in the reaction method since it can be called from two different
28.189 +threads simultaneously (your code has to be prepared for this).
28.190 +</BODY>
28.191 +</HTML>
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/doc-files/lookup-spi.html Sat Oct 31 15:28:13 2009 +0100
29.3 @@ -0,0 +1,147 @@
29.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
29.5 +<!--
29.6 + - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
29.7 + -
29.8 + - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
29.9 + -
29.10 + - The contents of this file are subject to the terms of either the GNU
29.11 + - General Public License Version 2 only ("GPL") or the Common
29.12 + - Development and Distribution License("CDDL") (collectively, the
29.13 + - "License"). You may not use this file except in compliance with the
29.14 + - License. You can obtain a copy of the License at
29.15 + - http://www.netbeans.org/cddl-gplv2.html
29.16 + - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
29.17 + - specific language governing permissions and limitations under the
29.18 + - License. When distributing the software, include this License Header
29.19 + - Notice in each file and include the License file at
29.20 + - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
29.21 + - particular file as subject to the "Classpath" exception as provided
29.22 + - by Sun in the GPL Version 2 section of the License file that
29.23 + - accompanied this code. If applicable, add the following below the
29.24 + - License Header, with the fields enclosed by brackets [] replaced by
29.25 + - your own identifying information:
29.26 + - "Portions Copyrighted [year] [name of copyright owner]"
29.27 + -
29.28 + - Contributor(s):
29.29 + -
29.30 + - The Original Software is NetBeans. The Initial Developer of the Original
29.31 + - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
29.32 + - Microsystems, Inc. All Rights Reserved.
29.33 + -
29.34 + - If you wish your version of this file to be governed by only the CDDL
29.35 + - or only the GPL Version 2, indicate your decision by adding
29.36 + - "[Contributor] elects to include this software in this distribution
29.37 + - under the [CDDL or GPL Version 2] license." If you do not indicate a
29.38 + - single choice of license, a recipient has the option to distribute
29.39 + - your version of this file under either the CDDL, the GPL Version 2 or
29.40 + - to extend the choice of license to its licensees as provided above.
29.41 + - However, if you add GPL Version 2 code and therefore, elected the GPL
29.42 + - Version 2 license, then the option applies only if the new code is
29.43 + - made subject to such option by the copyright holder.
29.44 + -->
29.45 +<HTML>
29.46 +<HEAD>
29.47 +<TITLE>Lookup Library SPI</TITLE>
29.48 +<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
29.49 +</HEAD>
29.50 +<BODY>
29.51 +<H1>Lookup library SPI</H1>
29.52 +This document describe usage of the SPI provided by the Lookup Library
29.53 +(for those seeking how to use lookup instance please
29.54 +check <A href="lookup-api.html">the API document</A>).
29.55 +<p>
29.56 +By using the SPI you can create lookups that can be used by the users of the
29.57 +Lookup API. While the Lookup API consists of a couple of classes in the package
29.58 +<em>org.openide.util.*</EM>,
29.59 +the SPI has its own package <em>org.openide.util.lookup.*</EM>.
29.60 +
29.61 +<H2> Simple lookups </H2>
29.62 +Let us start with the simplest case. You have decided that your newly created
29.63 +object will provide an API in the form of a getLookup() method. You have to
29.64 +return a functional lookup from this call. You can use static methods in class
29.65 +<a href="@TOP@org/openide/util/lookup/Lookups.html">
29.66 +<code>Lookups</code></A> to create a lookup for you. If you want only one
29.67 +object to be returned, just call
29.68 +<a href="@TOP@org/openide/util/lookup/Lookups.html#singleton(java.lang.Object)">
29.69 +<code>Lookups.singleton(x)</code></A> where x is the object to be
29.70 +returned by the lookup. Or if you want to supply more objects, use a call to the method
29.71 +<a href="@TOP@org/openide/util/lookup/Lookups.html#fixed(java.lang.Object...)">
29.72 +<code>fixed(Object []x)</CODE></A>.
29.73 +<EM> Note: </EM> The lookups returned from methods <code>singleton(...)</code> and
29.74 +<code>fixed(...)</code> do <EM>
29.75 +not </EM> support dynamic changes and attaching listeners. Their content is
29.76 +fixed from the time you call the creating method.
29.77 +
29.78 +<H2> ProxyLookup </H2>
29.79 +There can be situations where you get a lookup object from someone else and you
29.80 +want your lookup to return exactly the instances from the original lookup plus
29.81 +your own results. Here the class ProxyLookup comes into the play.
29.82 +<p>
29.83 +You simply create a new lookup like this:
29.84 +
29.85 +<pre>
29.86 + <font class="keyword">import</FONT> org.openide.util.Lookup;
29.87 + <font class="keyword">import</FONT> org.openide.util.lookup.*;
29.88 +
29.89 + <font class="type">Lookup</font> <font class="variable-name">lookup1</font> = ...;
29.90 +
29.91 + <font class="type">Lookup</font> <font class="variable-name">lookup2</font> = Lookups.singleton(MyService.<font class="keyword">class</font>);
29.92 + <font class="keyword">return</font> <font class="keyword">new</font> <font class="type">ProxyLookup</font>(<font class="keyword">new</font> <font class="type">Lookup</font>[] { lookup, lookup2 });
29.93 +</pre>
29.94 +
29.95 +<H2> AbstractLookup </H2>
29.96 +<!-- This paragraph originally copied from
29.97 +@TOP@org/openide/doc-files/services-api.html#lookup-impl
29.98 +-->
29.99 +
29.100 +<p>The most powerful way to provide a lookup is to directly define
29.101 +what instances and items it should provide, by subclassing. For this,
29.102 +
29.103 +<a href="@TOP@org/openide/util/lookup/AbstractLookup.html"><code>AbstractLookup</code></a>
29.104 +
29.105 +is recommended as it is easiest to use.
29.106 +
29.107 +<p>The simplest way to use <code>AbstractLookup</code> is to use its
29.108 +public constructor (in which case you need not subclass it). Here you
29.109 +provide an
29.110 +
29.111 +<a href="@TOP@org/openide/util/lookup/AbstractLookup.Content.html"><code>AbstractLookup.Content</code></a>
29.112 +
29.113 +object which you have created and hold on to privately, and which
29.114 +keeps track of instances and permits them to be registered and
29.115 +deregistered. Often
29.116 +
29.117 +<a href="@TOP@org/openide/util/lookup/InstanceContent.html"><code>InstanceContent</code></a>
29.118 +
29.119 +is used as the content implementation. To add something to the lookup,
29.120 +simply use
29.121 +
29.122 +<a href="@TOP@org/openide/util/lookup/InstanceContent.html#add(java.lang.Object)"><code>add(Object)</code></a>
29.123 +
29.124 +(and <code>remove(Object)</code> for the reverse). These may be called
29.125 +at any time and will update the set of registered instances (firing
29.126 +result changes as needed).
29.127 +
29.128 +<pre>
29.129 + <font class="keyword">import</FONT> org.openide.util.lookup.*;
29.130 + <font class="type">InstanceContent</font> <font class="variable-name">ic</font> = <font class="keyword">new</font> <font class="type">InstanceContent</font> ();
29.131 + ic.add(firstObject);
29.132 + <font class="keyword">return</font> <font class="keyword">new</font> <font class="type">AbstractLookup</font> (ic);
29.133 +</pre>
29.134 +
29.135 +<p>In case it is expensive to actually compute the object in the
29.136 +lookup, but there is some cheap "key" which can easily generate it,
29.137 +you may instead register the key by passing in an
29.138 +
29.139 +<a href="@TOP@org/openide/util/lookup/InstanceContent.Convertor.html"><code>InstanceContent.Convertor</code></a>.
29.140 +
29.141 +This convertor translates the key to the real instance that the lookup
29.142 +client sees, if and when needed. For example, if you have a long list
29.143 +of class names and wish to register default instances of each class,
29.144 +you might actually register the class name as the key, and supply a
29.145 +convertor which really loads the class and instantiates it. This makes
29.146 +it easy to set up the lookup, but nothing is really loaded until
29.147 +someone asks for it.
29.148 +
29.149 +</BODY>
29.150 +</HTML>
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/package.html Sat Oct 31 15:28:13 2009 +0100
30.3 @@ -0,0 +1,48 @@
30.4 +<!--
30.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
30.6 +
30.7 +Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
30.8 +
30.9 +
30.10 +The contents of this file are subject to the terms of either the GNU
30.11 +General Public License Version 2 only ("GPL") or the Common
30.12 +Development and Distribution License("CDDL") (collectively, the
30.13 +"License"). You may not use this file except in compliance with the
30.14 +License. You can obtain a copy of the License at
30.15 +http://www.netbeans.org/cddl-gplv2.html
30.16 +or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
30.17 +specific language governing permissions and limitations under the
30.18 +License. When distributing the software, include this License Header
30.19 +Notice in each file and include the License file at
30.20 +nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
30.21 +particular file as subject to the "Classpath" exception as provided
30.22 +by Sun in the GPL Version 2 section of the License file that
30.23 +accompanied this code. If applicable, add the following below the
30.24 +License Header, with the fields enclosed by brackets [] replaced by
30.25 +your own identifying information:
30.26 +"Portions Copyrighted [year] [name of copyright owner]"
30.27 +
30.28 +Contributor(s):
30.29 +
30.30 +The Original Software is NetBeans. The Initial Developer of the Original
30.31 +Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
30.32 +Microsystems, Inc. All Rights Reserved.
30.33 +
30.34 +If you wish your version of this file to be governed by only the CDDL
30.35 +or only the GPL Version 2, indicate your decision by adding
30.36 +"[Contributor] elects to include this software in this distribution
30.37 +under the [CDDL or GPL Version 2] license." If you do not indicate a
30.38 +single choice of license, a recipient has the option to distribute
30.39 +your version of this file under either the CDDL, the GPL Version 2 or
30.40 +to extend the choice of license to its licensees as provided above.
30.41 +However, if you add GPL Version 2 code and therefore, elected the GPL
30.42 +Version 2 license, then the option applies only if the new code is
30.43 +made subject to such option by the copyright holder.
30.44 +-->
30.45 +
30.46 +<html>
30.47 +<body>
30.48 +Support classes for the Registration and {@link org.openide.util.Lookup} extension mechanism.
30.49 +Read more: <a href="doc-files/index.html">Lookup Library</a>
30.50 +</body>
30.51 +</html>
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Comparator2.java Sat Oct 31 15:28:13 2009 +0100
31.3 @@ -0,0 +1,7 @@
31.4 +
31.5 +package org.bar;
31.6 +
31.7 +public class Comparator2 implements java.util.Comparator {
31.8 + public int compare(Object o1, Object o2) {return 0;}
31.9 + public boolean equals(Object obj) {return true;}
31.10 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Comparator3.java Sat Oct 31 15:28:13 2009 +0100
32.3 @@ -0,0 +1,7 @@
32.4 +
32.5 +package org.bar;
32.6 +
32.7 +public class Comparator3 implements java.util.Comparator {
32.8 + public int compare(Object o1, Object o2) {return 0;}
32.9 + public boolean equals(Object obj) {return true;}
32.10 +}
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Implementation2.java Sat Oct 31 15:28:13 2009 +0100
33.3 @@ -0,0 +1,3 @@
33.4 +package org.bar;
33.5 +import org.foo.Interface;
33.6 +public class Implementation2 implements Interface {}
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Iterator2.java Sat Oct 31 15:28:13 2009 +0100
34.3 @@ -0,0 +1,11 @@
34.4 +
34.5 +package org.bar;
34.6 +
34.7 +public class Iterator2 implements java.util.Iterator {
34.8 + public boolean hasNext() {return false;}
34.9 +
34.10 + public Object next() {return null;}
34.11 +
34.12 + public void remove() {}
34.13 +
34.14 +}
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/openide.util.lookup/test/unit/src/org/foo/Interface.java Sat Oct 31 15:28:13 2009 +0100
35.3 @@ -0,0 +1,2 @@
35.4 +package org.foo;
35.5 +public interface Interface {}
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Comparator1.java Sat Oct 31 15:28:13 2009 +0100
36.3 @@ -0,0 +1,7 @@
36.4 +
36.5 +package org.foo.impl;
36.6 +
36.7 +public class Comparator1 implements java.util.Comparator {
36.8 + public int compare(Object o1, Object o2) {return 0;}
36.9 + public boolean equals(Object obj) {return true;}
36.10 +}
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Implementation1.java Sat Oct 31 15:28:13 2009 +0100
37.3 @@ -0,0 +1,3 @@
37.4 +package org.foo.impl;
37.5 +import org.foo.Interface;
37.6 +public class Implementation1 implements Interface {}
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Iterator1.java Sat Oct 31 15:28:13 2009 +0100
38.3 @@ -0,0 +1,11 @@
38.4 +
38.5 +package org.foo.impl;
38.6 +
38.7 +public class Iterator1 implements java.util.Iterator {
38.8 + public boolean hasNext() {return false;}
38.9 +
38.10 + public Object next() {return null;}
38.11 +
38.12 + public void remove() {}
38.13 +
38.14 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Runnable1.java Sat Oct 31 15:28:13 2009 +0100
39.3 @@ -0,0 +1,6 @@
39.4 +
39.5 +package org.foo.impl;
39.6 +
39.7 +public class Runnable1 implements Runnable {
39.8 + public void run () {}
39.9 +}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupArrayStorageTest.java Sat Oct 31 15:28:13 2009 +0100
40.3 @@ -0,0 +1,120 @@
40.4 +/*
40.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
40.6 + *
40.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
40.8 + *
40.9 + * The contents of this file are subject to the terms of either the GNU
40.10 + * General Public License Version 2 only ("GPL") or the Common
40.11 + * Development and Distribution License("CDDL") (collectively, the
40.12 + * "License"). You may not use this file except in compliance with the
40.13 + * License. You can obtain a copy of the License at
40.14 + * http://www.netbeans.org/cddl-gplv2.html
40.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
40.16 + * specific language governing permissions and limitations under the
40.17 + * License. When distributing the software, include this License Header
40.18 + * Notice in each file and include the License file at
40.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
40.20 + * particular file as subject to the "Classpath" exception as provided
40.21 + * by Sun in the GPL Version 2 section of the License file that
40.22 + * accompanied this code. If applicable, add the following below the
40.23 + * License Header, with the fields enclosed by brackets [] replaced by
40.24 + * your own identifying information:
40.25 + * "Portions Copyrighted [year] [name of copyright owner]"
40.26 + *
40.27 + * Contributor(s):
40.28 + *
40.29 + * The Original Software is NetBeans. The Initial Developer of the Original
40.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
40.31 + * Microsystems, Inc. All Rights Reserved.
40.32 + *
40.33 + * If you wish your version of this file to be governed by only the CDDL
40.34 + * or only the GPL Version 2, indicate your decision by adding
40.35 + * "[Contributor] elects to include this software in this distribution
40.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
40.37 + * single choice of license, a recipient has the option to distribute
40.38 + * your version of this file under either the CDDL, the GPL Version 2 or
40.39 + * to extend the choice of license to its licensees as provided above.
40.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
40.41 + * Version 2 license, then the option applies only if the new code is
40.42 + * made subject to such option by the copyright holder.
40.43 + */
40.44 +
40.45 +package org.openide.util.lookup;
40.46 +
40.47 +import junit.framework.*;
40.48 +import org.netbeans.junit.*;
40.49 +import org.openide.util.Lookup;
40.50 +
40.51 +public class AbstractLookupArrayStorageTest extends AbstractLookupBaseHid {
40.52 + public AbstractLookupArrayStorageTest(java.lang.String testName) {
40.53 + super(testName, null);
40.54 + }
40.55 +
40.56 + public static TestSuite suite () {
40.57 + NbTestSuite suite = new NbTestSuite ();
40.58 + suite.addTest (new PL (2));
40.59 + suite.addTest (new AL (1));
40.60 + suite.addTest (new AL (-1));
40.61 + suite.addTest (new PL (-1));
40.62 + suite.addTest (new AL (5));
40.63 + suite.addTest (new PL (3));
40.64 + suite.addTest (new AL (2000));
40.65 + suite.addTest (new PL (2000));
40.66 + return suite;
40.67 + }
40.68 +
40.69 + static final class AL extends ArrayTestSuite {
40.70 + public AL (int trash) {
40.71 + super (trash);
40.72 + }
40.73 +
40.74 + public Lookup createLookup (Lookup lookup) {
40.75 + return lookup;
40.76 + }
40.77 +
40.78 + public void clearCaches () {
40.79 + }
40.80 +
40.81 + }
40.82 +
40.83 + static final class PL extends ArrayTestSuite {
40.84 + public PL (int trash) {
40.85 + super (trash);
40.86 + }
40.87 +
40.88 + public Lookup createLookup (Lookup lookup) {
40.89 + return new ProxyLookup (new Lookup[] { lookup });
40.90 + }
40.91 +
40.92 + public void clearCaches () {
40.93 + }
40.94 +
40.95 + }
40.96 +
40.97 + private static abstract class ArrayTestSuite extends NbTestSuite
40.98 + implements AbstractLookupBaseHid.Impl {
40.99 + private int trash;
40.100 +
40.101 + public ArrayTestSuite (int trash) {
40.102 + super (AbstractLookupArrayStorageTest.class);
40.103 + this.trash = trash;
40.104 +
40.105 + int cnt = this.countTestCases();
40.106 + for (int i = 0; i < cnt; i++) {
40.107 + Object o = this.testAt (i);
40.108 + AbstractLookupBaseHid t = (AbstractLookupBaseHid)o;
40.109 + t.impl = this;
40.110 + }
40.111 + }
40.112 +
40.113 + public Lookup createInstancesLookup (InstanceContent ic) {
40.114 + if (trash == -1) {
40.115 + return new AbstractLookup (ic, new ArrayStorage ());
40.116 + } else {
40.117 + return new AbstractLookup (ic, new ArrayStorage (new Integer (trash)));
40.118 + }
40.119 + }
40.120 +
40.121 +
40.122 + }
40.123 +}
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupAsynchExecutorTest.java Sat Oct 31 15:28:13 2009 +0100
41.3 @@ -0,0 +1,108 @@
41.4 +/*
41.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
41.6 + *
41.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
41.8 + *
41.9 + * The contents of this file are subject to the terms of either the GNU
41.10 + * General Public License Version 2 only ("GPL") or the Common
41.11 + * Development and Distribution License("CDDL") (collectively, the
41.12 + * "License"). You may not use this file except in compliance with the
41.13 + * License. You can obtain a copy of the License at
41.14 + * http://www.netbeans.org/cddl-gplv2.html
41.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
41.16 + * specific language governing permissions and limitations under the
41.17 + * License. When distributing the software, include this License Header
41.18 + * Notice in each file and include the License file at
41.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
41.20 + * particular file as subject to the "Classpath" exception as provided
41.21 + * by Sun in the GPL Version 2 section of the License file that
41.22 + * accompanied this code. If applicable, add the following below the
41.23 + * License Header, with the fields enclosed by brackets [] replaced by
41.24 + * your own identifying information:
41.25 + * "Portions Copyrighted [year] [name of copyright owner]"
41.26 + *
41.27 + * Contributor(s):
41.28 + *
41.29 + * The Original Software is NetBeans. The Initial Developer of the Original
41.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
41.31 + * Microsystems, Inc. All Rights Reserved.
41.32 + *
41.33 + * If you wish your version of this file to be governed by only the CDDL
41.34 + * or only the GPL Version 2, indicate your decision by adding
41.35 + * "[Contributor] elects to include this software in this distribution
41.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
41.37 + * single choice of license, a recipient has the option to distribute
41.38 + * your version of this file under either the CDDL, the GPL Version 2 or
41.39 + * to extend the choice of license to its licensees as provided above.
41.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
41.41 + * Version 2 license, then the option applies only if the new code is
41.42 + * made subject to such option by the copyright holder.
41.43 + */
41.44 +
41.45 +package org.openide.util.lookup;
41.46 +
41.47 +import java.util.ArrayList;
41.48 +import java.util.List;
41.49 +import java.util.concurrent.Executor;
41.50 +import org.netbeans.junit.NbTestCase;
41.51 +import org.openide.util.Lookup;
41.52 +import org.openide.util.LookupEvent;
41.53 +import org.openide.util.LookupListener;
41.54 +
41.55 +public class AbstractLookupAsynchExecutorTest extends NbTestCase implements Executor {
41.56 + private List<Runnable> toRun = new ArrayList<Runnable>();
41.57 +
41.58 +
41.59 + public AbstractLookupAsynchExecutorTest(java.lang.String testName) {
41.60 + super(testName);
41.61 + }
41.62 +
41.63 + public void testCanProxyLookupHaveWrongResults() {
41.64 + final InstanceContent ic = new InstanceContent(this);
41.65 + final AbstractLookup lookup = new AbstractLookup(ic);
41.66 +
41.67 + class L implements LookupListener {
41.68 + ProxyLookup pl;
41.69 + Lookup.Result<String> original;
41.70 + Lookup.Result<String> wrapped;
41.71 + boolean ok;
41.72 +
41.73 + public void test() {
41.74 + pl = new ProxyLookup(lookup);
41.75 + original = lookup.lookupResult(String.class);
41.76 +
41.77 + original.addLookupListener(this);
41.78 +
41.79 + wrapped = pl.lookupResult(String.class);
41.80 +
41.81 + assertEquals("Original empty", 0, original.allInstances().size());
41.82 + assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
41.83 +
41.84 + ic.add("Hello!");
41.85 + }
41.86 +
41.87 + public void resultChanged(LookupEvent ev) {
41.88 + ok = true;
41.89 + assertContainsHello();
41.90 + }
41.91 +
41.92 + public void assertContainsHello() {
41.93 + assertEquals("Original has hello", 1, original.allInstances().size());
41.94 + assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
41.95 + }
41.96 +
41.97 + }
41.98 + L listener = new L();
41.99 + listener.test();
41.100 + listener.assertContainsHello();
41.101 + for (Runnable r : toRun) {
41.102 + r.run();
41.103 + }
41.104 + assertTrue("Listener called", listener.ok);
41.105 + }
41.106 +
41.107 + public void execute(Runnable command) {
41.108 + toRun.add(command);
41.109 + }
41.110 +
41.111 +}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupBaseHid.java Sat Oct 31 15:28:13 2009 +0100
42.3 @@ -0,0 +1,2088 @@
42.4 +/*
42.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
42.6 + *
42.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
42.8 + *
42.9 + * The contents of this file are subject to the terms of either the GNU
42.10 + * General Public License Version 2 only ("GPL") or the Common
42.11 + * Development and Distribution License("CDDL") (collectively, the
42.12 + * "License"). You may not use this file except in compliance with the
42.13 + * License. You can obtain a copy of the License at
42.14 + * http://www.netbeans.org/cddl-gplv2.html
42.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
42.16 + * specific language governing permissions and limitations under the
42.17 + * License. When distributing the software, include this License Header
42.18 + * Notice in each file and include the License file at
42.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
42.20 + * particular file as subject to the "Classpath" exception as provided
42.21 + * by Sun in the GPL Version 2 section of the License file that
42.22 + * accompanied this code. If applicable, add the following below the
42.23 + * License Header, with the fields enclosed by brackets [] replaced by
42.24 + * your own identifying information:
42.25 + * "Portions Copyrighted [year] [name of copyright owner]"
42.26 + *
42.27 + * Contributor(s):
42.28 + *
42.29 + * The Original Software is NetBeans. The Initial Developer of the Original
42.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
42.31 + * Microsystems, Inc. All Rights Reserved.
42.32 + *
42.33 + * If you wish your version of this file to be governed by only the CDDL
42.34 + * or only the GPL Version 2, indicate your decision by adding
42.35 + * "[Contributor] elects to include this software in this distribution
42.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
42.37 + * single choice of license, a recipient has the option to distribute
42.38 + * your version of this file under either the CDDL, the GPL Version 2 or
42.39 + * to extend the choice of license to its licensees as provided above.
42.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
42.41 + * Version 2 license, then the option applies only if the new code is
42.42 + * made subject to such option by the copyright holder.
42.43 + */
42.44 +
42.45 +package org.openide.util.lookup;
42.46 +
42.47 +import java.io.ByteArrayInputStream;
42.48 +import java.io.ByteArrayOutputStream;
42.49 +import java.io.ObjectInputStream;
42.50 +import java.io.ObjectOutputStream;
42.51 +import java.io.Serializable;
42.52 +import java.lang.ref.WeakReference;
42.53 +import java.lang.ref.Reference;
42.54 +import java.util.ArrayList;
42.55 +import java.util.Arrays;
42.56 +import java.util.Collection;
42.57 +import java.util.Collections;
42.58 +import java.util.Iterator;
42.59 +import java.util.LinkedList;
42.60 +import java.util.List;
42.61 +import java.util.concurrent.Executors;
42.62 +import java.util.concurrent.TimeUnit;
42.63 +import javax.swing.ActionMap;
42.64 +import javax.swing.InputMap;
42.65 +import org.netbeans.junit.NbTestCase;
42.66 +import org.openide.util.Lookup;
42.67 +import org.openide.util.Lookup.Template;
42.68 +import org.openide.util.LookupEvent;
42.69 +import org.openide.util.LookupListener;
42.70 +
42.71 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
42.72 +public class AbstractLookupBaseHid extends NbTestCase {
42.73 + private static AbstractLookupBaseHid running;
42.74 +
42.75 + /** instance content to work with */
42.76 + InstanceContent ic;
42.77 + /** the lookup to work on */
42.78 + protected Lookup instanceLookup;
42.79 + /** the lookup created to work with */
42.80 + private Lookup lookup;
42.81 + /** implementation of methods that can influence the behaviour */
42.82 + Impl impl;
42.83 +
42.84 + protected AbstractLookupBaseHid(String testName, Impl impl) {
42.85 + super(testName);
42.86 + if (impl == null && (this instanceof Impl)) {
42.87 + impl = (Impl)this;
42.88 + }
42.89 + this.impl = impl;
42.90 + }
42.91 +
42.92 + protected @Override void setUp() {
42.93 + this.ic = new InstanceContent ();
42.94 +
42.95 + beforeActualTest(getName());
42.96 +
42.97 + this.instanceLookup = createInstancesLookup (ic);
42.98 + this.lookup = createLookup (instanceLookup);
42.99 + running = this;
42.100 + }
42.101 +
42.102 + protected @Override void tearDown() {
42.103 + running = null;
42.104 + }
42.105 +
42.106 + /** The methods to influence test behaviour */
42.107 + public static interface Impl {
42.108 + /** Creates the initial abstract lookup.
42.109 + */
42.110 + public Lookup createInstancesLookup (InstanceContent ic);
42.111 + /** Creates an lookup for given lookup. This class just returns
42.112 + * the object passed in, but subclasses can be different.
42.113 + * @param lookup in lookup
42.114 + * @return a lookup to use
42.115 + */
42.116 + public Lookup createLookup (Lookup lookup);
42.117 +
42.118 + /** If the impl has any caches that would prevent the system
42.119 + * to not garbage collect correctly, then clear them now.
42.120 + */
42.121 + public void clearCaches ();
42.122 + }
42.123 +
42.124 + private Lookup createInstancesLookup (InstanceContent ic) {
42.125 + return impl.createInstancesLookup (ic);
42.126 + }
42.127 +
42.128 + private Lookup createLookup (Lookup lookup) {
42.129 + return impl.createLookup (lookup);
42.130 + }
42.131 +
42.132 + /** instances that we register */
42.133 + private static Object[] INSTANCES = new Object[] {
42.134 + new Integer (10),
42.135 + new Object ()
42.136 + };
42.137 +
42.138 + /** Test if first is really first.
42.139 + */
42.140 + public void testFirst () {
42.141 + Integer i1 = 1;
42.142 + Integer i2 = 2;
42.143 +
42.144 + ic.add (i1);
42.145 + ic.add (i2);
42.146 +
42.147 + Integer found = lookup.lookup(Integer.class);
42.148 + if (found != i1) {
42.149 + fail ("First object is not first: " + found + " != " + i1);
42.150 + }
42.151 +
42.152 + List<Integer> list = new ArrayList<Integer>();
42.153 + list.add (i2);
42.154 + list.add (i1);
42.155 + ic.set (list, null);
42.156 +
42.157 + found = lookup.lookup (Integer.class);
42.158 + if (found != i2) {
42.159 + fail ("Second object is not first after reorder: " + found + " != " + i2);
42.160 + }
42.161 +
42.162 + }
42.163 +
42.164 + public void testToString() {
42.165 + String txt = lookup.toString();
42.166 + assertNotNull("Something is there", txt);
42.167 + assertTrue("Something2: " + txt, txt.length() > 0);
42.168 + }
42.169 +
42.170 +
42.171 + /** Tests ordering of items in the lookup.
42.172 + */
42.173 + public void testOrder () {
42.174 + addInstances (INSTANCES);
42.175 +
42.176 + if (INSTANCES[0] != lookup.lookup (INSTANCES[0].getClass ())) {
42.177 + fail ("First object in intances not found");
42.178 + }
42.179 +
42.180 + Iterator<?> all = lookup.lookupAll(Object.class).iterator();
42.181 + checkIterator ("Difference between instances added and found", all, Arrays.asList (INSTANCES));
42.182 + }
42.183 +
42.184 + /** Checks the reorder of items in lookup reflects the result.
42.185 + * Testing both classes and interfaces, because they are often treated
42.186 + * especially.
42.187 + */
42.188 + public void testReorder () {
42.189 + String s1 = "s2";
42.190 + String s2 = "s1";
42.191 + Runnable r1 = new Runnable () {
42.192 + public void run () {}
42.193 + };
42.194 + Runnable r2 = new Runnable () {
42.195 + public void run () {}
42.196 + };
42.197 + List<Object> l = new ArrayList<Object>();
42.198 +
42.199 + l.add (s1);
42.200 + l.add (s2);
42.201 + l.add (r1);
42.202 + l.add (r2);
42.203 + ic.set (l, null);
42.204 +
42.205 + assertEquals ("s1 is found", s1, lookup.lookup (String.class));
42.206 + assertEquals ("r1 is found", r1, lookup.lookup (Runnable.class));
42.207 +
42.208 + Collections.reverse (l);
42.209 +
42.210 + ic.set (l, null);
42.211 +
42.212 + assertEquals ("s2 is found", s2, lookup.lookup (String.class));
42.213 + assertEquals ("r2 is found", r2, lookup.lookup (Runnable.class));
42.214 + }
42.215 +
42.216 + /** Tries to set empty collection to the lookup.
42.217 + */
42.218 + public void testSetEmpty () {
42.219 + ic.add ("A serializable string");
42.220 + lookup.lookup (Serializable.class);
42.221 +
42.222 + ic.set (Collections.emptyList(), null);
42.223 + }
42.224 +
42.225 + /** Tests a more complex reorder on nodes.
42.226 + */
42.227 + public void testComplexReorder () {
42.228 + Integer i1 = 1;
42.229 + Long i2 = 2L;
42.230 +
42.231 + List<Object> l = new ArrayList<Object>();
42.232 + l.add (i1);
42.233 + l.add (i2);
42.234 + ic.set (l, null);
42.235 +
42.236 + assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
42.237 + assertEquals ("Find long", i2, lookup.lookup (Long.class));
42.238 + assertEquals ("Find number", i1, lookup.lookup (Number.class));
42.239 +
42.240 + Collections.reverse (l);
42.241 +
42.242 + ic.set (l, null);
42.243 +
42.244 + assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
42.245 + assertEquals ("Find long", i2, lookup.lookup (Long.class));
42.246 + assertEquals ("Find number", i2, lookup.lookup (Number.class));
42.247 + }
42.248 +
42.249 + /** Checks whether setPairs keeps the order.
42.250 + */
42.251 + public void testSetPairs () {
42.252 + // test setPairs method
42.253 + List<Object> li = new ArrayList<Object>();
42.254 + li.addAll (Arrays.asList (INSTANCES));
42.255 + ic.set (li, null);
42.256 +
42.257 + Lookup.Result<Object> res = lookup.lookupResult(Object.class);
42.258 + Iterator<?> all = res.allInstances().iterator();
42.259 + checkIterator ("Original order not kept", all, li);
42.260 +
42.261 + // reverse the order
42.262 + Collections.reverse (li);
42.263 +
42.264 + // change the pairs
42.265 + LL listener = new LL (res);
42.266 + res.addLookupListener (listener);
42.267 + ic.set (li, null);
42.268 + if (listener.getCount () != 1) {
42.269 + fail ("Result has not changed even we set reversed order");
42.270 + }
42.271 +
42.272 + all = res.allInstances ().iterator ();
42.273 + checkIterator ("Reversed order not kept", all, li);
42.274 + }
42.275 +
42.276 + /** Checks whether setPairs fires correct events.
42.277 + */
42.278 + public void testSetPairsFire () {
42.279 + // test setPairs method
42.280 + List<Object> li = new ArrayList<Object>();
42.281 + li.addAll (Arrays.asList (INSTANCES));
42.282 + ic.set (li, null);
42.283 +
42.284 + Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
42.285 + Iterator<?> all = res.allInstances().iterator();
42.286 + checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
42.287 +
42.288 + // change the pairs
42.289 + LL listener = new LL (res);
42.290 + res.addLookupListener (listener);
42.291 +
42.292 + List<Object> l2 = new ArrayList<Object>(li);
42.293 + l2.remove (INSTANCES[0]);
42.294 + ic.set (l2, null);
42.295 +
42.296 + all = lookup.lookupAll(Object.class).iterator();
42.297 + checkIterator ("The removed integer is not noticed", all, l2);
42.298 +
42.299 + if (listener.getCount () != 1) {
42.300 + fail ("Nothing has not been fired");
42.301 + }
42.302 + }
42.303 +
42.304 + /** Checks whether set pairs does not fire when they should not.
42.305 + */
42.306 + public void testSetPairsDoesNotFire () {
42.307 + Object tmp = new Object ();
42.308 +
42.309 + List<Object> li = new ArrayList<Object>();
42.310 + li.add (tmp);
42.311 + li.addAll (Arrays.asList (INSTANCES));
42.312 + ic.set (li, null);
42.313 +
42.314 + Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
42.315 + Iterator<?> all = res.allInstances ().iterator ();
42.316 + checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
42.317 +
42.318 + // change the pairs
42.319 + LL listener = new LL (res);
42.320 + res.addLookupListener (listener);
42.321 +
42.322 + List<Object> l2 = new ArrayList<Object>(li);
42.323 + l2.remove (tmp);
42.324 + ic.set (l2, null);
42.325 +
42.326 + all = lookup.lookupAll(Object.class).iterator();
42.327 + checkIterator ("The removed integer is not noticed", all, l2);
42.328 +
42.329 + if (listener.getCount () != 0) {
42.330 + fail ("Something has been fired");
42.331 + }
42.332 + }
42.333 +
42.334 + /** Test whether after registration it is possible to find registered objects
42.335 + *
42.336 + */
42.337 + public void testLookupAndAdd () throws Exception {
42.338 + addInstances (INSTANCES);
42.339 +
42.340 + for (int i = 0; i < INSTANCES.length; i++) {
42.341 + Object obj = INSTANCES[i];
42.342 + findAll (lookup, obj.getClass (), true);
42.343 + }
42.344 + }
42.345 +
42.346 + /** Tries to find all classes and superclasses in the lookup.
42.347 + */
42.348 + private void findAll(Lookup lookup, Class<?> clazz, boolean shouldBeThere) {
42.349 + if (clazz == null) return;
42.350 +
42.351 + Object found = lookup.lookup (clazz);
42.352 + if (found == null) {
42.353 + if (shouldBeThere) {
42.354 + // should find at either instance or something else, but must
42.355 + // find at least something
42.356 + fail ("Lookup (" + clazz.getName () + ") found nothing");
42.357 + }
42.358 + } else {
42.359 + if (!shouldBeThere) {
42.360 + // should find at either instance or something else, but must
42.361 + // find at least something
42.362 + fail ("Lookup (" + clazz.getName () + ") found " + found);
42.363 + }
42.364 + }
42.365 +
42.366 + Lookup.Result<?> res = lookup.lookupResult(clazz);
42.367 + Collection<?> collection = res.allInstances();
42.368 +
42.369 + for (int i = 0; i < INSTANCES.length; i++) {
42.370 + boolean isSubclass = clazz.isInstance (INSTANCES[i]);
42.371 + boolean isThere = collection.contains (INSTANCES[i]);
42.372 +
42.373 + if (isSubclass != isThere) {
42.374 + // a problem found
42.375 + // should find at either instance or something else, but must
42.376 + // find at least something
42.377 + fail ("Lookup.Result (" + clazz.getName () + ") for " + INSTANCES[i] + " is subclass: " + isSubclass + " isThere: " + isThere);
42.378 + }
42.379 + }
42.380 +
42.381 + // go on for superclasses
42.382 +
42.383 + findAll (lookup, clazz.getSuperclass (), shouldBeThere);
42.384 +
42.385 + Class[] ies = clazz.getInterfaces ();
42.386 + for (int i = 0; i < ies.length; i++) {
42.387 + findAll (lookup, ies[i], shouldBeThere);
42.388 + }
42.389 + }
42.390 +
42.391 + /** Test if it is possible to remove a registered object. */
42.392 + public void testRemoveRegisteredObject() {
42.393 + Integer inst = new Integer(10);
42.394 +
42.395 + ic.add(inst);
42.396 + if (lookup.lookup(inst.getClass()) == null) {
42.397 + // should find an instance
42.398 + fail("Lookup (" + inst.getClass().getName () + ") found nothing");
42.399 + }
42.400 +
42.401 + ic.remove(inst);
42.402 + if (lookup.lookup(inst.getClass()) != null) {
42.403 + // should NOT find an instance
42.404 + fail("Lookup (" + inst.getClass().getName () +
42.405 + ") found an instance after remove operation");
42.406 + }
42.407 + }
42.408 +
42.409 + public void testCanReturnReallyStrangeResults () throws Exception {
42.410 + class QueryingPair extends AbstractLookup.Pair<Object> {
42.411 + private Integer i = 434;
42.412 +
42.413 + //
42.414 + // do the test
42.415 + //
42.416 +
42.417 + public void doTest () throws Exception {
42.418 + ic.add (i);
42.419 + ic.addPair (this);
42.420 +
42.421 + Object found = lookup.lookup (QueryingPair.class);
42.422 + assertEquals ("This object is found", this, found);
42.423 + }
42.424 +
42.425 +
42.426 + //
42.427 + // Implementation of pair
42.428 + //
42.429 +
42.430 + public String getId() {
42.431 + return getType ().toString();
42.432 + }
42.433 +
42.434 + public String getDisplayName() {
42.435 + return getId ();
42.436 + }
42.437 +
42.438 + public Class<?> getType() {
42.439 + return getClass ();
42.440 + }
42.441 +
42.442 + protected boolean creatorOf(Object obj) {
42.443 + return obj == this;
42.444 + }
42.445 +
42.446 + protected boolean instanceOf(Class<?> c) {
42.447 + assertEquals ("Integer found or exception is thrown", i, lookup.lookup (Integer.class));
42.448 + return c.isAssignableFrom(getType ());
42.449 + }
42.450 +
42.451 + public Object getInstance() {
42.452 + return this;
42.453 + }
42.454 +
42.455 +
42.456 + }
42.457 +
42.458 +
42.459 + QueryingPair qp = new QueryingPair ();
42.460 + qp.doTest ();
42.461 + }
42.462 +
42.463 + /** Test of firing events. */
42.464 + public void testLookupListener() {
42.465 + Object inst = 10;
42.466 + Lookup.Result<?> res = lookup.lookupResult(inst.getClass());
42.467 + res.allInstances ();
42.468 +
42.469 + LL listener = new LL(res);
42.470 + res.addLookupListener(listener);
42.471 +
42.472 + ic.add(inst);
42.473 + if (listener.getCount() == 0) {
42.474 + fail("None event fired during NbLookup.addPair()");
42.475 + }
42.476 +
42.477 + ic.remove(inst);
42.478 + if (listener.getCount() == 0) {
42.479 + fail("None event fired during NbLookup.removePair()");
42.480 + }
42.481 +
42.482 + ic.add(inst);
42.483 + if (listener.getCount() == 0) {
42.484 + fail("None event fired during second NbLookup.addPair()");
42.485 + }
42.486 +
42.487 + ic.remove(inst);
42.488 + if (listener.getCount() == 0) {
42.489 + fail("None event fired during second NbLookup.removePair()");
42.490 + }
42.491 + }
42.492 +
42.493 + /** Testing identity of the lookup.
42.494 + */
42.495 + public void testId () {
42.496 + Lookup.Template<?> templ;
42.497 + int cnt;
42.498 +
42.499 + addInstances (INSTANCES);
42.500 +
42.501 + Lookup.Result<?> res = lookup.lookupResult(Object.class);
42.502 + for (AbstractLookup.Item<?> item : res.allItems()) {
42.503 +
42.504 + templ = new Lookup.Template<Object>(null, item.getId(), null);
42.505 + cnt = lookup.lookup (templ).allInstances ().size ();
42.506 + if (cnt != 1) {
42.507 + fail ("Identity lookup failed. Instances = " + cnt);
42.508 + }
42.509 +
42.510 + templ = makeTemplate(item.getType(), item.getId());
42.511 + cnt = lookup.lookup (templ).allInstances ().size ();
42.512 + if (cnt != 1) {
42.513 + fail ("Identity lookup with type failed. Instances = " + cnt);
42.514 + }
42.515 +
42.516 + templ = makeTemplate(this.getClass(), item.getId());
42.517 + cnt = lookup.lookup (templ).allInstances ().size ();
42.518 + if (cnt != 0) {
42.519 + fail ("Identity lookup with wrong type failed. Instances = " + cnt);
42.520 + }
42.521 +
42.522 + templ = new Lookup.Template<Object>(null, null, item.getInstance());
42.523 + cnt = lookup.lookup (templ).allInstances ().size ();
42.524 + if (cnt != 1) {
42.525 + fail ("Instance lookup failed. Instances = " + cnt);
42.526 + }
42.527 +
42.528 + templ = new Lookup.Template<Object>(null, item.getId(), item.getInstance());
42.529 + cnt = lookup.lookup (templ).allInstances ().size ();
42.530 + if (cnt != 1) {
42.531 + fail ("Instance & identity lookup failed. Instances = " + cnt);
42.532 + }
42.533 +
42.534 + }
42.535 + }
42.536 + private static <T> Lookup.Template<T> makeTemplate(Class<T> clazz, String id) { // captures type parameter
42.537 + return new Lookup.Template<T>(clazz, id, null);
42.538 + }
42.539 +
42.540 + /** Tests adding and removing.
42.541 + */
42.542 + public void testAddAndRemove () throws Exception {
42.543 + Object map = new javax.swing.ActionMap ();
42.544 + LL ll = new LL ();
42.545 +
42.546 + Lookup.Result<?> res = lookup.lookupResult(map.getClass());
42.547 + res.allItems();
42.548 + res.addLookupListener (ll);
42.549 + ll.source = res;
42.550 +
42.551 + ic.add (map);
42.552 +
42.553 + assertEquals ("First change when adding", ll.getCount (), 1);
42.554 +
42.555 + ic.remove (map);
42.556 +
42.557 + assertEquals ("Second when removing", ll.getCount (), 1);
42.558 +
42.559 + ic.add (map);
42.560 +
42.561 + assertEquals ("Third when readding", ll.getCount (), 1);
42.562 +
42.563 + ic.remove (map);
42.564 +
42.565 + assertEquals ("Forth when reremoving", ll.getCount (), 1);
42.566 +
42.567 + }
42.568 +
42.569 + /** Will a class garbage collect even it is registered in lookup.
42.570 + */
42.571 + public void testGarbageCollect () throws Exception {
42.572 + ClassLoader l = new CL ();
42.573 + Class<?> c = l.loadClass(Garbage.class.getName());
42.574 + Reference<?> ref = new WeakReference<Object>(c);
42.575 +
42.576 + lookup.lookup (c);
42.577 +
42.578 + // now test garbage collection
42.579 + c = null;
42.580 + l = null;
42.581 + impl.clearCaches ();
42.582 + assertGC ("The classloader has not been garbage collected!", ref);
42.583 + }
42.584 +
42.585 + /** Items are the same as results.
42.586 + */
42.587 + public void testItemsAndIntances () {
42.588 + addInstances (INSTANCES);
42.589 +
42.590 + Lookup.Result<Object> r = lookup.lookupResult(Object.class);
42.591 + Collection<? extends Lookup.Item<?>> items = r.allItems();
42.592 + Collection<?> insts = r.allInstances();
42.593 +
42.594 + if (items.size () != insts.size ()) {
42.595 + fail ("Different size of sets");
42.596 + }
42.597 +
42.598 + for (Lookup.Item<?> item : items) {
42.599 + if (!insts.contains (item.getInstance ())) {
42.600 + fail ("Intance " + item.getInstance () + " is missing in " + insts);
42.601 + }
42.602 + }
42.603 + }
42.604 +
42.605 + /** Checks search for interface.
42.606 + */
42.607 + public void testSearchForInterface () {
42.608 + Lookup.Template<Serializable> t = new Lookup.Template<Serializable>(Serializable.class, null, null);
42.609 +
42.610 + assertNull("Nothing to find", lookup.lookupItem (t));
42.611 +
42.612 + Serializable s = new Serializable () {};
42.613 + ic.add (s);
42.614 +
42.615 + Lookup.Item item = lookup.lookupItem (t);
42.616 + assertNotNull ("Something found", item);
42.617 + }
42.618 +
42.619 + /** Test to add broken item if it incorrectly answers instanceOf questions.
42.620 + */
42.621 + public void testIncorectInstanceOf40364 () {
42.622 + final Long sharedLong = new Long (0);
42.623 +
42.624 + class P extends AbstractLookup.Pair<Object> {
42.625 + public boolean isLong;
42.626 +
42.627 + P (boolean b) {
42.628 + isLong = b;
42.629 + }
42.630 +
42.631 + protected boolean creatorOf (Object obj) {
42.632 + return obj == sharedLong;
42.633 + }
42.634 +
42.635 + public String getDisplayName () {
42.636 + return "";
42.637 + }
42.638 +
42.639 + public String getId () {
42.640 + return "";
42.641 + }
42.642 +
42.643 + public Object getInstance () {
42.644 + return sharedLong;
42.645 + }
42.646 +
42.647 + public Class<?> getType() {
42.648 + return isLong ? Long.class : Number.class;
42.649 + }
42.650 +
42.651 + protected boolean instanceOf(Class<?> c) {
42.652 + return c.isAssignableFrom (getType ());
42.653 + }
42.654 +
42.655 + public @Override int hashCode() {
42.656 + return getClass ().hashCode ();
42.657 + }
42.658 +
42.659 + public @Override boolean equals(Object obj) {
42.660 + return obj != null && getClass ().equals (obj.getClass ());
42.661 + }
42.662 + }
42.663 +
42.664 + // to create the right structure in the lookup
42.665 + lookup.lookup (Object.class);
42.666 + lookup.lookup (Long.class);
42.667 + lookup.lookup (Number.class);
42.668 +
42.669 + P lng1 = new P (true);
42.670 + ic.addPair (lng1);
42.671 +
42.672 + P lng2 = new P (false);
42.673 + ic.setPairs (Collections.singleton (lng2));
42.674 +
42.675 + Collection<? extends Lookup.Item<?>> res = lookup.lookupResult(Object.class).allItems();
42.676 + assertEquals ("Just one pair", 1, res.size ());
42.677 + }
42.678 +
42.679 + public void testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly () throws Exception {
42.680 + class X implements TestInterfaceInheritanceA, TestInterfaceInheritanceB {
42.681 + }
42.682 + final X shared = new X ();
42.683 +
42.684 + class P extends AbstractLookup.Pair<Object> {
42.685 + public int howLong;
42.686 +
42.687 + P (int b) {
42.688 + howLong = b;
42.689 + }
42.690 +
42.691 + protected boolean creatorOf (Object obj) {
42.692 + return obj == shared;
42.693 + }
42.694 +
42.695 + public String getDisplayName () {
42.696 + return "";
42.697 + }
42.698 +
42.699 + public String getId () {
42.700 + return "";
42.701 + }
42.702 +
42.703 + public Object getInstance () {
42.704 + return shared;
42.705 + }
42.706 +
42.707 + public Class<?> getType() {
42.708 + return howLong == 0 ? TestInterfaceInheritanceB.class : TestInterfaceInheritanceA.class;
42.709 + }
42.710 +
42.711 + protected boolean instanceOf(Class<?> c) {
42.712 + return c.isAssignableFrom (getType ());
42.713 + }
42.714 +
42.715 + public @Override int hashCode() {
42.716 + return getClass ().hashCode ();
42.717 + }
42.718 +
42.719 + public @Override boolean equals(Object obj) {
42.720 + if (obj instanceof P) {
42.721 + P p = (P)obj;
42.722 + if (this.howLong > 0) {
42.723 + this.howLong--;
42.724 + return false;
42.725 + }
42.726 + if (p.howLong > 0) {
42.727 + p.howLong--;
42.728 + return false;
42.729 + }
42.730 + return getClass ().equals (p.getClass ());
42.731 + }
42.732 + return false;
42.733 + }
42.734 + }
42.735 +
42.736 + // to create the right structure in the lookup
42.737 + Lookup.Result<?> a = lookup.lookupResult(TestInterfaceInheritanceA.class);
42.738 + Lookup.Result<?> b = lookup.lookupResult(TestInterfaceInheritanceB.class);
42.739 +
42.740 + P lng1 = new P (0);
42.741 + ic.addPair (lng1);
42.742 +
42.743 + assertEquals ("One in a", 1, a.allItems ().size ());
42.744 + assertEquals ("One in b", 1, b.allItems ().size ());
42.745 +
42.746 + P lng2 = new P (1);
42.747 +
42.748 +
42.749 + /* Following call used to generate this exception:
42.750 + java.lang.IllegalStateException: Duplicate pair in treePair1: pair2: index1: 0 index2: 0 item1: org.openide.util.lookup.AbstractLookupBaseHid$1X@1a457b6 item2: org.openide.util.lookup.AbstractLookupBaseHid$1X@1a457b6 id1: 7a78d3 id2: 929206
42.751 + at org.openide.util.lookup.ALPairComparator.compare(ALPairComparator.java:52)
42.752 + at java.util.Arrays.mergeSort(Arrays.java:1284)
42.753 + at java.util.Arrays.sort(Arrays.java:1223)
42.754 + at java.util.Collections.sort(Collections.java:159)
42.755 + at org.openide.util.lookup.InheritanceTree.retainAllInterface(InheritanceTree.java:753)
42.756 + at org.openide.util.lookup.InheritanceTree.retainAll(InheritanceTree.java:183)
42.757 + at org.openide.util.lookup.DelegatingStorage.retainAll(DelegatingStorage.java:83)
42.758 + at org.openide.util.lookup.AbstractLookup.setPairsAndCollectListeners(AbstractLookup.java:238)
42.759 + at org.openide.util.lookup.AbstractLookup.setPairs(AbstractLookup.java:203)
42.760 + at org.openide.util.lookup.AbstractLookup$Content.setPairs(AbstractLookup.java:885)
42.761 + at org.openide.util.lookup.AbstractLookupBaseHid.testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly(AbstractLookupBaseHid.java:696)
42.762 + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
42.763 + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
42.764 + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
42.765 + at org.netbeans.junit.NbTestCase.run(NbTestCase.java:119)
42.766 + */
42.767 + ic.setPairs (Collections.singleton (lng2));
42.768 +
42.769 +
42.770 + }
42.771 +
42.772 + public void testInstancesArePreservedFoundWhenFixing48590 () throws Exception {
42.773 + class X implements Runnable, Serializable {
42.774 + public void run () {
42.775 +
42.776 + }
42.777 +
42.778 + public void assertOnlyMe (String msg, Lookup.Result<?> res) {
42.779 + Collection<?> col = res.allInstances();
42.780 + assertEquals (msg + " just one", 1, col.size ());
42.781 + assertSame (msg + " and it is me", this, col.iterator ().next ());
42.782 + }
42.783 + }
42.784 +
42.785 + Lookup.Result<?> runnable = lookup.lookupResult(Runnable.class);
42.786 + Lookup.Result<?> serial = lookup.lookupResult(Serializable.class);
42.787 +
42.788 +
42.789 + X x = new X ();
42.790 + ic.add (x);
42.791 +
42.792 +
42.793 + x.assertOnlyMe ("x implements it (1)", runnable);
42.794 + x.assertOnlyMe ("x implements it (2)", serial);
42.795 +
42.796 + ic.set (Collections.singleton (x), null);
42.797 +
42.798 + x.assertOnlyMe ("x implements it (3)", runnable);
42.799 + x.assertOnlyMe ("x implements it (4)", serial);
42.800 + }
42.801 +
42.802 + /** Testing lookup of inherited classes. */
42.803 + public void testInheritance() {
42.804 + class A {}
42.805 + class B extends A implements java.rmi.Remote {}
42.806 + class BB extends B {}
42.807 + class C extends A implements java.rmi.Remote {}
42.808 + class D extends A {}
42.809 +
42.810 + A[] types = {new B(), new BB(), new C(), new D()};
42.811 +
42.812 + for (int i = 0; i < types.length; i++) {
42.813 + ic.add(types[i]);
42.814 + if (lookup.lookup(types[i].getClass()) == null) {
42.815 + // should find an instance
42.816 + fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
42.817 + }
42.818 + }
42.819 +
42.820 + int size1, size2;
42.821 +
42.822 + //interface query
42.823 + size1 = lookup.lookupAll(java.rmi.Remote.class).size();
42.824 + size2 = countInstances(types, java.rmi.Remote.class);
42.825 +
42.826 + if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
42.827 +
42.828 + // superclass query
42.829 + size1 = lookup.lookupAll(A.class).size();
42.830 + size2 = countInstances(types, A.class);
42.831 +
42.832 + if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
42.833 + }
42.834 +
42.835 + /** Test interface inheritance.
42.836 + */
42.837 + public void testInterfaceInheritance() {
42.838 + TestInterfaceInheritanceA[] types = {
42.839 + new TestInterfaceInheritanceB() {},
42.840 + new TestInterfaceInheritanceBB() {},
42.841 + new TestInterfaceInheritanceC() {},
42.842 + new TestInterfaceInheritanceD() {}
42.843 + };
42.844 +
42.845 + for (int i = 0; i < types.length; i++) {
42.846 + ic.add(types[i]);
42.847 + if (lookup.lookup(types[i].getClass()) == null) {
42.848 + // should find an instance
42.849 + fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
42.850 + }
42.851 + }
42.852 +
42.853 + int size1, size2;
42.854 +
42.855 + //interface query
42.856 + LL l = new LL ();
42.857 + Lookup.Result<?> res = lookup.lookupResult(java.rmi.Remote.class);
42.858 + l.source = res;
42.859 + size1 = res.allInstances().size();
42.860 + size2 = countInstances(types, java.rmi.Remote.class);
42.861 +
42.862 + if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
42.863 +
42.864 + // superclass query
42.865 + size1 = lookup.lookupAll(TestInterfaceInheritanceA.class).size();
42.866 + size2 = countInstances(types, TestInterfaceInheritanceA.class);
42.867 +
42.868 + if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
42.869 +
42.870 + res.addLookupListener (l);
42.871 + ic.remove (types[0]);
42.872 +
42.873 + if (l.getCount () != 1) {
42.874 + fail ("No notification that a Remote is removed");
42.875 + }
42.876 + }
42.877 +
42.878 + /** Checks whether the AbstractLookup is guarded against modifications
42.879 + * while doing some kind of modification.
42.880 + */
42.881 + public void testModificationArePreventedWhenDoingModifications () throws Exception {
42.882 + BrokenPair broken = new BrokenPair (true, false);
42.883 + ic.addPair (broken);
42.884 +
42.885 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
42.886 + Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
42.887 + assertEquals ("Broken is found", broken, item);
42.888 + }
42.889 +
42.890 + public void testModificationArePreventedWhenDoingModificationsResult () throws Exception {
42.891 + BrokenPair broken = new BrokenPair (false, true);
42.892 + ic.addPair (broken);
42.893 +
42.894 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
42.895 +
42.896 + Collection<? extends BrokenPair> c = lookup.lookup (templ).allInstances();
42.897 + assertEquals ("One item", 1, c.size ());
42.898 + assertEquals ("Broken is found again", broken, c.iterator().next ());
42.899 + }
42.900 +
42.901 + public void testModificationArePreventedWhenDoingModificationsItemAndResult () throws Exception {
42.902 + BrokenPair broken = new BrokenPair (false, true);
42.903 + ic.addPair (broken);
42.904 +
42.905 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
42.906 + Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
42.907 + assertEquals ("Broken is found", broken, item);
42.908 +
42.909 + Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
42.910 + assertEquals ("One item", 1, c.size ());
42.911 + assertEquals ("Broken is found again", broken, c.iterator().next ());
42.912 + }
42.913 +
42.914 + public void testModificationArePreventedWhenDoingModificationsResultAndItem () throws Exception {
42.915 + BrokenPair broken = new BrokenPair (false, true);
42.916 + ic.addPair (broken);
42.917 +
42.918 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
42.919 + Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
42.920 + assertEquals ("One item", 1, c.size ());
42.921 + assertEquals ("Broken is found again", broken, c.iterator().next ());
42.922 +
42.923 + Object item = lookup.lookupItem (templ);
42.924 + assertEquals ("Broken is found", broken, item);
42.925 + }
42.926 +
42.927 + public void testAddALotOfPairsIntoTheLookupOneByOne () throws Exception {
42.928 + Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
42.929 + for (int i = 0; i < 1000; i++) {
42.930 + ic.add(i);
42.931 + }
42.932 + assertEquals (
42.933 + "there is the right count",
42.934 + 1000,
42.935 + res.allItems().size ()
42.936 + );
42.937 + }
42.938 +
42.939 + public void testAddALotOfPairsIntoTheLookup () throws Exception {
42.940 + List<Integer> arr = new ArrayList<Integer>();
42.941 + for (int i = 0; i < 1000; i++) {
42.942 + arr.add(i);
42.943 + }
42.944 + ic.set (arr, null);
42.945 +
42.946 + assertEquals (
42.947 + "there is the right count",
42.948 + 1000,
42.949 + lookup.lookupResult(Integer.class).allItems().size()
42.950 + );
42.951 + }
42.952 +
42.953 +
42.954 + public void testDoubleAddIssue35274 () throws Exception {
42.955 + class P extends AbstractLookup.Pair<Object> {
42.956 + protected boolean creatorOf(Object obj) { return false; }
42.957 + public String getDisplayName() { return ""; }
42.958 + public String getId() { return ""; }
42.959 + public Object getInstance() { return null; }
42.960 + public Class<?> getType() { return Object.class; }
42.961 + protected boolean instanceOf(Class<?> c) { return c.isAssignableFrom(getType ()); }
42.962 + public @Override int hashCode() {return getClass().hashCode();}
42.963 + public @Override boolean equals(Object obj) {return getClass() == obj.getClass();}
42.964 + }
42.965 +
42.966 + P p = new P ();
42.967 +
42.968 + ic.addPair (p);
42.969 + ic.addPair (p);
42.970 +
42.971 + Lookup.Result<Object> result = lookup.lookupResult(Object.class);
42.972 + Collection res = result.allItems ();
42.973 + assertEquals ("One item there", 1, res.size ());
42.974 + assertTrue ("It is the p", p == res.iterator ().next ());
42.975 +
42.976 + P p2 = new P ();
42.977 + ic.addPair (p2);
42.978 +
42.979 + Reference<?> ref = new WeakReference<Object>(result);
42.980 + result = null;
42.981 + assertGC ("The result can disappear", ref);
42.982 +
42.983 + impl.clearCaches ();
42.984 +
42.985 + result = lookup.lookupResult(Object.class);
42.986 + res = result.allItems ();
42.987 + assertEquals ("One item is still there", 1, res.size ());
42.988 + assertTrue ("But the p2 replaced p", p2 == res.iterator ().next ());
42.989 +
42.990 + }
42.991 +
42.992 + /** Test for proper serialization.
42.993 + */
42.994 + public void testSerializationSupport () throws Exception {
42.995 + doSerializationSupport (1);
42.996 + }
42.997 + public void testDoubleSerializationSupport () throws Exception {
42.998 + doSerializationSupport (2);
42.999 + }
42.1000 +
42.1001 + private void doSerializationSupport (int count) throws Exception {
42.1002 + if (lookup instanceof Serializable) {
42.1003 + ic.addPair (new SerialPair ("1"));
42.1004 + ic.addPair (new SerialPair ("2"));
42.1005 + ic.addPair (new SerialPair ("3"));
42.1006 +
42.1007 + Lookup l = (Lookup)reserialize(lookup);
42.1008 +
42.1009 + assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
42.1010 +
42.1011 + assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
42.1012 +
42.1013 + while (count-- > 0) {
42.1014 + l = (Lookup)reserialize(l);
42.1015 + }
42.1016 +
42.1017 + assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
42.1018 +
42.1019 + assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
42.1020 + }
42.1021 + }
42.1022 +
42.1023 + /** When a lookup with two different versions of the same class
42.1024 + * get's serialized, the results may be very bad.
42.1025 + */
42.1026 + public void testSerializationOfTwoClassesWithTheSameName () throws Exception {
42.1027 + if (lookup instanceof Serializable) {
42.1028 + doTwoSerializedClasses (false, false);
42.1029 + }
42.1030 + }
42.1031 + public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSave () throws Exception {
42.1032 + if (lookup instanceof Serializable) {
42.1033 + doTwoSerializedClasses (true, false);
42.1034 + }
42.1035 + }
42.1036 + public void testSerializationOfTwoClassesWithTheSameNameWithBroken () throws Exception {
42.1037 + if (lookup instanceof Serializable) {
42.1038 + doTwoSerializedClasses (false, true);
42.1039 + }
42.1040 + }
42.1041 + public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSaveWithBroken () throws Exception {
42.1042 + if (lookup instanceof Serializable) {
42.1043 + doTwoSerializedClasses (true, true);
42.1044 + }
42.1045 + }
42.1046 +
42.1047 + private void doTwoSerializedClasses (boolean queryBeforeSerialization, boolean useBroken) throws Exception {
42.1048 + ClassLoader loader = new CL ();
42.1049 + Class c = loader.loadClass (Garbage.class.getName ());
42.1050 +
42.1051 + // in case of InheritanceTree it creates a slot for class Garbage
42.1052 + lookup.lookup(c);
42.1053 +
42.1054 + // but creates new instance and adds it into the lookup
42.1055 + // without querying for it
42.1056 + loader = new CL ();
42.1057 + c = loader.loadClass (Garbage.class.getName ());
42.1058 +
42.1059 + Object theInstance = c.newInstance ();
42.1060 +
42.1061 + ic.addPair (new SerialPair (theInstance));
42.1062 +
42.1063 + Broken2Pair broken = null;
42.1064 + if (useBroken) {
42.1065 + broken = new Broken2Pair ();
42.1066 + ic.addPair (broken);
42.1067 +
42.1068 + assertNull (
42.1069 + "We need to create the slot for the List as " +
42.1070 + "the Broken2Pair will ask for it after deserialization",
42.1071 + lookup.lookup (java.awt.List.class)
42.1072 + );
42.1073 + }
42.1074 +
42.1075 + if (queryBeforeSerialization) {
42.1076 + assertEquals ("Instance is found", theInstance, lookup.lookup (c));
42.1077 + }
42.1078 +
42.1079 + // replace the old lookup with new one
42.1080 + lookup = (Lookup)reserialize(lookup);
42.1081 +
42.1082 + Lookup.Result result = lookup.lookup (new Lookup.Template (Garbage.class));
42.1083 + assertEquals ("One item is the result", 1, result.allInstances ().size ());
42.1084 + Object r = result.allInstances ().iterator ().next ();
42.1085 + assertNotNull("A value is found", r);
42.1086 + assertEquals ("It is of the right class", Garbage.class, r.getClass());
42.1087 + }
42.1088 +
42.1089 + /** Test of reorder and item change which used to fail on interfaces.
42.1090 + */
42.1091 + public void testReoderingIssue13779 () throws Exception {
42.1092 + LinkedList arr = new LinkedList ();
42.1093 +
42.1094 + class R extends Exception implements Cloneable {
42.1095 + }
42.1096 + Object o1 = new R ();
42.1097 + Object o2 = new R ();
42.1098 + Object o3 = new R ();
42.1099 +
42.1100 + arr.add (o1);
42.1101 + arr.add (o2);
42.1102 +
42.1103 + ic.set (arr, null);
42.1104 +
42.1105 + Lookup.Result objectResult = lookup.lookup (new Lookup.Template (Exception.class));
42.1106 + Lookup.Result interfaceResult = lookup.lookup (new Lookup.Template (Cloneable.class));
42.1107 + objectResult.allItems ();
42.1108 + interfaceResult.allItems ();
42.1109 +
42.1110 + LL l1 = new LL (objectResult);
42.1111 + LL l2 = new LL (interfaceResult);
42.1112 +
42.1113 + objectResult.addLookupListener(l1);
42.1114 + interfaceResult.addLookupListener(l2);
42.1115 +
42.1116 + arr.addFirst (o3);
42.1117 +
42.1118 + ic.set (arr, null);
42.1119 +
42.1120 + assertEquals ("One change on objects", 1, l1.getCount ());
42.1121 + assertEquals ("One change on interfaces", 1, l2.getCount ());
42.1122 +
42.1123 + arr.addFirst (new Cloneable () { });
42.1124 + ic.set (arr, null);
42.1125 +
42.1126 + assertEquals ("No change on objects", 0, l1.getCount ());
42.1127 + assertEquals ("But one change on interfaces", 1, l2.getCount ());
42.1128 +
42.1129 + }
42.1130 +
42.1131 + public void testDeadlockBetweenProxyResultAndLookupIssue47772 () throws Exception {
42.1132 + final String myModule = "My Module";
42.1133 + ic.add (myModule);
42.1134 +
42.1135 + class MyProxy extends ProxyLookup {
42.1136 + public MyProxy () {
42.1137 + super (new Lookup[] { lookup });
42.1138 + }
42.1139 + }
42.1140 + final MyProxy my = new MyProxy ();
42.1141 +
42.1142 + final Lookup.Result allModules = my.lookup (new Lookup.Template (String.class));
42.1143 +
42.1144 + class PairThatNeedsInfoAboutModules extends AbstractLookup.Pair {
42.1145 + public String getDisplayName () {
42.1146 + return "Need a module";
42.1147 + }
42.1148 + public String getId () {
42.1149 + return getDisplayName ();
42.1150 + }
42.1151 + public Class getType () {
42.1152 + return Integer.class;
42.1153 + }
42.1154 + protected boolean instanceOf (Class c) {
42.1155 + if (c == Integer.class) {
42.1156 + synchronized (this) {
42.1157 + notifyAll ();
42.1158 + try {
42.1159 + wait (1000);
42.1160 + } catch (InterruptedException ex) {
42.1161 + fail (ex.getMessage ());
42.1162 + }
42.1163 + }
42.1164 + java.util.Collection coll = allModules.allInstances ();
42.1165 + assertEquals ("Size is 1", 1, coll.size ());
42.1166 + assertEquals ("My module is there", myModule, coll.iterator ().next ());
42.1167 + }
42.1168 + return c.isAssignableFrom (Integer.class);
42.1169 + }
42.1170 +
42.1171 + public Object getInstance () {
42.1172 + return new Integer (10);
42.1173 + }
42.1174 +
42.1175 + protected boolean creatorOf (Object obj) {
42.1176 + return new Integer (10).equals (obj);
42.1177 + }
42.1178 + }
42.1179 +
42.1180 + PairThatNeedsInfoAboutModules pair = new PairThatNeedsInfoAboutModules ();
42.1181 + ic.addPair (pair);
42.1182 +
42.1183 + synchronized (pair) {
42.1184 + class BlockInInstanceOf implements Runnable {
42.1185 + public void run () {
42.1186 + Integer i = my.lookup(Integer.class);
42.1187 + assertEquals (new Integer (10), i);
42.1188 + }
42.1189 + }
42.1190 + BlockInInstanceOf blk = new BlockInInstanceOf ();
42.1191 + Executors.newSingleThreadScheduledExecutor().schedule(blk, 0, TimeUnit.MICROSECONDS);
42.1192 + pair.wait ();
42.1193 + }
42.1194 +
42.1195 + java.util.Collection coll = allModules.allInstances ();
42.1196 + assertEquals ("Size is 1", 1, coll.size ());
42.1197 + assertEquals ("My module is there", myModule, coll.iterator ().next ());
42.1198 + }
42.1199 +
42.1200 + public void testAWayToGenerateProblem13779 () {
42.1201 + ic.add (new Integer (1));
42.1202 + ic.add (new Integer (2));
42.1203 + ic.add (new Integer (1));
42.1204 + ic.add (new Integer (2));
42.1205 +
42.1206 + Collection c = lookup.lookup (new Lookup.Template (Integer.class)).allInstances ();
42.1207 + assertEquals ("There are two objects", 2, c.size ());
42.1208 +
42.1209 + }
42.1210 +
42.1211 + /** Replacing items with different objects.
42.1212 + */
42.1213 + public void testReplacingObjectsDoesNotGenerateException () throws Exception {
42.1214 + LinkedList arr = new LinkedList ();
42.1215 +
42.1216 + class R extends Exception implements Cloneable {
42.1217 + }
42.1218 + arr.add (new R ());
42.1219 + arr.add (new R ());
42.1220 +
42.1221 + ic.set (arr, null);
42.1222 +
42.1223 + arr.clear();
42.1224 +
42.1225 + arr.add (new R ());
42.1226 + arr.add (new R ());
42.1227 +
42.1228 + ic.set (arr, null);
42.1229 + }
42.1230 +
42.1231 + public void testAfterDeserializationNoQueryIsPeformedOnAlreadyQueriedObjects() throws Exception {
42.1232 + if (! (lookup instanceof Serializable)) {
42.1233 + // well this test works only for serializable lookups
42.1234 + return;
42.1235 + }
42.1236 +
42.1237 + SerialPair my = new SerialPair ("no");
42.1238 + ic.addPair (my);
42.1239 +
42.1240 + Lookup.Result res = lookup.lookup (new Lookup.Template (String.class));
42.1241 + assertEquals ("One instance", 1, res.allInstances().size ());
42.1242 + assertEquals ("my.instanceOf called once", 1, my.countInstanceOf);
42.1243 +
42.1244 + Lookup serial = (Lookup)reserialize(lookup);
42.1245 +
42.1246 + Lookup.Result r2 = serial.lookup(new Lookup.Template(String.class));
42.1247 +
42.1248 + assertEquals ("One item", 1, r2.allItems ().size ());
42.1249 + Object one = r2.allItems().iterator().next ();
42.1250 + assertEquals ("The right class", SerialPair.class, one.getClass());
42.1251 + SerialPair p = (SerialPair)one;
42.1252 +
42.1253 + assertEquals ("p.instanceOf has not been queried", 0, p.countInstanceOf);
42.1254 + }
42.1255 +
42.1256 + /** Checks the iterator */
42.1257 + private <T> void checkIterator(String msg, Iterator<? extends T> it1, List<? extends T> list) {
42.1258 + int cnt = 0;
42.1259 + Iterator<? extends T> it2 = list.iterator();
42.1260 + while (it1.hasNext () && it2.hasNext ()) {
42.1261 + T n1 = it1.next();
42.1262 + T n2 = it2.next();
42.1263 +
42.1264 + if (n1 != n2) {
42.1265 + fail (msg + " iterator[" + cnt + "] = " + n1 + " but list[" + cnt + "] = " + n2);
42.1266 + }
42.1267 +
42.1268 + cnt++;
42.1269 + }
42.1270 +
42.1271 + if (it1.hasNext ()) {
42.1272 + fail ("Iterator has more elements than list");
42.1273 + }
42.1274 +
42.1275 + if (it2.hasNext ()) {
42.1276 + fail ("List has more elements than iterator");
42.1277 + }
42.1278 + }
42.1279 +
42.1280 +
42.1281 + public void testResultsAreUnmodifyableOrAtLeastTheyDoNotPropagateToCache() throws Exception {
42.1282 + String s = "Ahoj";
42.1283 +
42.1284 + ic.add(s);
42.1285 +
42.1286 + Lookup.Result res = lookup.lookup(new Template(String.class));
42.1287 +
42.1288 + for (int i = 1; i < 5; i++) {
42.1289 + Collection c1 = res.allInstances();
42.1290 + Collection c2 = res.allClasses();
42.1291 + Collection c3 = res.allItems();
42.1292 +
42.1293 + assertTrue(i + ": c1 has it", c1.contains(s));
42.1294 + assertTrue(i + ": c2 has it", c2.contains(s.getClass()));
42.1295 + assertEquals(i + ": c3 has one", 1, c3.size());
42.1296 + Lookup.Item item = (Lookup.Item) c3.iterator().next();
42.1297 + assertEquals(i + ": c3 has it", s, item.getInstance());
42.1298 +
42.1299 + try {
42.1300 + c1.remove(s);
42.1301 + assertEquals("No elements now", 0, c1.size());
42.1302 + } catch (UnsupportedOperationException ex) {
42.1303 + // ok, this need not be supported
42.1304 + }
42.1305 + try {
42.1306 + c2.remove(s.getClass());
42.1307 + assertEquals("No elements now", 0, c2.size());
42.1308 + } catch (UnsupportedOperationException ex) {
42.1309 + // ok, this need not be supported
42.1310 + }
42.1311 + try {
42.1312 + c3.remove(item);
42.1313 + assertEquals("No elements now", 0, c3.size());
42.1314 + } catch (UnsupportedOperationException ex) {
42.1315 + // ok, this need not be supported
42.1316 + }
42.1317 + }
42.1318 + }
42.1319 +
42.1320 + public void testSomeProblemWithDVBFrameworkSeemsToBeInLookup() {
42.1321 + for (int i = 0; i < 5; i++) {
42.1322 + ic.add(lookup);
42.1323 + assertEquals("Can be found", lookup, lookup.lookup(lookup.getClass()));
42.1324 + ic.set(Collections.EMPTY_LIST, null);
42.1325 + }
42.1326 + }
42.1327 +
42.1328 + public void testListeningAndQueryingByTwoListenersInstances() {
42.1329 + doListeningAndQueryingByTwoListeners(0);
42.1330 + }
42.1331 + public void testListeningAndQueryingByTwoListenersClasses() {
42.1332 + doListeningAndQueryingByTwoListeners(1);
42.1333 + }
42.1334 + public void testListeningAndQueryingByTwoListenersItems() {
42.1335 + doListeningAndQueryingByTwoListeners(2);
42.1336 + }
42.1337 +
42.1338 +
42.1339 + private void doListeningAndQueryingByTwoListeners(final int type) {
42.1340 + class L implements LookupListener {
42.1341 + Lookup.Result integer = lookup.lookup(new Template(Integer.class));
42.1342 + Lookup.Result number = lookup.lookup(new Template(Number.class));
42.1343 + Lookup.Result serial = lookup.lookup(new Template(Serializable.class));
42.1344 +
42.1345 + {
42.1346 + integer.addLookupListener(this);
42.1347 + number.addLookupListener(this);
42.1348 + serial.addLookupListener(this);
42.1349 + }
42.1350 +
42.1351 + int round;
42.1352 +
42.1353 + public void resultChanged(LookupEvent ev) {
42.1354 + Collection c1 = get(type, integer);
42.1355 + Collection c2 = get(type, number);
42.1356 + Collection c3 = get(type, serial);
42.1357 +
42.1358 + assertEquals("round " + round + " c1 vs. c2", c1, c2);
42.1359 + assertEquals("round " + round + " c1 vs. c3", c1, c3);
42.1360 + assertEquals("round " + round + " c2 vs. c3", c2, c3);
42.1361 +
42.1362 + round++;
42.1363 + }
42.1364 +
42.1365 + private Collection get(int type, Lookup.Result res) {
42.1366 + Collection c;
42.1367 + switch(type) {
42.1368 + case 0: c = res.allInstances(); break;
42.1369 + case 1: c = res.allClasses(); break;
42.1370 + case 2: c = res.allItems(); break;
42.1371 + default: c = null; fail("Type: " + type); break;
42.1372 + }
42.1373 +
42.1374 + assertNotNull(c);
42.1375 + return new ArrayList(c);
42.1376 + }
42.1377 + }
42.1378 +
42.1379 + L listener = new L();
42.1380 + listener.resultChanged(null);
42.1381 +
42.1382 + for(int i = 0; i < 100; i++) {
42.1383 + ic.add(new Integer(i));
42.1384 + }
42.1385 +
42.1386 + assertEquals("3x100+1 checks", 301, listener.round);
42.1387 + }
42.1388 +
42.1389 + public void testChangeOfNodeDoesNotFireChangeInActionMap() {
42.1390 + ActionMap am = new ActionMap();
42.1391 + Lookup s = Lookups.singleton(am);
42.1392 + doChangeOfNodeDoesNotFireChangeInActionMap(am, s, false);
42.1393 + }
42.1394 + public void testChangeOfNodeDoesNotFireChangeInActionMapSimple() {
42.1395 + ActionMap am = new ActionMap();
42.1396 + Lookup s = Lookups.singleton(am);
42.1397 + doChangeOfNodeDoesNotFireChangeInActionMap(am, s, true);
42.1398 + }
42.1399 +
42.1400 + public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookupSimple() {
42.1401 + doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(true);
42.1402 + }
42.1403 +
42.1404 + public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup() {
42.1405 + doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(false);
42.1406 + }
42.1407 + private void doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(boolean wrapBySimple) {
42.1408 + final ActionMap am = new ActionMap();
42.1409 +
42.1410 + class Before extends AbstractLookup {
42.1411 + public InstanceContent ic;
42.1412 + public Before() {
42.1413 + this(new InstanceContent());
42.1414 + }
42.1415 +
42.1416 + private Before(InstanceContent ic) {
42.1417 + super(ic);
42.1418 + this.ic = ic;
42.1419 + }
42.1420 +
42.1421 + protected @Override void beforeLookup(Template template) {
42.1422 + if (ic != null) {
42.1423 + ic.add(am);
42.1424 + ic = null;
42.1425 + }
42.1426 + }
42.1427 + }
42.1428 +
42.1429 + Before s = new Before();
42.1430 + doChangeOfNodeDoesNotFireChangeInActionMap(am, s, wrapBySimple);
42.1431 +
42.1432 + assertNull("beforeLookup called once", s.ic);
42.1433 + }
42.1434 +
42.1435 + private void doChangeOfNodeDoesNotFireChangeInActionMap(final ActionMap am, Lookup actionMapLookup, final boolean wrapBySimple) {
42.1436 + Lookup[] lookups = { lookup, actionMapLookup };
42.1437 +
42.1438 + class Provider implements Lookup.Provider {
42.1439 + ProxyLookup delegate;
42.1440 + Lookup query;
42.1441 +
42.1442 + public Provider(Lookup[] arr) {
42.1443 + if (wrapBySimple) {
42.1444 + delegate = new ProxyLookup(arr);
42.1445 + query = Lookups.proxy(this);
42.1446 + } else {
42.1447 + query = delegate = new ProxyLookup(arr);
42.1448 + }
42.1449 + }
42.1450 +
42.1451 + public Lookup getLookup() {
42.1452 + return delegate;
42.1453 + }
42.1454 +
42.1455 + public void setLookups(Lookup... arr) {
42.1456 + if (wrapBySimple) {
42.1457 + delegate = new ProxyLookup(arr);
42.1458 + } else {
42.1459 + delegate.setLookups(arr);
42.1460 + }
42.1461 + }
42.1462 + }
42.1463 +
42.1464 + Provider p = new Provider(lookups);
42.1465 +
42.1466 + Lookup.Result res = p.query.lookup(new Lookup.Template(ActionMap.class));
42.1467 + LL ll = new LL();
42.1468 + res.addLookupListener(ll);
42.1469 +
42.1470 + Collection c = res.allInstances();
42.1471 + assertFalse("Has next", c.isEmpty());
42.1472 +
42.1473 + ActionMap am1 = (ActionMap)c.iterator().next();
42.1474 + assertEquals("Am is there", am, am1);
42.1475 +
42.1476 + assertEquals("No change in first get", 0, ll.getCount());
42.1477 +
42.1478 + Object m1 = new InputMap();
42.1479 + Object m2 = new InputMap();
42.1480 +
42.1481 + ic.add(m1);
42.1482 + assertEquals("No change in ActionMap 1", 0, ll.getCount());
42.1483 + ic.set(Collections.singletonList(m2), null);
42.1484 + assertEquals("No change in ActionMap 2", 0, ll.getCount());
42.1485 + ic.add(m2);
42.1486 + assertEquals("No change in ActionMap 3", 0, ll.getCount());
42.1487 + p.setLookups(lookup, actionMapLookup, Lookup.EMPTY);
42.1488 + assertEquals("No change in ActionMap 4", 0, ll.getCount());
42.1489 +
42.1490 + ActionMap am2 = p.query.lookup(ActionMap.class);
42.1491 + assertEquals("Still the same action map", am, am2);
42.1492 +
42.1493 +
42.1494 + class Before extends AbstractLookup {
42.1495 + public InstanceContent ic;
42.1496 + public Before() {
42.1497 + this(new InstanceContent());
42.1498 + }
42.1499 +
42.1500 + private Before(InstanceContent ic) {
42.1501 + super(ic);
42.1502 + this.ic = ic;
42.1503 + }
42.1504 +
42.1505 + protected @Override void beforeLookup(Template template) {
42.1506 + if (ic != null) {
42.1507 + ic.add(am);
42.1508 + ic = null;
42.1509 + }
42.1510 + }
42.1511 + }
42.1512 +
42.1513 + Before s = new Before();
42.1514 +
42.1515 + // adding different Before, but returning the same instance
42.1516 + // this happens with metaInfServices lookup often, moreover
42.1517 + // it adds the instance in beforeLookup, which confuses a lot
42.1518 + p.setLookups(new Lookup[]{ lookup, new Before() });
42.1519 + assertEquals("No change in ActionMap 5", 0, ll.getCount());
42.1520 +
42.1521 +
42.1522 + }
42.1523 +
42.1524 + public void testTasklistsCase() throws Exception {
42.1525 + ic.remove(new Object());
42.1526 + }
42.1527 +
42.1528 +
42.1529 +
42.1530 + public void testMultipleListeners() {
42.1531 + Object object = new ImplementationObject();
42.1532 + ic.add(object);
42.1533 +
42.1534 + Listener[] listeners = new Listener[4];
42.1535 + Lookup.Result result = lookup.lookup(new Lookup.Template(LookupObject.class));
42.1536 + for(int i = 0; i < listeners.length; ++i) {
42.1537 + listeners[i] = new Listener();
42.1538 + result.addLookupListener(listeners[i]);
42.1539 + }
42.1540 + // initialize listening
42.1541 + result.allItems();
42.1542 +
42.1543 + ic.remove(object);
42.1544 +
42.1545 + // Apparently, only odd-numbered listeners get called when there are multiple LookupListeners on a result
42.1546 + //for(int i = 0; i < listeners.length; ++i) {
42.1547 + // System.out.println("Listener " + i + ": " + listeners[i].wasCalled());
42.1548 + //}
42.1549 + for(int i = 0; i < listeners.length; ++i) {
42.1550 + assertTrue("Listener " + i + " called", listeners[i].wasCalled());
42.1551 + }
42.1552 + }
42.1553 +
42.1554 + static Object reserialize(Object o) throws Exception {
42.1555 + ByteArrayOutputStream os = new ByteArrayOutputStream();
42.1556 + ObjectOutputStream oos = new ObjectOutputStream(os);
42.1557 + oos.writeObject(o);
42.1558 + oos.close();
42.1559 +
42.1560 + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
42.1561 + ObjectInputStream ois = new ObjectInputStream(is);
42.1562 + return ois.readObject();
42.1563 + }
42.1564 +
42.1565 + private class Listener implements LookupListener {
42.1566 + private boolean listenerCalled = false;
42.1567 +
42.1568 + public void resultChanged(LookupEvent ev) {
42.1569 + listenerCalled = true;
42.1570 + }
42.1571 +
42.1572 + public boolean wasCalled() {
42.1573 + return listenerCalled;
42.1574 + }
42.1575 +
42.1576 + public void reset() {
42.1577 + listenerCalled = false;
42.1578 + }
42.1579 + }
42.1580 +
42.1581 + private interface LookupObject {}
42.1582 + private class ImplementationObject implements LookupObject {}
42.1583 + private class NullObject implements LookupObject {}
42.1584 +
42.1585 +
42.1586 + public void testReturnSomethingElseThenYouClaimYouWillReturn() {
42.1587 + class Liar extends AbstractLookup.Pair {
42.1588 + public Object obj;
42.1589 +
42.1590 + protected boolean instanceOf(Class c) {
42.1591 + return c.isAssignableFrom(String.class);
42.1592 + }
42.1593 +
42.1594 + protected boolean creatorOf(Object obj) {
42.1595 + return this.obj == obj;
42.1596 + }
42.1597 +
42.1598 + public Object getInstance() {
42.1599 + return this.obj;
42.1600 + }
42.1601 +
42.1602 + public Class getType() {
42.1603 + return String.class;
42.1604 + }
42.1605 +
42.1606 + public String getId() {
42.1607 + return String.class.getName();
42.1608 + }
42.1609 +
42.1610 + public String getDisplayName() {
42.1611 + return getId();
42.1612 + }
42.1613 + }
42.1614 +
42.1615 +
42.1616 + Liar l = new Liar();
42.1617 + l.obj = new Integer(5);
42.1618 +
42.1619 + this.ic.addPair(l);
42.1620 +
42.1621 + Collection c = lookup.lookup(new Lookup.Template(String.class)).allInstances();
42.1622 + assertTrue("It is empty: " + c, c.isEmpty());
42.1623 + }
42.1624 +
42.1625 + public void testCanProxyLookupHaveWrongResults() {
42.1626 + class L implements LookupListener {
42.1627 + ProxyLookup pl;
42.1628 + Lookup.Result<String> original;
42.1629 + Lookup.Result<String> wrapped;
42.1630 + boolean ok;
42.1631 +
42.1632 + public void test() {
42.1633 + pl = new ProxyLookup(lookup);
42.1634 + original = lookup.lookupResult(String.class);
42.1635 +
42.1636 + original.addLookupListener(this);
42.1637 +
42.1638 + wrapped = pl.lookupResult(String.class);
42.1639 +
42.1640 + assertEquals("Original empty", 0, original.allInstances().size());
42.1641 + assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
42.1642 +
42.1643 + ic.add("Hello!");
42.1644 + }
42.1645 +
42.1646 + public void resultChanged(LookupEvent ev) {
42.1647 + ok = true;
42.1648 +
42.1649 + assertEquals("Original has hello", 1, original.allInstances().size());
42.1650 + assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
42.1651 + }
42.1652 +
42.1653 + }
42.1654 + L listener = new L();
42.1655 + listener.test();
42.1656 + assertTrue("Listener called", listener.ok);
42.1657 + }
42.1658 +
42.1659 + public void testObjectFromInstanceContentConverterDisappearsIfNotReferenced() {
42.1660 + Conv converter = new Conv("foo");
42.1661 + ic.add (converter, converter);
42.1662 + Lookup lkp = instanceLookup;
42.1663 + StringBuilder sb = lookup.lookup (StringBuilder.class);
42.1664 + assertNotNull (sb);
42.1665 + int hash = System.identityHashCode(sb);
42.1666 + assertEquals ("foo", sb.toString());
42.1667 + Reference<StringBuilder> r = new WeakReference<StringBuilder>(sb);
42.1668 + sb = null;
42.1669 + assertGC("Lookup held onto object", r);
42.1670 + sb = lookup.lookup (StringBuilder.class);
42.1671 + assertNotSame(hash, System.identityHashCode(sb));
42.1672 + r = new WeakReference<StringBuilder>(sb);
42.1673 + sb = null;
42.1674 + assertGC("Lookup held onto object", r);
42.1675 + ic.remove (converter, converter);
42.1676 + Reference <InstanceContent.Convertor> cref = new WeakReference<InstanceContent.Convertor>(converter);
42.1677 + converter = null;
42.1678 + assertGC("Converter still referenced", cref);
42.1679 +
42.1680 + sb = lkp.lookup(StringBuilder.class);
42.1681 + assertNull ("Converter removed from lookup, but object it " +
42.1682 + "created still present:'" + sb +"'", sb);
42.1683 + converter = new Conv("bar");
42.1684 + ic.add (converter, converter);
42.1685 + assertNotNull (lkp.lookup(StringBuilder.class));
42.1686 + assertEquals ("bar", lkp.lookup(StringBuilder.class).toString());
42.1687 + }
42.1688 +
42.1689 + private static class Conv implements InstanceContent.Convertor<Conv, StringBuilder> {
42.1690 + private final String str;
42.1691 + private Conv (String str) {
42.1692 + this.str = str;
42.1693 + }
42.1694 +
42.1695 + public StringBuilder convert(Conv obj) {
42.1696 + return new StringBuilder (str);
42.1697 + }
42.1698 +
42.1699 + public Class<? extends StringBuilder> type(Conv obj) {
42.1700 + return StringBuilder.class;
42.1701 + }
42.1702 +
42.1703 + public String id(Conv obj) {
42.1704 + return "Foo";
42.1705 + }
42.1706 +
42.1707 + public String displayName(Conv obj) {
42.1708 + return "Foo";
42.1709 + }
42.1710 + } // end of Conv
42.1711 +
42.1712 + public void testCanGCResults() throws Exception {
42.1713 + class L implements LookupListener {
42.1714 + int cnt;
42.1715 +
42.1716 + public void resultChanged(LookupEvent ev) {
42.1717 + cnt++;
42.1718 + }
42.1719 +
42.1720 + }
42.1721 + L listener1 = new L();
42.1722 + L listener2 = new L();
42.1723 +
42.1724 + Lookup.Result<String> res1 = this.instanceLookup.lookupResult(String.class);
42.1725 + Lookup.Result<String> res2 = this.lookup.lookupResult(String.class);
42.1726 +
42.1727 + assertEquals("Empty1", 0, res1.allItems().size());
42.1728 + assertEquals("Empty2", 0, res2.allItems().size());
42.1729 +
42.1730 + res1.addLookupListener(listener1);
42.1731 + res2.addLookupListener(listener2);
42.1732 +
42.1733 + addInstances(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
42.1734 + this.ic.add("Ahoj");
42.1735 +
42.1736 + assertEquals("Change1", 1, listener1.cnt);
42.1737 + assertEquals("Change2", 1, listener2.cnt);
42.1738 +
42.1739 + assertEquals("Full1", 1, res1.allItems().size());
42.1740 + assertEquals("Full2", 1, res2.allItems().size());
42.1741 +
42.1742 +
42.1743 + Reference<Object> ref2 = new WeakReference<Object>(res2);
42.1744 + res2 = null;
42.1745 + assertGC("Result can disappear", ref2);
42.1746 + }
42.1747 +
42.1748 + void beforeActualTest(String n) {
42.1749 + if (n.equals("testEqualsIsNotCalledTooMuch")) {
42.1750 + CntPair.cnt = 0;
42.1751 + CntPair.hashCnt = 0;
42.1752 + CntPair.instances = 0;
42.1753 + int how = 1000;
42.1754 +
42.1755 + for(int i = 0; i < how; i++) {
42.1756 + this.ic.addPair(new CntPair("x" + i));
42.1757 + }
42.1758 +
42.1759 + assertEquals("No equals called", 0, CntPair.cnt);
42.1760 + assertEquals("1000 instances ", how, CntPair.instances);
42.1761 + }
42.1762 + }
42.1763 +
42.1764 + public void testEqualsIsNotCalledTooMuch() throws Exception {
42.1765 + // most of the work done in beforeActualTest
42.1766 +
42.1767 + // desirable: assertEquals("no comparitions", 0, CntPair.cnt);
42.1768 + // works for InheritanceTree, but not for ArrayStorage, but array
42.1769 + // storages are generally small
42.1770 +
42.1771 + if (CntPair.cnt > 12000) {
42.1772 + fail("Too much comparitions " + CntPair.cnt);
42.1773 + }
42.1774 + if (CntPair.hashCnt > 40000) {
42.1775 + fail("Too much hashes: " + CntPair.hashCnt);
42.1776 + }
42.1777 +
42.1778 + assertEquals("instaces is enough", 1000, CntPair.instances);
42.1779 + }
42.1780 +
42.1781 + /** Adds instances to the instance lookup.
42.1782 + */
42.1783 + private void addInstances (Object... instances) {
42.1784 + for (int i = 0; i < instances.length; i++) {
42.1785 + ic.add(instances[i]);
42.1786 + }
42.1787 + }
42.1788 +
42.1789 + /** Count instances of clazz in an array. */
42.1790 + private int countInstances (Object[] objs, Class clazz) {
42.1791 + int count = 0;
42.1792 + for (int i = 0; i < objs.length; i++) {
42.1793 + if (clazz.isInstance(objs[i])) count++;
42.1794 + }
42.1795 + return count;
42.1796 + }
42.1797 +
42.1798 + /** Counting listener */
42.1799 + protected static class LL implements LookupListener {
42.1800 + private int count = 0;
42.1801 + public Object source;
42.1802 + public Thread changesIn;
42.1803 +
42.1804 + public LL () {
42.1805 + this (null);
42.1806 + }
42.1807 +
42.1808 + public LL (Object source) {
42.1809 + this.source = source;
42.1810 + }
42.1811 +
42.1812 + public void resultChanged(LookupEvent ev) {
42.1813 + if (changesIn != null) {
42.1814 + assertEquals("Changes in the same thread", changesIn, Thread.currentThread());
42.1815 + } else {
42.1816 + changesIn = Thread.currentThread();
42.1817 + }
42.1818 + ++count;
42.1819 + if (source != null) {
42.1820 + assertSame ("Source is the same", source, ev.getSource ());
42.1821 +// assertSame ("Result is the same", source, ev.getResult ());
42.1822 + }
42.1823 + }
42.1824 +
42.1825 + public int getCount() {
42.1826 + int i = count;
42.1827 + count = 0;
42.1828 + return i;
42.1829 + }
42.1830 + };
42.1831 +
42.1832 + /** A set of interfaces for testInterfaceInheritance
42.1833 + */
42.1834 + interface TestInterfaceInheritanceA {}
42.1835 + interface TestInterfaceInheritanceB extends TestInterfaceInheritanceA, java.rmi.Remote {}
42.1836 + interface TestInterfaceInheritanceBB extends TestInterfaceInheritanceB {}
42.1837 + interface TestInterfaceInheritanceC extends TestInterfaceInheritanceA, java.rmi.Remote {}
42.1838 + interface TestInterfaceInheritanceD extends TestInterfaceInheritanceA {}
42.1839 +
42.1840 + /** A special class for garbage test */
42.1841 + public static final class Garbage extends Object implements Serializable {
42.1842 + static final long serialVersionUID = 435340912534L;
42.1843 + }
42.1844 +
42.1845 +
42.1846 + /* A classloader that can load one class in a special way */
42.1847 + private static class CL extends ClassLoader {
42.1848 + public CL () {
42.1849 + super (null);
42.1850 + }
42.1851 +
42.1852 + public @Override Class findClass(String name) throws ClassNotFoundException {
42.1853 + if (name.equals (Garbage.class.getName ())) {
42.1854 + String n = name.replace ('.', '/');
42.1855 + java.io.InputStream is = getClass ().getResourceAsStream ("/" + n + ".class");
42.1856 + byte[] arr = new byte[8096];
42.1857 + try {
42.1858 + int cnt = is.read (arr);
42.1859 + if (cnt == arr.length) {
42.1860 + fail ("Buffer to load the class is not big enough");
42.1861 + }
42.1862 +
42.1863 + return defineClass (name, arr, 0, cnt);
42.1864 + } catch (java.io.IOException ex) {
42.1865 + ex.printStackTrace();
42.1866 + fail ("IO Exception");
42.1867 + return null;
42.1868 + }
42.1869 + } else {
42.1870 + return null;
42.1871 + }
42.1872 + }
42.1873 +
42.1874 + /** Convert obj to other object. There is no need to implement
42.1875 + * cache mechanism. It is provided by AbstractLookup.Item.getInstance().
42.1876 + * Method should be called more than once because Lookup holds
42.1877 + * just weak reference.
42.1878 + */
42.1879 + public Object convert(Object obj) {
42.1880 + return null;
42.1881 + }
42.1882 +
42.1883 + /** Return type of converted object. */
42.1884 + public Class type(Object obj) {
42.1885 + try {
42.1886 + return loadClass (Garbage.class.getName ());
42.1887 + } catch (ClassNotFoundException ex) {
42.1888 + fail ("Class not found");
42.1889 + throw new InternalError ();
42.1890 + }
42.1891 + }
42.1892 + }
42.1893 +
42.1894 + private static final class CntPair extends AbstractLookup.Pair {
42.1895 + private static int instances;
42.1896 + private String txt;
42.1897 +
42.1898 + public CntPair(String txt) {
42.1899 + this.txt = txt;
42.1900 + instances++;
42.1901 + }
42.1902 +
42.1903 + public static int hashCnt;
42.1904 + @Override
42.1905 + public int hashCode() {
42.1906 + hashCnt++;
42.1907 + return txt.hashCode() + 3777;
42.1908 + }
42.1909 +
42.1910 + public static int cnt;
42.1911 + @Override
42.1912 + public boolean equals(Object obj) {
42.1913 + cnt++;
42.1914 +
42.1915 + if (obj == null) {
42.1916 + return false;
42.1917 + }
42.1918 + if (getClass() != obj.getClass()) {
42.1919 + return false;
42.1920 + }
42.1921 + final CntPair other = (CntPair) obj;
42.1922 + if (this.txt != other.txt && (this.txt == null || !this.txt.equals(other.txt))) {
42.1923 + return false;
42.1924 + }
42.1925 + return true;
42.1926 + }
42.1927 +
42.1928 + protected boolean instanceOf(Class c) {
42.1929 + return c.isAssignableFrom(String.class);
42.1930 + }
42.1931 +
42.1932 + protected boolean creatorOf(Object obj) {
42.1933 + return obj == txt;
42.1934 + }
42.1935 +
42.1936 + public Object getInstance() {
42.1937 + return txt;
42.1938 + }
42.1939 +
42.1940 + public Class getType() {
42.1941 + return String.class;
42.1942 + }
42.1943 +
42.1944 + public String getId() {
42.1945 + return txt;
42.1946 + }
42.1947 +
42.1948 + public String getDisplayName() {
42.1949 + return txt;
42.1950 + }
42.1951 +
42.1952 + }
42.1953 +
42.1954 + public static final class SerialPair extends AbstractLookup.Pair
42.1955 + implements java.io.Serializable {
42.1956 + static final long serialVersionUID = 54305834L;
42.1957 + private Object value;
42.1958 + public transient int countInstanceOf;
42.1959 +
42.1960 + public SerialPair (Object value) {
42.1961 + this.value = value;
42.1962 + }
42.1963 +
42.1964 + protected boolean creatorOf(Object obj) {
42.1965 + return obj == value;
42.1966 + }
42.1967 +
42.1968 + public String getDisplayName() {
42.1969 + return getId ();
42.1970 + }
42.1971 +
42.1972 + public String getId() {
42.1973 + return value.toString();
42.1974 + }
42.1975 +
42.1976 + public Object getInstance() {
42.1977 + return value;
42.1978 + }
42.1979 +
42.1980 + public Class getType() {
42.1981 + return value.getClass ();
42.1982 + }
42.1983 +
42.1984 + protected boolean instanceOf(Class c) {
42.1985 + countInstanceOf++;
42.1986 + return c.isInstance(value);
42.1987 + }
42.1988 + } // end of SerialPair
42.1989 +
42.1990 + private static class BrokenPair extends AbstractLookup.Pair {
42.1991 + private transient ThreadLocal IN = new ThreadLocal ();
42.1992 + private boolean checkModify;
42.1993 + private boolean checkQuery;
42.1994 +
42.1995 + public BrokenPair (boolean checkModify, boolean checkQuery) {
42.1996 + this.checkModify = checkModify;
42.1997 + this.checkQuery = checkQuery;
42.1998 + }
42.1999 +
42.2000 + protected boolean creatorOf(Object obj) { return this == obj; }
42.2001 + public String getDisplayName() { return "Broken"; }
42.2002 + public String getId() { return "broken"; }
42.2003 + public Object getInstance() { return this; }
42.2004 + public Class getType() { return getClass (); }
42.2005 + protected boolean instanceOf(Class c) {
42.2006 +
42.2007 + if (checkQuery) {
42.2008 + if (IN.get () == null) {
42.2009 + try {
42.2010 + IN.set (this);
42.2011 + // broken behaviour, tries to modify the lookup
42.2012 + // queries have to survive
42.2013 +
42.2014 + running.lookup.lookup (java.awt.List.class);
42.2015 +
42.2016 + //
42.2017 + // creation of new result has to survive as well
42.2018 + Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.Button.class));
42.2019 + Collection all = myQuery.allItems ();
42.2020 + } finally {
42.2021 + IN.set (null);
42.2022 + }
42.2023 + }
42.2024 + }
42.2025 +
42.2026 +
42.2027 + if (checkModify) {
42.2028 + //
42.2029 + // modifications should fail
42.2030 + //
42.2031 +
42.2032 + try {
42.2033 + running.ic.addPair (new SerialPair (""));
42.2034 + fail ("Modification from a query should be prohibited");
42.2035 + } catch (IllegalStateException ex) {
42.2036 + }
42.2037 +
42.2038 + try {
42.2039 + running.ic.removePair (this);
42.2040 + fail ("This has to throw the exception");
42.2041 + } catch (IllegalStateException ex) {
42.2042 + }
42.2043 + try {
42.2044 + running.ic.setPairs (Collections.EMPTY_SET);
42.2045 + fail ("This has to throw the exception as well");
42.2046 + } catch (IllegalStateException ex) {
42.2047 + }
42.2048 + }
42.2049 +
42.2050 + return c.isAssignableFrom(getType ());
42.2051 + }
42.2052 + } // end of BrokenPair
42.2053 +
42.2054 + private static class Broken2Pair extends AbstractLookup.Pair {
42.2055 + static final long serialVersionUID = 4532587018501L;
42.2056 + public transient ThreadLocal IN;
42.2057 +
42.2058 + public Broken2Pair () {
42.2059 + }
42.2060 +
42.2061 + private void writeObject (java.io.ObjectOutputStream oos) throws java.io.IOException {
42.2062 + }
42.2063 +
42.2064 + private void readObject (java.io.ObjectInputStream ois) throws java.io.IOException, ClassNotFoundException {
42.2065 + IN = new ThreadLocal ();
42.2066 + }
42.2067 +
42.2068 + protected boolean creatorOf(Object obj) { return this == obj; }
42.2069 + public String getDisplayName() { return "Broken"; }
42.2070 + public String getId() { return "broken"; }
42.2071 + public Object getInstance() { return this; }
42.2072 + public Class getType() { return getClass (); }
42.2073 + protected boolean instanceOf(Class c) {
42.2074 +
42.2075 + // behaviour gets broken only after deserialization
42.2076 + if (IN != null && IN.get () == null) {
42.2077 + try {
42.2078 + IN.set (this);
42.2079 +
42.2080 + // creation of new result has to survive as well
42.2081 + Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.List.class));
42.2082 + Collection all = myQuery.allItems ();
42.2083 + } finally {
42.2084 + IN.set (null);
42.2085 + }
42.2086 + }
42.2087 +
42.2088 + return c.isAssignableFrom(getType ());
42.2089 + }
42.2090 + } // end of Broken2Pair
42.2091 +}
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupExecutorTest.java Sat Oct 31 15:28:13 2009 +0100
43.3 @@ -0,0 +1,98 @@
43.4 +/*
43.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
43.6 + *
43.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
43.8 + *
43.9 + * The contents of this file are subject to the terms of either the GNU
43.10 + * General Public License Version 2 only ("GPL") or the Common
43.11 + * Development and Distribution License("CDDL") (collectively, the
43.12 + * "License"). You may not use this file except in compliance with the
43.13 + * License. You can obtain a copy of the License at
43.14 + * http://www.netbeans.org/cddl-gplv2.html
43.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
43.16 + * specific language governing permissions and limitations under the
43.17 + * License. When distributing the software, include this License Header
43.18 + * Notice in each file and include the License file at
43.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
43.20 + * particular file as subject to the "Classpath" exception as provided
43.21 + * by Sun in the GPL Version 2 section of the License file that
43.22 + * accompanied this code. If applicable, add the following below the
43.23 + * License Header, with the fields enclosed by brackets [] replaced by
43.24 + * your own identifying information:
43.25 + * "Portions Copyrighted [year] [name of copyright owner]"
43.26 + *
43.27 + * Contributor(s):
43.28 + *
43.29 + * The Original Software is NetBeans. The Initial Developer of the Original
43.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
43.31 + * Microsystems, Inc. All Rights Reserved.
43.32 + *
43.33 + * If you wish your version of this file to be governed by only the CDDL
43.34 + * or only the GPL Version 2, indicate your decision by adding
43.35 + * "[Contributor] elects to include this software in this distribution
43.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
43.37 + * single choice of license, a recipient has the option to distribute
43.38 + * your version of this file under either the CDDL, the GPL Version 2 or
43.39 + * to extend the choice of license to its licensees as provided above.
43.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
43.41 + * Version 2 license, then the option applies only if the new code is
43.42 + * made subject to such option by the copyright holder.
43.43 + */
43.44 +
43.45 +package org.openide.util.lookup;
43.46 +
43.47 +import java.util.concurrent.Executor;
43.48 +import org.openide.util.Lookup;
43.49 +import org.openide.util.LookupEvent;
43.50 +import org.openide.util.LookupListener;
43.51 +
43.52 +public class AbstractLookupExecutorTest extends AbstractLookupBaseHid
43.53 +implements AbstractLookupBaseHid.Impl, Executor, LookupListener {
43.54 + Lookup.Result<?> res;
43.55 +
43.56 +
43.57 + public AbstractLookupExecutorTest(java.lang.String testName) {
43.58 + super(testName, null);
43.59 + }
43.60 +
43.61 + //
43.62 + // Impl of AbstractLookupBaseHid.Impl
43.63 + //
43.64 +
43.65 + /** Creates the initial abstract lookup.
43.66 + */
43.67 + public Lookup createInstancesLookup (InstanceContent ic) {
43.68 + ic.attachExecutor(this);
43.69 + Lookup l = new AbstractLookup (ic, new InheritanceTree ());
43.70 + return l;
43.71 + }
43.72 +
43.73 + /** Creates an lookup for given lookup. This class just returns
43.74 + * the object passed in, but subclasses can be different.
43.75 + * @param lookup in lookup
43.76 + * @return a lookup to use
43.77 + */
43.78 + public Lookup createLookup (Lookup lookup) {
43.79 + res = lookup.lookupResult(Object.class);
43.80 + res.addLookupListener(this);
43.81 + return lookup;
43.82 + }
43.83 +
43.84 + public void clearCaches () {
43.85 + }
43.86 +
43.87 + ThreadLocal<Object> ME = new ThreadLocal<Object>();
43.88 + public void execute(Runnable command) {
43.89 + assertEquals("Not yet set", null, ME.get());
43.90 + ME.set(this);
43.91 + try {
43.92 + command.run();
43.93 + } finally {
43.94 + ME.set(null);
43.95 + }
43.96 + }
43.97 +
43.98 + public void resultChanged(LookupEvent ev) {
43.99 + assertEquals("Changes delivered only from execute method", this, ME.get());
43.100 + }
43.101 +}
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupMemoryTest.java Sat Oct 31 15:28:13 2009 +0100
44.3 @@ -0,0 +1,158 @@
44.4 +/*
44.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
44.6 + *
44.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
44.8 + *
44.9 + * The contents of this file are subject to the terms of either the GNU
44.10 + * General Public License Version 2 only ("GPL") or the Common
44.11 + * Development and Distribution License("CDDL") (collectively, the
44.12 + * "License"). You may not use this file except in compliance with the
44.13 + * License. You can obtain a copy of the License at
44.14 + * http://www.netbeans.org/cddl-gplv2.html
44.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
44.16 + * specific language governing permissions and limitations under the
44.17 + * License. When distributing the software, include this License Header
44.18 + * Notice in each file and include the License file at
44.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
44.20 + * particular file as subject to the "Classpath" exception as provided
44.21 + * by Sun in the GPL Version 2 section of the License file that
44.22 + * accompanied this code. If applicable, add the following below the
44.23 + * License Header, with the fields enclosed by brackets [] replaced by
44.24 + * your own identifying information:
44.25 + * "Portions Copyrighted [year] [name of copyright owner]"
44.26 + *
44.27 + * Contributor(s):
44.28 + *
44.29 + * The Original Software is NetBeans. The Initial Developer of the Original
44.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
44.31 + * Microsystems, Inc. All Rights Reserved.
44.32 + *
44.33 + * If you wish your version of this file to be governed by only the CDDL
44.34 + * or only the GPL Version 2, indicate your decision by adding
44.35 + * "[Contributor] elects to include this software in this distribution
44.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
44.37 + * single choice of license, a recipient has the option to distribute
44.38 + * your version of this file under either the CDDL, the GPL Version 2 or
44.39 + * to extend the choice of license to its licensees as provided above.
44.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
44.41 + * Version 2 license, then the option applies only if the new code is
44.42 + * made subject to such option by the copyright holder.
44.43 + */
44.44 +
44.45 +package org.openide.util.lookup;
44.46 +
44.47 +import java.util.*;
44.48 +import org.netbeans.junit.*;
44.49 +import org.netbeans.modules.openide.util.ActiveQueue;
44.50 +import org.openide.util.Lookup;
44.51 +
44.52 +/** Testing memory consumption of various AbstractLookup aspects.
44.53 + */
44.54 +public class AbstractLookupMemoryTest extends NbTestCase {
44.55 + public AbstractLookupMemoryTest(java.lang.String testName) {
44.56 + super(testName);
44.57 + }
44.58 +
44.59 + public static void main(java.lang.String[] args) {
44.60 + junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupMemoryTest.class));
44.61 + }
44.62 +
44.63 + public void testEmptySize () {
44.64 + AbstractLookup instanceLookup = new AbstractLookup ();
44.65 + assertSize ("Empty lookup should be small", 16, instanceLookup);
44.66 +
44.67 + InstanceContent ic = new InstanceContent ();
44.68 + instanceLookup = new AbstractLookup (ic);
44.69 + assertSize ("Lookup with InstanceContent should be small as well", 16, instanceLookup);
44.70 + }
44.71 +
44.72 + public void testPairSize () {
44.73 + AbstractLookup.Pair pair = new EmptyPair ();
44.74 + assertSize ("Pair occupies only 16 bytes", 16, pair);
44.75 + }
44.76 +
44.77 + public void testPairWithOnePointerSize () {
44.78 + AbstractLookup.Pair pair = new OneItemPair ();
44.79 + assertSize ("Pair occupies only 16 bytes", 16, pair);
44.80 + }
44.81 +
44.82 + public void testLookupWithPairs () {
44.83 + Lookup.Template<Object> t = new Lookup.Template<Object>(Object.class);
44.84 + class L implements org.openide.util.LookupListener {
44.85 + public int cnt;
44.86 + public void resultChanged (org.openide.util.LookupEvent ev) {
44.87 + cnt++;
44.88 + }
44.89 + }
44.90 + L listener = new L ();
44.91 + L listener2 = new L ();
44.92 +
44.93 + EmptyPair[] pairs = {
44.94 + new EmptyPair(),
44.95 + new EmptyPair(),
44.96 + new EmptyPair(),
44.97 + new EmptyPair(),
44.98 + };
44.99 + Object[] ignore = {
44.100 + pairs[0],
44.101 + pairs[1],
44.102 + pairs[2],
44.103 + pairs[3],
44.104 + t,
44.105 + ActiveQueue.queue(),
44.106 + listener,
44.107 + listener2,
44.108 + new Integer (11) // trashhold is shared
44.109 + };
44.110 +
44.111 + AbstractLookup.Content c = new AbstractLookup.Content ();
44.112 + AbstractLookup l = new AbstractLookup (c, (Integer)ignore[ignore.length - 1]);
44.113 +
44.114 + c.addPair ((EmptyPair)ignore[0]);
44.115 + assertSize ("Should be really small (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
44.116 +
44.117 + c.addPair ((EmptyPair)ignore[1]);
44.118 + assertSize ("Is bigger I guess (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
44.119 +
44.120 + c.setPairs(Arrays.asList(pairs).subList(0, 3));
44.121 + assertSize ("Even bigger (not counting the pair sizes)", Collections.singleton (l), 64, ignore);
44.122 +
44.123 + c.setPairs(Arrays.asList(pairs).subList(0, 4));
44.124 + assertSize ("Now not that much(not counting the pair sizes)", Collections.singleton (l), 64, ignore);
44.125 +
44.126 + Lookup.Result res = l.lookup (t);
44.127 +
44.128 + assertSize ("After creating a result", Collections.singleton (l), 120, ignore);
44.129 +
44.130 + res.addLookupListener (listener);
44.131 +
44.132 + assertSize ("And attaching one listener", Collections.singleton (l), 120, ignore);
44.133 +
44.134 + res.addLookupListener (listener2);
44.135 + assertSize ("Second listener makes the situation much worse", Collections.singleton (l), 200, ignore);
44.136 + res.removeLookupListener(listener2);
44.137 + assertSize ("But removing it returns us back to original size", Collections.singleton (l), 120, ignore);
44.138 +
44.139 +
44.140 + assertEquals ("Current for pairs are in", res.allItems ().size (), 4); // also activates the listener
44.141 + assertSize ("and making the listener to work", Collections.singleton (l), 120, ignore);
44.142 +
44.143 + c.removePair ((EmptyPair)ignore[0]);
44.144 + assertEquals ("A changes has been delivered", 1, listener.cnt);
44.145 + }
44.146 +
44.147 + /** Simple pair with no data */
44.148 + private static class EmptyPair extends AbstractLookup.Pair {
44.149 + protected boolean creatorOf(Object obj) { return false; }
44.150 + public String getDisplayName() { return ""; }
44.151 + public String getId() { return ""; }
44.152 + public Object getInstance() { return null; }
44.153 + public Class getType() { return Object.class; }
44.154 + protected boolean instanceOf(Class c) { return c == getType (); }
44.155 + } // end of EmptyPair
44.156 +
44.157 + /** Pair with one item (like InstanceContent.Pair) */
44.158 + private static class OneItemPair extends EmptyPair {
44.159 + private Object pointer;
44.160 + }
44.161 +}
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupTest.java Sat Oct 31 15:28:13 2009 +0100
45.3 @@ -0,0 +1,356 @@
45.4 +/*
45.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
45.6 + *
45.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
45.8 + *
45.9 + * The contents of this file are subject to the terms of either the GNU
45.10 + * General Public License Version 2 only ("GPL") or the Common
45.11 + * Development and Distribution License("CDDL") (collectively, the
45.12 + * "License"). You may not use this file except in compliance with the
45.13 + * License. You can obtain a copy of the License at
45.14 + * http://www.netbeans.org/cddl-gplv2.html
45.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
45.16 + * specific language governing permissions and limitations under the
45.17 + * License. When distributing the software, include this License Header
45.18 + * Notice in each file and include the License file at
45.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
45.20 + * particular file as subject to the "Classpath" exception as provided
45.21 + * by Sun in the GPL Version 2 section of the License file that
45.22 + * accompanied this code. If applicable, add the following below the
45.23 + * License Header, with the fields enclosed by brackets [] replaced by
45.24 + * your own identifying information:
45.25 + * "Portions Copyrighted [year] [name of copyright owner]"
45.26 + *
45.27 + * Contributor(s):
45.28 + *
45.29 + * The Original Software is NetBeans. The Initial Developer of the Original
45.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
45.31 + * Microsystems, Inc. All Rights Reserved.
45.32 + *
45.33 + * If you wish your version of this file to be governed by only the CDDL
45.34 + * or only the GPL Version 2, indicate your decision by adding
45.35 + * "[Contributor] elects to include this software in this distribution
45.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
45.37 + * single choice of license, a recipient has the option to distribute
45.38 + * your version of this file under either the CDDL, the GPL Version 2 or
45.39 + * to extend the choice of license to its licensees as provided above.
45.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
45.41 + * Version 2 license, then the option applies only if the new code is
45.42 + * made subject to such option by the copyright holder.
45.43 + */
45.44 +
45.45 +package org.openide.util.lookup;
45.46 +
45.47 +import java.util.concurrent.ExecutionException;
45.48 +
45.49 +import java.lang.ref.WeakReference;
45.50 +import java.util.*;
45.51 +import java.util.concurrent.Executors;
45.52 +import java.util.concurrent.TimeUnit;
45.53 +import org.netbeans.junit.*;
45.54 +import org.openide.util.Lookup;
45.55 +import org.openide.util.lookup.AbstractLookup.Pair;
45.56 +
45.57 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
45.58 +public class AbstractLookupTest extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
45.59 + public AbstractLookupTest(java.lang.String testName) {
45.60 + super(testName, null);
45.61 + }
45.62 +
45.63 + //
45.64 + // Impl of AbstractLookupBaseHid.Impl
45.65 + //
45.66 +
45.67 + /** Creates the initial abstract lookup.
45.68 + */
45.69 + public Lookup createInstancesLookup (InstanceContent ic) {
45.70 + return new AbstractLookup (ic, new InheritanceTree ());
45.71 + }
45.72 +
45.73 + /** Creates an lookup for given lookup. This class just returns
45.74 + * the object passed in, but subclasses can be different.
45.75 + * @param lookup in lookup
45.76 + * @return a lookup to use
45.77 + */
45.78 + public Lookup createLookup (Lookup lookup) {
45.79 + return lookup;
45.80 + }
45.81 +
45.82 + public void clearCaches () {
45.83 + }
45.84 +
45.85 + public static void main(java.lang.String[] args) {
45.86 + junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupTest.class));
45.87 + }
45.88 +
45.89 + static class LkpResultCanBeGargageCollectedAndClearsTheResult extends AbstractLookup {
45.90 + public int cleared;
45.91 + public int dirty;
45.92 +
45.93 + synchronized @Override boolean cleanUpResult(Template t) {
45.94 + boolean res = super.cleanUpResult (t);
45.95 + if (res) {
45.96 + cleared++;
45.97 + } else {
45.98 + dirty++;
45.99 + }
45.100 +
45.101 + notifyAll ();
45.102 +
45.103 + return res;
45.104 + }
45.105 + }
45.106 + public void testResultCanBeGargageCollectedAndClearsTheResult () throws Exception {
45.107 + LkpResultCanBeGargageCollectedAndClearsTheResult lkp = new LkpResultCanBeGargageCollectedAndClearsTheResult ();
45.108 + assertSize ("24 for AbstractLookup, 8 for two ints", 32, lkp);
45.109 + synchronized (lkp) {
45.110 + Lookup.Result res = lkp.lookup (new Lookup.Template (getClass ()));
45.111 + res.allItems();
45.112 +
45.113 + WeakReference ref = new WeakReference (res);
45.114 + res = null;
45.115 + assertGC ("Reference can get cleared", ref);
45.116 +
45.117 + // wait till we
45.118 + while (lkp.cleared == 0 && lkp.dirty == 0) {
45.119 + lkp.wait ();
45.120 + }
45.121 +
45.122 + assertEquals ("No dirty cleanups", 0, lkp.dirty);
45.123 + assertEquals ("One final cleanup", 1, lkp.cleared);
45.124 + }
45.125 + //assertSize ("Everything has been cleaned to original size", 32, lkp);
45.126 +
45.127 + }
45.128 +
45.129 + public void testPairCannotBeUsedInMoreThanOneLookupAtOnce () throws Exception {
45.130 + /** Simple pair with no data */
45.131 + class EmptyPair extends AbstractLookup.Pair {
45.132 + protected boolean creatorOf(Object obj) { return false; }
45.133 + public String getDisplayName() { return "Empty"; }
45.134 + public String getId() { return "empty"; }
45.135 + public Object getInstance() { return null; }
45.136 + public Class getType() { return Object.class; }
45.137 + protected boolean instanceOf(Class c) { return c == getType (); }
45.138 + } // end of EmptyPair
45.139 +
45.140 + AbstractLookup.Content c1 = new AbstractLookup.Content ();
45.141 + AbstractLookup.Content c2 = new AbstractLookup.Content ();
45.142 + AbstractLookup l1 = new AbstractLookup (c1);
45.143 + AbstractLookup l2 = new AbstractLookup (c2);
45.144 +
45.145 + EmptyPair empty = new EmptyPair ();
45.146 + c1.addPair (empty);
45.147 + Lookup.Result res = l1.lookup (new Lookup.Template (Object.class));
45.148 + assertEquals (
45.149 + "Pair is really found", empty,
45.150 + res.allItems ().iterator().next ()
45.151 + );
45.152 + try {
45.153 + c2.addPair (empty);
45.154 + fail ("It should not be possible to add pair to two lookups");
45.155 + } catch (IllegalStateException ex) {
45.156 + // ok, exception is fine
45.157 + }
45.158 + assertEquals (
45.159 + "L2 is still empty", Collections.EMPTY_LIST,
45.160 + new ArrayList (l2.lookup (new Lookup.Template (Object.class)).allItems ())
45.161 + );
45.162 + }
45.163 +
45.164 + public void testInitializationCanBeDoneFromAnotherThread () {
45.165 + class MyLkp extends AbstractLookup implements Runnable {
45.166 + private InstanceContent ic;
45.167 + private boolean direct;
45.168 +
45.169 + public MyLkp (boolean direct) {
45.170 + this (direct, new InstanceContent ());
45.171 + }
45.172 +
45.173 + private MyLkp (boolean direct, InstanceContent ic) {
45.174 + super (ic);
45.175 + this.direct = direct;
45.176 + this.ic = ic;
45.177 + }
45.178 +
45.179 + protected @Override void initialize() {
45.180 + if (direct) {
45.181 + run ();
45.182 + } else {
45.183 + try {
45.184 + Executors.newSingleThreadScheduledExecutor().schedule(this, 0, TimeUnit.MICROSECONDS).get();
45.185 + } catch (InterruptedException ex) {
45.186 + ex.printStackTrace();
45.187 + } catch (ExecutionException ex) {
45.188 + ex.printStackTrace();
45.189 + }
45.190 + }
45.191 + }
45.192 +
45.193 + public void run () {
45.194 + ic.add (this);
45.195 + ic.remove (this);
45.196 + ic.set (Collections.nCopies(10, this), null);
45.197 + ic.set (Collections.EMPTY_LIST, null);
45.198 + ic.add (AbstractLookupTest.this);
45.199 + }
45.200 + }
45.201 +
45.202 + assertEquals ("The test should be there", this, new MyLkp (true).lookup (Object.class));
45.203 + assertEquals ("and in async mode as well", this, new MyLkp (false).lookup (Object.class));
45.204 + }
45.205 +
45.206 + public void testBeforeLookupIsCalled () {
45.207 + class BeforeL extends AbstractLookup {
45.208 + public ArrayList list = new ArrayList ();
45.209 + public String toAdd;
45.210 + public InstanceContent ic;
45.211 +
45.212 + public BeforeL () {
45.213 + this (new InstanceContent ());
45.214 + }
45.215 +
45.216 + private BeforeL (InstanceContent c) {
45.217 + super (c);
45.218 + this.ic = c;
45.219 + }
45.220 +
45.221 + protected @Override void beforeLookup(Template t) {
45.222 + if (toAdd != null) {
45.223 + list.add (0, new SerialPair (toAdd));
45.224 + setPairs (list);
45.225 + } else {
45.226 + ic.add (new Integer (1));
45.227 + }
45.228 + }
45.229 + }
45.230 +
45.231 + BeforeL lookup = new BeforeL ();
45.232 +
45.233 + lookup.toAdd = "First";
45.234 + assertEquals ("First if found", "First", lookup.lookup (String.class));
45.235 +
45.236 + lookup.toAdd = "2";
45.237 + assertEquals ("2 is not first", "2", lookup.lookup (String.class));
45.238 +
45.239 + Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
45.240 + for (int i = 3; i < 20; i++) {
45.241 + lookup.toAdd = String.valueOf (i);
45.242 + assertEquals (i + " items are now there", i, res.allInstances ().size ());
45.243 + }
45.244 + for (int i = 20; i < 35; i++) {
45.245 + lookup.toAdd = String.valueOf (i);
45.246 + assertEquals (i + " items are now there", i, res.allItems ().size ());
45.247 + }
45.248 +
45.249 + assertEquals ("Just strings are there now", 1, res.allClasses ().size ());
45.250 + lookup.toAdd = null; // this will add integer
45.251 + assertEquals ("Two classes now", 2, res.allClasses ().size ());
45.252 + }
45.253 +
45.254 + public void testInconsistentAfterDeserIssue71744() throws Exception {
45.255 + InheritanceTree inhTree = new InheritanceTree();
45.256 +
45.257 + AbstractLookup al = new AbstractLookup(new AbstractLookup.Content(), inhTree);
45.258 + {
45.259 +
45.260 + Collection r = al.lookup(new Lookup.Template(Integer.class)).allInstances();
45.261 + assertEquals("None", 0, r.size());
45.262 + }
45.263 +
45.264 + ICP item = new ICP(new Integer(10));
45.265 + al.addPair(item);
45.266 + al.removePair(item);
45.267 +
45.268 + AbstractLookup newLookup = (AbstractLookup)reserialize(al);
45.269 +
45.270 + newLookup.lookup(Number.class);
45.271 +
45.272 +
45.273 + newLookup.addPair(new ICP(new Long(20)));
45.274 +
45.275 + {
45.276 +
45.277 + Collection r = newLookup.lookup(new Lookup.Template(Number.class)).allInstances();
45.278 + assertEquals("one", 1, r.size());
45.279 +/*
45.280 + Iterator it = r.iterator();
45.281 + assertEquals(new Integer(10), it.next());
45.282 + assertEquals(new Long(20), it.next());*/
45.283 + }
45.284 + }
45.285 +
45.286 + public void testMatchesIssue130673() {
45.287 + class BrokenPairReturningNullID extends Pair<Object> {
45.288 + @Override
45.289 + protected boolean instanceOf(Class<?> c) {
45.290 + return false;
45.291 + }
45.292 +
45.293 + @Override
45.294 + protected boolean creatorOf(Object obj) {
45.295 + return false;
45.296 + }
45.297 +
45.298 + @Override
45.299 + public Object getInstance() {
45.300 + return null;
45.301 + }
45.302 +
45.303 + @Override
45.304 + public Class<? extends Object> getType() {
45.305 + return null;
45.306 + }
45.307 +
45.308 + @Override
45.309 + public String getId() {
45.310 + return null;
45.311 + }
45.312 +
45.313 + @Override
45.314 + public String getDisplayName() {
45.315 + return null;
45.316 + }
45.317 + }
45.318 + BrokenPairReturningNullID broken = new BrokenPairReturningNullID();
45.319 +
45.320 +
45.321 + Lookup.Template<String> t = new Lookup.Template<String>(String.class, "ID", null);
45.322 + boolean not = AbstractLookup.matches(t, broken, true);
45.323 + assertFalse("Does not match the template, but throws no exception", not);
45.324 + }
45.325 +
45.326 + private static final class ICP extends AbstractLookup.Pair {
45.327 + private Number s;
45.328 +
45.329 + public ICP (Number s) {
45.330 + this.s = s;
45.331 + }
45.332 +
45.333 +
45.334 + protected boolean instanceOf(Class c) {
45.335 + return c.isInstance(s);
45.336 + }
45.337 +
45.338 + protected boolean creatorOf(Object obj) {
45.339 + return s == obj;
45.340 + }
45.341 +
45.342 + public Object getInstance() {
45.343 + return s;
45.344 + }
45.345 +
45.346 + public Class getType() {
45.347 + return s.getClass();
45.348 + }
45.349 +
45.350 + public String getId() {
45.351 + return s.toString();
45.352 + }
45.353 +
45.354 + public String getDisplayName() {
45.355 + return getId();
45.356 + }
45.357 +
45.358 + }
45.359 +}
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java Sat Oct 31 15:28:13 2009 +0100
46.3 @@ -0,0 +1,228 @@
46.4 +/*
46.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
46.6 + *
46.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
46.8 + *
46.9 + * The contents of this file are subject to the terms of either the GNU
46.10 + * General Public License Version 2 only ("GPL") or the Common
46.11 + * Development and Distribution License("CDDL") (collectively, the
46.12 + * "License"). You may not use this file except in compliance with the
46.13 + * License. You can obtain a copy of the License at
46.14 + * http://www.netbeans.org/cddl-gplv2.html
46.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
46.16 + * specific language governing permissions and limitations under the
46.17 + * License. When distributing the software, include this License Header
46.18 + * Notice in each file and include the License file at
46.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
46.20 + * particular file as subject to the "Classpath" exception as provided
46.21 + * by Sun in the GPL Version 2 section of the License file that
46.22 + * accompanied this code. If applicable, add the following below the
46.23 + * License Header, with the fields enclosed by brackets [] replaced by
46.24 + * your own identifying information:
46.25 + * "Portions Copyrighted [year] [name of copyright owner]"
46.26 + *
46.27 + * Contributor(s):
46.28 + *
46.29 + * The Original Software is NetBeans. The Initial Developer of the Original
46.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
46.31 + * Microsystems, Inc. All Rights Reserved.
46.32 + *
46.33 + * If you wish your version of this file to be governed by only the CDDL
46.34 + * or only the GPL Version 2, indicate your decision by adding
46.35 + * "[Contributor] elects to include this software in this distribution
46.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
46.37 + * single choice of license, a recipient has the option to distribute
46.38 + * your version of this file under either the CDDL, the GPL Version 2 or
46.39 + * to extend the choice of license to its licensees as provided above.
46.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
46.41 + * Version 2 license, then the option applies only if the new code is
46.42 + * made subject to such option by the copyright holder.
46.43 + */
46.44 +
46.45 +package org.openide.util.lookup;
46.46 +
46.47 +import java.util.*;
46.48 +import org.openide.util.Lookup;
46.49 +
46.50 +/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
46.51 + */
46.52 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
46.53 +public class ExcludingLookupTest extends AbstractLookupBaseHid
46.54 +implements AbstractLookupBaseHid.Impl {
46.55 + public ExcludingLookupTest(java.lang.String testName) {
46.56 + super(testName, null);
46.57 + }
46.58 +
46.59 + public Lookup createLookup (final Lookup lookup) {
46.60 + return Lookups.exclude (lookup, new Class[0]);
46.61 + }
46.62 +
46.63 + public Lookup createInstancesLookup (InstanceContent ic) {
46.64 + return new AbstractLookup (ic);
46.65 + }
46.66 +
46.67 + public void clearCaches () {
46.68 + }
46.69 +
46.70 + public void testWeCanRemoveInteger () throws Exception {
46.71 + doBasicFilteringTest (Integer.class, Integer.class, 0);
46.72 + }
46.73 +
46.74 + public void testWeCanRemoveIntegersEvenByAskingForRemoveOfAllNumbers () throws Exception {
46.75 + doBasicFilteringTest (Number.class, Integer.class, 0);
46.76 + }
46.77 + public void testFunWithInterfaces () throws Exception {
46.78 + doBasicFilteringTest (java.io.Serializable.class, Integer.class, 0);
46.79 + }
46.80 +
46.81 + public void testWeCanGetInstanceOfSerializableEvenItIsExcludedIfWeAskForClassNotExtendingIt () throws Exception {
46.82 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { java.io.Serializable.class });
46.83 + Lookup.Template t = new Lookup.Template (Object.class);
46.84 + Lookup.Result res = lookup.lookup (t);
46.85 +
46.86 + LL ll = new LL ();
46.87 + res.addLookupListener (ll);
46.88 + assertEquals ("Nothing is there", 0, res.allItems ().size ());
46.89 +
46.90 + Object inst = new Integer (3);
46.91 + ic.add (inst);
46.92 +
46.93 + assertEquals ("Not Filtered out", inst, lookup.lookup (Object.class));
46.94 + assertEquals ("Not Filtered out2", inst, lookup.lookupItem (t).getInstance ());
46.95 + assertEquals ("One is there - 2", 1, res.allItems ().size ());
46.96 + assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
46.97 + assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
46.98 + assertEquals ("Right # of events", 1, ll.getCount ());
46.99 +
46.100 + ic.remove (inst);
46.101 + assertEquals ("Filtered out3", null, lookup.lookupItem (t));
46.102 + assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
46.103 + assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
46.104 + assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
46.105 + assertEquals ("Of course it is not there", null, lookup.lookup (Object.class));
46.106 + assertEquals ("Right # of events", 1, ll.getCount ());
46.107 + }
46.108 +
46.109 + public void testIntegersQueriedThruObject () throws Exception {
46.110 + doBasicFilteringTest (Number.class, Object.class, 1);
46.111 + }
46.112 +
46.113 + private void doBasicFilteringTest (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
46.114 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
46.115 + Lookup.Template t = new Lookup.Template (theQuery);
46.116 + Lookup.Result res = lookup.lookup (t);
46.117 +
46.118 + LL ll = new LL ();
46.119 + res.addLookupListener (ll);
46.120 + assertEquals ("Nothing is there", 0, res.allItems ().size ());
46.121 +
46.122 + Object inst = new Integer (3);
46.123 + ic.add (inst);
46.124 +
46.125 + assertEquals ("Filtered out", null, lookup.lookup (theQuery));
46.126 + assertEquals ("Filtered out2", null, lookup.lookupItem (t));
46.127 + assertEquals ("Nothing is there - 2", 0, res.allItems ().size ());
46.128 + assertEquals ("Nothing is there - 2a", 0, res.allInstances ().size ());
46.129 + assertEquals ("Nothing is there - 2b", 0, res.allClasses ().size ());
46.130 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
46.131 +
46.132 + ic.remove (inst);
46.133 + assertEquals ("Filtered out3", null, lookup.lookupItem (t));
46.134 + assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
46.135 + assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
46.136 + assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
46.137 + assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
46.138 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
46.139 +
46.140 + }
46.141 +
46.142 + public void testSizeOfTheLookup () throws Exception {
46.143 + Class exclude = String.class;
46.144 +
46.145 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { exclude });
46.146 +
46.147 + assertSize ("Should be pretty lightweight", Collections.singleton (lookup), 16,
46.148 + new Object[] { this.instanceLookup, exclude });
46.149 + }
46.150 + public void testSizeOfTheLookupForMultipleFiltersIsHigher () throws Exception {
46.151 + Class exclude = String.class;
46.152 + Class exclude2 = Integer.class;
46.153 + Class[] arr = new Class[] { exclude, exclude2 };
46.154 +
46.155 + Lookup lookup = Lookups.exclude (this.instanceLookup, arr);
46.156 +
46.157 + assertSize ("Is fatter", Collections.singleton (lookup), 40,
46.158 + new Object[] { this.instanceLookup, exclude, exclude2 });
46.159 + assertSize ("But only due to the array", Collections.singleton (lookup), 16,
46.160 + new Object[] { this.instanceLookup, exclude, exclude2, arr });
46.161 + }
46.162 +
46.163 + public void testFilteringOfSomething () throws Exception {
46.164 + doFilteringOfSomething (Runnable.class, java.io.Serializable.class, 1);
46.165 + }
46.166 +
46.167 + private void doFilteringOfSomething (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
46.168 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
46.169 + Lookup.Template t = new Lookup.Template (theQuery);
46.170 + Lookup.Result res = lookup.lookup (t);
46.171 +
46.172 + LL ll = new LL ();
46.173 + res.addLookupListener (ll);
46.174 + assertEquals ("Nothing is there", 0, res.allItems ().size ());
46.175 +
46.176 + Object inst = new Integer (3);
46.177 + ic.add (inst);
46.178 +
46.179 + assertEquals ("Accepted", inst, lookup.lookup (theQuery));
46.180 + assertNotNull ("Accepted too", lookup.lookupItem (t));
46.181 + assertEquals ("One is there - 2", 1, res.allItems ().size ());
46.182 + assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
46.183 + assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
46.184 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
46.185 +
46.186 + Object inst2 = new Thread (); // implements Runnable
46.187 + ic.add (inst2);
46.188 + assertEquals ("Accepted - 2", inst, lookup.lookup (theQuery));
46.189 + assertNotNull ("Accepted too -2", lookup.lookupItem (t));
46.190 + assertEquals ("One is there - 3", 1, res.allItems ().size ());
46.191 + assertEquals ("One is there - 3a", 1, res.allInstances ().size ());
46.192 + assertEquals ("One is there - 3b", 1, res.allClasses ().size ());
46.193 + assertEquals ("Right # of events", 0, ll.getCount ());
46.194 +
46.195 +
46.196 + ic.remove (inst);
46.197 + assertEquals ("Filtered out3", null, lookup.lookupItem (t));
46.198 + assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
46.199 + assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
46.200 + assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
46.201 + assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
46.202 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
46.203 + }
46.204 +
46.205 + public void testTheBehaviourAsRequestedByDavidAndDescribedByJesse () throws Exception {
46.206 + class C implements Runnable, java.io.Serializable {
46.207 + public void run () {}
46.208 + }
46.209 + Object c = new C();
46.210 + Lookup l1 = Lookups.singleton(c);
46.211 + Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
46.212 + assertNull(l2.lookup(Runnable.class));
46.213 + assertEquals(c, l2.lookup(java.io.Serializable.class));
46.214 + }
46.215 +
46.216 + public void testTheBehaviourAsRequestedByDavidAndDescribedByJesseWithUsageOfResult () throws Exception {
46.217 + class C implements Runnable, java.io.Serializable {
46.218 + public void run () {}
46.219 + }
46.220 + Object c = new C();
46.221 + Lookup l1 = Lookups.singleton(c);
46.222 + Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
46.223 +
46.224 + Lookup.Result run = l2.lookup (new Lookup.Template (Runnable.class));
46.225 + Lookup.Result ser = l2.lookup (new Lookup.Template (java.io.Serializable.class));
46.226 +
46.227 + assertEquals ("Runnables filtered out", 0, run.allItems ().size ());
46.228 + assertEquals ("One serialiazble", 1, ser.allItems ().size ());
46.229 + assertEquals ("And it is c", c, ser.allInstances ().iterator ().next ());
46.230 + }
46.231 +}
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/InheritanceTreeTest.java Sat Oct 31 15:28:13 2009 +0100
47.3 @@ -0,0 +1,77 @@
47.4 +/*
47.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
47.6 + *
47.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
47.8 + *
47.9 + * The contents of this file are subject to the terms of either the GNU
47.10 + * General Public License Version 2 only ("GPL") or the Common
47.11 + * Development and Distribution License("CDDL") (collectively, the
47.12 + * "License"). You may not use this file except in compliance with the
47.13 + * License. You can obtain a copy of the License at
47.14 + * http://www.netbeans.org/cddl-gplv2.html
47.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
47.16 + * specific language governing permissions and limitations under the
47.17 + * License. When distributing the software, include this License Header
47.18 + * Notice in each file and include the License file at
47.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
47.20 + * particular file as subject to the "Classpath" exception as provided
47.21 + * by Sun in the GPL Version 2 section of the License file that
47.22 + * accompanied this code. If applicable, add the following below the
47.23 + * License Header, with the fields enclosed by brackets [] replaced by
47.24 + * your own identifying information:
47.25 + * "Portions Copyrighted [year] [name of copyright owner]"
47.26 + *
47.27 + * Contributor(s):
47.28 + *
47.29 + * The Original Software is NetBeans. The Initial Developer of the Original
47.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
47.31 + * Microsystems, Inc. All Rights Reserved.
47.32 + *
47.33 + * If you wish your version of this file to be governed by only the CDDL
47.34 + * or only the GPL Version 2, indicate your decision by adding
47.35 + * "[Contributor] elects to include this software in this distribution
47.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
47.37 + * single choice of license, a recipient has the option to distribute
47.38 + * your version of this file under either the CDDL, the GPL Version 2 or
47.39 + * to extend the choice of license to its licensees as provided above.
47.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
47.41 + * Version 2 license, then the option applies only if the new code is
47.42 + * made subject to such option by the copyright holder.
47.43 + */
47.44 +package org.openide.util.lookup;
47.45 +
47.46 +import junit.framework.TestCase;
47.47 +import junit.framework.*;
47.48 +import org.openide.util.Lookup;
47.49 +import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
47.50 +import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
47.51 +import java.io.*;
47.52 +import java.lang.ref.WeakReference;
47.53 +import java.util.*;
47.54 +
47.55 +/**
47.56 + *
47.57 + * @author Jaroslav Tulach
47.58 + */
47.59 +public class InheritanceTreeTest extends TestCase {
47.60 +
47.61 + public InheritanceTreeTest(String testName) {
47.62 + super(testName);
47.63 + }
47.64 +
47.65 + protected void setUp() throws Exception {
47.66 + }
47.67 +
47.68 + protected void tearDown() throws Exception {
47.69 + }
47.70 +
47.71 + public void testDeserOfNode() {
47.72 + InheritanceTree inh = new InheritanceTree();
47.73 + InheritanceTree.Node n = new InheritanceTree.Node(String.class);
47.74 + n.markDeserialized();
47.75 + n.markDeserialized();
47.76 +
47.77 + n.assignItem(inh, new InstanceContent.SimpleItem("Ahoj"));
47.78 + }
47.79 +
47.80 +}
48.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
48.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/InitializationBug44134Test.java Sat Oct 31 15:28:13 2009 +0100
48.3 @@ -0,0 +1,126 @@
48.4 +/*
48.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
48.6 + *
48.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
48.8 + *
48.9 + * The contents of this file are subject to the terms of either the GNU
48.10 + * General Public License Version 2 only ("GPL") or the Common
48.11 + * Development and Distribution License("CDDL") (collectively, the
48.12 + * "License"). You may not use this file except in compliance with the
48.13 + * License. You can obtain a copy of the License at
48.14 + * http://www.netbeans.org/cddl-gplv2.html
48.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
48.16 + * specific language governing permissions and limitations under the
48.17 + * License. When distributing the software, include this License Header
48.18 + * Notice in each file and include the License file at
48.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
48.20 + * particular file as subject to the "Classpath" exception as provided
48.21 + * by Sun in the GPL Version 2 section of the License file that
48.22 + * accompanied this code. If applicable, add the following below the
48.23 + * License Header, with the fields enclosed by brackets [] replaced by
48.24 + * your own identifying information:
48.25 + * "Portions Copyrighted [year] [name of copyright owner]"
48.26 + *
48.27 + * Contributor(s):
48.28 + *
48.29 + * The Original Software is NetBeans. The Initial Developer of the Original
48.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
48.31 + * Microsystems, Inc. All Rights Reserved.
48.32 + *
48.33 + * If you wish your version of this file to be governed by only the CDDL
48.34 + * or only the GPL Version 2, indicate your decision by adding
48.35 + * "[Contributor] elects to include this software in this distribution
48.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
48.37 + * single choice of license, a recipient has the option to distribute
48.38 + * your version of this file under either the CDDL, the GPL Version 2 or
48.39 + * to extend the choice of license to its licensees as provided above.
48.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
48.41 + * Version 2 license, then the option applies only if the new code is
48.42 + * made subject to such option by the copyright holder.
48.43 + */
48.44 +
48.45 +package org.openide.util.lookup;
48.46 +
48.47 +import java.util.*;
48.48 +import org.netbeans.junit.*;
48.49 +import org.openide.util.Lookup;
48.50 +
48.51 +public class InitializationBug44134Test extends NbTestCase {
48.52 + public InitializationBug44134Test (java.lang.String testName) {
48.53 + super(testName);
48.54 + }
48.55 +
48.56 + public static void main(java.lang.String[] args) {
48.57 + junit.textui.TestRunner.run(new NbTestSuite(InitializationBug44134Test.class));
48.58 + }
48.59 +
48.60 + public void testThereShouldBe18Integers () throws Exception {
48.61 + FooManifestLookup foo = new FooManifestLookup ();
48.62 +
48.63 + Collection items = foo.lookup (new Lookup.Template (Integer.class)).allItems ();
48.64 +
48.65 + assertEquals ("18 of them", 18, items.size ());
48.66 +
48.67 + Iterator it = items.iterator ();
48.68 + while (it.hasNext()) {
48.69 + Lookup.Item t = (Lookup.Item)it.next ();
48.70 + assertEquals ("Is Integer", Integer.class, t.getInstance ().getClass ());
48.71 + }
48.72 + }
48.73 +
48.74 +
48.75 + public class FooManifestLookup extends AbstractLookup {
48.76 + public FooManifestLookup() {
48.77 + super();
48.78 + }
48.79 +
48.80 + @Override
48.81 + protected void initialize() {
48.82 + for (int i=0; i<18; i++) {
48.83 + try {
48.84 + String id= "__" + i;
48.85 +
48.86 + addPair(new FooLookupItem(new Integer(i),id));
48.87 + }
48.88 + catch (Exception e) {
48.89 + }
48.90 + }
48.91 + }
48.92 +
48.93 + public class FooLookupItem extends AbstractLookup.Pair {
48.94 + public FooLookupItem(Integer data, String id) {
48.95 + super();
48.96 + this.data=data;
48.97 + this.id=id;
48.98 + }
48.99 +
48.100 + protected boolean creatorOf(Object obj) {
48.101 + return obj == data;
48.102 + }
48.103 +
48.104 + public String getDisplayName() {
48.105 + return data.toString();
48.106 + }
48.107 +
48.108 + public Class getType () {
48.109 + return Integer.class;
48.110 + }
48.111 +
48.112 + protected boolean instanceOf (Class c) {
48.113 + return c.isInstance(data);
48.114 + }
48.115 +
48.116 + public Object getInstance() {
48.117 + return data;
48.118 + }
48.119 +
48.120 + public String getId() {
48.121 + return id;
48.122 + }
48.123 +
48.124 + private Integer data;
48.125 + private String id;
48.126 + }
48.127 + }
48.128 +
48.129 +}
49.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
49.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/KomrskaLookupTest.java Sat Oct 31 15:28:13 2009 +0100
49.3 @@ -0,0 +1,177 @@
49.4 +/*
49.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
49.6 + *
49.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
49.8 + *
49.9 + * The contents of this file are subject to the terms of either the GNU
49.10 + * General Public License Version 2 only ("GPL") or the Common
49.11 + * Development and Distribution License("CDDL") (collectively, the
49.12 + * "License"). You may not use this file except in compliance with the
49.13 + * License. You can obtain a copy of the License at
49.14 + * http://www.netbeans.org/cddl-gplv2.html
49.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
49.16 + * specific language governing permissions and limitations under the
49.17 + * License. When distributing the software, include this License Header
49.18 + * Notice in each file and include the License file at
49.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
49.20 + * particular file as subject to the "Classpath" exception as provided
49.21 + * by Sun in the GPL Version 2 section of the License file that
49.22 + * accompanied this code. If applicable, add the following below the
49.23 + * License Header, with the fields enclosed by brackets [] replaced by
49.24 + * your own identifying information:
49.25 + * "Portions Copyrighted [year] [name of copyright owner]"
49.26 + *
49.27 + * If you wish your version of this file to be governed by only the CDDL
49.28 + * or only the GPL Version 2, indicate your decision by adding
49.29 + * "[Contributor] elects to include this software in this distribution
49.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
49.31 + * single choice of license, a recipient has the option to distribute
49.32 + * your version of this file under either the CDDL, the GPL Version 2 or
49.33 + * to extend the choice of license to its licensees as provided above.
49.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
49.35 + * Version 2 license, then the option applies only if the new code is
49.36 + * made subject to such option by the copyright holder.
49.37 + *
49.38 + * Contributor(s):
49.39 + *
49.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
49.41 + */
49.42 +package org.openide.util.lookup;
49.43 +
49.44 +import org.junit.After;
49.45 +import org.junit.Before;
49.46 +import org.junit.Test;
49.47 +import org.openide.util.Lookup;
49.48 +import org.openide.util.LookupEvent;
49.49 +import org.openide.util.LookupListener;
49.50 +import static org.junit.Assert.*;
49.51 +
49.52 +/**
49.53 + * Test donated by Mr. Komrska. Seems to pass with 6.5.
49.54 + * @author komrska
49.55 + */
49.56 +public final class KomrskaLookupTest {
49.57 + private TestLookupManager lookupManager=null;
49.58 + private StringBuffer result=null;
49.59 +
49.60 + //
49.61 +
49.62 + private void addToLookup(final TestLookupItemA object) {
49.63 + result.append('A');
49.64 + lookupManager.add(object);
49.65 + }
49.66 + private void removeFromLookup(final TestLookupItemA object) {
49.67 + result.append('A');
49.68 + lookupManager.remove(object);
49.69 + }
49.70 +
49.71 + private void addToLookup(final TestLookupItemB object) {
49.72 + result.append('B');
49.73 + lookupManager.add(object);
49.74 + }
49.75 + private void removeFromLookup(final TestLookupItemB object) {
49.76 + result.append('B');
49.77 + lookupManager.remove(object);
49.78 + }
49.79 +
49.80 + public String getResult() {
49.81 + return result.toString();
49.82 + }
49.83 +
49.84 + //
49.85 +
49.86 + @Before
49.87 + public void setUp() {
49.88 + lookupManager=new TestLookupManager();
49.89 + result=new StringBuffer();
49.90 + }
49.91 +
49.92 + @After
49.93 + public void tearDown() {
49.94 + lookupManager=null;
49.95 + result=null;
49.96 + }
49.97 +
49.98 + @Test
49.99 + public void testLookupBug() {
49.100 + TestLookupItemA itemA1=new TestLookupItemA();
49.101 + TestLookupItemB itemB1=new TestLookupItemB();
49.102 + //
49.103 + addToLookup(itemA1);
49.104 + addToLookup(itemB1);
49.105 + removeFromLookup(itemA1);
49.106 + removeFromLookup(itemB1);
49.107 + addToLookup(itemB1);
49.108 + removeFromLookup(itemB1);
49.109 + //
49.110 + addToLookup(itemA1);
49.111 + addToLookup(itemB1);
49.112 + removeFromLookup(itemA1);
49.113 + removeFromLookup(itemB1);
49.114 + addToLookup(itemB1);
49.115 + removeFromLookup(itemB1);
49.116 + //
49.117 + addToLookup(itemA1);
49.118 + addToLookup(itemB1);
49.119 + removeFromLookup(itemA1);
49.120 + removeFromLookup(itemB1);
49.121 + addToLookup(itemB1);
49.122 + removeFromLookup(itemB1);
49.123 + //
49.124 + assertEquals(getResult(),lookupManager.getResult());
49.125 + }
49.126 +
49.127 + public static final class TestLookupItemA {}
49.128 + public static final class TestLookupItemB {}
49.129 + public static final class TestLookupManager {
49.130 + private InstanceContent instanceContent=new InstanceContent();
49.131 + private AbstractLookup abstractLookup=new AbstractLookup(instanceContent);
49.132 +
49.133 + private Lookup.Result<TestLookupItemA> resultA=null;
49.134 + private Lookup.Result<TestLookupItemB> resultB=null;
49.135 +
49.136 + private LookupListener listenerA=new LookupListener() {
49.137 + public void resultChanged(LookupEvent event) {
49.138 + result.append('A');
49.139 + }
49.140 + };
49.141 + private LookupListener listenerB=new LookupListener() {
49.142 + public void resultChanged(LookupEvent event) {
49.143 + result.append('B');
49.144 + }
49.145 + };
49.146 +
49.147 + private StringBuffer result=new StringBuffer();
49.148 +
49.149 + //
49.150 +
49.151 + public TestLookupManager() {
49.152 + Lookup.Template<TestLookupItemA> templateA=
49.153 + new Lookup.Template<TestLookupItemA>(TestLookupItemA.class);
49.154 + resultA=abstractLookup.lookup(templateA);
49.155 + resultA.addLookupListener(listenerA);
49.156 + resultA.allInstances().size();
49.157 + //
49.158 + Lookup.Template<TestLookupItemB> templateB=
49.159 + new Lookup.Template<TestLookupItemB>(TestLookupItemB.class);
49.160 + resultB=abstractLookup.lookup(templateB);
49.161 + resultB.addLookupListener(listenerB);
49.162 + resultB.allInstances().size();
49.163 + // WORKAROUND
49.164 + // instanceContent.add(Boolean.TRUE);
49.165 + }
49.166 +
49.167 + //
49.168 +
49.169 + public void add(Object item) {
49.170 + instanceContent.add(item);
49.171 + }
49.172 + public void remove(Object item) {
49.173 + instanceContent.remove(item);
49.174 + }
49.175 + public String getResult() {
49.176 + return result.toString();
49.177 + }
49.178 + }
49.179 +
49.180 +}
50.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
50.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/LookupBugTest.java Sat Oct 31 15:28:13 2009 +0100
50.3 @@ -0,0 +1,79 @@
50.4 +package org.openide.util.lookup;
50.5 +
50.6 +import java.util.logging.Logger;
50.7 +import org.junit.Before;
50.8 +import org.junit.Test;
50.9 +import org.openide.util.Lookup;
50.10 +import org.openide.util.LookupEvent;
50.11 +import org.openide.util.LookupListener;
50.12 +import static org.junit.Assert.*;
50.13 +
50.14 +/**
50.15 + * Test of a Lookup bug seen in NetBeans platforms 6.0-6.5M1.
50.16 + * @author rlee
50.17 + */
50.18 +public class LookupBugTest implements LookupListener
50.19 +{
50.20 + private static final int MAX_LOOPS = 1000;
50.21 +
50.22 + private AbstractLookup lookup;
50.23 + private InstanceContent content;
50.24 + private Lookup.Result<String> wordResult;
50.25 + private Lookup.Result<Integer> numberResult;
50.26 + private String word;
50.27 + private Integer number;
50.28 + private Logger LOG;
50.29 +
50.30 + private boolean fired;
50.31 + private int i;
50.32 +
50.33 + @Before
50.34 + public void setUp()
50.35 + {
50.36 + LOG = Logger.getLogger("test.LookupBugTest");
50.37 + content = new InstanceContent();
50.38 + lookup = new AbstractLookup(content);
50.39 + wordResult = lookup.lookupResult(java.lang.String.class);
50.40 + wordResult.addLookupListener(this);
50.41 + numberResult = lookup.lookupResult(java.lang.Integer.class);
50.42 + numberResult.addLookupListener(this);
50.43 +
50.44 + fired = false;
50.45 + }
50.46 +
50.47 + @Test
50.48 + public void lookupTest()
50.49 + {
50.50 + for(i = 0; i < MAX_LOOPS; i++ )
50.51 + {
50.52 + word = String.valueOf(i);
50.53 + number = new Integer(i);
50.54 + content.add(word);
50.55 + assertTrue( "word on loop " + i, checkLookupEventFired() );
50.56 + content.add(number);
50.57 + assertTrue( "number on loop " + i, checkLookupEventFired() );
50.58 + content.remove(word);
50.59 + assertTrue( "remove word on loop " + i, checkLookupEventFired() );
50.60 + content.remove(number);
50.61 + assertTrue( "remove number on loop " + i, checkLookupEventFired() );
50.62 +
50.63 + assertTrue("The lookup still needs to stay simple", AbstractLookup.isSimple(lookup));
50.64 + }
50.65 + }
50.66 +
50.67 + public void resultChanged(LookupEvent ev)
50.68 + {
50.69 + fired = true;
50.70 + }
50.71 +
50.72 + public boolean checkLookupEventFired()
50.73 + {
50.74 + LOG.fine(" round: " + i + " word = " + word + " number = " + number);
50.75 + if( fired )
50.76 + {
50.77 + fired = false;
50.78 + return true;
50.79 + }
50.80 + else return false;
50.81 + }
50.82 +}
51.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
51.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/LookupsProxyTest.java Sat Oct 31 15:28:13 2009 +0100
51.3 @@ -0,0 +1,282 @@
51.4 +/*
51.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
51.6 + *
51.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
51.8 + *
51.9 + * The contents of this file are subject to the terms of either the GNU
51.10 + * General Public License Version 2 only ("GPL") or the Common
51.11 + * Development and Distribution License("CDDL") (collectively, the
51.12 + * "License"). You may not use this file except in compliance with the
51.13 + * License. You can obtain a copy of the License at
51.14 + * http://www.netbeans.org/cddl-gplv2.html
51.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
51.16 + * specific language governing permissions and limitations under the
51.17 + * License. When distributing the software, include this License Header
51.18 + * Notice in each file and include the License file at
51.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
51.20 + * particular file as subject to the "Classpath" exception as provided
51.21 + * by Sun in the GPL Version 2 section of the License file that
51.22 + * accompanied this code. If applicable, add the following below the
51.23 + * License Header, with the fields enclosed by brackets [] replaced by
51.24 + * your own identifying information:
51.25 + * "Portions Copyrighted [year] [name of copyright owner]"
51.26 + *
51.27 + * Contributor(s):
51.28 + *
51.29 + * The Original Software is NetBeans. The Initial Developer of the Original
51.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
51.31 + * Microsystems, Inc. All Rights Reserved.
51.32 + *
51.33 + * If you wish your version of this file to be governed by only the CDDL
51.34 + * or only the GPL Version 2, indicate your decision by adding
51.35 + * "[Contributor] elects to include this software in this distribution
51.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
51.37 + * single choice of license, a recipient has the option to distribute
51.38 + * your version of this file under either the CDDL, the GPL Version 2 or
51.39 + * to extend the choice of license to its licensees as provided above.
51.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
51.41 + * Version 2 license, then the option applies only if the new code is
51.42 + * made subject to such option by the copyright holder.
51.43 + */
51.44 +
51.45 +package org.openide.util.lookup;
51.46 +
51.47 +import java.io.Serializable;
51.48 +
51.49 +import java.util.*;
51.50 +import org.netbeans.junit.*;
51.51 +import org.openide.util.Lookup;
51.52 +import org.openide.util.LookupEvent;
51.53 +import org.openide.util.LookupListener;
51.54 +
51.55 +/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
51.56 + */
51.57 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
51.58 +public class LookupsProxyTest extends AbstractLookupBaseHid
51.59 +implements AbstractLookupBaseHid.Impl {
51.60 + public LookupsProxyTest(java.lang.String testName) {
51.61 + super(testName, null);
51.62 + }
51.63 +
51.64 + public static void main(java.lang.String[] args) {
51.65 + junit.textui.TestRunner.run(new NbTestSuite (LookupsProxyTest.class));
51.66 + }
51.67 +
51.68 + /** Creates an lookup for given lookup. This class just returns
51.69 + * the object passed in, but subclasses can be different.
51.70 + * @param lookup in lookup
51.71 + * @return a lookup to use
51.72 + */
51.73 + public Lookup createLookup (final Lookup lookup) {
51.74 + return org.openide.util.lookup.Lookups.proxy (
51.75 + new Lookup.Provider () {
51.76 + public Lookup getLookup () {
51.77 + return lookup;
51.78 + }
51.79 + }
51.80 + );
51.81 + }
51.82 +
51.83 + public Lookup createInstancesLookup (InstanceContent ic) {
51.84 + return new AbstractLookup (ic);
51.85 + }
51.86 +
51.87 + public void clearCaches () {
51.88 + }
51.89 +
51.90 +
51.91 +
51.92 + /** Check whether setLookups method does not fire when there is no
51.93 + * change in the lookups.
51.94 + */
51.95 + public void testProxyListener () {
51.96 + Changer ch = new Changer (Lookup.EMPTY);
51.97 +
51.98 + Lookup lookup = Lookups.proxy(ch);
51.99 + Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
51.100 +
51.101 + LL ll = new LL ();
51.102 + res.addLookupListener (ll);
51.103 + Collection allRes = res.allInstances ();
51.104 +
51.105 + ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
51.106 + lookup.lookup (Object.class); // does the refresh
51.107 +
51.108 + assertEquals("Replacing an empty by empty does not generate an event", 0, ll.getCount());
51.109 +
51.110 + InstanceContent content = new InstanceContent ();
51.111 + AbstractLookup del = new AbstractLookup (content);
51.112 + content.add (this);
51.113 + ch.setLookup (del);
51.114 + lookup.lookup (Object.class);
51.115 +
51.116 + if (ll.getCount () != 1) {
51.117 + fail ("Changing lookups with different content generates an event");
51.118 + }
51.119 +
51.120 + ch.setLookup (del);
51.121 + lookup.lookup (Object.class);
51.122 +
51.123 + if (ll.getCount () != 0) {
51.124 + fail ("Not changing the lookups does not generate any event");
51.125 + }
51.126 + }
51.127 +
51.128 +
51.129 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
51.130 + doListeningAndQueryingByTwoListenersSetLookups(0, 1, false);
51.131 + }
51.132 + public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
51.133 + doListeningAndQueryingByTwoListenersSetLookups(1, 1, false);
51.134 + }
51.135 + public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
51.136 + doListeningAndQueryingByTwoListenersSetLookups(2, 1, false);
51.137 + }
51.138 +
51.139 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
51.140 + doListeningAndQueryingByTwoListenersSetLookups(0, 2, false);
51.141 + }
51.142 + public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
51.143 + doListeningAndQueryingByTwoListenersSetLookups(1, 2, false);
51.144 + }
51.145 + public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
51.146 + doListeningAndQueryingByTwoListenersSetLookups(2, 2, false);
51.147 + }
51.148 +
51.149 + public void testListeningAndQueryingByTwoListenersInstancesSetLookupsWithProxy() {
51.150 + doListeningAndQueryingByTwoListenersSetLookups(0, 1, true);
51.151 + }
51.152 + public void testListeningAndQueryingByTwoListenersClassesSetLookupsWithProxy() {
51.153 + doListeningAndQueryingByTwoListenersSetLookups(1, 1, true);
51.154 + }
51.155 + public void testListeningAndQueryingByTwoListenersItemsSetLookupsWithProxy() {
51.156 + doListeningAndQueryingByTwoListenersSetLookups(2, 1, true);
51.157 + }
51.158 +
51.159 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups2WithProxy() {
51.160 + doListeningAndQueryingByTwoListenersSetLookups(0, 2, true);
51.161 + }
51.162 + public void testListeningAndQueryingByTwoListenersClassesSetLookups2WithProxy() {
51.163 + doListeningAndQueryingByTwoListenersSetLookups(1, 2, true);
51.164 + }
51.165 + public void testListeningAndQueryingByTwoListenersItemsSetLookups2WithProxy() {
51.166 + doListeningAndQueryingByTwoListenersSetLookups(2, 2, true);
51.167 + }
51.168 +
51.169 + /* XXX: these are pretty slow, seems there is a performance problem 2^22
51.170 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
51.171 + doListeningAndQueryingByTwoListenersSetLookups(0, 22);
51.172 + }
51.173 + public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
51.174 + doListeningAndQueryingByTwoListenersSetLookups(1, 22);
51.175 + }
51.176 + public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
51.177 + doListeningAndQueryingByTwoListenersSetLookups(2, 22);
51.178 + }
51.179 + */
51.180 +
51.181 + private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth, boolean cacheOnTop) {
51.182 + Changer orig = new Changer(Lookup.EMPTY);
51.183 + Lookup on = Lookups.proxy(orig);
51.184 + Lookup first = on;
51.185 +
51.186 + while (--depth > 0) {
51.187 + Changer next = new Changer(on);
51.188 + on = Lookups.proxy(next);
51.189 + }
51.190 +
51.191 +
51.192 + final Lookup lookup = cacheOnTop ? new ProxyLookup(new Lookup[] { on }) : on;
51.193 +
51.194 + class L implements LookupListener {
51.195 + Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
51.196 + Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
51.197 + Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
51.198 +
51.199 + {
51.200 + integer.addLookupListener(this);
51.201 + number.addLookupListener(this);
51.202 + serial.addLookupListener(this);
51.203 + }
51.204 +
51.205 + int round;
51.206 +
51.207 + public void resultChanged(LookupEvent ev) {
51.208 + Collection c1 = get(type, integer);
51.209 + Collection c2 = get(type, number);
51.210 + Collection c3 = get(type, serial);
51.211 +
51.212 + assertEquals("round " + round + " c1 vs. c2", c1, c2);
51.213 + assertEquals("round " + round + " c1 vs. c3", c1, c3);
51.214 + assertEquals("round " + round + " c2 vs. c3", c2, c3);
51.215 +
51.216 + round++;
51.217 + }
51.218 +
51.219 + private Collection get(int type, Lookup.Result res) {
51.220 + Collection c;
51.221 + switch(type) {
51.222 + case 0: c = res.allInstances(); break;
51.223 + case 1: c = res.allClasses(); break;
51.224 + case 2: c = res.allItems(); break;
51.225 + default: c = null; fail("Type: " + type); break;
51.226 + }
51.227 +
51.228 + assertNotNull(c);
51.229 + return new ArrayList(c);
51.230 + }
51.231 + }
51.232 +
51.233 + L listener = new L();
51.234 + listener.resultChanged(null);
51.235 + ArrayList arr = new ArrayList();
51.236 + for(int i = 0; i < 100; i++) {
51.237 + arr.add(new Integer(i));
51.238 +
51.239 + orig.lookup = Lookups.fixed(arr.toArray());
51.240 + // do the refresh
51.241 + first.lookup((Class)null);
51.242 + }
51.243 +
51.244 + assertEquals("3x100+1 checks", 301, listener.round);
51.245 + }
51.246 +
51.247 +
51.248 + public void testRefreshWithoutAllInstances103300 () {
51.249 + Changer ch = new Changer (Lookup.EMPTY);
51.250 +
51.251 + Lookup lookup = Lookups.proxy(ch);
51.252 +
51.253 + ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
51.254 + assertNull("Nothing there", lookup.lookup (Object.class)); // does the refresh
51.255 +
51.256 + InstanceContent content = new InstanceContent ();
51.257 + AbstractLookup del = new AbstractLookup (content);
51.258 + content.add (this);
51.259 + ch.setLookup (del);
51.260 + assertEquals("Can see me", this, lookup.lookup (Object.class));
51.261 +
51.262 + ch.setLookup (del);
51.263 + assertEquals("Still can see me", this, lookup.lookup (Object.class));
51.264 +
51.265 + assertEquals("I am visible", this, lookup.lookup(LookupsProxyTest.class));
51.266 + }
51.267 +
51.268 +
51.269 + private static final class Changer implements Lookup.Provider {
51.270 + private Lookup lookup;
51.271 +
51.272 + public Changer (Lookup lookup) {
51.273 + setLookup (lookup);
51.274 + }
51.275 +
51.276 + public void setLookup (Lookup lookup) {
51.277 + this.lookup = lookup;
51.278 + }
51.279 +
51.280 + public Lookup getLookup() {
51.281 + return lookup;
51.282 + }
51.283 + }
51.284 +
51.285 +}
52.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
52.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTest.java Sat Oct 31 15:28:13 2009 +0100
52.3 @@ -0,0 +1,550 @@
52.4 +/*
52.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
52.6 + *
52.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
52.8 + *
52.9 + * The contents of this file are subject to the terms of either the GNU
52.10 + * General Public License Version 2 only ("GPL") or the Common
52.11 + * Development and Distribution License("CDDL") (collectively, the
52.12 + * "License"). You may not use this file except in compliance with the
52.13 + * License. You can obtain a copy of the License at
52.14 + * http://www.netbeans.org/cddl-gplv2.html
52.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
52.16 + * specific language governing permissions and limitations under the
52.17 + * License. When distributing the software, include this License Header
52.18 + * Notice in each file and include the License file at
52.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
52.20 + * particular file as subject to the "Classpath" exception as provided
52.21 + * by Sun in the GPL Version 2 section of the License file that
52.22 + * accompanied this code. If applicable, add the following below the
52.23 + * License Header, with the fields enclosed by brackets [] replaced by
52.24 + * your own identifying information:
52.25 + * "Portions Copyrighted [year] [name of copyright owner]"
52.26 + *
52.27 + * Contributor(s):
52.28 + *
52.29 + * The Original Software is NetBeans. The Initial Developer of the Original
52.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
52.31 + * Microsystems, Inc. All Rights Reserved.
52.32 + *
52.33 + * If you wish your version of this file to be governed by only the CDDL
52.34 + * or only the GPL Version 2, indicate your decision by adding
52.35 + * "[Contributor] elects to include this software in this distribution
52.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
52.37 + * single choice of license, a recipient has the option to distribute
52.38 + * your version of this file under either the CDDL, the GPL Version 2 or
52.39 + * to extend the choice of license to its licensees as provided above.
52.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
52.41 + * Version 2 license, then the option applies only if the new code is
52.42 + * made subject to such option by the copyright holder.
52.43 + */
52.44 +
52.45 +package org.openide.util.lookup;
52.46 +
52.47 +import java.io.ByteArrayInputStream;
52.48 +import java.io.File;
52.49 +import java.io.FileOutputStream;
52.50 +import java.io.IOException;
52.51 +import java.io.InputStream;
52.52 +import java.io.InputStreamReader;
52.53 +import java.lang.ref.Reference;
52.54 +import java.lang.ref.WeakReference;
52.55 +import java.net.URL;
52.56 +import java.net.URLClassLoader;
52.57 +import java.net.URLConnection;
52.58 +import java.net.URLStreamHandler;
52.59 +import java.util.ArrayList;
52.60 +import java.util.Collection;
52.61 +import java.util.Collections;
52.62 +import java.util.Comparator;
52.63 +import java.util.Enumeration;
52.64 +import java.util.HashSet;
52.65 +import java.util.Iterator;
52.66 +import java.util.List;
52.67 +import java.util.Map;
52.68 +import java.util.Set;
52.69 +import java.util.TreeSet;
52.70 +import java.util.WeakHashMap;
52.71 +import java.util.concurrent.atomic.AtomicBoolean;
52.72 +import java.util.jar.JarEntry;
52.73 +import java.util.jar.JarOutputStream;
52.74 +import java.util.logging.Level;
52.75 +import java.util.logging.Logger;
52.76 +import java.util.regex.Matcher;
52.77 +import java.util.regex.Pattern;
52.78 +import org.bar.Comparator2;
52.79 +import org.netbeans.junit.MockServices;
52.80 +import org.netbeans.junit.NbTestCase;
52.81 +import org.openide.util.Enumerations;
52.82 +import org.openide.util.Exceptions;
52.83 +import org.openide.util.Lookup;
52.84 +import org.openide.util.LookupEvent;
52.85 +import org.openide.util.LookupListener;
52.86 +import org.openide.util.test.MockLookup;
52.87 +
52.88 +/** Test finding services from manifest.
52.89 + * @author Jesse Glick
52.90 + */
52.91 +public class MetaInfServicesLookupTest extends NbTestCase {
52.92 + private Logger LOG;
52.93 + private Map<ClassLoader,Lookup> lookups = new WeakHashMap<ClassLoader,Lookup>();
52.94 +
52.95 + public MetaInfServicesLookupTest(String name) {
52.96 + super(name);
52.97 + LOG = Logger.getLogger("Test." + name);
52.98 + }
52.99 +
52.100 + protected String prefix() {
52.101 + return "META-INF/services/";
52.102 + }
52.103 +
52.104 + protected Lookup createLookup(ClassLoader c) {
52.105 + return Lookups.metaInfServices(c);
52.106 + }
52.107 +
52.108 + @Override
52.109 + protected Level logLevel() {
52.110 + return Level.INFO;
52.111 + }
52.112 +
52.113 + private Lookup getTestedLookup(ClassLoader c) {
52.114 + MockServices.setServices();
52.115 + Lookup l = lookups.get(c);
52.116 + if (l == null) {
52.117 + l = createLookup(c);
52.118 + lookups.put(c, l);
52.119 + }
52.120 + return l;
52.121 + }
52.122 +
52.123 + private URL findJar(String n) throws IOException {
52.124 + LOG.info("Looking for " + n);
52.125 + File jarDir = new File(getWorkDir(), "jars");
52.126 + jarDir.mkdirs();
52.127 + File jar = new File(jarDir, n);
52.128 + if (jar.exists()) {
52.129 + return jar.toURI().toURL();
52.130 + }
52.131 +
52.132 + LOG.info("generating " + jar);
52.133 +
52.134 + URL data = MetaInfServicesLookupTest.class.getResource(n.replaceAll("\\.jar", "\\.txt"));
52.135 + assertNotNull("Data found", data);
52.136 + StringBuffer sb = new StringBuffer();
52.137 + InputStreamReader r = new InputStreamReader(data.openStream());
52.138 + for(;;) {
52.139 + int ch = r.read();
52.140 + if (ch == -1) {
52.141 + break;
52.142 + }
52.143 + sb.append((char)ch);
52.144 + }
52.145 +
52.146 + JarOutputStream os = new JarOutputStream(new FileOutputStream(jar));
52.147 +
52.148 + Pattern p = Pattern.compile(":([^:]+):([^:]*)", Pattern.MULTILINE | Pattern.DOTALL);
52.149 + Matcher m = p.matcher(sb);
52.150 + Pattern foobar = Pattern.compile("^(org\\.(foo|bar)\\..*)$", Pattern.MULTILINE);
52.151 + Set<String> names = new TreeSet<String>();
52.152 + while (m.find()) {
52.153 + assert m.groupCount() == 2;
52.154 + String entryName = prefix() + m.group(1);
52.155 + LOG.info("putting there entry: " + entryName);
52.156 + os.putNextEntry(new JarEntry(entryName));
52.157 + os.write(m.group(2).getBytes());
52.158 + os.closeEntry();
52.159 +
52.160 + Matcher fb = foobar.matcher(m.group(2));
52.161 + while (fb.find()) {
52.162 + String clazz = fb.group(1).replace('.', '/') + ".class";
52.163 + LOG.info("will copy " + clazz);
52.164 + names.add(clazz);
52.165 + }
52.166 + }
52.167 +
52.168 + for (String copy : names) {
52.169 + os.putNextEntry(new JarEntry(copy));
52.170 + LOG.info("copying " + copy);
52.171 + InputStream from = MetaInfServicesLookupTest.class.getResourceAsStream("/" + copy);
52.172 + assertNotNull(copy, from);
52.173 + for (;;) {
52.174 + int ch = from.read();
52.175 + if (ch == -1) {
52.176 + break;
52.177 + }
52.178 + os.write(ch);
52.179 + }
52.180 + from.close();
52.181 + os.closeEntry();
52.182 + }
52.183 + os.close();
52.184 + LOG.info("done " + jar);
52.185 + return jar.toURI().toURL();
52.186 + }
52.187 +
52.188 + ClassLoader c1, c2, c2a, c3, c4;
52.189 +
52.190 + @Override
52.191 + protected void setUp() throws Exception {
52.192 + clearWorkDir();
52.193 + ClassLoader app = getClass().getClassLoader().getParent();
52.194 + ClassLoader c0 = app;
52.195 +
52.196 + c1 = new URLClassLoader(new URL[] {
52.197 + findJar("services-jar-1.jar"),
52.198 + }, c0);
52.199 + c2 = new URLClassLoader(new URL[] {
52.200 + findJar("services-jar-2.jar"),
52.201 + }, c1);
52.202 + c2a = new URLClassLoader(new URL[] {
52.203 + findJar("services-jar-2.jar"),
52.204 + }, c1);
52.205 + c3 = new URLClassLoader(new URL[] { findJar("services-jar-2.jar") },
52.206 + c0
52.207 + );
52.208 + c4 = new URLClassLoader(new URL[] {
52.209 + findJar("services-jar-1.jar"),
52.210 + findJar("services-jar-2.jar"),
52.211 + }, c0);
52.212 + }
52.213 +
52.214 + @Override
52.215 + protected void tearDown() throws Exception {
52.216 + Set<Reference<Lookup>> weak = new HashSet<Reference<Lookup>>();
52.217 + for (Lookup l : lookups.values()) {
52.218 + weak.add(new WeakReference<Lookup>(l));
52.219 + }
52.220 +
52.221 + lookups = null;
52.222 +
52.223 + for(Reference<Lookup> ref : weak) {
52.224 + assertGC("Lookup can disappear", ref);
52.225 + }
52.226 + }
52.227 +
52.228 + public void testBasicUsage() throws Exception {
52.229 + Lookup l = getTestedLookup(c2);
52.230 + Class<?> xface = c1.loadClass("org.foo.Interface");
52.231 + List<?> results = new ArrayList<Object>(l.lookupAll(xface));
52.232 + assertEquals("Two items in result: " + results, 2, results.size());
52.233 + // Note that they have to be in order:
52.234 + assertEquals("org.foo.impl.Implementation1", results.get(0).getClass().getName());
52.235 + assertEquals("org.bar.Implementation2", results.get(1).getClass().getName());
52.236 + // Make sure it does not gratuitously replace items:
52.237 + List<?> results2 = new ArrayList<Object>(l.lookupAll(xface));
52.238 + assertEquals(results, results2);
52.239 + }
52.240 +
52.241 + public void testLoaderSkew() throws Exception {
52.242 + Class<?> xface1 = c1.loadClass("org.foo.Interface");
52.243 + Lookup l3 = getTestedLookup(c3);
52.244 + // If we cannot load Interface, there should be no impls of course... quietly!
52.245 + assertEquals(Collections.emptyList(),
52.246 + new ArrayList<Object>(l3.lookupAll(xface1)));
52.247 + Lookup l4 = getTestedLookup(c4);
52.248 + // If we can load Interface but it is the wrong one, ignore it.
52.249 + assertEquals(Collections.emptyList(),
52.250 + new ArrayList<Object>(l4.lookupAll(xface1)));
52.251 + // Make sure l4 is really OK - it can load from its own JARs.
52.252 + Class<?> xface4 = c4.loadClass("org.foo.Interface");
52.253 + assertEquals(2, l4.lookupAll(xface4).size());
52.254 + }
52.255 +
52.256 + public void testStability() throws Exception {
52.257 + Lookup l = getTestedLookup(c2);
52.258 + Class<?> xface = c1.loadClass("org.foo.Interface");
52.259 + Object first = l.lookup(xface);
52.260 + assertEquals(first, l.lookupAll(xface).iterator().next());
52.261 + l = getTestedLookup(c2a);
52.262 + Object second = l.lookup(xface);
52.263 + assertEquals(first, second);
52.264 + }
52.265 +
52.266 + public void testMaskingOfResources() throws Exception {
52.267 + Lookup l1 = getTestedLookup(c1);
52.268 + Lookup l2 = getTestedLookup(c2);
52.269 + Lookup l4 = getTestedLookup(c4);
52.270 +
52.271 + assertNotNull("services1.jar defines a class that implements runnable", l1.lookup(Runnable.class));
52.272 + assertNull("services2.jar does not defines a class that implements runnable", l2.lookup(Runnable.class));
52.273 + assertNull("services1.jar defines Runnable, but services2.jar masks it out", l4.lookup(Runnable.class));
52.274 + }
52.275 +
52.276 + public void testOrdering() throws Exception {
52.277 + Lookup l = getTestedLookup(c1);
52.278 + Class<?> xface = c1.loadClass("java.util.Comparator");
52.279 + List<?> results = new ArrayList<Object>(l.lookupAll(xface));
52.280 + assertEquals(1, results.size());
52.281 +
52.282 + l = getTestedLookup(c2);
52.283 + xface = c2.loadClass("java.util.Comparator");
52.284 + results = new ArrayList<Object>(l.lookupAll(xface));
52.285 + assertEquals(2, results.size());
52.286 + // Test order:
52.287 + assertEquals("org.bar.Comparator2", results.get(0).getClass().getName());
52.288 + assertEquals("org.foo.impl.Comparator1", results.get(1).getClass().getName());
52.289 +
52.290 + // test that items without position are always at the end
52.291 + l = getTestedLookup(c2);
52.292 + xface = c2.loadClass("java.util.Iterator");
52.293 + results = new ArrayList<Object>(l.lookupAll(xface));
52.294 + assertEquals(2, results.size());
52.295 + // Test order:
52.296 + assertEquals("org.bar.Iterator2", results.get(0).getClass().getName());
52.297 + assertEquals("org.foo.impl.Iterator1", results.get(1).getClass().getName());
52.298 + }
52.299 +
52.300 + public void testNoCallToGetResourceForObjectIssue65124() throws Exception {
52.301 + class Loader extends ClassLoader {
52.302 + private int counter;
52.303 +
52.304 + @Override
52.305 + protected URL findResource(String name) {
52.306 + if (name.equals(prefix() + "java.lang.Object")) {
52.307 + counter++;
52.308 + }
52.309 +
52.310 + URL retValue;
52.311 +
52.312 + retValue = super.findResource(name);
52.313 + return retValue;
52.314 + }
52.315 +
52.316 + @Override
52.317 + protected Enumeration<URL> findResources(String name) throws IOException {
52.318 + if (name.equals(prefix() + "java.lang.Object")) {
52.319 + counter++;
52.320 + }
52.321 + return super.findResources(name);
52.322 + }
52.323 + }
52.324 + Loader loader = new Loader();
52.325 + Lookup l = getTestedLookup(loader);
52.326 +
52.327 + Object no = l.lookup(String.class);
52.328 + assertNull("Not found of course", no);
52.329 + assertEquals("No lookup of Object", 0, loader.counter);
52.330 + }
52.331 +
52.332 + public void testCanGarbageCollectClasses() throws Exception {
52.333 + class Loader extends ClassLoader {
52.334 + public Loader() {
52.335 + super(Loader.class.getClassLoader().getParent());
52.336 + }
52.337 +
52.338 + @Override
52.339 + protected URL findResource(String name) {
52.340 + if (name.equals(prefix() + "java.lang.Runnable")) {
52.341 + return Loader.class.getResource("MetaInfServicesLookupTestRunnable.txt");
52.342 + }
52.343 +
52.344 + URL retValue;
52.345 +
52.346 + retValue = super.findResource(name);
52.347 + return retValue;
52.348 + }
52.349 +
52.350 + @Override
52.351 + protected Class<?> findClass(String name) throws ClassNotFoundException {
52.352 + if (name.equals("org.openide.util.lookup.MetaInfServicesLookupTestRunnable")) {
52.353 + try {
52.354 + InputStream is = getClass().getResourceAsStream("MetaInfServicesLookupTestRunnable.class");
52.355 + byte[] arr = new byte[is.available()];
52.356 + int read = is.read(arr);
52.357 + assertEquals("Fully read", arr.length, read);
52.358 + return defineClass(name, arr, 0, arr.length);
52.359 + } catch (IOException ex) {
52.360 + throw new ClassNotFoundException("Cannot load", ex);
52.361 + }
52.362 + }
52.363 + throw new ClassNotFoundException();
52.364 + }
52.365 +
52.366 +
52.367 +
52.368 + @Override
52.369 + protected Enumeration<URL> findResources(String name) throws IOException {
52.370 + if (name.equals(prefix() + "java.lang.Runnable")) {
52.371 + return Collections.enumeration(Collections.singleton(findResource(name)));
52.372 + }
52.373 + return super.findResources(name);
52.374 + }
52.375 + }
52.376 + Loader loader = new Loader();
52.377 + Lookup l = getTestedLookup(loader);
52.378 +
52.379 +
52.380 + Object no = l.lookup(Runnable.class);
52.381 + assertNotNull("Found of course", no);
52.382 + assertEquals("The right name", "MetaInfServicesLookupTestRunnable", no.getClass().getSimpleName());
52.383 + if (no.getClass().getClassLoader() != loader) {
52.384 + fail("Wrong classloader: " + no.getClass().getClassLoader());
52.385 + }
52.386 +
52.387 + WeakReference<Object> ref = new WeakReference<Object>(no.getClass());
52.388 + loader = null;
52.389 + no = null;
52.390 + l = null;
52.391 + lookups.clear();
52.392 + MockLookup.setInstances();
52.393 + Thread.currentThread().setContextClassLoader(null);
52.394 + assertGC("Class can be garbage collected", ref);
52.395 + }
52.396 +
52.397 + public void testSuperTypes() throws Exception {
52.398 + doTestSuperTypes(createLookup(c2));
52.399 + doTestSuperTypes(new ProxyLookup(createLookup(c2)));
52.400 + }
52.401 + private void doTestSuperTypes(Lookup l) throws Exception {
52.402 + final Class<?> xface = c1.loadClass("org.foo.Interface");
52.403 + final Lookup.Result<Object> res = l.lookupResult(Object.class);
52.404 + assertEquals("Nothing yet", 0, res.allInstances().size());
52.405 + final AtomicBoolean event = new AtomicBoolean();
52.406 + final Thread here = Thread.currentThread();
52.407 + res.addLookupListener(new LookupListener() {
52.408 + public void resultChanged(LookupEvent ev) {
52.409 + if (Thread.currentThread() == here) {
52.410 + event.set(true);
52.411 + }
52.412 + }
52.413 + });
52.414 + assertNotNull("Interface found", l.lookup(xface));
52.415 + assertFalse(event.get());
52.416 + class W implements Runnable {
52.417 + boolean ok;
52.418 + public synchronized void run() {
52.419 + ok = true;
52.420 + notifyAll();
52.421 + }
52.422 +
52.423 + public synchronized void await() throws Exception {
52.424 + while (!ok) {
52.425 + wait();
52.426 + }
52.427 + }
52.428 + }
52.429 + W w = new W();
52.430 + MetaInfServicesLookup.RP.execute(w);
52.431 + w.await();
52.432 + assertEquals("Now two", 2, res.allInstances().size());
52.433 + }
52.434 +
52.435 + public void testWrongOrderAsInIssue100320() throws Exception {
52.436 + ClassLoader app = getClass().getClassLoader().getParent();
52.437 + ClassLoader c0 = app;
52.438 + ClassLoader ctmp = new URLClassLoader(new URL[] {
52.439 + findJar("problem100320.jar"),
52.440 + }, c0);
52.441 + Lookup lookup = Lookups.metaInfServices(ctmp, prefix());
52.442 +
52.443 + Collection<?> colAWT = lookup.lookupAll(IOException.class);
52.444 + assertEquals("There is enough objects to switch to InheritanceTree", 12, colAWT.size());
52.445 +
52.446 +
52.447 + List<?> col1 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
52.448 + assertEquals("Two", 2, col1.size());
52.449 + Collection<?> col2 = lookup.lookupAll(ctmp.loadClass(Comparator2.class.getName()));
52.450 + assertEquals("One", 1, col2.size());
52.451 + List<?> col3 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
52.452 + assertEquals("Two2", 2, col3.size());
52.453 +
52.454 + Iterator<?> it1 = col1.iterator();
52.455 + Iterator<?> it3 = col3.iterator();
52.456 + if (
52.457 + it1.next() != it3.next() ||
52.458 + it1.next() != it3.next()
52.459 + ) {
52.460 + fail("Collections are different:\nFirst: " + col1 + "\nLast: " + col3);
52.461 + }
52.462 + }
52.463 +
52.464 + public void testContentionWhenLoadingMetainfServices() throws Exception {
52.465 + class My extends ClassLoader implements Runnable {
52.466 + Lookup query;
52.467 + Integer value;
52.468 +
52.469 + public void run() {
52.470 + value = query.lookup(Integer.class);
52.471 + }
52.472 +
52.473 +
52.474 + @Override
52.475 + protected URL findResource(String name) {
52.476 + waitForTask(name);
52.477 + return super.findResource(name);
52.478 + }
52.479 +
52.480 + @Override
52.481 + protected Enumeration<URL> findResources(String name) throws IOException {
52.482 + waitForTask(name);
52.483 + return super.findResources(name);
52.484 + }
52.485 +
52.486 + private synchronized void waitForTask(String name) {
52.487 + if (name.startsWith(prefix()) && Thread.currentThread().getName().contains("block")) {
52.488 + try {
52.489 + wait();
52.490 + } catch (InterruptedException ex) {
52.491 + Exceptions.printStackTrace(ex);
52.492 + }
52.493 + }
52.494 + }
52.495 + }
52.496 +
52.497 + My loader = new My();
52.498 + loader.query = createLookup(loader);
52.499 + Thread t = new Thread(loader, "block when querying");
52.500 + t.start();
52.501 + t.join(1000);
52.502 +
52.503 + // this blocks waiting for the waitForTask to finish
52.504 + // right now
52.505 + Float f = loader.query.lookup(Float.class);
52.506 + assertNull("Nothing found", f);
52.507 +
52.508 + synchronized (loader) {
52.509 + loader.notifyAll();
52.510 + }
52.511 + t.join();
52.512 +
52.513 + assertNull("Nothing found", loader.value);
52.514 + }
52.515 +
52.516 + public void testInitializerRobustness() throws Exception { // #174055
52.517 + check(Broken1.class.getName());
52.518 + check(Broken2.class.getName());
52.519 + }
52.520 + private void check(final String n) {
52.521 + assertNull(Lookups.metaInfServices(new ClassLoader() {
52.522 + protected @Override Enumeration<URL> findResources(String name) throws IOException {
52.523 + if (name.equals("META-INF/services/java.lang.Object")) {
52.524 + return Enumerations.singleton(new URL(null, "dummy:stuff", new URLStreamHandler() {
52.525 + protected URLConnection openConnection(URL u) throws IOException {
52.526 + return new URLConnection(u) {
52.527 + public void connect() throws IOException {}
52.528 + public @Override InputStream getInputStream() throws IOException {
52.529 + return new ByteArrayInputStream(n.getBytes("UTF-8"));
52.530 + }
52.531 + };
52.532 + }
52.533 + }));
52.534 + } else {
52.535 + return Enumerations.empty();
52.536 + }
52.537 + }
52.538 + }).lookup(Object.class));
52.539 + }
52.540 + public static class Broken1 {
52.541 + public Broken1() {
52.542 + throw new NullPointerException("broken1");
52.543 + }
52.544 + }
52.545 + public static class Broken2 {
52.546 + static {
52.547 + if (true) { // otherwise javac complains
52.548 + throw new NullPointerException("broken2");
52.549 + }
52.550 + }
52.551 + }
52.552 +
52.553 +}
53.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
53.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTestRunnable.java Sat Oct 31 15:28:13 2009 +0100
53.3 @@ -0,0 +1,50 @@
53.4 +/*
53.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
53.6 + *
53.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
53.8 + *
53.9 + * The contents of this file are subject to the terms of either the GNU
53.10 + * General Public License Version 2 only ("GPL") or the Common
53.11 + * Development and Distribution License("CDDL") (collectively, the
53.12 + * "License"). You may not use this file except in compliance with the
53.13 + * License. You can obtain a copy of the License at
53.14 + * http://www.netbeans.org/cddl-gplv2.html
53.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
53.16 + * specific language governing permissions and limitations under the
53.17 + * License. When distributing the software, include this License Header
53.18 + * Notice in each file and include the License file at
53.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
53.20 + * particular file as subject to the "Classpath" exception as provided
53.21 + * by Sun in the GPL Version 2 section of the License file that
53.22 + * accompanied this code. If applicable, add the following below the
53.23 + * License Header, with the fields enclosed by brackets [] replaced by
53.24 + * your own identifying information:
53.25 + * "Portions Copyrighted [year] [name of copyright owner]"
53.26 + *
53.27 + * Contributor(s):
53.28 + *
53.29 + * The Original Software is NetBeans. The Initial Developer of the Original
53.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
53.31 + * Microsystems, Inc. All Rights Reserved.
53.32 + *
53.33 + * If you wish your version of this file to be governed by only the CDDL
53.34 + * or only the GPL Version 2, indicate your decision by adding
53.35 + * "[Contributor] elects to include this software in this distribution
53.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
53.37 + * single choice of license, a recipient has the option to distribute
53.38 + * your version of this file under either the CDDL, the GPL Version 2 or
53.39 + * to extend the choice of license to its licensees as provided above.
53.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
53.41 + * Version 2 license, then the option applies only if the new code is
53.42 + * made subject to such option by the copyright holder.
53.43 + */
53.44 +
53.45 +package org.openide.util.lookup;
53.46 +
53.47 +
53.48 +/**
53.49 + */
53.50 +public final class MetaInfServicesLookupTestRunnable implements Runnable {
53.51 + public void run() {
53.52 + }
53.53 +}
54.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
54.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTestRunnable.txt Sat Oct 31 15:28:13 2009 +0100
54.3 @@ -0,0 +1,1 @@
54.4 +org.openide.util.lookup.MetaInfServicesLookupTestRunnable
55.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
55.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/NamedServicesLookupTest.java Sat Oct 31 15:28:13 2009 +0100
55.3 @@ -0,0 +1,85 @@
55.4 +/*
55.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
55.6 + *
55.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
55.8 + *
55.9 + * The contents of this file are subject to the terms of either the GNU
55.10 + * General Public License Version 2 only ("GPL") or the Common
55.11 + * Development and Distribution License("CDDL") (collectively, the
55.12 + * "License"). You may not use this file except in compliance with the
55.13 + * License. You can obtain a copy of the License at
55.14 + * http://www.netbeans.org/cddl-gplv2.html
55.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
55.16 + * specific language governing permissions and limitations under the
55.17 + * License. When distributing the software, include this License Header
55.18 + * Notice in each file and include the License file at
55.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
55.20 + * particular file as subject to the "Classpath" exception as provided
55.21 + * by Sun in the GPL Version 2 section of the License file that
55.22 + * accompanied this code. If applicable, add the following below the
55.23 + * License Header, with the fields enclosed by brackets [] replaced by
55.24 + * your own identifying information:
55.25 + * "Portions Copyrighted [year] [name of copyright owner]"
55.26 + *
55.27 + * Contributor(s):
55.28 + *
55.29 + * The Original Software is NetBeans. The Initial Developer of the Original
55.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
55.31 + * Microsystems, Inc. All Rights Reserved.
55.32 + *
55.33 + * If you wish your version of this file to be governed by only the CDDL
55.34 + * or only the GPL Version 2, indicate your decision by adding
55.35 + * "[Contributor] elects to include this software in this distribution
55.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
55.37 + * single choice of license, a recipient has the option to distribute
55.38 + * your version of this file under either the CDDL, the GPL Version 2 or
55.39 + * to extend the choice of license to its licensees as provided above.
55.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
55.41 + * Version 2 license, then the option applies only if the new code is
55.42 + * made subject to such option by the copyright holder.
55.43 + */
55.44 +
55.45 +package org.openide.util.lookup;
55.46 +
55.47 +import org.openide.util.Lookup;
55.48 +import org.openide.util.test.MockLookup;
55.49 +
55.50 +
55.51 +/** Test finding services from manifest.
55.52 + * @author Jaroslav Tulach
55.53 + */
55.54 +public class NamedServicesLookupTest extends MetaInfServicesLookupTest {
55.55 + static {
55.56 + MockLookup.init();
55.57 + }
55.58 + public NamedServicesLookupTest(String name) {
55.59 + super(name);
55.60 + }
55.61 +
55.62 + @Override
55.63 + protected String prefix() {
55.64 + return "META-INF/namedservices/sub/path/";
55.65 + }
55.66 +
55.67 + @Override
55.68 + protected Lookup createLookup(ClassLoader c) {
55.69 + MockLookup.setInstances(c);
55.70 + Thread.currentThread().setContextClassLoader(c);
55.71 + Lookup l = Lookups.forPath("sub/path");
55.72 + return l;
55.73 + }
55.74 +
55.75 + //
55.76 + // this is not much inheriting test, as we mask most of the tested methods
55.77 + // anyway, but the infrastructure to generate the JAR files is useful
55.78 + //
55.79 +
55.80 + public @Override void testLoaderSkew() {}
55.81 + public @Override void testStability() throws Exception {}
55.82 + public @Override void testMaskingOfResources() throws Exception {}
55.83 + public @Override void testOrdering() throws Exception {}
55.84 + public @Override void testNoCallToGetResourceForObjectIssue65124() throws Exception {}
55.85 + public @Override void testSuperTypes() throws Exception {}
55.86 + public @Override void testWrongOrderAsInIssue100320() throws Exception {}
55.87 +
55.88 +}
56.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
56.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/PathInLookupTest.java Sat Oct 31 15:28:13 2009 +0100
56.3 @@ -0,0 +1,112 @@
56.4 +/*
56.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
56.6 + *
56.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
56.8 + *
56.9 + * The contents of this file are subject to the terms of either the GNU
56.10 + * General Public License Version 2 only ("GPL") or the Common
56.11 + * Development and Distribution License("CDDL") (collectively, the
56.12 + * "License"). You may not use this file except in compliance with the
56.13 + * License. You can obtain a copy of the License at
56.14 + * http://www.netbeans.org/cddl-gplv2.html
56.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
56.16 + * specific language governing permissions and limitations under the
56.17 + * License. When distributing the software, include this License Header
56.18 + * Notice in each file and include the License file at
56.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
56.20 + * particular file as subject to the "Classpath" exception as provided
56.21 + * by Sun in the GPL Version 2 section of the License file that
56.22 + * accompanied this code. If applicable, add the following below the
56.23 + * License Header, with the fields enclosed by brackets [] replaced by
56.24 + * your own identifying information:
56.25 + * "Portions Copyrighted [year] [name of copyright owner]"
56.26 + *
56.27 + * Contributor(s):
56.28 + *
56.29 + * The Original Software is NetBeans. The Initial Developer of the Original
56.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
56.31 + * Microsystems, Inc. All Rights Reserved.
56.32 + *
56.33 + * If you wish your version of this file to be governed by only the CDDL
56.34 + * or only the GPL Version 2, indicate your decision by adding
56.35 + * "[Contributor] elects to include this software in this distribution
56.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
56.37 + * single choice of license, a recipient has the option to distribute
56.38 + * your version of this file under either the CDDL, the GPL Version 2 or
56.39 + * to extend the choice of license to its licensees as provided above.
56.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
56.41 + * Version 2 license, then the option applies only if the new code is
56.42 + * made subject to such option by the copyright holder.
56.43 + */
56.44 +
56.45 +package org.openide.util.lookup;
56.46 +
56.47 +import java.util.logging.Level;
56.48 +import org.netbeans.junit.MockServices;
56.49 +import org.netbeans.junit.NbTestCase;
56.50 +import org.netbeans.modules.openide.util.NamedServicesProvider;
56.51 +import org.openide.util.Lookup;
56.52 +
56.53 +/**
56.54 + * @author Jaroslav Tulach
56.55 + */
56.56 +public class PathInLookupTest extends NbTestCase {
56.57 + static {
56.58 + System.setProperty("org.openide.util.Lookup.paths", "MyServices:YourServices");
56.59 + MockServices.setServices(P.class);
56.60 + Lookup.getDefault();
56.61 + }
56.62 +
56.63 + public PathInLookupTest(String name) {
56.64 + super(name);
56.65 + }
56.66 +
56.67 + @Override
56.68 + protected Level logLevel() {
56.69 + return Level.FINE;
56.70 + }
56.71 +
56.72 + public void testInterfaceFoundInMyServices() throws Exception {
56.73 + assertNull("not found", Lookup.getDefault().lookup(Shared.class));
56.74 + Shared v = new Shared();
56.75 + P.ic1.add(v);
56.76 + assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
56.77 + P.ic1.remove(v);
56.78 + assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
56.79 + }
56.80 + public void testInterfaceFoundInMyServices2() throws Exception {
56.81 + assertNull("not found", Lookup.getDefault().lookup(Shared.class));
56.82 + Shared v = new Shared();
56.83 + P.ic2.add(v);
56.84 + assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
56.85 + P.ic2.remove(v);
56.86 + assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
56.87 + }
56.88 +
56.89 + static final class Shared extends Object {}
56.90 +
56.91 + public static final class P extends NamedServicesProvider {
56.92 + static InstanceContent ic1 = new InstanceContent();
56.93 + static InstanceContent ic2 = new InstanceContent();
56.94 + static AbstractLookup[] arr = {
56.95 + new AbstractLookup(ic1), new AbstractLookup(ic2)
56.96 + };
56.97 +
56.98 +
56.99 + @Override
56.100 + public Lookup create(String path) {
56.101 + int indx = -1;
56.102 + if (path.equals("MyServices/")) {
56.103 + indx = 0;
56.104 + }
56.105 + if (path.equals("YourServices/")) {
56.106 + indx = 1;
56.107 + }
56.108 + if (indx == -1) {
56.109 + fail("Unexpected lookup query: " + path);
56.110 + }
56.111 + return arr[indx];
56.112 + }
56.113 + }
56.114 +
56.115 +}
57.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
57.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/PrefixServicesLookupTest.java Sat Oct 31 15:28:13 2009 +0100
57.3 @@ -0,0 +1,63 @@
57.4 +/*
57.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
57.6 + *
57.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
57.8 + *
57.9 + * The contents of this file are subject to the terms of either the GNU
57.10 + * General Public License Version 2 only ("GPL") or the Common
57.11 + * Development and Distribution License("CDDL") (collectively, the
57.12 + * "License"). You may not use this file except in compliance with the
57.13 + * License. You can obtain a copy of the License at
57.14 + * http://www.netbeans.org/cddl-gplv2.html
57.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
57.16 + * specific language governing permissions and limitations under the
57.17 + * License. When distributing the software, include this License Header
57.18 + * Notice in each file and include the License file at
57.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
57.20 + * particular file as subject to the "Classpath" exception as provided
57.21 + * by Sun in the GPL Version 2 section of the License file that
57.22 + * accompanied this code. If applicable, add the following below the
57.23 + * License Header, with the fields enclosed by brackets [] replaced by
57.24 + * your own identifying information:
57.25 + * "Portions Copyrighted [year] [name of copyright owner]"
57.26 + *
57.27 + * Contributor(s):
57.28 + *
57.29 + * The Original Software is NetBeans. The Initial Developer of the Original
57.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
57.31 + * Microsystems, Inc. All Rights Reserved.
57.32 + *
57.33 + * If you wish your version of this file to be governed by only the CDDL
57.34 + * or only the GPL Version 2, indicate your decision by adding
57.35 + * "[Contributor] elects to include this software in this distribution
57.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
57.37 + * single choice of license, a recipient has the option to distribute
57.38 + * your version of this file under either the CDDL, the GPL Version 2 or
57.39 + * to extend the choice of license to its licensees as provided above.
57.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
57.41 + * Version 2 license, then the option applies only if the new code is
57.42 + * made subject to such option by the copyright holder.
57.43 + */
57.44 +
57.45 +package org.openide.util.lookup;
57.46 +
57.47 +import org.openide.util.Lookup;
57.48 +
57.49 +
57.50 +/** Test finding services from manifest.
57.51 + * @author Jaroslav Tulach
57.52 + */
57.53 +public class PrefixServicesLookupTest extends MetaInfServicesLookupTest {
57.54 + public PrefixServicesLookupTest(String name) {
57.55 + super(name);
57.56 + }
57.57 +
57.58 + protected String prefix() {
57.59 + return "META-INF/netbeans/prefix/services/test/";
57.60 + }
57.61 +
57.62 + protected Lookup createLookup(ClassLoader c) {
57.63 + return Lookups.metaInfServices(c, prefix());
57.64 + }
57.65 +
57.66 +}
58.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
58.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/ProxyLookupEventIssue136866Test.java Sat Oct 31 15:28:13 2009 +0100
58.3 @@ -0,0 +1,56 @@
58.4 +package org.openide.util.lookup;
58.5 +
58.6 +import junit.framework.TestCase;
58.7 +import org.openide.util.Lookup;
58.8 +import org.openide.util.LookupEvent;
58.9 +import org.openide.util.LookupListener;
58.10 +
58.11 +/**
58.12 + * Test case which demonstrates that ProxyLookup does not fire
58.13 + * an event when it should.
58.14 + */
58.15 +public class ProxyLookupEventIssue136866Test extends TestCase {
58.16 +
58.17 + public ProxyLookupEventIssue136866Test(String testName) {
58.18 + super(testName);
58.19 + }
58.20 +
58.21 + public void testAbstractLookupFiresEventWhenContentChanged() {
58.22 + InstanceContent ic = new InstanceContent();
58.23 + AbstractLookup al = new AbstractLookup(ic);
58.24 +
58.25 + final int[] counts = {0}; // Number of items observed upon a LookupEvent
58.26 + final Lookup.Result<String> result = al.lookupResult(String.class);
58.27 +
58.28 + result.addLookupListener(new LookupListener() {
58.29 + public void resultChanged(LookupEvent ev) {
58.30 + // this gets called as expected
58.31 + assertSame(result, ev.getSource());
58.32 + counts[0] = result.allInstances().size();
58.33 + }
58.34 + });
58.35 +
58.36 + ic.add("hello1");
58.37 + assertEquals(1, counts[0]);
58.38 + }
58.39 +
58.40 + public void testProxyLookupFailsToFireEventWhenProxiedLookupChanged() {
58.41 + InstanceContent ic = new InstanceContent();
58.42 +// AbstractLookup al = new AbstractLookup(ic);
58.43 + Lookup proxy = new AbstractLookup(ic);
58.44 +
58.45 + final int[] counts = {0}; // Number of items observed upon a LookupEvent
58.46 + final Lookup.Result<String> result = proxy.lookupResult(String.class);
58.47 +
58.48 + result.addLookupListener(new LookupListener() {
58.49 + public void resultChanged(LookupEvent ev) {
58.50 + // this should be called but never is
58.51 + assertSame(result, ev.getSource());
58.52 + counts[0] = result.allInstances().size();
58.53 + }
58.54 + });
58.55 +
58.56 + ic.add("hello1");
58.57 + assertEquals(1, counts[0]);
58.58 + }
58.59 +}
59.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
59.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java Sat Oct 31 15:28:13 2009 +0100
59.3 @@ -0,0 +1,655 @@
59.4 +/*
59.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
59.6 + *
59.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
59.8 + *
59.9 + * The contents of this file are subject to the terms of either the GNU
59.10 + * General Public License Version 2 only ("GPL") or the Common
59.11 + * Development and Distribution License("CDDL") (collectively, the
59.12 + * "License"). You may not use this file except in compliance with the
59.13 + * License. You can obtain a copy of the License at
59.14 + * http://www.netbeans.org/cddl-gplv2.html
59.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
59.16 + * specific language governing permissions and limitations under the
59.17 + * License. When distributing the software, include this License Header
59.18 + * Notice in each file and include the License file at
59.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
59.20 + * particular file as subject to the "Classpath" exception as provided
59.21 + * by Sun in the GPL Version 2 section of the License file that
59.22 + * accompanied this code. If applicable, add the following below the
59.23 + * License Header, with the fields enclosed by brackets [] replaced by
59.24 + * your own identifying information:
59.25 + * "Portions Copyrighted [year] [name of copyright owner]"
59.26 + *
59.27 + * Contributor(s):
59.28 + *
59.29 + * The Original Software is NetBeans. The Initial Developer of the Original
59.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
59.31 + * Microsystems, Inc. All Rights Reserved.
59.32 + *
59.33 + * If you wish your version of this file to be governed by only the CDDL
59.34 + * or only the GPL Version 2, indicate your decision by adding
59.35 + * "[Contributor] elects to include this software in this distribution
59.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
59.37 + * single choice of license, a recipient has the option to distribute
59.38 + * your version of this file under either the CDDL, the GPL Version 2 or
59.39 + * to extend the choice of license to its licensees as provided above.
59.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
59.41 + * Version 2 license, then the option applies only if the new code is
59.42 + * made subject to such option by the copyright holder.
59.43 + */
59.44 +
59.45 +package org.openide.util.lookup;
59.46 +
59.47 +import java.io.Serializable;
59.48 +
59.49 +import java.lang.ref.Reference;
59.50 +import java.lang.ref.WeakReference;
59.51 +import java.util.*;
59.52 +import java.util.concurrent.Executor;
59.53 +import junit.framework.*;
59.54 +import org.netbeans.junit.*;
59.55 +import org.netbeans.modules.openide.util.ActiveQueue;
59.56 +import org.openide.util.Lookup;
59.57 +import org.openide.util.Lookup.Result;
59.58 +import org.openide.util.LookupEvent;
59.59 +import org.openide.util.LookupListener;
59.60 +
59.61 +/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
59.62 + */
59.63 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
59.64 +public class ProxyLookupTest extends AbstractLookupBaseHid
59.65 +implements AbstractLookupBaseHid.Impl {
59.66 + public ProxyLookupTest(java.lang.String testName) {
59.67 + super(testName, null);
59.68 + }
59.69 +
59.70 + public static Test suite() {
59.71 + return new NbTestSuite (ProxyLookupTest.class);
59.72 +// return new ProxyLookupTest("testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679");
59.73 + }
59.74 +
59.75 + /** Creates an lookup for given lookup. This class just returns
59.76 + * the object passed in, but subclasses can be different.
59.77 + * @param lookup in lookup
59.78 + * @return a lookup to use
59.79 + */
59.80 + public Lookup createLookup (Lookup lookup) {
59.81 + return new ProxyLookup (new Lookup[] { lookup });
59.82 + }
59.83 +
59.84 + public Lookup createInstancesLookup (InstanceContent ic) {
59.85 + return new AbstractLookup (ic);
59.86 + }
59.87 +
59.88 +
59.89 + public void clearCaches () {
59.90 + }
59.91 +
59.92 +
59.93 + /** Check whether setLookups method does not fire when there is no
59.94 + * change in the lookups.
59.95 + */
59.96 + public void testProxyListener () {
59.97 + ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
59.98 +
59.99 + final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
59.100 + final Object[] IGNORE = {
59.101 + ProxyLookup.ImmutableInternalData.EMPTY,
59.102 + ProxyLookup.ImmutableInternalData.EMPTY_ARR,
59.103 + ActiveQueue.queue(),
59.104 + Collections.emptyMap(),
59.105 + Collections.emptyList(),
59.106 + Collections.emptySet()
59.107 + };
59.108 +
59.109 + assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
59.110 +
59.111 + Lookup.Result<Object> res = lookup.lookup (template);
59.112 +
59.113 + assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
59.114 +
59.115 + LL ll = new LL ();
59.116 + res.addLookupListener (ll);
59.117 + Collection allRes = res.allInstances ();
59.118 +
59.119 + lookup.setLookups (new Lookup[0]);
59.120 +
59.121 + if (ll.getCount () != 0) {
59.122 + fail ("Calling setLookups (emptyarray) fired a change");
59.123 + }
59.124 +
59.125 + InstanceContent t = new InstanceContent();
59.126 + Lookup del = new AbstractLookup (t);
59.127 + t.add("Ahoj");
59.128 + lookup.setLookups (new Lookup[] { del });
59.129 +
59.130 + if (ll.getCount () != 1) {
59.131 + fail ("Changing lookups did not generate an event");
59.132 + }
59.133 +
59.134 + lookup.setLookups (new Lookup[] { del });
59.135 +
59.136 + if (ll.getCount () != 0) {
59.137 + fail ("Calling setLookups (thesamearray) fired a change");
59.138 + }
59.139 + }
59.140 +
59.141 + public void testNoListenersProxyListener () {
59.142 + ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
59.143 + class E implements Executor {
59.144 + Runnable r;
59.145 + public void execute(Runnable command) {
59.146 + assertNull("NO previous", r);
59.147 + r = command;
59.148 + }
59.149 + public void perform() {
59.150 + assertNotNull("We shall have a runnable", r);
59.151 + r.run();
59.152 + r = null;
59.153 + }
59.154 + }
59.155 + E executor = new E();
59.156 +
59.157 +
59.158 + final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
59.159 + final Object[] IGNORE = {
59.160 + ProxyLookup.ImmutableInternalData.EMPTY,
59.161 + ProxyLookup.ImmutableInternalData.EMPTY_ARR,
59.162 + ActiveQueue.queue(),
59.163 + Collections.emptyMap(),
59.164 + Collections.emptyList(),
59.165 + Collections.emptySet()
59.166 + };
59.167 +
59.168 + assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
59.169 +
59.170 + Lookup.Result<Object> res = lookup.lookup (template);
59.171 +
59.172 + assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
59.173 +
59.174 + LL ll = new LL ();
59.175 + res.addLookupListener (ll);
59.176 + Collection allRes = res.allInstances ();
59.177 +
59.178 + lookup.setLookups (executor, new Lookup[0]);
59.179 + if (ll.getCount () != 0) {
59.180 + fail ("Calling setLookups (emptyarray) fired a change");
59.181 + }
59.182 +
59.183 + InstanceContent t = new InstanceContent();
59.184 + Lookup del = new AbstractLookup (t);
59.185 + t.add("Ahoj");
59.186 + lookup.setLookups (executor, new Lookup[] { del });
59.187 + assertEquals("No change yet", 0, ll.getCount());
59.188 + executor.perform();
59.189 + if (ll.getCount () != 1) {
59.190 + fail ("Changing lookups did not generate an event");
59.191 + }
59.192 +
59.193 + lookup.setLookups (executor, new Lookup[] { del });
59.194 + if (ll.getCount () != 0) {
59.195 + fail ("Calling setLookups (thesamearray) fired a change");
59.196 + }
59.197 + }
59.198 +
59.199 + public void testSetLookups () throws Exception {
59.200 + AbstractLookup a1 = new AbstractLookup (new InstanceContent ());
59.201 + AbstractLookup a2 = new AbstractLookup (new InstanceContent ());
59.202 +
59.203 + InstanceContent i3 = new InstanceContent ();
59.204 + i3.add (i3);
59.205 + AbstractLookup a3 = new AbstractLookup (i3);
59.206 +
59.207 + final ProxyLookup p = new ProxyLookup (new Lookup[] { a1, a2 });
59.208 + final Lookup.Result res1 = p.lookup (new Lookup.Template (Object.class));
59.209 + Collection c1 = res1.allInstances();
59.210 +
59.211 + Lookup.Result res2 = p.lookup (new Lookup.Template (String.class));
59.212 + Collection c2 = res2.allInstances ();
59.213 +
59.214 +
59.215 + assertTrue ("We need two results", res1 != res2);
59.216 +
59.217 + final Object blocked = new Object ();
59.218 +
59.219 + class L extends Object implements LookupListener {
59.220 + public void resultChanged (LookupEvent ev) {
59.221 + try {
59.222 + res1.removeLookupListener(this);
59.223 +
59.224 + // waiting for second thread to start #111#
59.225 + blocked.wait ();
59.226 +
59.227 + } catch (Exception ex) {
59.228 + ex.printStackTrace();
59.229 + fail ("An exception occured ");
59.230 + }
59.231 + }
59.232 + }
59.233 +
59.234 + final L listener1 = new L ();
59.235 + res1.addLookupListener (listener1);
59.236 +
59.237 +
59.238 + Runnable newLookupSetter = new Runnable() {
59.239 + public void run () {
59.240 + synchronized (blocked) {
59.241 + try {
59.242 + p.setLookups (new Lookup[0]);
59.243 + } catch (Exception ex) {
59.244 + ex.printStackTrace();
59.245 + fail ("setLookups failed.");
59.246 + } finally {
59.247 + // starts the main thread #111#
59.248 + blocked.notify ();
59.249 + }
59.250 + }
59.251 + }
59.252 + };
59.253 +
59.254 + synchronized (blocked) {
59.255 + new Thread (newLookupSetter).start ();
59.256 +
59.257 + p.setLookups (new Lookup[] { a1, a2, a3 });
59.258 + }
59.259 + }
59.260 +
59.261 + public void testProxyLookupTemplateCaching(){
59.262 + Lookup lookups[] = new Lookup[1];
59.263 + doProxyLookupTemplateCaching(lookups, false);
59.264 + }
59.265 +
59.266 + public void testProxyLookupTemplateCachingOnSizeTwoArray() {
59.267 + Lookup lookups[] = new Lookup[2];
59.268 + lookups[1] = Lookup.EMPTY;
59.269 + doProxyLookupTemplateCaching(lookups, false);
59.270 + }
59.271 + public void testProxyLookupShallNotAllowModificationOfGetLookups(){
59.272 + Lookup lookups[] = new Lookup[1];
59.273 + doProxyLookupTemplateCaching(lookups, true);
59.274 + }
59.275 +
59.276 + public void testProxyLookupShallNotAllowModificationOfGetLookupsOnSizeTwoArray() {
59.277 + Lookup lookups[] = new Lookup[2];
59.278 + lookups[1] = Lookup.EMPTY;
59.279 + doProxyLookupTemplateCaching(lookups, true);
59.280 + }
59.281 +
59.282 + /** Index 0 of lookups will be modified, the rest is up to the
59.283 + * setup code.
59.284 + */
59.285 + private void doProxyLookupTemplateCaching(Lookup[] lookups, boolean reget) {
59.286 + // Create MyProxyLookup with one lookup containing the String object
59.287 + InstanceContent inst = new InstanceContent();
59.288 + inst.add(new String("Hello World")); //NOI18N
59.289 + lookups[0] = new AbstractLookup(inst);
59.290 + ProxyLookup proxy = new ProxyLookup(lookups);
59.291 + if (reget) {
59.292 + lookups = proxy.getLookups();
59.293 + }
59.294 +
59.295 + // Performing template lookup for String object
59.296 + Lookup.Result result = proxy.lookup(new Lookup.Template(String.class, null, null));
59.297 + int stringTemplateResultSize = result.allInstances().size();
59.298 + assertEquals ("Ensure, there is only one instance of String.class in proxyLookup:", //NOI18N
59.299 + 1, stringTemplateResultSize);
59.300 +
59.301 + // Changing lookup in proxy lookup, now it will contain
59.302 + // StringBuffer Object instead of String
59.303 + InstanceContent ic2 = new InstanceContent();
59.304 + ic2.add(new Integer(1234567890));
59.305 + lookups[0] = new AbstractLookup(ic2);
59.306 + proxy.setLookups(lookups);
59.307 +
59.308 + assertEquals ("the old result is updated", 0, result.allInstances().size());
59.309 +
59.310 + // Instance of String.class should not appear in proxyLookup
59.311 + Lookup.Result r2 = proxy.lookup(new Lookup.Template(String.class, null, null));
59.312 + assertEquals ("Instance of String.class should not appear in proxyLookup:", //NOI18N
59.313 + 0, r2.allInstances().size());
59.314 +
59.315 + Lookup.Result r3 = proxy.lookup(new Lookup.Template(Integer.class, null, null));
59.316 + assertEquals ("There is only one instance of Integer.class in proxyLookup:", //NOI18N
59.317 + 1, r3.allInstances().size());
59.318 + }
59.319 +
59.320 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
59.321 + doListeningAndQueryingByTwoListenersSetLookups(0, 1);
59.322 + }
59.323 + public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
59.324 + doListeningAndQueryingByTwoListenersSetLookups(1, 1);
59.325 + }
59.326 + public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
59.327 + doListeningAndQueryingByTwoListenersSetLookups(2, 1);
59.328 + }
59.329 +
59.330 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
59.331 + doListeningAndQueryingByTwoListenersSetLookups(0, 2);
59.332 + }
59.333 + public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
59.334 + doListeningAndQueryingByTwoListenersSetLookups(1, 2);
59.335 + }
59.336 + public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
59.337 + doListeningAndQueryingByTwoListenersSetLookups(2, 2);
59.338 + }
59.339 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
59.340 + doListeningAndQueryingByTwoListenersSetLookups(0, 22);
59.341 + }
59.342 + public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
59.343 + doListeningAndQueryingByTwoListenersSetLookups(1, 22);
59.344 + }
59.345 + public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
59.346 + doListeningAndQueryingByTwoListenersSetLookups(2, 22);
59.347 + }
59.348 +
59.349 + private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth) {
59.350 + ProxyLookup orig = new ProxyLookup();
59.351 + ProxyLookup on = orig;
59.352 +
59.353 + while (--depth > 0) {
59.354 + on = new ProxyLookup(new Lookup[] { on });
59.355 + }
59.356 +
59.357 +
59.358 + final ProxyLookup lookup = on;
59.359 +
59.360 + class L implements LookupListener {
59.361 + Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
59.362 + Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
59.363 + Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
59.364 +
59.365 + {
59.366 + integer.addLookupListener(this);
59.367 + number.addLookupListener(this);
59.368 + serial.addLookupListener(this);
59.369 + }
59.370 +
59.371 + int round;
59.372 +
59.373 + public void resultChanged(LookupEvent ev) {
59.374 + Collection c1 = get(type, integer);
59.375 + Collection c2 = get(type, number);
59.376 + Collection c3 = get(type, serial);
59.377 +
59.378 + assertEquals("round " + round + " c1 vs. c2", c1, c2);
59.379 + assertEquals("round " + round + " c1 vs. c3", c1, c3);
59.380 + assertEquals("round " + round + " c2 vs. c3", c2, c3);
59.381 +
59.382 + round++;
59.383 + }
59.384 +
59.385 + private Collection get(int type, Lookup.Result res) {
59.386 + Collection c;
59.387 + switch(type) {
59.388 + case 0: c = res.allInstances(); break;
59.389 + case 1: c = res.allClasses(); break;
59.390 + case 2: c = res.allItems(); break;
59.391 + default: c = null; fail("Type: " + type); break;
59.392 + }
59.393 +
59.394 + assertNotNull(c);
59.395 + return new ArrayList(c);
59.396 + }
59.397 + }
59.398 +
59.399 + L listener = new L();
59.400 + listener.resultChanged(null);
59.401 + ArrayList arr = new ArrayList();
59.402 + for(int i = 0; i < 100; i++) {
59.403 + arr.add(new Integer(i));
59.404 +
59.405 + orig.setLookups(new Lookup[] { Lookups.fixed(arr.toArray()) });
59.406 + }
59.407 +
59.408 + assertEquals("3x100+1 checks", 301, listener.round);
59.409 + }
59.410 +
59.411 + static Object holder;
59.412 +
59.413 + public void testProxyWithLiveResultCanBeCollected() {
59.414 + Lookup layer0 = Lookups.singleton("Hello");
59.415 + Lookup layer1 = new ProxyLookup(new Lookup[] { layer0 });
59.416 + Lookup layer2 = new ProxyLookup(new Lookup[] { layer1 });
59.417 + Lookup.Result result1 = layer1.lookup(new Lookup.Template(String.class));
59.418 +
59.419 + assertEquals("One instance", 1, result1.allInstances().size());
59.420 +
59.421 + // this will create ProxyLookup$R which listens on origResult
59.422 + Lookup.Result result2 = layer2.lookup(new Lookup.Template(String.class));
59.423 +
59.424 + // this line is necessary. W/o actually querying the result,
59.425 + // it will nether compute it nor attach the listener.
59.426 + assertEquals("One instance", 1, result2.allInstances().size());
59.427 +
59.428 + result2.addLookupListener(new LookupListener() {
59.429 + public void resultChanged(LookupEvent ev) {}
59.430 + });
59.431 +
59.432 + Reference ref = new WeakReference(layer2);
59.433 + layer2 = null;
59.434 + result2 = null;
59.435 + try {
59.436 + holder = result1;
59.437 + assertGC ("The proxy lookup not been garbage collected!", ref);
59.438 + } finally {
59.439 + holder = null;
59.440 + }
59.441 + }
59.442 +
59.443 + public void testArrayIndexAsInIssue119292() throws Exception {
59.444 + final ProxyLookup pl = new ProxyLookup();
59.445 + final int[] cnt = { 0 };
59.446 +
59.447 + class L extends Lookup {
59.448 + L[] set;
59.449 + Lookup l;
59.450 +
59.451 + public L(String s) {
59.452 + l = Lookups.singleton(s);
59.453 + }
59.454 +
59.455 + @Override
59.456 + public <T> T lookup(Class<T> clazz) {
59.457 + return l.lookup(clazz);
59.458 + }
59.459 +
59.460 + @Override
59.461 + public <T> Result<T> lookup(Template<T> template) {
59.462 + return l.lookup(template);
59.463 + }
59.464 +
59.465 + @Override
59.466 + @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
59.467 + public boolean equals(Object obj) {
59.468 + if (set != null) {
59.469 + cnt[0]++;
59.470 + pl.setLookups(set);
59.471 + }
59.472 + return super.equals(obj);
59.473 + }
59.474 +
59.475 + @Override
59.476 + public int hashCode() {
59.477 + int hash = 3;
59.478 + return hash;
59.479 + }
59.480 + }
59.481 +
59.482 + Result<String> res = pl.lookupResult(String.class);
59.483 + assertEquals(Collections.EMPTY_LIST, res.allItems());
59.484 +
59.485 + L[] old = { new L("A"), new L("B") };
59.486 + L[] now = { new L("C") };
59.487 +
59.488 + pl.setLookups(old);
59.489 + cnt[0] = 0;
59.490 +
59.491 + old[0].set = new L[0];
59.492 + pl.setLookups(now);
59.493 +
59.494 + assertEquals("No call to equals", 0, cnt[0]);
59.495 +
59.496 + assertEquals("Still assigned to C", Collections.singletonList("C"), res.allInstances());
59.497 + }
59.498 +
59.499 + public void testArrayIndexWithAddRemoveListenerAsInIssue119292() throws Exception {
59.500 + final ProxyLookup pl = new ProxyLookup();
59.501 + final int[] cnt = { 0 };
59.502 +
59.503 + class L extends Lookup {
59.504 + L[] set;
59.505 + Lookup l;
59.506 +
59.507 + public L(String s) {
59.508 + l = Lookups.singleton(s);
59.509 + }
59.510 +
59.511 + @Override
59.512 + public <T> T lookup(Class<T> clazz) {
59.513 + return l.lookup(clazz);
59.514 + }
59.515 +
59.516 + @Override
59.517 + public <T> Result<T> lookup(Template<T> template) {
59.518 + Result<T> r = l.lookup(template);
59.519 + return new R<T>(r);
59.520 + }
59.521 +
59.522 + final class R<T> extends Result<T> {
59.523 + private Result<T> delegate;
59.524 +
59.525 + public R(Result<T> delegate) {
59.526 + this.delegate = delegate;
59.527 + }
59.528 +
59.529 + @Override
59.530 + public void addLookupListener(LookupListener l) {
59.531 + cnt[0]++;
59.532 + if (set != null) {
59.533 + pl.setLookups(set);
59.534 + }
59.535 + delegate.addLookupListener(l);
59.536 + }
59.537 +
59.538 + @Override
59.539 + public void removeLookupListener(LookupListener l) {
59.540 + cnt[0]++;
59.541 + if (set != null) {
59.542 + pl.setLookups(set);
59.543 + }
59.544 + delegate.removeLookupListener(l);
59.545 + }
59.546 +
59.547 + @Override
59.548 + public Collection<? extends T> allInstances() {
59.549 + return delegate.allInstances();
59.550 + }
59.551 + }
59.552 + }
59.553 +
59.554 + Result<String> res = pl.lookupResult(String.class);
59.555 + assertEquals(Collections.EMPTY_LIST, res.allItems());
59.556 +
59.557 + L[] old = { new L("A"), new L("B") };
59.558 + L[] now = { new L("C") };
59.559 +
59.560 + pl.setLookups(old);
59.561 + cnt[0] = 0;
59.562 +
59.563 + old[0].set = new L[0];
59.564 + pl.setLookups(now);
59.565 +
59.566 + if (cnt[0] == 0) {
59.567 + fail("There should be calls to listeners");
59.568 + }
59.569 +
59.570 + assertEquals("C is overriden from removeLookupListener", Collections.emptyList(), res.allInstances());
59.571 + }
59.572 +
59.573 +
59.574 + public void testArrayIndexWithSetLookupAsInIssue123679() throws Exception {
59.575 + final ProxyLookup pl = new ProxyLookup();
59.576 + final int[] cnt = { 0 };
59.577 +
59.578 + class L extends Lookup {
59.579 + L[] set;
59.580 + Lookup l;
59.581 + Collection<? extends Serializable> res;
59.582 +
59.583 + public L(String s) {
59.584 + l = Lookups.singleton(s);
59.585 + }
59.586 +
59.587 + @Override
59.588 + public <T> T lookup(Class<T> clazz) {
59.589 + return l.lookup(clazz);
59.590 + }
59.591 +
59.592 + @Override
59.593 + public <T> Result<T> lookup(Template<T> template) {
59.594 + cnt[0]++;
59.595 + if (set != null) {
59.596 + pl.setLookups(set);
59.597 + res = pl.lookupAll(Serializable.class);
59.598 + }
59.599 + Result<T> r = l.lookup(template);
59.600 + return r;
59.601 + }
59.602 + }
59.603 +
59.604 + L[] now = { new L("A"), new L("B") };
59.605 + L[] old = { new L("C") };
59.606 + pl.setLookups(old);
59.607 + old[0].set = now;
59.608 +
59.609 + Result<String> res = pl.lookupResult(String.class);
59.610 + assertEquals("New items visible", 2, res.allItems().size());
59.611 +
59.612 +
59.613 + pl.setLookups(new L("X"), new L("Y"), new L("Z"));
59.614 + }
59.615 +
59.616 + public void testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679() throws Exception {
59.617 + final ProxyLookup pl = new ProxyLookup();
59.618 + final int[] cnt = { 0 };
59.619 +
59.620 + class L extends Lookup {
59.621 + L[] set;
59.622 + Lookup l;
59.623 + Collection<? extends Serializable> res;
59.624 +
59.625 + public L(String s) {
59.626 + l = Lookups.singleton(s);
59.627 + }
59.628 +
59.629 + @Override
59.630 + public <T> T lookup(Class<T> clazz) {
59.631 + return l.lookup(clazz);
59.632 + }
59.633 +
59.634 + @Override
59.635 + public <T> Result<T> lookup(Template<T> template) {
59.636 + cnt[0]++;
59.637 + if (set != null) {
59.638 + pl.setLookups(set);
59.639 + res = pl.lookupAll(Serializable.class);
59.640 + }
59.641 + Result<T> r = l.lookup(template);
59.642 + return r;
59.643 + }
59.644 + }
59.645 +
59.646 + L dupl = new L("A");
59.647 + L[] now = { dupl };
59.648 + L[] old = { new L("C") };
59.649 + pl.setLookups(old);
59.650 + old[0].set = now;
59.651 +
59.652 + Result<String> res = pl.lookupResult(String.class);
59.653 + assertEquals("New items visible", 1, res.allItems().size());
59.654 +
59.655 +
59.656 + pl.setLookups(old);
59.657 + }
59.658 +}
60.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
60.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleLookupTest.java Sat Oct 31 15:28:13 2009 +0100
60.3 @@ -0,0 +1,351 @@
60.4 +/*
60.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
60.6 + *
60.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
60.8 + *
60.9 + * The contents of this file are subject to the terms of either the GNU
60.10 + * General Public License Version 2 only ("GPL") or the Common
60.11 + * Development and Distribution License("CDDL") (collectively, the
60.12 + * "License"). You may not use this file except in compliance with the
60.13 + * License. You can obtain a copy of the License at
60.14 + * http://www.netbeans.org/cddl-gplv2.html
60.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
60.16 + * specific language governing permissions and limitations under the
60.17 + * License. When distributing the software, include this License Header
60.18 + * Notice in each file and include the License file at
60.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
60.20 + * particular file as subject to the "Classpath" exception as provided
60.21 + * by Sun in the GPL Version 2 section of the License file that
60.22 + * accompanied this code. If applicable, add the following below the
60.23 + * License Header, with the fields enclosed by brackets [] replaced by
60.24 + * your own identifying information:
60.25 + * "Portions Copyrighted [year] [name of copyright owner]"
60.26 + *
60.27 + * Contributor(s):
60.28 + *
60.29 + * The Original Software is NetBeans. The Initial Developer of the Original
60.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
60.31 + * Microsystems, Inc. All Rights Reserved.
60.32 + *
60.33 + * If you wish your version of this file to be governed by only the CDDL
60.34 + * or only the GPL Version 2, indicate your decision by adding
60.35 + * "[Contributor] elects to include this software in this distribution
60.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
60.37 + * single choice of license, a recipient has the option to distribute
60.38 + * your version of this file under either the CDDL, the GPL Version 2 or
60.39 + * to extend the choice of license to its licensees as provided above.
60.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
60.41 + * Version 2 license, then the option applies only if the new code is
60.42 + * made subject to such option by the copyright holder.
60.43 + */
60.44 +
60.45 +package org.openide.util.lookup;
60.46 +
60.47 +import java.util.ArrayList;
60.48 +import java.util.Arrays;
60.49 +import java.util.Collection;
60.50 +import java.util.List;
60.51 +import java.util.Set;
60.52 +import org.netbeans.junit.NbTestCase;
60.53 +import org.openide.util.Lookup;
60.54 +
60.55 +/**
60.56 + * Tests for class SimpleLookup.
60.57 + * @author David Strupl
60.58 + */
60.59 +public class SimpleLookupTest extends NbTestCase {
60.60 +
60.61 + public SimpleLookupTest(String testName) {
60.62 + super(testName);
60.63 + }
60.64 +
60.65 + public void testEmptyLookup() {
60.66 + assertSize("Lookup.EMPTY should be small", 8, Lookup.EMPTY);
60.67 + }
60.68 +
60.69 + /**
60.70 + * Simple tests testing singleton lookup.
60.71 + */
60.72 + public void testSingleton() {
60.73 + //
60.74 + Object orig = new Object();
60.75 + Lookup p1 = Lookups.singleton(orig);
60.76 + Object obj = p1.lookup(Object.class);
60.77 + assertTrue(obj == orig);
60.78 + assertNull(p1.lookup(String.class));
60.79 + assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
60.80 + //
60.81 + Lookup p2 = Lookups.singleton("test");
60.82 + assertNotNull(p2.lookup(Object.class));
60.83 + assertNotNull(p2.lookup(String.class));
60.84 + assertNotNull(p2.lookup(java.io.Serializable.class));
60.85 + }
60.86 +
60.87 + public void testEmptyFixed() {
60.88 + Lookup l = Lookups.fixed();
60.89 + assertSize("Lookups.fixed() for empty list of items should be small", 8, l);
60.90 + assertSame(Lookup.EMPTY, l);
60.91 + }
60.92 +
60.93 + public void testSingleItemFixed() {
60.94 + Object o = new Object();
60.95 + Lookup l = Lookups.fixed(o);
60.96 + assertSize("Lookups.fixed(o) for a single item should be small", 24, l);
60.97 + }
60.98 +
60.99 + /**
60.100 + * Simple tests testing fixed lookup.
60.101 + */
60.102 + public void testFixed() {
60.103 + //
60.104 + Object[] orig = new Object[] { new Object(), new Object() };
60.105 + Lookup p1 = Lookups.fixed(orig);
60.106 + Object obj = p1.lookup(Object.class);
60.107 + assertTrue(obj == orig[0] || obj == orig[1]);
60.108 + assertNull(p1.lookup(String.class));
60.109 + //
60.110 + String[] s = new String[] { "test1", "test2" };
60.111 + Lookup p2 = Lookups.fixed((Object[]) s);
60.112 + Object obj2 = p2.lookup(Object.class);
60.113 + assertNotNull(obj2);
60.114 + if (obj2 != s[0] && obj2 != s[1]) {
60.115 + fail("Returned objects are not the originals");
60.116 + }
60.117 + assertNotNull(p2.lookup(String.class));
60.118 + assertNotNull(p2.lookup(java.io.Serializable.class));
60.119 + Lookup.Template<String> t = new Lookup.Template<String>(String.class);
60.120 + Lookup.Result<String> r = p2.lookup(t);
60.121 + Collection<? extends String> all = r.allInstances();
60.122 + assertTrue(all.size() == 2);
60.123 + for (String o : all) {
60.124 + assertTrue("allInstances contains wrong objects", o.equals(s[0]) || o.equals(s[1]));
60.125 + }
60.126 +
60.127 + try {
60.128 + Lookups.fixed(new Object[] {null});
60.129 + fail("No nulls are allowed");
60.130 + } catch (NullPointerException ex) {
60.131 + // ok, NPE is what we want
60.132 + }
60.133 + }
60.134 +
60.135 + public void testFixedSubtypes() {
60.136 + class A {}
60.137 + class B extends A {}
60.138 + Lookup l = Lookups.fixed(new A(), new B());
60.139 + assertEquals(1, l.lookupAll(B.class).size());
60.140 + assertEquals(2, l.lookupAll(A.class).size());
60.141 + }
60.142 +
60.143 + /**
60.144 + * Simple tests testing converting lookup.
60.145 + */
60.146 + public void testConverting() {
60.147 + //
60.148 + String[] orig = new String[] { TestConvertor.TEST1, TestConvertor.TEST2 };
60.149 + TestConvertor convertor = new TestConvertor();
60.150 + Lookup p1 = Lookups.fixed(orig, convertor);
60.151 + assertNull("Converting from String to Integer - it should not find String in result", p1.lookup(String.class));
60.152 + assertNotNull(p1.lookup(Integer.class));
60.153 + assertNotNull(p1.lookup(Integer.class));
60.154 + assertTrue("Convertor should be called only once.", convertor.getNumberOfConvertCalls() == 1);
60.155 + Lookup.Template<Integer> t = new Lookup.Template<Integer>(Integer.class);
60.156 + Lookup.Result<Integer> r = p1.lookup(t);
60.157 + Collection<? extends Integer> all = r.allInstances();
60.158 + assertTrue(all.size() == 2);
60.159 + for (int i : all) {
60.160 + assertTrue("allInstances contains wrong objects", i == TestConvertor.t1 || i == TestConvertor.t2);
60.161 + }
60.162 + }
60.163 +
60.164 + private static class TestConvertor implements InstanceContent.Convertor<String,Integer> {
60.165 + static final String TEST1 = "test1";
60.166 + static final int t1 = 1;
60.167 + static final String TEST2 = "test2";
60.168 + static final int t2 = 2;
60.169 +
60.170 + private int numberOfConvertCalls = 0;
60.171 +
60.172 + public Integer convert(String obj) {
60.173 + numberOfConvertCalls++;
60.174 + if (obj.equals(TEST1)) {
60.175 + return t1;
60.176 + }
60.177 + if (obj.equals(TEST2)) {
60.178 + return t2;
60.179 + }
60.180 + throw new IllegalArgumentException();
60.181 + }
60.182 +
60.183 + public String displayName(String obj) {
60.184 + return obj;
60.185 + }
60.186 +
60.187 + public String id(String obj) {
60.188 + if (obj.equals(TEST1)) {
60.189 + return TEST1;
60.190 + }
60.191 + if (obj.equals(TEST2)) {
60.192 + return TEST2;
60.193 + }
60.194 + return null;
60.195 + }
60.196 +
60.197 + public Class<? extends Integer> type(String obj) {
60.198 + return Integer.class;
60.199 + }
60.200 +
60.201 + int getNumberOfConvertCalls() {
60.202 + return numberOfConvertCalls;
60.203 + }
60.204 + }
60.205 +
60.206 + public void testLookupItem() {
60.207 + SomeInst inst = new SomeInst();
60.208 + Lookup.Item item = Lookups.lookupItem(inst, "XYZ");
60.209 +
60.210 + assertTrue("Wrong instance", item.getInstance() == inst);
60.211 + assertTrue("Wrong instance class", item.getType() == inst.getClass());
60.212 + assertEquals("Wrong id", "XYZ", item.getId());
60.213 +
60.214 + item = Lookups.lookupItem(inst, null);
60.215 + assertNotNull("Id must never be null", item.getId());
60.216 + }
60.217 +
60.218 + public void testLookupItemEquals() {
60.219 + SomeInst instA = new SomeInst();
60.220 + SomeInst instB = new SomeInst();
60.221 + Lookup.Item itemA = Lookups.lookupItem(instA, null);
60.222 + Lookup.Item itemB = Lookups.lookupItem(instB, null);
60.223 +
60.224 + assertTrue("Lookup items shouldn't be equal", !itemA.equals(itemB) && !itemB.equals(itemA));
60.225 +
60.226 + itemA = Lookups.lookupItem(instA, null);
60.227 + itemB = Lookups.lookupItem(instA, null); // same instance
60.228 +
60.229 + assertTrue("Lookup items should be equal", itemA.equals(itemB) && itemB.equals(itemA));
60.230 + assertTrue("Lookup items hashcode should be same", itemA.hashCode() == itemB.hashCode());
60.231 +
60.232 + itemA = Lookups.lookupItem(new String("VOKURKA"), null);
60.233 + itemB = Lookups.lookupItem(new String("VOKURKA"), null);
60.234 +
60.235 + assertTrue("Lookup items shouldn't be equal (2)", !itemA.equals(itemB) && !itemB.equals(itemA));
60.236 + }
60.237 +
60.238 + public void testAllClassesIssue42399 () throws Exception {
60.239 + Object[] arr = { "Ahoj", new Object () };
60.240 +
60.241 + Lookup l = Lookups.fixed (arr);
60.242 +
60.243 + Set<Class<? extends Object>> s = l.lookup(new Lookup.Template<Object>(Object.class)).allClasses();
60.244 +
60.245 + assertEquals ("Two there", 2, s.size ());
60.246 + assertTrue ("Contains Object.class", s.contains (Object.class));
60.247 + assertTrue ("Contains string", s.contains (String.class));
60.248 +
60.249 + }
60.250 +
60.251 + public void testLookupItemEarlyInitializationProblem() {
60.252 + InstanceContent ic = new InstanceContent();
60.253 + AbstractLookup al = new AbstractLookup(ic);
60.254 + LI item = new LI();
60.255 + List<AbstractLookup.Pair> pairs1 = new ArrayList<AbstractLookup.Pair>();
60.256 + List<AbstractLookup.Pair> pairs2 = new ArrayList<AbstractLookup.Pair>();
60.257 +
60.258 + assertEquals("Item's instance shouldn't be requested", 0, item.cnt);
60.259 +
60.260 + pairs1.add(new ItemPair<Object>(Lookups.<Object>lookupItem(new SomeInst(), null)));
60.261 + pairs1.add(new ItemPair<Object>(item));
60.262 + pairs1.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
60.263 +
60.264 + pairs2.add(new ItemPair<Object>(item));
60.265 + pairs2.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
60.266 +
60.267 + ic.setPairs(pairs1);
60.268 + ic.setPairs(pairs2);
60.269 +
60.270 + assertEquals("Item's instance shouldn't be requested when added to lookup", 0, item.cnt);
60.271 +
60.272 + LI item2 = al.lookup(LI.class);
60.273 + assertEquals("Item's instance should be requested", 1, item.cnt);
60.274 + }
60.275 +
60.276 + public void testConvenienceMethods() throws Exception {
60.277 + // Just check signatures and basic behavior of #73848.
60.278 + Lookup l = Lookups.fixed(new Object[] {1, "hello", 2, "goodbye"});
60.279 + Collection<? extends Integer> ints = l.lookupAll(Integer.class);
60.280 + assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
60.281 + Lookup.Result<Integer> r = l.lookupResult(Integer.class);
60.282 + ints = r.allInstances();
60.283 + assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
60.284 + }
60.285 +
60.286 + private static class SomeInst { }
60.287 +
60.288 + private static class LI extends Lookup.Item<Object> {
60.289 +
60.290 + public long cnt = 0;
60.291 +
60.292 + public String getDisplayName() {
60.293 + return getId();
60.294 + }
60.295 +
60.296 + public String getId() {
60.297 + return getClass() + "@" + hashCode();
60.298 + }
60.299 +
60.300 + public Object getInstance() {
60.301 + cnt++;
60.302 + return this;
60.303 + }
60.304 +
60.305 + public Class<? extends Object> getType() {
60.306 + return getClass();
60.307 + }
60.308 + } // End of LI class
60.309 +
60.310 + private static class ItemPair<T> extends AbstractLookup.Pair<T> {
60.311 +
60.312 + private AbstractLookup.Item<T> item;
60.313 +
60.314 + public ItemPair(Lookup.Item<T> i) {
60.315 + this.item = i;
60.316 + }
60.317 +
60.318 + protected boolean creatorOf(Object obj) {
60.319 + return item.getInstance() == obj;
60.320 + }
60.321 +
60.322 + public String getDisplayName() {
60.323 + return item.getDisplayName ();
60.324 + }
60.325 +
60.326 + public String getId() {
60.327 + return item.getId ();
60.328 + }
60.329 +
60.330 + public T getInstance() {
60.331 + return item.getInstance ();
60.332 + }
60.333 +
60.334 + public Class<? extends T> getType() {
60.335 + return item.getType ();
60.336 + }
60.337 +
60.338 + protected boolean instanceOf(Class<?> c) {
60.339 + return c.isAssignableFrom(getType());
60.340 + }
60.341 +
60.342 + public @Override boolean equals(Object o) {
60.343 + if (o instanceof ItemPair) {
60.344 + ItemPair p = (ItemPair)o;
60.345 + return item.equals (p.item);
60.346 + }
60.347 + return false;
60.348 + }
60.349 +
60.350 + public @Override int hashCode() {
60.351 + return item.hashCode ();
60.352 + }
60.353 + } // end of ItemPair
60.354 +}
61.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
61.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleProxyLookupIssue42244Test.java Sat Oct 31 15:28:13 2009 +0100
61.3 @@ -0,0 +1,120 @@
61.4 +/*
61.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
61.6 + *
61.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
61.8 + *
61.9 + * The contents of this file are subject to the terms of either the GNU
61.10 + * General Public License Version 2 only ("GPL") or the Common
61.11 + * Development and Distribution License("CDDL") (collectively, the
61.12 + * "License"). You may not use this file except in compliance with the
61.13 + * License. You can obtain a copy of the License at
61.14 + * http://www.netbeans.org/cddl-gplv2.html
61.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
61.16 + * specific language governing permissions and limitations under the
61.17 + * License. When distributing the software, include this License Header
61.18 + * Notice in each file and include the License file at
61.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
61.20 + * particular file as subject to the "Classpath" exception as provided
61.21 + * by Sun in the GPL Version 2 section of the License file that
61.22 + * accompanied this code. If applicable, add the following below the
61.23 + * License Header, with the fields enclosed by brackets [] replaced by
61.24 + * your own identifying information:
61.25 + * "Portions Copyrighted [year] [name of copyright owner]"
61.26 + *
61.27 + * Contributor(s):
61.28 + *
61.29 + * The Original Software is NetBeans. The Initial Developer of the Original
61.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
61.31 + * Microsystems, Inc. All Rights Reserved.
61.32 + *
61.33 + * If you wish your version of this file to be governed by only the CDDL
61.34 + * or only the GPL Version 2, indicate your decision by adding
61.35 + * "[Contributor] elects to include this software in this distribution
61.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
61.37 + * single choice of license, a recipient has the option to distribute
61.38 + * your version of this file under either the CDDL, the GPL Version 2 or
61.39 + * to extend the choice of license to its licensees as provided above.
61.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
61.41 + * Version 2 license, then the option applies only if the new code is
61.42 + * made subject to such option by the copyright holder.
61.43 + */
61.44 +
61.45 +package org.openide.util.lookup;
61.46 +
61.47 +import java.lang.ref.WeakReference;
61.48 +import java.util.*;
61.49 +import junit.framework.*;
61.50 +import org.netbeans.junit.*;
61.51 +import org.openide.util.Lookup;
61.52 +
61.53 +/** To simulate issue 42244.
61.54 + */
61.55 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
61.56 +public class SimpleProxyLookupIssue42244Test extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
61.57 + public SimpleProxyLookupIssue42244Test (java.lang.String testName) {
61.58 + super(testName, null);
61.59 + }
61.60 +
61.61 + public static Test suite() {
61.62 + // return new SimpleProxyLookupIssue42244Test("testGarbageCollect");
61.63 + return new NbTestSuite(SimpleProxyLookupIssue42244Test.class);
61.64 + }
61.65 +
61.66 + /** Creates an lookup for given lookup. This class just returns
61.67 + * the object passed in, but subclasses can be different.
61.68 + * @param lookup in lookup
61.69 + * @return a lookup to use
61.70 + */
61.71 + public Lookup createLookup (final Lookup lookup) {
61.72 + class C implements Lookup.Provider {
61.73 + public Lookup getLookup () {
61.74 + return lookup;
61.75 + }
61.76 + }
61.77 + return Lookups.proxy (new C ());
61.78 + }
61.79 +
61.80 + public Lookup createInstancesLookup (InstanceContent ic) {
61.81 + return new KeepResultsProxyLookup (new AbstractLookup (ic));
61.82 + }
61.83 +
61.84 + public void clearCaches () {
61.85 + KeepResultsProxyLookup k = (KeepResultsProxyLookup)this.instanceLookup;
61.86 +
61.87 + ArrayList toGC = new ArrayList ();
61.88 + Iterator it = k.allQueries.iterator ();
61.89 + while (it.hasNext ()) {
61.90 + Lookup.Result r = (Lookup.Result)it.next ();
61.91 + toGC.add (new WeakReference (r));
61.92 + }
61.93 +
61.94 + k.allQueries = null;
61.95 +
61.96 + it = toGC.iterator ();
61.97 + while (it.hasNext ()) {
61.98 + WeakReference r = (WeakReference)it.next ();
61.99 + assertGC ("Trying to release all results from memory", r);
61.100 + }
61.101 + }
61.102 +
61.103 + class KeepResultsProxyLookup extends ProxyLookup {
61.104 + private ArrayList allQueries = new ArrayList ();
61.105 + private ThreadLocal in = new ThreadLocal ();
61.106 +
61.107 + public KeepResultsProxyLookup (Lookup delegate) {
61.108 + super (new Lookup[] { delegate });
61.109 + }
61.110 +
61.111 + @Override
61.112 + protected void beforeLookup (org.openide.util.Lookup.Template template) {
61.113 + super.beforeLookup (template);
61.114 + if (allQueries != null && in.get () == null) {
61.115 + in.set (this);
61.116 + Lookup.Result res = lookup (template);
61.117 + allQueries.add (res);
61.118 + in.set (null);
61.119 + }
61.120 + }
61.121 +
61.122 + }
61.123 +}
62.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
62.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleProxyLookupSpeedIssue42244Test.java Sat Oct 31 15:28:13 2009 +0100
62.3 @@ -0,0 +1,118 @@
62.4 +/*
62.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
62.6 + *
62.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
62.8 + *
62.9 + * The contents of this file are subject to the terms of either the GNU
62.10 + * General Public License Version 2 only ("GPL") or the Common
62.11 + * Development and Distribution License("CDDL") (collectively, the
62.12 + * "License"). You may not use this file except in compliance with the
62.13 + * License. You can obtain a copy of the License at
62.14 + * http://www.netbeans.org/cddl-gplv2.html
62.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
62.16 + * specific language governing permissions and limitations under the
62.17 + * License. When distributing the software, include this License Header
62.18 + * Notice in each file and include the License file at
62.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
62.20 + * particular file as subject to the "Classpath" exception as provided
62.21 + * by Sun in the GPL Version 2 section of the License file that
62.22 + * accompanied this code. If applicable, add the following below the
62.23 + * License Header, with the fields enclosed by brackets [] replaced by
62.24 + * your own identifying information:
62.25 + * "Portions Copyrighted [year] [name of copyright owner]"
62.26 + *
62.27 + * Contributor(s):
62.28 + *
62.29 + * The Original Software is NetBeans. The Initial Developer of the Original
62.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
62.31 + * Microsystems, Inc. All Rights Reserved.
62.32 + *
62.33 + * If you wish your version of this file to be governed by only the CDDL
62.34 + * or only the GPL Version 2, indicate your decision by adding
62.35 + * "[Contributor] elects to include this software in this distribution
62.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
62.37 + * single choice of license, a recipient has the option to distribute
62.38 + * your version of this file under either the CDDL, the GPL Version 2 or
62.39 + * to extend the choice of license to its licensees as provided above.
62.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
62.41 + * Version 2 license, then the option applies only if the new code is
62.42 + * made subject to such option by the copyright holder.
62.43 + */
62.44 +
62.45 +package org.openide.util.lookup;
62.46 +
62.47 +import java.util.HashSet;
62.48 +import java.util.Set;
62.49 +import org.netbeans.junit.NbTestCase;
62.50 +
62.51 +import org.netbeans.junit.RandomlyFails;
62.52 +import org.openide.util.Lookup;
62.53 +
62.54 +/**
62.55 + * @author Petr Nejedly, adapted to test by Jaroslav Tulach
62.56 + */
62.57 +@RandomlyFails // NB-Core-Build #1847
62.58 +public class SimpleProxyLookupSpeedIssue42244Test extends NbTestCase {
62.59 +
62.60 + public SimpleProxyLookupSpeedIssue42244Test (String name) {
62.61 + super (name);
62.62 + }
62.63 +
62.64 + public void testCompareTheSpeed () {
62.65 + String content1 = "String1";
62.66 + String content2 = "String2";
62.67 +
62.68 + Lookup fixed1 = Lookups.singleton(content1);
62.69 + Lookup fixed2 = Lookups.singleton(content2);
62.70 +
62.71 + MyProvider provider = new MyProvider();
62.72 + provider.setLookup(fixed1);
62.73 +
62.74 + Lookup top = Lookups.proxy(provider);
62.75 +
62.76 + Lookup.Result<String> r0 = top.lookupResult(String.class);
62.77 + r0.allInstances();
62.78 +
62.79 + long time = System.currentTimeMillis();
62.80 + top.lookupAll(String.class);
62.81 + long withOneResult = System.currentTimeMillis() - time;
62.82 +
62.83 +
62.84 + Set<Object> results = new HashSet<Object>();
62.85 + for (int i=0; i<10000; i++) {
62.86 + Lookup.Result<String> res = top.lookupResult(String.class);
62.87 + results.add (res);
62.88 + res.allInstances();
62.89 + }
62.90 +
62.91 + provider.setLookup(fixed2);
62.92 +
62.93 + time = System.currentTimeMillis();
62.94 + top.lookupAll(String.class);
62.95 + long withManyResults = System.currentTimeMillis() - time;
62.96 +
62.97 + // if the measurement takes less then 10ms, pretend 10ms
62.98 + if (withManyResults < 10) {
62.99 + withManyResults = 10;
62.100 + }
62.101 + if (withOneResult < 10) {
62.102 + withOneResult = 10;
62.103 + }
62.104 +
62.105 + if (withManyResults >= 10 * withOneResult) {
62.106 + fail ("With many results the test runs too long.\n With many: " + withManyResults + "\n With one : " + withOneResult);
62.107 + }
62.108 + }
62.109 +
62.110 + private static class MyProvider implements Lookup.Provider {
62.111 + private Lookup lookup;
62.112 + public Lookup getLookup() {
62.113 + return lookup;
62.114 + }
62.115 +
62.116 + void setLookup(Lookup lookup) {
62.117 + this.lookup = lookup;
62.118 + }
62.119 + }
62.120 +
62.121 +}
63.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
63.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleProxyLookupTest.java Sat Oct 31 15:28:13 2009 +0100
63.3 @@ -0,0 +1,73 @@
63.4 +/*
63.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
63.6 + *
63.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
63.8 + *
63.9 + * The contents of this file are subject to the terms of either the GNU
63.10 + * General Public License Version 2 only ("GPL") or the Common
63.11 + * Development and Distribution License("CDDL") (collectively, the
63.12 + * "License"). You may not use this file except in compliance with the
63.13 + * License. You can obtain a copy of the License at
63.14 + * http://www.netbeans.org/cddl-gplv2.html
63.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
63.16 + * specific language governing permissions and limitations under the
63.17 + * License. When distributing the software, include this License Header
63.18 + * Notice in each file and include the License file at
63.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
63.20 + * particular file as subject to the "Classpath" exception as provided
63.21 + * by Sun in the GPL Version 2 section of the License file that
63.22 + * accompanied this code. If applicable, add the following below the
63.23 + * License Header, with the fields enclosed by brackets [] replaced by
63.24 + * your own identifying information:
63.25 + * "Portions Copyrighted [year] [name of copyright owner]"
63.26 + *
63.27 + * Contributor(s):
63.28 + *
63.29 + * The Original Software is NetBeans. The Initial Developer of the Original
63.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
63.31 + * Microsystems, Inc. All Rights Reserved.
63.32 + *
63.33 + * If you wish your version of this file to be governed by only the CDDL
63.34 + * or only the GPL Version 2, indicate your decision by adding
63.35 + * "[Contributor] elects to include this software in this distribution
63.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
63.37 + * single choice of license, a recipient has the option to distribute
63.38 + * your version of this file under either the CDDL, the GPL Version 2 or
63.39 + * to extend the choice of license to its licensees as provided above.
63.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
63.41 + * Version 2 license, then the option applies only if the new code is
63.42 + * made subject to such option by the copyright holder.
63.43 + */
63.44 +
63.45 +package org.openide.util.lookup;
63.46 +
63.47 +import java.lang.ref.WeakReference;
63.48 +import org.netbeans.junit.NbTestCase;
63.49 +import org.openide.util.Lookup;
63.50 +import org.openide.util.Lookup.Provider;
63.51 +
63.52 +/**
63.53 + *
63.54 + * @author Jan Lahoda
63.55 + */
63.56 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
63.57 +public class SimpleProxyLookupTest extends NbTestCase {
63.58 +
63.59 + public SimpleProxyLookupTest(String testName) {
63.60 + super(testName);
63.61 + }
63.62 +
63.63 + public void test69810() throws Exception {
63.64 + Lookup.Template t = new Lookup.Template(String.class);
63.65 + SimpleProxyLookup spl = new SimpleProxyLookup(new Provider() {
63.66 + public Lookup getLookup() {
63.67 + return Lookups.fixed(new Object[] {"test1", "test2"});
63.68 + }
63.69 + });
63.70 +
63.71 + assertGC("", new WeakReference(spl.lookup(t)));
63.72 +
63.73 + spl.lookup(new Lookup.Template(Object.class)).allInstances();
63.74 + }
63.75 +
63.76 +}
64.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
64.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SingletonLookupTest.java Sat Oct 31 15:28:13 2009 +0100
64.3 @@ -0,0 +1,113 @@
64.4 +/*
64.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
64.6 + *
64.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
64.8 + *
64.9 + * The contents of this file are subject to the terms of either the GNU
64.10 + * General Public License Version 2 only ("GPL") or the Common
64.11 + * Development and Distribution License("CDDL") (collectively, the
64.12 + * "License"). You may not use this file except in compliance with the
64.13 + * License. You can obtain a copy of the License at
64.14 + * http://www.netbeans.org/cddl-gplv2.html
64.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
64.16 + * specific language governing permissions and limitations under the
64.17 + * License. When distributing the software, include this License Header
64.18 + * Notice in each file and include the License file at
64.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
64.20 + * particular file as subject to the "Classpath" exception as provided
64.21 + * by Sun in the GPL Version 2 section of the License file that
64.22 + * accompanied this code. If applicable, add the following below the
64.23 + * License Header, with the fields enclosed by brackets [] replaced by
64.24 + * your own identifying information:
64.25 + * "Portions Copyrighted [year] [name of copyright owner]"
64.26 + *
64.27 + * If you wish your version of this file to be governed by only the CDDL
64.28 + * or only the GPL Version 2, indicate your decision by adding
64.29 + * "[Contributor] elects to include this software in this distribution
64.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
64.31 + * single choice of license, a recipient has the option to distribute
64.32 + * your version of this file under either the CDDL, the GPL Version 2 or
64.33 + * to extend the choice of license to its licensees as provided above.
64.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
64.35 + * Version 2 license, then the option applies only if the new code is
64.36 + * made subject to such option by the copyright holder.
64.37 + *
64.38 + * Contributor(s):
64.39 + *
64.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
64.41 + */
64.42 +
64.43 +package org.openide.util.lookup;
64.44 +
64.45 +import java.util.Collection;
64.46 +import org.netbeans.junit.NbTestCase;
64.47 +import org.openide.util.Lookup;
64.48 +
64.49 +/**
64.50 + * Contains tests of class {@code SingletonLookup}.
64.51 + *
64.52 + * @author Marian Petras
64.53 + */
64.54 +public class SingletonLookupTest extends NbTestCase {
64.55 +
64.56 + public SingletonLookupTest(String testName) {
64.57 + super(testName);
64.58 + }
64.59 +
64.60 + public void testBasics() {
64.61 + Object orig = new Object();
64.62 + Lookup p1 = new SingletonLookup(orig);
64.63 + Object obj = p1.lookup(Object.class);
64.64 + assertTrue(obj == orig);
64.65 + assertNull(p1.lookup(String.class));
64.66 + assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
64.67 + //
64.68 + Lookup p2 = new SingletonLookup("test");
64.69 + assertNotNull(p2.lookup(Object.class));
64.70 + assertNotNull(p2.lookup(String.class));
64.71 + assertNotNull(p2.lookup(java.io.Serializable.class));
64.72 + }
64.73 +
64.74 + public void testId() {
64.75 + Object orig = new Object();
64.76 + Collection allInstances;
64.77 +
64.78 + Lookup l = new SingletonLookup(orig, "id");
64.79 +
64.80 + allInstances = l.lookup(new Lookup.Template<Object>(Object.class, null, null)).allInstances();
64.81 + assertNotNull(allInstances);
64.82 + assertFalse(allInstances.isEmpty());
64.83 + assertEquals(1, allInstances.size());
64.84 + assertTrue(allInstances.iterator().next() == orig);
64.85 +
64.86 + allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "id", null)).allInstances();
64.87 + assertNotNull(allInstances);
64.88 + assertFalse(allInstances.isEmpty());
64.89 + assertEquals(1, allInstances.size());
64.90 + assertTrue(allInstances.iterator().next() == orig);
64.91 +
64.92 + allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "not", null)).allInstances();
64.93 + assertNotNull(allInstances);
64.94 + assertTrue(allInstances.isEmpty());
64.95 +
64.96 + allInstances = l.lookup(new Lookup.Template<String>(String.class, null, null)).allInstances();
64.97 + assertNotNull(allInstances);
64.98 + assertTrue(allInstances.isEmpty());
64.99 +
64.100 + allInstances = l.lookup(new Lookup.Template<String>(String.class, "id", null)).allInstances();
64.101 + assertNotNull(allInstances);
64.102 + assertTrue(allInstances.isEmpty());
64.103 +
64.104 + allInstances = l.lookup(new Lookup.Template<String>(String.class, "not", null)).allInstances();
64.105 + assertNotNull(allInstances);
64.106 + assertTrue(allInstances.isEmpty());
64.107 + }
64.108 +
64.109 + public void testSize() {
64.110 + final Object obj = new Object();
64.111 + assertSize("The singleton lookup instance should be small",
64.112 + 24,
64.113 + new SingletonLookup(obj));
64.114 + }
64.115 +
64.116 +}
65.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
65.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/problem100320.txt Sat Oct 31 15:28:13 2009 +0100
65.3 @@ -0,0 +1,17 @@
65.4 +:java.io.IOException:
65.5 +java.nio.charset.CharacterCodingException
65.6 +java.io.EOFException
65.7 +java.io.FileNotFoundException
65.8 +java.io.InterruptedIOException
65.9 +java.net.MalformedURLException
65.10 +java.io.IOException
65.11 +java.io.UnsupportedEncodingException
65.12 +java.io.NotActiveException
65.13 +java.io.StreamCorruptedException
65.14 +java.io.UTFDataFormatException
65.15 +java.util.zip.ZipException
65.16 +java.util.jar.JarException
65.17 +:java.util.Comparator:
65.18 +org.bar.Comparator3
65.19 +org.bar.Comparator2
65.20 +#position=5
66.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
66.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/services-jar-1.txt Sat Oct 31 15:28:13 2009 +0100
66.3 @@ -0,0 +1,17 @@
66.4 +:somedummyfile:
66.5 +org.foo.Interface
66.6 +:java.lang.Runnable:
66.7 +org.foo.impl.Runnable1
66.8 +:java.util.Comparator:
66.9 +#some comment
66.10 +org.foo.impl.Comparator1
66.11 +#position=10
66.12 +#som comment2
66.13 +:java.util.Iterator:
66.14 +org.foo.impl.Iterator1
66.15 +:org.foo.Interface:
66.16 +# Some header info, maybe.
66.17 +
66.18 +# Our first impl here
66.19 +org.foo.impl.Implementation1
66.20 +
67.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
67.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/services-jar-2.txt Sat Oct 31 15:28:13 2009 +0100
67.3 @@ -0,0 +1,10 @@
67.4 +:java.lang.Runnable:
67.5 +#-org.foo.impl.Runnable1
67.6 +:java.util.Comparator:
67.7 +org.bar.Comparator2
67.8 +#position=5
67.9 +:java.util.Iterator:
67.10 +org.bar.Iterator2
67.11 +#position=100
67.12 +:org.foo.Interface:
67.13 +org.bar.Implementation2
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
68.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/test/MockLookup.java Sat Oct 31 15:28:13 2009 +0100
68.3 @@ -0,0 +1,135 @@
68.4 +/*
68.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
68.6 + *
68.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
68.8 + *
68.9 + * The contents of this file are subject to the terms of either the GNU
68.10 + * General Public License Version 2 only ("GPL") or the Common
68.11 + * Development and Distribution License("CDDL") (collectively, the
68.12 + * "License"). You may not use this file except in compliance with the
68.13 + * License. You can obtain a copy of the License at
68.14 + * http://www.netbeans.org/cddl-gplv2.html
68.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
68.16 + * specific language governing permissions and limitations under the
68.17 + * License. When distributing the software, include this License Header
68.18 + * Notice in each file and include the License file at
68.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
68.20 + * particular file as subject to the "Classpath" exception as provided
68.21 + * by Sun in the GPL Version 2 section of the License file that
68.22 + * accompanied this code. If applicable, add the following below the
68.23 + * License Header, with the fields enclosed by brackets [] replaced by
68.24 + * your own identifying information:
68.25 + * "Portions Copyrighted [year] [name of copyright owner]"
68.26 + *
68.27 + * Contributor(s):
68.28 + *
68.29 + * The Original Software is NetBeans. The Initial Developer of the Original
68.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
68.31 + * Microsystems, Inc. All Rights Reserved.
68.32 + *
68.33 + * If you wish your version of this file to be governed by only the CDDL
68.34 + * or only the GPL Version 2, indicate your decision by adding
68.35 + * "[Contributor] elects to include this software in this distribution
68.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
68.37 + * single choice of license, a recipient has the option to distribute
68.38 + * your version of this file under either the CDDL, the GPL Version 2 or
68.39 + * to extend the choice of license to its licensees as provided above.
68.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
68.41 + * Version 2 license, then the option applies only if the new code is
68.42 + * made subject to such option by the copyright holder.
68.43 + */
68.44 +
68.45 +package org.openide.util.test;
68.46 +
68.47 +import java.lang.reflect.Field;
68.48 +import java.util.Collection;
68.49 +import static junit.framework.Assert.*;
68.50 +import org.openide.util.Lookup;
68.51 +import org.openide.util.lookup.Lookups;
68.52 +import org.openide.util.lookup.ProxyLookup;
68.53 +
68.54 +/**
68.55 + * Mock implementation of system default lookup suitable for use in unit tests.
68.56 + * The initial value just contains classpath services.
68.57 + */
68.58 +public class MockLookup extends ProxyLookup {
68.59 +
68.60 + private static MockLookup DEFAULT;
68.61 + private static boolean making = false;
68.62 + private static volatile boolean ready;
68.63 +
68.64 + static {
68.65 + making = true;
68.66 + try {
68.67 + System.setProperty("org.openide.util.Lookup", MockLookup.class.getName());
68.68 + if (Lookup.getDefault().getClass() != MockLookup.class) {
68.69 + // Someone else initialized lookup first. Try to force our way.
68.70 + Field defaultLookup = Lookup.class.getDeclaredField("defaultLookup");
68.71 + defaultLookup.setAccessible(true);
68.72 + defaultLookup.set(null, null);
68.73 + }
68.74 + assertEquals(MockLookup.class, Lookup.getDefault().getClass());
68.75 + } catch (Exception x) {
68.76 + throw new ExceptionInInitializerError(x);
68.77 + } finally {
68.78 + making = false;
68.79 + }
68.80 + }
68.81 +
68.82 + /** Do not call this directly! */
68.83 + public MockLookup() {
68.84 + assertTrue(making);
68.85 + assertNull(DEFAULT);
68.86 + DEFAULT = this;
68.87 + }
68.88 +
68.89 + /**
68.90 + * Just ensures that this lookup is default lookup, but does not actually change its content.
68.91 + * Useful mainly if you have some test utility method which calls foreign code which might use default lookup,
68.92 + * and you want to ensure that any users of mock lookup will see the correct default lookup right away,
68.93 + * even if they have not yet called {@link #setLookup} or {@link #setInstances}.
68.94 + */
68.95 + public static void init() {
68.96 + if (!ready) {
68.97 + setInstances();
68.98 + }
68.99 + }
68.100 +
68.101 + /**
68.102 + * Sets the global default lookup with zero or more delegate lookups.
68.103 + * Caution: if you don't include Lookups.metaInfServices, you may have trouble,
68.104 + * e.g. {@link #makeScratchDir} will not work.
68.105 + * Most of the time you should use {@link #setInstances} instead.
68.106 + */
68.107 + public static void setLookup(Lookup... lookups) {
68.108 + ready = true;
68.109 + DEFAULT.setLookups(lookups);
68.110 + }
68.111 +
68.112 + /**
68.113 + * Sets the global default lookup with some fixed instances.
68.114 + * Will also include (at a lower priority) a {@link ClassLoader},
68.115 + * and services found from <code>META-INF/services/*</code> in the classpath.
68.116 + */
68.117 + public static void setInstances(Object... instances) {
68.118 + ClassLoader l = MockLookup.class.getClassLoader();
68.119 + setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
68.120 + }
68.121 + /**
68.122 + * Sets the global default lookup with some fixed instances and
68.123 + * content read from Services folder from system file system.
68.124 + * Will also include (at a lower priority) a {@link ClassLoader},
68.125 + * and services found from <code>META-INF/services/*</code> in the classpath.
68.126 + */
68.127 + public static void setLayersAndInstances(Object... instances) {
68.128 + ClassLoader l = MockLookup.class.getClassLoader();
68.129 + if (l != Lookup.getDefault().lookup(ClassLoader.class)) {
68.130 + setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
68.131 + }
68.132 + Lookup projects = Lookups.forPath("Services");
68.133 + Collection<?> initialize = projects.lookupAll(Object.class);
68.134 + //System.err.println("all: " + initialize);
68.135 + setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l), projects);
68.136 + }
68.137 +
68.138 +}
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/test/MockLookupTest.java Sat Oct 31 15:28:13 2009 +0100
69.3 @@ -0,0 +1,66 @@
69.4 +/*
69.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
69.6 + *
69.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
69.8 + *
69.9 + * The contents of this file are subject to the terms of either the GNU
69.10 + * General Public License Version 2 only ("GPL") or the Common
69.11 + * Development and Distribution License("CDDL") (collectively, the
69.12 + * "License"). You may not use this file except in compliance with the
69.13 + * License. You can obtain a copy of the License at
69.14 + * http://www.netbeans.org/cddl-gplv2.html
69.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
69.16 + * specific language governing permissions and limitations under the
69.17 + * License. When distributing the software, include this License Header
69.18 + * Notice in each file and include the License file at
69.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
69.20 + * particular file as subject to the "Classpath" exception as provided
69.21 + * by Sun in the GPL Version 2 section of the License file that
69.22 + * accompanied this code. If applicable, add the following below the
69.23 + * License Header, with the fields enclosed by brackets [] replaced by
69.24 + * your own identifying information:
69.25 + * "Portions Copyrighted [year] [name of copyright owner]"
69.26 + *
69.27 + * Contributor(s):
69.28 + *
69.29 + * The Original Software is NetBeans. The Initial Developer of the Original
69.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
69.31 + * Microsystems, Inc. All Rights Reserved.
69.32 + *
69.33 + * If you wish your version of this file to be governed by only the CDDL
69.34 + * or only the GPL Version 2, indicate your decision by adding
69.35 + * "[Contributor] elects to include this software in this distribution
69.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
69.37 + * single choice of license, a recipient has the option to distribute
69.38 + * your version of this file under either the CDDL, the GPL Version 2 or
69.39 + * to extend the choice of license to its licensees as provided above.
69.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
69.41 + * Version 2 license, then the option applies only if the new code is
69.42 + * made subject to such option by the copyright holder.
69.43 + */
69.44 +
69.45 +package org.openide.util.test;
69.46 +
69.47 +import junit.framework.TestCase;
69.48 +import org.openide.util.Lookup;
69.49 +
69.50 +public class MockLookupTest extends TestCase {
69.51 +
69.52 + // XXX test:
69.53 + // setLookup with one or more lookup args does not use M-I/s
69.54 + // still works if another Lookup.getDefault was set before
69.55 +
69.56 + public MockLookupTest(String n) {
69.57 + super(n);
69.58 + }
69.59 +
69.60 + public void testSetLookup() throws Exception {
69.61 + MockLookup.setInstances("hello");
69.62 + assertEquals("initial lookup works", "hello", Lookup.getDefault().lookup(String.class));
69.63 + MockLookup.setInstances("goodbye");
69.64 + assertEquals("modified lookup works", "goodbye", Lookup.getDefault().lookup(String.class));
69.65 + MockLookup.setInstances();
69.66 + assertEquals("cleared lookup works", null, Lookup.getDefault().lookup(String.class));
69.67 + }
69.68 +
69.69 +}
70.1 --- a/openide.util/src/org/netbeans/modules/openide/util/ActiveQueue.java Sat Oct 31 15:06:58 2009 +0100
70.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
70.3 @@ -1,108 +0,0 @@
70.4 -package org.netbeans.modules.openide.util;
70.5 -
70.6 -import java.lang.ref.Reference;
70.7 -import java.lang.ref.ReferenceQueue;
70.8 -import java.util.logging.Level;
70.9 -import java.util.logging.Logger;
70.10 -
70.11 -/**
70.12 - * Implementation of the active reference queue.
70.13 - */
70.14 -public final class ActiveQueue extends ReferenceQueue<Object> implements Runnable {
70.15 -
70.16 - private static final Logger LOGGER = Logger.getLogger(ActiveQueue.class.getName().replace('$', '.'));
70.17 - private static ActiveQueue activeReferenceQueue;
70.18 -
70.19 - /** number of known outstanding references */
70.20 - private int count;
70.21 - private boolean deprecated;
70.22 -
70.23 - ActiveQueue(boolean deprecated) {
70.24 - super();
70.25 - this.deprecated = deprecated;
70.26 - }
70.27 -
70.28 - public static synchronized ReferenceQueue<Object> queue() {
70.29 - if (activeReferenceQueue == null) {
70.30 - activeReferenceQueue = new ActiveQueue(false);
70.31 - }
70.32 -
70.33 - activeReferenceQueue.ping();
70.34 -
70.35 - return activeReferenceQueue;
70.36 - }
70.37 -
70.38 - @Override
70.39 - public Reference<Object> poll() {
70.40 - throw new UnsupportedOperationException();
70.41 - }
70.42 -
70.43 - @Override
70.44 - public Reference<Object> remove(long timeout) throws IllegalArgumentException, InterruptedException {
70.45 - throw new InterruptedException();
70.46 - }
70.47 -
70.48 - @Override
70.49 - public Reference<Object> remove() throws InterruptedException {
70.50 - throw new InterruptedException();
70.51 - }
70.52 -
70.53 - public void run() {
70.54 - while (true) {
70.55 - try {
70.56 - Reference<?> ref = super.remove(0);
70.57 - LOGGER.finer("dequeued reference");
70.58 - if (!(ref instanceof Runnable)) {
70.59 - LOGGER.warning("A reference not implementing runnable has been added to the Utilities.activeReferenceQueue(): " + ref.getClass());
70.60 - continue;
70.61 - }
70.62 - if (deprecated) {
70.63 - LOGGER.warning("Utilities.ACTIVE_REFERENCE_QUEUE has been deprecated for " + ref.getClass() + " use Utilities.activeReferenceQueue");
70.64 - }
70.65 - // do the cleanup
70.66 - try {
70.67 - ((Runnable) ref).run();
70.68 - } catch (ThreadDeath td) {
70.69 - throw td;
70.70 - } catch (Throwable t) {
70.71 - // Should not happen.
70.72 - // If it happens, it is a bug in client code, notify!
70.73 - LOGGER.log(Level.WARNING, null, t);
70.74 - } finally {
70.75 - // to allow GC
70.76 - ref = null;
70.77 - }
70.78 - } catch (InterruptedException ex) {
70.79 - // Can happen during VM shutdown, it seems. Ignore.
70.80 - continue;
70.81 - }
70.82 - synchronized (this) {
70.83 - assert count > 0;
70.84 - count--;
70.85 - if (count == 0) {
70.86 - // We have processed all we have to process (for now at least).
70.87 - // Could be restarted later if ping() called again.
70.88 - // This could also happen in case someone called queue() once and tried
70.89 - // to use it for several references; in that case run() might never be called on
70.90 - // the later ones to be collected. Can't really protect against that situation.
70.91 - // See issue #86625 for details.
70.92 - LOGGER.fine("stopping thread");
70.93 - break;
70.94 - }
70.95 - }
70.96 - }
70.97 - }
70.98 -
70.99 - synchronized void ping() {
70.100 - if (count == 0) {
70.101 - Thread t = new Thread(this, "Active Reference Queue Daemon");
70.102 - t.setPriority(Thread.MIN_PRIORITY);
70.103 - t.setDaemon(true);
70.104 - t.start();
70.105 - LOGGER.fine("starting thread");
70.106 - } else {
70.107 - LOGGER.finer("enqueuing reference");
70.108 - }
70.109 - count++;
70.110 - }
70.111 -}
71.1 --- a/openide.util/src/org/netbeans/modules/openide/util/NamedServicesProvider.java Sat Oct 31 15:06:58 2009 +0100
71.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
71.3 @@ -1,81 +0,0 @@
71.4 -/*
71.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
71.6 - *
71.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
71.8 - *
71.9 - * The contents of this file are subject to the terms of either the GNU
71.10 - * General Public License Version 2 only ("GPL") or the Common
71.11 - * Development and Distribution License("CDDL") (collectively, the
71.12 - * "License"). You may not use this file except in compliance with the
71.13 - * License. You can obtain a copy of the License at
71.14 - * http://www.netbeans.org/cddl-gplv2.html
71.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
71.16 - * specific language governing permissions and limitations under the
71.17 - * License. When distributing the software, include this License Header
71.18 - * Notice in each file and include the License file at
71.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
71.20 - * particular file as subject to the "Classpath" exception as provided
71.21 - * by Sun in the GPL Version 2 section of the License file that
71.22 - * accompanied this code. If applicable, add the following below the
71.23 - * License Header, with the fields enclosed by brackets [] replaced by
71.24 - * your own identifying information:
71.25 - * "Portions Copyrighted [year] [name of copyright owner]"
71.26 - *
71.27 - * Contributor(s):
71.28 - *
71.29 - * The Original Software is NetBeans. The Initial Developer of the Original
71.30 - * Software is Sun Microsystems, Inc.
71.31 - *
71.32 - * Portions Copyrighted 2006 Sun Microsystems, Inc.
71.33 - */
71.34 -
71.35 -package org.netbeans.modules.openide.util;
71.36 -
71.37 -import java.lang.ref.Reference;
71.38 -import java.lang.ref.WeakReference;
71.39 -import java.util.Collections;
71.40 -import java.util.HashMap;
71.41 -import java.util.Map;
71.42 -import org.openide.util.Lookup;
71.43 -import org.openide.util.lookup.Lookups;
71.44 -
71.45 -/** Interface for core/startup and core/settings
71.46 - * to provide lookup over system filesystem.
71.47 - *
71.48 - * @author Jaroslav Tulach
71.49 - */
71.50 -public abstract class NamedServicesProvider {
71.51 -
71.52 - private static final Map<String,Reference<Lookup>> map = Collections.synchronizedMap(new HashMap<String,Reference<Lookup>>());
71.53 -
71.54 - public abstract Lookup create(String path);
71.55 -
71.56 - public static Lookup find(String path) {
71.57 - if (!path.endsWith("/")) {
71.58 - path = path + "/";
71.59 - }
71.60 -
71.61 - Reference<Lookup> ref = map.get(path);
71.62 - Lookup lkp = ref == null ? null : ref.get();
71.63 - if (lkp != null) {
71.64 - return lkp;
71.65 - }
71.66 - NamedServicesProvider prov = Lookup.getDefault().lookup(NamedServicesProvider.class);
71.67 - if (prov != null) {
71.68 - lkp = prov.create(path);
71.69 - } else {
71.70 - ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
71.71 - if (l == null) {
71.72 - l = Thread.currentThread().getContextClassLoader();
71.73 - if (l == null) {
71.74 - l = NamedServicesProvider.class.getClassLoader();
71.75 - }
71.76 - }
71.77 - lkp = Lookups.metaInfServices(l, "META-INF/namedservices/" + path);
71.78 - }
71.79 -
71.80 - map.put(path, new WeakReference<Lookup>(lkp));
71.81 - return lkp;
71.82 - }
71.83 -
71.84 -}
72.1 --- a/openide.util/src/org/openide/util/Lookup.java Sat Oct 31 15:06:58 2009 +0100
72.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
72.3 @@ -1,544 +0,0 @@
72.4 -/*
72.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
72.6 - *
72.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
72.8 - *
72.9 - * The contents of this file are subject to the terms of either the GNU
72.10 - * General Public License Version 2 only ("GPL") or the Common
72.11 - * Development and Distribution License("CDDL") (collectively, the
72.12 - * "License"). You may not use this file except in compliance with the
72.13 - * License. You can obtain a copy of the License at
72.14 - * http://www.netbeans.org/cddl-gplv2.html
72.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
72.16 - * specific language governing permissions and limitations under the
72.17 - * License. When distributing the software, include this License Header
72.18 - * Notice in each file and include the License file at
72.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
72.20 - * particular file as subject to the "Classpath" exception as provided
72.21 - * by Sun in the GPL Version 2 section of the License file that
72.22 - * accompanied this code. If applicable, add the following below the
72.23 - * License Header, with the fields enclosed by brackets [] replaced by
72.24 - * your own identifying information:
72.25 - * "Portions Copyrighted [year] [name of copyright owner]"
72.26 - *
72.27 - * Contributor(s):
72.28 - *
72.29 - * The Original Software is NetBeans. The Initial Developer of the Original
72.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
72.31 - * Microsystems, Inc. All Rights Reserved.
72.32 - *
72.33 - * If you wish your version of this file to be governed by only the CDDL
72.34 - * or only the GPL Version 2, indicate your decision by adding
72.35 - * "[Contributor] elects to include this software in this distribution
72.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
72.37 - * single choice of license, a recipient has the option to distribute
72.38 - * your version of this file under either the CDDL, the GPL Version 2 or
72.39 - * to extend the choice of license to its licensees as provided above.
72.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
72.41 - * Version 2 license, then the option applies only if the new code is
72.42 - * made subject to such option by the copyright holder.
72.43 - */
72.44 -
72.45 -package org.openide.util;
72.46 -
72.47 -import java.util.ArrayList;
72.48 -import java.util.Collection;
72.49 -import java.util.Collections;
72.50 -import java.util.Iterator;
72.51 -import java.util.List;
72.52 -import java.util.Set;
72.53 -import org.openide.util.lookup.Lookups;
72.54 -import org.openide.util.lookup.ProxyLookup;
72.55 -import org.openide.util.lookup.ServiceProvider;
72.56 -
72.57 -/**
72.58 - * A general registry permitting clients to find instances of services
72.59 - * (implementation of a given interface).
72.60 - * This class is inspired by the
72.61 - * <a href="http://www.jini.org/">Jini</a>
72.62 - * registration and lookup mechanism. The difference is that the methods do
72.63 - * not throw checked exceptions (as they usually work only locally and not over the network)
72.64 - * and that the Lookup API concentrates on the lookup, not on the registration
72.65 - * (although {@link Lookup#getDefault} is strongly encouraged to support
72.66 - * {@link Lookups#metaInfServices} for registration in addition to whatever
72.67 - * else it decides to support).
72.68 - * <p>
72.69 - * For a general talk about the idea behind the lookup pattern please see
72.70 - * <UL>
72.71 - * <LI><a href="lookup/doc-files/index.html">The Solution to Communication Between Components</a>
72.72 - * page
72.73 - * <LI>the introduction to the <a href="lookup/doc-files/lookup-api.html">lookup API via
72.74 - * use cases</a>
72.75 - * <LI>the examples of <a href="lookup/doc-files/lookup-spi.html">how to write your own lookup</a>
72.76 - * </UL>
72.77 - *
72.78 - * @see org.openide.util.lookup.AbstractLookup
72.79 - * @see Lookups
72.80 - * @see LookupListener
72.81 - * @see LookupEvent
72.82 - * @author Jaroslav Tulach
72.83 - */
72.84 -public abstract class Lookup {
72.85 - /** A dummy lookup that never returns any results.
72.86 - */
72.87 - public static final Lookup EMPTY = new Empty();
72.88 -
72.89 - /** default instance */
72.90 - private static Lookup defaultLookup;
72.91 -
72.92 - /** Empty constructor for use by subclasses. */
72.93 - public Lookup() {
72.94 - }
72.95 -
72.96 - /** Static method to obtain the global lookup in the whole system.
72.97 - * The actual returned implementation can be different in different
72.98 - * systems, but the default one is based on
72.99 - * {@link org.openide.util.lookup.Lookups#metaInfServices}
72.100 - * with the context classloader of the first caller. Each system is
72.101 - * adviced to honor this and include some form of <code>metaInfServices</code>
72.102 - * implementation in the returned lookup as usage of <code>META-INF/services</code>
72.103 - * is a JDK standard.
72.104 - *
72.105 - * @return the global lookup in the system
72.106 - * @see ServiceProvider
72.107 - */
72.108 - public static synchronized Lookup getDefault() {
72.109 - if (defaultLookup != null) {
72.110 - return defaultLookup;
72.111 - }
72.112 -
72.113 - // You can specify a Lookup impl using a system property if you like.
72.114 - String className = System.getProperty("org.openide.util.Lookup" // NOI18N
72.115 - );
72.116 -
72.117 - if ("-".equals(className)) { // NOI18N
72.118 -
72.119 - // Suppress even MetaInfServicesLookup.
72.120 - return EMPTY;
72.121 - }
72.122 -
72.123 - ClassLoader l = Thread.currentThread().getContextClassLoader();
72.124 -
72.125 - try {
72.126 - if (className != null) {
72.127 - defaultLookup = (Lookup) Class.forName(className, true, l).newInstance();
72.128 -
72.129 - return defaultLookup;
72.130 - }
72.131 - } catch (Exception e) {
72.132 - // do not use ErrorManager because we are in the startup code
72.133 - // and ErrorManager might not be ready
72.134 - e.printStackTrace();
72.135 - }
72.136 -
72.137 - // OK, none specified (successfully) in a system property.
72.138 - // Try MetaInfServicesLookup as a default, which may also
72.139 - // have a org.openide.util.Lookup line specifying the lookup.
72.140 - Lookup misl = Lookups.metaInfServices(l);
72.141 - defaultLookup = misl.lookup(Lookup.class);
72.142 -
72.143 - if (defaultLookup != null) {
72.144 - return defaultLookup;
72.145 - }
72.146 -
72.147 - // You may also specify a Lookup.Provider.
72.148 - Lookup.Provider prov = misl.lookup(Lookup.Provider.class);
72.149 -
72.150 - if (prov != null) {
72.151 - defaultLookup = Lookups.proxy(prov);
72.152 -
72.153 - return defaultLookup;
72.154 - }
72.155 -
72.156 - DefLookup def = new DefLookup();
72.157 - def.init(l, misl, false);
72.158 - defaultLookup = def;
72.159 - def.init(l, misl, true);
72.160 - return defaultLookup;
72.161 - }
72.162 -
72.163 - private static final class DefLookup extends ProxyLookup {
72.164 - public DefLookup() {
72.165 - super(new Lookup[0]);
72.166 - }
72.167 -
72.168 - public void init(ClassLoader loader, Lookup metaInfLookup, boolean addPath) {
72.169 - // Had no such line, use simple impl.
72.170 - // It does however need to have ClassLoader available or many things will break.
72.171 - // Use the thread context classloader in effect now.
72.172 - Lookup clLookup = Lookups.singleton(loader);
72.173 - List<Lookup> arr = new ArrayList<Lookup>();
72.174 - arr.add(metaInfLookup);
72.175 - arr.add(clLookup);
72.176 - String paths = System.getProperty("org.openide.util.Lookup.paths"); // NOI18N
72.177 - if (addPath && paths != null) {
72.178 - for (String p : paths.split(":")) { // NOI18N
72.179 - arr.add(Lookups.forPath(p));
72.180 - }
72.181 - }
72.182 - setLookups(arr.toArray(new Lookup[0]));
72.183 - }
72.184 - }
72.185 -
72.186 - /** Called from MockServices to reset default lookup in case services change
72.187 - */
72.188 - private static void resetDefaultLookup() {
72.189 - if (defaultLookup instanceof DefLookup) {
72.190 - DefLookup def = (DefLookup)defaultLookup;
72.191 - ClassLoader l = Thread.currentThread().getContextClassLoader();
72.192 - def.init(l, Lookups.metaInfServices(l), true);
72.193 - }
72.194 - }
72.195 -
72.196 - /** Look up an object matching a given interface.
72.197 - * This is the simplest method to use.
72.198 - * If more than one object matches, the first will be returned.
72.199 - * The template class may be a class or interface; the instance is
72.200 - * guaranteed to be assignable to it.
72.201 - *
72.202 - * @param clazz class of the object we are searching for
72.203 - * @return an object implementing the given class or <code>null</code> if no such
72.204 - * implementation is found
72.205 - */
72.206 - public abstract <T> T lookup(Class<T> clazz);
72.207 -
72.208 - /** The general lookup method. Callers can get list of all instances and classes
72.209 - * that match the given <code>template</code>, request more info about
72.210 - * them in form of {@link Lookup.Item} and attach a listener to
72.211 - * this be notified about changes. The general interface does not
72.212 - * specify whether subsequent calls with the same template produce new
72.213 - * instance of the {@link Lookup.Result} or return shared instance. The
72.214 - * prefered behaviour however is to return shared one.
72.215 - *
72.216 - * @param template a template describing the services to look for
72.217 - * @return an object containing the results
72.218 - */
72.219 - public abstract <T> Result<T> lookup(Template<T> template);
72.220 -
72.221 - /** Look up the first item matching a given template.
72.222 - * Includes not only the instance but other associated information.
72.223 - * @param template the template to check
72.224 - * @return a matching item or <code>null</code>
72.225 - *
72.226 - * @since 1.8
72.227 - */
72.228 - public <T> Item<T> lookupItem(Template<T> template) {
72.229 - Result<T> res = lookup(template);
72.230 - Iterator<? extends Item<T>> it = res.allItems().iterator();
72.231 - return it.hasNext() ? it.next() : null;
72.232 - }
72.233 -
72.234 - /**
72.235 - * Find a result corresponding to a given class.
72.236 - * Equivalent to calling {@link #lookup(Lookup.Template)} but slightly more convenient.
72.237 - * Subclasses may override this method to produce the same semantics more efficiently.
72.238 - * @param clazz the supertype of the result
72.239 - * @return a live object representing instances of that type
72.240 - * @since org.openide.util 6.10
72.241 - */
72.242 - public <T> Lookup.Result<T> lookupResult(Class<T> clazz) {
72.243 - return lookup(new Lookup.Template<T>(clazz));
72.244 - }
72.245 -
72.246 - /**
72.247 - * Find all instances corresponding to a given class.
72.248 - * Equivalent to calling {@link #lookupResult} and asking for {@link Lookup.Result#allInstances} but slightly more convenient.
72.249 - * Subclasses may override this method to produce the same semantics more efficiently.
72.250 - * <div class="nonnormative">
72.251 - * <p>Example usage:</p>
72.252 - * <pre>
72.253 - * for (MyService svc : Lookup.getDefault().lookupAll(MyService.class)) {
72.254 - * svc.useMe();
72.255 - * }
72.256 - * </pre>
72.257 - * </div>
72.258 - * @param clazz the supertype of the result
72.259 - * @return all currently available instances of that type
72.260 - * @since org.openide.util 6.10
72.261 - */
72.262 - public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
72.263 - return lookupResult(clazz).allInstances();
72.264 - }
72.265 -
72.266 - /**
72.267 - * Objects implementing interface Lookup.Provider are capable of
72.268 - * and willing to provide a lookup (usually bound to the object).
72.269 - * @since 3.6
72.270 - */
72.271 - public interface Provider {
72.272 - /**
72.273 - * Returns lookup associated with the object.
72.274 - * @return fully initialized lookup instance provided by this object
72.275 - */
72.276 - Lookup getLookup();
72.277 - }
72.278 -
72.279 - /*
72.280 - * I expect this class to grow in the future, but for now, it is
72.281 - * enough to start with something simple.
72.282 - */
72.283 -
72.284 - /** Template defining a pattern to filter instances by.
72.285 - */
72.286 - public static final class Template<T> extends Object {
72.287 - /** cached hash code */
72.288 - private int hashCode;
72.289 -
72.290 - /** type of the service */
72.291 - private Class<T> type;
72.292 -
72.293 - /** identity to search for */
72.294 - private String id;
72.295 -
72.296 - /** instance to search for */
72.297 - private T instance;
72.298 -
72.299 - /** General template to find all possible instances.
72.300 - * @deprecated Use <code>new Template (Object.class)</code> which
72.301 - * is going to be better typed with JDK1.5 templates and should produce
72.302 - * the same result.
72.303 - */
72.304 - @Deprecated
72.305 - public Template() {
72.306 - this(null);
72.307 - }
72.308 -
72.309 - /** Create a simple template matching by class.
72.310 - * @param type the class of service we are looking for (subclasses will match)
72.311 - */
72.312 - public Template(Class<T> type) {
72.313 - this(type, null, null);
72.314 - }
72.315 -
72.316 - /** Constructor to create new template.
72.317 - * @param type the class of service we are looking for or <code>null</code> to leave unspecified
72.318 - * @param id the ID of the item/service we are looking for or <code>null</code> to leave unspecified
72.319 - * @param instance a specific known instance to look for or <code>null</code> to leave unspecified
72.320 - */
72.321 - public Template(Class<T> type, String id, T instance) {
72.322 - this.type = extractType(type);
72.323 - this.id = id;
72.324 - this.instance = instance;
72.325 - }
72.326 -
72.327 - @SuppressWarnings("unchecked")
72.328 - private Class<T> extractType(Class<T> type) {
72.329 - return (type == null) ? (Class<T>)Object.class : type;
72.330 - }
72.331 -
72.332 - /** Get the class (or superclass or interface) to search for.
72.333 - * If it was not specified in the constructor, <code>Object</code> is used as
72.334 - * this will match any instance.
72.335 - * @return the class to search for
72.336 - */
72.337 - public Class<T> getType() {
72.338 - return type;
72.339 - }
72.340 -
72.341 - /** Get the persistent identifier being searched for, if any.
72.342 - * @return the ID or <code>null</code>
72.343 - * @see Lookup.Item#getId
72.344 - *
72.345 - * @since 1.8
72.346 - */
72.347 - public String getId() {
72.348 - return id;
72.349 - }
72.350 -
72.351 - /** Get the specific instance being searched for, if any.
72.352 - * Most useful for finding an <code>Item</code> when the instance
72.353 - * is already known.
72.354 - *
72.355 - * @return the object to find or <code>null</code>
72.356 - *
72.357 - * @since 1.8
72.358 - */
72.359 - public T getInstance() {
72.360 - return instance;
72.361 - }
72.362 -
72.363 - /* Computes hashcode for this template. The hashcode is cached.
72.364 - * @return hashcode
72.365 - */
72.366 - @Override
72.367 - public int hashCode() {
72.368 - if (hashCode != 0) {
72.369 - return hashCode;
72.370 - }
72.371 -
72.372 - hashCode = ((type == null) ? 1 : type.hashCode()) + ((id == null) ? 2 : id.hashCode()) +
72.373 - ((instance == null) ? 3 : 0);
72.374 -
72.375 - return hashCode;
72.376 - }
72.377 -
72.378 - /* Checks whether two templates represent the same query.
72.379 - * @param obj another template to check
72.380 - * @return true if so, false otherwise
72.381 - */
72.382 - @Override
72.383 - public boolean equals(Object obj) {
72.384 - if (!(obj instanceof Template)) {
72.385 - return false;
72.386 - }
72.387 -
72.388 - Template t = (Template) obj;
72.389 -
72.390 - if (hashCode() != t.hashCode()) {
72.391 - // this is an optimalization - the hashCodes should have been
72.392 - // precomputed
72.393 - return false;
72.394 - }
72.395 -
72.396 - if (type != t.type) {
72.397 - return false;
72.398 - }
72.399 -
72.400 - if (id == null) {
72.401 - if (t.id != null) {
72.402 - return false;
72.403 - }
72.404 - } else {
72.405 - if (!id.equals(t.id)) {
72.406 - return false;
72.407 - }
72.408 - }
72.409 -
72.410 - if (instance == null) {
72.411 - return (t.instance == null);
72.412 - } else {
72.413 - return instance.equals(t.instance);
72.414 - }
72.415 - }
72.416 -
72.417 - /* for debugging */
72.418 - @Override
72.419 - public String toString() {
72.420 - return "Lookup.Template[type=" + type + ",id=" + id + ",instance=" + instance + "]"; // NOI18N
72.421 - }
72.422 - }
72.423 -
72.424 - /** Result of a lookup request.
72.425 - * Allows access to all matching instances at once.
72.426 - * Also permits listening to changes in the result.
72.427 - * Result can contain duplicate items.
72.428 - */
72.429 - public static abstract class Result<T> extends Object {
72.430 - /** Registers a listener that is invoked when there is a possible
72.431 - * change in this result.
72.432 - *
72.433 - * @param l the listener to add
72.434 - */
72.435 - public abstract void addLookupListener(LookupListener l);
72.436 -
72.437 - /** Unregisters a listener previously added.
72.438 - * @param l the listener to remove
72.439 - */
72.440 - public abstract void removeLookupListener(LookupListener l);
72.441 -
72.442 - /** Get all instances in the result. The return value type
72.443 - * should be List instead of Collection, but it is too late to change it.
72.444 - * @return unmodifiable collection of all instances that will never change its content
72.445 - */
72.446 - public abstract Collection<? extends T> allInstances();
72.447 -
72.448 - /** Get all classes represented in the result.
72.449 - * That is, the set of concrete classes
72.450 - * used by instances present in the result.
72.451 - * All duplicate classes will be omitted.
72.452 - * @return unmodifiable set of <code>Class</code> objects that will never change its content
72.453 - *
72.454 - * @since 1.8
72.455 - */
72.456 - public Set<Class<? extends T>> allClasses() {
72.457 - return Collections.emptySet();
72.458 - }
72.459 -
72.460 - /** Get all registered items.
72.461 - * This should include all pairs of instances together
72.462 - * with their classes, IDs, and so on. The return value type
72.463 - * should be List instead of Collection, but it is too late to change it.
72.464 - * @return unmodifiable collection of {@link Lookup.Item} that will never change its content
72.465 - *
72.466 - * @since 1.8
72.467 - */
72.468 - public Collection<? extends Item<T>> allItems() {
72.469 - return Collections.emptyList();
72.470 - }
72.471 - }
72.472 -
72.473 - /** A single item in a lookup result.
72.474 - * This wrapper provides unified access to not just the instance,
72.475 - * but its class, a possible persistent identifier, and so on.
72.476 - *
72.477 - * @since 1.25
72.478 - */
72.479 - public static abstract class Item<T> extends Object {
72.480 - /** Get the instance itself.
72.481 - * @return the instance or null if the instance cannot be created
72.482 - */
72.483 - public abstract T getInstance();
72.484 -
72.485 - /** Get the implementing class of the instance.
72.486 - * @return the class of the item
72.487 - */
72.488 - public abstract Class<? extends T> getType();
72.489 -
72.490 - // XXX can it be null??
72.491 -
72.492 - /** Get a persistent indentifier for the item.
72.493 - * This identifier should uniquely represent the item
72.494 - * within its containing lookup (and if possible within the
72.495 - * global lookup as a whole). For example, it might represent
72.496 - * the source of the instance as a file name. The ID may be
72.497 - * persisted and in a later session used to find the same instance
72.498 - * as was encountered earlier, by means of passing it into a
72.499 - * lookup template.
72.500 - *
72.501 - * @return a string ID of the item
72.502 - */
72.503 - public abstract String getId();
72.504 -
72.505 - /** Get a human presentable name for the item.
72.506 - * This might be used when summarizing all the items found in a
72.507 - * lookup result in some part of a GUI.
72.508 - * @return the string suitable for presenting the object to a user
72.509 - */
72.510 - public abstract String getDisplayName();
72.511 -
72.512 - /* show ID for debugging */
72.513 - @Override
72.514 - public String toString() {
72.515 - return getId();
72.516 - }
72.517 - }
72.518 -
72.519 - //
72.520 - // Implementation of the default lookup
72.521 - //
72.522 - private static final class Empty extends Lookup {
72.523 - private static final Result NO_RESULT = new Result() {
72.524 - public void addLookupListener(LookupListener l) {
72.525 - }
72.526 -
72.527 - public void removeLookupListener(LookupListener l) {
72.528 - }
72.529 -
72.530 - public Collection allInstances() {
72.531 - return Collections.EMPTY_SET;
72.532 - }
72.533 - };
72.534 -
72.535 - Empty() {
72.536 - }
72.537 -
72.538 - public <T> T lookup(Class<T> clazz) {
72.539 - return null;
72.540 - }
72.541 -
72.542 - @SuppressWarnings("unchecked")
72.543 - public <T> Result<T> lookup(Template<T> template) {
72.544 - return NO_RESULT;
72.545 - }
72.546 - }
72.547 -}
73.1 --- a/openide.util/src/org/openide/util/LookupEvent.java Sat Oct 31 15:06:58 2009 +0100
73.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
73.3 @@ -1,57 +0,0 @@
73.4 -/*
73.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
73.6 - *
73.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
73.8 - *
73.9 - * The contents of this file are subject to the terms of either the GNU
73.10 - * General Public License Version 2 only ("GPL") or the Common
73.11 - * Development and Distribution License("CDDL") (collectively, the
73.12 - * "License"). You may not use this file except in compliance with the
73.13 - * License. You can obtain a copy of the License at
73.14 - * http://www.netbeans.org/cddl-gplv2.html
73.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
73.16 - * specific language governing permissions and limitations under the
73.17 - * License. When distributing the software, include this License Header
73.18 - * Notice in each file and include the License file at
73.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
73.20 - * particular file as subject to the "Classpath" exception as provided
73.21 - * by Sun in the GPL Version 2 section of the License file that
73.22 - * accompanied this code. If applicable, add the following below the
73.23 - * License Header, with the fields enclosed by brackets [] replaced by
73.24 - * your own identifying information:
73.25 - * "Portions Copyrighted [year] [name of copyright owner]"
73.26 - *
73.27 - * Contributor(s):
73.28 - *
73.29 - * The Original Software is NetBeans. The Initial Developer of the Original
73.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
73.31 - * Microsystems, Inc. All Rights Reserved.
73.32 - *
73.33 - * If you wish your version of this file to be governed by only the CDDL
73.34 - * or only the GPL Version 2, indicate your decision by adding
73.35 - * "[Contributor] elects to include this software in this distribution
73.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
73.37 - * single choice of license, a recipient has the option to distribute
73.38 - * your version of this file under either the CDDL, the GPL Version 2 or
73.39 - * to extend the choice of license to its licensees as provided above.
73.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
73.41 - * Version 2 license, then the option applies only if the new code is
73.42 - * made subject to such option by the copyright holder.
73.43 - */
73.44 -package org.openide.util;
73.45 -
73.46 -import java.util.*;
73.47 -
73.48 -
73.49 -/** An event describing the change in the lookup's result.
73.50 - *
73.51 - * @author Jaroslav Tulach
73.52 - */
73.53 -public final class LookupEvent extends EventObject {
73.54 - /** Create a new lookup event.
73.55 - * @param source the lookup result which has changed
73.56 - */
73.57 - public LookupEvent(Lookup.Result source) {
73.58 - super(source);
73.59 - }
73.60 -}
74.1 --- a/openide.util/src/org/openide/util/LookupListener.java Sat Oct 31 15:06:58 2009 +0100
74.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
74.3 @@ -1,59 +0,0 @@
74.4 -/*
74.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
74.6 - *
74.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
74.8 - *
74.9 - * The contents of this file are subject to the terms of either the GNU
74.10 - * General Public License Version 2 only ("GPL") or the Common
74.11 - * Development and Distribution License("CDDL") (collectively, the
74.12 - * "License"). You may not use this file except in compliance with the
74.13 - * License. You can obtain a copy of the License at
74.14 - * http://www.netbeans.org/cddl-gplv2.html
74.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
74.16 - * specific language governing permissions and limitations under the
74.17 - * License. When distributing the software, include this License Header
74.18 - * Notice in each file and include the License file at
74.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
74.20 - * particular file as subject to the "Classpath" exception as provided
74.21 - * by Sun in the GPL Version 2 section of the License file that
74.22 - * accompanied this code. If applicable, add the following below the
74.23 - * License Header, with the fields enclosed by brackets [] replaced by
74.24 - * your own identifying information:
74.25 - * "Portions Copyrighted [year] [name of copyright owner]"
74.26 - *
74.27 - * Contributor(s):
74.28 - *
74.29 - * The Original Software is NetBeans. The Initial Developer of the Original
74.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
74.31 - * Microsystems, Inc. All Rights Reserved.
74.32 - *
74.33 - * If you wish your version of this file to be governed by only the CDDL
74.34 - * or only the GPL Version 2, indicate your decision by adding
74.35 - * "[Contributor] elects to include this software in this distribution
74.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
74.37 - * single choice of license, a recipient has the option to distribute
74.38 - * your version of this file under either the CDDL, the GPL Version 2 or
74.39 - * to extend the choice of license to its licensees as provided above.
74.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
74.41 - * Version 2 license, then the option applies only if the new code is
74.42 - * made subject to such option by the copyright holder.
74.43 - */
74.44 -package org.openide.util;
74.45 -
74.46 -import java.util.*;
74.47 -
74.48 -
74.49 -/** General listener for changes in lookup.
74.50 - *
74.51 - * @author Jaroslav Tulach
74.52 - */
74.53 -public interface LookupListener extends EventListener {
74.54 - /** A change in lookup occured. Please note that this method
74.55 - * should never block since it might be called from lookup implementation
74.56 - * internal threads. If you block here you are in risk that the thread
74.57 - * you wait for might in turn to wait for the lookup internal thread to
74.58 - * finish its work.
74.59 - * @param ev event describing the change
74.60 - */
74.61 - public void resultChanged(LookupEvent ev);
74.62 -}
75.1 --- a/openide.util/src/org/openide/util/lookup/ALPairComparator.java Sat Oct 31 15:06:58 2009 +0100
75.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
75.3 @@ -1,88 +0,0 @@
75.4 -/*
75.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
75.6 - *
75.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
75.8 - *
75.9 - * The contents of this file are subject to the terms of either the GNU
75.10 - * General Public License Version 2 only ("GPL") or the Common
75.11 - * Development and Distribution License("CDDL") (collectively, the
75.12 - * "License"). You may not use this file except in compliance with the
75.13 - * License. You can obtain a copy of the License at
75.14 - * http://www.netbeans.org/cddl-gplv2.html
75.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
75.16 - * specific language governing permissions and limitations under the
75.17 - * License. When distributing the software, include this License Header
75.18 - * Notice in each file and include the License file at
75.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
75.20 - * particular file as subject to the "Classpath" exception as provided
75.21 - * by Sun in the GPL Version 2 section of the License file that
75.22 - * accompanied this code. If applicable, add the following below the
75.23 - * License Header, with the fields enclosed by brackets [] replaced by
75.24 - * your own identifying information:
75.25 - * "Portions Copyrighted [year] [name of copyright owner]"
75.26 - *
75.27 - * Contributor(s):
75.28 - *
75.29 - * The Original Software is NetBeans. The Initial Developer of the Original
75.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
75.31 - * Microsystems, Inc. All Rights Reserved.
75.32 - *
75.33 - * If you wish your version of this file to be governed by only the CDDL
75.34 - * or only the GPL Version 2, indicate your decision by adding
75.35 - * "[Contributor] elects to include this software in this distribution
75.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
75.37 - * single choice of license, a recipient has the option to distribute
75.38 - * your version of this file under either the CDDL, the GPL Version 2 or
75.39 - * to extend the choice of license to its licensees as provided above.
75.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
75.41 - * Version 2 license, then the option applies only if the new code is
75.42 - * made subject to such option by the copyright holder.
75.43 - */
75.44 -package org.openide.util.lookup;
75.45 -
75.46 -import java.util.Comparator;
75.47 -import org.openide.util.lookup.AbstractLookup.Pair;
75.48 -
75.49 -
75.50 -/** Implementation of comparator for AbstractLookup.Pair
75.51 - *
75.52 - * @author Jaroslav Tulach
75.53 - */
75.54 -final class ALPairComparator implements Comparator<Pair<?>> {
75.55 - public static final Comparator<Pair<?>> DEFAULT = new ALPairComparator();
75.56 -
75.57 - /** Creates a new instance of ALPairComparator */
75.58 - private ALPairComparator() {
75.59 - }
75.60 -
75.61 - /** Compares two items.
75.62 - */
75.63 - public int compare(Pair<?> i1, Pair<?> i2) {
75.64 - int result = i1.getIndex() - i2.getIndex();
75.65 -
75.66 - if (result == 0) {
75.67 - if (i1 != i2) {
75.68 - java.io.ByteArrayOutputStream bs = new java.io.ByteArrayOutputStream();
75.69 - java.io.PrintStream ps = new java.io.PrintStream(bs);
75.70 -
75.71 - ps.println(
75.72 - "Duplicate pair in tree" + // NOI18N
75.73 - "Pair1: " + i1 + " pair2: " + i2 + " index1: " + i1.getIndex() + " index2: " +
75.74 - i2.getIndex() // NOI18N
75.75 - +" item1: " + i1.getInstance() + " item2: " + i2.getInstance() // NOI18N
75.76 - +" id1: " + Integer.toHexString(System.identityHashCode(i1)) // NOI18N
75.77 - +" id2: " + Integer.toHexString(System.identityHashCode(i2)) // NOI18N
75.78 - );
75.79 -
75.80 - // print (ps, false);
75.81 - ps.close();
75.82 -
75.83 - throw new IllegalStateException(bs.toString());
75.84 - }
75.85 -
75.86 - return 0;
75.87 - }
75.88 -
75.89 - return result;
75.90 - }
75.91 -}
76.1 --- a/openide.util/src/org/openide/util/lookup/AbstractLookup.java Sat Oct 31 15:06:58 2009 +0100
76.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
76.3 @@ -1,1467 +0,0 @@
76.4 -/*
76.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
76.6 - *
76.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
76.8 - *
76.9 - * The contents of this file are subject to the terms of either the GNU
76.10 - * General Public License Version 2 only ("GPL") or the Common
76.11 - * Development and Distribution License("CDDL") (collectively, the
76.12 - * "License"). You may not use this file except in compliance with the
76.13 - * License. You can obtain a copy of the License at
76.14 - * http://www.netbeans.org/cddl-gplv2.html
76.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
76.16 - * specific language governing permissions and limitations under the
76.17 - * License. When distributing the software, include this License Header
76.18 - * Notice in each file and include the License file at
76.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
76.20 - * particular file as subject to the "Classpath" exception as provided
76.21 - * by Sun in the GPL Version 2 section of the License file that
76.22 - * accompanied this code. If applicable, add the following below the
76.23 - * License Header, with the fields enclosed by brackets [] replaced by
76.24 - * your own identifying information:
76.25 - * "Portions Copyrighted [year] [name of copyright owner]"
76.26 - *
76.27 - * Contributor(s):
76.28 - *
76.29 - * The Original Software is NetBeans. The Initial Developer of the Original
76.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
76.31 - * Microsystems, Inc. All Rights Reserved.
76.32 - *
76.33 - * If you wish your version of this file to be governed by only the CDDL
76.34 - * or only the GPL Version 2, indicate your decision by adding
76.35 - * "[Contributor] elects to include this software in this distribution
76.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
76.37 - * single choice of license, a recipient has the option to distribute
76.38 - * your version of this file under either the CDDL, the GPL Version 2 or
76.39 - * to extend the choice of license to its licensees as provided above.
76.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
76.41 - * Version 2 license, then the option applies only if the new code is
76.42 - * made subject to such option by the copyright holder.
76.43 - */
76.44 -package org.openide.util.lookup;
76.45 -
76.46 -import java.io.PrintStream;
76.47 -import org.openide.util.Lookup;
76.48 -import org.openide.util.LookupEvent;
76.49 -import org.openide.util.LookupListener;
76.50 -
76.51 -import java.io.IOException;
76.52 -import java.io.ObjectOutputStream;
76.53 -import java.io.Serializable;
76.54 -
76.55 -import java.lang.ref.ReferenceQueue;
76.56 -import java.lang.ref.WeakReference;
76.57 -import java.util.ArrayList;
76.58 -import java.util.Arrays;
76.59 -import java.util.Collection;
76.60 -import java.util.Collections;
76.61 -import java.util.Enumeration;
76.62 -import java.util.HashMap;
76.63 -import java.util.HashSet;
76.64 -import java.util.Iterator;
76.65 -import java.util.LinkedHashSet;
76.66 -import java.util.Map;
76.67 -import java.util.Set;
76.68 -import java.util.TreeSet;
76.69 -
76.70 -import java.util.concurrent.Executor;
76.71 -import org.netbeans.modules.openide.util.ActiveQueue;
76.72 -
76.73 -
76.74 -/** Implementation of the lookup from OpenAPIs that is based on the
76.75 - * introduction of Item. This class should provide the default way
76.76 - * of how to store (Class, Object) pairs in the lookups. It offers
76.77 - * protected methods for subclasses to register the pairs.
76.78 - * <p>Serializable since 3.27.
76.79 - * @author Jaroslav Tulach
76.80 - * @since 1.9
76.81 - */
76.82 -public class AbstractLookup extends Lookup implements Serializable {
76.83 - static final long serialVersionUID = 5L;
76.84 -
76.85 - /** lock for initialization of the maps of lookups */
76.86 - private static final Object treeLock = new Object();
76.87 -
76.88 - /** the tree that registers all items (or Integer as a treshold size) */
76.89 - private Object tree;
76.90 -
76.91 - /** count of items in to lookup */
76.92 - private int count;
76.93 -
76.94 - /** Constructor to create this lookup and associate it with given
76.95 - * Content. The content than allows the creator to invoke protected
76.96 - * methods which are not accessible for any other user of the lookup.
76.97 - *
76.98 - * @param content the content to assciate with
76.99 - *
76.100 - * @since 1.25
76.101 - */
76.102 - public AbstractLookup(Content content) {
76.103 - content.attach(this);
76.104 - }
76.105 -
76.106 - /** Constructor for testing purposes that allows specification of storage
76.107 - * as mechanism as well.
76.108 - */
76.109 - AbstractLookup(Content content, Storage<?> storage) {
76.110 - this(content);
76.111 - this.tree = storage;
76.112 - initialize();
76.113 - }
76.114 -
76.115 - /** Constructor for testing purposes that allows specification of storage
76.116 - * as mechanism as well.
76.117 - * @param trashhold number of Pair to "remain small"
76.118 - */
76.119 - AbstractLookup(Content content, Integer trashhold) {
76.120 - this(content);
76.121 - this.tree = trashhold;
76.122 - }
76.123 -
76.124 - /** Default constructor for subclasses that do not need to provide a content
76.125 - */
76.126 - protected AbstractLookup() {
76.127 - }
76.128 -
76.129 - @Override
76.130 - public String toString() {
76.131 - if (tree instanceof Storage) {
76.132 - return "AbstractLookup" + lookup(new Lookup.Template<Object>(Object.class)).allItems(); // NOI18N
76.133 - } else {
76.134 - return super.toString();
76.135 - }
76.136 - }
76.137 -
76.138 - /** Entres the storage management system.
76.139 - */
76.140 - @SuppressWarnings("unchecked")
76.141 - private <T> AbstractLookup.Storage<T> enterStorage() {
76.142 - for (;;) {
76.143 - synchronized (treeLock) {
76.144 - if (tree instanceof AbstractLookup.Storage) {
76.145 - if (tree instanceof DelegatingStorage) {
76.146 - // somebody is using the lookup right now
76.147 - DelegatingStorage del = (DelegatingStorage) tree;
76.148 -
76.149 - // check whether there is not access from the same
76.150 - // thread (can throw exception)
76.151 - del.checkForTreeModification();
76.152 -
76.153 - try {
76.154 - treeLock.wait();
76.155 - } catch (InterruptedException ex) {
76.156 - // ignore and go on
76.157 - }
76.158 -
76.159 - continue;
76.160 - } else {
76.161 - // ok, tree is initialized and nobody is using it yet
76.162 - tree = new DelegatingStorage((Storage<T>) tree);
76.163 -
76.164 - return (Storage<T>) tree;
76.165 - }
76.166 - }
76.167 -
76.168 - // first time initialization of the tree
76.169 - if (tree instanceof Integer) {
76.170 - tree = new ArrayStorage((Integer) tree);
76.171 - } else {
76.172 - tree = new ArrayStorage();
76.173 - }
76.174 - }
76.175 -
76.176 - // the tree has not yet been initilized, initialize and go on again
76.177 - initialize();
76.178 - }
76.179 - }
76.180 -
76.181 - /** Exists tree ownership.
76.182 - */
76.183 - private AbstractLookup.Storage exitStorage() {
76.184 - synchronized (treeLock) {
76.185 - AbstractLookup.Storage stor = ((DelegatingStorage) tree).exitDelegate();
76.186 - tree = stor;
76.187 - treeLock.notifyAll();
76.188 -
76.189 - return stor;
76.190 - }
76.191 - }
76.192 -
76.193 - /** Method for subclasses to initialize them selves.
76.194 - */
76.195 - protected void initialize() {
76.196 - }
76.197 -
76.198 - /** Notifies subclasses that a query is about to be processed.
76.199 - * @param template the template
76.200 - */
76.201 - protected void beforeLookup(Template<?> template) {
76.202 - }
76.203 -
76.204 - /** The method to add instance to the lookup with.
76.205 - * @param pair class/instance pair
76.206 - */
76.207 - protected final void addPair(Pair<?> pair) {
76.208 - addPairImpl(pair, null);
76.209 - }
76.210 -
76.211 - /** The method to add instance to the lookup with.
76.212 - * @param pair class/instance pair
76.213 - * @param notifyIn the executor that will handle the notification of events
76.214 - * @since 7.16
76.215 - */
76.216 - protected final void addPair(Pair<?> pair, Executor notifyIn) {
76.217 - addPairImpl(pair, notifyIn);
76.218 - }
76.219 -
76.220 - private final <Transaction> void addPairImpl(Pair<?> pair, Executor notifyIn) {
76.221 - HashSet<R> toNotify = new HashSet<R>();
76.222 -
76.223 - AbstractLookup.Storage<Transaction> t = enterStorage();
76.224 - Transaction transaction = null;
76.225 -
76.226 - try {
76.227 - transaction = t.beginTransaction(-2);
76.228 -
76.229 - if (t.add(pair, transaction)) {
76.230 - try {
76.231 - pair.setIndex(t, count++);
76.232 - } catch (IllegalStateException ex) {
76.233 - // remove the pair
76.234 - t.remove(pair, transaction);
76.235 -
76.236 - // rethrow the exception
76.237 - throw ex;
76.238 - }
76.239 -
76.240 - // if the pair is newly added and was not there before
76.241 - t.endTransaction(transaction, toNotify);
76.242 - } else {
76.243 - // just finish the process by calling endTransaction
76.244 - t.endTransaction(transaction, new HashSet<R>());
76.245 - }
76.246 - } finally {
76.247 - exitStorage();
76.248 - }
76.249 -
76.250 - notifyIn(notifyIn, toNotify);
76.251 - }
76.252 -
76.253 - /** Remove instance.
76.254 - * @param pair class/instance pair
76.255 - */
76.256 - protected final void removePair(Pair<?> pair) {
76.257 - removePairImpl(pair, null);
76.258 - }
76.259 - /** Remove instance.
76.260 - * @param pair class/instance pair
76.261 - * @param notifyIn the executor that will handle the notification of events
76.262 - * @since 7.16
76.263 - */
76.264 - protected final void removePair(Pair<?> pair, Executor notifyIn) {
76.265 - removePairImpl(pair, notifyIn);
76.266 - }
76.267 -
76.268 - private <Transaction> void removePairImpl(Pair<?> pair, Executor notifyIn) {
76.269 - HashSet<R> toNotify = new HashSet<R>();
76.270 -
76.271 - AbstractLookup.Storage<Transaction> t = enterStorage();
76.272 - Transaction transaction = null;
76.273 -
76.274 - try {
76.275 - transaction = t.beginTransaction(-1);
76.276 - t.remove(pair, transaction);
76.277 - t.endTransaction(transaction, toNotify);
76.278 - } finally {
76.279 - exitStorage();
76.280 - }
76.281 -
76.282 - notifyIn(notifyIn, toNotify);
76.283 - }
76.284 -
76.285 - /** Changes all pairs in the lookup to new values.
76.286 - * @param collection the collection of (Pair) objects
76.287 - */
76.288 - protected final void setPairs(Collection<? extends Pair> collection) {
76.289 - setPairs(collection, null);
76.290 - }
76.291 -
76.292 - /** Changes all pairs in the lookup to new values, notifies listeners
76.293 - * using provided executor.
76.294 - *
76.295 - * @param collection the collection of (Pair) objects
76.296 - * @param notifyIn the executor that will handle the notification of events
76.297 - * @since 7.16
76.298 - */
76.299 - protected final void setPairs(Collection<? extends Pair> collection, Executor notifyIn) {
76.300 - HashSet<R> listeners = setPairsAndCollectListeners(collection);
76.301 - notifyIn(notifyIn, listeners);
76.302 - }
76.303 -
76.304 - private final void notifyIn(Executor notifyIn, final HashSet<R> listeners) {
76.305 - NotifyListeners notify = new NotifyListeners(listeners);
76.306 - if (notify.shallRun()) {
76.307 - if (notifyIn == null) {
76.308 - notify.run();
76.309 - } else {
76.310 - notifyIn.execute(notify);
76.311 - }
76.312 - }
76.313 - }
76.314 -
76.315 - /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
76.316 - * @return a LinkedHashSet that can be modified
76.317 - */
76.318 - final LinkedHashSet<Pair<?>> getPairsAsLHS() {
76.319 - AbstractLookup.Storage<?> t = enterStorage();
76.320 -
76.321 - try {
76.322 - Enumeration<Pair<Object>> en = t.lookup(Object.class);
76.323 - TreeSet<Pair<?>> arr = new TreeSet<Pair<?>>(ALPairComparator.DEFAULT);
76.324 - while (en.hasMoreElements()) {
76.325 - Pair<Object> item = en.nextElement();
76.326 - arr.add(item);
76.327 - }
76.328 - return new LinkedHashSet<Pair<?>>(arr);
76.329 - } finally {
76.330 - exitStorage();
76.331 - }
76.332 - }
76.333 -
76.334 - /** Collects listeners without notification. Needed in MetaInfServicesLookup
76.335 - * right now, but maybe will become an API later.
76.336 - */
76.337 - final <Transaction> HashSet<R> setPairsAndCollectListeners(Collection<? extends Pair> collection) {
76.338 - HashSet<R> toNotify = new HashSet<R>(27);
76.339 -
76.340 - AbstractLookup.Storage<Transaction> t = enterStorage();
76.341 - Transaction transaction = null;
76.342 -
76.343 - try {
76.344 - // map between the Items and their indexes (Integer)
76.345 - HashMap<Item<?>,Info> shouldBeThere = new HashMap<Item<?>,Info>(collection.size() * 2);
76.346 -
76.347 - count = 0;
76.348 -
76.349 - Iterator it = collection.iterator();
76.350 - transaction = t.beginTransaction(collection.size());
76.351 -
76.352 - while (it.hasNext()) {
76.353 - Pair item = (Pair) it.next();
76.354 -
76.355 - if (t.add(item, transaction)) {
76.356 - // the item has not been there yet
76.357 - //t.endTransaction(transaction, toNotify);
76.358 - }
76.359 -
76.360 - // remeber the item, because it should not be removed
76.361 - shouldBeThere.put(item, new Info(count++, transaction));
76.362 -
76.363 - // arr.clear ();
76.364 - }
76.365 -
76.366 - // Object transaction = t.beginTransaction ();
76.367 - // deletes all objects that should not be there and
76.368 - t.retainAll(shouldBeThere, transaction);
76.369 -
76.370 - // collect listeners
76.371 - t.endTransaction(transaction, toNotify);
76.372 -
76.373 - /*
76.374 - // check consistency
76.375 - Enumeration en = t.lookup (java.lang.Object.class);
76.376 - boolean[] max = new boolean[count];
76.377 - int mistake = -1;
76.378 - while (en.hasMoreElements ()) {
76.379 - Pair item = (Pair)en.nextElement ();
76.380 -
76.381 - if (max[item.index]) {
76.382 - mistake = item.index;
76.383 - }
76.384 - max[item.index] = true;
76.385 - }
76.386 -
76.387 - if (mistake != -1) {
76.388 - System.err.println ("Mistake at: " + mistake);
76.389 - tree.print (System.err, true);
76.390 - }
76.391 - */
76.392 - } finally {
76.393 - exitStorage();
76.394 - }
76.395 -
76.396 - return toNotify;
76.397 - }
76.398 -
76.399 - private final void writeObject(ObjectOutputStream oos)
76.400 - throws IOException {
76.401 - AbstractLookup.Storage s = enterStorage();
76.402 -
76.403 - try {
76.404 - // #36830: Serializing only InheritanceTree no ArrayStorage
76.405 - s.beginTransaction(Integer.MAX_VALUE);
76.406 -
76.407 - // #32040: don't write half-made changes
76.408 - oos.defaultWriteObject();
76.409 - } finally {
76.410 - exitStorage();
76.411 - }
76.412 - }
76.413 -
76.414 - public final <T> T lookup(Class<T> clazz) {
76.415 - Lookup.Item<T> item = lookupItem(new Lookup.Template<T>(clazz));
76.416 - return (item == null) ? null : item.getInstance();
76.417 - }
76.418 -
76.419 - @Override
76.420 - public final <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
76.421 - AbstractLookup.this.beforeLookup(template);
76.422 -
76.423 - ArrayList<Pair<T>> list = null;
76.424 - AbstractLookup.Storage<?> t = enterStorage();
76.425 -
76.426 - try {
76.427 - Enumeration<Pair<T>> en;
76.428 -
76.429 - try {
76.430 - en = t.lookup(template.getType());
76.431 -
76.432 - return findSmallest(en, template, false);
76.433 - } catch (AbstractLookup.ISE ex) {
76.434 - // not possible to enumerate the exception, ok, copy it
76.435 - // to create new
76.436 - list = new ArrayList<Pair<T>>();
76.437 - en = t.lookup(null); // this should get all the items without any checks
76.438 -
76.439 - // the checks will be done out side of the storage
76.440 - while (en.hasMoreElements()) {
76.441 - list.add(en.nextElement());
76.442 - }
76.443 - }
76.444 - } finally {
76.445 - exitStorage();
76.446 - }
76.447 -
76.448 - return findSmallest(Collections.enumeration(list), template, true);
76.449 - }
76.450 -
76.451 - private static <T> Pair<T> findSmallest(Enumeration<Pair<T>> en, Lookup.Template<T> template, boolean deepCheck) {
76.452 - int smallest = InheritanceTree.unsorted(en) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
76.453 - Pair<T> res = null;
76.454 -
76.455 - while (en.hasMoreElements()) {
76.456 - Pair<T> item = en.nextElement();
76.457 -
76.458 - if (matches(template, item, deepCheck)) {
76.459 - if (smallest == Integer.MIN_VALUE) {
76.460 - // ok, sorted enumeration the first that matches is fine
76.461 - return item;
76.462 - } else {
76.463 - // check for the smallest item
76.464 - if (smallest > item.getIndex()) {
76.465 - smallest = item.getIndex();
76.466 - res = item;
76.467 - }
76.468 - }
76.469 - }
76.470 - }
76.471 -
76.472 - return res;
76.473 - }
76.474 -
76.475 - public final <T> Lookup.Result<T> lookup(Lookup.Template<T> template) {
76.476 - for (;;) {
76.477 - AbstractLookup.ISE toRun = null;
76.478 -
76.479 - AbstractLookup.Storage<?> t = enterStorage();
76.480 -
76.481 - try {
76.482 - R<T> r = new R<T>();
76.483 - ReferenceToResult<T> newRef = new ReferenceToResult<T>(r, this, template);
76.484 - newRef.next = t.registerReferenceToResult(newRef);
76.485 -
76.486 - return r;
76.487 - } catch (AbstractLookup.ISE ex) {
76.488 - toRun = ex;
76.489 - } finally {
76.490 - exitStorage();
76.491 - }
76.492 -
76.493 - toRun.recover(this);
76.494 -
76.495 - // and try again
76.496 - }
76.497 - }
76.498 -
76.499 - /** Notifies listeners.
76.500 - * @param allAffectedResults set of R
76.501 - */
76.502 - static final class NotifyListeners implements Runnable {
76.503 - private final ArrayList<Object> evAndListeners;
76.504 -
76.505 - public NotifyListeners(Set<R> allAffectedResults) {
76.506 - if (allAffectedResults.isEmpty()) {
76.507 - evAndListeners = null;
76.508 - return;
76.509 - }
76.510 -
76.511 - evAndListeners = new ArrayList<Object>();
76.512 - {
76.513 - for (R<?> result : allAffectedResults) {
76.514 - result.collectFires(evAndListeners);
76.515 - }
76.516 - }
76.517 - }
76.518 -
76.519 - public boolean shallRun() {
76.520 - return evAndListeners != null && !evAndListeners.isEmpty();
76.521 - }
76.522 -
76.523 - public void run() {
76.524 - Iterator it = evAndListeners.iterator();
76.525 - while (it.hasNext()) {
76.526 - LookupEvent ev = (LookupEvent)it.next();
76.527 - LookupListener l = (LookupListener)it.next();
76.528 - l.resultChanged(ev);
76.529 - }
76.530 - }
76.531 - }
76.532 -
76.533 - /**
76.534 - * Call resultChanged on all listeners.
76.535 - * @param listeners array of listeners in the format used by
76.536 - * javax.swing.EventListenerList. It means that there are Class
76.537 - * objects on even positions and the listeners on odd positions
76.538 - * @param ev the event to fire
76.539 - */
76.540 - static void notifyListeners(Object[] listeners, LookupEvent ev, Collection<Object> evAndListeners) {
76.541 - for (int i = listeners.length - 1; i >= 0; i--) {
76.542 - if (! (listeners[i] instanceof LookupListener)) {
76.543 - continue;
76.544 - }
76.545 - LookupListener ll = (LookupListener)listeners[i];
76.546 -
76.547 - try {
76.548 - if (evAndListeners != null) {
76.549 - if (ll instanceof WaitableResult) {
76.550 - WaitableResult<?> wr = (WaitableResult<?>)ll;
76.551 - wr.collectFires(evAndListeners);
76.552 - } else {
76.553 - evAndListeners.add(ev);
76.554 - evAndListeners.add(ll);
76.555 - }
76.556 - } else {
76.557 - ll.resultChanged(ev);
76.558 - }
76.559 - } catch (StackOverflowError err) {
76.560 - throw new CycleError(evAndListeners); // NOI18N
76.561 - } catch (RuntimeException e) {
76.562 - // Such as e.g. occurred in #32040. Do not halt other things.
76.563 - e.printStackTrace();
76.564 - }
76.565 - }
76.566 - }
76.567 -
76.568 - private static class CycleError extends StackOverflowError {
76.569 - private final Collection<Object> print;
76.570 - public CycleError(Collection<Object> evAndListeners) {
76.571 - this.print = evAndListeners;
76.572 - }
76.573 -
76.574 - @Override
76.575 - public String getMessage() {
76.576 - StringBuilder sb = new StringBuilder();
76.577 - sb.append("StackOverflowError, here are the listeners:\n"); // NOI18N
76.578 - for (Object o : print) {
76.579 - sb.append('\n').append(o);
76.580 - if (sb.length() > 10000) {
76.581 - break;
76.582 - }
76.583 - }
76.584 - return sb.toString();
76.585 - }
76.586 - } // end of CycleError
76.587 -
76.588 - /** A method that defines matching between Item and Template.
76.589 - * @param t template providing the criteria
76.590 - * @param item the item to match
76.591 - * @param deepCheck true if type of the pair should be tested, false if it is already has been tested
76.592 - * @return true if item matches the template requirements, false if not
76.593 - */
76.594 - static boolean matches(Template<?> t, Pair<?> item, boolean deepCheck) {
76.595 - String id = t.getId();
76.596 -
76.597 - if (id != null && !id.equals(item.getId())) {
76.598 - return false;
76.599 - }
76.600 -
76.601 - Object instance = t.getInstance();
76.602 -
76.603 - if ((instance != null) && !item.creatorOf(instance)) {
76.604 - return false;
76.605 - }
76.606 -
76.607 - if (deepCheck) {
76.608 - return item.instanceOf(t.getType());
76.609 - } else {
76.610 - return true;
76.611 - }
76.612 - }
76.613 -
76.614 - /**
76.615 - * Compares the array elements for equality.
76.616 - * @return true if all elements in the arrays are equal
76.617 - * (by calling equals(Object x) method)
76.618 - */
76.619 - private static boolean compareArrays(Object[] a, Object[] b) {
76.620 - // handle null values
76.621 - if (a == null) {
76.622 - return (b == null);
76.623 - } else {
76.624 - if (b == null) {
76.625 - return false;
76.626 - }
76.627 - }
76.628 -
76.629 - if (a.length != b.length) {
76.630 - return false;
76.631 - }
76.632 -
76.633 - for (int i = 0; i < a.length; i++) {
76.634 - // handle null values for individual elements
76.635 - if (a[i] == null) {
76.636 - if (b[i] != null) {
76.637 - return false;
76.638 - }
76.639 -
76.640 - // both are null --> ok, take next
76.641 - continue;
76.642 - } else {
76.643 - if (b[i] == null) {
76.644 - return false;
76.645 - }
76.646 - }
76.647 -
76.648 - // perform the comparison
76.649 - if (!a[i].equals(b[i])) {
76.650 - return false;
76.651 - }
76.652 - }
76.653 -
76.654 - return true;
76.655 - }
76.656 -
76.657 - /** Method to be called when a result is cleared to signal that the list
76.658 - * of all result should be checked for clearing.
76.659 - * @param template the template the result was for
76.660 - * @return true if the hash map with all items has been cleared
76.661 - */
76.662 - <T> boolean cleanUpResult(Lookup.Template<T> template) {
76.663 - AbstractLookup.Storage<?> t = enterStorage();
76.664 -
76.665 - try {
76.666 - return t.cleanUpResult(template) == null;
76.667 - } finally {
76.668 - exitStorage();
76.669 - }
76.670 - }
76.671 -
76.672 - /** Storage check for tests. */
76.673 - static boolean isSimple(AbstractLookup l) {
76.674 - return DelegatingStorage.isSimple((Storage)l.tree);
76.675 - }
76.676 -
76.677 - /** Generic support for listeners, so it can be used in other results
76.678 - * as well.
76.679 - * @param add true to add it, false to modify
76.680 - * @param l listener to modify
76.681 - * @param ref the value of the reference to listener or listener list
76.682 - * @return new value to the reference to listener or list
76.683 - */
76.684 - @SuppressWarnings("unchecked")
76.685 - static Object modifyListenerList(boolean add, LookupListener l, Object ref) {
76.686 - if (add) {
76.687 - if (ref == null) {
76.688 - return l;
76.689 - }
76.690 -
76.691 - if (ref instanceof LookupListener) {
76.692 - ArrayList arr = new ArrayList();
76.693 - arr.add(ref);
76.694 - ref = arr;
76.695 - }
76.696 -
76.697 - ((ArrayList) ref).add(l);
76.698 -
76.699 - return ref;
76.700 - } else {
76.701 - // remove
76.702 - if (ref == null) {
76.703 - return null;
76.704 - }
76.705 -
76.706 - if (ref == l) {
76.707 - return null;
76.708 - }
76.709 -
76.710 - ArrayList arr = (ArrayList) ref;
76.711 - arr.remove(l);
76.712 -
76.713 - if (arr.size() == 1) {
76.714 - return arr.iterator().next();
76.715 - } else {
76.716 - return arr;
76.717 - }
76.718 - }
76.719 - }
76.720 -
76.721 - private static ReferenceQueue<Object> activeQueue() {
76.722 - return ActiveQueue.queue();
76.723 - }
76.724 -
76.725 - /** Storage to keep the internal structure of Pairs and to answer
76.726 - * different queries.
76.727 - */
76.728 - interface Storage<Transaction> {
76.729 - /** Initializes a modification operation by creating an object
76.730 - * that will be passsed to all add, remove, retainAll methods
76.731 - * and should collect enough information about the change to
76.732 - * notify listeners about the transaction later
76.733 - *
76.734 - * @param ensure the amount of items that will appear in the storage
76.735 - * after the modifications (-1 == remove one, -2 == add one, >= 0
76.736 - * the amount of objects at the end
76.737 - * @return a token to identify the transaction
76.738 - */
76.739 - public Transaction beginTransaction(int ensure);
76.740 -
76.741 - /** Collects all affected results R that were modified in the
76.742 - * given transaction.
76.743 - *
76.744 - * @param modified place to add results R to
76.745 - * @param transaction the transaction indentification
76.746 - */
76.747 - public void endTransaction(Transaction transaction, Set<R> modifiedResults);
76.748 -
76.749 - /** Adds an item into the storage.
76.750 - * @param item to add
76.751 - * @param transaction transaction token
76.752 - * @return true if the Item has been added for the first time or false if some other
76.753 - * item equal to this one already existed in the lookup
76.754 - */
76.755 - public boolean add(AbstractLookup.Pair<?> item, Transaction transaction);
76.756 -
76.757 - /** Removes an item.
76.758 - */
76.759 - public void remove(AbstractLookup.Pair item, Transaction transaction);
76.760 -
76.761 - /** Removes all items that are not present in the provided collection.
76.762 - * @param retain collection of Pairs to keep them in
76.763 - * @param transaction the transaction context
76.764 - */
76.765 - public void retainAll(Map retain, Transaction transaction);
76.766 -
76.767 - /** Queries for instances of given class.
76.768 - * @param clazz the class to check
76.769 - * @return enumeration of Item
76.770 - * @see #unsorted
76.771 - */
76.772 - public <T> Enumeration<Pair<T>> lookup(Class<T> clazz);
76.773 -
76.774 - /** Registers another reference to a result with the storage. This method
76.775 - * has also a special meaning.
76.776 - *
76.777 - * @param newRef the new reference to remember
76.778 - * @return the previous reference that was kept (null if newRef is the first one)
76.779 - * the applications is expected to link from newRef to this returned
76.780 - * value to form a linked list
76.781 - */
76.782 - public ReferenceToResult<?> registerReferenceToResult(ReferenceToResult<?> newRef);
76.783 -
76.784 - /** Given the provided template, Do cleanup the results.
76.785 - * @param templ template of a result(s) that should be checked
76.786 - * @return null if all references for this template were cleared or one of them
76.787 - */
76.788 - public ReferenceToResult<?> cleanUpResult(Lookup.Template<?> templ);
76.789 - }
76.790 -
76.791 - /** Extension to the default lookup item that offers additional information
76.792 - * for the data structures use in AbstractLookup
76.793 - */
76.794 - public static abstract class Pair<T> extends Lookup.Item<T> implements Serializable {
76.795 - private static final long serialVersionUID = 1L;
76.796 -
76.797 - /** possition of this item in the lookup, manipulated in addPair, removePair, setPairs methods */
76.798 - private int index = -1;
76.799 -
76.800 - /** For use by subclasses. */
76.801 - protected Pair() {
76.802 - }
76.803 -
76.804 - final int getIndex() {
76.805 - return index;
76.806 - }
76.807 -
76.808 - final void setIndex(AbstractLookup.Storage<?> tree, int x) {
76.809 - if (tree == null) {
76.810 - this.index = x;
76.811 -
76.812 - return;
76.813 - }
76.814 -
76.815 - if (this.index == -1) {
76.816 - this.index = x;
76.817 - } else {
76.818 - throw new IllegalStateException("You cannot use " + this + " in more than one AbstractLookup. Prev: " + this.index + " new: " + x); // NOI18N
76.819 - }
76.820 - }
76.821 -
76.822 - /** Tests whether this item can produce object
76.823 - * of class c.
76.824 - */
76.825 - protected abstract boolean instanceOf(Class<?> c);
76.826 -
76.827 - /** Method that can test whether an instance of a class has been created
76.828 - * by this item.
76.829 - *
76.830 - * @param obj the instance
76.831 - * @return if the item has already create an instance and it is the same
76.832 - * as obj.
76.833 - */
76.834 - protected abstract boolean creatorOf(Object obj);
76.835 - }
76.836 -
76.837 - /** Result based on one instance returned.
76.838 - */
76.839 - static final class R<T> extends WaitableResult<T> {
76.840 - /** reference our result is attached to (do not modify) */
76.841 - public ReferenceToResult<T> reference;
76.842 -
76.843 - /** listeners on the results or pointer to one listener */
76.844 - private Object listeners;
76.845 -
76.846 - public R() {
76.847 - }
76.848 -
76.849 - /** Checks whether we have simple behaviour of complex.
76.850 - */
76.851 - private boolean isSimple() {
76.852 - Storage s = (Storage) reference.lookup.tree;
76.853 -
76.854 - return DelegatingStorage.isSimple(s);
76.855 - }
76.856 -
76.857 - //
76.858 - // Handling cache management for both cases, no caches
76.859 - // for simple (but mark that we needed them, so refresh can
76.860 - // be done in cloneList) and complex when all 3 types
76.861 - // of result are cached
76.862 - //
76.863 - private Object getFromCache(int indx) {
76.864 - if (isSimple()) {
76.865 - return null;
76.866 - }
76.867 -
76.868 - Object maybeArray = reference.caches;
76.869 -
76.870 - if (maybeArray instanceof Object[]) {
76.871 - return ((Object[]) maybeArray)[indx];
76.872 - }
76.873 -
76.874 - return null;
76.875 - }
76.876 -
76.877 - @SuppressWarnings("unchecked")
76.878 - private Set<Class<? extends T>> getClassesCache() {
76.879 - return (Set<Class<? extends T>>) getFromCache(0);
76.880 - }
76.881 -
76.882 - private void setClassesCache(Set s) {
76.883 - if (isSimple()) {
76.884 - // mark it as being used
76.885 - reference.caches = reference;
76.886 -
76.887 - return;
76.888 - }
76.889 -
76.890 - if (!(reference.caches instanceof Object[])) {
76.891 - reference.caches = new Object[3];
76.892 - }
76.893 -
76.894 - ((Object[]) reference.caches)[0] = s;
76.895 - }
76.896 -
76.897 - @SuppressWarnings("unchecked")
76.898 - private Collection<T> getInstancesCache() {
76.899 - return (Collection<T>) getFromCache(1);
76.900 - }
76.901 -
76.902 - private void setInstancesCache(Collection c) {
76.903 - if (isSimple()) {
76.904 - // mark it as being used
76.905 - reference.caches = reference;
76.906 -
76.907 - return;
76.908 - }
76.909 -
76.910 - if (!(reference.caches instanceof Object[])) {
76.911 - reference.caches = new Object[3];
76.912 - }
76.913 -
76.914 - ((Object[]) reference.caches)[1] = c;
76.915 - }
76.916 -
76.917 - @SuppressWarnings("unchecked")
76.918 - private Pair<T>[] getItemsCache() {
76.919 - return (Pair<T>[]) getFromCache(2);
76.920 - }
76.921 -
76.922 - private void setItemsCache(Collection<?> c) {
76.923 - if (isSimple()) {
76.924 - // mark it as being used
76.925 - reference.caches = reference;
76.926 -
76.927 - return;
76.928 - }
76.929 -
76.930 - if (!(reference.caches instanceof Object[])) {
76.931 - reference.caches = new Object[3];
76.932 - }
76.933 -
76.934 - ((Object[]) reference.caches)[2] = c.toArray(new Pair[0]);
76.935 - }
76.936 -
76.937 - private void clearCaches() {
76.938 - if (reference.caches instanceof Object[]) {
76.939 - reference.caches = new Object[3];
76.940 - }
76.941 - }
76.942 -
76.943 - /** Ok, register listeners to all classes and super classes.
76.944 - */
76.945 - public synchronized void addLookupListener(LookupListener l) {
76.946 - listeners = modifyListenerList(true, l, listeners);
76.947 - }
76.948 -
76.949 - /** Ok, register listeners to all classes and super classes.
76.950 - */
76.951 - public synchronized void removeLookupListener(LookupListener l) {
76.952 - listeners = modifyListenerList(false, l, listeners);
76.953 - }
76.954 -
76.955 - /** Delete all cached values, the template changed.
76.956 - */
76.957 - protected void collectFires(Collection<Object> evAndListeners) {
76.958 - Object[] previousItems = getItemsCache();
76.959 - clearCaches();
76.960 -
76.961 - if (previousItems != null) {
76.962 - Object[] newArray = allItemsWithoutBeforeLookup().toArray();
76.963 -
76.964 - if (compareArrays(previousItems, newArray)) {
76.965 - // do not fire any change if nothing has been changed
76.966 - return;
76.967 - }
76.968 - }
76.969 -
76.970 - LookupListener[] arr;
76.971 -
76.972 - synchronized (this) {
76.973 - if (listeners == null) {
76.974 - return;
76.975 - }
76.976 -
76.977 - if (listeners instanceof LookupListener) {
76.978 - arr = new LookupListener[] { (LookupListener) listeners };
76.979 - } else {
76.980 - ArrayList<?> l = (ArrayList<?>) listeners;
76.981 - arr = l.toArray(new LookupListener[l.size()]);
76.982 - }
76.983 - }
76.984 -
76.985 - final LookupListener[] ll = arr;
76.986 - final LookupEvent ev = new LookupEvent(this);
76.987 - notifyListeners(ll, ev, evAndListeners);
76.988 - }
76.989 -
76.990 - public Collection<T> allInstances() {
76.991 - reference.lookup.beforeLookup(reference.template);
76.992 -
76.993 - Collection<T> s = getInstancesCache();
76.994 -
76.995 - if (s != null) {
76.996 - return s;
76.997 - }
76.998 -
76.999 - Collection<Pair<T>> items = allItemsWithoutBeforeLookup();
76.1000 - ArrayList<T> list = new ArrayList<T>(items.size());
76.1001 -
76.1002 - Iterator<Pair<T>> it = items.iterator();
76.1003 -
76.1004 - while (it.hasNext()) {
76.1005 - Pair<T> item = it.next();
76.1006 - T obj = item.getInstance();
76.1007 -
76.1008 - if (reference.template.getType().isInstance(obj)) {
76.1009 - list.add(obj);
76.1010 - }
76.1011 - }
76.1012 -
76.1013 - s = Collections.unmodifiableList(list);
76.1014 - setInstancesCache(s);
76.1015 -
76.1016 - return s;
76.1017 - }
76.1018 -
76.1019 - /** Set of all classes.
76.1020 - *
76.1021 - */
76.1022 - @Override
76.1023 - public Set<Class<? extends T>> allClasses() {
76.1024 - reference.lookup.beforeLookup(reference.template);
76.1025 -
76.1026 - Set<Class<? extends T>> s = getClassesCache();
76.1027 -
76.1028 - if (s != null) {
76.1029 - return s;
76.1030 - }
76.1031 -
76.1032 - s = new HashSet<Class<? extends T>>();
76.1033 -
76.1034 - for (Pair<T> item : allItemsWithoutBeforeLookup()) {
76.1035 - Class<? extends T> clazz = item.getType();
76.1036 -
76.1037 - if (clazz != null) {
76.1038 - s.add(clazz);
76.1039 - }
76.1040 - }
76.1041 -
76.1042 - s = Collections.unmodifiableSet(s);
76.1043 - setClassesCache(s);
76.1044 -
76.1045 - return s;
76.1046 - }
76.1047 -
76.1048 - /** Items are stored directly in the allItems.
76.1049 - */
76.1050 - @Override
76.1051 - public Collection<? extends Item<T>> allItems() {
76.1052 - reference.lookup.beforeLookup(reference.template);
76.1053 -
76.1054 - return allItemsWithoutBeforeLookup();
76.1055 - }
76.1056 -
76.1057 - /** Implements the search for allItems, but without asking for before lookup */
76.1058 - private Collection<Pair<T>> allItemsWithoutBeforeLookup() {
76.1059 - Pair<T>[] c = getItemsCache();
76.1060 -
76.1061 - if (c != null) {
76.1062 - return Collections.unmodifiableList(Arrays.asList(c));
76.1063 - }
76.1064 -
76.1065 - ArrayList<Pair<Object>> saferCheck = null;
76.1066 - AbstractLookup.Storage<?> t = reference.lookup.enterStorage();
76.1067 -
76.1068 - try {
76.1069 - try {
76.1070 - return Collections.unmodifiableCollection(initItems(t));
76.1071 - } catch (AbstractLookup.ISE ex) {
76.1072 - // do less effective evaluation of items outside of the
76.1073 - // locked storage
76.1074 - saferCheck = new ArrayList<Pair<Object>>();
76.1075 -
76.1076 - Enumeration<Pair<Object>> en = t.lookup(null); // get all Pairs
76.1077 -
76.1078 - while (en.hasMoreElements()) {
76.1079 - Pair<Object> i = en.nextElement();
76.1080 - saferCheck.add(i);
76.1081 - }
76.1082 - }
76.1083 - } finally {
76.1084 - reference.lookup.exitStorage();
76.1085 - }
76.1086 - return extractPairs(saferCheck);
76.1087 - }
76.1088 -
76.1089 - @SuppressWarnings("unchecked")
76.1090 - private Collection<Pair<T>> extractPairs(final ArrayList<Pair<Object>> saferCheck) {
76.1091 - TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
76.1092 - for (Pair<Object> i : saferCheck) {
76.1093 - if (matches(reference.template, i, false)) {
76.1094 - items.add((Pair<T>)i);
76.1095 - }
76.1096 - }
76.1097 - return Collections.unmodifiableCollection(items);
76.1098 - }
76.1099 -
76.1100 - /** Initializes items.
76.1101 - */
76.1102 - private Collection<Pair<T>> initItems(Storage<?> t) {
76.1103 - // manipulation with the tree must be synchronized
76.1104 - Enumeration<Pair<T>> en = t.lookup(reference.template.getType());
76.1105 -
76.1106 - // InheritanceTree is comparator for AbstractLookup.Pairs
76.1107 - TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
76.1108 -
76.1109 - while (en.hasMoreElements()) {
76.1110 - Pair<T> i = en.nextElement();
76.1111 -
76.1112 - if (matches(reference.template, i, false)) {
76.1113 - items.add(i);
76.1114 - }
76.1115 - }
76.1116 -
76.1117 - // create a correctly sorted copy using the tree as the comparator
76.1118 - setItemsCache(items);
76.1119 -
76.1120 - return items;
76.1121 - }
76.1122 -
76.1123 - /** Used by proxy results to synchronize before lookup.
76.1124 - */
76.1125 - protected void beforeLookup(Lookup.Template t) {
76.1126 - if (t.getType() == reference.template.getType()) {
76.1127 - reference.lookup.beforeLookup(t);
76.1128 - }
76.1129 - }
76.1130 -
76.1131 - /* Do not need to implement it, the default way is ok.
76.1132 - public boolean equals(java.lang.Object obj) {
76.1133 - return obj == this;
76.1134 - }
76.1135 - */
76.1136 - @Override
76.1137 - public String toString() {
76.1138 - return super.toString() + " for " + reference.template;
76.1139 - }
76.1140 - }
76.1141 - // end of R
76.1142 -
76.1143 - /** A class that can be used by the creator of the AbstractLookup to
76.1144 - * control its content. It can be passed to AbstractLookup constructor
76.1145 - * and used to add and remove pairs.
76.1146 - *
76.1147 - * @since 1.25
76.1148 - */
76.1149 - public static class Content extends Object implements Serializable {
76.1150 - private static final long serialVersionUID = 1L;
76.1151 -
76.1152 - // one of them is always null (except attach stage)
76.1153 -
76.1154 - /** abstract lookup we are connected to */
76.1155 - private AbstractLookup al;
76.1156 - private transient Object notifyIn;
76.1157 -
76.1158 - /** Default constructor.
76.1159 - */
76.1160 - public Content() {
76.1161 - this(null);
76.1162 - }
76.1163 -
76.1164 - /** Creates a content associated with an executor to handle dispatch
76.1165 - * of changes.
76.1166 - * @param notifyIn the executor to notify changes in
76.1167 - * @since 7.16
76.1168 - */
76.1169 - public Content(Executor notifyIn) {
76.1170 - this.notifyIn = notifyIn;
76.1171 - }
76.1172 -
76.1173 - /** for testing purposes */
76.1174 - final void attachExecutor(Executor notifyIn) {
76.1175 - this.notifyIn = notifyIn;
76.1176 - }
76.1177 -
76.1178 - /** A lookup attaches to this object.
76.1179 - */
76.1180 - final synchronized void attach(AbstractLookup al) {
76.1181 - if (this.al == null) {
76.1182 - this.al = al;
76.1183 -
76.1184 - ArrayList<Pair> ep = getEarlyPairs();
76.1185 - if (ep != null) {
76.1186 - notifyIn = null;
76.1187 - setPairs(ep);
76.1188 - }
76.1189 - } else {
76.1190 - throw new IllegalStateException(
76.1191 - "Trying to use content for " + al + " but it is already used for " + this.al
76.1192 - ); // NOI18N
76.1193 - }
76.1194 - }
76.1195 -
76.1196 - /** The method to add instance to the lookup with.
76.1197 - * @param pair class/instance pair
76.1198 - */
76.1199 - public final void addPair(Pair<?> pair) {
76.1200 - AbstractLookup a = al;
76.1201 - Executor e = getExecutor();
76.1202 -
76.1203 - if (a != null || e != null) {
76.1204 - a.addPair(pair, e);
76.1205 - } else {
76.1206 - if (notifyIn == null) {
76.1207 - notifyIn = new ArrayList<Pair>(3);
76.1208 - }
76.1209 -
76.1210 - getEarlyPairs().add(pair);
76.1211 - }
76.1212 - }
76.1213 -
76.1214 - /** Remove instance.
76.1215 - * @param pair class/instance pair
76.1216 - */
76.1217 - public final void removePair(Pair<?> pair) {
76.1218 - AbstractLookup a = al;
76.1219 - Executor e = getExecutor();
76.1220 -
76.1221 - if (a != null || e != null) {
76.1222 - a.removePair(pair, e);
76.1223 - } else {
76.1224 - if (notifyIn == null) {
76.1225 - notifyIn = new ArrayList<Pair>(3);
76.1226 - }
76.1227 -
76.1228 - getEarlyPairs().remove(pair);
76.1229 - }
76.1230 - }
76.1231 -
76.1232 - /** Changes all pairs in the lookup to new values.
76.1233 - * @param c the collection of (Pair) objects
76.1234 - */
76.1235 - public final void setPairs(Collection<? extends Pair> c) {
76.1236 - AbstractLookup a = al;
76.1237 - Executor e = getExecutor();
76.1238 -
76.1239 - if (a != null || e != null) {
76.1240 - a.setPairs(c, e);
76.1241 - } else {
76.1242 - notifyIn = new ArrayList<Pair>(c);
76.1243 - }
76.1244 - }
76.1245 -
76.1246 - @SuppressWarnings("unchecked")
76.1247 - private ArrayList<Pair> getEarlyPairs() {
76.1248 - Object o = notifyIn;
76.1249 - return o instanceof ArrayList ? (ArrayList<Pair>)o : null;
76.1250 - }
76.1251 -
76.1252 - private Executor getExecutor() {
76.1253 - Object o = notifyIn;
76.1254 - return o instanceof Executor ? (Executor)o : null;
76.1255 - }
76.1256 - }
76.1257 - // end of Content
76.1258 -
76.1259 - /** Just a holder for index & modified values.
76.1260 - */
76.1261 - final static class Info extends Object {
76.1262 - public int index;
76.1263 - public Object transaction;
76.1264 -
76.1265 - public Info(int i, Object t) {
76.1266 - index = i;
76.1267 - transaction = t;
76.1268 - }
76.1269 - }
76.1270 -
76.1271 - /** Reference to a result R
76.1272 - */
76.1273 - static final class ReferenceToResult<T> extends WeakReference<R<T>> implements Runnable {
76.1274 - /** next refernece in chain, modified only from AbstractLookup or this */
76.1275 - private ReferenceToResult<?> next;
76.1276 -
76.1277 - /** the template for the result */
76.1278 - public final Template<T> template;
76.1279 -
76.1280 - /** the lookup we are attached to */
76.1281 - public final AbstractLookup lookup;
76.1282 -
76.1283 - /** caches for results */
76.1284 - public Object caches;
76.1285 -
76.1286 - /** Creates a weak refernece to a new result R in context of lookup
76.1287 - * for given template
76.1288 - */
76.1289 - private ReferenceToResult(R<T> result, AbstractLookup lookup, Template<T> template) {
76.1290 - super(result, activeQueue());
76.1291 - this.template = template;
76.1292 - this.lookup = lookup;
76.1293 - getResult().reference = this;
76.1294 - }
76.1295 -
76.1296 - /** Returns the result or null
76.1297 - */
76.1298 - R<T> getResult() {
76.1299 - return get();
76.1300 - }
76.1301 -
76.1302 - /** Cleans the reference. Implements Runnable interface, do not call
76.1303 - * directly.
76.1304 - */
76.1305 - public void run() {
76.1306 - lookup.cleanUpResult(this.template);
76.1307 - }
76.1308 -
76.1309 - /** Clones the reference list to given Storage.
76.1310 - * @param storage storage to clone to
76.1311 - */
76.1312 - public void cloneList(AbstractLookup.Storage<?> storage) {
76.1313 - ReferenceIterator it = new ReferenceIterator(this);
76.1314 -
76.1315 - while (it.next()) {
76.1316 - ReferenceToResult<?> current = it.current();
76.1317 - ReferenceToResult<?> newRef = current.cloneRef();
76.1318 - newRef.next = storage.registerReferenceToResult(newRef);
76.1319 - newRef.caches = current.caches;
76.1320 -
76.1321 - if (current.caches == current) {
76.1322 - current.getResult().initItems(storage);
76.1323 - }
76.1324 - }
76.1325 - }
76.1326 -
76.1327 - private ReferenceToResult<T> cloneRef() {
76.1328 - return new ReferenceToResult<T>(getResult(), lookup, template);
76.1329 - }
76.1330 - }
76.1331 - // end of ReferenceToResult
76.1332 -
76.1333 - /** Supporting class to iterate over linked list of ReferenceToResult
76.1334 - * Use:
76.1335 - * <PRE>
76.1336 - * ReferenceIterator it = new ReferenceIterator (this.ref);
76.1337 - * while (it.next ()) {
76.1338 - * it.current (): // do some work
76.1339 - * }
76.1340 - * this.ref = it.first (); // remember the first one
76.1341 - */
76.1342 - static final class ReferenceIterator extends Object {
76.1343 - private ReferenceToResult<?> first;
76.1344 - private ReferenceToResult<?> current;
76.1345 -
76.1346 - /** hard reference to current result, so it is not GCed meanwhile */
76.1347 - private R<?> currentResult;
76.1348 -
76.1349 - /** Initializes the iterator with first reference.
76.1350 - */
76.1351 - public ReferenceIterator(ReferenceToResult<?> first) {
76.1352 - this.first = first;
76.1353 - }
76.1354 -
76.1355 - /** Moves the current to next possition */
76.1356 - public boolean next() {
76.1357 - ReferenceToResult<?> prev;
76.1358 - ReferenceToResult<?> ref;
76.1359 -
76.1360 - if (current == null) {
76.1361 - ref = first;
76.1362 - prev = null;
76.1363 - } else {
76.1364 - prev = current;
76.1365 - ref = current.next;
76.1366 - }
76.1367 -
76.1368 - while (ref != null) {
76.1369 - R<?> result = ref.get();
76.1370 -
76.1371 - if (result == null) {
76.1372 - if (prev == null) {
76.1373 - // move the head
76.1374 - first = ref.next;
76.1375 - } else {
76.1376 - // skip over this reference
76.1377 - prev.next = ref.next;
76.1378 - }
76.1379 -
76.1380 - prev = ref;
76.1381 - ref = ref.next;
76.1382 - } else {
76.1383 - // we have found next item
76.1384 - currentResult = result;
76.1385 - current = ref;
76.1386 -
76.1387 - return true;
76.1388 - }
76.1389 - }
76.1390 -
76.1391 - currentResult = null;
76.1392 - current = null;
76.1393 -
76.1394 - return false;
76.1395 - }
76.1396 -
76.1397 - /** Access to current reference.
76.1398 - */
76.1399 - public ReferenceToResult<?> current() {
76.1400 - return current;
76.1401 - }
76.1402 -
76.1403 - /** Access to reference that is supposed to be the first one.
76.1404 - */
76.1405 - public ReferenceToResult<?> first() {
76.1406 - return first;
76.1407 - }
76.1408 - }
76.1409 -
76.1410 - /** Signals that a lookup is being modified from a lookup query.
76.1411 - *
76.1412 - * @author Jaroslav Tulach
76.1413 - */
76.1414 - static final class ISE extends IllegalStateException {
76.1415 - static final long serialVersionUID = 100L;
76.1416 -
76.1417 - /** list of jobs to execute. */
76.1418 - private java.util.List<Job> jobs;
76.1419 -
76.1420 - /** @param msg message
76.1421 - */
76.1422 - public ISE(String msg) {
76.1423 - super(msg);
76.1424 - }
76.1425 -
76.1426 - /** Registers a job to be executed partially out and partially in
76.1427 - * the lock over storage.
76.1428 - */
76.1429 - public void registerJob(Job job) {
76.1430 - if (jobs == null) {
76.1431 - jobs = new java.util.ArrayList<Job>();
76.1432 - }
76.1433 -
76.1434 - jobs.add(job);
76.1435 - }
76.1436 -
76.1437 - /** Executes the jobs outside, and then inside a locked session.
76.1438 - */
76.1439 - public void recover(AbstractLookup lookup) {
76.1440 - if (jobs == null) {
76.1441 - // no recovery plan, throw itself
76.1442 - throw this;
76.1443 - }
76.1444 -
76.1445 - for (Job j : jobs) {
76.1446 - j.before();
76.1447 - }
76.1448 -
76.1449 - AbstractLookup.Storage s = lookup.enterStorage();
76.1450 -
76.1451 - try {
76.1452 - for (Job j : jobs) {
76.1453 - j.inside();
76.1454 - }
76.1455 - } finally {
76.1456 - lookup.exitStorage();
76.1457 - }
76.1458 - }
76.1459 -
76.1460 - /** A job to be executed partially outside and partially inside
76.1461 - * the storage lock.
76.1462 - */
76.1463 - static interface Job {
76.1464 - public void before();
76.1465 -
76.1466 - public void inside();
76.1467 - }
76.1468 - }
76.1469 - // end of ISE
76.1470 -}
77.1 --- a/openide.util/src/org/openide/util/lookup/ArrayStorage.java Sat Oct 31 15:06:58 2009 +0100
77.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
77.3 @@ -1,477 +0,0 @@
77.4 -/*
77.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
77.6 - *
77.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
77.8 - *
77.9 - * The contents of this file are subject to the terms of either the GNU
77.10 - * General Public License Version 2 only ("GPL") or the Common
77.11 - * Development and Distribution License("CDDL") (collectively, the
77.12 - * "License"). You may not use this file except in compliance with the
77.13 - * License. You can obtain a copy of the License at
77.14 - * http://www.netbeans.org/cddl-gplv2.html
77.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
77.16 - * specific language governing permissions and limitations under the
77.17 - * License. When distributing the software, include this License Header
77.18 - * Notice in each file and include the License file at
77.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
77.20 - * particular file as subject to the "Classpath" exception as provided
77.21 - * by Sun in the GPL Version 2 section of the License file that
77.22 - * accompanied this code. If applicable, add the following below the
77.23 - * License Header, with the fields enclosed by brackets [] replaced by
77.24 - * your own identifying information:
77.25 - * "Portions Copyrighted [year] [name of copyright owner]"
77.26 - *
77.27 - * Contributor(s):
77.28 - *
77.29 - * The Original Software is NetBeans. The Initial Developer of the Original
77.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
77.31 - * Microsystems, Inc. All Rights Reserved.
77.32 - *
77.33 - * If you wish your version of this file to be governed by only the CDDL
77.34 - * or only the GPL Version 2, indicate your decision by adding
77.35 - * "[Contributor] elects to include this software in this distribution
77.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
77.37 - * single choice of license, a recipient has the option to distribute
77.38 - * your version of this file under either the CDDL, the GPL Version 2 or
77.39 - * to extend the choice of license to its licensees as provided above.
77.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
77.41 - * Version 2 license, then the option applies only if the new code is
77.42 - * made subject to such option by the copyright holder.
77.43 - */
77.44 -package org.openide.util.lookup;
77.45 -
77.46 -import org.openide.util.Lookup;
77.47 -
77.48 -
77.49 -
77.50 -import java.util.*;
77.51 -import org.openide.util.lookup.AbstractLookup.Pair;
77.52 -
77.53 -
77.54 -/** ArrayStorage of Pairs from AbstractLookup.
77.55 - * @author Jaroslav Tulach
77.56 - */
77.57 -final class ArrayStorage extends Object
77.58 -implements AbstractLookup.Storage<ArrayStorage.Transaction> {
77.59 - /** default trashold */
77.60 - static final Integer DEFAULT_TRASH = new Integer(11);
77.61 -
77.62 - /** list of items */
77.63 - private Object content;
77.64 -
77.65 - /** linked list of refernces to results */
77.66 - private transient AbstractLookup.ReferenceToResult<?> results;
77.67 -
77.68 - /** Constructor
77.69 - */
77.70 - public ArrayStorage() {
77.71 - this(DEFAULT_TRASH);
77.72 - }
77.73 -
77.74 - /** Constructs new ArrayStorage */
77.75 - public ArrayStorage(Integer treshhold) {
77.76 - this.content = treshhold;
77.77 - }
77.78 -
77.79 - /** Adds an item into the tree.
77.80 - * @param item to add
77.81 - * @return true if the Item has been added for the first time or false if some other
77.82 - * item equal to this one already existed in the lookup
77.83 - */
77.84 - public boolean add(AbstractLookup.Pair<?> item, Transaction changed) {
77.85 - Object[] arr = changed.current;
77.86 -
77.87 - if (changed.arr == null) {
77.88 - // just simple add of one item
77.89 - for (int i = 0; i < arr.length; i++) {
77.90 - if (arr[i] == null) {
77.91 - arr[i] = item;
77.92 - changed.add(item);
77.93 -
77.94 - return true;
77.95 - }
77.96 -
77.97 - if (arr[i].equals(item)) {
77.98 - // reassign the item number
77.99 - item.setIndex(null, ((AbstractLookup.Pair) arr[i]).getIndex());
77.100 -
77.101 - // already there, but update it
77.102 - arr[i] = item;
77.103 -
77.104 - return false;
77.105 - }
77.106 - }
77.107 -
77.108 - // cannot happen as the beginTransaction ensured we can finish
77.109 - // correctly
77.110 - throw new IllegalStateException();
77.111 - } else {
77.112 - // doing remainAll after that, let Transaction hold the new array
77.113 - int newIndex = changed.addPair(item);
77.114 -
77.115 - for (int i = 0; i < arr.length; i++) {
77.116 - if (arr[i] == null) {
77.117 - changed.add(item);
77.118 -
77.119 - return true;
77.120 - }
77.121 -
77.122 - if (arr[i].equals(item)) {
77.123 - // already there
77.124 - if (i != newIndex) {
77.125 - // change in index
77.126 - changed.add(item);
77.127 -
77.128 - return false;
77.129 - } else {
77.130 - // no change
77.131 - return false;
77.132 - }
77.133 - }
77.134 - }
77.135 -
77.136 - // if not found in the original array
77.137 - changed.add(item);
77.138 -
77.139 - return true;
77.140 - }
77.141 - }
77.142 -
77.143 - /** Removes an item.
77.144 - */
77.145 - public void remove(AbstractLookup.Pair item, Transaction changed) {
77.146 - Object[] arr = changed.current;
77.147 - if (arr == null) {
77.148 - return;
77.149 - }
77.150 -
77.151 - int found = -1;
77.152 -
77.153 - for (int i = 0; i < arr.length;) {
77.154 - if (arr[i] == null) {
77.155 - // end of task
77.156 - return;
77.157 - }
77.158 -
77.159 - if ((found == -1) && arr[i].equals(item)) {
77.160 - // already there
77.161 - Pair<?> p = (Pair<?>)arr[i];
77.162 - p.setIndex(null, -1);
77.163 - changed.add(p);
77.164 - found = i;
77.165 - }
77.166 -
77.167 - i++;
77.168 -
77.169 - if (found != -1) {
77.170 - if (i < arr.length && !(arr[i] instanceof Integer)) {
77.171 - // moving the array
77.172 - arr[i - 1] = arr[i];
77.173 - } else {
77.174 - arr[i - 1] = null;
77.175 - }
77.176 - }
77.177 - }
77.178 - }
77.179 -
77.180 - /** Removes all items that are not present in the provided collection.
77.181 - * @param retain Pair -> AbstractLookup.Info map
77.182 - * @param notify set of Classes that has possibly changed
77.183 - */
77.184 - public void retainAll(Map retain, Transaction changed) {
77.185 - Object[] arr = changed.current;
77.186 -
77.187 - for (int from = 0; from < arr.length; from++) {
77.188 - if (!(arr[from] instanceof AbstractLookup.Pair)) {
77.189 - // end of content
77.190 - break;
77.191 - }
77.192 -
77.193 - AbstractLookup.Pair p = (AbstractLookup.Pair) arr[from];
77.194 -
77.195 - AbstractLookup.Info info = (AbstractLookup.Info) retain.get(p);
77.196 -
77.197 - if (info == null) {
77.198 - // was removed
77.199 -
77.200 - /*
77.201 - if (info != null) {
77.202 - if (info.index < arr.length) {
77.203 - newArr[info.index] = p;
77.204 - }
77.205 -
77.206 - if (p.getIndex() != info.index) {
77.207 - p.setIndex (null, info.index);
77.208 - changed.add (p);
77.209 - }
77.210 - } else {
77.211 - // removed
77.212 - */
77.213 - changed.add(p);
77.214 - }
77.215 - }
77.216 - }
77.217 -
77.218 - /** Queries for instances of given class.
77.219 - * @param clazz the class to check
77.220 - * @return enumeration of Item
77.221 - * @see #unsorted
77.222 - */
77.223 - public <T> Enumeration<Pair<T>> lookup(final Class<T> clazz) {
77.224 - if (content instanceof Object[]) {
77.225 - final Enumeration<Object> all = InheritanceTree.arrayEn((Object[]) content);
77.226 - class JustPairs implements Enumeration<Pair<T>> {
77.227 - private Pair<T> next;
77.228 -
77.229 - @SuppressWarnings("unchecked")
77.230 - private Pair<T> findNext() {
77.231 - for (;;) {
77.232 - if (next != null) {
77.233 - return next;
77.234 - }
77.235 - if (!all.hasMoreElements()) {
77.236 - return null;
77.237 - }
77.238 - Object o = all.nextElement();
77.239 - boolean ok;
77.240 - if (o instanceof AbstractLookup.Pair) {
77.241 - ok = (clazz == null) || ((AbstractLookup.Pair<?>) o).instanceOf(clazz);
77.242 - } else {
77.243 - ok = false;
77.244 - }
77.245 -
77.246 - next = ok ? (Pair<T>) o : null;
77.247 - }
77.248 - }
77.249 -
77.250 - public boolean hasMoreElements() {
77.251 - return findNext() != null;
77.252 - }
77.253 -
77.254 - public Pair<T> nextElement() {
77.255 - Pair<T> r = findNext();
77.256 - if (r == null) {
77.257 - throw new NoSuchElementException();
77.258 - }
77.259 - next = null;
77.260 - return r;
77.261 - }
77.262 - } // end of JustPairs
77.263 - return new JustPairs();
77.264 - } else {
77.265 - return InheritanceTree.emptyEn();
77.266 - }
77.267 - }
77.268 -
77.269 - /** Associates another result with this storage.
77.270 - */
77.271 - public AbstractLookup.ReferenceToResult registerReferenceToResult(AbstractLookup.ReferenceToResult<?> newRef) {
77.272 - AbstractLookup.ReferenceToResult prev = this.results;
77.273 - this.results = newRef;
77.274 -
77.275 - return prev;
77.276 - }
77.277 -
77.278 - /** Cleanup the references
77.279 - */
77.280 - public AbstractLookup.ReferenceToResult cleanUpResult(Lookup.Template<?> templ) {
77.281 - AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
77.282 -
77.283 - while (it.next()) {
77.284 - // empty
77.285 - }
77.286 -
77.287 - return this.results = it.first();
77.288 - }
77.289 -
77.290 - /** We use a hash set of all modified Pair to handle the transaction */
77.291 - public Transaction beginTransaction(int ensure) {
77.292 - return new Transaction(ensure, content);
77.293 - }
77.294 -
77.295 - /** Extract all results.
77.296 - */
77.297 - public void endTransaction(Transaction changed, Set<AbstractLookup.R> modified) {
77.298 - AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
77.299 -
77.300 - if (changed.arr == null) {
77.301 - // either add or remove, only check the content of check HashSet
77.302 - while (it.next()) {
77.303 - AbstractLookup.ReferenceToResult ref = it.current();
77.304 - Iterator<Pair<?>> pairs = changed.iterator();
77.305 -
77.306 - while (pairs.hasNext()) {
77.307 - AbstractLookup.Pair p = (AbstractLookup.Pair) pairs.next();
77.308 -
77.309 - if (AbstractLookup.matches(ref.template, p, true)) {
77.310 - modified.add(ref.getResult());
77.311 - }
77.312 - }
77.313 - }
77.314 - } else {
77.315 - // do full check of changes
77.316 - while (it.next()) {
77.317 - AbstractLookup.ReferenceToResult ref = it.current();
77.318 -
77.319 - int oldIndex = -1;
77.320 - int newIndex = -1;
77.321 -
77.322 - for (;;) {
77.323 - oldIndex = findMatching(ref.template, changed.current, oldIndex);
77.324 - newIndex = findMatching(ref.template, changed.arr, newIndex);
77.325 -
77.326 - if ((oldIndex == -1) && (newIndex == -1)) {
77.327 - break;
77.328 - }
77.329 -
77.330 - if (
77.331 - (oldIndex == -1) || (newIndex == -1) ||
77.332 - !changed.current[oldIndex].equals(changed.arr[newIndex])
77.333 - ) {
77.334 - modified.add(ref.getResult());
77.335 -
77.336 - break;
77.337 - }
77.338 - }
77.339 - }
77.340 - }
77.341 -
77.342 - this.results = it.first();
77.343 - this.content = changed.newContent(this.content);
77.344 - }
77.345 -
77.346 - private static int findMatching(Lookup.Template t, Object[] arr, int from) {
77.347 - while (++from < arr.length) {
77.348 - if (arr[from] instanceof AbstractLookup.Pair) {
77.349 - if (AbstractLookup.matches(t, (AbstractLookup.Pair) arr[from], true)) {
77.350 - return from;
77.351 - }
77.352 - }
77.353 - }
77.354 -
77.355 - return -1;
77.356 - }
77.357 -
77.358 - /** HashSet with additional field for new array which is callocated
77.359 - * in case we are doing replace to hold all new items.
77.360 - */
77.361 - static final class Transaction extends HashSet<Pair<?>> {
77.362 - /** array with current objects */
77.363 - public final Object[] current;
77.364 -
77.365 - /** array with new objects */
77.366 - public final Object[] arr;
77.367 -
77.368 - /** number of objects in the array */
77.369 - private int cnt;
77.370 -
77.371 - public Transaction(int ensure, Object currentContent) {
77.372 - Integer trashold;
77.373 - Object[] _arr;
77.374 -
77.375 - if (currentContent instanceof Integer) {
77.376 - trashold = (Integer) currentContent;
77.377 - _arr = null;
77.378 - } else {
77.379 - _arr = (Object[]) currentContent;
77.380 -
77.381 - if (_arr[_arr.length - 1] instanceof Integer) {
77.382 - trashold = (Integer) _arr[_arr.length - 1];
77.383 - } else {
77.384 - // nowhere to grow we have reached the limit
77.385 - trashold = null;
77.386 - }
77.387 - }
77.388 -
77.389 - int maxSize = (trashold == null) ? _arr.length : trashold.intValue();
77.390 -
77.391 - if (ensure > maxSize) {
77.392 - throw new UnsupportedOperationException();
77.393 - }
77.394 -
77.395 - if (ensure == -1) {
77.396 - // remove => it is ok
77.397 - this.current = currentContent instanceof Integer ? null : (Object[]) currentContent;
77.398 - this.arr = null;
77.399 -
77.400 - return;
77.401 - }
77.402 -
77.403 - if (ensure == -2) {
77.404 - // adding one
77.405 - if (_arr == null) {
77.406 - // first time add, let's allocate the array
77.407 - _arr = new Object[2];
77.408 - _arr[1] = trashold;
77.409 - } else {
77.410 - if (_arr[_arr.length - 1] instanceof AbstractLookup.Pair) {
77.411 - // we are full
77.412 - throw new UnsupportedOperationException();
77.413 - } else {
77.414 - // ensure we have allocated enough space
77.415 - if (_arr.length < 2 || _arr[_arr.length - 2] != null) {
77.416 - // double the array
77.417 - int newSize = (_arr.length - 1) * 2;
77.418 -
77.419 - if (newSize <= 1) {
77.420 - newSize = 2;
77.421 - }
77.422 -
77.423 - if (newSize > maxSize) {
77.424 - newSize = maxSize;
77.425 -
77.426 - if (newSize <= _arr.length) {
77.427 - // no space to get in
77.428 - throw new UnsupportedOperationException();
77.429 - }
77.430 -
77.431 - _arr = new Object[newSize];
77.432 - } else {
77.433 - // still a lot of space
77.434 - _arr = new Object[newSize + 1];
77.435 - _arr[newSize] = trashold;
77.436 - }
77.437 -
77.438 - // copy content of original array without the last Integer into
77.439 - // the new one
77.440 - System.arraycopy(currentContent, 0, _arr, 0, ((Object[]) currentContent).length - 1);
77.441 - }
77.442 - }
77.443 - }
77.444 -
77.445 - this.current = _arr;
77.446 - this.arr = null;
77.447 - } else {
77.448 - // allocate array for complete replacement
77.449 - if (ensure == maxSize) {
77.450 - this.arr = new Object[ensure];
77.451 - } else {
77.452 - this.arr = new Object[ensure + 1];
77.453 - this.arr[ensure] = trashold;
77.454 - }
77.455 -
77.456 - this.current = (currentContent instanceof Object[]) ? (Object[]) currentContent : new Object[0];
77.457 - }
77.458 - }
77.459 -
77.460 - public int addPair(AbstractLookup.Pair<?> p) {
77.461 - p.setIndex(null, cnt);
77.462 - arr[cnt++] = p;
77.463 -
77.464 - return p.getIndex();
77.465 - }
77.466 -
77.467 - public Object newContent(Object prev) {
77.468 - if (arr == null) {
77.469 - if (current == null) {
77.470 - return prev;
77.471 - } else {
77.472 - return current;
77.473 - }
77.474 - } else {
77.475 - return arr;
77.476 - }
77.477 - }
77.478 - }
77.479 - // end of Transaction
77.480 -}
78.1 --- a/openide.util/src/org/openide/util/lookup/DelegatingStorage.java Sat Oct 31 15:06:58 2009 +0100
78.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
78.3 @@ -1,180 +0,0 @@
78.4 -/*
78.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
78.6 - *
78.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
78.8 - *
78.9 - * The contents of this file are subject to the terms of either the GNU
78.10 - * General Public License Version 2 only ("GPL") or the Common
78.11 - * Development and Distribution License("CDDL") (collectively, the
78.12 - * "License"). You may not use this file except in compliance with the
78.13 - * License. You can obtain a copy of the License at
78.14 - * http://www.netbeans.org/cddl-gplv2.html
78.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
78.16 - * specific language governing permissions and limitations under the
78.17 - * License. When distributing the software, include this License Header
78.18 - * Notice in each file and include the License file at
78.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
78.20 - * particular file as subject to the "Classpath" exception as provided
78.21 - * by Sun in the GPL Version 2 section of the License file that
78.22 - * accompanied this code. If applicable, add the following below the
78.23 - * License Header, with the fields enclosed by brackets [] replaced by
78.24 - * your own identifying information:
78.25 - * "Portions Copyrighted [year] [name of copyright owner]"
78.26 - *
78.27 - * Contributor(s):
78.28 - *
78.29 - * The Original Software is NetBeans. The Initial Developer of the Original
78.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
78.31 - * Microsystems, Inc. All Rights Reserved.
78.32 - *
78.33 - * If you wish your version of this file to be governed by only the CDDL
78.34 - * or only the GPL Version 2, indicate your decision by adding
78.35 - * "[Contributor] elects to include this software in this distribution
78.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
78.37 - * single choice of license, a recipient has the option to distribute
78.38 - * your version of this file under either the CDDL, the GPL Version 2 or
78.39 - * to extend the choice of license to its licensees as provided above.
78.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
78.41 - * Version 2 license, then the option applies only if the new code is
78.42 - * made subject to such option by the copyright holder.
78.43 - */
78.44 -package org.openide.util.lookup;
78.45 -
78.46 -import org.openide.util.Lookup;
78.47 -
78.48 -import java.io.*;
78.49 -
78.50 -import java.lang.ref.WeakReference;
78.51 -
78.52 -import java.util.*;
78.53 -import org.openide.util.lookup.AbstractLookup.Pair;
78.54 -
78.55 -
78.56 -/** Storages that can switch between another storages.
78.57 - * @author Jaroslav Tulach
78.58 - */
78.59 -final class DelegatingStorage<Transaction> extends Object
78.60 -implements Serializable, AbstractLookup.Storage<Transaction> {
78.61 - /** object to delegate to */
78.62 - private AbstractLookup.Storage<Transaction> delegate;
78.63 -
78.64 - /** thread just accessing the storage */
78.65 - private Thread owner;
78.66 -
78.67 - public DelegatingStorage(AbstractLookup.Storage<Transaction> d) {
78.68 - this.delegate = d;
78.69 - this.owner = Thread.currentThread();
78.70 - }
78.71 -
78.72 - /** Never serialize yourself, always put there the delegate */
78.73 - public Object writeReplace() {
78.74 - return this.delegate;
78.75 - }
78.76 -
78.77 - /** Method to check whether there is not multiple access from the same thread.
78.78 - */
78.79 - public void checkForTreeModification() {
78.80 - if (Thread.currentThread() == owner) {
78.81 - throw new AbstractLookup.ISE("You are trying to modify lookup from lookup query!"); // NOI18N
78.82 - }
78.83 - }
78.84 -
78.85 - /** Checks whether we have simple behaviour or complex.
78.86 - */
78.87 - public static boolean isSimple(AbstractLookup.Storage s) {
78.88 - if (s instanceof DelegatingStorage) {
78.89 - return ((DelegatingStorage) s).delegate instanceof ArrayStorage;
78.90 - } else {
78.91 - return s instanceof ArrayStorage;
78.92 - }
78.93 - }
78.94 -
78.95 - /** Exits from the owners ship of the storage.
78.96 - */
78.97 - public AbstractLookup.Storage<Transaction> exitDelegate() {
78.98 - if (Thread.currentThread() != owner) {
78.99 - throw new IllegalStateException("Onwer: " + owner + " caller: " + Thread.currentThread()); // NOI18N
78.100 - }
78.101 -
78.102 - AbstractLookup.Storage<Transaction> d = delegate;
78.103 - delegate = null;
78.104 -
78.105 - return d;
78.106 - }
78.107 -
78.108 - public boolean add(AbstractLookup.Pair<?> item, Transaction transaction) {
78.109 - return delegate.add(item, transaction);
78.110 - }
78.111 -
78.112 - public void remove(org.openide.util.lookup.AbstractLookup.Pair item, Transaction transaction) {
78.113 - delegate.remove(item, transaction);
78.114 - }
78.115 -
78.116 - public void retainAll(Map retain, Transaction transaction) {
78.117 - delegate.retainAll(retain, transaction);
78.118 - }
78.119 -
78.120 - /** A special method to change the backing storage.
78.121 - * In fact it is not much typesafe as it changes the
78.122 - * type of Transaction but we know that nobody is currently
78.123 - * holding a transaction object, so there cannot be inconsitencies.
78.124 - */
78.125 - @SuppressWarnings("unchecked")
78.126 - private void changeDelegate(InheritanceTree st) {
78.127 - delegate = (AbstractLookup.Storage<Transaction>)st;
78.128 - }
78.129 -
78.130 - public Transaction beginTransaction(int ensure) {
78.131 - try {
78.132 - return delegate.beginTransaction(ensure);
78.133 - } catch (UnsupportedOperationException ex) {
78.134 - // let's convert to InheritanceTree
78.135 - ArrayStorage arr = (ArrayStorage) delegate;
78.136 - InheritanceTree inh = new InheritanceTree();
78.137 - changeDelegate(inh);
78.138 -
78.139 - //
78.140 - // Copy content
78.141 - //
78.142 - Enumeration<Pair<Object>> en = arr.lookup(Object.class);
78.143 -
78.144 - while (en.hasMoreElements()) {
78.145 - if (!inh.add(en.nextElement(), new ArrayList<Class>())) {
78.146 - throw new IllegalStateException("All objects have to be accepted"); // NOI18N
78.147 - }
78.148 - }
78.149 -
78.150 - //
78.151 - // Copy listeners
78.152 - //
78.153 - AbstractLookup.ReferenceToResult<?> ref = arr.cleanUpResult(null);
78.154 -
78.155 - if (ref != null) {
78.156 - ref.cloneList(inh);
78.157 - }
78.158 -
78.159 - // we have added the current content and now we can start transaction
78.160 - return delegate.beginTransaction(ensure);
78.161 - }
78.162 - }
78.163 -
78.164 - public org.openide.util.lookup.AbstractLookup.ReferenceToResult cleanUpResult(
78.165 - org.openide.util.Lookup.Template templ
78.166 - ) {
78.167 - return delegate.cleanUpResult(templ);
78.168 - }
78.169 -
78.170 - public void endTransaction(Transaction transaction, Set<AbstractLookup.R> modified) {
78.171 - delegate.endTransaction(transaction, modified);
78.172 - }
78.173 -
78.174 - public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
78.175 - return delegate.lookup(clazz);
78.176 - }
78.177 -
78.178 - public org.openide.util.lookup.AbstractLookup.ReferenceToResult registerReferenceToResult(
78.179 - org.openide.util.lookup.AbstractLookup.ReferenceToResult newRef
78.180 - ) {
78.181 - return delegate.registerReferenceToResult(newRef);
78.182 - }
78.183 -}
79.1 --- a/openide.util/src/org/openide/util/lookup/ExcludingLookup.java Sat Oct 31 15:06:58 2009 +0100
79.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
79.3 @@ -1,428 +0,0 @@
79.4 -/*
79.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
79.6 - *
79.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
79.8 - *
79.9 - * The contents of this file are subject to the terms of either the GNU
79.10 - * General Public License Version 2 only ("GPL") or the Common
79.11 - * Development and Distribution License("CDDL") (collectively, the
79.12 - * "License"). You may not use this file except in compliance with the
79.13 - * License. You can obtain a copy of the License at
79.14 - * http://www.netbeans.org/cddl-gplv2.html
79.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
79.16 - * specific language governing permissions and limitations under the
79.17 - * License. When distributing the software, include this License Header
79.18 - * Notice in each file and include the License file at
79.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
79.20 - * particular file as subject to the "Classpath" exception as provided
79.21 - * by Sun in the GPL Version 2 section of the License file that
79.22 - * accompanied this code. If applicable, add the following below the
79.23 - * License Header, with the fields enclosed by brackets [] replaced by
79.24 - * your own identifying information:
79.25 - * "Portions Copyrighted [year] [name of copyright owner]"
79.26 - *
79.27 - * Contributor(s):
79.28 - *
79.29 - * The Original Software is NetBeans. The Initial Developer of the Original
79.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
79.31 - * Microsystems, Inc. All Rights Reserved.
79.32 - *
79.33 - * If you wish your version of this file to be governed by only the CDDL
79.34 - * or only the GPL Version 2, indicate your decision by adding
79.35 - * "[Contributor] elects to include this software in this distribution
79.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
79.37 - * single choice of license, a recipient has the option to distribute
79.38 - * your version of this file under either the CDDL, the GPL Version 2 or
79.39 - * to extend the choice of license to its licensees as provided above.
79.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
79.41 - * Version 2 license, then the option applies only if the new code is
79.42 - * made subject to such option by the copyright holder.
79.43 - */
79.44 -package org.openide.util.lookup;
79.45 -
79.46 -import java.lang.ref.Reference;
79.47 -import java.lang.ref.WeakReference;
79.48 -import org.openide.util.Lookup;
79.49 -import org.openide.util.LookupListener;
79.50 -
79.51 -import java.util.*;
79.52 -import org.openide.util.LookupEvent;
79.53 -
79.54 -
79.55 -/** Allows exclusion of certain instances from lookup.
79.56 - *
79.57 - * @author Jaroslav Tulach
79.58 - */
79.59 -final class ExcludingLookup extends org.openide.util.Lookup {
79.60 - /** the other lookup that we delegate to */
79.61 - private Lookup delegate;
79.62 -
79.63 - /** classes to exclude (Class[]) or just one class (Class) */
79.64 - private Object classes;
79.65 -
79.66 - /**
79.67 - * Creates new Result object with supplied instances parameter.
79.68 - * @param instances to be used to return from the lookup
79.69 - */
79.70 - ExcludingLookup(Lookup delegate, Class[] classes) {
79.71 - this.delegate = delegate;
79.72 -
79.73 - for (Class c : classes) {
79.74 - if (c == null) {
79.75 - throw new NullPointerException();
79.76 - }
79.77 - }
79.78 - if (classes.length == 1) {
79.79 - this.classes = classes[0];
79.80 - } else {
79.81 - this.classes = classes;
79.82 - }
79.83 - }
79.84 -
79.85 - @Override
79.86 - public String toString() {
79.87 - return "ExcludingLookup: " + delegate + " excludes: " + Arrays.asList(classes()); // NOI18N
79.88 - }
79.89 -
79.90 - public <T> Result<T> lookup(Template<T> template) {
79.91 - if (template == null) {
79.92 - throw new NullPointerException();
79.93 - }
79.94 -
79.95 - if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
79.96 - // empty result
79.97 - return Lookup.EMPTY.lookup(template);
79.98 - }
79.99 -
79.100 - return new R<T>(template.getType(), delegate.lookup(template));
79.101 - }
79.102 -
79.103 - public <T> T lookup(Class<T> clazz) {
79.104 - if (areSubclassesOfThisClassAlwaysExcluded(clazz)) {
79.105 - return null;
79.106 - }
79.107 -
79.108 - T res = delegate.lookup(clazz);
79.109 -
79.110 - if (isObjectAccessible(clazz, res, 0)) {
79.111 - return res;
79.112 - } else {
79.113 - return null;
79.114 - }
79.115 - }
79.116 -
79.117 - @Override
79.118 - public <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
79.119 - if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
79.120 - return null;
79.121 - }
79.122 -
79.123 - Lookup.Item<T> retValue = delegate.lookupItem(template);
79.124 -
79.125 - if (isObjectAccessible(template.getType(), retValue, 2)) {
79.126 - return retValue;
79.127 - } else {
79.128 - return null;
79.129 - }
79.130 - }
79.131 -
79.132 - /** @return true if the instance of class c shall never be returned from this lookup
79.133 - */
79.134 - private boolean areSubclassesOfThisClassAlwaysExcluded(Class<?> c) {
79.135 - Class<?>[] arr = classes();
79.136 -
79.137 - for (int i = 0; i < arr.length; i++) {
79.138 - if (arr[i].isAssignableFrom(c)) {
79.139 - return true;
79.140 - }
79.141 - }
79.142 -
79.143 - return false;
79.144 - }
79.145 -
79.146 - /** Returns the array of classes this lookup filters.
79.147 - */
79.148 - final Class<?>[] classes() {
79.149 - if (classes instanceof Class[]) {
79.150 - return (Class[]) classes;
79.151 - } else {
79.152 - return new Class[] { (Class) classes };
79.153 - }
79.154 - }
79.155 -
79.156 - /** Does a check whether two classes are accessible (in the super/sub class)
79.157 - * releation ship without walking thru any of the classes mentioned in the
79.158 - * barrier.
79.159 - */
79.160 - private static boolean isAccessible(Class<?>[] barriers, Class<?> from, Class<?> to) {
79.161 - if ((to == null) || !from.isAssignableFrom(to)) {
79.162 - // no way to reach each other by walking up
79.163 - return false;
79.164 - }
79.165 -
79.166 - for (int i = 0; i < barriers.length; i++) {
79.167 - if (to == barriers[i]) {
79.168 - return false;
79.169 - }
79.170 - }
79.171 -
79.172 - if (from == to) {
79.173 - return true;
79.174 - }
79.175 -
79.176 - //
79.177 - // depth first search
79.178 - //
79.179 - if (isAccessible(barriers, from, to.getSuperclass())) {
79.180 - return true;
79.181 - }
79.182 -
79.183 - Class[] interfaces = to.getInterfaces();
79.184 -
79.185 - for (int i = 0; i < interfaces.length; i++) {
79.186 - if (isAccessible(barriers, from, interfaces[i])) {
79.187 - return true;
79.188 - }
79.189 - }
79.190 -
79.191 - return false;
79.192 - }
79.193 -
79.194 - /** based on type decides whether the class accepts or not anObject
79.195 - * @param from the base type of the query
79.196 - * @param to depending on value of type either Object, Class or Item
79.197 - * @param type 0,1,2 for Object, Class or Item
79.198 - * @return true if we can access the to from from by walking around the bariers
79.199 - */
79.200 - private final boolean isObjectAccessible(Class from, Object to, int type) {
79.201 - if (to == null) {
79.202 - return false;
79.203 - }
79.204 -
79.205 - return isObjectAccessible(classes(), from, to, type);
79.206 - }
79.207 -
79.208 - /** based on type decides whether the class accepts or not anObject
79.209 - * @param barriers classes to avoid when testing reachability
79.210 - * @param from the base type of the query
79.211 - * @param to depending on value of type either Object, Class or Item
79.212 - * @param type 0,1,2 for Object, Class or Item
79.213 - * @return true if we can access the to from from by walking around the bariers
79.214 - */
79.215 - static final boolean isObjectAccessible(Class[] barriers, Class from, Object to, int type) {
79.216 - if (to == null) {
79.217 - return false;
79.218 - }
79.219 -
79.220 - switch (type) {
79.221 - case 0:
79.222 - return isAccessible(barriers, from, to.getClass());
79.223 -
79.224 - case 1:
79.225 - return isAccessible(barriers, from, (Class) to);
79.226 -
79.227 - case 2: {
79.228 - Item item = (Item) to;
79.229 -
79.230 - return isAccessible(barriers, from, item.getType());
79.231 - }
79.232 -
79.233 - default:
79.234 - throw new IllegalStateException("Type: " + type);
79.235 - }
79.236 - }
79.237 -
79.238 - /** Filters collection accroding to set of given filters.
79.239 - */
79.240 - final <E, T extends Collection<E>> T filter(
79.241 - Class<?>[] arr, Class<?> from, T c, int type, T prototype
79.242 - ) {
79.243 - T ret = null;
79.244 -
79.245 -
79.246 -// optimistic strategy expecting we will not need to filter
79.247 -TWICE:
79.248 - for (;;) {
79.249 - Iterator<E> it = c.iterator();
79.250 -BIG:
79.251 - while (it.hasNext()) {
79.252 - E res = it.next();
79.253 -
79.254 - if (!isObjectAccessible(arr, from, res, type)) {
79.255 - if (ret == null) {
79.256 - // we need to restart the scanning again
79.257 - // as there is an active filter
79.258 - ret = prototype;
79.259 - continue TWICE;
79.260 - }
79.261 -
79.262 - continue BIG;
79.263 - }
79.264 -
79.265 - if (ret != null) {
79.266 - // if we are running the second round from TWICE
79.267 - ret.add(res);
79.268 - }
79.269 - }
79.270 -
79.271 - // ok, processed
79.272 - break TWICE;
79.273 - }
79.274 -
79.275 - return (ret != null) ? ret : c;
79.276 - }
79.277 -
79.278 - /** Delegating result that filters unwanted items and instances.
79.279 - */
79.280 - private final class R<T> extends WaitableResult<T> implements LookupListener {
79.281 - private Result<T> result;
79.282 - private WeakResult<T> weak;
79.283 - private Object listeners;
79.284 - private Class<?> from;
79.285 -
79.286 - R(Class<?> from, Result<T> delegate) {
79.287 - this.from = from;
79.288 - this.result = delegate;
79.289 - this.weak = new WeakResult<T>(this, delegate);
79.290 - }
79.291 -
79.292 - protected void beforeLookup(Template t) {
79.293 - if (result instanceof WaitableResult) {
79.294 - ((WaitableResult) result).beforeLookup(t);
79.295 - }
79.296 - }
79.297 -
79.298 - public void addLookupListener(LookupListener l) {
79.299 - boolean add;
79.300 -
79.301 - synchronized (this) {
79.302 - listeners = AbstractLookup.modifyListenerList(true, l, listeners);
79.303 - add = listeners != null;
79.304 - }
79.305 -
79.306 - if (add) {
79.307 - result.addLookupListener(weak);
79.308 - }
79.309 - }
79.310 -
79.311 - public void removeLookupListener(LookupListener l) {
79.312 - boolean remove;
79.313 -
79.314 - synchronized (this) {
79.315 - listeners = AbstractLookup.modifyListenerList(false, l, listeners);
79.316 - remove = listeners == null;
79.317 - }
79.318 -
79.319 - if (remove) {
79.320 - result.removeLookupListener(weak);
79.321 - }
79.322 - }
79.323 -
79.324 - public Collection<? extends T> allInstances() {
79.325 - return openCol(result.allInstances(), 0);
79.326 - }
79.327 -
79.328 - private <S> Collection<S> openCol(Collection<S> c, int type) {
79.329 - return filter(classes(), from, c, type, new ArrayList<S>(c.size()));
79.330 - }
79.331 -
79.332 - @Override
79.333 - public Set<Class<? extends T>> allClasses() {
79.334 - return filter(classes(), from, result.allClasses(), 1, new HashSet<Class<? extends T>>());
79.335 - }
79.336 -
79.337 - @Override
79.338 - public Collection<? extends Item<T>> allItems() {
79.339 - return openCol(result.allItems(), 2);
79.340 - }
79.341 -
79.342 - public void resultChanged(org.openide.util.LookupEvent ev) {
79.343 - if (ev.getSource() == result) {
79.344 - collectFires(null);
79.345 - }
79.346 - }
79.347 -
79.348 - protected void collectFires(Collection<Object> evAndListeners) {
79.349 - LookupListener[] arr;
79.350 -
79.351 - synchronized (this) {
79.352 - if (listeners == null) {
79.353 - return;
79.354 - }
79.355 -
79.356 - if (listeners instanceof LookupListener) {
79.357 - arr = new LookupListener[] { (LookupListener) listeners };
79.358 - } else {
79.359 - ArrayList<?> l = (ArrayList<?>) listeners;
79.360 - arr = l.toArray(new LookupListener[l.size()]);
79.361 - }
79.362 - }
79.363 -
79.364 - final LookupListener[] ll = arr;
79.365 - final org.openide.util.LookupEvent newev = new org.openide.util.LookupEvent(this);
79.366 - AbstractLookup.notifyListeners(ll, newev, evAndListeners);
79.367 - }
79.368 - } // end of R
79.369 -
79.370 - private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
79.371 - private Lookup.Result source;
79.372 - private Reference<R<T>> result;
79.373 -
79.374 - public WeakResult(R<T> r, Lookup.Result<T> s) {
79.375 - this.result = new WeakReference<R<T>>(r);
79.376 - this.source = s;
79.377 - }
79.378 -
79.379 - protected void beforeLookup(Lookup.Template t) {
79.380 - R r = (R)result.get();
79.381 - if (r != null) {
79.382 - r.beforeLookup(t);
79.383 - } else {
79.384 - source.removeLookupListener(this);
79.385 - }
79.386 - }
79.387 -
79.388 - protected void collectFires(Collection<Object> evAndListeners) {
79.389 - R<T> r = result.get();
79.390 - if (r != null) {
79.391 - r.collectFires(evAndListeners);
79.392 - } else {
79.393 - source.removeLookupListener(this);
79.394 - }
79.395 - }
79.396 -
79.397 - public void addLookupListener(LookupListener l) {
79.398 - assert false;
79.399 - }
79.400 -
79.401 - public void removeLookupListener(LookupListener l) {
79.402 - assert false;
79.403 - }
79.404 -
79.405 - public Collection<T> allInstances() {
79.406 - assert false;
79.407 - return null;
79.408 - }
79.409 -
79.410 - public void resultChanged(LookupEvent ev) {
79.411 - R r = (R)result.get();
79.412 - if (r != null) {
79.413 - r.resultChanged(ev);
79.414 - } else {
79.415 - source.removeLookupListener(this);
79.416 - }
79.417 - }
79.418 -
79.419 - @Override
79.420 - public Collection<? extends Item<T>> allItems() {
79.421 - assert false;
79.422 - return null;
79.423 - }
79.424 -
79.425 - @Override
79.426 - public Set<Class<? extends T>> allClasses() {
79.427 - assert false;
79.428 - return null;
79.429 - }
79.430 - } // end of WeakResult
79.431 -}
80.1 --- a/openide.util/src/org/openide/util/lookup/InheritanceTree.java Sat Oct 31 15:06:58 2009 +0100
80.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
80.3 @@ -1,1276 +0,0 @@
80.4 -/*
80.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
80.6 - *
80.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
80.8 - *
80.9 - * The contents of this file are subject to the terms of either the GNU
80.10 - * General Public License Version 2 only ("GPL") or the Common
80.11 - * Development and Distribution License("CDDL") (collectively, the
80.12 - * "License"). You may not use this file except in compliance with the
80.13 - * License. You can obtain a copy of the License at
80.14 - * http://www.netbeans.org/cddl-gplv2.html
80.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
80.16 - * specific language governing permissions and limitations under the
80.17 - * License. When distributing the software, include this License Header
80.18 - * Notice in each file and include the License file at
80.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
80.20 - * particular file as subject to the "Classpath" exception as provided
80.21 - * by Sun in the GPL Version 2 section of the License file that
80.22 - * accompanied this code. If applicable, add the following below the
80.23 - * License Header, with the fields enclosed by brackets [] replaced by
80.24 - * your own identifying information:
80.25 - * "Portions Copyrighted [year] [name of copyright owner]"
80.26 - *
80.27 - * Contributor(s):
80.28 - *
80.29 - * The Original Software is NetBeans. The Initial Developer of the Original
80.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
80.31 - * Microsystems, Inc. All Rights Reserved.
80.32 - *
80.33 - * If you wish your version of this file to be governed by only the CDDL
80.34 - * or only the GPL Version 2, indicate your decision by adding
80.35 - * "[Contributor] elects to include this software in this distribution
80.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
80.37 - * single choice of license, a recipient has the option to distribute
80.38 - * your version of this file under either the CDDL, the GPL Version 2 or
80.39 - * to extend the choice of license to its licensees as provided above.
80.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
80.41 - * Version 2 license, then the option applies only if the new code is
80.42 - * made subject to such option by the copyright holder.
80.43 - */
80.44 -package org.openide.util.lookup;
80.45 -
80.46 -import org.openide.util.Lookup;
80.47 -import org.openide.util.lookup.AbstractLookup.Pair;
80.48 -import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
80.49 -import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
80.50 -
80.51 -import java.io.*;
80.52 -
80.53 -import java.lang.ref.WeakReference;
80.54 -
80.55 -import java.util.*;
80.56 -
80.57 -
80.58 -/** A tree to represent classes with inheritance. Description of the
80.59 - * data structure by Petr Nejedly:
80.60 - * <P>
80.61 - * So pretend I'm Lookup implementation. I've got a bunch of Items (e.g.
80.62 - * setPairs() method),
80.63 - * didn't do anything on them yet (no startup penalty) so I know nothing
80.64 - * about them.
80.65 - * Then I'll be asked for all instances implementing given interface or a
80.66 - * class. I surely need
80.67 - * to check all the Items now, as I don't know anything abou them. I surely
80.68 - * don't want to call
80.69 - * Item.getClass() as it will dismiss the whole effort. So all I have is
80.70 - * Item.instanceOf()
80.71 - * and I'll call it on every Item. I'll cache results, so the next time
80.72 - * you'll ask me for
80.73 - * the same interface/class, I'll answer immediatelly. But what if you ask
80.74 - * me for another
80.75 - * interface/class? I'll have to scan all Items for it again, unless I can
80.76 - * be sure some
80.77 - * of them can't implement it. The only source of this knowledge are the
80.78 - * previous questions
80.79 - * and my rulings on them. Here the algorithm have to be split into two
80.80 - * paths. If you
80.81 - * previously asked me for interfaces only, I'll have no hint for
80.82 - * subsequent queries,
80.83 - * but if you asked me for a class in history, and then for another class
80.84 - * and these classes
80.85 - * are not in inheritance relation (I can check hierarchy of lookup
80.86 - * arguments, because
80.87 - * they are already resolved/loaded) I can tell that those returned in
80.88 - * previous query can't
80.89 - * implement the newly asked class (they are in different hierarchy branch)
80.90 - * and I need to
80.91 - * ask less Items.
80.92 - * <P>
80.93 - * So if we use mostly classes for asking for services (and it is a trend
80.94 - * to use
80.95 - * abstract classes for this purpose in IDE anyway), this could be usable.
80.96 - * <P>
80.97 - * The data structure for separating the Items based on previous queries is
80.98 - * simple
80.99 - * tree, with every node tagged with one class. The tree's root is,
80.100 - * naturally,
80.101 - * java.lang.Object, is marked invited and initially contains all the
80.102 - * Items.
80.103 - * For every class query, the missing part of class hierarchy tree is
80.104 - * created,
80.105 - * the node of the class looked up is marked as invited and all Items from
80.106 - * nearest
80.107 - * invited parent (sperclass) are dragged to this node. The result are then
80.108 - * all
80.109 - * Items from this node and all the nodes deeper in hierarchy. Because it
80.110 - * may
80.111 - * be too complicated to walk through the children nodes, the results could
80.112 - * be
80.113 - * cached in the map.
80.114 - * For interface lookup, there is a little hint in reality (interfaces
80.115 - * and superinterfaces), but it would be harder to exploit it, so we could
80.116 - * fall-back
80.117 - * to walking through all the Items and cache results.
80.118 - *
80.119 - *
80.120 - * @author Jaroslav Tulach
80.121 - */
80.122 -final class InheritanceTree extends Object
80.123 -implements Serializable, AbstractLookup.Storage<ArrayList<Class>> {
80.124 - private static final long serialVersionUID = 1L;
80.125 -
80.126 - /** the root item (represents Object) */
80.127 - private transient Node object;
80.128 -
80.129 - /** Map of queried interfaces.
80.130 - * <p>Type: <code>Map<Class, (Collection<AbstractLookup.Pair> | AbstractLookup.Pair)></code>
80.131 - */
80.132 - private transient Map<Class,Object> interfaces;
80.133 -
80.134 - /** Map (Class, ReferenceToResult) of all listeners that are waiting in
80.135 - * changes in class Class
80.136 - */
80.137 - private transient Map<Class,ReferenceToResult> reg;
80.138 -
80.139 - /** Constructor
80.140 - */
80.141 - public InheritanceTree() {
80.142 - object = new Node(java.lang.Object.class);
80.143 - }
80.144 -
80.145 - private void writeObject(ObjectOutputStream oos) throws IOException {
80.146 - oos.writeObject(object);
80.147 -
80.148 - if (interfaces != null) {
80.149 - Iterator it = interfaces.entrySet().iterator();
80.150 -
80.151 - while (it.hasNext()) {
80.152 - Map.Entry e = (Map.Entry) it.next();
80.153 - Class c = (Class) e.getKey();
80.154 - oos.writeObject(c.getName());
80.155 -
80.156 - Object o = e.getValue();
80.157 -
80.158 - if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
80.159 - throw new ClassCastException(String.valueOf(o));
80.160 - }
80.161 -
80.162 - oos.writeObject(o);
80.163 - }
80.164 - }
80.165 -
80.166 - oos.writeObject(null);
80.167 - }
80.168 -
80.169 - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
80.170 - object = (Node) ois.readObject();
80.171 - interfaces = new WeakHashMap<Class,Object>();
80.172 -
80.173 - String clazz;
80.174 - ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
80.175 -
80.176 - while ((clazz = (String) ois.readObject()) != null) {
80.177 - Object o = ois.readObject();
80.178 -
80.179 - if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
80.180 - throw new ClassCastException(String.valueOf(o));
80.181 - }
80.182 -
80.183 - Class c = Class.forName(clazz, false, l);
80.184 - interfaces.put(c, o);
80.185 - }
80.186 - }
80.187 -
80.188 - /** Adds an item into the tree.
80.189 - * @param item to add
80.190 - * @return true if the Item has been added for the first time or false if some other
80.191 - * item equal to this one already existed in the lookup
80.192 - */
80.193 - public boolean add(AbstractLookup.Pair<?> item, ArrayList<Class> affected) {
80.194 - Node node = registerClass(object, item);
80.195 -
80.196 - affected.add(node.getType());
80.197 -
80.198 - if (node.assignItem(this, item)) {
80.199 - // this is the first item added to n.items
80.200 - // ok, we have to test interfaces too
80.201 - } else {
80.202 - // equal item is already there => stop processing
80.203 - return false;
80.204 - }
80.205 -
80.206 - boolean registeredAsInterface = registerInterface(item, affected);
80.207 -
80.208 - return registeredAsInterface;
80.209 - }
80.210 -
80.211 - /** Removes an item.
80.212 - */
80.213 - public void remove(AbstractLookup.Pair item, ArrayList<Class> affected) {
80.214 - Node n = removeClass(object, item);
80.215 -
80.216 - if (n != null) {
80.217 - affected.add(n.getType());
80.218 - }
80.219 -
80.220 - removeInterface(item, affected);
80.221 - }
80.222 -
80.223 - /** Removes all items that are not present in the provided collection.
80.224 - * @param retain collection of Pairs to keep them in
80.225 - * @param notify set of Classes that has possibly changed
80.226 - */
80.227 - public void retainAll(Map retain, ArrayList<Class> notify) {
80.228 - retainAllInterface(retain, notify);
80.229 - retainAllClasses(object, retain, notify);
80.230 - }
80.231 -
80.232 - /** Queries for instances of given class.
80.233 - * @param clazz the class to check
80.234 - * @return enumeration of Item
80.235 - * @see #unsorted
80.236 - */
80.237 - @SuppressWarnings("unchecked")
80.238 - public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
80.239 - if ((clazz != null) && clazz.isInterface()) {
80.240 - return (Enumeration)searchInterface(clazz);
80.241 - } else {
80.242 - return (Enumeration)searchClass(object, clazz);
80.243 - }
80.244 - }
80.245 -
80.246 - /** A method to check whether the enumeration returned from
80.247 - * lookup method is sorted or is not
80.248 - * @param en enumeration to check
80.249 - * @return true if it is unsorted and needs to be sorted to find
80.250 - * pair with smallest index
80.251 - */
80.252 - public static boolean unsorted(Enumeration en) {
80.253 - return en instanceof NeedsSortEnum;
80.254 - }
80.255 -
80.256 - /** Prints debug messages.
80.257 - * @param out stream to output to
80.258 - * @param instances print also instances of the
80.259 - */
80.260 - public void print(java.io.PrintStream out, boolean instances) {
80.261 - printNode(object, "", out, instances); // NOI18N
80.262 - }
80.263 -
80.264 - //
80.265 - // methods to work on classes which are not interfaces
80.266 - //
80.267 -
80.268 - /** Searches the subtree and register the item where necessary.
80.269 - * @return the node that should contain the item
80.270 - */
80.271 - private static Node registerClass(Node n, AbstractLookup.Pair item) {
80.272 - if (!n.accepts(item)) {
80.273 - return null;
80.274 - }
80.275 -
80.276 - if (n.children != null) {
80.277 - Iterator it = n.children.iterator();
80.278 -
80.279 - for (;;) {
80.280 - Node ch = extractNode(it);
80.281 -
80.282 - if (ch == null) {
80.283 - break;
80.284 - }
80.285 -
80.286 - Node result = registerClass(ch, item);
80.287 -
80.288 - if (result != null) {
80.289 - // it is in subclass, in case of classes, it cannot
80.290 - // be any other class
80.291 - return result;
80.292 - }
80.293 - }
80.294 - }
80.295 -
80.296 - // ok, nobody of our subclasses wants the class, I'll take it
80.297 - return n;
80.298 - }
80.299 -
80.300 - /** Removes the item from the tree of objects.
80.301 - * @return most narrow class that this item was removed from
80.302 - */
80.303 - private static Node removeClass(Node n, AbstractLookup.Pair item) {
80.304 - if (!n.accepts(item)) {
80.305 - return null;
80.306 - }
80.307 -
80.308 - if ((n.items != null) && n.items.remove(item)) {
80.309 - // this node really contains the item
80.310 - return n;
80.311 - }
80.312 -
80.313 - if (n.children != null) {
80.314 - Iterator it = n.children.iterator();
80.315 -
80.316 - for (;;) {
80.317 - Node ch = extractNode(it);
80.318 -
80.319 - if (ch == null) {
80.320 - break;
80.321 - }
80.322 -
80.323 - Node result = removeClass(ch, item);
80.324 -
80.325 - // If the children node was emptied, remove it if possible.
80.326 - if (((ch.items == null) || ch.items.isEmpty()) && ((ch.children == null) || ch.children.isEmpty())) {
80.327 - it.remove();
80.328 - }
80.329 -
80.330 - if (result != null) {
80.331 - // it is in subclass, in case of classes, it cannot
80.332 - // be any other class
80.333 - return result;
80.334 - }
80.335 - }
80.336 - }
80.337 -
80.338 - // nobody found
80.339 - return null;
80.340 - }
80.341 -
80.342 - /** Finds a node that represents a class.
80.343 - * @param n node to search from
80.344 - * @param clazz the clazz to find
80.345 - * @return node that represents clazz in the tree or null if the clazz is not
80.346 - * represented under the node n
80.347 - */
80.348 - private Node classToNode(final Node n, final Class<?> clazz) {
80.349 - if (!n.accepts(clazz)) {
80.350 - // nothing from us
80.351 - return null;
80.352 - }
80.353 -
80.354 - if (n.getType() == clazz) {
80.355 - // we have found what we need
80.356 - return n;
80.357 - }
80.358 -
80.359 - if (n.children != null) {
80.360 - // have to proceed to children
80.361 - Iterator it = n.children.iterator();
80.362 -
80.363 - for (;;) {
80.364 - final Node ch = extractNode(it);
80.365 -
80.366 - if (ch == null) {
80.367 - break;
80.368 - }
80.369 -
80.370 - Node found = classToNode(ch, clazz);
80.371 -
80.372 - if ((found != null) && ch.deserialized()) {
80.373 - class VerifyJob implements AbstractLookup.ISE.Job {
80.374 - private AbstractLookup.Pair<?>[] pairs;
80.375 - private boolean[] answers;
80.376 -
80.377 - public VerifyJob(Collection<Pair> items) {
80.378 - if (items != null) {
80.379 - pairs = items.toArray(new AbstractLookup.Pair[0]);
80.380 - }
80.381 - }
80.382 -
80.383 - public void before() {
80.384 - // make sure the node is converted into deserialized state
80.385 - ch.deserialized();
80.386 -
80.387 - if (pairs != null) {
80.388 - answers = new boolean[pairs.length];
80.389 -
80.390 - for (int i = 0; i < pairs.length; i++) {
80.391 - answers[i] = pairs[i].instanceOf(clazz);
80.392 - }
80.393 - }
80.394 - }
80.395 -
80.396 - public void inside() {
80.397 - if (pairs != null) {
80.398 - for (int i = 0; i < pairs.length; i++) {
80.399 - if (answers[i]) {
80.400 - ch.assignItem(InheritanceTree.this, pairs[i]);
80.401 - n.items.remove(pairs[i]);
80.402 - }
80.403 - }
80.404 - }
80.405 -
80.406 - if (n.children != null) {
80.407 - // consolidate all nodes that represent the same class
80.408 - HashMap<Class,Node> nodes = new HashMap<Class,Node>(n.children.size() * 3);
80.409 -
80.410 - Iterator child = n.children.iterator();
80.411 -
80.412 - while (child.hasNext()) {
80.413 - Node node = extractNode(child);
80.414 - if (node == null) {
80.415 - continue;
80.416 - }
80.417 - Node prev = nodes.put(node.getType(), node);
80.418 -
80.419 - if (prev != null) {
80.420 - child.remove();
80.421 - nodes.put(node.getType(), prev);
80.422 -
80.423 - // mark as being deserialized
80.424 - prev.markDeserialized();
80.425 -
80.426 - if (prev.children == null) {
80.427 - prev.children = node.children;
80.428 - } else {
80.429 - if (node.children != null) {
80.430 - prev.children.addAll(node.children);
80.431 - }
80.432 - }
80.433 -
80.434 - if (node.items != null) {
80.435 - Iterator items = node.items.iterator();
80.436 -
80.437 - while (items.hasNext()) {
80.438 - AbstractLookup.Pair item = (AbstractLookup.Pair) items.next();
80.439 - prev.assignItem(InheritanceTree.this, item);
80.440 - }
80.441 - }
80.442 - }
80.443 - }
80.444 - }
80.445 - }
80.446 - }
80.447 -
80.448 - VerifyJob verify = new VerifyJob(n.items);
80.449 -
80.450 - try {
80.451 - verify.before();
80.452 - } catch (AbstractLookup.ISE ex) {
80.453 - // mark deserialized again
80.454 - ch.markDeserialized();
80.455 - ex.registerJob(verify);
80.456 - throw ex;
80.457 - }
80.458 -
80.459 - verify.inside();
80.460 -
80.461 - found = classToNode(ch, clazz);
80.462 - }
80.463 -
80.464 - if (found != null) {
80.465 - // class found in one of subnodes
80.466 - return found;
80.467 - }
80.468 - }
80.469 - }
80.470 -
80.471 - class TwoJobs implements AbstractLookup.ISE.Job {
80.472 - private AbstractLookup.Pair[] pairs;
80.473 - private boolean[] answers;
80.474 - private Node newNode;
80.475 -
80.476 - public void before() {
80.477 - // have to create new subnode and possibly reparent one of my own
80.478 - // but all changes can be done only if we will not be interrupted from
80.479 - // outside - e.g. instanceOf methods will not throw exception
80.480 - // first of all let's compute the answers to method instanceOf
80.481 - AbstractLookup.Pair[] arr = null;
80.482 - boolean[] boolArr = null;
80.483 -
80.484 - if (n.items != null) {
80.485 - arr = new AbstractLookup.Pair[n.items.size()];
80.486 - boolArr = new boolean[n.items.size()];
80.487 -
80.488 - int i = 0;
80.489 - Iterator<Pair> it = n.items.iterator();
80.490 -
80.491 - while (it.hasNext()) {
80.492 - AbstractLookup.Pair<?> item = it.next();
80.493 - arr[i] = item;
80.494 - boolArr[i] = item.instanceOf(clazz);
80.495 - i++;
80.496 - }
80.497 - }
80.498 -
80.499 - pairs = arr;
80.500 - answers = boolArr;
80.501 - }
80.502 -
80.503 - public void inside() {
80.504 - // test if the query has not chagned since
80.505 - if (pairs != null) {
80.506 - if (!Arrays.equals(n.items.toArray(), pairs)) {
80.507 - // ok, let try once more
80.508 - return;
80.509 - }
80.510 - }
80.511 -
80.512 - internal();
80.513 - }
80.514 -
80.515 - public void internal() {
80.516 - ArrayList<Node> reparent = null;
80.517 -
80.518 - if (n.children == null) {
80.519 - n.children = new ArrayList<Node>();
80.520 - } else {
80.521 - // scan thru all my nodes if some of them are not a subclass
80.522 - // of clazz => then they would need to become child of newNode
80.523 - Iterator it = n.children.iterator();
80.524 -
80.525 - for (;;) {
80.526 - Node r = extractNode(it);
80.527 -
80.528 - if (r == null) {
80.529 - break;
80.530 - }
80.531 -
80.532 - if (clazz.isAssignableFrom(r.getType())) {
80.533 - if (reparent == null) {
80.534 - reparent = new ArrayList<Node>();
80.535 - }
80.536 -
80.537 - reparent.add(r);
80.538 - it.remove();
80.539 - }
80.540 - }
80.541 - }
80.542 -
80.543 - newNode = new Node(clazz);
80.544 - n.children.add(newNode);
80.545 -
80.546 - if (reparent != null) {
80.547 - // reassing reparent node as a child of newNode
80.548 - newNode.children = reparent;
80.549 - }
80.550 -
80.551 - // now take all my items that are instances of that class and
80.552 - // reasign them
80.553 - if (n.items != null) {
80.554 - Iterator it = n.items.iterator();
80.555 - int i = 0;
80.556 -
80.557 - while (it.hasNext()) {
80.558 - AbstractLookup.Pair item = (AbstractLookup.Pair) it.next();
80.559 -
80.560 - if (answers[i]) { // answers[i] is precomputed value of item.instanceOf (clazz))
80.561 - it.remove();
80.562 - newNode.assignItem(InheritanceTree.this, pairs[i]);
80.563 - }
80.564 -
80.565 - i++;
80.566 - }
80.567 - }
80.568 - }
80.569 - }
80.570 -
80.571 - TwoJobs j = new TwoJobs();
80.572 -
80.573 - try {
80.574 - j.before();
80.575 - } catch (AbstractLookup.ISE ex) {
80.576 - // ok, it is not possible to call instanceOf now, let's
80.577 - // schedule it for later
80.578 - // so register recovery job
80.579 - ex.registerJob(j);
80.580 - throw ex;
80.581 - }
80.582 -
80.583 - j.internal();
80.584 -
80.585 - // newNode represents my clazz
80.586 - return j.newNode;
80.587 - }
80.588 -
80.589 - /** Search for a requested class.
80.590 - * @return enumeration of Pair
80.591 - */
80.592 - private Enumeration<Pair> searchClass(Node n, Class<?> clazz) {
80.593 - if (clazz != null) {
80.594 - n = classToNode(n, clazz);
80.595 - }
80.596 -
80.597 - if (n == null) {
80.598 - // not for us
80.599 - return emptyEn();
80.600 - } else {
80.601 - return nodeToEnum(n);
80.602 - }
80.603 - }
80.604 -
80.605 - /** Retains all classes. Removes nodes which items and children are emptied, works
80.606 - * recursivelly from specified root node.
80.607 - * @param node root node from which to start to process the tree
80.608 - * @param retain a map from (Item, AbstractLookup.Info) that describes which items to retain
80.609 - * and witch integer to assign them
80.610 - * @param notify collection of classes will be changed
80.611 - * @return <code>true<code> if some items were changed and node items and children are emptied,
80.612 - * those nodes, excluding root, will be removed from tree */
80.613 - private boolean retainAllClasses(Node node, Map retain, Collection<Class> notify) {
80.614 - boolean retained = false;
80.615 -
80.616 - if ((node.items != null) && (retain != null)) {
80.617 - Iterator<Pair> it = node.items.iterator();
80.618 -
80.619 - while (it.hasNext()) {
80.620 - AbstractLookup.Pair<?> item = it.next();
80.621 - AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(item);
80.622 -
80.623 - if (n == null) {
80.624 - // remove this item, it should not be there
80.625 - it.remove();
80.626 - retained = true;
80.627 - } else {
80.628 - // change the index
80.629 - if (item.getIndex() != n.index) {
80.630 - item.setIndex(null, n.index);
80.631 -
80.632 - // notify.addAll ((ArrayList)n.transaction);
80.633 - }
80.634 - }
80.635 - }
80.636 -
80.637 - if (retained && (notify != null)) {
80.638 - // type of this node has been changed
80.639 - notify.add(node.getType());
80.640 - }
80.641 - }
80.642 -
80.643 - if (node.children != null) {
80.644 - for (Iterator it = node.children.iterator();;) {
80.645 - Node ch = extractNode(it);
80.646 -
80.647 - if (ch == null) {
80.648 - break;
80.649 - }
80.650 -
80.651 - boolean result = retainAllClasses(ch, retain, notify);
80.652 -
80.653 - if (result) {
80.654 - // The children node was emptied and has no children -> remove it.
80.655 - it.remove();
80.656 - }
80.657 - }
80.658 - }
80.659 -
80.660 - return retained && node.items.isEmpty() && ((node.children == null) || node.children.isEmpty());
80.661 - }
80.662 -
80.663 - /** A method that creates enumeration of all items under given node.
80.664 - *
80.665 - * @param n node to create enumeration for
80.666 - * @return enumeration of Pairs
80.667 - */
80.668 - private static Enumeration<Pair> nodeToEnum(Node n) {
80.669 - if (n.children == null) {
80.670 - // create a simple enumeration because we do not have children
80.671 - Enumeration<Pair> e;
80.672 - if (n.items == null) {
80.673 - e = emptyEn();
80.674 - } else {
80.675 - e = Collections.enumeration(n.items);
80.676 - }
80.677 - return e;
80.678 - }
80.679 -
80.680 - // create enumeration of Items
80.681 - return new NeedsSortEnum(n);
80.682 - }
80.683 -
80.684 - //
80.685 - // Methods to work on interfaces
80.686 - //
80.687 -
80.688 - /** Registers an item with interfaces.
80.689 - * @param item item to register
80.690 - * @param affected list of classes that were affected
80.691 - * @return false if similar item has already been registered
80.692 - */
80.693 - @SuppressWarnings("unchecked")
80.694 - private boolean registerInterface(AbstractLookup.Pair<?> item, Collection<Class> affected) {
80.695 - if (interfaces == null) {
80.696 - return true;
80.697 - }
80.698 -
80.699 - Iterator<Map.Entry<Class,Object>> it = interfaces.entrySet().iterator();
80.700 -
80.701 - while (it.hasNext()) {
80.702 - Map.Entry<Class,Object> entry = it.next();
80.703 - Class<?> iface = entry.getKey();
80.704 -
80.705 - if (item.instanceOf(iface)) {
80.706 - Object value = entry.getValue();
80.707 -
80.708 - if (value instanceof Collection) {
80.709 - Collection<Object> set = (Collection<Object>) value;
80.710 -
80.711 - if (!set.add(item)) {
80.712 - // item is already there, probably (if everything is correct) is registered in
80.713 - // all other ifaces too, so stop additional testing
80.714 - return false;
80.715 - }
80.716 - } else {
80.717 - // there is just one pair right now
80.718 - if (value.equals(item)) {
80.719 - // item is there => stop processing (same as above)
80.720 - return false;
80.721 - }
80.722 -
80.723 - // otherwise replace the single item with ArrayList
80.724 - ArrayList<Object> ll = new ArrayList<Object>(3);
80.725 - ll.add(value);
80.726 - ll.add(item);
80.727 - entry.setValue(ll);
80.728 - }
80.729 -
80.730 - affected.add(iface);
80.731 - }
80.732 - }
80.733 -
80.734 - return true;
80.735 - }
80.736 -
80.737 - /** Removes interface.
80.738 - * @param item item to register
80.739 - * @param affected list of classes that were affected
80.740 - */
80.741 - @SuppressWarnings("unchecked")
80.742 - private void removeInterface(AbstractLookup.Pair item, Collection affected) {
80.743 - if (interfaces == null) {
80.744 - return;
80.745 - }
80.746 -
80.747 - Iterator it = interfaces.entrySet().iterator();
80.748 -
80.749 - while (it.hasNext()) {
80.750 - Map.Entry entry = (Map.Entry) it.next();
80.751 - Object value = entry.getValue();
80.752 -
80.753 - if (value instanceof Collection) {
80.754 - Collection set = (Collection) value;
80.755 -
80.756 - if (set.remove(item)) {
80.757 - if (set.size() == 1) {
80.758 - // if there is just one item remaining change to single item mode
80.759 - entry.setValue(set.iterator().next());
80.760 - }
80.761 -
80.762 - // adds the Class the item was register to into affected
80.763 - affected.add(entry.getKey());
80.764 - }
80.765 - } else {
80.766 - // single item value
80.767 - if (value.equals(item)) {
80.768 - // Emptied -> remove.
80.769 - it.remove();
80.770 -
80.771 - affected.add(entry.getKey());
80.772 - }
80.773 - }
80.774 - }
80.775 - }
80.776 -
80.777 - /** Retains some items.
80.778 - * @param retainItems items to retain and their mapping to index numbers
80.779 - * (AbstractLookup.Pair -> AbstractLookup.Info)
80.780 - * @param affected list of classes that were affected
80.781 - */
80.782 - @SuppressWarnings("unchecked")
80.783 - private void retainAllInterface(Map retainItems, Collection affected) {
80.784 - if (interfaces == null) {
80.785 - return;
80.786 - }
80.787 -
80.788 - Iterator it = interfaces.entrySet().iterator();
80.789 -
80.790 - while (it.hasNext()) {
80.791 - Map.Entry entry = (Map.Entry) it.next();
80.792 - Object value = entry.getValue();
80.793 -
80.794 - HashMap<?,?> retain = new HashMap(retainItems);
80.795 -
80.796 - Iterator elems;
80.797 - boolean multi = value instanceof Collection;
80.798 -
80.799 - if (multi) {
80.800 - // collection mode
80.801 - elems = ((Collection) value).iterator();
80.802 - } else {
80.803 - // single item mode
80.804 - elems = Collections.singleton(value).iterator();
80.805 - }
80.806 -
80.807 - boolean changed = false;
80.808 - boolean reordered = false;
80.809 -
80.810 - while (elems.hasNext()) {
80.811 - AbstractLookup.Pair p = (AbstractLookup.Pair) elems.next();
80.812 -
80.813 - AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(p);
80.814 -
80.815 - if (n == null) {
80.816 - if (multi) {
80.817 - // remove it
80.818 - elems.remove();
80.819 - }
80.820 -
80.821 - changed = true;
80.822 - } else {
80.823 - if (p.getIndex() != n.index) {
80.824 - // improve the index
80.825 - p.setIndex(null, n.index);
80.826 -
80.827 - // affected.addAll ((ArrayList)n.transaction);
80.828 - reordered = true;
80.829 - }
80.830 - }
80.831 - }
80.832 -
80.833 - if (reordered && value instanceof List) {
80.834 - // if reordered, than update the order in the collection
80.835 - List l = (List) value;
80.836 - Collections.sort(l, ALPairComparator.DEFAULT);
80.837 - }
80.838 -
80.839 - if (changed) {
80.840 - if (multi) {
80.841 - Collection c = (Collection) value;
80.842 -
80.843 - if (c.size() == 1) {
80.844 - // back to single item mode
80.845 - entry.setValue(c.iterator().next());
80.846 - }
80.847 - } else {
80.848 - // remove in single mode => remove completely
80.849 - it.remove();
80.850 - }
80.851 -
80.852 - // adds the Class the item was register to into affected
80.853 - affected.add(entry.getKey());
80.854 - }
80.855 - }
80.856 - }
80.857 -
80.858 - /** Searches for a clazz between interfaces.
80.859 - * @param clazz class to search for
80.860 - * @return enumeration of Items
80.861 - */
80.862 - @SuppressWarnings("unchecked")
80.863 - private Enumeration<Pair> searchInterface(final Class<?> clazz) {
80.864 - if (interfaces == null) {
80.865 - // first call for interface, only initialize
80.866 - interfaces = new WeakHashMap();
80.867 - }
80.868 -
80.869 - Object obj = interfaces.get(clazz);
80.870 -
80.871 - if (obj == null) {
80.872 - // set of items
80.873 - AbstractLookup.Pair one = null;
80.874 - ArrayList items = null;
80.875 -
80.876 - Enumeration en = lookup(Object.class);
80.877 -
80.878 - while (en.hasMoreElements()) {
80.879 - AbstractLookup.Pair it = (AbstractLookup.Pair) en.nextElement();
80.880 -
80.881 - if (it.instanceOf(clazz)) {
80.882 - // ok, this item implements given clazz
80.883 - if (one == null) {
80.884 - one = it;
80.885 - } else {
80.886 - if (items == null) {
80.887 - items = new ArrayList(3);
80.888 - items.add(one);
80.889 - }
80.890 -
80.891 - items.add(it);
80.892 - }
80.893 - }
80.894 - }
80.895 -
80.896 - if ((items == null) && (one != null)) {
80.897 - // single item mode
80.898 - interfaces.put(clazz, one);
80.899 -
80.900 - return singletonEn(one);
80.901 - } else {
80.902 - if (items == null) {
80.903 - items = new ArrayList(2);
80.904 - }
80.905 -
80.906 - interfaces.put(clazz, items);
80.907 -
80.908 - return Collections.enumeration(items);
80.909 - }
80.910 - } else {
80.911 - if (obj instanceof Collection) {
80.912 - return Collections.enumeration((Collection) obj);
80.913 - } else {
80.914 - // single item mode
80.915 - return singletonEn((Pair)obj);
80.916 - }
80.917 - }
80.918 - }
80.919 -
80.920 - /** Extracts a node from an iterator, returning null if no next element found
80.921 - */
80.922 - private static Node extractNode(Iterator it) {
80.923 - while (it.hasNext()) {
80.924 - Node n = (Node) it.next();
80.925 -
80.926 - if (n.get() == null) {
80.927 - it.remove();
80.928 - } else {
80.929 - return n;
80.930 - }
80.931 - }
80.932 -
80.933 - return null;
80.934 - }
80.935 -
80.936 - /** Prints debug info about the node.
80.937 - * @param n node to print
80.938 - * @param sp spaces to add
80.939 - * @param out where
80.940 - * @param instances print also instances
80.941 - */
80.942 - private static void printNode(Node n, String sp, java.io.PrintStream out, boolean instances) {
80.943 - int i;
80.944 - Iterator it;
80.945 -
80.946 - Class type = n.getType();
80.947 -
80.948 - out.print(sp);
80.949 - out.println("Node for: " + type + "\t" + ((type == null) ? null : type.getClassLoader())); // NOI18N
80.950 -
80.951 - if (n.items != null) {
80.952 - i = 0;
80.953 - it = new ArrayList<Pair>(n.items).iterator();
80.954 -
80.955 - while (it.hasNext()) {
80.956 - AbstractLookup.Pair p = (AbstractLookup.Pair) it.next();
80.957 - out.print(sp);
80.958 - out.print(" item (" + i++ + "): ");
80.959 - out.print(p); // NOI18N
80.960 - out.print(" id: " + Integer.toHexString(System.identityHashCode(p))); // NOI18N
80.961 - out.print(" index: "); // NOI18N
80.962 - out.print(p.getIndex());
80.963 -
80.964 - if (instances) {
80.965 - out.print(" I: " + p.getInstance());
80.966 - }
80.967 -
80.968 - out.println();
80.969 - }
80.970 - }
80.971 -
80.972 - if (n.children != null) {
80.973 - i = 0;
80.974 - it = n.children.iterator();
80.975 -
80.976 - while (it.hasNext()) {
80.977 - Node ch = (Node) it.next();
80.978 - printNode(ch, sp + " ", out, instances); // NOI18N
80.979 - }
80.980 - }
80.981 - }
80.982 -
80.983 - public ReferenceToResult registerReferenceToResult(ReferenceToResult<?> newRef) {
80.984 - if (reg == null) {
80.985 - reg = new HashMap<Class,ReferenceToResult>();
80.986 - }
80.987 -
80.988 - Class<? extends Object> clazz = newRef.template.getType();
80.989 -
80.990 - // initialize the data structures if not yet
80.991 - lookup(clazz);
80.992 -
80.993 - // newRef will be the new head of the list
80.994 - return reg.put(clazz, newRef);
80.995 - }
80.996 -
80.997 - public ReferenceToResult cleanUpResult(Lookup.Template templ) {
80.998 - collectListeners(null, templ.getType());
80.999 -
80.1000 - return (reg == null) ? null : reg.get(templ.getType());
80.1001 - }
80.1002 -
80.1003 - public ArrayList<Class> beginTransaction(int ensure) {
80.1004 - return new ArrayList<Class>();
80.1005 - }
80.1006 -
80.1007 - public void endTransaction(ArrayList<Class> list, Set<AbstractLookup.R> allAffectedResults) {
80.1008 - if (list.size() == 1) {
80.1009 - // probably the most common case
80.1010 - collectListeners(allAffectedResults, list.get(0));
80.1011 - } else {
80.1012 - Iterator it = list.iterator();
80.1013 -
80.1014 - while (it.hasNext()) {
80.1015 - collectListeners(allAffectedResults, (Class) it.next());
80.1016 - }
80.1017 - }
80.1018 - }
80.1019 -
80.1020 - /** Notifies all listeners that are interested in changes in this class.
80.1021 - * Should be called from synchronized places.
80.1022 - * @param allAffectedResults adds Results into this set
80.1023 - * @param c the class that has changed
80.1024 - */
80.1025 - private void collectListeners(Set<AbstractLookup.R> allAffectedResults, Class c) {
80.1026 - if (reg == null) {
80.1027 - return;
80.1028 - }
80.1029 -
80.1030 - while (c != null) {
80.1031 - ReferenceToResult first = reg.get(c);
80.1032 - ReferenceIterator it = new ReferenceIterator(first);
80.1033 -
80.1034 - while (it.next()) {
80.1035 - AbstractLookup.R result = it.current().getResult();
80.1036 -
80.1037 - if (allAffectedResults != null) {
80.1038 - // add result
80.1039 - allAffectedResults.add(result);
80.1040 - }
80.1041 - }
80.1042 -
80.1043 - if (first != it.first()) {
80.1044 - if (it.first() == null) {
80.1045 - // we do not need have more results on this object
80.1046 - reg.remove(c);
80.1047 - } else {
80.1048 - // move the head of the list
80.1049 - reg.put(c, it.first());
80.1050 - }
80.1051 - }
80.1052 -
80.1053 - c = c.getSuperclass();
80.1054 - }
80.1055 -
80.1056 - if (reg.isEmpty()) {
80.1057 - // clean up the list of all results if we do not need them anymore
80.1058 - reg = null;
80.1059 - }
80.1060 - }
80.1061 -
80.1062 - /** Node in the tree.
80.1063 - */
80.1064 - static final class Node extends WeakReference<Class> implements Serializable {
80.1065 - static final long serialVersionUID = 3L;
80.1066 -
80.1067 - /** children nodes */
80.1068 - public ArrayList<Node> children;
80.1069 -
80.1070 - /** list of items assigned to this node (suspect to be subclasses) */
80.1071 - public Collection<Pair> items;
80.1072 -
80.1073 - /** Constructor.
80.1074 - */
80.1075 - public Node(Class clazz) {
80.1076 - super(clazz);
80.1077 - }
80.1078 -
80.1079 - /** Returns true if the object was deserialized also clears the serialized flag.
80.1080 - * @return true if so.
80.1081 - */
80.1082 - public boolean deserialized() {
80.1083 - if ((items == null) || items instanceof LinkedHashSet) {
80.1084 - return false;
80.1085 - }
80.1086 -
80.1087 - if (items.isEmpty()) {
80.1088 - items = null;
80.1089 - } else {
80.1090 - items = new LinkedHashSet<Pair>(items);
80.1091 - }
80.1092 -
80.1093 - return true;
80.1094 - }
80.1095 -
80.1096 - /** Marks this item as being deserialized.
80.1097 - */
80.1098 - public void markDeserialized() {
80.1099 - if (items == null || items == Collections.EMPTY_LIST) {
80.1100 - items = Collections.emptyList();
80.1101 - } else {
80.1102 - items = Collections.synchronizedCollection(items);
80.1103 - }
80.1104 - }
80.1105 -
80.1106 - /** Getter for the type associated with this node.
80.1107 - */
80.1108 - public Class<?> getType() {
80.1109 - Class<?> c = get();
80.1110 -
80.1111 - // if garbage collected, then return a garbage
80.1112 - return (c == null) ? Void.TYPE : c;
80.1113 - }
80.1114 -
80.1115 - /** Checks whether a node can represent an class.
80.1116 - */
80.1117 - public boolean accepts(Class<?> clazz) {
80.1118 - if (getType() == Object.class) {
80.1119 - return true;
80.1120 - }
80.1121 -
80.1122 - return getType().isAssignableFrom(clazz);
80.1123 - }
80.1124 -
80.1125 - /** Checks whether item is instance of this node.
80.1126 - */
80.1127 - public boolean accepts(AbstractLookup.Pair<?> item) {
80.1128 - if (getType() == Object.class) {
80.1129 - // Object.class
80.1130 - return true;
80.1131 - }
80.1132 -
80.1133 - return item.instanceOf(getType());
80.1134 - }
80.1135 -
80.1136 - /** Assings an item to this node.
80.1137 - * @param item the item
80.1138 - * @return true if item has been added as new
80.1139 - */
80.1140 - public boolean assignItem(InheritanceTree tree, AbstractLookup.Pair<?> item) {
80.1141 - if ((items == null) || (items == Collections.EMPTY_LIST)) {
80.1142 - items = new LinkedHashSet<Pair>();
80.1143 - items.add(item);
80.1144 -
80.1145 - return true;
80.1146 - }
80.1147 -
80.1148 - if (items.contains(item)) {
80.1149 - Iterator<Pair> it = items.iterator();
80.1150 - Pair old;
80.1151 - for (;;) {
80.1152 - old = it.next();
80.1153 - if (item.equals(old)) {
80.1154 - break;
80.1155 - }
80.1156 - }
80.1157 -
80.1158 - if (old != item) {
80.1159 - // replace the items there
80.1160 - item.setIndex(tree, old.getIndex());
80.1161 - }
80.1162 -
80.1163 - it.remove();
80.1164 - items.add(item);
80.1165 -
80.1166 - return false;
80.1167 - }
80.1168 -
80.1169 - items.add(item);
80.1170 -
80.1171 - return true;
80.1172 - }
80.1173 -
80.1174 - private Object writeReplace() {
80.1175 - return new R(this);
80.1176 - }
80.1177 -
80.1178 - @Override
80.1179 - public String toString() {
80.1180 - return "Node for " + get();
80.1181 - }
80.1182 - }
80.1183 - // End of class Node.
80.1184 -
80.1185 - private static final class R implements Serializable {
80.1186 - static final long serialVersionUID = 1L;
80.1187 - private static ClassLoader l;
80.1188 - private String clazzName;
80.1189 - private transient Class<?> clazz;
80.1190 - private ArrayList<Node> children;
80.1191 - private Collection<Pair> items;
80.1192 -
80.1193 - public R(Node n) {
80.1194 - this.clazzName = n.getType().getName();
80.1195 - this.children = n.children;
80.1196 -
80.1197 - if (n.items instanceof LinkedHashSet || (n.items == null)) {
80.1198 - this.items = n.items;
80.1199 - } else {
80.1200 - this.items = new LinkedHashSet<Pair>(n.items);
80.1201 - }
80.1202 - }
80.1203 -
80.1204 - private void readObject(ObjectInputStream ois)
80.1205 - throws IOException, ClassNotFoundException {
80.1206 - ois.defaultReadObject();
80.1207 -
80.1208 - if (l == null) {
80.1209 - l = Lookup.getDefault().lookup(ClassLoader.class);
80.1210 - }
80.1211 -
80.1212 - clazz = Class.forName(clazzName, false, l);
80.1213 - }
80.1214 -
80.1215 - private Object readResolve() throws ObjectStreamException {
80.1216 - Node n = new Node(clazz);
80.1217 - n.children = children;
80.1218 - n.items = items;
80.1219 - n.markDeserialized();
80.1220 -
80.1221 - return n;
80.1222 - }
80.1223 - }
80.1224 - // end of R
80.1225 -
80.1226 - static Enumeration<Object> arrayEn(Object[] object) {
80.1227 - return Collections.enumeration(Arrays.asList(object));
80.1228 - }
80.1229 - static <T> Enumeration<T> singletonEn(T object) {
80.1230 - return Collections.enumeration(Collections.singleton(object));
80.1231 - }
80.1232 - static <T> Enumeration<T> emptyEn() {
80.1233 - return Collections.enumeration(Collections.<T>emptyList());
80.1234 - }
80.1235 -
80.1236 - /** Just a marker class to be able to do instanceof and find out
80.1237 - * that this enumeration is not sorted
80.1238 - */
80.1239 - private static final class NeedsSortEnum extends LinkedList<Node>
80.1240 - implements Enumeration<Pair> {
80.1241 - private Enumeration<Pair> en;
80.1242 -
80.1243 - public NeedsSortEnum(Node n) {
80.1244 - add(n);
80.1245 - }
80.1246 -
80.1247 - private boolean ensureNext() {
80.1248 - for (;;) {
80.1249 - if (en != null && en.hasMoreElements()) {
80.1250 - return true;
80.1251 - }
80.1252 - if (isEmpty()) {
80.1253 - return false;
80.1254 - }
80.1255 -
80.1256 - Node n2 = poll();
80.1257 - if (n2.children != null) {
80.1258 - addAll(n2.children);
80.1259 - }
80.1260 -
80.1261 - if (n2.items != null && !n2.items.isEmpty()) {
80.1262 - en = Collections.enumeration(n2.items);
80.1263 - }
80.1264 - }
80.1265 - }
80.1266 -
80.1267 - public boolean hasMoreElements() {
80.1268 - return ensureNext();
80.1269 - }
80.1270 -
80.1271 - public Pair nextElement() {
80.1272 - if (!ensureNext()) {
80.1273 - throw new NoSuchElementException();
80.1274 - }
80.1275 - return en.nextElement();
80.1276 - }
80.1277 - }
80.1278 - // end of NeedsSortEnum
80.1279 -}
81.1 --- a/openide.util/src/org/openide/util/lookup/InstanceContent.java Sat Oct 31 15:06:58 2009 +0100
81.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
81.3 @@ -1,378 +0,0 @@
81.4 -/*
81.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
81.6 - *
81.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
81.8 - *
81.9 - * The contents of this file are subject to the terms of either the GNU
81.10 - * General Public License Version 2 only ("GPL") or the Common
81.11 - * Development and Distribution License("CDDL") (collectively, the
81.12 - * "License"). You may not use this file except in compliance with the
81.13 - * License. You can obtain a copy of the License at
81.14 - * http://www.netbeans.org/cddl-gplv2.html
81.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
81.16 - * specific language governing permissions and limitations under the
81.17 - * License. When distributing the software, include this License Header
81.18 - * Notice in each file and include the License file at
81.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
81.20 - * particular file as subject to the "Classpath" exception as provided
81.21 - * by Sun in the GPL Version 2 section of the License file that
81.22 - * accompanied this code. If applicable, add the following below the
81.23 - * License Header, with the fields enclosed by brackets [] replaced by
81.24 - * your own identifying information:
81.25 - * "Portions Copyrighted [year] [name of copyright owner]"
81.26 - *
81.27 - * Contributor(s):
81.28 - *
81.29 - * The Original Software is NetBeans. The Initial Developer of the Original
81.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
81.31 - * Microsystems, Inc. All Rights Reserved.
81.32 - *
81.33 - * If you wish your version of this file to be governed by only the CDDL
81.34 - * or only the GPL Version 2, indicate your decision by adding
81.35 - * "[Contributor] elects to include this software in this distribution
81.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
81.37 - * single choice of license, a recipient has the option to distribute
81.38 - * your version of this file under either the CDDL, the GPL Version 2 or
81.39 - * to extend the choice of license to its licensees as provided above.
81.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
81.41 - * Version 2 license, then the option applies only if the new code is
81.42 - * made subject to such option by the copyright holder.
81.43 - */
81.44 -package org.openide.util.lookup;
81.45 -
81.46 -import org.openide.util.lookup.AbstractLookup.Pair;
81.47 -
81.48 -import java.lang.ref.WeakReference;
81.49 -
81.50 -import java.util.*;
81.51 -import java.util.concurrent.Executor;
81.52 -import org.openide.util.Lookup.Item;
81.53 -
81.54 -
81.55 -/** A special content implementation that can be passed to AbstractLookup
81.56 - * and provides methods for registration of instances and lazy instances.
81.57 - * <PRE>
81.58 - * InstanceContent ic = new InstanceContent ();
81.59 - * AbstractLookup al = new AbstractLookup (ic);
81.60 - *
81.61 - * ic.add (new Object ());
81.62 - * ic.add (new Dimension (...));
81.63 - *
81.64 - * Dimension theDim = (Dimension)al.lookup (Dimension.class);
81.65 - * </PRE>
81.66 - *
81.67 - * @author Jaroslav Tulach
81.68 - *
81.69 - * @since 1.25
81.70 - */
81.71 -public final class InstanceContent extends AbstractLookup.Content {
81.72 - /**
81.73 - * Create a new, empty content.
81.74 - */
81.75 - public InstanceContent() {
81.76 - }
81.77 -
81.78 - /** Creates a content associated with an executor to handle dispatch
81.79 - * of changes.
81.80 - * @param notifyIn the executor to notify changes in
81.81 - * @since 7.16
81.82 - */
81.83 - public InstanceContent(Executor notifyIn) {
81.84 - super(notifyIn);
81.85 - }
81.86 - /** The method to add instance to the lookup with.
81.87 - * @param inst instance
81.88 - */
81.89 - public final void add(Object inst) {
81.90 - addPair(new SimpleItem<Object>(inst));
81.91 - }
81.92 -
81.93 - /** Adds a convertible instance into the lookup. The <code>inst</code>
81.94 - * argument is just a key, not the actual value to appear in the lookup.
81.95 - * The value will be created on demand, later when it is really needed
81.96 - * by calling <code>convertor</code> methods.
81.97 - * <p>
81.98 - * This method is useful to delay creation of heavy weight objects.
81.99 - * Instead just register lightweight key and a convertor.
81.100 - * <p>
81.101 - * To remove registered object from lookup use {@link #remove(java.lang.Object, org.openide.util.lookup.InstanceContent.Convertor)}
81.102 - * with the same arguments.
81.103 - *
81.104 - * @param inst instance
81.105 - * @param conv convertor which postponing an instantiation,
81.106 - * if <code>conv==null</code> then the instance is registered directly.
81.107 - */
81.108 - public final <T,R> void add(T inst, Convertor<T,R> conv) {
81.109 - addPair(new ConvertingItem<T,R>(inst, conv));
81.110 - }
81.111 -
81.112 - /** Remove instance.
81.113 - * @param inst instance
81.114 - */
81.115 - public final void remove(Object inst) {
81.116 - removePair(new SimpleItem<Object>(inst));
81.117 - }
81.118 -
81.119 - /** Remove instance added with a convertor.
81.120 - * @param inst instance
81.121 - * @param conv convertor, if <code>conv==null</code> it is same like
81.122 - * remove(Object)
81.123 - */
81.124 - public final <T,R> void remove(T inst, Convertor<T,R> conv) {
81.125 - removePair(new ConvertingItem<T,R>(inst, conv));
81.126 - }
81.127 -
81.128 - /** Changes all pairs in the lookup to new values. Converts collection of
81.129 - * instances to collection of pairs.
81.130 - * @param col the collection of (Item) objects
81.131 - * @param conv the convertor to use or null
81.132 - */
81.133 - public final <T,R> void set(Collection<T> col, Convertor<T,R> conv) {
81.134 - ArrayList<Pair<?>> l = new ArrayList<Pair<?>>(col.size());
81.135 - Iterator<T> it = col.iterator();
81.136 -
81.137 - if (conv == null) {
81.138 - while (it.hasNext()) {
81.139 - l.add(new SimpleItem<T>(it.next()));
81.140 - }
81.141 - } else {
81.142 - while (it.hasNext()) {
81.143 - l.add(new ConvertingItem<T,R>(it.next(), conv));
81.144 - }
81.145 - }
81.146 -
81.147 - setPairs(l);
81.148 - }
81.149 -
81.150 - /** Convertor postpones an instantiation of an object.
81.151 - * @since 1.25
81.152 - */
81.153 - public static interface Convertor<T,R> {
81.154 - /** Convert obj to other object. There is no need to implement
81.155 - * cache mechanism. It is provided by
81.156 - * {@link Item#getInstance()} method itself. However the
81.157 - * method can be called more than once because instance is held
81.158 - * just by weak reference.
81.159 - *
81.160 - * @param obj the registered object
81.161 - * @return the object converted from this object
81.162 - */
81.163 - public R convert(T obj);
81.164 -
81.165 - /** Return type of converted object. Accessible via
81.166 - * {@link Item#getType()}
81.167 - * @param obj the registered object
81.168 - * @return the class that will be produced from this object (class or
81.169 - * superclass of convert (obj))
81.170 - */
81.171 - public Class<? extends R> type(T obj);
81.172 -
81.173 - /** Computes the ID of the resulted object. Accessible via
81.174 - * {@link Item#getId()}.
81.175 - * @param obj the registered object
81.176 - * @return the ID for the object
81.177 - */
81.178 - public String id(T obj);
81.179 -
81.180 - /** The human presentable name for the object. Accessible via
81.181 - * {@link Item#getDisplayName()}.
81.182 - * @param obj the registered object
81.183 - * @return the name representing the object for the user
81.184 - */
81.185 - public String displayName(T obj);
81.186 - }
81.187 -
81.188 - /** Instance of one item representing an object.
81.189 - */
81.190 - final static class SimpleItem<T> extends Pair<T> {
81.191 - private T obj;
81.192 -
81.193 - /** Create an item.
81.194 - * @obj object to register
81.195 - */
81.196 - public SimpleItem(T obj) {
81.197 - if (obj == null) {
81.198 - throw new NullPointerException();
81.199 - }
81.200 - this.obj = obj;
81.201 - }
81.202 -
81.203 - /** Tests whether this item can produce object
81.204 - * of class c.
81.205 - */
81.206 - public boolean instanceOf(Class<?> c) {
81.207 - return c.isInstance(obj);
81.208 - }
81.209 -
81.210 - /** Get instance of registered object. If convertor is specified then
81.211 - * method InstanceLookup.Convertor.convertor is used and weak reference
81.212 - * to converted object is saved.
81.213 - * @return the instance of the object.
81.214 - */
81.215 - public T getInstance() {
81.216 - return obj;
81.217 - }
81.218 -
81.219 - @Override
81.220 - public boolean equals(Object o) {
81.221 - if (o instanceof SimpleItem) {
81.222 - return obj.equals(((SimpleItem) o).obj);
81.223 - } else {
81.224 - return false;
81.225 - }
81.226 - }
81.227 -
81.228 - @Override
81.229 - public int hashCode() {
81.230 - return obj.hashCode();
81.231 - }
81.232 -
81.233 - /** An identity of the item.
81.234 - * @return string representing the item, that can be used for
81.235 - * persistance purposes to locate the same item next time
81.236 - */
81.237 - public String getId() {
81.238 - return "IL[" + obj.toString(); // NOI18N
81.239 - }
81.240 -
81.241 - /** Getter for display name of the item.
81.242 - */
81.243 - public String getDisplayName() {
81.244 - return obj.toString();
81.245 - }
81.246 -
81.247 - /** Method that can test whether an instance of a class has been created
81.248 - * by this item.
81.249 - *
81.250 - * @param obj the instance
81.251 - * @return if the item has already create an instance and it is the same
81.252 - * as obj.
81.253 - */
81.254 - protected boolean creatorOf(Object obj) {
81.255 - return obj == this.obj;
81.256 - }
81.257 -
81.258 - /** The class of this item.
81.259 - * @return the correct class
81.260 - */
81.261 - @SuppressWarnings("unchecked")
81.262 - public Class<? extends T> getType() {
81.263 - return (Class<? extends T>)obj.getClass();
81.264 - }
81.265 - }
81.266 - // end of SimpleItem
81.267 -
81.268 - /** Instance of one item registered in the map.
81.269 - */
81.270 - final static class ConvertingItem<T,R> extends Pair<R> {
81.271 - /** registered object */
81.272 - private T obj;
81.273 -
81.274 - /** Reference to converted object. */
81.275 - private WeakReference<R> ref;
81.276 -
81.277 - /** convertor to use */
81.278 - private Convertor<? super T,R> conv;
81.279 -
81.280 - /** Create an item.
81.281 - * @obj object to register
81.282 - * @conv a convertor, can be <code>null</code>.
81.283 - */
81.284 - public ConvertingItem(T obj, Convertor<? super T,R> conv) {
81.285 - this.obj = obj;
81.286 - this.conv = conv;
81.287 - }
81.288 -
81.289 - /** Tests whether this item can produce object
81.290 - * of class c.
81.291 - */
81.292 - public boolean instanceOf(Class<?> c) {
81.293 - return c.isAssignableFrom(getType());
81.294 - }
81.295 -
81.296 - /** Returns converted object or null if obj has not been converted yet
81.297 - * or reference was cleared by garbage collector.
81.298 - */
81.299 - private R getConverted() {
81.300 - if (ref == null) {
81.301 - return null;
81.302 - }
81.303 -
81.304 - return ref.get();
81.305 - }
81.306 -
81.307 - /** Get instance of registered object. If convertor is specified then
81.308 - * method InstanceLookup.Convertor.convertor is used and weak reference
81.309 - * to converted object is saved.
81.310 - * @return the instance of the object.
81.311 - */
81.312 - public synchronized R getInstance() {
81.313 - R converted = getConverted();
81.314 -
81.315 - if (converted == null) {
81.316 - converted = conv.convert(obj);
81.317 - ref = new WeakReference<R>(converted);
81.318 - }
81.319 -
81.320 - return converted;
81.321 - }
81.322 -
81.323 - @Override
81.324 - public boolean equals(Object o) {
81.325 - if (o instanceof ConvertingItem) {
81.326 - return obj.equals(((ConvertingItem) o).obj);
81.327 - } else {
81.328 - return false;
81.329 - }
81.330 - }
81.331 -
81.332 - @Override
81.333 - public int hashCode() {
81.334 - return obj.hashCode();
81.335 - }
81.336 -
81.337 - /** An identity of the item.
81.338 - * @return string representing the item, that can be used for
81.339 - * persistance purposes to locate the same item next time
81.340 - */
81.341 - public String getId() {
81.342 - return conv.id(obj);
81.343 - }
81.344 -
81.345 - /** Getter for display name of the item.
81.346 - */
81.347 - public String getDisplayName() {
81.348 - return conv.displayName(obj);
81.349 - }
81.350 -
81.351 - /** Method that can test whether an instance of a class has been created
81.352 - * by this item.
81.353 - *
81.354 - * @param obj the instance
81.355 - * @return if the item has already create an instance and it is the same
81.356 - * as obj.
81.357 - */
81.358 - protected boolean creatorOf(Object obj) {
81.359 - if (conv == null) {
81.360 - return obj == this.obj;
81.361 - } else {
81.362 - return obj == getConverted();
81.363 - }
81.364 - }
81.365 -
81.366 - /** The class of this item.
81.367 - * @return the correct class
81.368 - */
81.369 - @SuppressWarnings("unchecked")
81.370 - public Class<? extends R> getType() {
81.371 - R converted = getConverted();
81.372 -
81.373 - if (converted == null) {
81.374 - return conv.type(obj);
81.375 - }
81.376 -
81.377 - return (Class<? extends R>)converted.getClass();
81.378 - }
81.379 - }
81.380 - // end of ConvertingItem
81.381 -}
82.1 --- a/openide.util/src/org/openide/util/lookup/Lookups.java Sat Oct 31 15:06:58 2009 +0100
82.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
82.3 @@ -1,317 +0,0 @@
82.4 -/*
82.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
82.6 - *
82.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
82.8 - *
82.9 - * The contents of this file are subject to the terms of either the GNU
82.10 - * General Public License Version 2 only ("GPL") or the Common
82.11 - * Development and Distribution License("CDDL") (collectively, the
82.12 - * "License"). You may not use this file except in compliance with the
82.13 - * License. You can obtain a copy of the License at
82.14 - * http://www.netbeans.org/cddl-gplv2.html
82.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
82.16 - * specific language governing permissions and limitations under the
82.17 - * License. When distributing the software, include this License Header
82.18 - * Notice in each file and include the License file at
82.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
82.20 - * particular file as subject to the "Classpath" exception as provided
82.21 - * by Sun in the GPL Version 2 section of the License file that
82.22 - * accompanied this code. If applicable, add the following below the
82.23 - * License Header, with the fields enclosed by brackets [] replaced by
82.24 - * your own identifying information:
82.25 - * "Portions Copyrighted [year] [name of copyright owner]"
82.26 - *
82.27 - * Contributor(s):
82.28 - *
82.29 - * The Original Software is NetBeans. The Initial Developer of the Original
82.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
82.31 - * Microsystems, Inc. All Rights Reserved.
82.32 - *
82.33 - * If you wish your version of this file to be governed by only the CDDL
82.34 - * or only the GPL Version 2, indicate your decision by adding
82.35 - * "[Contributor] elects to include this software in this distribution
82.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
82.37 - * single choice of license, a recipient has the option to distribute
82.38 - * your version of this file under either the CDDL, the GPL Version 2 or
82.39 - * to extend the choice of license to its licensees as provided above.
82.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
82.41 - * Version 2 license, then the option applies only if the new code is
82.42 - * made subject to such option by the copyright holder.
82.43 - */
82.44 -
82.45 -package org.openide.util.lookup;
82.46 -
82.47 -import java.util.Arrays;
82.48 -import org.netbeans.modules.openide.util.NamedServicesProvider;
82.49 -import org.openide.util.Lookup;
82.50 -
82.51 -/**
82.52 - * Static factory methods for creating common lookup implementations.
82.53 - *
82.54 - * @author David Strupl
82.55 - * @since 2.21
82.56 - */
82.57 -public class Lookups {
82.58 -
82.59 - /** static methods only */
82.60 - private Lookups() {}
82.61 -
82.62 - /**
82.63 - * Creates a singleton lookup. It means lookup that contains only
82.64 - * one object specified via the supplied parameter. The lookup will
82.65 - * either return the object or null if the supplied template does
82.66 - * not match the class. If the specified argument is null the method
82.67 - * will end with NullPointerException.
82.68 - * @return Fully initialized lookup object ready to use
82.69 - * @throws NullPointerException if the supplied argument is null
82.70 - * @since 2.21
82.71 - */
82.72 - public static Lookup singleton(Object objectToLookup) {
82.73 - if (objectToLookup == null) {
82.74 - throw new NullPointerException();
82.75 - }
82.76 -
82.77 - return new SingletonLookup(objectToLookup);
82.78 - }
82.79 -
82.80 - /**
82.81 - * Creates a lookup that contains an array of objects specified via the
82.82 - * parameter. The resulting lookup is fixed in the following sense: it
82.83 - * contains only fixed set of objects passed in by the array parameter.
82.84 - * Its contents never changes so registering listeners on such lookup
82.85 - * does not have any observable effect (the listeners are never called).
82.86 - *
82.87 - * @param objectsToLookup list of objects to include
82.88 - * @return Fully initialized lookup object ready to use
82.89 - * @throws NullPointerException if the supplied argument is null
82.90 - * @since 2.21
82.91 - *
82.92 - */
82.93 - public static Lookup fixed(Object... objectsToLookup) {
82.94 - if (objectsToLookup == null) {
82.95 - throw new NullPointerException();
82.96 - }
82.97 -
82.98 - if (objectsToLookup.length == 0) {
82.99 - return Lookup.EMPTY;
82.100 - }
82.101 -
82.102 - if (objectsToLookup.length == 1) {
82.103 - return singleton(objectsToLookup[0]);
82.104 - }
82.105 -
82.106 - return new SimpleLookup(Arrays.asList(objectsToLookup));
82.107 - }
82.108 -
82.109 - /**
82.110 - * Creates a lookup that contains an array of objects specified via the
82.111 - * parameter. The resulting lookup is fixed in the following sense: it
82.112 - * contains only fixed set of objects passed in by the array parameter.
82.113 - * The objects returned from this lookup are converted to real objects
82.114 - * before they are returned by the lookup.
82.115 - * Its contents never changes so registering listeners on such lookup
82.116 - * does not have any observable effect (the listeners are never called).
82.117 - *
82.118 - * @return Fully initialized lookup object ready to use
82.119 - * @throws NullPointerException if the any of the arguments is null
82.120 - * @since 2.21
82.121 - *
82.122 - */
82.123 - public static <T,R> Lookup fixed(T[] keys, InstanceContent.Convertor<? super T,R> convertor) {
82.124 - if (keys == null) {
82.125 - throw new NullPointerException();
82.126 - }
82.127 -
82.128 - if (convertor == null) {
82.129 - throw new NullPointerException();
82.130 - }
82.131 -
82.132 - return new SimpleLookup(Arrays.asList(keys), convertor);
82.133 - }
82.134 -
82.135 - /** Creates a lookup that delegates to another one but that one can change
82.136 - * from time to time. The returned lookup checks every time somebody calls
82.137 - * <code>lookup</code> or <code>lookupItem</code> method whether the
82.138 - * provider still returns the same lookup. If not, it updates state of
82.139 - * all {@link org.openide.util.Lookup.Result}s
82.140 - * that it created (and that still exists).
82.141 - * <P>
82.142 - * The user of this method has to implement its provider's <code>getLookup</code>
82.143 - * method (must be thread safe and fast, will be called often and from any thread)
82.144 - * pass it to this method and use the returned lookup. Whenever the user
82.145 - * changes the return value from the <code>getLookup</code> method and wants
82.146 - * to notify listeners on the lookup about that it should trigger the event
82.147 - * firing, for example by calling <code>lookup.lookup (Object.class)</code>
82.148 - * directly on the lookup returned by this method
82.149 - * that forces a check of the return value of {@link org.openide.util.Lookup.Provider#getLookup}</code>.
82.150 - *
82.151 - * @param provider the provider that returns a lookup to delegate to
82.152 - * @return lookup delegating to the lookup returned by the provider
82.153 - * @since 3.9
82.154 - */
82.155 - public static Lookup proxy(Lookup.Provider provider) {
82.156 - return new SimpleProxyLookup(provider);
82.157 - }
82.158 -
82.159 - /** Returns a lookup that implements the JDK1.3 JAR services mechanism and delegates
82.160 - * to META-INF/services/name.of.class files.
82.161 - * <p>Some extensions to the JAR services specification are implemented:
82.162 - * <ol>
82.163 - * <li>An entry may be followed by a line of the form <code>#position=<i>integer</i></code>
82.164 - * to specify ordering. (Smaller numbers first, entries with unspecified position last.)
82.165 - * <li>A line of the form <code>#-<i>classname</i></code> suppresses an entry registered
82.166 - * in another file, so can be used to supersede one implementation with another.
82.167 - * </ol>
82.168 - * <p>Note: It is not dynamic - so if you need to change the classloader or JARs,
82.169 - * wrap it in a {@link ProxyLookup} and change the delegate when necessary.
82.170 - * Existing instances will be kept if the implementation classes are unchanged,
82.171 - * so there is "stability" in doing this provided some parent loaders are the same
82.172 - * as the previous ones.
82.173 - * @since 3.35
82.174 - * @see ServiceProvider
82.175 - */
82.176 - public static Lookup metaInfServices(ClassLoader classLoader) {
82.177 - return new MetaInfServicesLookup(classLoader, "META-INF/services/"); // NOI18N
82.178 - }
82.179 -
82.180 - /** Returns a lookup that behaves exactly like {@link #metaInfServices(ClassLoader)}
82.181 - * except that it does not read data from <code>META-INF/services/</code>, but instead
82.182 - * from the specified prefix.
82.183 - * @param classLoader class loader to use for loading
82.184 - * @param prefix prefix to prepend to the class name when searching
82.185 - * @since 7.9
82.186 - */
82.187 - public static Lookup metaInfServices(ClassLoader classLoader, String prefix) {
82.188 - return new MetaInfServicesLookup(classLoader, prefix);
82.189 - }
82.190 -
82.191 - /** Creates a <q>named</q> lookup.
82.192 - * It is a lookup identified by a given path.
82.193 - * Two lookups with the same path should have the same content.
82.194 - * <p>It is expected that each <q>named</q> lookup
82.195 - * will contain a superset of what would be created by:
82.196 - * <code>{@linkplain #metaInfServices(ClassLoader,String) metaInfServices}(theRightLoader, "META-INF/namedservices/" + path + "/")</code>
82.197 - *
82.198 - * <p class="nonnormative">Various environments can add their own
82.199 - * extensions to its content. As such
82.200 - * {@link Lookups#forPath(java.lang.String)} can combine lookups
82.201 - * from several sources. In current NetBeans Runtime Container, two lookups are used:
82.202 - * </p>
82.203 - * <ul class="nonnormative">
82.204 - * <li><code>Lookups.metaInfServices("META-INF/namedservices/" + path)</code></li>
82.205 - * <li><code>org.openide.loaders.FolderLookup(path)</code></li>
82.206 - * </ul>
82.207 - * <p class="nonnormative">
82.208 - * Please note that these lookups differ in the way they inspect sub-folders.
82.209 - * The first lookup just returns instances from the given path, ignoring
82.210 - * sub-folders, the second one retrieves instances from the whole sub-tree.
82.211 - * </p>
82.212 - * <p>
82.213 - * Read more about the <a href="../doc-files/api.html#folderlookup">usage of this method</a>.
82.214 - *
82.215 - * @param path the path identifying the lookup, e.g. <code>Projects/Actions</code>
82.216 - * @return lookup associated with this path
82.217 - * @since 7.9
82.218 - */
82.219 - public static Lookup forPath(String path) {
82.220 - return NamedServicesProvider.find(path);
82.221 - }
82.222 -
82.223 - /** Creates a lookup that wraps another one and filters out instances
82.224 - * of specified classes. If you have a lookup and
82.225 - * you want to remove all instances of ActionMap you can use:
82.226 - * <pre>
82.227 - * l = Lookups.exclude(lookup, ActionMap.class);
82.228 - * </pre>
82.229 - * Then anybody who asks for <code>l.lookup(ActionMap.class)</code> or
82.230 - * subclass will get <code>null</code>. Even if the original lookup contains the
82.231 - * value.
82.232 - * To create empty lookup (well, just an example, otherwise use {@link Lookup#EMPTY}) one could use:
82.233 - * <pre>
82.234 - * Lookup.exclude(anyLookup, Object.class);
82.235 - * </pre>
82.236 - * as any instance in any lookup is of type Object and thus would be excluded.
82.237 - * <p>
82.238 - * The complete behavior can be described as <code>classes</code> being
82.239 - * a barrier. For an object not to be excluded, there has to be an inheritance
82.240 - * path between the queried class and the actual class of the instance,
82.241 - * that is not blocked by any of the excluded classes:
82.242 - * <pre>
82.243 - * interface A {}
82.244 - * interface B {}
82.245 - * class C implements A, B {}
82.246 - * Object c = new C();
82.247 - * Lookup l1 = Lookups.singleton(c);
82.248 - * Lookup l2 = Lookups.exclude(l1, A.class);
82.249 - * assertNull("A is directly excluded", l2.lookup(A.class));
82.250 - * assertEquals("Returns C as A.class is not between B and C", c, l2.lookup(B.class));
82.251 - * </pre>
82.252 - * For more info check the
82.253 - * <a href="http://hg.netbeans.org/main-golden/annotate/4883eaeda744/openide.util/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java">
82.254 - * excluding lookup tests</a> and the discussion in issue
82.255 - * <a href="http://openide.netbeans.org/issues/show_bug.cgi?id=53058">53058</a>.
82.256 - *
82.257 - * @param lookup the original lookup that should be filtered
82.258 - * @param classes array of classes those instances should be excluded
82.259 - * @since 5.4
82.260 - */
82.261 - public static Lookup exclude(Lookup lookup, Class... classes) {
82.262 - return new ExcludingLookup(lookup, classes);
82.263 - }
82.264 -
82.265 - /** Creates <code>Lookup.Item</code> representing the instance passed in.
82.266 - *
82.267 - * @param instance the object for which Lookup.Item should be creted
82.268 - * @param id unique identification of the object, for details see {@link org.openide.util.Lookup.Item#getId},
82.269 - * can be <code>null</code>
82.270 - * @return lookup item representing instance
82.271 - * @since 4.8
82.272 - */
82.273 - public static <T> Lookup.Item<T> lookupItem(T instance, String id) {
82.274 - return new LookupItem<T>(instance, id);
82.275 - }
82.276 -
82.277 - private static class LookupItem<T> extends Lookup.Item<T> {
82.278 - private String id;
82.279 - private T instance;
82.280 -
82.281 - public LookupItem(T instance) {
82.282 - this(instance, null);
82.283 - }
82.284 -
82.285 - public LookupItem(T instance, String id) {
82.286 - this.id = id;
82.287 - this.instance = instance;
82.288 - }
82.289 -
82.290 - public String getDisplayName() {
82.291 - return getId();
82.292 - }
82.293 -
82.294 - public String getId() {
82.295 - return (id == null) ? instance.toString() : id;
82.296 - }
82.297 -
82.298 - public T getInstance() {
82.299 - return instance;
82.300 - }
82.301 -
82.302 - @SuppressWarnings("unchecked")
82.303 - public Class<? extends T> getType() {
82.304 - return (Class<? extends T>)instance.getClass();
82.305 - }
82.306 -
82.307 - public @Override boolean equals(Object object) {
82.308 - if (object instanceof LookupItem) {
82.309 - return instance == ((LookupItem) object).getInstance();
82.310 - }
82.311 -
82.312 - return false;
82.313 - }
82.314 -
82.315 - public @Override int hashCode() {
82.316 - return instance.hashCode();
82.317 - }
82.318 - }
82.319 - // End of LookupItem class
82.320 -}
83.1 --- a/openide.util/src/org/openide/util/lookup/MetaInfServicesLookup.java Sat Oct 31 15:06:58 2009 +0100
83.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
83.3 @@ -1,560 +0,0 @@
83.4 -/*
83.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
83.6 - *
83.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
83.8 - *
83.9 - * The contents of this file are subject to the terms of either the GNU
83.10 - * General Public License Version 2 only ("GPL") or the Common
83.11 - * Development and Distribution License("CDDL") (collectively, the
83.12 - * "License"). You may not use this file except in compliance with the
83.13 - * License. You can obtain a copy of the License at
83.14 - * http://www.netbeans.org/cddl-gplv2.html
83.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
83.16 - * specific language governing permissions and limitations under the
83.17 - * License. When distributing the software, include this License Header
83.18 - * Notice in each file and include the License file at
83.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
83.20 - * particular file as subject to the "Classpath" exception as provided
83.21 - * by Sun in the GPL Version 2 section of the License file that
83.22 - * accompanied this code. If applicable, add the following below the
83.23 - * License Header, with the fields enclosed by brackets [] replaced by
83.24 - * your own identifying information:
83.25 - * "Portions Copyrighted [year] [name of copyright owner]"
83.26 - *
83.27 - * Contributor(s):
83.28 - *
83.29 - * The Original Software is NetBeans. The Initial Developer of the Original
83.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
83.31 - * Microsystems, Inc. All Rights Reserved.
83.32 - *
83.33 - * If you wish your version of this file to be governed by only the CDDL
83.34 - * or only the GPL Version 2, indicate your decision by adding
83.35 - * "[Contributor] elects to include this software in this distribution
83.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
83.37 - * single choice of license, a recipient has the option to distribute
83.38 - * your version of this file under either the CDDL, the GPL Version 2 or
83.39 - * to extend the choice of license to its licensees as provided above.
83.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
83.41 - * Version 2 license, then the option applies only if the new code is
83.42 - * made subject to such option by the copyright holder.
83.43 - */
83.44 -
83.45 -package org.openide.util.lookup;
83.46 -
83.47 -import java.io.BufferedReader;
83.48 -import java.io.IOException;
83.49 -import java.io.InputStream;
83.50 -import java.io.InputStreamReader;
83.51 -import java.lang.ref.Reference;
83.52 -import java.lang.ref.WeakReference;
83.53 -import java.lang.reflect.Method;
83.54 -import java.net.URL;
83.55 -import java.util.ArrayList;
83.56 -import java.util.Collection;
83.57 -import java.util.Enumeration;
83.58 -import java.util.HashSet;
83.59 -import java.util.LinkedHashSet;
83.60 -import java.util.List;
83.61 -import java.util.Map;
83.62 -import java.util.WeakHashMap;
83.63 -import java.util.concurrent.Executor;
83.64 -import java.util.logging.Level;
83.65 -import java.util.logging.Logger;
83.66 -import org.openide.util.Lookup;
83.67 -import org.openide.util.RequestProcessor;
83.68 -
83.69 -/**
83.70 - * @author Jaroslav Tulach, Jesse Glick
83.71 - * @see Lookups#metaInfServices(ClassLoader,String)
83.72 - * @see "#14722"
83.73 - */
83.74 -final class MetaInfServicesLookup extends AbstractLookup {
83.75 -
83.76 - private static final Logger LOGGER = Logger.getLogger(MetaInfServicesLookup.class.getName());
83.77 - static final Executor RP = new RequestProcessor(MetaInfServicesLookup.class.getName(), 1);
83.78 - private static int knownInstancesCount;
83.79 - private static final List<Reference<Object>> knownInstances;
83.80 - static {
83.81 - knownInstances = new ArrayList<Reference<Object>>();
83.82 - for (int i = 0; i < 512; i++) {
83.83 - knownInstances.add(null);
83.84 - }
83.85 - }
83.86 -
83.87 - /** A set of all requested classes.
83.88 - * Note that classes that we actually succeeded on can never be removed
83.89 - * from here because we hold a strong reference to the loader.
83.90 - * However we also hold classes which are definitely not loadable by
83.91 - * our loader.
83.92 - */
83.93 - private final Map<Class,Object> classes = new WeakHashMap<Class,Object>();
83.94 -
83.95 - /** class loader to use */
83.96 - private final ClassLoader loader;
83.97 - /** prefix to prepend */
83.98 - private final String prefix;
83.99 -
83.100 - /** Create a lookup reading from a specified classloader.
83.101 - */
83.102 - public MetaInfServicesLookup(ClassLoader loader, String prefix) {
83.103 - this.loader = loader;
83.104 - this.prefix = prefix;
83.105 -
83.106 - LOGGER.log(Level.FINE, "Created: {0}", this);
83.107 - }
83.108 -
83.109 - @Override
83.110 - public String toString() {
83.111 - return "MetaInfServicesLookup[" + loader + "]"; // NOI18N
83.112 - }
83.113 -
83.114 - /* Tries to load appropriate resources from manifest files.
83.115 - */
83.116 - @Override
83.117 - protected final void beforeLookup(Lookup.Template t) {
83.118 - Class c = t.getType();
83.119 -
83.120 - Collection<AbstractLookup.Pair<?>> toAdd = null;
83.121 - synchronized (this) {
83.122 - if (classes.get(c) == null) { // NOI18N
83.123 - toAdd = new ArrayList<Pair<?>>();
83.124 - } else {
83.125 - // ok, nothing needs to be done
83.126 - return;
83.127 - }
83.128 - }
83.129 - if (toAdd != null) {
83.130 - search(c, toAdd);
83.131 - }
83.132 - synchronized (this) {
83.133 - if (classes.put(c, "") == null) { // NOI18N
83.134 - // Added new class, search for it.
83.135 - LinkedHashSet<AbstractLookup.Pair<?>> arr = getPairsAsLHS();
83.136 - arr.addAll(toAdd);
83.137 - setPairs(arr, RP);
83.138 - }
83.139 - }
83.140 - }
83.141 -
83.142 - /** Finds all pairs and adds them to the collection.
83.143 - *
83.144 - * @param clazz class to find
83.145 - * @param result collection to add Pair to
83.146 - */
83.147 - private void search(Class<?> clazz, Collection<AbstractLookup.Pair<?>> result) {
83.148 - if (LOGGER.isLoggable(Level.FINER)) {
83.149 - LOGGER.log(Level.FINER, "Searching for " + clazz.getName() + " in " + clazz.getClassLoader() + " from " + this);
83.150 - }
83.151 -
83.152 - String res = prefix + clazz.getName(); // NOI18N
83.153 - Enumeration<URL> en;
83.154 -
83.155 - try {
83.156 - en = loader.getResources(res);
83.157 - } catch (IOException ioe) {
83.158 - // do not use ErrorManager because we are in the startup code
83.159 - // and ErrorManager might not be ready
83.160 - ioe.printStackTrace();
83.161 -
83.162 - return;
83.163 - }
83.164 -
83.165 - // Do not create multiple instances in case more than one JAR
83.166 - // has the same entry in it (and they load to the same class).
83.167 - // Probably would not happen, assuming JARs only list classes
83.168 - // they own, but just in case...
83.169 - List<Item> foundClasses = new ArrayList<Item>();
83.170 - Collection<Class> removeClasses = new ArrayList<Class>();
83.171 -
83.172 - boolean foundOne = false;
83.173 -
83.174 - while (en.hasMoreElements()) {
83.175 - if (!foundOne) {
83.176 - foundOne = true;
83.177 -
83.178 - // Double-check that in fact we can load the *interface* class.
83.179 - // For example, say class I is defined in two JARs, J1 and J2.
83.180 - // There is also an implementation M1 defined in J1, and another
83.181 - // implementation M2 defined in J2.
83.182 - // Classloaders C1 and C2 are made from J1 and J2.
83.183 - // A MetaInfServicesLookup is made from C1. Then the user asks to
83.184 - // lookup I as loaded from C2. J1 has the services line and lists
83.185 - // M1, and we can in fact make it. However it is not of the desired
83.186 - // type to be looked up. Don't do this check, which could be expensive,
83.187 - // unless we expect to be getting some results, however.
83.188 - Class realMcCoy = null;
83.189 -
83.190 - try {
83.191 - realMcCoy = loader.loadClass(clazz.getName());
83.192 - } catch (ClassNotFoundException cnfe) {
83.193 - // our loader does not know about it, OK
83.194 - }
83.195 -
83.196 - if (realMcCoy != clazz) {
83.197 - // Either the interface class is not available at all in our loader,
83.198 - // or it is not the same version as we expected. Don't provide results.
83.199 - if (LOGGER.isLoggable(Level.WARNING)) {
83.200 - if (realMcCoy != null) {
83.201 - LOGGER.log(Level.WARNING,
83.202 - clazz.getName() + " is not the real McCoy! Actually found it in " +
83.203 - realMcCoy.getClassLoader()
83.204 - ); // NOI18N
83.205 - } else {
83.206 - LOGGER.log(Level.WARNING, clazz.getName() + " could not be found in " + loader); // NOI18N
83.207 - }
83.208 - }
83.209 -
83.210 - return;
83.211 - }
83.212 - }
83.213 -
83.214 - URL url = en.nextElement();
83.215 - Item currentItem = null;
83.216 -
83.217 - try {
83.218 - InputStream is = url.openStream();
83.219 -
83.220 - try {
83.221 - BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // NOI18N
83.222 -
83.223 - while (true) {
83.224 - String line = reader.readLine();
83.225 -
83.226 - if (line == null) {
83.227 - break;
83.228 - }
83.229 -
83.230 - line = line.trim();
83.231 -
83.232 - // is it position attribute?
83.233 - if (line.startsWith("#position=")) {
83.234 - if (currentItem == null) {
83.235 - LOGGER.log(Level.WARNING, "Found line '{0}' in {1} but there is no item to associate it with", new Object[] {line, url});
83.236 - continue;
83.237 - }
83.238 -
83.239 - try {
83.240 - currentItem.position = Integer.parseInt(line.substring(10));
83.241 - } catch (NumberFormatException e) {
83.242 - // do not use ErrorManager because we are in the startup code
83.243 - // and ErrorManager might not be ready
83.244 - e.printStackTrace();
83.245 - }
83.246 - }
83.247 -
83.248 - if (currentItem != null) {
83.249 - insertItem(currentItem, foundClasses);
83.250 - currentItem = null;
83.251 - }
83.252 -
83.253 - // Ignore blank lines and comments.
83.254 - if (line.length() == 0) {
83.255 - continue;
83.256 - }
83.257 -
83.258 - boolean remove = false;
83.259 -
83.260 - if (line.charAt(0) == '#') {
83.261 - if ((line.length() == 1) || (line.charAt(1) != '-')) {
83.262 - continue;
83.263 - }
83.264 -
83.265 - // line starting with #- is a sign to remove that class from lookup
83.266 - remove = true;
83.267 - line = line.substring(2);
83.268 - }
83.269 -
83.270 - Class inst = null;
83.271 -
83.272 - try {
83.273 - // Most lines are fully-qualified class names.
83.274 - inst = Class.forName(line, false, loader);
83.275 - } catch (ClassNotFoundException cnfe) {
83.276 - if (remove) {
83.277 - // if we are removing somthing and the something
83.278 - // cannot be found it is ok to do nothing
83.279 - continue;
83.280 - } else {
83.281 - // but if we are not removing just rethrow
83.282 - throw cnfe;
83.283 - }
83.284 - }
83.285 -
83.286 - if (!clazz.isAssignableFrom(inst)) {
83.287 - throw new ClassNotFoundException(clazzToString(inst) + " not a subclass of " + clazzToString(clazz)); // NOI18N
83.288 - }
83.289 -
83.290 - if (remove) {
83.291 - removeClasses.add(inst);
83.292 - } else {
83.293 - // create new item here, but do not put it into
83.294 - // foundClasses array yet because following line
83.295 - // might specify its position
83.296 - currentItem = new Item();
83.297 - currentItem.clazz = inst;
83.298 - }
83.299 - }
83.300 -
83.301 - if (currentItem != null) {
83.302 - insertItem(currentItem, foundClasses);
83.303 - currentItem = null;
83.304 - }
83.305 - } finally {
83.306 - is.close();
83.307 - }
83.308 - } catch (ClassNotFoundException ex) {
83.309 - LOGGER.log(Level.WARNING, null, ex);
83.310 - } catch (IOException ex) {
83.311 - LOGGER.log(Level.WARNING, null, ex);
83.312 - }
83.313 - }
83.314 -
83.315 - LOGGER.log(Level.FINER, "Found impls of {0}: {1} and removed: {2} from: {3}", new Object[] {clazz.getName(), foundClasses, removeClasses, this});
83.316 -
83.317 - foundClasses.removeAll(removeClasses);
83.318 -
83.319 - for (Item item : foundClasses) {
83.320 - if (removeClasses.contains(item.clazz)) {
83.321 - continue;
83.322 - }
83.323 -
83.324 - result.add(new P(item.clazz));
83.325 - }
83.326 - }
83.327 - private static String clazzToString(Class clazz) {
83.328 - return clazz.getName() + "@" + clazz.getClassLoader() + ":" + clazz.getProtectionDomain().getCodeSource().getLocation(); // NOI18N
83.329 - }
83.330 -
83.331 - /**
83.332 - * Insert item to the list according to item.position value.
83.333 - */
83.334 - private void insertItem(Item item, List<Item> list) {
83.335 - // no position? -> add it to the end
83.336 - if (item.position == -1) {
83.337 - list.add(item);
83.338 -
83.339 - return;
83.340 - }
83.341 -
83.342 - int index = -1;
83.343 - for (Item i : list) {
83.344 - index++;
83.345 -
83.346 - if (i.position == -1) {
83.347 - list.add(index, item);
83.348 -
83.349 - return;
83.350 - } else {
83.351 - if (i.position > item.position) {
83.352 - list.add(index, item);
83.353 -
83.354 - return;
83.355 - }
83.356 - }
83.357 - }
83.358 -
83.359 - list.add(item);
83.360 - }
83.361 -
83.362 - private static class Item {
83.363 - private Class clazz;
83.364 - private int position = -1;
83.365 - @Override
83.366 - public String toString() {
83.367 - return "MetaInfServicesLookup.Item[" + clazz.getName() + "]"; // NOI18N
83.368 - }
83.369 - }
83.370 -
83.371 - /** Pair that holds name of a class and maybe the instance.
83.372 - */
83.373 - private static final class P extends AbstractLookup.Pair<Object> {
83.374 - /** May be one of three things:
83.375 - * 1. The implementation class which was named in the services file.
83.376 - * 2. An instance of it.
83.377 - * 3. Null, if creation of the instance resulted in an error.
83.378 - */
83.379 - private Object object;
83.380 -
83.381 - public P(Class<?> clazz) {
83.382 - this.object = clazz;
83.383 - }
83.384 -
83.385 - /** Finds the class.
83.386 - */
83.387 - private Class<? extends Object> clazz() {
83.388 - Object o = object;
83.389 -
83.390 - if (o instanceof Class) {
83.391 - return (Class<? extends Object>) o;
83.392 - } else if (o != null) {
83.393 - return o.getClass();
83.394 - } else {
83.395 - // Broken.
83.396 - return Object.class;
83.397 - }
83.398 - }
83.399 -
83.400 - @Override
83.401 - public boolean equals(Object o) {
83.402 - if (o instanceof P) {
83.403 - return ((P) o).clazz().equals(clazz());
83.404 - }
83.405 -
83.406 - return false;
83.407 - }
83.408 -
83.409 - @Override
83.410 - public int hashCode() {
83.411 - return clazz().hashCode();
83.412 - }
83.413 -
83.414 - protected boolean instanceOf(Class<?> c) {
83.415 - return c.isAssignableFrom(clazz());
83.416 - }
83.417 -
83.418 - public Class<?> getType() {
83.419 - return clazz();
83.420 - }
83.421 -
83.422 - public Object getInstance() {
83.423 - Object o = object; // keeping local copy to avoid another
83.424 -
83.425 - // thread to modify it under my hands
83.426 - if (o instanceof Class) {
83.427 - synchronized (o) { // o is Class and we will not create
83.428 - // 2 instances of the same class
83.429 -
83.430 - try {
83.431 - Class<?> c = ((Class) o);
83.432 - o = null;
83.433 -
83.434 - synchronized (knownInstances) { // guards only the static cache
83.435 - int size = knownInstances.size();
83.436 - int index = c.hashCode() % size;
83.437 - for (int i = 0; i < size; i++) {
83.438 - Reference<Object> ref = knownInstances.get(index);
83.439 - Object obj = ref == null ? null : ref.get();
83.440 - if (obj == null) {
83.441 - break;
83.442 - }
83.443 - if (c == obj.getClass()) {
83.444 - o = obj;
83.445 - break;
83.446 - }
83.447 - if (++index == size) {
83.448 - index = 0;
83.449 - }
83.450 - }
83.451 - }
83.452 -
83.453 - if (o == null) {
83.454 - o = createInstance(c);
83.455 -
83.456 - synchronized (knownInstances) { // guards only the static cache
83.457 - hashPut(o);
83.458 -
83.459 - int size = knownInstances.size();
83.460 - if (knownInstancesCount > size * 2 / 3) {
83.461 - LOGGER.log(Level.CONFIG, "Cache of size {0} is 2/3 full. Rehashing.", size);
83.462 - HashSet<Reference<Object>> all = new HashSet<Reference<Object>>();
83.463 - all.addAll(knownInstances);
83.464 - for (int i = 0; i < size; i++) {
83.465 - knownInstances.set(i, null);
83.466 - }
83.467 - for (int i = 0; i < size; i++) {
83.468 - knownInstances.add(null);
83.469 - }
83.470 - knownInstancesCount = 0;
83.471 - for (Reference<Object> r : all) {
83.472 - if (r == null) {
83.473 - continue;
83.474 - }
83.475 - Object instance = r.get();
83.476 - if (instance == null) {
83.477 - continue;
83.478 - }
83.479 - hashPut(instance);
83.480 - }
83.481 - }
83.482 -
83.483 - }
83.484 - }
83.485 -
83.486 - // Do not assign to instance var unless there is a complete synch
83.487 - // block between the newInstance and this line. Otherwise we could
83.488 - // be assigning a half-constructed instance that another thread
83.489 - // could see and return immediately.
83.490 - object = o;
83.491 - } catch (Exception ex) {
83.492 - LOGGER.log(Level.WARNING, "Cannot create " + object, ex);
83.493 - object = null;
83.494 - } catch (ExceptionInInitializerError x) { // #174055
83.495 - LOGGER.log(Level.WARNING, "Cannot create " + object, x);
83.496 - object = null;
83.497 - }
83.498 - }
83.499 - }
83.500 -
83.501 - return object;
83.502 - }
83.503 -
83.504 - public String getDisplayName() {
83.505 - return clazz().getName();
83.506 - }
83.507 -
83.508 - public String getId() {
83.509 - return clazz().getName();
83.510 - }
83.511 -
83.512 - protected boolean creatorOf(Object obj) {
83.513 - return obj == object;
83.514 - }
83.515 -
83.516 - private static void hashPut(Object o) {
83.517 - Class<?> c = o.getClass();
83.518 - int size = knownInstances.size();
83.519 - int index = c.hashCode() % size;
83.520 - for (int i = 0; i < size; i++) {
83.521 - Reference<Object> ref = knownInstances.get(index);
83.522 - Object obj = ref == null ? null : ref.get();
83.523 - if (obj == null) {
83.524 - knownInstances.set(index, new WeakReference<Object>(o));
83.525 - knownInstancesCount++;
83.526 - break;
83.527 - }
83.528 - if (++index == size) {
83.529 - index = 0;
83.530 - }
83.531 - }
83.532 - }
83.533 -
83.534 - private static boolean findSharedClassObjectSkip;
83.535 - private static Method findSharedClassObject;
83.536 - /** Basically does c.newInstance(), however the method is complicated
83.537 - * with a special behaviour for old and almost obsoleted NetBeans
83.538 - * class: SharedClassObject.
83.539 - */
83.540 - private static Object createInstance(Class<?> c) throws InstantiationException, IllegalAccessException {
83.541 - if (!findSharedClassObjectSkip) {
83.542 - try {
83.543 - if (findSharedClassObject == null) {
83.544 - Class<?> sco;
83.545 - try {
83.546 - sco = Class.forName("org.openide.util.SharedClassObject"); // NOI18N
83.547 - } catch (ClassNotFoundException ex) {
83.548 - findSharedClassObjectSkip = true;
83.549 - return c.newInstance();
83.550 - }
83.551 - findSharedClassObject = sco.getMethod("findObject", Class.class, boolean.class);
83.552 - }
83.553 - if (findSharedClassObject.getReturnType().isAssignableFrom(c)) {
83.554 - return findSharedClassObject.invoke(null, c, true);
83.555 - }
83.556 - } catch (Exception problem) {
83.557 - throw (InstantiationException)new InstantiationException(problem.getMessage()).initCause(problem);
83.558 - }
83.559 - }
83.560 - return c.newInstance();
83.561 - }
83.562 - }
83.563 -}
84.1 --- a/openide.util/src/org/openide/util/lookup/ProxyLookup.java Sat Oct 31 15:06:58 2009 +0100
84.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
84.3 @@ -1,969 +0,0 @@
84.4 -/*
84.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
84.6 - *
84.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
84.8 - *
84.9 - * The contents of this file are subject to the terms of either the GNU
84.10 - * General Public License Version 2 only ("GPL") or the Common
84.11 - * Development and Distribution License("CDDL") (collectively, the
84.12 - * "License"). You may not use this file except in compliance with the
84.13 - * License. You can obtain a copy of the License at
84.14 - * http://www.netbeans.org/cddl-gplv2.html
84.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
84.16 - * specific language governing permissions and limitations under the
84.17 - * License. When distributing the software, include this License Header
84.18 - * Notice in each file and include the License file at
84.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
84.20 - * particular file as subject to the "Classpath" exception as provided
84.21 - * by Sun in the GPL Version 2 section of the License file that
84.22 - * accompanied this code. If applicable, add the following below the
84.23 - * License Header, with the fields enclosed by brackets [] replaced by
84.24 - * your own identifying information:
84.25 - * "Portions Copyrighted [year] [name of copyright owner]"
84.26 - *
84.27 - * Contributor(s):
84.28 - *
84.29 - * The Original Software is NetBeans. The Initial Developer of the Original
84.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
84.31 - * Microsystems, Inc. All Rights Reserved.
84.32 - *
84.33 - * If you wish your version of this file to be governed by only the CDDL
84.34 - * or only the GPL Version 2, indicate your decision by adding
84.35 - * "[Contributor] elects to include this software in this distribution
84.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
84.37 - * single choice of license, a recipient has the option to distribute
84.38 - * your version of this file under either the CDDL, the GPL Version 2 or
84.39 - * to extend the choice of license to its licensees as provided above.
84.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
84.41 - * Version 2 license, then the option applies only if the new code is
84.42 - * made subject to such option by the copyright holder.
84.43 - */
84.44 -
84.45 -package org.openide.util.lookup;
84.46 -
84.47 -import java.lang.ref.Reference;
84.48 -import java.lang.ref.WeakReference;
84.49 -import java.util.ArrayList;
84.50 -import java.util.Arrays;
84.51 -import java.util.Collection;
84.52 -import java.util.Collections;
84.53 -import java.util.HashMap;
84.54 -import java.util.HashSet;
84.55 -import java.util.IdentityHashMap;
84.56 -import java.util.Iterator;
84.57 -import java.util.List;
84.58 -import java.util.Map;
84.59 -import java.util.Map.Entry;
84.60 -import java.util.Set;
84.61 -import java.util.concurrent.Executor;
84.62 -import javax.swing.event.EventListenerList;
84.63 -import org.openide.util.Lookup;
84.64 -import org.openide.util.LookupEvent;
84.65 -import org.openide.util.LookupListener;
84.66 -
84.67 -/** Implementation of lookup that can delegate to others.
84.68 - *
84.69 - * @author Jaroslav Tulach
84.70 - * @since 1.9
84.71 - */
84.72 -public class ProxyLookup extends Lookup {
84.73 - /** data representing the state of the lookup */
84.74 - private ImmutableInternalData data;
84.75 -
84.76 - /** Create a proxy to some other lookups.
84.77 - * @param lookups the initial delegates
84.78 - */
84.79 - public ProxyLookup(Lookup... lookups) {
84.80 - data = ImmutableInternalData.EMPTY.setLookupsNoFire(lookups, true);
84.81 - }
84.82 -
84.83 - /**
84.84 - * Create a lookup initially proxying to no others.
84.85 - * Permits serializable subclasses.
84.86 - * @since 3.27
84.87 - */
84.88 - protected ProxyLookup() {
84.89 - data = ImmutableInternalData.EMPTY;
84.90 - }
84.91 -
84.92 - @Override
84.93 - public synchronized String toString() {
84.94 - return "ProxyLookup(class=" + getClass() + ")->" + Arrays.asList(getData().getLookups(false)); // NOI18N
84.95 - }
84.96 -
84.97 - /** Getter for the delegates.
84.98 - * @return the array of lookups we delegate to
84.99 - * @since 1.19
84.100 - */
84.101 - protected final Lookup[] getLookups() {
84.102 - synchronized (ProxyLookup.this) {
84.103 - return getData().getLookups(true);
84.104 - }
84.105 - }
84.106 -
84.107 - private Set<Lookup> identityHashSet(Collection<Lookup> current) {
84.108 - Map<Lookup,Void> map = new IdentityHashMap<Lookup, Void>();
84.109 - for (Lookup lookup : current) {
84.110 - map.put(lookup, null);
84.111 - }
84.112 - return map.keySet();
84.113 - }
84.114 -
84.115 - /**
84.116 - * Changes the delegates.
84.117 - *
84.118 - * @param lookups the new lookups to delegate to
84.119 - * @since 1.19 protected
84.120 - */
84.121 - protected final void setLookups(Lookup... lookups) {
84.122 - setLookups(null, lookups);
84.123 - }
84.124 -
84.125 - /**
84.126 - * Changes the delegates immediatelly, notifies the listeners in provided
84.127 - * executor, potentially later.
84.128 - *
84.129 - * @param lookups the new lookups to delegate to
84.130 - * @param notifyIn executor to deliver the notification to listeners or null
84.131 - * @since 7.16
84.132 - */
84.133 - protected final void setLookups(Executor notifyIn, Lookup... lookups) {
84.134 - Collection<Reference<R>> arr;
84.135 - Set<Lookup> newL;
84.136 - Set<Lookup> current;
84.137 - Lookup[] old;
84.138 -
84.139 - Map<Result,LookupListener> toRemove = new IdentityHashMap<Lookup.Result, LookupListener>();
84.140 - Map<Result,LookupListener> toAdd = new IdentityHashMap<Lookup.Result, LookupListener>();
84.141 -
84.142 - ImmutableInternalData orig;
84.143 - synchronized (ProxyLookup.this) {
84.144 - orig = getData();
84.145 - ImmutableInternalData newData = getData().setLookupsNoFire(lookups, false);
84.146 - if (newData == getData()) {
84.147 - return;
84.148 - }
84.149 - arr = setData(newData, lookups, toAdd, toRemove);
84.150 - }
84.151 -
84.152 - // better to do this later than in synchronized block
84.153 - for (Map.Entry<Result, LookupListener> e : toRemove.entrySet()) {
84.154 - e.getKey().removeLookupListener(e.getValue());
84.155 - }
84.156 - for (Map.Entry<Result, LookupListener> e : toAdd.entrySet()) {
84.157 - e.getKey().addLookupListener(e.getValue());
84.158 - }
84.159 -
84.160 -
84.161 - // this cannot be done from the synchronized block
84.162 - final ArrayList<Object> evAndListeners = new ArrayList<Object>();
84.163 - for (Reference<R> ref : arr) {
84.164 - R<?> r = ref.get();
84.165 - if (r != null) {
84.166 - r.collectFires(evAndListeners);
84.167 - }
84.168 - }
84.169 -
84.170 - class Notify implements Runnable {
84.171 - public void run() {
84.172 - Iterator it = evAndListeners.iterator();
84.173 - while (it.hasNext()) {
84.174 - LookupEvent ev = (LookupEvent)it.next();
84.175 - LookupListener l = (LookupListener)it.next();
84.176 - l.resultChanged(ev);
84.177 - }
84.178 - }
84.179 - }
84.180 - Notify n = new Notify();
84.181 - if (notifyIn == null) {
84.182 - n.run();
84.183 - } else {
84.184 - notifyIn.execute(n);
84.185 - }
84.186 - }
84.187 -
84.188 - /** Notifies subclasses that a query is about to be processed.
84.189 - * Subclasses can update its state before the actual processing
84.190 - * begins. It is allowed to call <code>setLookups</code> method
84.191 - * to change/update the set of objects the proxy delegates to.
84.192 - *
84.193 - * @param template the template of the query
84.194 - * @since 1.31
84.195 - */
84.196 - protected void beforeLookup(Template<?> template) {
84.197 - }
84.198 -
84.199 - public final <T> T lookup(Class<T> clazz) {
84.200 - beforeLookup(new Template<T>(clazz));
84.201 -
84.202 - Lookup[] tmpLkps;
84.203 - synchronized (ProxyLookup.this) {
84.204 - tmpLkps = getData().getLookups(false);
84.205 - }
84.206 -
84.207 - for (int i = 0; i < tmpLkps.length; i++) {
84.208 - T o = tmpLkps[i].lookup(clazz);
84.209 -
84.210 - if (o != null) {
84.211 - return o;
84.212 - }
84.213 - }
84.214 -
84.215 - return null;
84.216 - }
84.217 -
84.218 - @Override
84.219 - public final <T> Item<T> lookupItem(Template<T> template) {
84.220 - beforeLookup(template);
84.221 -
84.222 - Lookup[] tmpLkps;
84.223 - synchronized (ProxyLookup.this) {
84.224 - tmpLkps = getData().getLookups(false);
84.225 - }
84.226 -
84.227 - for (int i = 0; i < tmpLkps.length; i++) {
84.228 - Item<T> o = tmpLkps[i].lookupItem(template);
84.229 -
84.230 - if (o != null) {
84.231 - return o;
84.232 - }
84.233 - }
84.234 -
84.235 - return null;
84.236 - }
84.237 -
84.238 - @SuppressWarnings("unchecked")
84.239 - private static <T> R<T> convertResult(R r) {
84.240 - return (R<T>)r;
84.241 - }
84.242 -
84.243 - public final <T> Result<T> lookup(Lookup.Template<T> template) {
84.244 - synchronized (ProxyLookup.this) {
84.245 - ImmutableInternalData[] res = { null };
84.246 - R<T> newR = getData().findResult(this, res, template);
84.247 - setData(res[0], getData().getLookups(false), null, null);
84.248 - return newR;
84.249 - }
84.250 - }
84.251 -
84.252 - /** Unregisters a template from the has map.
84.253 - */
84.254 - private final void unregisterTemplate(Template<?> template) {
84.255 - synchronized (ProxyLookup.this) {
84.256 - ImmutableInternalData id = getData();
84.257 - if (id == null) {
84.258 - return;
84.259 - }
84.260 - setData(id.removeTemplate(this, template), getData().getLookups(false), null, null);
84.261 - }
84.262 - }
84.263 -
84.264 - private ImmutableInternalData getData() {
84.265 - assert Thread.holdsLock(this);
84.266 - return data;
84.267 - }
84.268 -
84.269 - private Collection<Reference<R>> setData(
84.270 - ImmutableInternalData newData, Lookup[] current,
84.271 - Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
84.272 - ) {
84.273 - assert Thread.holdsLock(ProxyLookup.this);
84.274 - assert newData != null;
84.275 -
84.276 - ImmutableInternalData previous = this.getData();
84.277 -
84.278 - if (previous == newData) {
84.279 - return Collections.emptyList();
84.280 - }
84.281 -
84.282 - if (newData.isEmpty()) {
84.283 - this.setData(newData);
84.284 - // no affected results => exit
84.285 - return Collections.emptyList();
84.286 - }
84.287 -
84.288 - Collection<Reference<R>> arr = newData.references();
84.289 -
84.290 - Set<Lookup> removed = identityHashSet(previous.getLookupsList());
84.291 - Set<Lookup> currentSet = identityHashSet(Arrays.asList(current));
84.292 - Set<Lookup> newL = identityHashSet(currentSet);
84.293 - removed.removeAll(currentSet); // current contains just those lookups that have disappeared
84.294 - newL.removeAll(previous.getLookupsList()); // really new lookups
84.295 -
84.296 - for (Reference<R> ref : arr) {
84.297 - R<?> r = ref.get();
84.298 - if (r != null) {
84.299 - r.lookupChange(newData, current, previous, newL, removed, toAdd, toRemove);
84.300 - if (this.getData() != previous) {
84.301 - // the data were changed by an re-entrant call
84.302 - // skip any other change processing, as it is not needed
84.303 - // anymore
84.304 - }
84.305 - }
84.306 - }
84.307 - for (Reference<R> ref : arr) {
84.308 - R<?> r = ref.get();
84.309 - if (r != null) {
84.310 - r.data = newData;
84.311 - }
84.312 - }
84.313 - this.setData(newData);
84.314 - return arr;
84.315 - }
84.316 -
84.317 - private void setData(ImmutableInternalData data) {
84.318 - this.data = data;
84.319 - }
84.320 -
84.321 - /** Result of a lookup request. Allows access to single object
84.322 - * that was found (not too useful) and also to all objects found
84.323 - * (more useful).
84.324 - */
84.325 - private static final class R<T> extends WaitableResult<T> {
84.326 - /** weak listener & result */
84.327 - private final WeakResult<T> weakL;
84.328 -
84.329 - /** list of listeners added */
84.330 - private javax.swing.event.EventListenerList listeners;
84.331 -
84.332 - /** collection of Objects */
84.333 - private Collection[] cache;
84.334 -
84.335 -
84.336 - /** associated lookup */
84.337 - private ImmutableInternalData data;
84.338 -
84.339 - /** Constructor.
84.340 - */
84.341 - public R(ProxyLookup proxy, Lookup.Template<T> t) {
84.342 - this.weakL = new WeakResult<T>(proxy, this, t);
84.343 - }
84.344 -
84.345 - private ProxyLookup proxy() {
84.346 - return weakL.result.proxy;
84.347 - }
84.348 -
84.349 - @SuppressWarnings("unchecked")
84.350 - private Result<T>[] newResults(int len) {
84.351 - return new Result[len];
84.352 - }
84.353 -
84.354 - @Override
84.355 - protected void finalize() {
84.356 - weakL.result.run();
84.357 - }
84.358 -
84.359 - /** initializes the results
84.360 - */
84.361 - private Result<T>[] initResults() {
84.362 - BIG_LOOP: for (;;) {
84.363 - Lookup[] myLkps;
84.364 - ImmutableInternalData current;
84.365 - synchronized (proxy()) {
84.366 - if (weakL.getResults() != null) {
84.367 - return weakL.getResults();
84.368 - }
84.369 - myLkps = data.getLookups(false);
84.370 - current = data;
84.371 - }
84.372 -
84.373 - Result<T>[] arr = newResults(myLkps.length);
84.374 -
84.375 - for (int i = 0; i < arr.length; i++) {
84.376 - arr[i] = myLkps[i].lookup(weakL.result.template);
84.377 - }
84.378 -
84.379 - synchronized (proxy()) {
84.380 - if (current != data) {
84.381 - continue;
84.382 - }
84.383 -
84.384 - Lookup[] currentLkps = data.getLookups(false);
84.385 - if (currentLkps.length != myLkps.length) {
84.386 - continue BIG_LOOP;
84.387 - }
84.388 - for (int i = 0; i < currentLkps.length; i++) {
84.389 - if (currentLkps[i] != myLkps[i]) {
84.390 - continue BIG_LOOP;
84.391 - }
84.392 - }
84.393 -
84.394 - // some other thread might compute the result mean while.
84.395 - // if not finish the computation yourself
84.396 - if (weakL.getResults() != null) {
84.397 - return weakL.getResults();
84.398 - }
84.399 -
84.400 - for (int i = 0; i < arr.length; i++) {
84.401 - arr[i].addLookupListener(weakL);
84.402 - }
84.403 -
84.404 - weakL.setResults(arr);
84.405 -
84.406 - return arr;
84.407 - }
84.408 - }
84.409 - }
84.410 -
84.411 - /** Called when there is a change in the list of proxied lookups.
84.412 - * @param added set of added lookups
84.413 - * @param remove set of removed lookups
84.414 - * @param current array of current lookups
84.415 - */
84.416 - final void lookupChange(
84.417 - ImmutableInternalData newData, Lookup[] current, ImmutableInternalData oldData,
84.418 - Set<Lookup> added, Set<Lookup> removed,
84.419 - Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
84.420 - ) {
84.421 - if (weakL.getResults() == null) {
84.422 - // not computed yet, do not need to do anything
84.423 - return;
84.424 - }
84.425 -
84.426 - Lookup[] old = oldData.getLookups(false);
84.427 -
84.428 - // map (Lookup, Lookup.Result)
84.429 - Map<Lookup,Result<T>> map = new IdentityHashMap<Lookup,Result<T>>(old.length * 2);
84.430 -
84.431 - for (int i = 0; i < old.length; i++) {
84.432 - if (removed.contains(old[i])) {
84.433 - // removed lookup
84.434 - if (toRemove != null) {
84.435 - toRemove.put(weakL.getResults()[i], weakL);
84.436 - }
84.437 - } else {
84.438 - // remember the association
84.439 - map.put(old[i], weakL.getResults()[i]);
84.440 - }
84.441 - }
84.442 -
84.443 - Lookup.Result<T>[] arr = newResults(current.length);
84.444 -
84.445 - for (int i = 0; i < current.length; i++) {
84.446 - if (added.contains(current[i])) {
84.447 - // new lookup
84.448 - arr[i] = current[i].lookup(weakL.result.template);
84.449 - if (toAdd != null) {
84.450 - toAdd.put(arr[i], weakL);
84.451 - }
84.452 - } else {
84.453 - // old lookup
84.454 - arr[i] = map.get(current[i]);
84.455 -
84.456 - if (arr[i] == null) {
84.457 - // assert
84.458 - throw new IllegalStateException();
84.459 - }
84.460 - }
84.461 - }
84.462 -
84.463 - // remember the new results
84.464 - weakL.setResults(arr);
84.465 - }
84.466 -
84.467 - /** Just delegates.
84.468 - */
84.469 - public void addLookupListener(LookupListener l) {
84.470 - synchronized (proxy()) {
84.471 - if (listeners == null) {
84.472 - listeners = new EventListenerList();
84.473 - }
84.474 - }
84.475 -
84.476 - listeners.add(LookupListener.class, l);
84.477 - }
84.478 -
84.479 - /** Just delegates.
84.480 - */
84.481 - public void removeLookupListener(LookupListener l) {
84.482 - if (listeners != null) {
84.483 - listeners.remove(LookupListener.class, l);
84.484 - }
84.485 - }
84.486 -
84.487 - /** Access to all instances in the result.
84.488 - * @return collection of all instances
84.489 - */
84.490 - @SuppressWarnings("unchecked")
84.491 - public java.util.Collection<T> allInstances() {
84.492 - return computeResult(0);
84.493 - }
84.494 -
84.495 - /** Classes of all results. Set of the most concreate classes
84.496 - * that are registered in the system.
84.497 - * @return set of Class objects
84.498 - */
84.499 - @SuppressWarnings("unchecked")
84.500 - @Override
84.501 - public java.util.Set<Class<? extends T>> allClasses() {
84.502 - return (java.util.Set<Class<? extends T>>) computeResult(1);
84.503 - }
84.504 -
84.505 - /** All registered items. The collection of all pairs of
84.506 - * ii and their classes.
84.507 - * @return collection of Lookup.Item
84.508 - */
84.509 - @SuppressWarnings("unchecked")
84.510 - @Override
84.511 - public java.util.Collection<? extends Item<T>> allItems() {
84.512 - return computeResult(2);
84.513 - }
84.514 -
84.515 - /** Computes results from proxied lookups.
84.516 - * @param indexToCache 0 = allInstances, 1 = allClasses, 2 = allItems
84.517 - * @return the collection or set of the objects
84.518 - */
84.519 - private java.util.Collection computeResult(int indexToCache) {
84.520 - // results to use
84.521 - Lookup.Result<T>[] arr = myBeforeLookup();
84.522 -
84.523 - // if the call to beforeLookup resulted in deletion of caches
84.524 - synchronized (proxy()) {
84.525 - if (getCache() != null) {
84.526 - Collection result = getCache()[indexToCache];
84.527 - if (result != null) {
84.528 - return result;
84.529 - }
84.530 - }
84.531 - }
84.532 -
84.533 - // initialize the collection to hold result
84.534 - Collection<Object> compute;
84.535 - Collection<Object> ret;
84.536 -
84.537 - if (indexToCache == 1) {
84.538 - HashSet<Object> s = new HashSet<Object>();
84.539 - compute = s;
84.540 - ret = Collections.unmodifiableSet(s);
84.541 - } else {
84.542 - List<Object> l = new ArrayList<Object>(arr.length * 2);
84.543 - compute = l;
84.544 - ret = Collections.unmodifiableList(l);
84.545 - }
84.546 -
84.547 - // fill the collection
84.548 - for (int i = 0; i < arr.length; i++) {
84.549 - switch (indexToCache) {
84.550 - case 0:
84.551 - compute.addAll(arr[i].allInstances());
84.552 - break;
84.553 - case 1:
84.554 - compute.addAll(arr[i].allClasses());
84.555 - break;
84.556 - case 2:
84.557 - compute.addAll(arr[i].allItems());
84.558 - break;
84.559 - default:
84.560 - assert false : "Wrong index: " + indexToCache;
84.561 - }
84.562 - }
84.563 -
84.564 -
84.565 -
84.566 - synchronized (proxy()) {
84.567 - if (getCache() == null) {
84.568 - // initialize the cache to indicate this result is in use
84.569 - setCache(new Collection[3]);
84.570 - }
84.571 -
84.572 - if (arr == weakL.getResults()) {
84.573 - // updates the results, if the results have not been
84.574 - // changed during the computation of allInstances
84.575 - getCache()[indexToCache] = ret;
84.576 - }
84.577 - }
84.578 -
84.579 - return ret;
84.580 - }
84.581 -
84.582 - /** When the result changes, fire the event.
84.583 - */
84.584 - public void resultChanged(LookupEvent ev) {
84.585 - collectFires(null);
84.586 - }
84.587 -
84.588 - protected void collectFires(Collection<Object> evAndListeners) {
84.589 - // clear cached instances
84.590 - Collection oldItems;
84.591 - Collection oldInstances;
84.592 - synchronized (proxy()) {
84.593 - if (getCache() == null) {
84.594 - // nobody queried the result yet
84.595 - return;
84.596 - }
84.597 - oldInstances = getCache()[0];
84.598 - oldItems = getCache()[2];
84.599 -
84.600 -
84.601 - if (listeners == null || listeners.getListenerCount() == 0) {
84.602 - // clear the cache
84.603 - setCache(new Collection[3]);
84.604 - return;
84.605 - }
84.606 -
84.607 - // ignore events if they arrive as a result of call to allItems
84.608 - // or allInstances, bellow...
84.609 - setCache(null);
84.610 - }
84.611 -
84.612 - boolean modified = true;
84.613 -
84.614 - if (oldItems != null) {
84.615 - Collection newItems = allItems();
84.616 - if (oldItems.equals(newItems)) {
84.617 - modified = false;
84.618 - }
84.619 - } else {
84.620 - if (oldInstances != null) {
84.621 - Collection newInstances = allInstances();
84.622 - if (oldInstances.equals(newInstances)) {
84.623 - modified = false;
84.624 - }
84.625 - } else {
84.626 - synchronized (proxy()) {
84.627 - if (getCache() == null) {
84.628 - // we have to initialize the cache
84.629 - // to show that the result has been initialized
84.630 - setCache(new Collection[3]);
84.631 - }
84.632 - }
84.633 - }
84.634 - }
84.635 -
84.636 - if (modified) {
84.637 - LookupEvent ev = new LookupEvent(this);
84.638 - AbstractLookup.notifyListeners(listeners.getListenerList(), ev, evAndListeners);
84.639 - }
84.640 - }
84.641 -
84.642 - /** Implementation of my before lookup.
84.643 - * @return results to work on.
84.644 - */
84.645 - private Lookup.Result<T>[] myBeforeLookup() {
84.646 - Template<T> template = weakL.result.template;
84.647 -
84.648 - proxy().beforeLookup(template);
84.649 -
84.650 - Lookup.Result<T>[] arr = initResults();
84.651 -
84.652 - // invoke update on the results
84.653 - for (int i = 0; i < arr.length; i++) {
84.654 - if (arr[i] instanceof WaitableResult) {
84.655 - WaitableResult w = (WaitableResult) arr[i];
84.656 - w.beforeLookup(template);
84.657 - }
84.658 - }
84.659 -
84.660 - return arr;
84.661 - }
84.662 -
84.663 - /** Used by proxy results to synchronize before lookup.
84.664 - */
84.665 - protected void beforeLookup(Lookup.Template t) {
84.666 - if (t.getType() == weakL.result.template.getType()) {
84.667 - myBeforeLookup();
84.668 - }
84.669 - }
84.670 -
84.671 - private Collection[] getCache() {
84.672 - return cache;
84.673 - }
84.674 -
84.675 - private void setCache(Collection[] cache) {
84.676 - assert Thread.holdsLock(proxy());
84.677 - this.cache = cache;
84.678 - }
84.679 - }
84.680 - private static final class WeakRef<T> extends WeakReference<R> implements Runnable {
84.681 - final WeakResult<T> result;
84.682 - final ProxyLookup proxy;
84.683 - final Template<T> template;
84.684 -
84.685 - public WeakRef(R r, WeakResult<T> result, ProxyLookup proxy, Template<T> template) {
84.686 - super(r);
84.687 - this.result = result;
84.688 - this.template = template;
84.689 - this.proxy = proxy;
84.690 - }
84.691 -
84.692 - public void run() {
84.693 - result.removeListeners();
84.694 - proxy.unregisterTemplate(template);
84.695 - }
84.696 - }
84.697 -
84.698 -
84.699 - private static final class WeakResult<T> extends WaitableResult<T> implements LookupListener, Runnable {
84.700 - /** all results */
84.701 - private Lookup.Result<T>[] results;
84.702 - private final WeakRef<T> result;
84.703 -
84.704 - public WeakResult(ProxyLookup proxy, R r, Template<T> t) {
84.705 - this.result = new WeakRef<T>(r, this, proxy, t);
84.706 - }
84.707 -
84.708 - final void removeListeners() {
84.709 - Lookup.Result<T>[] arr = this.getResults();
84.710 - if (arr == null) {
84.711 - return;
84.712 - }
84.713 -
84.714 - for(int i = 0; i < arr.length; i++) {
84.715 - arr[i].removeLookupListener(this);
84.716 - }
84.717 - }
84.718 -
84.719 - protected void beforeLookup(Lookup.Template t) {
84.720 - R r = result.get();
84.721 - if (r != null) {
84.722 - r.beforeLookup(t);
84.723 - } else {
84.724 - removeListeners();
84.725 - }
84.726 - }
84.727 -
84.728 - protected void collectFires(Collection<Object> evAndListeners) {
84.729 - R<?> r = result.get();
84.730 - if (r != null) {
84.731 - r.collectFires(evAndListeners);
84.732 - } else {
84.733 - removeListeners();
84.734 - }
84.735 - }
84.736 -
84.737 - public void addLookupListener(LookupListener l) {
84.738 - assert false;
84.739 - }
84.740 -
84.741 - public void removeLookupListener(LookupListener l) {
84.742 - assert false;
84.743 - }
84.744 -
84.745 - public Collection<T> allInstances() {
84.746 - assert false;
84.747 - return null;
84.748 - }
84.749 -
84.750 - public void resultChanged(LookupEvent ev) {
84.751 - R r = result.get();
84.752 - if (r != null) {
84.753 - r.resultChanged(ev);
84.754 - } else {
84.755 - removeListeners();
84.756 - }
84.757 - }
84.758 -
84.759 - @Override
84.760 - public Collection<? extends Item<T>> allItems() {
84.761 - assert false;
84.762 - return null;
84.763 - }
84.764 -
84.765 - @Override
84.766 - public Set<Class<? extends T>> allClasses() {
84.767 - assert false;
84.768 - return null;
84.769 - }
84.770 -
84.771 - public void run() {
84.772 - removeListeners();
84.773 - }
84.774 -
84.775 - private Lookup.Result<T>[] getResults() {
84.776 - return results;
84.777 - }
84.778 -
84.779 - private void setResults(Lookup.Result<T>[] results) {
84.780 - this.results = results;
84.781 - }
84.782 - } // end of WeakResult
84.783 -
84.784 - static abstract class ImmutableInternalData extends Object {
84.785 - static final ImmutableInternalData EMPTY = new EmptyInternalData();
84.786 - static final Lookup[] EMPTY_ARR = new Lookup[0];
84.787 -
84.788 -
84.789 - protected ImmutableInternalData() {
84.790 - }
84.791 -
84.792 - public static ImmutableInternalData create(Object lkp, Map<Template, Reference<R>> results) {
84.793 - if (results.size() == 0 && lkp == EMPTY_ARR) {
84.794 - return EMPTY;
84.795 - }
84.796 - if (results.size() == 1) {
84.797 - Entry<Template,Reference<R>> e = results.entrySet().iterator().next();
84.798 - return new SingleInternalData(lkp, e.getKey(), e.getValue());
84.799 - }
84.800 -
84.801 - return new RealInternalData(lkp, results);
84.802 - }
84.803 -
84.804 - protected abstract boolean isEmpty();
84.805 - protected abstract Map<Template, Reference<R>> getResults();
84.806 - protected abstract Object getRawLookups();
84.807 -
84.808 - final Collection<Reference<R>> references() {
84.809 - return getResults().values();
84.810 - }
84.811 -
84.812 - final <T> ImmutableInternalData removeTemplate(ProxyLookup proxy, Template<T> template) {
84.813 - if (getResults().containsKey(template)) {
84.814 - HashMap<Template,Reference<R>> c = new HashMap<Template, Reference<ProxyLookup.R>>(getResults());
84.815 - Reference<R> ref = c.remove(template);
84.816 - if (ref != null && ref.get() != null) {
84.817 - // seems like there is a reference to a result for this template
84.818 - // thta is still alive
84.819 - return this;
84.820 - }
84.821 - return create(getRawLookups(), c);
84.822 - } else {
84.823 - return this;
84.824 - }
84.825 - }
84.826 -
84.827 - <T> R<T> findResult(ProxyLookup proxy, ImmutableInternalData[] newData, Template<T> template) {
84.828 - assert Thread.holdsLock(proxy);
84.829 -
84.830 - Map<Template,Reference<R>> map = getResults();
84.831 -
84.832 - Reference<R> ref = map.get(template);
84.833 - R r = (ref == null) ? null : ref.get();
84.834 -
84.835 - if (r != null) {
84.836 - newData[0] = this;
84.837 - return convertResult(r);
84.838 - }
84.839 -
84.840 - HashMap<Template, Reference<R>> res = new HashMap<Template, Reference<R>>(map);
84.841 - R<T> newR = new R<T>(proxy, template);
84.842 - res.put(template, new java.lang.ref.SoftReference<R>(newR));
84.843 - newR.data = newData[0] = create(getRawLookups(), res);
84.844 - return newR;
84.845 - }
84.846 - final ImmutableInternalData setLookupsNoFire(Lookup[] lookups, boolean skipCheck) {
84.847 - Object l;
84.848 -
84.849 - if (!skipCheck) {
84.850 - Lookup[] previous = getLookups(false);
84.851 - if (previous == lookups) {
84.852 - return this;
84.853 - }
84.854 -
84.855 - if (previous.length == lookups.length) {
84.856 - int same = 0;
84.857 - for (int i = 0; i < previous.length; i++) {
84.858 - if (lookups[i] != previous[i]) {
84.859 - break;
84.860 - }
84.861 - same++;
84.862 - }
84.863 - if (same == previous.length) {
84.864 - return this;
84.865 - }
84.866 - }
84.867 - }
84.868 -
84.869 - if (lookups.length == 1) {
84.870 - l = lookups[0];
84.871 - assert l != null : "Cannot assign null delegate";
84.872 - } else {
84.873 - if (lookups.length == 0) {
84.874 - l = EMPTY_ARR;
84.875 - } else {
84.876 - l = lookups.clone();
84.877 - }
84.878 - }
84.879 -
84.880 - if (isEmpty() && l == EMPTY_ARR) {
84.881 - return this;
84.882 - }
84.883 -
84.884 - return create(l, getResults());
84.885 - }
84.886 - final Lookup[] getLookups(boolean clone) {
84.887 - Object l = this.getRawLookups();
84.888 - if (l instanceof Lookup) {
84.889 - return new Lookup[] { (Lookup)l };
84.890 - } else {
84.891 - Lookup[] arr = (Lookup[])l;
84.892 - if (clone) {
84.893 - arr = arr.clone();
84.894 - }
84.895 - return arr;
84.896 - }
84.897 - }
84.898 - final List<Lookup> getLookupsList() {
84.899 - return Arrays.asList(getLookups(false));
84.900 - }
84.901 -
84.902 - } // end of ImmutableInternalData
84.903 -
84.904 - private static final class SingleInternalData extends ImmutableInternalData {
84.905 - /** lookups to delegate to (either Lookup or array of Lookups) */
84.906 - private final Object lookups;
84.907 - private final Template template;
84.908 - private final Reference<ProxyLookup.R> result;
84.909 -
84.910 - public SingleInternalData(Object lookups, Template<?> template, Reference<ProxyLookup.R> result) {
84.911 - this.lookups = lookups;
84.912 - this.template = template;
84.913 - this.result = result;
84.914 - }
84.915 -
84.916 - protected final boolean isEmpty() {
84.917 - return false;
84.918 - }
84.919 -
84.920 - protected Map<Template, Reference<R>> getResults() {
84.921 - return Collections.singletonMap(template, result);
84.922 - }
84.923 -
84.924 - protected Object getRawLookups() {
84.925 - return lookups;
84.926 - }
84.927 - }
84.928 - private static final class RealInternalData extends ImmutableInternalData {
84.929 - /** lookups to delegate to (either Lookup or array of Lookups) */
84.930 - private final Object lookups;
84.931 -
84.932 - /** map of templates to currently active results */
84.933 - private final Map<Template,Reference<R>> results;
84.934 -
84.935 - public RealInternalData(Object lookups, Map<Template, Reference<ProxyLookup.R>> results) {
84.936 - this.results = results;
84.937 - this.lookups = lookups;
84.938 - }
84.939 -
84.940 - protected final boolean isEmpty() {
84.941 - return false;
84.942 - }
84.943 -
84.944 - protected Map<Template, Reference<R>> getResults() {
84.945 - boolean strict = false;
84.946 - assert strict = true;
84.947 - return strict ? Collections.unmodifiableMap(results) : results;
84.948 - }
84.949 -
84.950 - protected Object getRawLookups() {
84.951 - return lookups;
84.952 - }
84.953 - }
84.954 -
84.955 - private static final class EmptyInternalData extends ImmutableInternalData {
84.956 - EmptyInternalData() {
84.957 - }
84.958 -
84.959 - protected final boolean isEmpty() {
84.960 - return true;
84.961 - }
84.962 -
84.963 - protected Map<Template, Reference<R>> getResults() {
84.964 - return Collections.emptyMap();
84.965 - }
84.966 -
84.967 - @Override
84.968 - protected Object getRawLookups() {
84.969 - return EMPTY_ARR;
84.970 - }
84.971 - } // end of EmptyInternalData
84.972 -}
85.1 --- a/openide.util/src/org/openide/util/lookup/ServiceProvider.java Sat Oct 31 15:06:58 2009 +0100
85.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
85.3 @@ -1,102 +0,0 @@
85.4 -/*
85.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
85.6 - *
85.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
85.8 - *
85.9 - * The contents of this file are subject to the terms of either the GNU
85.10 - * General Public License Version 2 only ("GPL") or the Common
85.11 - * Development and Distribution License("CDDL") (collectively, the
85.12 - * "License"). You may not use this file except in compliance with the
85.13 - * License. You can obtain a copy of the License at
85.14 - * http://www.netbeans.org/cddl-gplv2.html
85.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
85.16 - * specific language governing permissions and limitations under the
85.17 - * License. When distributing the software, include this License Header
85.18 - * Notice in each file and include the License file at
85.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
85.20 - * particular file as subject to the "Classpath" exception as provided
85.21 - * by Sun in the GPL Version 2 section of the License file that
85.22 - * accompanied this code. If applicable, add the following below the
85.23 - * License Header, with the fields enclosed by brackets [] replaced by
85.24 - * your own identifying information:
85.25 - * "Portions Copyrighted [year] [name of copyright owner]"
85.26 - *
85.27 - * If you wish your version of this file to be governed by only the CDDL
85.28 - * or only the GPL Version 2, indicate your decision by adding
85.29 - * "[Contributor] elects to include this software in this distribution
85.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
85.31 - * single choice of license, a recipient has the option to distribute
85.32 - * your version of this file under either the CDDL, the GPL Version 2 or
85.33 - * to extend the choice of license to its licensees as provided above.
85.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
85.35 - * Version 2 license, then the option applies only if the new code is
85.36 - * made subject to such option by the copyright holder.
85.37 - *
85.38 - * Contributor(s):
85.39 - *
85.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
85.41 - */
85.42 -
85.43 -package org.openide.util.lookup;
85.44 -
85.45 -import java.lang.annotation.ElementType;
85.46 -import java.lang.annotation.Retention;
85.47 -import java.lang.annotation.RetentionPolicy;
85.48 -import java.lang.annotation.Target;
85.49 -import org.openide.util.Lookup;
85.50 -
85.51 -/**
85.52 - * Declarative registration of a singleton service provider.
85.53 - * By marking an implementation class with this annotation,
85.54 - * you automatically register that implementation, normally in {@link Lookup#getDefault}.
85.55 - * The class must be public and have a public no-argument constructor.
85.56 - * <p>Example of usage:
85.57 - * <pre>
85.58 - * package my.module;
85.59 - * import org.netbeans.spi.whatever.Thing;
85.60 - * import org.openide.util.lookup.ServiceProvider;
85.61 - * @ServiceProvider(service=Thing.class)
85.62 - * public class MyThing implements Thing {...}
85.63 - * </pre>
85.64 - * <p>would result in a resource file <code>META-INF/services/org.netbeans.spi.whatever.Thing</code>
85.65 - * containing the single line of text: <code>my.module.MyThing</code>
85.66 - * @see Lookups#metaInfServices(ClassLoader)
85.67 - * @since org.openide.util 7.20
85.68 - */
85.69 -@Retention(RetentionPolicy.SOURCE)
85.70 -@Target(ElementType.TYPE)
85.71 -public @interface ServiceProvider {
85.72 -
85.73 - /**
85.74 - * The interface (or abstract class) to register this implementation under.
85.75 - * It is an error if the implementation class is not in fact assignable to the interface.
85.76 - * <p>If you need to register one class under multiple interfaces, use {@link ServiceProviders}.
85.77 - * <p>Requests to look up the specified interface should result in this implementation.
85.78 - * Requests for any other types may or may not result in this implementation even if the
85.79 - * implementation is assignable to those types.
85.80 - */
85.81 - Class<?> service();
85.82 -
85.83 - /**
85.84 - * An optional position in which to register this service relative to others.
85.85 - * Lower-numbered services are returned in the lookup result first.
85.86 - * Services with no specified position are returned last.
85.87 - */
85.88 - int position() default Integer.MAX_VALUE;
85.89 -
85.90 - /**
85.91 - * An optional list of implementations (given as fully-qualified class names) which this implementation supersedes.
85.92 - * If specified, those implementations will not be loaded even if they were registered.
85.93 - * Useful on occasion to cancel a generic implementation and replace it with a more advanced one.
85.94 - */
85.95 - String[] supersedes() default {};
85.96 -
85.97 - /**
85.98 - * An optional path to register this implementation in.
85.99 - * For example, <code>Projects/sometype/Nodes</code> could be used.
85.100 - * This style of registration would be recognized by {@link Lookups#forPath}
85.101 - * rather than {@link Lookup#getDefault}.
85.102 - */
85.103 - String path() default "";
85.104 -
85.105 -}
86.1 --- a/openide.util/src/org/openide/util/lookup/ServiceProviders.java Sat Oct 31 15:06:58 2009 +0100
86.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
86.3 @@ -1,60 +0,0 @@
86.4 -/*
86.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
86.6 - *
86.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
86.8 - *
86.9 - * The contents of this file are subject to the terms of either the GNU
86.10 - * General Public License Version 2 only ("GPL") or the Common
86.11 - * Development and Distribution License("CDDL") (collectively, the
86.12 - * "License"). You may not use this file except in compliance with the
86.13 - * License. You can obtain a copy of the License at
86.14 - * http://www.netbeans.org/cddl-gplv2.html
86.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
86.16 - * specific language governing permissions and limitations under the
86.17 - * License. When distributing the software, include this License Header
86.18 - * Notice in each file and include the License file at
86.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
86.20 - * particular file as subject to the "Classpath" exception as provided
86.21 - * by Sun in the GPL Version 2 section of the License file that
86.22 - * accompanied this code. If applicable, add the following below the
86.23 - * License Header, with the fields enclosed by brackets [] replaced by
86.24 - * your own identifying information:
86.25 - * "Portions Copyrighted [year] [name of copyright owner]"
86.26 - *
86.27 - * If you wish your version of this file to be governed by only the CDDL
86.28 - * or only the GPL Version 2, indicate your decision by adding
86.29 - * "[Contributor] elects to include this software in this distribution
86.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
86.31 - * single choice of license, a recipient has the option to distribute
86.32 - * your version of this file under either the CDDL, the GPL Version 2 or
86.33 - * to extend the choice of license to its licensees as provided above.
86.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
86.35 - * Version 2 license, then the option applies only if the new code is
86.36 - * made subject to such option by the copyright holder.
86.37 - *
86.38 - * Contributor(s):
86.39 - *
86.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
86.41 - */
86.42 -
86.43 -package org.openide.util.lookup;
86.44 -
86.45 -import java.lang.annotation.ElementType;
86.46 -import java.lang.annotation.Retention;
86.47 -import java.lang.annotation.RetentionPolicy;
86.48 -import java.lang.annotation.Target;
86.49 -
86.50 -/**
86.51 - * Similar to {@link ServiceProvider} but permits multiple registrations of one class.
86.52 - * @since org.openide.util 7.20
86.53 - */
86.54 -@Retention(RetentionPolicy.SOURCE)
86.55 -@Target(ElementType.TYPE)
86.56 -public @interface ServiceProviders {
86.57 -
86.58 - /**
86.59 - * List of service provider registrations.
86.60 - */
86.61 - ServiceProvider[] value();
86.62 -
86.63 -}
87.1 --- a/openide.util/src/org/openide/util/lookup/SimpleLookup.java Sat Oct 31 15:06:58 2009 +0100
87.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
87.3 @@ -1,250 +0,0 @@
87.4 -/*
87.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
87.6 - *
87.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
87.8 - *
87.9 - * The contents of this file are subject to the terms of either the GNU
87.10 - * General Public License Version 2 only ("GPL") or the Common
87.11 - * Development and Distribution License("CDDL") (collectively, the
87.12 - * "License"). You may not use this file except in compliance with the
87.13 - * License. You can obtain a copy of the License at
87.14 - * http://www.netbeans.org/cddl-gplv2.html
87.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
87.16 - * specific language governing permissions and limitations under the
87.17 - * License. When distributing the software, include this License Header
87.18 - * Notice in each file and include the License file at
87.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
87.20 - * particular file as subject to the "Classpath" exception as provided
87.21 - * by Sun in the GPL Version 2 section of the License file that
87.22 - * accompanied this code. If applicable, add the following below the
87.23 - * License Header, with the fields enclosed by brackets [] replaced by
87.24 - * your own identifying information:
87.25 - * "Portions Copyrighted [year] [name of copyright owner]"
87.26 - *
87.27 - * Contributor(s):
87.28 - *
87.29 - * The Original Software is NetBeans. The Initial Developer of the Original
87.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
87.31 - * Microsystems, Inc. All Rights Reserved.
87.32 - *
87.33 - * If you wish your version of this file to be governed by only the CDDL
87.34 - * or only the GPL Version 2, indicate your decision by adding
87.35 - * "[Contributor] elects to include this software in this distribution
87.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
87.37 - * single choice of license, a recipient has the option to distribute
87.38 - * your version of this file under either the CDDL, the GPL Version 2 or
87.39 - * to extend the choice of license to its licensees as provided above.
87.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
87.41 - * Version 2 license, then the option applies only if the new code is
87.42 - * made subject to such option by the copyright holder.
87.43 - */
87.44 -package org.openide.util.lookup;
87.45 -
87.46 -import org.openide.util.Lookup;
87.47 -import org.openide.util.LookupListener;
87.48 -
87.49 -import java.util.*;
87.50 -
87.51 -
87.52 -/**
87.53 - * Simple lookup implementation. It can be used to create temporary lookups
87.54 - * that do not change over time. The result stores references to all objects
87.55 - * passed in the constructor. Those objecst are the only ones returned as
87.56 - * result.
87.57 - * @author David Strupl
87.58 - */
87.59 -class SimpleLookup extends org.openide.util.Lookup {
87.60 - /** This variable is initialized in constructor and thus null
87.61 - * value is not allowed as its value. */
87.62 - private Collection<Item<?>> allItems;
87.63 -
87.64 - /**
87.65 - * Creates new Result object with supplied instances parameter.
87.66 - * @param instances to be used to return from the lookup
87.67 - */
87.68 - SimpleLookup(Collection<Object> instances) {
87.69 - allItems = new ArrayList<Item<?>>(instances.size());
87.70 -
87.71 - for (Iterator i = instances.iterator(); i.hasNext();) {
87.72 - allItems.add(new InstanceContent.SimpleItem<Object>(i.next()));
87.73 - }
87.74 - }
87.75 -
87.76 - <T,R> SimpleLookup(Collection<T> keys, InstanceContent.Convertor<? super T,R> conv) {
87.77 - allItems = new ArrayList<Item<?>>(keys.size());
87.78 -
87.79 - for (T item : keys) {
87.80 - allItems.add(new InstanceContent.ConvertingItem<T,R>(item, conv));
87.81 - }
87.82 - }
87.83 -
87.84 - public String toString() {
87.85 - return "SimpleLookup" + lookup(new Template<Object>(Object.class)).allInstances();
87.86 - }
87.87 -
87.88 - public <T> Result<T> lookup(Template<T> template) {
87.89 - if (template == null) {
87.90 - throw new NullPointerException();
87.91 - }
87.92 -
87.93 - return new SimpleResult<T>(template);
87.94 - }
87.95 -
87.96 - public <T> T lookup(Class<T> clazz) {
87.97 - for (Iterator i = allItems.iterator(); i.hasNext();) {
87.98 - Object o = i.next();
87.99 -
87.100 - if (o instanceof AbstractLookup.Pair) {
87.101 - AbstractLookup.Pair<?> p = (AbstractLookup.Pair<?>)o;
87.102 - if (p.instanceOf(clazz)) {
87.103 - Object ret = p.getInstance();
87.104 - if (clazz.isInstance(ret)) {
87.105 - return clazz.cast(ret);
87.106 - }
87.107 - }
87.108 - }
87.109 - }
87.110 - return null;
87.111 - }
87.112 -
87.113 - /** A method that defines matching between Item and Template.
87.114 - * @param item the item to match
87.115 - * @return true if item matches the template requirements, false if not
87.116 - */
87.117 - private static boolean matches(Template<?> t, AbstractLookup.Pair<?> item) {
87.118 - if (!AbstractLookup.matches(t, item, true)) {
87.119 - return false;
87.120 - }
87.121 -
87.122 - Class<?> type = t.getType();
87.123 -
87.124 - if ((type != null) && !type.isAssignableFrom(item.getType())) {
87.125 - return false;
87.126 - }
87.127 -
87.128 - return true;
87.129 - }
87.130 -
87.131 - /**
87.132 - * Result used in SimpleLookup. It holds a reference to the collection
87.133 - * passed in constructor. As the contents of this lookup result never
87.134 - * changes the addLookupListener and removeLookupListener are empty.
87.135 - */
87.136 - private class SimpleResult<T> extends Lookup.Result<T> {
87.137 - /** can be null and is initialized lazily */
87.138 - private Set<Class<? extends T>> classes;
87.139 -
87.140 - /** can be null and is initialized lazily */
87.141 - private Collection<? extends Item<T>> items;
87.142 -
87.143 - /** Template used for this result. It is never null.*/
87.144 - private Template<T> template;
87.145 -
87.146 - /** can be null and is initialized lazily */
87.147 - private Collection<T> results;
87.148 -
87.149 - /** Just remembers the supplied argument in variable template.*/
87.150 - SimpleResult(Template<T> template) {
87.151 - this.template = template;
87.152 - }
87.153 -
87.154 - /**
87.155 - * Intentionally does nothing because the lookup does not change
87.156 - * and no notification is needed.
87.157 - */
87.158 - public void addLookupListener(LookupListener l) {
87.159 - }
87.160 -
87.161 - /**
87.162 - * Intentionally does nothing because the lookup does not change
87.163 - * and no notification is needed.
87.164 - */
87.165 - public void removeLookupListener(LookupListener l) {
87.166 - }
87.167 -
87.168 - /**
87.169 - * Lazy initializes the results collection. Uses a call to allItems
87.170 - * to obtain the instances.
87.171 - */
87.172 - public java.util.Collection<? extends T> allInstances() {
87.173 - synchronized (this) {
87.174 - if (results != null) {
87.175 - return results;
87.176 - }
87.177 - }
87.178 -
87.179 -
87.180 - Collection<T> res = new ArrayList<T>(allItems.size());
87.181 -
87.182 - for (Item<T> item : allItems()) {
87.183 - res.add(item.getInstance());
87.184 - }
87.185 -
87.186 - synchronized (this) {
87.187 - results = Collections.unmodifiableCollection(res);
87.188 - }
87.189 -
87.190 - return results;
87.191 - }
87.192 -
87.193 - /**
87.194 - * Lazy initializes variable classes. Uses a call to allItems to
87.195 - * compute the result.
87.196 - */
87.197 - public Set<Class<? extends T>> allClasses() {
87.198 - synchronized (this) {
87.199 - if (classes != null) {
87.200 - return classes;
87.201 - }
87.202 - }
87.203 -
87.204 - Set<Class<? extends T>> res = new HashSet<Class<? extends T>>();
87.205 -
87.206 - for (Item<T> item : allItems()) {
87.207 - res.add(item.getType());
87.208 - }
87.209 -
87.210 - synchronized (this) {
87.211 - classes = Collections.unmodifiableSet(res);
87.212 - }
87.213 -
87.214 - return classes;
87.215 - }
87.216 -
87.217 - /**
87.218 - * Lazy initializes variable items. Creates an item for each
87.219 - * element in the instances collection. It puts either SimpleItem
87.220 - * or ConvertingItem to the collection.
87.221 - */
87.222 - public Collection<? extends Item<T>> allItems() {
87.223 - synchronized (this) {
87.224 - if (items != null) {
87.225 - return items;
87.226 - }
87.227 - }
87.228 -
87.229 - Collection<Item<T>> res = new ArrayList<Item<T>>(allItems.size());
87.230 -
87.231 - for (Iterator<Item<?>> i = allItems.iterator(); i.hasNext();) {
87.232 - Item<?> o = i.next();
87.233 -
87.234 - if (o instanceof AbstractLookup.Pair) {
87.235 - if (matches(template, (AbstractLookup.Pair) o)) {
87.236 - res.add(cast(o));
87.237 - }
87.238 - }
87.239 - }
87.240 -
87.241 - synchronized (this) {
87.242 - items = Collections.unmodifiableCollection(res);
87.243 - }
87.244 -
87.245 - return items;
87.246 - }
87.247 -
87.248 - @SuppressWarnings("unchecked")
87.249 - private Item<T> cast(Item<?> i) {
87.250 - return (Item<T>)i;
87.251 - }
87.252 - }
87.253 -}
88.1 --- a/openide.util/src/org/openide/util/lookup/SimpleProxyLookup.java Sat Oct 31 15:06:58 2009 +0100
88.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
88.3 @@ -1,359 +0,0 @@
88.4 -/*
88.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
88.6 - *
88.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
88.8 - *
88.9 - * The contents of this file are subject to the terms of either the GNU
88.10 - * General Public License Version 2 only ("GPL") or the Common
88.11 - * Development and Distribution License("CDDL") (collectively, the
88.12 - * "License"). You may not use this file except in compliance with the
88.13 - * License. You can obtain a copy of the License at
88.14 - * http://www.netbeans.org/cddl-gplv2.html
88.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
88.16 - * specific language governing permissions and limitations under the
88.17 - * License. When distributing the software, include this License Header
88.18 - * Notice in each file and include the License file at
88.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
88.20 - * particular file as subject to the "Classpath" exception as provided
88.21 - * by Sun in the GPL Version 2 section of the License file that
88.22 - * accompanied this code. If applicable, add the following below the
88.23 - * License Header, with the fields enclosed by brackets [] replaced by
88.24 - * your own identifying information:
88.25 - * "Portions Copyrighted [year] [name of copyright owner]"
88.26 - *
88.27 - * Contributor(s):
88.28 - *
88.29 - * The Original Software is NetBeans. The Initial Developer of the Original
88.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
88.31 - * Microsystems, Inc. All Rights Reserved.
88.32 - *
88.33 - * If you wish your version of this file to be governed by only the CDDL
88.34 - * or only the GPL Version 2, indicate your decision by adding
88.35 - * "[Contributor] elects to include this software in this distribution
88.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
88.37 - * single choice of license, a recipient has the option to distribute
88.38 - * your version of this file under either the CDDL, the GPL Version 2 or
88.39 - * to extend the choice of license to its licensees as provided above.
88.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
88.41 - * Version 2 license, then the option applies only if the new code is
88.42 - * made subject to such option by the copyright holder.
88.43 - */
88.44 -package org.openide.util.lookup;
88.45 -
88.46 -import java.lang.ref.Reference;
88.47 -import java.lang.ref.WeakReference;
88.48 -import org.openide.util.Lookup;
88.49 -import org.openide.util.LookupEvent;
88.50 -import org.openide.util.LookupListener;
88.51 -
88.52 -import java.util.*;
88.53 -
88.54 -
88.55 -/**
88.56 - * Simple proxy lookup. Keeps reference to a lookup it delegates to and
88.57 - * forwards all requests.
88.58 - *
88.59 - * @author Jaroslav Tulach
88.60 - */
88.61 -final class SimpleProxyLookup extends org.openide.util.Lookup {
88.62 - /** the provider to check for the status */
88.63 - private Provider provider;
88.64 -
88.65 - /** the lookup we currently delegate to */
88.66 - private Lookup delegate;
88.67 -
88.68 - /** map of all templates to Reference (results) associated to this lookup */
88.69 - private WeakHashMap<Template<?>,Reference<ProxyResult<?>>> results;
88.70 -
88.71 - /**
88.72 - * @param provider provider to delegate to
88.73 - */
88.74 - SimpleProxyLookup(Provider provider) {
88.75 - this.provider = provider;
88.76 - }
88.77 -
88.78 - /** Checks whether we still delegate to the same lookup */
88.79 - private Lookup checkLookup() {
88.80 - Lookup l = provider.getLookup();
88.81 -
88.82 - // iterator over Reference (ProxyResult)
88.83 - Iterator<Reference<ProxyResult<?>>> toCheck = null;
88.84 -
88.85 - synchronized (this) {
88.86 - if (l != delegate) {
88.87 - this.delegate = l;
88.88 -
88.89 - if (results != null) {
88.90 - toCheck = new ArrayList<Reference<ProxyResult<?>>>(results.values()).iterator();
88.91 - }
88.92 - }
88.93 - }
88.94 -
88.95 - if (toCheck != null) {
88.96 - // update
88.97 - ArrayList<Object> evAndListeners = new ArrayList<Object>();
88.98 - for (Iterator<Reference<ProxyResult<?>>> it = toCheck; it.hasNext(); ) {
88.99 - java.lang.ref.Reference<ProxyResult<?>> ref = it.next();
88.100 - if (ref == null) {
88.101 - continue;
88.102 - }
88.103 -
88.104 - ProxyResult<?> p = ref.get();
88.105 -
88.106 - if (p != null && p.updateLookup(l)) {
88.107 - p.collectFires(evAndListeners);
88.108 - }
88.109 - }
88.110 -
88.111 - for (Iterator it = evAndListeners.iterator(); it.hasNext(); ) {
88.112 - LookupEvent ev = (LookupEvent)it.next();
88.113 - LookupListener ll = (LookupListener)it.next();
88.114 - ll.resultChanged(ev);
88.115 - }
88.116 - }
88.117 -
88.118 - return delegate;
88.119 - }
88.120 -
88.121 - @SuppressWarnings("unchecked")
88.122 - private static <T> ProxyResult<T> cast(ProxyResult<?> p) {
88.123 - return (ProxyResult<T>)p;
88.124 - }
88.125 -
88.126 - public <T> Result<T> lookup(Template<T> template) {
88.127 - synchronized (this) {
88.128 - if (results == null) {
88.129 - results = new WeakHashMap<Template<?>,Reference<ProxyResult<?>>>();
88.130 - } else {
88.131 - Reference<ProxyResult<?>> ref = results.get(template);
88.132 -
88.133 - if (ref != null) {
88.134 - ProxyResult<?> p = ref.get();
88.135 -
88.136 - if (p != null) {
88.137 - return cast(p);
88.138 - }
88.139 - }
88.140 - }
88.141 -
88.142 - ProxyResult<T> p = new ProxyResult<T>(template);
88.143 - Reference<ProxyResult<?>> ref = new WeakReference<ProxyResult<?>>(p);
88.144 - results.put(template, ref);
88.145 -
88.146 - return p;
88.147 - }
88.148 - }
88.149 -
88.150 - public <T> T lookup(Class<T> clazz) {
88.151 - if (clazz == null) {
88.152 - checkLookup();
88.153 - return null;
88.154 - }
88.155 - return checkLookup().lookup(clazz);
88.156 - }
88.157 -
88.158 - public <T> Item<T> lookupItem(Template<T> template) {
88.159 - return checkLookup().lookupItem(template);
88.160 - }
88.161 -
88.162 - /**
88.163 - * Result used in SimpleLookup. It holds a reference to the collection
88.164 - * passed in constructor. As the contents of this lookup result never
88.165 - * changes the addLookupListener and removeLookupListener are empty.
88.166 - */
88.167 - private final class ProxyResult<T> extends WaitableResult<T> implements LookupListener {
88.168 - /** Template used for this result. It is never null.*/
88.169 - private Template<T> template;
88.170 -
88.171 - /** result to delegate to */
88.172 - private Lookup.Result<T> delegate;
88.173 -
88.174 - /** listeners set */
88.175 - private javax.swing.event.EventListenerList listeners;
88.176 - private LookupListener lastListener;
88.177 -
88.178 - /** Just remembers the supplied argument in variable template.*/
88.179 - ProxyResult(Template<T> template) {
88.180 - this.template = template;
88.181 - }
88.182 -
88.183 - /** Checks state of the result
88.184 - */
88.185 - private Result<T> checkResult() {
88.186 - updateLookup(checkLookup());
88.187 -
88.188 - return this.delegate;
88.189 - }
88.190 -
88.191 - /** Updates the state of the lookup.
88.192 - * @return true if the lookup really changed
88.193 - */
88.194 - public boolean updateLookup(Lookup l) {
88.195 - Collection<? extends Item<T>> oldPairs = (delegate != null) ? delegate.allItems() : null;
88.196 -
88.197 - LookupListener removedListener;
88.198 -
88.199 - synchronized (this) {
88.200 - if ((delegate != null) && (lastListener != null)) {
88.201 - removedListener = lastListener;
88.202 - delegate.removeLookupListener(lastListener);
88.203 - } else {
88.204 - removedListener = null;
88.205 - }
88.206 - }
88.207 -
88.208 - // cannot call to foreign code
88.209 - Lookup.Result<T> res = l.lookup(template);
88.210 -
88.211 - synchronized (this) {
88.212 - if (removedListener == lastListener) {
88.213 - delegate = res;
88.214 - lastListener = new WeakResult<T>(this, delegate);
88.215 - delegate.addLookupListener(lastListener);
88.216 - }
88.217 - }
88.218 -
88.219 - if (oldPairs == null) {
88.220 - // nobody knows about a change
88.221 - return false;
88.222 - }
88.223 -
88.224 - Collection<? extends Item<T>> newPairs = delegate.allItems();
88.225 -
88.226 - // See #34961 for explanation.
88.227 - if (!(oldPairs instanceof List)) {
88.228 - if (oldPairs == Collections.EMPTY_SET) {
88.229 - // avoid allocation
88.230 - oldPairs = Collections.emptyList();
88.231 - } else {
88.232 - oldPairs = new ArrayList<Item<T>>(oldPairs);
88.233 - }
88.234 - }
88.235 -
88.236 - if (!(newPairs instanceof List)) {
88.237 - newPairs = new ArrayList<Item<T>>(newPairs);
88.238 - }
88.239 -
88.240 - return !oldPairs.equals(newPairs);
88.241 - }
88.242 -
88.243 - public synchronized void addLookupListener(LookupListener l) {
88.244 - if (listeners == null) {
88.245 - listeners = new javax.swing.event.EventListenerList();
88.246 - }
88.247 -
88.248 - listeners.add(LookupListener.class, l);
88.249 - }
88.250 -
88.251 - public synchronized void removeLookupListener(LookupListener l) {
88.252 - if (listeners != null) {
88.253 - listeners.remove(LookupListener.class, l);
88.254 - }
88.255 - }
88.256 -
88.257 - public java.util.Collection<? extends T> allInstances() {
88.258 - return checkResult().allInstances();
88.259 - }
88.260 -
88.261 - public Set<Class<? extends T>> allClasses() {
88.262 - return checkResult().allClasses();
88.263 - }
88.264 -
88.265 - public Collection<? extends Item<T>> allItems() {
88.266 - return checkResult().allItems();
88.267 - }
88.268 -
88.269 - protected void beforeLookup(Lookup.Template t) {
88.270 - Lookup.Result r = checkResult();
88.271 -
88.272 - if (r instanceof WaitableResult) {
88.273 - ((WaitableResult) r).beforeLookup(t);
88.274 - }
88.275 - }
88.276 -
88.277 - /** A change in lookup occured.
88.278 - * @param ev event describing the change
88.279 - *
88.280 - */
88.281 - public void resultChanged(LookupEvent anEvent) {
88.282 - collectFires(null);
88.283 - }
88.284 -
88.285 - protected void collectFires(Collection<Object> evAndListeners) {
88.286 - javax.swing.event.EventListenerList l = this.listeners;
88.287 -
88.288 - if (l == null) {
88.289 - return;
88.290 - }
88.291 -
88.292 - Object[] listeners = l.getListenerList();
88.293 -
88.294 - if (listeners.length == 0) {
88.295 - return;
88.296 - }
88.297 -
88.298 - LookupEvent ev = new LookupEvent(this);
88.299 - AbstractLookup.notifyListeners(listeners, ev, evAndListeners);
88.300 - }
88.301 - }
88.302 - // end of ProxyResult
88.303 - private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
88.304 - private Lookup.Result source;
88.305 - private Reference<ProxyResult<T>> result;
88.306 -
88.307 - public WeakResult(ProxyResult<T> r, Lookup.Result<T> s) {
88.308 - this.result = new WeakReference<ProxyResult<T>>(r);
88.309 - this.source = s;
88.310 - }
88.311 -
88.312 - protected void beforeLookup(Lookup.Template t) {
88.313 - ProxyResult r = (ProxyResult)result.get();
88.314 - if (r != null) {
88.315 - r.beforeLookup(t);
88.316 - } else {
88.317 - source.removeLookupListener(this);
88.318 - }
88.319 - }
88.320 -
88.321 - protected void collectFires(Collection<Object> evAndListeners) {
88.322 - ProxyResult<T> r = result.get();
88.323 - if (r != null) {
88.324 - r.collectFires(evAndListeners);
88.325 - } else {
88.326 - source.removeLookupListener(this);
88.327 - }
88.328 - }
88.329 -
88.330 - public void addLookupListener(LookupListener l) {
88.331 - assert false;
88.332 - }
88.333 -
88.334 - public void removeLookupListener(LookupListener l) {
88.335 - assert false;
88.336 - }
88.337 -
88.338 - public Collection<T> allInstances() {
88.339 - assert false;
88.340 - return null;
88.341 - }
88.342 -
88.343 - public void resultChanged(LookupEvent ev) {
88.344 - ProxyResult r = (ProxyResult)result.get();
88.345 - if (r != null) {
88.346 - r.resultChanged(ev);
88.347 - } else {
88.348 - source.removeLookupListener(this);
88.349 - }
88.350 - }
88.351 -
88.352 - public Collection<? extends Item<T>> allItems() {
88.353 - assert false;
88.354 - return null;
88.355 - }
88.356 -
88.357 - public Set<Class<? extends T>> allClasses() {
88.358 - assert false;
88.359 - return null;
88.360 - }
88.361 - } // end of WeakResult
88.362 -}
89.1 --- a/openide.util/src/org/openide/util/lookup/SingletonLookup.java Sat Oct 31 15:06:58 2009 +0100
89.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
89.3 @@ -1,173 +0,0 @@
89.4 -/*
89.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
89.6 - *
89.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
89.8 - *
89.9 - * The contents of this file are subject to the terms of either the GNU
89.10 - * General Public License Version 2 only ("GPL") or the Common
89.11 - * Development and Distribution License("CDDL") (collectively, the
89.12 - * "License"). You may not use this file except in compliance with the
89.13 - * License. You can obtain a copy of the License at
89.14 - * http://www.netbeans.org/cddl-gplv2.html
89.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
89.16 - * specific language governing permissions and limitations under the
89.17 - * License. When distributing the software, include this License Header
89.18 - * Notice in each file and include the License file at
89.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
89.20 - * particular file as subject to the "Classpath" exception as provided
89.21 - * by Sun in the GPL Version 2 section of the License file that
89.22 - * accompanied this code. If applicable, add the following below the
89.23 - * License Header, with the fields enclosed by brackets [] replaced by
89.24 - * your own identifying information:
89.25 - * "Portions Copyrighted [year] [name of copyright owner]"
89.26 - *
89.27 - * If you wish your version of this file to be governed by only the CDDL
89.28 - * or only the GPL Version 2, indicate your decision by adding
89.29 - * "[Contributor] elects to include this software in this distribution
89.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
89.31 - * single choice of license, a recipient has the option to distribute
89.32 - * your version of this file under either the CDDL, the GPL Version 2 or
89.33 - * to extend the choice of license to its licensees as provided above.
89.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
89.35 - * Version 2 license, then the option applies only if the new code is
89.36 - * made subject to such option by the copyright holder.
89.37 - *
89.38 - * Contributor(s):
89.39 - *
89.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
89.41 - */
89.42 -
89.43 -package org.openide.util.lookup;
89.44 -
89.45 -import java.util.Collection;
89.46 -import java.util.Collections;
89.47 -import java.util.Set;
89.48 -import org.openide.util.Lookup;
89.49 -import org.openide.util.LookupListener;
89.50 -
89.51 -/**
89.52 - * Unmodifiable lookup that contains just one fixed object.
89.53 - *
89.54 - * @author Marian Petras
89.55 - */
89.56 -class SingletonLookup extends Lookup {
89.57 -
89.58 - private final Object objectToLookup;
89.59 - private final String id;
89.60 -
89.61 - SingletonLookup(Object objectToLookup) {
89.62 - this(objectToLookup, null);
89.63 - }
89.64 -
89.65 - SingletonLookup(Object objectToLookup, String id) {
89.66 - if (objectToLookup == null) {
89.67 - throw new IllegalArgumentException("null"); //NOI18N
89.68 - }
89.69 -
89.70 - this.objectToLookup = objectToLookup;
89.71 - this.id = id;
89.72 - }
89.73 -
89.74 - @Override
89.75 - public <T> T lookup(Class<T> clazz) {
89.76 - if (clazz == null) {
89.77 - throw new IllegalArgumentException("null"); //NOI18N
89.78 - }
89.79 -
89.80 - return (clazz.isInstance(objectToLookup))
89.81 - ? clazz.cast(objectToLookup)
89.82 - : null;
89.83 - }
89.84 -
89.85 - @Override
89.86 - public <T> Result<T> lookup(Template<T> template) {
89.87 - if (template == null) {
89.88 - throw new IllegalArgumentException("null"); //NOI18N
89.89 - }
89.90 -
89.91 - Lookup.Item<T> item = lookupItem(template);
89.92 - if (item != null) {
89.93 - return new SingletonResult<T>(item);
89.94 - } else {
89.95 - return Lookup.EMPTY.lookup(template);
89.96 - }
89.97 - }
89.98 -
89.99 - @Override
89.100 - public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
89.101 - if (clazz == null) {
89.102 - throw new IllegalArgumentException("null"); //NOI18N
89.103 - }
89.104 -
89.105 - return (clazz.isInstance(objectToLookup))
89.106 - ? Collections.singletonList(clazz.cast(objectToLookup))
89.107 - : Collections.<T>emptyList();
89.108 - }
89.109 -
89.110 - @Override
89.111 - @SuppressWarnings("unchecked")
89.112 - public <T> Item<T> lookupItem(Template<T> template) {
89.113 - if (template == null) {
89.114 - throw new IllegalArgumentException("null"); //NOI18N
89.115 - }
89.116 -
89.117 - String templateId = template.getId();
89.118 - if ((templateId != null) && !templateId.equals(id)) {
89.119 - return null;
89.120 - }
89.121 -
89.122 - Object templateInst = template.getInstance();
89.123 - if ((templateInst != null) && (objectToLookup != templateInst)) {
89.124 - return null;
89.125 - }
89.126 -
89.127 - Class<T> clazz = template.getType();
89.128 - if ((clazz != null) && !clazz.isInstance(objectToLookup)) {
89.129 - return null;
89.130 - }
89.131 -
89.132 - Lookup.Item<T> item;
89.133 - if (clazz != null) {
89.134 - item = Lookups.lookupItem(clazz.cast(objectToLookup), id);
89.135 - } else {
89.136 - item = Lookups.lookupItem((T) objectToLookup, id);
89.137 - }
89.138 - return item;
89.139 - }
89.140 -
89.141 - static class SingletonResult<T> extends Lookup.Result<T> {
89.142 -
89.143 - private final Lookup.Item<T> item;
89.144 -
89.145 - SingletonResult(Lookup.Item<T> item) {
89.146 - this.item = item;
89.147 - }
89.148 -
89.149 - @Override
89.150 - public void addLookupListener(LookupListener l) {
89.151 - // this result never changes - no need to register a listener
89.152 - }
89.153 -
89.154 - @Override
89.155 - public void removeLookupListener(LookupListener l) {
89.156 - // this result never changes - no need to register a listener
89.157 - }
89.158 -
89.159 - @Override
89.160 - public Set<Class<? extends T>> allClasses() {
89.161 - return Collections.<Class<? extends T>>singleton(item.getType());
89.162 - }
89.163 -
89.164 - @Override
89.165 - public Collection<? extends Item<T>> allItems() {
89.166 - return Collections.singletonList(item);
89.167 - }
89.168 -
89.169 - @Override
89.170 - public Collection<? extends T> allInstances() {
89.171 - return Collections.singletonList(item.getInstance());
89.172 - }
89.173 -
89.174 - }
89.175 -
89.176 -}
90.1 --- a/openide.util/src/org/openide/util/lookup/WaitableResult.java Sat Oct 31 15:06:58 2009 +0100
90.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
90.3 @@ -1,62 +0,0 @@
90.4 -/*
90.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
90.6 - *
90.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
90.8 - *
90.9 - * The contents of this file are subject to the terms of either the GNU
90.10 - * General Public License Version 2 only ("GPL") or the Common
90.11 - * Development and Distribution License("CDDL") (collectively, the
90.12 - * "License"). You may not use this file except in compliance with the
90.13 - * License. You can obtain a copy of the License at
90.14 - * http://www.netbeans.org/cddl-gplv2.html
90.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
90.16 - * specific language governing permissions and limitations under the
90.17 - * License. When distributing the software, include this License Header
90.18 - * Notice in each file and include the License file at
90.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
90.20 - * particular file as subject to the "Classpath" exception as provided
90.21 - * by Sun in the GPL Version 2 section of the License file that
90.22 - * accompanied this code. If applicable, add the following below the
90.23 - * License Header, with the fields enclosed by brackets [] replaced by
90.24 - * your own identifying information:
90.25 - * "Portions Copyrighted [year] [name of copyright owner]"
90.26 - *
90.27 - * Contributor(s):
90.28 - *
90.29 - * The Original Software is NetBeans. The Initial Developer of the Original
90.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
90.31 - * Microsystems, Inc. All Rights Reserved.
90.32 - *
90.33 - * If you wish your version of this file to be governed by only the CDDL
90.34 - * or only the GPL Version 2, indicate your decision by adding
90.35 - * "[Contributor] elects to include this software in this distribution
90.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
90.37 - * single choice of license, a recipient has the option to distribute
90.38 - * your version of this file under either the CDDL, the GPL Version 2 or
90.39 - * to extend the choice of license to its licensees as provided above.
90.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
90.41 - * Version 2 license, then the option applies only if the new code is
90.42 - * made subject to such option by the copyright holder.
90.43 - */
90.44 -package org.openide.util.lookup;
90.45 -
90.46 -import java.util.Collection;
90.47 -import org.openide.util.Lookup;
90.48 -
90.49 -
90.50 -/** A special subclass of lookup that is able to wait before queries.
90.51 - *
90.52 - * @author Jaroslav Tulach
90.53 - */
90.54 -abstract class WaitableResult<T> extends Lookup.Result<T> {
90.55 - /** Used by proxy results to synchronize before lookup.
90.56 - */
90.57 - protected abstract void beforeLookup(Lookup.Template t);
90.58 -
90.59 - /** Needed to group notification of outside the package listeners
90.60 - * after all AbstractLookup and ProxyLookups have been updated.
90.61 - * @param evAndListeners LookupEvent, LookupListener, LookupEvent, LookupListener, etc.
90.62 - */
90.63 - protected abstract void collectFires(Collection<Object> evAndListeners);
90.64 -
90.65 -}
91.1 --- a/openide.util/src/org/openide/util/lookup/doc-files/index.html Sat Oct 31 15:06:58 2009 +0100
91.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
91.3 @@ -1,208 +0,0 @@
91.4 -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
91.5 -<!--
91.6 - - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
91.7 - -
91.8 - - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
91.9 - -
91.10 - - The contents of this file are subject to the terms of either the GNU
91.11 - - General Public License Version 2 only ("GPL") or the Common
91.12 - - Development and Distribution License("CDDL") (collectively, the
91.13 - - "License"). You may not use this file except in compliance with the
91.14 - - License. You can obtain a copy of the License at
91.15 - - http://www.netbeans.org/cddl-gplv2.html
91.16 - - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
91.17 - - specific language governing permissions and limitations under the
91.18 - - License. When distributing the software, include this License Header
91.19 - - Notice in each file and include the License file at
91.20 - - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
91.21 - - particular file as subject to the "Classpath" exception as provided
91.22 - - by Sun in the GPL Version 2 section of the License file that
91.23 - - accompanied this code. If applicable, add the following below the
91.24 - - License Header, with the fields enclosed by brackets [] replaced by
91.25 - - your own identifying information:
91.26 - - "Portions Copyrighted [year] [name of copyright owner]"
91.27 - -
91.28 - - Contributor(s):
91.29 - -
91.30 - - The Original Software is NetBeans. The Initial Developer of the Original
91.31 - - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
91.32 - - Microsystems, Inc. All Rights Reserved.
91.33 - -
91.34 - - If you wish your version of this file to be governed by only the CDDL
91.35 - - or only the GPL Version 2, indicate your decision by adding
91.36 - - "[Contributor] elects to include this software in this distribution
91.37 - - under the [CDDL or GPL Version 2] license." If you do not indicate a
91.38 - - single choice of license, a recipient has the option to distribute
91.39 - - your version of this file under either the CDDL, the GPL Version 2 or
91.40 - - to extend the choice of license to its licensees as provided above.
91.41 - - However, if you add GPL Version 2 code and therefore, elected the GPL
91.42 - - Version 2 license, then the option applies only if the new code is
91.43 - - made subject to such option by the copyright holder.
91.44 - -->
91.45 -<HTML>
91.46 -<HEAD>
91.47 -<TITLE>Lookup Library</TITLE>
91.48 -<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
91.49 -</HEAD>
91.50 -<BODY>
91.51 -
91.52 -<P>
91.53 -
91.54 -This is the home page of the <em>lookup library</em> implementation, which
91.55 -is intended to solve a general problem that every <cite>component-based system</CITE>
91.56 -has had to face: how different components <b>register</b> to the system
91.57 -and how other parts of the system can <b>look</b> them <b>up</B>.
91.58 -<P>
91.59 -There already are libraries trying to solve this problem, usually by querying for
91.60 -an interface and finding its appropriate implementaion. The most famous is
91.61 -<A href="http://www.jini.org/">Jini</A>, the platform for development of
91.62 -distributed network services. Our library does something similar, but tries
91.63 -to stay small and easy
91.64 -to use. The NetBeans <em>Lookup
91.65 -Library</EM>'s main focus is a modular application consisting of independent modules
91.66 -that want to communicate with each other. It does not try to solve networking or
91.67 -legacy application integration. It is simple but powerful.
91.68 -
91.69 -<H2>Why would you want to use it?</H2>
91.70 -
91.71 -A well-written modular program separates <em>development</EM>
91.72 -and <em>deployment</EM>.
91.73 -There are many situations where a component needs some functionality but
91.74 -does not actually care about the implementation. It is up to the <em>system
91.75 -adminstrator</em> that deploys (installs) the application to decide which
91.76 -implementation to use.
91.77 -<P>
91.78 -The most simple and most often used method for allowing other implementations
91.79 -to be plugged in is the <em>system property</em> pattern:
91.80 -
91.81 -<pre>
91.82 - <font class="keyword">public</font> <font class="type">Toolkit</font> <font class="function-name">getDefaultToolkit</font> () {
91.83 - java.awt.<font class="type">Toolkit</font> <font class="variable-name">t</font> = <font class="constant">null</font>;
91.84 - <font class="type">String</font> <font class="variable-name">classname</font> = System.getProperty (<font class="string">"java.awt.Toolkit"</font>);
91.85 - <font class="keyword">if</font> (classname != <font class="constant">null</font>) {
91.86 - <font class="keyword">try</font> {
91.87 - <font class="type">Class</font> <font class="variable-name">c</font> = Class.forName (classname);
91.88 - t = (java.awt.<font class="type">Toolkit</font>)c.newInstance ();
91.89 - } <font class="keyword">catch</font> (<font class="type">Exception</font> <font class="variable-name">ex</font>) {
91.90 - System.out.println (<font class="string">"Cannot initialize toolkit: "</font> + classname);
91.91 - ex.printStackTrace ();
91.92 - }
91.93 - }
91.94 - <font class="comment">// fallback </font>
91.95 - <font class="keyword">if</font> (t == <font class="constant">null</font>) {
91.96 - t = <font class="keyword">new</font> <font class="type">GenericAWTToolkit</font> ();
91.97 - }
91.98 - }
91.99 -</pre>
91.100 -
91.101 -
91.102 -The idea is simple. The <em>deployer</em> can start the Java VM with the flag
91.103 -<code>-Djava.awt.Toolkit=org.myorg.MyToolkit</code> where the <code>MyToolkit</code>
91.104 -is his class with default constructor and the code in the <code>getDefaultToolkit</CODE>
91.105 -method will instantiate the class and use it.
91.106 -<P>
91.107 -In principle this is general enough of a solution and works well, except that writing the
91.108 -code above is error prone and it also requires passing the arguments to the virtual machine.
91.109 -It would be much nicer if the registation could be done just by putting a JAR file with the <code>MyToolkit</code> class
91.110 -into the application classpath.
91.111 -<P>
91.112 -Actually this has been realized also by the JDK development team and addressed in
91.113 -JDK 1.3 as part of the <a href="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Provider%20Configuration%20File">provider extension mechanism</A>.
91.114 -The <code>MyToolkit</code> could be registered by adding a file
91.115 -<code>/META-INF/services/java.awt.Toolkit</code> with one line
91.116 -<code>org.myorg.MyToolkit</code> into the JAR file that contains the
91.117 -<code>MyToolkit</CODE> implementation. The code in <code>getDefaultToolkit</CODE>
91.118 -will scan all JAR files in classpath and search for that file,
91.119 -create an instance of <code>MyToolkit</code> and use it.
91.120 -The deployer can influence which toolkit will be created by
91.121 -adding the right JAR files into the classpath.
91.122 -<P>
91.123 -Of course the code to access the <code>META-INF/services/</code> files is even
91.124 -more error prone than the <em>property pattern</EM>. And this is exactly the
91.125 -place where the <em>lookup library</em> can help. It provides an implementation of
91.126 -the search algorithm with an easy interface. Just write:
91.127 -<pre>
91.128 - <font class="keyword">import</font> <font class="type">java.awt.Toolkit</font>;
91.129 - <font class="keyword">import</font> <font class="type">org.openide.util.Lookup;</font>;
91.130 - <font class="type">Toolkit</font> <font class="variable-name">t</font> = (<font class="type">Toolkit</font>)Lookup.getDefault().<a href="@TOP@org/openide/util/Lookup.html#lookup(java.lang.Class)">lookup</a>(Toolkit.<font class="keyword">class</font>);
91.131 -</PRE>
91.132 -and if the JAR with <code>MyToolkit</CODE> is in the class path, the simple call
91.133 -above will do the rest.
91.134 -<P>
91.135 -So whenever one writes an application divided into several independent modules (jar files)
91.136 -that are being developed and deployed independently, there is a need for registering
91.137 -and discovering components. First of all, a set of interfaces can be defined to enable
91.138 -inter-module communication (like the abstract class <code>java.awt.Toolkit</CODE>).
91.139 -After that a set of modules providing implementation can written (<code>MyToolkit</code> and other concurent implementations)
91.140 -and after that, whenever a module trying to utilitize the functionality wants to access
91.141 -the <code>Toolkit</code> via lookup, the real implementation is returned.
91.142 -<P>
91.143 -It is the responsibility of lookup to find a suitable implementation of the
91.144 -requested service and return an object implementing the service. This is the
91.145 -the basic functionality and while the library provides you with a little bit
91.146 -more, even this simple usage might be extremaly useful: the client code knows
91.147 -nothing about the implementation and the implementation can be switched in
91.148 -deployment time by simply replacing one implementation jar with other. There
91.149 -is no code change required.
91.150 -
91.151 -<H2> Local lookup usage </H2>
91.152 -The example in previous paragraph demostrated the usage of lookup as a global
91.153 -registry (by using the <CODE>Lookup.getDefault()</CODE> call). One can also
91.154 -consider another scenario where the lookup can help.
91.155 -<P>
91.156 -Let's switch hats to be an API designer for a while. The goal is to introduce a
91.157 -new object into the system. But you either are not sure yet what all the roles
91.158 -of the new object will be or you (more importantly) want to be able to add (or
91.159 -change) roles of the object dynamically. So why not to introduce following
91.160 -method to the object's interface:
91.161 -<pre>
91.162 -<font class="keyword">public class </FONT> <font class="type">MorphingObject</FONT> {
91.163 - <font class="keyword">public</FONT> <font class="type"><a href="@TOP@org/openide/util/Lookup.html">Lookup</A></FONT> getLookup() {
91.164 - <font class="keyword">return</FONT> <font class="variable-name">myLookup;</FONT>
91.165 - }
91.166 - ...
91.167 -}
91.168 -</pre>
91.169 -By exposing the method getLookup you can attach different functionality to the
91.170 -MorphingObject at runtime and whoever gets a reference to your object can ask it
91.171 -whether the object supports a given interface like this:
91.172 -<pre>
91.173 -<font class="type">MorphingObject</FONT> <font class="variable-name">morph</FONT> = ...
91.174 -<font class="type">AnInterface</font> <font class="variable-name">impl</font> = (<font
91.175 -class="type">AnInterface</font>)morph.getLookup().<a
91.176 -href="@TOP@org/openide/util/Lookup.html#lookup(java.lang.Class)">lookup</a>(AnInterface.<font class="keyword">class</font>);
91.177 -<font class="keyword">if</font> (impl == <font class="constant">null</font>) {
91.178 - <font class="keyword">return;</font><font class="comment">/* AnInterface not supported now! */</font>
91.179 -}
91.180 -impl.useIt();
91.181 -</PRE>
91.182 -
91.183 -<H2>Additional functionality</H2>
91.184 -The NetBeans lookup library also provides:
91.185 -<UL>
91.186 -<LI>Support for dynamically changing the lookup content.</LI>
91.187 -<LI>The ability to return multiple results.</LI>
91.188 -<LI>Notification of changes. After retrieving the result, the client can attach a
91.189 -listener and be notified when the result of the lookup is changed.</LI>
91.190 -<LI>Lazy initialization of the implementation. The implementation objects are
91.191 -initialized only after someone asks for them. Even the implementation classes
91.192 -are not loaded if they are not going to be used! </LI>
91.193 -</UL>
91.194 -
91.195 -<H2>Further information</H2>
91.196 -<UL>
91.197 - <LI><A HREF="lookup-api.html">Lookup Library APIs</A> for those writing the client code.
91.198 -Specifying the query, getting the result and listenning on changes.</LI>
91.199 - <LI><A HREF="lookup-spi.html">Lookup Library SPIs</A> for those writing the
91.200 -implementaion code and registering it with lookup. Includes also writing own
91.201 -lookup implementation.</LI>
91.202 - <LI>Download <A HREF="http://www.netbeans.org/">NetBeans platform</A> which
91.203 -contains <code>org-openide-util.jar</code></LI>
91.204 - <A HREF="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/lookup/">
91.205 - implementation package (org.openide.util.lookup) </A>
91.206 - + classes Lookup, LookupEvent, LookupListener in
91.207 - <A href="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/">util package</A></LI>
91.208 - <li><a href="http://www.martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a> (Martin Fowler)</li>
91.209 -</UL>
91.210 -</BODY>
91.211 -</HTML>
92.1 --- a/openide.util/src/org/openide/util/lookup/doc-files/lookup-api.html Sat Oct 31 15:06:58 2009 +0100
92.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
92.3 @@ -1,188 +0,0 @@
92.4 -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
92.5 -<!--
92.6 - - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
92.7 - -
92.8 - - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
92.9 - -
92.10 - - The contents of this file are subject to the terms of either the GNU
92.11 - - General Public License Version 2 only ("GPL") or the Common
92.12 - - Development and Distribution License("CDDL") (collectively, the
92.13 - - "License"). You may not use this file except in compliance with the
92.14 - - License. You can obtain a copy of the License at
92.15 - - http://www.netbeans.org/cddl-gplv2.html
92.16 - - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
92.17 - - specific language governing permissions and limitations under the
92.18 - - License. When distributing the software, include this License Header
92.19 - - Notice in each file and include the License file at
92.20 - - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
92.21 - - particular file as subject to the "Classpath" exception as provided
92.22 - - by Sun in the GPL Version 2 section of the License file that
92.23 - - accompanied this code. If applicable, add the following below the
92.24 - - License Header, with the fields enclosed by brackets [] replaced by
92.25 - - your own identifying information:
92.26 - - "Portions Copyrighted [year] [name of copyright owner]"
92.27 - -
92.28 - - Contributor(s):
92.29 - -
92.30 - - The Original Software is NetBeans. The Initial Developer of the Original
92.31 - - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
92.32 - - Microsystems, Inc. All Rights Reserved.
92.33 - -
92.34 - - If you wish your version of this file to be governed by only the CDDL
92.35 - - or only the GPL Version 2, indicate your decision by adding
92.36 - - "[Contributor] elects to include this software in this distribution
92.37 - - under the [CDDL or GPL Version 2] license." If you do not indicate a
92.38 - - single choice of license, a recipient has the option to distribute
92.39 - - your version of this file under either the CDDL, the GPL Version 2 or
92.40 - - to extend the choice of license to its licensees as provided above.
92.41 - - However, if you add GPL Version 2 code and therefore, elected the GPL
92.42 - - Version 2 license, then the option applies only if the new code is
92.43 - - made subject to such option by the copyright holder.
92.44 - -->
92.45 -<HTML>
92.46 -<HEAD>
92.47 -<TITLE>Lookup Library API</TITLE>
92.48 -<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
92.49 -</HEAD>
92.50 -<BODY>
92.51 -<H1>Lookup library API</H1>
92.52 -<p>
92.53 -This document describes usage of the API provided by the Lookup Library. In this
92.54 -document we assume that someone has already provided us with a lookup
92.55 -implementation (for those seeking how to write a lookup implementation please
92.56 -check <A href="lookup-spi.html">the SPI document</A>).
92.57 -
92.58 -<H2> Getting the lookup </H2>
92.59 -
92.60 -The first question you might ask is this: how can I get hold of a
92.61 -lookup instance? There are basically two ways how you can get it.
92.62 -
92.63 -<H3> Global lookup </H3>
92.64 -As you can see in the
92.65 -
92.66 -<a href="@TOP@org/openide/util/Lookup.html">Lookup</a>
92.67 -
92.68 -Javadoc there is a static method
92.69 -
92.70 -<pre><a href="@TOP@org/openide/util/Lookup.html#getDefault()">public static Lookup getDefault()</a></pre>
92.71 -
92.72 -The object returned from this method is
92.73 -a global lookup that can serve as a central place for registering services.
92.74 -The default implementation is a lookup that implements
92.75 -<a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">
92.76 -the JDK JAR services</A>
92.77 -mechanism and delegates to <samp>META-INF/services/name.of.Class</samp> files.
92.78 -<P>
92.79 -If you want to add your class to this lookup just create a file in your
92.80 -jar file under the <code>META-INF</code> directory (e.g. <samp>META-INF/services/com.my.APIClass</samp>)
92.81 -and let the file contain only one line of text
92.82 -
92.83 -<pre>com.foo.impl.ImplOfTheAPI</pre>
92.84 -
92.85 -<p>(This is more easily done using the <code>@ServiceProvider</code> annotation.)</p>
92.86 -
92.87 -The following code will return you a newly created instance of
92.88 -<code>com.foo.impl.ImplOfTheAPI</code>:
92.89 -
92.90 -<PRE>
92.91 - <font class="keyword">import</FONT> org.openide.util.Lookup;
92.92 - return Lookup.getDefault().lookup(com.my.APIClass.class);
92.93 -</PRE>
92.94 -
92.95 -<H3> Local lookup </H3>
92.96 -
92.97 -This is just a reminder that whenever you find a method called getLookup
92.98 -or similar returning a lookup instance, the provided lookup is <EM>not</EM> the
92.99 -general lookup described in the previous paragraph. Rather, it is a private lookup
92.100 -implementation that is usually bound to the object you invoked the method on.
92.101 -
92.102 -<H2> Use of Lookup.Template and Lookup.Result </H2>
92.103 -
92.104 -There are more ways how you can ask lookup besides the variant with one class
92.105 -parameter. If you want more functionality, you have to implement the interface
92.106 -Lookup.Template and pass an instance of such object to the lookup call.
92.107 -<p>
92.108 -<EM>Note:</EM> If you use Lookup.Template, the object returned from the lookup is
92.109 -<EM>not</EM> the object you are looking for but rather a result object
92.110 -(Lookup.Result). You can call methods on such a result object to get the actual
92.111 -results.
92.112 -<p>
92.113 -Let's examine following example:
92.114 -
92.115 -<pre>
92.116 - <font class="keyword">import</FONT> org.openide.util.Lookup;
92.117 -
92.118 - <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
92.119 - Lookup.<font class="type">Template</font> <font class="variable-name">template</font> = <font class="keyword">new</font> Lookup.<font class="type">Template</font>(MyService.<font class="keyword">class</font>);
92.120 - Lookup.<font class="type">Result</font> <font class="variable-name">result</font> = lookup.lookup(template);
92.121 - <font class="type">Collection</font> <font class="variable-name">c</font> = result.allInstances();
92.122 - <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = c.iterator(); i.hasNext(); ) {
92.123 - <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
92.124 - s.callMyService();
92.125 - }
92.126 -</pre>
92.127 -
92.128 -In this example the call to method lookup(...) returns immediately because the
92.129 -result object can be constructed even without real results. The first time you
92.130 -ask for the result object by calling r.allInstances(), the lookup has to supply you
92.131 -the real results and this method can block until the required data are really
92.132 -available.
92.133 -<p>
92.134 -If you are not interested in all objects as in the previous example, you can use the
92.135 -template to ask for one resulting object (wrapped in special Item instance):
92.136 -<pre>
92.137 - <font class="keyword">import</FONT> org.openide.util.Lookup;
92.138 -
92.139 - <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
92.140 - Lookup.<font class="type">Template</font> <font class="variable-name">template</font> = <font class="keyword">new</font> Lookup.<font class="type">Template</font>(MyService.<font class="keyword">class</font>);
92.141 - Lookup.<font class="type">Item</font> <font class="variable-name">item</font> = lookup.lookupItem(template);
92.142 - <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)item.getInstance();
92.143 - s.callMyService();
92.144 -</pre>
92.145 -
92.146 -Again, the Item object can construct the real instance only if you call
92.147 -getInstance. The item can be useful even without calling getInstance - you can get
92.148 -its display name or an unique id. You can use this information, for example, for
92.149 -constructing menu items without the need to instantiate (or even load!)
92.150 -the class implementing the functionality. Only when the real functionality is
92.151 -needed (e.g. the user has selected the menu item) you can call getInstance
92.152 -and call the real meat of the implementation.
92.153 -
92.154 -<H2> Listenning on lookup changes </H2>
92.155 -There is one additional piece of functionality bound to the Lookup.Result object worth
92.156 -mentioning: you can attach a listener to it and be informed about any changes in
92.157 -the lookup. This might be extremly usefull when the lookup dynamically changes
92.158 -(from other threads). The listener can keep state of your object up-to-date even
92.159 -in cases where the lookup changes asynchronously.
92.160 -<p>
92.161 -So here is some sample code using the listenner:
92.162 -
92.163 -<pre>
92.164 - <font class="keyword">import</FONT> org.openide.util.Lookup;
92.165 - <font class="keyword">import</FONT> org.openide.util.LookupListener;
92.166 - <font class="keyword">import</FONT> org.openide.util.LookupEvent;
92.167 -
92.168 - <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
92.169 - Lookup.<font class="type">Template</font> <font class="variable-name">template</font> = <font class="keyword">new</font> Lookup.<font class="type">Template</font>(MyService.<font class="keyword">class</font>);
92.170 - <font class="keyword">final</font> <font class="variable-name">Lookup</font>.<font class="type">Result</font> <font class="variable-name">result</font> = lookup.lookup(template);
92.171 - result.addLookupListener(<font class="keyword">new</font> <font class="type">LookupListener</font>() {
92.172 - <font class="keyword">public</font> <font class="type">void</font> <font class="function-name">resultChanged</font>(<font class="type">LookupEvent</font> <font class="variable-name">e</font>) {
92.173 - reaction(result);
92.174 - }
92.175 - });
92.176 - reaction(result);
92.177 - }
92.178 - <font class="keyword">private</font> <font class="keyword">static</font> <font class="type">void</font> <font class="function-name">reaction</font>(Lookup.<font class="type">Result</font> <font class="variable-name">r</font>) {
92.179 - <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = r.allInstances().iterator(); i.hasNext(); ) {
92.180 - <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
92.181 - s.callMyService();
92.182 - }
92.183 - }
92.184 -</pre>
92.185 -
92.186 -Please note that we first attach a listener and then call the reaction method.
92.187 -This ensures that we always get the newest possible state. Also you must be
92.188 -careful in the reaction method since it can be called from two different
92.189 -threads simultaneously (your code has to be prepared for this).
92.190 -</BODY>
92.191 -</HTML>
93.1 --- a/openide.util/src/org/openide/util/lookup/doc-files/lookup-spi.html Sat Oct 31 15:06:58 2009 +0100
93.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
93.3 @@ -1,147 +0,0 @@
93.4 -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
93.5 -<!--
93.6 - - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
93.7 - -
93.8 - - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
93.9 - -
93.10 - - The contents of this file are subject to the terms of either the GNU
93.11 - - General Public License Version 2 only ("GPL") or the Common
93.12 - - Development and Distribution License("CDDL") (collectively, the
93.13 - - "License"). You may not use this file except in compliance with the
93.14 - - License. You can obtain a copy of the License at
93.15 - - http://www.netbeans.org/cddl-gplv2.html
93.16 - - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
93.17 - - specific language governing permissions and limitations under the
93.18 - - License. When distributing the software, include this License Header
93.19 - - Notice in each file and include the License file at
93.20 - - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
93.21 - - particular file as subject to the "Classpath" exception as provided
93.22 - - by Sun in the GPL Version 2 section of the License file that
93.23 - - accompanied this code. If applicable, add the following below the
93.24 - - License Header, with the fields enclosed by brackets [] replaced by
93.25 - - your own identifying information:
93.26 - - "Portions Copyrighted [year] [name of copyright owner]"
93.27 - -
93.28 - - Contributor(s):
93.29 - -
93.30 - - The Original Software is NetBeans. The Initial Developer of the Original
93.31 - - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
93.32 - - Microsystems, Inc. All Rights Reserved.
93.33 - -
93.34 - - If you wish your version of this file to be governed by only the CDDL
93.35 - - or only the GPL Version 2, indicate your decision by adding
93.36 - - "[Contributor] elects to include this software in this distribution
93.37 - - under the [CDDL or GPL Version 2] license." If you do not indicate a
93.38 - - single choice of license, a recipient has the option to distribute
93.39 - - your version of this file under either the CDDL, the GPL Version 2 or
93.40 - - to extend the choice of license to its licensees as provided above.
93.41 - - However, if you add GPL Version 2 code and therefore, elected the GPL
93.42 - - Version 2 license, then the option applies only if the new code is
93.43 - - made subject to such option by the copyright holder.
93.44 - -->
93.45 -<HTML>
93.46 -<HEAD>
93.47 -<TITLE>Lookup Library SPI</TITLE>
93.48 -<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
93.49 -</HEAD>
93.50 -<BODY>
93.51 -<H1>Lookup library SPI</H1>
93.52 -This document describe usage of the SPI provided by the Lookup Library
93.53 -(for those seeking how to use lookup instance please
93.54 -check <A href="lookup-api.html">the API document</A>).
93.55 -<p>
93.56 -By using the SPI you can create lookups that can be used by the users of the
93.57 -Lookup API. While the Lookup API consists of a couple of classes in the package
93.58 -<em>org.openide.util.*</EM>,
93.59 -the SPI has its own package <em>org.openide.util.lookup.*</EM>.
93.60 -
93.61 -<H2> Simple lookups </H2>
93.62 -Let us start with the simplest case. You have decided that your newly created
93.63 -object will provide an API in the form of a getLookup() method. You have to
93.64 -return a functional lookup from this call. You can use static methods in class
93.65 -<a href="@TOP@org/openide/util/lookup/Lookups.html">
93.66 -<code>Lookups</code></A> to create a lookup for you. If you want only one
93.67 -object to be returned, just call
93.68 -<a href="@TOP@org/openide/util/lookup/Lookups.html#singleton(java.lang.Object)">
93.69 -<code>Lookups.singleton(x)</code></A> where x is the object to be
93.70 -returned by the lookup. Or if you want to supply more objects, use a call to the method
93.71 -<a href="@TOP@org/openide/util/lookup/Lookups.html#fixed(java.lang.Object...)">
93.72 -<code>fixed(Object []x)</CODE></A>.
93.73 -<EM> Note: </EM> The lookups returned from methods <code>singleton(...)</code> and
93.74 -<code>fixed(...)</code> do <EM>
93.75 -not </EM> support dynamic changes and attaching listeners. Their content is
93.76 -fixed from the time you call the creating method.
93.77 -
93.78 -<H2> ProxyLookup </H2>
93.79 -There can be situations where you get a lookup object from someone else and you
93.80 -want your lookup to return exactly the instances from the original lookup plus
93.81 -your own results. Here the class ProxyLookup comes into the play.
93.82 -<p>
93.83 -You simply create a new lookup like this:
93.84 -
93.85 -<pre>
93.86 - <font class="keyword">import</FONT> org.openide.util.Lookup;
93.87 - <font class="keyword">import</FONT> org.openide.util.lookup.*;
93.88 -
93.89 - <font class="type">Lookup</font> <font class="variable-name">lookup1</font> = ...;
93.90 -
93.91 - <font class="type">Lookup</font> <font class="variable-name">lookup2</font> = Lookups.singleton(MyService.<font class="keyword">class</font>);
93.92 - <font class="keyword">return</font> <font class="keyword">new</font> <font class="type">ProxyLookup</font>(<font class="keyword">new</font> <font class="type">Lookup</font>[] { lookup, lookup2 });
93.93 -</pre>
93.94 -
93.95 -<H2> AbstractLookup </H2>
93.96 -<!-- This paragraph originally copied from
93.97 -@TOP@org/openide/doc-files/services-api.html#lookup-impl
93.98 --->
93.99 -
93.100 -<p>The most powerful way to provide a lookup is to directly define
93.101 -what instances and items it should provide, by subclassing. For this,
93.102 -
93.103 -<a href="@TOP@org/openide/util/lookup/AbstractLookup.html"><code>AbstractLookup</code></a>
93.104 -
93.105 -is recommended as it is easiest to use.
93.106 -
93.107 -<p>The simplest way to use <code>AbstractLookup</code> is to use its
93.108 -public constructor (in which case you need not subclass it). Here you
93.109 -provide an
93.110 -
93.111 -<a href="@TOP@org/openide/util/lookup/AbstractLookup.Content.html"><code>AbstractLookup.Content</code></a>
93.112 -
93.113 -object which you have created and hold on to privately, and which
93.114 -keeps track of instances and permits them to be registered and
93.115 -deregistered. Often
93.116 -
93.117 -<a href="@TOP@org/openide/util/lookup/InstanceContent.html"><code>InstanceContent</code></a>
93.118 -
93.119 -is used as the content implementation. To add something to the lookup,
93.120 -simply use
93.121 -
93.122 -<a href="@TOP@org/openide/util/lookup/InstanceContent.html#add(java.lang.Object)"><code>add(Object)</code></a>
93.123 -
93.124 -(and <code>remove(Object)</code> for the reverse). These may be called
93.125 -at any time and will update the set of registered instances (firing
93.126 -result changes as needed).
93.127 -
93.128 -<pre>
93.129 - <font class="keyword">import</FONT> org.openide.util.lookup.*;
93.130 - <font class="type">InstanceContent</font> <font class="variable-name">ic</font> = <font class="keyword">new</font> <font class="type">InstanceContent</font> ();
93.131 - ic.add(firstObject);
93.132 - <font class="keyword">return</font> <font class="keyword">new</font> <font class="type">AbstractLookup</font> (ic);
93.133 -</pre>
93.134 -
93.135 -<p>In case it is expensive to actually compute the object in the
93.136 -lookup, but there is some cheap "key" which can easily generate it,
93.137 -you may instead register the key by passing in an
93.138 -
93.139 -<a href="@TOP@org/openide/util/lookup/InstanceContent.Convertor.html"><code>InstanceContent.Convertor</code></a>.
93.140 -
93.141 -This convertor translates the key to the real instance that the lookup
93.142 -client sees, if and when needed. For example, if you have a long list
93.143 -of class names and wish to register default instances of each class,
93.144 -you might actually register the class name as the key, and supply a
93.145 -convertor which really loads the class and instantiates it. This makes
93.146 -it easy to set up the lookup, but nothing is really loaded until
93.147 -someone asks for it.
93.148 -
93.149 -</BODY>
93.150 -</HTML>
94.1 --- a/openide.util/src/org/openide/util/lookup/package.html Sat Oct 31 15:06:58 2009 +0100
94.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
94.3 @@ -1,48 +0,0 @@
94.4 -<!--
94.5 -DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
94.6 -
94.7 -Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
94.8 -
94.9 -
94.10 -The contents of this file are subject to the terms of either the GNU
94.11 -General Public License Version 2 only ("GPL") or the Common
94.12 -Development and Distribution License("CDDL") (collectively, the
94.13 -"License"). You may not use this file except in compliance with the
94.14 -License. You can obtain a copy of the License at
94.15 -http://www.netbeans.org/cddl-gplv2.html
94.16 -or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
94.17 -specific language governing permissions and limitations under the
94.18 -License. When distributing the software, include this License Header
94.19 -Notice in each file and include the License file at
94.20 -nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
94.21 -particular file as subject to the "Classpath" exception as provided
94.22 -by Sun in the GPL Version 2 section of the License file that
94.23 -accompanied this code. If applicable, add the following below the
94.24 -License Header, with the fields enclosed by brackets [] replaced by
94.25 -your own identifying information:
94.26 -"Portions Copyrighted [year] [name of copyright owner]"
94.27 -
94.28 -Contributor(s):
94.29 -
94.30 -The Original Software is NetBeans. The Initial Developer of the Original
94.31 -Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
94.32 -Microsystems, Inc. All Rights Reserved.
94.33 -
94.34 -If you wish your version of this file to be governed by only the CDDL
94.35 -or only the GPL Version 2, indicate your decision by adding
94.36 -"[Contributor] elects to include this software in this distribution
94.37 -under the [CDDL or GPL Version 2] license." If you do not indicate a
94.38 -single choice of license, a recipient has the option to distribute
94.39 -your version of this file under either the CDDL, the GPL Version 2 or
94.40 -to extend the choice of license to its licensees as provided above.
94.41 -However, if you add GPL Version 2 code and therefore, elected the GPL
94.42 -Version 2 license, then the option applies only if the new code is
94.43 -made subject to such option by the copyright holder.
94.44 --->
94.45 -
94.46 -<html>
94.47 -<body>
94.48 -Support classes for the Registration and {@link org.openide.util.Lookup} extension mechanism.
94.49 -Read more: <a href="doc-files/index.html">Lookup Library</a>
94.50 -</body>
94.51 -</html>
95.1 --- a/openide.util/test/unit/src/org/bar/Comparator2.java Sat Oct 31 15:06:58 2009 +0100
95.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
95.3 @@ -1,7 +0,0 @@
95.4 -
95.5 -package org.bar;
95.6 -
95.7 -public class Comparator2 implements java.util.Comparator {
95.8 - public int compare(Object o1, Object o2) {return 0;}
95.9 - public boolean equals(Object obj) {return true;}
95.10 -}
96.1 --- a/openide.util/test/unit/src/org/bar/Comparator3.java Sat Oct 31 15:06:58 2009 +0100
96.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
96.3 @@ -1,7 +0,0 @@
96.4 -
96.5 -package org.bar;
96.6 -
96.7 -public class Comparator3 implements java.util.Comparator {
96.8 - public int compare(Object o1, Object o2) {return 0;}
96.9 - public boolean equals(Object obj) {return true;}
96.10 -}
97.1 --- a/openide.util/test/unit/src/org/bar/Implementation2.java Sat Oct 31 15:06:58 2009 +0100
97.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
97.3 @@ -1,3 +0,0 @@
97.4 -package org.bar;
97.5 -import org.foo.Interface;
97.6 -public class Implementation2 implements Interface {}
98.1 --- a/openide.util/test/unit/src/org/bar/Iterator2.java Sat Oct 31 15:06:58 2009 +0100
98.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
98.3 @@ -1,11 +0,0 @@
98.4 -
98.5 -package org.bar;
98.6 -
98.7 -public class Iterator2 implements java.util.Iterator {
98.8 - public boolean hasNext() {return false;}
98.9 -
98.10 - public Object next() {return null;}
98.11 -
98.12 - public void remove() {}
98.13 -
98.14 -}
99.1 --- a/openide.util/test/unit/src/org/foo/Interface.java Sat Oct 31 15:06:58 2009 +0100
99.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
99.3 @@ -1,2 +0,0 @@
99.4 -package org.foo;
99.5 -public interface Interface {}
100.1 --- a/openide.util/test/unit/src/org/foo/impl/Comparator1.java Sat Oct 31 15:06:58 2009 +0100
100.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
100.3 @@ -1,7 +0,0 @@
100.4 -
100.5 -package org.foo.impl;
100.6 -
100.7 -public class Comparator1 implements java.util.Comparator {
100.8 - public int compare(Object o1, Object o2) {return 0;}
100.9 - public boolean equals(Object obj) {return true;}
100.10 -}
101.1 --- a/openide.util/test/unit/src/org/foo/impl/Implementation1.java Sat Oct 31 15:06:58 2009 +0100
101.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
101.3 @@ -1,3 +0,0 @@
101.4 -package org.foo.impl;
101.5 -import org.foo.Interface;
101.6 -public class Implementation1 implements Interface {}
102.1 --- a/openide.util/test/unit/src/org/foo/impl/Iterator1.java Sat Oct 31 15:06:58 2009 +0100
102.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
102.3 @@ -1,11 +0,0 @@
102.4 -
102.5 -package org.foo.impl;
102.6 -
102.7 -public class Iterator1 implements java.util.Iterator {
102.8 - public boolean hasNext() {return false;}
102.9 -
102.10 - public Object next() {return null;}
102.11 -
102.12 - public void remove() {}
102.13 -
102.14 -}
103.1 --- a/openide.util/test/unit/src/org/foo/impl/Runnable1.java Sat Oct 31 15:06:58 2009 +0100
103.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
103.3 @@ -1,6 +0,0 @@
103.4 -
103.5 -package org.foo.impl;
103.6 -
103.7 -public class Runnable1 implements Runnable {
103.8 - public void run () {}
103.9 -}
104.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupArrayStorageTest.java Sat Oct 31 15:06:58 2009 +0100
104.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
104.3 @@ -1,120 +0,0 @@
104.4 -/*
104.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
104.6 - *
104.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
104.8 - *
104.9 - * The contents of this file are subject to the terms of either the GNU
104.10 - * General Public License Version 2 only ("GPL") or the Common
104.11 - * Development and Distribution License("CDDL") (collectively, the
104.12 - * "License"). You may not use this file except in compliance with the
104.13 - * License. You can obtain a copy of the License at
104.14 - * http://www.netbeans.org/cddl-gplv2.html
104.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
104.16 - * specific language governing permissions and limitations under the
104.17 - * License. When distributing the software, include this License Header
104.18 - * Notice in each file and include the License file at
104.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
104.20 - * particular file as subject to the "Classpath" exception as provided
104.21 - * by Sun in the GPL Version 2 section of the License file that
104.22 - * accompanied this code. If applicable, add the following below the
104.23 - * License Header, with the fields enclosed by brackets [] replaced by
104.24 - * your own identifying information:
104.25 - * "Portions Copyrighted [year] [name of copyright owner]"
104.26 - *
104.27 - * Contributor(s):
104.28 - *
104.29 - * The Original Software is NetBeans. The Initial Developer of the Original
104.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
104.31 - * Microsystems, Inc. All Rights Reserved.
104.32 - *
104.33 - * If you wish your version of this file to be governed by only the CDDL
104.34 - * or only the GPL Version 2, indicate your decision by adding
104.35 - * "[Contributor] elects to include this software in this distribution
104.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
104.37 - * single choice of license, a recipient has the option to distribute
104.38 - * your version of this file under either the CDDL, the GPL Version 2 or
104.39 - * to extend the choice of license to its licensees as provided above.
104.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
104.41 - * Version 2 license, then the option applies only if the new code is
104.42 - * made subject to such option by the copyright holder.
104.43 - */
104.44 -
104.45 -package org.openide.util.lookup;
104.46 -
104.47 -import junit.framework.*;
104.48 -import org.netbeans.junit.*;
104.49 -import org.openide.util.Lookup;
104.50 -
104.51 -public class AbstractLookupArrayStorageTest extends AbstractLookupBaseHid {
104.52 - public AbstractLookupArrayStorageTest(java.lang.String testName) {
104.53 - super(testName, null);
104.54 - }
104.55 -
104.56 - public static TestSuite suite () {
104.57 - NbTestSuite suite = new NbTestSuite ();
104.58 - suite.addTest (new PL (2));
104.59 - suite.addTest (new AL (1));
104.60 - suite.addTest (new AL (-1));
104.61 - suite.addTest (new PL (-1));
104.62 - suite.addTest (new AL (5));
104.63 - suite.addTest (new PL (3));
104.64 - suite.addTest (new AL (2000));
104.65 - suite.addTest (new PL (2000));
104.66 - return suite;
104.67 - }
104.68 -
104.69 - static final class AL extends ArrayTestSuite {
104.70 - public AL (int trash) {
104.71 - super (trash);
104.72 - }
104.73 -
104.74 - public Lookup createLookup (Lookup lookup) {
104.75 - return lookup;
104.76 - }
104.77 -
104.78 - public void clearCaches () {
104.79 - }
104.80 -
104.81 - }
104.82 -
104.83 - static final class PL extends ArrayTestSuite {
104.84 - public PL (int trash) {
104.85 - super (trash);
104.86 - }
104.87 -
104.88 - public Lookup createLookup (Lookup lookup) {
104.89 - return new ProxyLookup (new Lookup[] { lookup });
104.90 - }
104.91 -
104.92 - public void clearCaches () {
104.93 - }
104.94 -
104.95 - }
104.96 -
104.97 - private static abstract class ArrayTestSuite extends NbTestSuite
104.98 - implements AbstractLookupBaseHid.Impl {
104.99 - private int trash;
104.100 -
104.101 - public ArrayTestSuite (int trash) {
104.102 - super (AbstractLookupArrayStorageTest.class);
104.103 - this.trash = trash;
104.104 -
104.105 - int cnt = this.countTestCases();
104.106 - for (int i = 0; i < cnt; i++) {
104.107 - Object o = this.testAt (i);
104.108 - AbstractLookupBaseHid t = (AbstractLookupBaseHid)o;
104.109 - t.impl = this;
104.110 - }
104.111 - }
104.112 -
104.113 - public Lookup createInstancesLookup (InstanceContent ic) {
104.114 - if (trash == -1) {
104.115 - return new AbstractLookup (ic, new ArrayStorage ());
104.116 - } else {
104.117 - return new AbstractLookup (ic, new ArrayStorage (new Integer (trash)));
104.118 - }
104.119 - }
104.120 -
104.121 -
104.122 - }
104.123 -}
105.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupAsynchExecutorTest.java Sat Oct 31 15:06:58 2009 +0100
105.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
105.3 @@ -1,108 +0,0 @@
105.4 -/*
105.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
105.6 - *
105.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
105.8 - *
105.9 - * The contents of this file are subject to the terms of either the GNU
105.10 - * General Public License Version 2 only ("GPL") or the Common
105.11 - * Development and Distribution License("CDDL") (collectively, the
105.12 - * "License"). You may not use this file except in compliance with the
105.13 - * License. You can obtain a copy of the License at
105.14 - * http://www.netbeans.org/cddl-gplv2.html
105.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
105.16 - * specific language governing permissions and limitations under the
105.17 - * License. When distributing the software, include this License Header
105.18 - * Notice in each file and include the License file at
105.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
105.20 - * particular file as subject to the "Classpath" exception as provided
105.21 - * by Sun in the GPL Version 2 section of the License file that
105.22 - * accompanied this code. If applicable, add the following below the
105.23 - * License Header, with the fields enclosed by brackets [] replaced by
105.24 - * your own identifying information:
105.25 - * "Portions Copyrighted [year] [name of copyright owner]"
105.26 - *
105.27 - * Contributor(s):
105.28 - *
105.29 - * The Original Software is NetBeans. The Initial Developer of the Original
105.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
105.31 - * Microsystems, Inc. All Rights Reserved.
105.32 - *
105.33 - * If you wish your version of this file to be governed by only the CDDL
105.34 - * or only the GPL Version 2, indicate your decision by adding
105.35 - * "[Contributor] elects to include this software in this distribution
105.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
105.37 - * single choice of license, a recipient has the option to distribute
105.38 - * your version of this file under either the CDDL, the GPL Version 2 or
105.39 - * to extend the choice of license to its licensees as provided above.
105.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
105.41 - * Version 2 license, then the option applies only if the new code is
105.42 - * made subject to such option by the copyright holder.
105.43 - */
105.44 -
105.45 -package org.openide.util.lookup;
105.46 -
105.47 -import java.util.ArrayList;
105.48 -import java.util.List;
105.49 -import java.util.concurrent.Executor;
105.50 -import org.netbeans.junit.NbTestCase;
105.51 -import org.openide.util.Lookup;
105.52 -import org.openide.util.LookupEvent;
105.53 -import org.openide.util.LookupListener;
105.54 -
105.55 -public class AbstractLookupAsynchExecutorTest extends NbTestCase implements Executor {
105.56 - private List<Runnable> toRun = new ArrayList<Runnable>();
105.57 -
105.58 -
105.59 - public AbstractLookupAsynchExecutorTest(java.lang.String testName) {
105.60 - super(testName);
105.61 - }
105.62 -
105.63 - public void testCanProxyLookupHaveWrongResults() {
105.64 - final InstanceContent ic = new InstanceContent(this);
105.65 - final AbstractLookup lookup = new AbstractLookup(ic);
105.66 -
105.67 - class L implements LookupListener {
105.68 - ProxyLookup pl;
105.69 - Lookup.Result<String> original;
105.70 - Lookup.Result<String> wrapped;
105.71 - boolean ok;
105.72 -
105.73 - public void test() {
105.74 - pl = new ProxyLookup(lookup);
105.75 - original = lookup.lookupResult(String.class);
105.76 -
105.77 - original.addLookupListener(this);
105.78 -
105.79 - wrapped = pl.lookupResult(String.class);
105.80 -
105.81 - assertEquals("Original empty", 0, original.allInstances().size());
105.82 - assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
105.83 -
105.84 - ic.add("Hello!");
105.85 - }
105.86 -
105.87 - public void resultChanged(LookupEvent ev) {
105.88 - ok = true;
105.89 - assertContainsHello();
105.90 - }
105.91 -
105.92 - public void assertContainsHello() {
105.93 - assertEquals("Original has hello", 1, original.allInstances().size());
105.94 - assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
105.95 - }
105.96 -
105.97 - }
105.98 - L listener = new L();
105.99 - listener.test();
105.100 - listener.assertContainsHello();
105.101 - for (Runnable r : toRun) {
105.102 - r.run();
105.103 - }
105.104 - assertTrue("Listener called", listener.ok);
105.105 - }
105.106 -
105.107 - public void execute(Runnable command) {
105.108 - toRun.add(command);
105.109 - }
105.110 -
105.111 -}
106.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupBaseHid.java Sat Oct 31 15:06:58 2009 +0100
106.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
106.3 @@ -1,2088 +0,0 @@
106.4 -/*
106.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
106.6 - *
106.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
106.8 - *
106.9 - * The contents of this file are subject to the terms of either the GNU
106.10 - * General Public License Version 2 only ("GPL") or the Common
106.11 - * Development and Distribution License("CDDL") (collectively, the
106.12 - * "License"). You may not use this file except in compliance with the
106.13 - * License. You can obtain a copy of the License at
106.14 - * http://www.netbeans.org/cddl-gplv2.html
106.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
106.16 - * specific language governing permissions and limitations under the
106.17 - * License. When distributing the software, include this License Header
106.18 - * Notice in each file and include the License file at
106.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
106.20 - * particular file as subject to the "Classpath" exception as provided
106.21 - * by Sun in the GPL Version 2 section of the License file that
106.22 - * accompanied this code. If applicable, add the following below the
106.23 - * License Header, with the fields enclosed by brackets [] replaced by
106.24 - * your own identifying information:
106.25 - * "Portions Copyrighted [year] [name of copyright owner]"
106.26 - *
106.27 - * Contributor(s):
106.28 - *
106.29 - * The Original Software is NetBeans. The Initial Developer of the Original
106.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
106.31 - * Microsystems, Inc. All Rights Reserved.
106.32 - *
106.33 - * If you wish your version of this file to be governed by only the CDDL
106.34 - * or only the GPL Version 2, indicate your decision by adding
106.35 - * "[Contributor] elects to include this software in this distribution
106.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
106.37 - * single choice of license, a recipient has the option to distribute
106.38 - * your version of this file under either the CDDL, the GPL Version 2 or
106.39 - * to extend the choice of license to its licensees as provided above.
106.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
106.41 - * Version 2 license, then the option applies only if the new code is
106.42 - * made subject to such option by the copyright holder.
106.43 - */
106.44 -
106.45 -package org.openide.util.lookup;
106.46 -
106.47 -import java.io.ByteArrayInputStream;
106.48 -import java.io.ByteArrayOutputStream;
106.49 -import java.io.ObjectInputStream;
106.50 -import java.io.ObjectOutputStream;
106.51 -import java.io.Serializable;
106.52 -import java.lang.ref.WeakReference;
106.53 -import java.lang.ref.Reference;
106.54 -import java.util.ArrayList;
106.55 -import java.util.Arrays;
106.56 -import java.util.Collection;
106.57 -import java.util.Collections;
106.58 -import java.util.Iterator;
106.59 -import java.util.LinkedList;
106.60 -import java.util.List;
106.61 -import java.util.concurrent.Executors;
106.62 -import java.util.concurrent.TimeUnit;
106.63 -import javax.swing.ActionMap;
106.64 -import javax.swing.InputMap;
106.65 -import org.netbeans.junit.NbTestCase;
106.66 -import org.openide.util.Lookup;
106.67 -import org.openide.util.Lookup.Template;
106.68 -import org.openide.util.LookupEvent;
106.69 -import org.openide.util.LookupListener;
106.70 -
106.71 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
106.72 -public class AbstractLookupBaseHid extends NbTestCase {
106.73 - private static AbstractLookupBaseHid running;
106.74 -
106.75 - /** instance content to work with */
106.76 - InstanceContent ic;
106.77 - /** the lookup to work on */
106.78 - protected Lookup instanceLookup;
106.79 - /** the lookup created to work with */
106.80 - private Lookup lookup;
106.81 - /** implementation of methods that can influence the behaviour */
106.82 - Impl impl;
106.83 -
106.84 - protected AbstractLookupBaseHid(String testName, Impl impl) {
106.85 - super(testName);
106.86 - if (impl == null && (this instanceof Impl)) {
106.87 - impl = (Impl)this;
106.88 - }
106.89 - this.impl = impl;
106.90 - }
106.91 -
106.92 - protected @Override void setUp() {
106.93 - this.ic = new InstanceContent ();
106.94 -
106.95 - beforeActualTest(getName());
106.96 -
106.97 - this.instanceLookup = createInstancesLookup (ic);
106.98 - this.lookup = createLookup (instanceLookup);
106.99 - running = this;
106.100 - }
106.101 -
106.102 - protected @Override void tearDown() {
106.103 - running = null;
106.104 - }
106.105 -
106.106 - /** The methods to influence test behaviour */
106.107 - public static interface Impl {
106.108 - /** Creates the initial abstract lookup.
106.109 - */
106.110 - public Lookup createInstancesLookup (InstanceContent ic);
106.111 - /** Creates an lookup for given lookup. This class just returns
106.112 - * the object passed in, but subclasses can be different.
106.113 - * @param lookup in lookup
106.114 - * @return a lookup to use
106.115 - */
106.116 - public Lookup createLookup (Lookup lookup);
106.117 -
106.118 - /** If the impl has any caches that would prevent the system
106.119 - * to not garbage collect correctly, then clear them now.
106.120 - */
106.121 - public void clearCaches ();
106.122 - }
106.123 -
106.124 - private Lookup createInstancesLookup (InstanceContent ic) {
106.125 - return impl.createInstancesLookup (ic);
106.126 - }
106.127 -
106.128 - private Lookup createLookup (Lookup lookup) {
106.129 - return impl.createLookup (lookup);
106.130 - }
106.131 -
106.132 - /** instances that we register */
106.133 - private static Object[] INSTANCES = new Object[] {
106.134 - new Integer (10),
106.135 - new Object ()
106.136 - };
106.137 -
106.138 - /** Test if first is really first.
106.139 - */
106.140 - public void testFirst () {
106.141 - Integer i1 = 1;
106.142 - Integer i2 = 2;
106.143 -
106.144 - ic.add (i1);
106.145 - ic.add (i2);
106.146 -
106.147 - Integer found = lookup.lookup(Integer.class);
106.148 - if (found != i1) {
106.149 - fail ("First object is not first: " + found + " != " + i1);
106.150 - }
106.151 -
106.152 - List<Integer> list = new ArrayList<Integer>();
106.153 - list.add (i2);
106.154 - list.add (i1);
106.155 - ic.set (list, null);
106.156 -
106.157 - found = lookup.lookup (Integer.class);
106.158 - if (found != i2) {
106.159 - fail ("Second object is not first after reorder: " + found + " != " + i2);
106.160 - }
106.161 -
106.162 - }
106.163 -
106.164 - public void testToString() {
106.165 - String txt = lookup.toString();
106.166 - assertNotNull("Something is there", txt);
106.167 - assertTrue("Something2: " + txt, txt.length() > 0);
106.168 - }
106.169 -
106.170 -
106.171 - /** Tests ordering of items in the lookup.
106.172 - */
106.173 - public void testOrder () {
106.174 - addInstances (INSTANCES);
106.175 -
106.176 - if (INSTANCES[0] != lookup.lookup (INSTANCES[0].getClass ())) {
106.177 - fail ("First object in intances not found");
106.178 - }
106.179 -
106.180 - Iterator<?> all = lookup.lookupAll(Object.class).iterator();
106.181 - checkIterator ("Difference between instances added and found", all, Arrays.asList (INSTANCES));
106.182 - }
106.183 -
106.184 - /** Checks the reorder of items in lookup reflects the result.
106.185 - * Testing both classes and interfaces, because they are often treated
106.186 - * especially.
106.187 - */
106.188 - public void testReorder () {
106.189 - String s1 = "s2";
106.190 - String s2 = "s1";
106.191 - Runnable r1 = new Runnable () {
106.192 - public void run () {}
106.193 - };
106.194 - Runnable r2 = new Runnable () {
106.195 - public void run () {}
106.196 - };
106.197 - List<Object> l = new ArrayList<Object>();
106.198 -
106.199 - l.add (s1);
106.200 - l.add (s2);
106.201 - l.add (r1);
106.202 - l.add (r2);
106.203 - ic.set (l, null);
106.204 -
106.205 - assertEquals ("s1 is found", s1, lookup.lookup (String.class));
106.206 - assertEquals ("r1 is found", r1, lookup.lookup (Runnable.class));
106.207 -
106.208 - Collections.reverse (l);
106.209 -
106.210 - ic.set (l, null);
106.211 -
106.212 - assertEquals ("s2 is found", s2, lookup.lookup (String.class));
106.213 - assertEquals ("r2 is found", r2, lookup.lookup (Runnable.class));
106.214 - }
106.215 -
106.216 - /** Tries to set empty collection to the lookup.
106.217 - */
106.218 - public void testSetEmpty () {
106.219 - ic.add ("A serializable string");
106.220 - lookup.lookup (Serializable.class);
106.221 -
106.222 - ic.set (Collections.emptyList(), null);
106.223 - }
106.224 -
106.225 - /** Tests a more complex reorder on nodes.
106.226 - */
106.227 - public void testComplexReorder () {
106.228 - Integer i1 = 1;
106.229 - Long i2 = 2L;
106.230 -
106.231 - List<Object> l = new ArrayList<Object>();
106.232 - l.add (i1);
106.233 - l.add (i2);
106.234 - ic.set (l, null);
106.235 -
106.236 - assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
106.237 - assertEquals ("Find long", i2, lookup.lookup (Long.class));
106.238 - assertEquals ("Find number", i1, lookup.lookup (Number.class));
106.239 -
106.240 - Collections.reverse (l);
106.241 -
106.242 - ic.set (l, null);
106.243 -
106.244 - assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
106.245 - assertEquals ("Find long", i2, lookup.lookup (Long.class));
106.246 - assertEquals ("Find number", i2, lookup.lookup (Number.class));
106.247 - }
106.248 -
106.249 - /** Checks whether setPairs keeps the order.
106.250 - */
106.251 - public void testSetPairs () {
106.252 - // test setPairs method
106.253 - List<Object> li = new ArrayList<Object>();
106.254 - li.addAll (Arrays.asList (INSTANCES));
106.255 - ic.set (li, null);
106.256 -
106.257 - Lookup.Result<Object> res = lookup.lookupResult(Object.class);
106.258 - Iterator<?> all = res.allInstances().iterator();
106.259 - checkIterator ("Original order not kept", all, li);
106.260 -
106.261 - // reverse the order
106.262 - Collections.reverse (li);
106.263 -
106.264 - // change the pairs
106.265 - LL listener = new LL (res);
106.266 - res.addLookupListener (listener);
106.267 - ic.set (li, null);
106.268 - if (listener.getCount () != 1) {
106.269 - fail ("Result has not changed even we set reversed order");
106.270 - }
106.271 -
106.272 - all = res.allInstances ().iterator ();
106.273 - checkIterator ("Reversed order not kept", all, li);
106.274 - }
106.275 -
106.276 - /** Checks whether setPairs fires correct events.
106.277 - */
106.278 - public void testSetPairsFire () {
106.279 - // test setPairs method
106.280 - List<Object> li = new ArrayList<Object>();
106.281 - li.addAll (Arrays.asList (INSTANCES));
106.282 - ic.set (li, null);
106.283 -
106.284 - Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
106.285 - Iterator<?> all = res.allInstances().iterator();
106.286 - checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
106.287 -
106.288 - // change the pairs
106.289 - LL listener = new LL (res);
106.290 - res.addLookupListener (listener);
106.291 -
106.292 - List<Object> l2 = new ArrayList<Object>(li);
106.293 - l2.remove (INSTANCES[0]);
106.294 - ic.set (l2, null);
106.295 -
106.296 - all = lookup.lookupAll(Object.class).iterator();
106.297 - checkIterator ("The removed integer is not noticed", all, l2);
106.298 -
106.299 - if (listener.getCount () != 1) {
106.300 - fail ("Nothing has not been fired");
106.301 - }
106.302 - }
106.303 -
106.304 - /** Checks whether set pairs does not fire when they should not.
106.305 - */
106.306 - public void testSetPairsDoesNotFire () {
106.307 - Object tmp = new Object ();
106.308 -
106.309 - List<Object> li = new ArrayList<Object>();
106.310 - li.add (tmp);
106.311 - li.addAll (Arrays.asList (INSTANCES));
106.312 - ic.set (li, null);
106.313 -
106.314 - Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
106.315 - Iterator<?> all = res.allInstances ().iterator ();
106.316 - checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
106.317 -
106.318 - // change the pairs
106.319 - LL listener = new LL (res);
106.320 - res.addLookupListener (listener);
106.321 -
106.322 - List<Object> l2 = new ArrayList<Object>(li);
106.323 - l2.remove (tmp);
106.324 - ic.set (l2, null);
106.325 -
106.326 - all = lookup.lookupAll(Object.class).iterator();
106.327 - checkIterator ("The removed integer is not noticed", all, l2);
106.328 -
106.329 - if (listener.getCount () != 0) {
106.330 - fail ("Something has been fired");
106.331 - }
106.332 - }
106.333 -
106.334 - /** Test whether after registration it is possible to find registered objects
106.335 - *
106.336 - */
106.337 - public void testLookupAndAdd () throws Exception {
106.338 - addInstances (INSTANCES);
106.339 -
106.340 - for (int i = 0; i < INSTANCES.length; i++) {
106.341 - Object obj = INSTANCES[i];
106.342 - findAll (lookup, obj.getClass (), true);
106.343 - }
106.344 - }
106.345 -
106.346 - /** Tries to find all classes and superclasses in the lookup.
106.347 - */
106.348 - private void findAll(Lookup lookup, Class<?> clazz, boolean shouldBeThere) {
106.349 - if (clazz == null) return;
106.350 -
106.351 - Object found = lookup.lookup (clazz);
106.352 - if (found == null) {
106.353 - if (shouldBeThere) {
106.354 - // should find at either instance or something else, but must
106.355 - // find at least something
106.356 - fail ("Lookup (" + clazz.getName () + ") found nothing");
106.357 - }
106.358 - } else {
106.359 - if (!shouldBeThere) {
106.360 - // should find at either instance or something else, but must
106.361 - // find at least something
106.362 - fail ("Lookup (" + clazz.getName () + ") found " + found);
106.363 - }
106.364 - }
106.365 -
106.366 - Lookup.Result<?> res = lookup.lookupResult(clazz);
106.367 - Collection<?> collection = res.allInstances();
106.368 -
106.369 - for (int i = 0; i < INSTANCES.length; i++) {
106.370 - boolean isSubclass = clazz.isInstance (INSTANCES[i]);
106.371 - boolean isThere = collection.contains (INSTANCES[i]);
106.372 -
106.373 - if (isSubclass != isThere) {
106.374 - // a problem found
106.375 - // should find at either instance or something else, but must
106.376 - // find at least something
106.377 - fail ("Lookup.Result (" + clazz.getName () + ") for " + INSTANCES[i] + " is subclass: " + isSubclass + " isThere: " + isThere);
106.378 - }
106.379 - }
106.380 -
106.381 - // go on for superclasses
106.382 -
106.383 - findAll (lookup, clazz.getSuperclass (), shouldBeThere);
106.384 -
106.385 - Class[] ies = clazz.getInterfaces ();
106.386 - for (int i = 0; i < ies.length; i++) {
106.387 - findAll (lookup, ies[i], shouldBeThere);
106.388 - }
106.389 - }
106.390 -
106.391 - /** Test if it is possible to remove a registered object. */
106.392 - public void testRemoveRegisteredObject() {
106.393 - Integer inst = new Integer(10);
106.394 -
106.395 - ic.add(inst);
106.396 - if (lookup.lookup(inst.getClass()) == null) {
106.397 - // should find an instance
106.398 - fail("Lookup (" + inst.getClass().getName () + ") found nothing");
106.399 - }
106.400 -
106.401 - ic.remove(inst);
106.402 - if (lookup.lookup(inst.getClass()) != null) {
106.403 - // should NOT find an instance
106.404 - fail("Lookup (" + inst.getClass().getName () +
106.405 - ") found an instance after remove operation");
106.406 - }
106.407 - }
106.408 -
106.409 - public void testCanReturnReallyStrangeResults () throws Exception {
106.410 - class QueryingPair extends AbstractLookup.Pair<Object> {
106.411 - private Integer i = 434;
106.412 -
106.413 - //
106.414 - // do the test
106.415 - //
106.416 -
106.417 - public void doTest () throws Exception {
106.418 - ic.add (i);
106.419 - ic.addPair (this);
106.420 -
106.421 - Object found = lookup.lookup (QueryingPair.class);
106.422 - assertEquals ("This object is found", this, found);
106.423 - }
106.424 -
106.425 -
106.426 - //
106.427 - // Implementation of pair
106.428 - //
106.429 -
106.430 - public String getId() {
106.431 - return getType ().toString();
106.432 - }
106.433 -
106.434 - public String getDisplayName() {
106.435 - return getId ();
106.436 - }
106.437 -
106.438 - public Class<?> getType() {
106.439 - return getClass ();
106.440 - }
106.441 -
106.442 - protected boolean creatorOf(Object obj) {
106.443 - return obj == this;
106.444 - }
106.445 -
106.446 - protected boolean instanceOf(Class<?> c) {
106.447 - assertEquals ("Integer found or exception is thrown", i, lookup.lookup (Integer.class));
106.448 - return c.isAssignableFrom(getType ());
106.449 - }
106.450 -
106.451 - public Object getInstance() {
106.452 - return this;
106.453 - }
106.454 -
106.455 -
106.456 - }
106.457 -
106.458 -
106.459 - QueryingPair qp = new QueryingPair ();
106.460 - qp.doTest ();
106.461 - }
106.462 -
106.463 - /** Test of firing events. */
106.464 - public void testLookupListener() {
106.465 - Object inst = 10;
106.466 - Lookup.Result<?> res = lookup.lookupResult(inst.getClass());
106.467 - res.allInstances ();
106.468 -
106.469 - LL listener = new LL(res);
106.470 - res.addLookupListener(listener);
106.471 -
106.472 - ic.add(inst);
106.473 - if (listener.getCount() == 0) {
106.474 - fail("None event fired during NbLookup.addPair()");
106.475 - }
106.476 -
106.477 - ic.remove(inst);
106.478 - if (listener.getCount() == 0) {
106.479 - fail("None event fired during NbLookup.removePair()");
106.480 - }
106.481 -
106.482 - ic.add(inst);
106.483 - if (listener.getCount() == 0) {
106.484 - fail("None event fired during second NbLookup.addPair()");
106.485 - }
106.486 -
106.487 - ic.remove(inst);
106.488 - if (listener.getCount() == 0) {
106.489 - fail("None event fired during second NbLookup.removePair()");
106.490 - }
106.491 - }
106.492 -
106.493 - /** Testing identity of the lookup.
106.494 - */
106.495 - public void testId () {
106.496 - Lookup.Template<?> templ;
106.497 - int cnt;
106.498 -
106.499 - addInstances (INSTANCES);
106.500 -
106.501 - Lookup.Result<?> res = lookup.lookupResult(Object.class);
106.502 - for (AbstractLookup.Item<?> item : res.allItems()) {
106.503 -
106.504 - templ = new Lookup.Template<Object>(null, item.getId(), null);
106.505 - cnt = lookup.lookup (templ).allInstances ().size ();
106.506 - if (cnt != 1) {
106.507 - fail ("Identity lookup failed. Instances = " + cnt);
106.508 - }
106.509 -
106.510 - templ = makeTemplate(item.getType(), item.getId());
106.511 - cnt = lookup.lookup (templ).allInstances ().size ();
106.512 - if (cnt != 1) {
106.513 - fail ("Identity lookup with type failed. Instances = " + cnt);
106.514 - }
106.515 -
106.516 - templ = makeTemplate(this.getClass(), item.getId());
106.517 - cnt = lookup.lookup (templ).allInstances ().size ();
106.518 - if (cnt != 0) {
106.519 - fail ("Identity lookup with wrong type failed. Instances = " + cnt);
106.520 - }
106.521 -
106.522 - templ = new Lookup.Template<Object>(null, null, item.getInstance());
106.523 - cnt = lookup.lookup (templ).allInstances ().size ();
106.524 - if (cnt != 1) {
106.525 - fail ("Instance lookup failed. Instances = " + cnt);
106.526 - }
106.527 -
106.528 - templ = new Lookup.Template<Object>(null, item.getId(), item.getInstance());
106.529 - cnt = lookup.lookup (templ).allInstances ().size ();
106.530 - if (cnt != 1) {
106.531 - fail ("Instance & identity lookup failed. Instances = " + cnt);
106.532 - }
106.533 -
106.534 - }
106.535 - }
106.536 - private static <T> Lookup.Template<T> makeTemplate(Class<T> clazz, String id) { // captures type parameter
106.537 - return new Lookup.Template<T>(clazz, id, null);
106.538 - }
106.539 -
106.540 - /** Tests adding and removing.
106.541 - */
106.542 - public void testAddAndRemove () throws Exception {
106.543 - Object map = new javax.swing.ActionMap ();
106.544 - LL ll = new LL ();
106.545 -
106.546 - Lookup.Result<?> res = lookup.lookupResult(map.getClass());
106.547 - res.allItems();
106.548 - res.addLookupListener (ll);
106.549 - ll.source = res;
106.550 -
106.551 - ic.add (map);
106.552 -
106.553 - assertEquals ("First change when adding", ll.getCount (), 1);
106.554 -
106.555 - ic.remove (map);
106.556 -
106.557 - assertEquals ("Second when removing", ll.getCount (), 1);
106.558 -
106.559 - ic.add (map);
106.560 -
106.561 - assertEquals ("Third when readding", ll.getCount (), 1);
106.562 -
106.563 - ic.remove (map);
106.564 -
106.565 - assertEquals ("Forth when reremoving", ll.getCount (), 1);
106.566 -
106.567 - }
106.568 -
106.569 - /** Will a class garbage collect even it is registered in lookup.
106.570 - */
106.571 - public void testGarbageCollect () throws Exception {
106.572 - ClassLoader l = new CL ();
106.573 - Class<?> c = l.loadClass(Garbage.class.getName());
106.574 - Reference<?> ref = new WeakReference<Object>(c);
106.575 -
106.576 - lookup.lookup (c);
106.577 -
106.578 - // now test garbage collection
106.579 - c = null;
106.580 - l = null;
106.581 - impl.clearCaches ();
106.582 - assertGC ("The classloader has not been garbage collected!", ref);
106.583 - }
106.584 -
106.585 - /** Items are the same as results.
106.586 - */
106.587 - public void testItemsAndIntances () {
106.588 - addInstances (INSTANCES);
106.589 -
106.590 - Lookup.Result<Object> r = lookup.lookupResult(Object.class);
106.591 - Collection<? extends Lookup.Item<?>> items = r.allItems();
106.592 - Collection<?> insts = r.allInstances();
106.593 -
106.594 - if (items.size () != insts.size ()) {
106.595 - fail ("Different size of sets");
106.596 - }
106.597 -
106.598 - for (Lookup.Item<?> item : items) {
106.599 - if (!insts.contains (item.getInstance ())) {
106.600 - fail ("Intance " + item.getInstance () + " is missing in " + insts);
106.601 - }
106.602 - }
106.603 - }
106.604 -
106.605 - /** Checks search for interface.
106.606 - */
106.607 - public void testSearchForInterface () {
106.608 - Lookup.Template<Serializable> t = new Lookup.Template<Serializable>(Serializable.class, null, null);
106.609 -
106.610 - assertNull("Nothing to find", lookup.lookupItem (t));
106.611 -
106.612 - Serializable s = new Serializable () {};
106.613 - ic.add (s);
106.614 -
106.615 - Lookup.Item item = lookup.lookupItem (t);
106.616 - assertNotNull ("Something found", item);
106.617 - }
106.618 -
106.619 - /** Test to add broken item if it incorrectly answers instanceOf questions.
106.620 - */
106.621 - public void testIncorectInstanceOf40364 () {
106.622 - final Long sharedLong = new Long (0);
106.623 -
106.624 - class P extends AbstractLookup.Pair<Object> {
106.625 - public boolean isLong;
106.626 -
106.627 - P (boolean b) {
106.628 - isLong = b;
106.629 - }
106.630 -
106.631 - protected boolean creatorOf (Object obj) {
106.632 - return obj == sharedLong;
106.633 - }
106.634 -
106.635 - public String getDisplayName () {
106.636 - return "";
106.637 - }
106.638 -
106.639 - public String getId () {
106.640 - return "";
106.641 - }
106.642 -
106.643 - public Object getInstance () {
106.644 - return sharedLong;
106.645 - }
106.646 -
106.647 - public Class<?> getType() {
106.648 - return isLong ? Long.class : Number.class;
106.649 - }
106.650 -
106.651 - protected boolean instanceOf(Class<?> c) {
106.652 - return c.isAssignableFrom (getType ());
106.653 - }
106.654 -
106.655 - public @Override int hashCode() {
106.656 - return getClass ().hashCode ();
106.657 - }
106.658 -
106.659 - public @Override boolean equals(Object obj) {
106.660 - return obj != null && getClass ().equals (obj.getClass ());
106.661 - }
106.662 - }
106.663 -
106.664 - // to create the right structure in the lookup
106.665 - lookup.lookup (Object.class);
106.666 - lookup.lookup (Long.class);
106.667 - lookup.lookup (Number.class);
106.668 -
106.669 - P lng1 = new P (true);
106.670 - ic.addPair (lng1);
106.671 -
106.672 - P lng2 = new P (false);
106.673 - ic.setPairs (Collections.singleton (lng2));
106.674 -
106.675 - Collection<? extends Lookup.Item<?>> res = lookup.lookupResult(Object.class).allItems();
106.676 - assertEquals ("Just one pair", 1, res.size ());
106.677 - }
106.678 -
106.679 - public void testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly () throws Exception {
106.680 - class X implements TestInterfaceInheritanceA, TestInterfaceInheritanceB {
106.681 - }
106.682 - final X shared = new X ();
106.683 -
106.684 - class P extends AbstractLookup.Pair<Object> {
106.685 - public int howLong;
106.686 -
106.687 - P (int b) {
106.688 - howLong = b;
106.689 - }
106.690 -
106.691 - protected boolean creatorOf (Object obj) {
106.692 - return obj == shared;
106.693 - }
106.694 -
106.695 - public String getDisplayName () {
106.696 - return "";
106.697 - }
106.698 -
106.699 - public String getId () {
106.700 - return "";
106.701 - }
106.702 -
106.703 - public Object getInstance () {
106.704 - return shared;
106.705 - }
106.706 -
106.707 - public Class<?> getType() {
106.708 - return howLong == 0 ? TestInterfaceInheritanceB.class : TestInterfaceInheritanceA.class;
106.709 - }
106.710 -
106.711 - protected boolean instanceOf(Class<?> c) {
106.712 - return c.isAssignableFrom (getType ());
106.713 - }
106.714 -
106.715 - public @Override int hashCode() {
106.716 - return getClass ().hashCode ();
106.717 - }
106.718 -
106.719 - public @Override boolean equals(Object obj) {
106.720 - if (obj instanceof P) {
106.721 - P p = (P)obj;
106.722 - if (this.howLong > 0) {
106.723 - this.howLong--;
106.724 - return false;
106.725 - }
106.726 - if (p.howLong > 0) {
106.727 - p.howLong--;
106.728 - return false;
106.729 - }
106.730 - return getClass ().equals (p.getClass ());
106.731 - }
106.732 - return false;
106.733 - }
106.734 - }
106.735 -
106.736 - // to create the right structure in the lookup
106.737 - Lookup.Result<?> a = lookup.lookupResult(TestInterfaceInheritanceA.class);
106.738 - Lookup.Result<?> b = lookup.lookupResult(TestInterfaceInheritanceB.class);
106.739 -
106.740 - P lng1 = new P (0);
106.741 - ic.addPair (lng1);
106.742 -
106.743 - assertEquals ("One in a", 1, a.allItems ().size ());
106.744 - assertEquals ("One in b", 1, b.allItems ().size ());
106.745 -
106.746 - P lng2 = new P (1);
106.747 -
106.748 -
106.749 - /* Following call used to generate this exception:
106.750 - java.lang.IllegalStateException: Duplicate pair in treePair1: pair2: index1: 0 index2: 0 item1: org.openide.util.lookup.AbstractLookupBaseHid$1X@1a457b6 item2: org.openide.util.lookup.AbstractLookupBaseHid$1X@1a457b6 id1: 7a78d3 id2: 929206
106.751 - at org.openide.util.lookup.ALPairComparator.compare(ALPairComparator.java:52)
106.752 - at java.util.Arrays.mergeSort(Arrays.java:1284)
106.753 - at java.util.Arrays.sort(Arrays.java:1223)
106.754 - at java.util.Collections.sort(Collections.java:159)
106.755 - at org.openide.util.lookup.InheritanceTree.retainAllInterface(InheritanceTree.java:753)
106.756 - at org.openide.util.lookup.InheritanceTree.retainAll(InheritanceTree.java:183)
106.757 - at org.openide.util.lookup.DelegatingStorage.retainAll(DelegatingStorage.java:83)
106.758 - at org.openide.util.lookup.AbstractLookup.setPairsAndCollectListeners(AbstractLookup.java:238)
106.759 - at org.openide.util.lookup.AbstractLookup.setPairs(AbstractLookup.java:203)
106.760 - at org.openide.util.lookup.AbstractLookup$Content.setPairs(AbstractLookup.java:885)
106.761 - at org.openide.util.lookup.AbstractLookupBaseHid.testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly(AbstractLookupBaseHid.java:696)
106.762 - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
106.763 - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
106.764 - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
106.765 - at org.netbeans.junit.NbTestCase.run(NbTestCase.java:119)
106.766 - */
106.767 - ic.setPairs (Collections.singleton (lng2));
106.768 -
106.769 -
106.770 - }
106.771 -
106.772 - public void testInstancesArePreservedFoundWhenFixing48590 () throws Exception {
106.773 - class X implements Runnable, Serializable {
106.774 - public void run () {
106.775 -
106.776 - }
106.777 -
106.778 - public void assertOnlyMe (String msg, Lookup.Result<?> res) {
106.779 - Collection<?> col = res.allInstances();
106.780 - assertEquals (msg + " just one", 1, col.size ());
106.781 - assertSame (msg + " and it is me", this, col.iterator ().next ());
106.782 - }
106.783 - }
106.784 -
106.785 - Lookup.Result<?> runnable = lookup.lookupResult(Runnable.class);
106.786 - Lookup.Result<?> serial = lookup.lookupResult(Serializable.class);
106.787 -
106.788 -
106.789 - X x = new X ();
106.790 - ic.add (x);
106.791 -
106.792 -
106.793 - x.assertOnlyMe ("x implements it (1)", runnable);
106.794 - x.assertOnlyMe ("x implements it (2)", serial);
106.795 -
106.796 - ic.set (Collections.singleton (x), null);
106.797 -
106.798 - x.assertOnlyMe ("x implements it (3)", runnable);
106.799 - x.assertOnlyMe ("x implements it (4)", serial);
106.800 - }
106.801 -
106.802 - /** Testing lookup of inherited classes. */
106.803 - public void testInheritance() {
106.804 - class A {}
106.805 - class B extends A implements java.rmi.Remote {}
106.806 - class BB extends B {}
106.807 - class C extends A implements java.rmi.Remote {}
106.808 - class D extends A {}
106.809 -
106.810 - A[] types = {new B(), new BB(), new C(), new D()};
106.811 -
106.812 - for (int i = 0; i < types.length; i++) {
106.813 - ic.add(types[i]);
106.814 - if (lookup.lookup(types[i].getClass()) == null) {
106.815 - // should find an instance
106.816 - fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
106.817 - }
106.818 - }
106.819 -
106.820 - int size1, size2;
106.821 -
106.822 - //interface query
106.823 - size1 = lookup.lookupAll(java.rmi.Remote.class).size();
106.824 - size2 = countInstances(types, java.rmi.Remote.class);
106.825 -
106.826 - if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
106.827 -
106.828 - // superclass query
106.829 - size1 = lookup.lookupAll(A.class).size();
106.830 - size2 = countInstances(types, A.class);
106.831 -
106.832 - if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
106.833 - }
106.834 -
106.835 - /** Test interface inheritance.
106.836 - */
106.837 - public void testInterfaceInheritance() {
106.838 - TestInterfaceInheritanceA[] types = {
106.839 - new TestInterfaceInheritanceB() {},
106.840 - new TestInterfaceInheritanceBB() {},
106.841 - new TestInterfaceInheritanceC() {},
106.842 - new TestInterfaceInheritanceD() {}
106.843 - };
106.844 -
106.845 - for (int i = 0; i < types.length; i++) {
106.846 - ic.add(types[i]);
106.847 - if (lookup.lookup(types[i].getClass()) == null) {
106.848 - // should find an instance
106.849 - fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
106.850 - }
106.851 - }
106.852 -
106.853 - int size1, size2;
106.854 -
106.855 - //interface query
106.856 - LL l = new LL ();
106.857 - Lookup.Result<?> res = lookup.lookupResult(java.rmi.Remote.class);
106.858 - l.source = res;
106.859 - size1 = res.allInstances().size();
106.860 - size2 = countInstances(types, java.rmi.Remote.class);
106.861 -
106.862 - if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
106.863 -
106.864 - // superclass query
106.865 - size1 = lookup.lookupAll(TestInterfaceInheritanceA.class).size();
106.866 - size2 = countInstances(types, TestInterfaceInheritanceA.class);
106.867 -
106.868 - if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
106.869 -
106.870 - res.addLookupListener (l);
106.871 - ic.remove (types[0]);
106.872 -
106.873 - if (l.getCount () != 1) {
106.874 - fail ("No notification that a Remote is removed");
106.875 - }
106.876 - }
106.877 -
106.878 - /** Checks whether the AbstractLookup is guarded against modifications
106.879 - * while doing some kind of modification.
106.880 - */
106.881 - public void testModificationArePreventedWhenDoingModifications () throws Exception {
106.882 - BrokenPair broken = new BrokenPair (true, false);
106.883 - ic.addPair (broken);
106.884 -
106.885 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
106.886 - Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
106.887 - assertEquals ("Broken is found", broken, item);
106.888 - }
106.889 -
106.890 - public void testModificationArePreventedWhenDoingModificationsResult () throws Exception {
106.891 - BrokenPair broken = new BrokenPair (false, true);
106.892 - ic.addPair (broken);
106.893 -
106.894 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
106.895 -
106.896 - Collection<? extends BrokenPair> c = lookup.lookup (templ).allInstances();
106.897 - assertEquals ("One item", 1, c.size ());
106.898 - assertEquals ("Broken is found again", broken, c.iterator().next ());
106.899 - }
106.900 -
106.901 - public void testModificationArePreventedWhenDoingModificationsItemAndResult () throws Exception {
106.902 - BrokenPair broken = new BrokenPair (false, true);
106.903 - ic.addPair (broken);
106.904 -
106.905 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
106.906 - Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
106.907 - assertEquals ("Broken is found", broken, item);
106.908 -
106.909 - Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
106.910 - assertEquals ("One item", 1, c.size ());
106.911 - assertEquals ("Broken is found again", broken, c.iterator().next ());
106.912 - }
106.913 -
106.914 - public void testModificationArePreventedWhenDoingModificationsResultAndItem () throws Exception {
106.915 - BrokenPair broken = new BrokenPair (false, true);
106.916 - ic.addPair (broken);
106.917 -
106.918 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
106.919 - Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
106.920 - assertEquals ("One item", 1, c.size ());
106.921 - assertEquals ("Broken is found again", broken, c.iterator().next ());
106.922 -
106.923 - Object item = lookup.lookupItem (templ);
106.924 - assertEquals ("Broken is found", broken, item);
106.925 - }
106.926 -
106.927 - public void testAddALotOfPairsIntoTheLookupOneByOne () throws Exception {
106.928 - Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
106.929 - for (int i = 0; i < 1000; i++) {
106.930 - ic.add(i);
106.931 - }
106.932 - assertEquals (
106.933 - "there is the right count",
106.934 - 1000,
106.935 - res.allItems().size ()
106.936 - );
106.937 - }
106.938 -
106.939 - public void testAddALotOfPairsIntoTheLookup () throws Exception {
106.940 - List<Integer> arr = new ArrayList<Integer>();
106.941 - for (int i = 0; i < 1000; i++) {
106.942 - arr.add(i);
106.943 - }
106.944 - ic.set (arr, null);
106.945 -
106.946 - assertEquals (
106.947 - "there is the right count",
106.948 - 1000,
106.949 - lookup.lookupResult(Integer.class).allItems().size()
106.950 - );
106.951 - }
106.952 -
106.953 -
106.954 - public void testDoubleAddIssue35274 () throws Exception {
106.955 - class P extends AbstractLookup.Pair<Object> {
106.956 - protected boolean creatorOf(Object obj) { return false; }
106.957 - public String getDisplayName() { return ""; }
106.958 - public String getId() { return ""; }
106.959 - public Object getInstance() { return null; }
106.960 - public Class<?> getType() { return Object.class; }
106.961 - protected boolean instanceOf(Class<?> c) { return c.isAssignableFrom(getType ()); }
106.962 - public @Override int hashCode() {return getClass().hashCode();}
106.963 - public @Override boolean equals(Object obj) {return getClass() == obj.getClass();}
106.964 - }
106.965 -
106.966 - P p = new P ();
106.967 -
106.968 - ic.addPair (p);
106.969 - ic.addPair (p);
106.970 -
106.971 - Lookup.Result<Object> result = lookup.lookupResult(Object.class);
106.972 - Collection res = result.allItems ();
106.973 - assertEquals ("One item there", 1, res.size ());
106.974 - assertTrue ("It is the p", p == res.iterator ().next ());
106.975 -
106.976 - P p2 = new P ();
106.977 - ic.addPair (p2);
106.978 -
106.979 - Reference<?> ref = new WeakReference<Object>(result);
106.980 - result = null;
106.981 - assertGC ("The result can disappear", ref);
106.982 -
106.983 - impl.clearCaches ();
106.984 -
106.985 - result = lookup.lookupResult(Object.class);
106.986 - res = result.allItems ();
106.987 - assertEquals ("One item is still there", 1, res.size ());
106.988 - assertTrue ("But the p2 replaced p", p2 == res.iterator ().next ());
106.989 -
106.990 - }
106.991 -
106.992 - /** Test for proper serialization.
106.993 - */
106.994 - public void testSerializationSupport () throws Exception {
106.995 - doSerializationSupport (1);
106.996 - }
106.997 - public void testDoubleSerializationSupport () throws Exception {
106.998 - doSerializationSupport (2);
106.999 - }
106.1000 -
106.1001 - private void doSerializationSupport (int count) throws Exception {
106.1002 - if (lookup instanceof Serializable) {
106.1003 - ic.addPair (new SerialPair ("1"));
106.1004 - ic.addPair (new SerialPair ("2"));
106.1005 - ic.addPair (new SerialPair ("3"));
106.1006 -
106.1007 - Lookup l = (Lookup)reserialize(lookup);
106.1008 -
106.1009 - assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
106.1010 -
106.1011 - assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
106.1012 -
106.1013 - while (count-- > 0) {
106.1014 - l = (Lookup)reserialize(l);
106.1015 - }
106.1016 -
106.1017 - assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
106.1018 -
106.1019 - assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
106.1020 - }
106.1021 - }
106.1022 -
106.1023 - /** When a lookup with two different versions of the same class
106.1024 - * get's serialized, the results may be very bad.
106.1025 - */
106.1026 - public void testSerializationOfTwoClassesWithTheSameName () throws Exception {
106.1027 - if (lookup instanceof Serializable) {
106.1028 - doTwoSerializedClasses (false, false);
106.1029 - }
106.1030 - }
106.1031 - public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSave () throws Exception {
106.1032 - if (lookup instanceof Serializable) {
106.1033 - doTwoSerializedClasses (true, false);
106.1034 - }
106.1035 - }
106.1036 - public void testSerializationOfTwoClassesWithTheSameNameWithBroken () throws Exception {
106.1037 - if (lookup instanceof Serializable) {
106.1038 - doTwoSerializedClasses (false, true);
106.1039 - }
106.1040 - }
106.1041 - public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSaveWithBroken () throws Exception {
106.1042 - if (lookup instanceof Serializable) {
106.1043 - doTwoSerializedClasses (true, true);
106.1044 - }
106.1045 - }
106.1046 -
106.1047 - private void doTwoSerializedClasses (boolean queryBeforeSerialization, boolean useBroken) throws Exception {
106.1048 - ClassLoader loader = new CL ();
106.1049 - Class c = loader.loadClass (Garbage.class.getName ());
106.1050 -
106.1051 - // in case of InheritanceTree it creates a slot for class Garbage
106.1052 - lookup.lookup(c);
106.1053 -
106.1054 - // but creates new instance and adds it into the lookup
106.1055 - // without querying for it
106.1056 - loader = new CL ();
106.1057 - c = loader.loadClass (Garbage.class.getName ());
106.1058 -
106.1059 - Object theInstance = c.newInstance ();
106.1060 -
106.1061 - ic.addPair (new SerialPair (theInstance));
106.1062 -
106.1063 - Broken2Pair broken = null;
106.1064 - if (useBroken) {
106.1065 - broken = new Broken2Pair ();
106.1066 - ic.addPair (broken);
106.1067 -
106.1068 - assertNull (
106.1069 - "We need to create the slot for the List as " +
106.1070 - "the Broken2Pair will ask for it after deserialization",
106.1071 - lookup.lookup (java.awt.List.class)
106.1072 - );
106.1073 - }
106.1074 -
106.1075 - if (queryBeforeSerialization) {
106.1076 - assertEquals ("Instance is found", theInstance, lookup.lookup (c));
106.1077 - }
106.1078 -
106.1079 - // replace the old lookup with new one
106.1080 - lookup = (Lookup)reserialize(lookup);
106.1081 -
106.1082 - Lookup.Result result = lookup.lookup (new Lookup.Template (Garbage.class));
106.1083 - assertEquals ("One item is the result", 1, result.allInstances ().size ());
106.1084 - Object r = result.allInstances ().iterator ().next ();
106.1085 - assertNotNull("A value is found", r);
106.1086 - assertEquals ("It is of the right class", Garbage.class, r.getClass());
106.1087 - }
106.1088 -
106.1089 - /** Test of reorder and item change which used to fail on interfaces.
106.1090 - */
106.1091 - public void testReoderingIssue13779 () throws Exception {
106.1092 - LinkedList arr = new LinkedList ();
106.1093 -
106.1094 - class R extends Exception implements Cloneable {
106.1095 - }
106.1096 - Object o1 = new R ();
106.1097 - Object o2 = new R ();
106.1098 - Object o3 = new R ();
106.1099 -
106.1100 - arr.add (o1);
106.1101 - arr.add (o2);
106.1102 -
106.1103 - ic.set (arr, null);
106.1104 -
106.1105 - Lookup.Result objectResult = lookup.lookup (new Lookup.Template (Exception.class));
106.1106 - Lookup.Result interfaceResult = lookup.lookup (new Lookup.Template (Cloneable.class));
106.1107 - objectResult.allItems ();
106.1108 - interfaceResult.allItems ();
106.1109 -
106.1110 - LL l1 = new LL (objectResult);
106.1111 - LL l2 = new LL (interfaceResult);
106.1112 -
106.1113 - objectResult.addLookupListener(l1);
106.1114 - interfaceResult.addLookupListener(l2);
106.1115 -
106.1116 - arr.addFirst (o3);
106.1117 -
106.1118 - ic.set (arr, null);
106.1119 -
106.1120 - assertEquals ("One change on objects", 1, l1.getCount ());
106.1121 - assertEquals ("One change on interfaces", 1, l2.getCount ());
106.1122 -
106.1123 - arr.addFirst (new Cloneable () { });
106.1124 - ic.set (arr, null);
106.1125 -
106.1126 - assertEquals ("No change on objects", 0, l1.getCount ());
106.1127 - assertEquals ("But one change on interfaces", 1, l2.getCount ());
106.1128 -
106.1129 - }
106.1130 -
106.1131 - public void testDeadlockBetweenProxyResultAndLookupIssue47772 () throws Exception {
106.1132 - final String myModule = "My Module";
106.1133 - ic.add (myModule);
106.1134 -
106.1135 - class MyProxy extends ProxyLookup {
106.1136 - public MyProxy () {
106.1137 - super (new Lookup[] { lookup });
106.1138 - }
106.1139 - }
106.1140 - final MyProxy my = new MyProxy ();
106.1141 -
106.1142 - final Lookup.Result allModules = my.lookup (new Lookup.Template (String.class));
106.1143 -
106.1144 - class PairThatNeedsInfoAboutModules extends AbstractLookup.Pair {
106.1145 - public String getDisplayName () {
106.1146 - return "Need a module";
106.1147 - }
106.1148 - public String getId () {
106.1149 - return getDisplayName ();
106.1150 - }
106.1151 - public Class getType () {
106.1152 - return Integer.class;
106.1153 - }
106.1154 - protected boolean instanceOf (Class c) {
106.1155 - if (c == Integer.class) {
106.1156 - synchronized (this) {
106.1157 - notifyAll ();
106.1158 - try {
106.1159 - wait (1000);
106.1160 - } catch (InterruptedException ex) {
106.1161 - fail (ex.getMessage ());
106.1162 - }
106.1163 - }
106.1164 - java.util.Collection coll = allModules.allInstances ();
106.1165 - assertEquals ("Size is 1", 1, coll.size ());
106.1166 - assertEquals ("My module is there", myModule, coll.iterator ().next ());
106.1167 - }
106.1168 - return c.isAssignableFrom (Integer.class);
106.1169 - }
106.1170 -
106.1171 - public Object getInstance () {
106.1172 - return new Integer (10);
106.1173 - }
106.1174 -
106.1175 - protected boolean creatorOf (Object obj) {
106.1176 - return new Integer (10).equals (obj);
106.1177 - }
106.1178 - }
106.1179 -
106.1180 - PairThatNeedsInfoAboutModules pair = new PairThatNeedsInfoAboutModules ();
106.1181 - ic.addPair (pair);
106.1182 -
106.1183 - synchronized (pair) {
106.1184 - class BlockInInstanceOf implements Runnable {
106.1185 - public void run () {
106.1186 - Integer i = my.lookup(Integer.class);
106.1187 - assertEquals (new Integer (10), i);
106.1188 - }
106.1189 - }
106.1190 - BlockInInstanceOf blk = new BlockInInstanceOf ();
106.1191 - Executors.newSingleThreadScheduledExecutor().schedule(blk, 0, TimeUnit.MICROSECONDS);
106.1192 - pair.wait ();
106.1193 - }
106.1194 -
106.1195 - java.util.Collection coll = allModules.allInstances ();
106.1196 - assertEquals ("Size is 1", 1, coll.size ());
106.1197 - assertEquals ("My module is there", myModule, coll.iterator ().next ());
106.1198 - }
106.1199 -
106.1200 - public void testAWayToGenerateProblem13779 () {
106.1201 - ic.add (new Integer (1));
106.1202 - ic.add (new Integer (2));
106.1203 - ic.add (new Integer (1));
106.1204 - ic.add (new Integer (2));
106.1205 -
106.1206 - Collection c = lookup.lookup (new Lookup.Template (Integer.class)).allInstances ();
106.1207 - assertEquals ("There are two objects", 2, c.size ());
106.1208 -
106.1209 - }
106.1210 -
106.1211 - /** Replacing items with different objects.
106.1212 - */
106.1213 - public void testReplacingObjectsDoesNotGenerateException () throws Exception {
106.1214 - LinkedList arr = new LinkedList ();
106.1215 -
106.1216 - class R extends Exception implements Cloneable {
106.1217 - }
106.1218 - arr.add (new R ());
106.1219 - arr.add (new R ());
106.1220 -
106.1221 - ic.set (arr, null);
106.1222 -
106.1223 - arr.clear();
106.1224 -
106.1225 - arr.add (new R ());
106.1226 - arr.add (new R ());
106.1227 -
106.1228 - ic.set (arr, null);
106.1229 - }
106.1230 -
106.1231 - public void testAfterDeserializationNoQueryIsPeformedOnAlreadyQueriedObjects() throws Exception {
106.1232 - if (! (lookup instanceof Serializable)) {
106.1233 - // well this test works only for serializable lookups
106.1234 - return;
106.1235 - }
106.1236 -
106.1237 - SerialPair my = new SerialPair ("no");
106.1238 - ic.addPair (my);
106.1239 -
106.1240 - Lookup.Result res = lookup.lookup (new Lookup.Template (String.class));
106.1241 - assertEquals ("One instance", 1, res.allInstances().size ());
106.1242 - assertEquals ("my.instanceOf called once", 1, my.countInstanceOf);
106.1243 -
106.1244 - Lookup serial = (Lookup)reserialize(lookup);
106.1245 -
106.1246 - Lookup.Result r2 = serial.lookup(new Lookup.Template(String.class));
106.1247 -
106.1248 - assertEquals ("One item", 1, r2.allItems ().size ());
106.1249 - Object one = r2.allItems().iterator().next ();
106.1250 - assertEquals ("The right class", SerialPair.class, one.getClass());
106.1251 - SerialPair p = (SerialPair)one;
106.1252 -
106.1253 - assertEquals ("p.instanceOf has not been queried", 0, p.countInstanceOf);
106.1254 - }
106.1255 -
106.1256 - /** Checks the iterator */
106.1257 - private <T> void checkIterator(String msg, Iterator<? extends T> it1, List<? extends T> list) {
106.1258 - int cnt = 0;
106.1259 - Iterator<? extends T> it2 = list.iterator();
106.1260 - while (it1.hasNext () && it2.hasNext ()) {
106.1261 - T n1 = it1.next();
106.1262 - T n2 = it2.next();
106.1263 -
106.1264 - if (n1 != n2) {
106.1265 - fail (msg + " iterator[" + cnt + "] = " + n1 + " but list[" + cnt + "] = " + n2);
106.1266 - }
106.1267 -
106.1268 - cnt++;
106.1269 - }
106.1270 -
106.1271 - if (it1.hasNext ()) {
106.1272 - fail ("Iterator has more elements than list");
106.1273 - }
106.1274 -
106.1275 - if (it2.hasNext ()) {
106.1276 - fail ("List has more elements than iterator");
106.1277 - }
106.1278 - }
106.1279 -
106.1280 -
106.1281 - public void testResultsAreUnmodifyableOrAtLeastTheyDoNotPropagateToCache() throws Exception {
106.1282 - String s = "Ahoj";
106.1283 -
106.1284 - ic.add(s);
106.1285 -
106.1286 - Lookup.Result res = lookup.lookup(new Template(String.class));
106.1287 -
106.1288 - for (int i = 1; i < 5; i++) {
106.1289 - Collection c1 = res.allInstances();
106.1290 - Collection c2 = res.allClasses();
106.1291 - Collection c3 = res.allItems();
106.1292 -
106.1293 - assertTrue(i + ": c1 has it", c1.contains(s));
106.1294 - assertTrue(i + ": c2 has it", c2.contains(s.getClass()));
106.1295 - assertEquals(i + ": c3 has one", 1, c3.size());
106.1296 - Lookup.Item item = (Lookup.Item) c3.iterator().next();
106.1297 - assertEquals(i + ": c3 has it", s, item.getInstance());
106.1298 -
106.1299 - try {
106.1300 - c1.remove(s);
106.1301 - assertEquals("No elements now", 0, c1.size());
106.1302 - } catch (UnsupportedOperationException ex) {
106.1303 - // ok, this need not be supported
106.1304 - }
106.1305 - try {
106.1306 - c2.remove(s.getClass());
106.1307 - assertEquals("No elements now", 0, c2.size());
106.1308 - } catch (UnsupportedOperationException ex) {
106.1309 - // ok, this need not be supported
106.1310 - }
106.1311 - try {
106.1312 - c3.remove(item);
106.1313 - assertEquals("No elements now", 0, c3.size());
106.1314 - } catch (UnsupportedOperationException ex) {
106.1315 - // ok, this need not be supported
106.1316 - }
106.1317 - }
106.1318 - }
106.1319 -
106.1320 - public void testSomeProblemWithDVBFrameworkSeemsToBeInLookup() {
106.1321 - for (int i = 0; i < 5; i++) {
106.1322 - ic.add(lookup);
106.1323 - assertEquals("Can be found", lookup, lookup.lookup(lookup.getClass()));
106.1324 - ic.set(Collections.EMPTY_LIST, null);
106.1325 - }
106.1326 - }
106.1327 -
106.1328 - public void testListeningAndQueryingByTwoListenersInstances() {
106.1329 - doListeningAndQueryingByTwoListeners(0);
106.1330 - }
106.1331 - public void testListeningAndQueryingByTwoListenersClasses() {
106.1332 - doListeningAndQueryingByTwoListeners(1);
106.1333 - }
106.1334 - public void testListeningAndQueryingByTwoListenersItems() {
106.1335 - doListeningAndQueryingByTwoListeners(2);
106.1336 - }
106.1337 -
106.1338 -
106.1339 - private void doListeningAndQueryingByTwoListeners(final int type) {
106.1340 - class L implements LookupListener {
106.1341 - Lookup.Result integer = lookup.lookup(new Template(Integer.class));
106.1342 - Lookup.Result number = lookup.lookup(new Template(Number.class));
106.1343 - Lookup.Result serial = lookup.lookup(new Template(Serializable.class));
106.1344 -
106.1345 - {
106.1346 - integer.addLookupListener(this);
106.1347 - number.addLookupListener(this);
106.1348 - serial.addLookupListener(this);
106.1349 - }
106.1350 -
106.1351 - int round;
106.1352 -
106.1353 - public void resultChanged(LookupEvent ev) {
106.1354 - Collection c1 = get(type, integer);
106.1355 - Collection c2 = get(type, number);
106.1356 - Collection c3 = get(type, serial);
106.1357 -
106.1358 - assertEquals("round " + round + " c1 vs. c2", c1, c2);
106.1359 - assertEquals("round " + round + " c1 vs. c3", c1, c3);
106.1360 - assertEquals("round " + round + " c2 vs. c3", c2, c3);
106.1361 -
106.1362 - round++;
106.1363 - }
106.1364 -
106.1365 - private Collection get(int type, Lookup.Result res) {
106.1366 - Collection c;
106.1367 - switch(type) {
106.1368 - case 0: c = res.allInstances(); break;
106.1369 - case 1: c = res.allClasses(); break;
106.1370 - case 2: c = res.allItems(); break;
106.1371 - default: c = null; fail("Type: " + type); break;
106.1372 - }
106.1373 -
106.1374 - assertNotNull(c);
106.1375 - return new ArrayList(c);
106.1376 - }
106.1377 - }
106.1378 -
106.1379 - L listener = new L();
106.1380 - listener.resultChanged(null);
106.1381 -
106.1382 - for(int i = 0; i < 100; i++) {
106.1383 - ic.add(new Integer(i));
106.1384 - }
106.1385 -
106.1386 - assertEquals("3x100+1 checks", 301, listener.round);
106.1387 - }
106.1388 -
106.1389 - public void testChangeOfNodeDoesNotFireChangeInActionMap() {
106.1390 - ActionMap am = new ActionMap();
106.1391 - Lookup s = Lookups.singleton(am);
106.1392 - doChangeOfNodeDoesNotFireChangeInActionMap(am, s, false);
106.1393 - }
106.1394 - public void testChangeOfNodeDoesNotFireChangeInActionMapSimple() {
106.1395 - ActionMap am = new ActionMap();
106.1396 - Lookup s = Lookups.singleton(am);
106.1397 - doChangeOfNodeDoesNotFireChangeInActionMap(am, s, true);
106.1398 - }
106.1399 -
106.1400 - public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookupSimple() {
106.1401 - doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(true);
106.1402 - }
106.1403 -
106.1404 - public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup() {
106.1405 - doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(false);
106.1406 - }
106.1407 - private void doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(boolean wrapBySimple) {
106.1408 - final ActionMap am = new ActionMap();
106.1409 -
106.1410 - class Before extends AbstractLookup {
106.1411 - public InstanceContent ic;
106.1412 - public Before() {
106.1413 - this(new InstanceContent());
106.1414 - }
106.1415 -
106.1416 - private Before(InstanceContent ic) {
106.1417 - super(ic);
106.1418 - this.ic = ic;
106.1419 - }
106.1420 -
106.1421 - protected @Override void beforeLookup(Template template) {
106.1422 - if (ic != null) {
106.1423 - ic.add(am);
106.1424 - ic = null;
106.1425 - }
106.1426 - }
106.1427 - }
106.1428 -
106.1429 - Before s = new Before();
106.1430 - doChangeOfNodeDoesNotFireChangeInActionMap(am, s, wrapBySimple);
106.1431 -
106.1432 - assertNull("beforeLookup called once", s.ic);
106.1433 - }
106.1434 -
106.1435 - private void doChangeOfNodeDoesNotFireChangeInActionMap(final ActionMap am, Lookup actionMapLookup, final boolean wrapBySimple) {
106.1436 - Lookup[] lookups = { lookup, actionMapLookup };
106.1437 -
106.1438 - class Provider implements Lookup.Provider {
106.1439 - ProxyLookup delegate;
106.1440 - Lookup query;
106.1441 -
106.1442 - public Provider(Lookup[] arr) {
106.1443 - if (wrapBySimple) {
106.1444 - delegate = new ProxyLookup(arr);
106.1445 - query = Lookups.proxy(this);
106.1446 - } else {
106.1447 - query = delegate = new ProxyLookup(arr);
106.1448 - }
106.1449 - }
106.1450 -
106.1451 - public Lookup getLookup() {
106.1452 - return delegate;
106.1453 - }
106.1454 -
106.1455 - public void setLookups(Lookup... arr) {
106.1456 - if (wrapBySimple) {
106.1457 - delegate = new ProxyLookup(arr);
106.1458 - } else {
106.1459 - delegate.setLookups(arr);
106.1460 - }
106.1461 - }
106.1462 - }
106.1463 -
106.1464 - Provider p = new Provider(lookups);
106.1465 -
106.1466 - Lookup.Result res = p.query.lookup(new Lookup.Template(ActionMap.class));
106.1467 - LL ll = new LL();
106.1468 - res.addLookupListener(ll);
106.1469 -
106.1470 - Collection c = res.allInstances();
106.1471 - assertFalse("Has next", c.isEmpty());
106.1472 -
106.1473 - ActionMap am1 = (ActionMap)c.iterator().next();
106.1474 - assertEquals("Am is there", am, am1);
106.1475 -
106.1476 - assertEquals("No change in first get", 0, ll.getCount());
106.1477 -
106.1478 - Object m1 = new InputMap();
106.1479 - Object m2 = new InputMap();
106.1480 -
106.1481 - ic.add(m1);
106.1482 - assertEquals("No change in ActionMap 1", 0, ll.getCount());
106.1483 - ic.set(Collections.singletonList(m2), null);
106.1484 - assertEquals("No change in ActionMap 2", 0, ll.getCount());
106.1485 - ic.add(m2);
106.1486 - assertEquals("No change in ActionMap 3", 0, ll.getCount());
106.1487 - p.setLookups(lookup, actionMapLookup, Lookup.EMPTY);
106.1488 - assertEquals("No change in ActionMap 4", 0, ll.getCount());
106.1489 -
106.1490 - ActionMap am2 = p.query.lookup(ActionMap.class);
106.1491 - assertEquals("Still the same action map", am, am2);
106.1492 -
106.1493 -
106.1494 - class Before extends AbstractLookup {
106.1495 - public InstanceContent ic;
106.1496 - public Before() {
106.1497 - this(new InstanceContent());
106.1498 - }
106.1499 -
106.1500 - private Before(InstanceContent ic) {
106.1501 - super(ic);
106.1502 - this.ic = ic;
106.1503 - }
106.1504 -
106.1505 - protected @Override void beforeLookup(Template template) {
106.1506 - if (ic != null) {
106.1507 - ic.add(am);
106.1508 - ic = null;
106.1509 - }
106.1510 - }
106.1511 - }
106.1512 -
106.1513 - Before s = new Before();
106.1514 -
106.1515 - // adding different Before, but returning the same instance
106.1516 - // this happens with metaInfServices lookup often, moreover
106.1517 - // it adds the instance in beforeLookup, which confuses a lot
106.1518 - p.setLookups(new Lookup[]{ lookup, new Before() });
106.1519 - assertEquals("No change in ActionMap 5", 0, ll.getCount());
106.1520 -
106.1521 -
106.1522 - }
106.1523 -
106.1524 - public void testTasklistsCase() throws Exception {
106.1525 - ic.remove(new Object());
106.1526 - }
106.1527 -
106.1528 -
106.1529 -
106.1530 - public void testMultipleListeners() {
106.1531 - Object object = new ImplementationObject();
106.1532 - ic.add(object);
106.1533 -
106.1534 - Listener[] listeners = new Listener[4];
106.1535 - Lookup.Result result = lookup.lookup(new Lookup.Template(LookupObject.class));
106.1536 - for(int i = 0; i < listeners.length; ++i) {
106.1537 - listeners[i] = new Listener();
106.1538 - result.addLookupListener(listeners[i]);
106.1539 - }
106.1540 - // initialize listening
106.1541 - result.allItems();
106.1542 -
106.1543 - ic.remove(object);
106.1544 -
106.1545 - // Apparently, only odd-numbered listeners get called when there are multiple LookupListeners on a result
106.1546 - //for(int i = 0; i < listeners.length; ++i) {
106.1547 - // System.out.println("Listener " + i + ": " + listeners[i].wasCalled());
106.1548 - //}
106.1549 - for(int i = 0; i < listeners.length; ++i) {
106.1550 - assertTrue("Listener " + i + " called", listeners[i].wasCalled());
106.1551 - }
106.1552 - }
106.1553 -
106.1554 - static Object reserialize(Object o) throws Exception {
106.1555 - ByteArrayOutputStream os = new ByteArrayOutputStream();
106.1556 - ObjectOutputStream oos = new ObjectOutputStream(os);
106.1557 - oos.writeObject(o);
106.1558 - oos.close();
106.1559 -
106.1560 - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
106.1561 - ObjectInputStream ois = new ObjectInputStream(is);
106.1562 - return ois.readObject();
106.1563 - }
106.1564 -
106.1565 - private class Listener implements LookupListener {
106.1566 - private boolean listenerCalled = false;
106.1567 -
106.1568 - public void resultChanged(LookupEvent ev) {
106.1569 - listenerCalled = true;
106.1570 - }
106.1571 -
106.1572 - public boolean wasCalled() {
106.1573 - return listenerCalled;
106.1574 - }
106.1575 -
106.1576 - public void reset() {
106.1577 - listenerCalled = false;
106.1578 - }
106.1579 - }
106.1580 -
106.1581 - private interface LookupObject {}
106.1582 - private class ImplementationObject implements LookupObject {}
106.1583 - private class NullObject implements LookupObject {}
106.1584 -
106.1585 -
106.1586 - public void testReturnSomethingElseThenYouClaimYouWillReturn() {
106.1587 - class Liar extends AbstractLookup.Pair {
106.1588 - public Object obj;
106.1589 -
106.1590 - protected boolean instanceOf(Class c) {
106.1591 - return c.isAssignableFrom(String.class);
106.1592 - }
106.1593 -
106.1594 - protected boolean creatorOf(Object obj) {
106.1595 - return this.obj == obj;
106.1596 - }
106.1597 -
106.1598 - public Object getInstance() {
106.1599 - return this.obj;
106.1600 - }
106.1601 -
106.1602 - public Class getType() {
106.1603 - return String.class;
106.1604 - }
106.1605 -
106.1606 - public String getId() {
106.1607 - return String.class.getName();
106.1608 - }
106.1609 -
106.1610 - public String getDisplayName() {
106.1611 - return getId();
106.1612 - }
106.1613 - }
106.1614 -
106.1615 -
106.1616 - Liar l = new Liar();
106.1617 - l.obj = new Integer(5);
106.1618 -
106.1619 - this.ic.addPair(l);
106.1620 -
106.1621 - Collection c = lookup.lookup(new Lookup.Template(String.class)).allInstances();
106.1622 - assertTrue("It is empty: " + c, c.isEmpty());
106.1623 - }
106.1624 -
106.1625 - public void testCanProxyLookupHaveWrongResults() {
106.1626 - class L implements LookupListener {
106.1627 - ProxyLookup pl;
106.1628 - Lookup.Result<String> original;
106.1629 - Lookup.Result<String> wrapped;
106.1630 - boolean ok;
106.1631 -
106.1632 - public void test() {
106.1633 - pl = new ProxyLookup(lookup);
106.1634 - original = lookup.lookupResult(String.class);
106.1635 -
106.1636 - original.addLookupListener(this);
106.1637 -
106.1638 - wrapped = pl.lookupResult(String.class);
106.1639 -
106.1640 - assertEquals("Original empty", 0, original.allInstances().size());
106.1641 - assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
106.1642 -
106.1643 - ic.add("Hello!");
106.1644 - }
106.1645 -
106.1646 - public void resultChanged(LookupEvent ev) {
106.1647 - ok = true;
106.1648 -
106.1649 - assertEquals("Original has hello", 1, original.allInstances().size());
106.1650 - assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
106.1651 - }
106.1652 -
106.1653 - }
106.1654 - L listener = new L();
106.1655 - listener.test();
106.1656 - assertTrue("Listener called", listener.ok);
106.1657 - }
106.1658 -
106.1659 - public void testObjectFromInstanceContentConverterDisappearsIfNotReferenced() {
106.1660 - Conv converter = new Conv("foo");
106.1661 - ic.add (converter, converter);
106.1662 - Lookup lkp = instanceLookup;
106.1663 - StringBuilder sb = lookup.lookup (StringBuilder.class);
106.1664 - assertNotNull (sb);
106.1665 - int hash = System.identityHashCode(sb);
106.1666 - assertEquals ("foo", sb.toString());
106.1667 - Reference<StringBuilder> r = new WeakReference<StringBuilder>(sb);
106.1668 - sb = null;
106.1669 - assertGC("Lookup held onto object", r);
106.1670 - sb = lookup.lookup (StringBuilder.class);
106.1671 - assertNotSame(hash, System.identityHashCode(sb));
106.1672 - r = new WeakReference<StringBuilder>(sb);
106.1673 - sb = null;
106.1674 - assertGC("Lookup held onto object", r);
106.1675 - ic.remove (converter, converter);
106.1676 - Reference <InstanceContent.Convertor> cref = new WeakReference<InstanceContent.Convertor>(converter);
106.1677 - converter = null;
106.1678 - assertGC("Converter still referenced", cref);
106.1679 -
106.1680 - sb = lkp.lookup(StringBuilder.class);
106.1681 - assertNull ("Converter removed from lookup, but object it " +
106.1682 - "created still present:'" + sb +"'", sb);
106.1683 - converter = new Conv("bar");
106.1684 - ic.add (converter, converter);
106.1685 - assertNotNull (lkp.lookup(StringBuilder.class));
106.1686 - assertEquals ("bar", lkp.lookup(StringBuilder.class).toString());
106.1687 - }
106.1688 -
106.1689 - private static class Conv implements InstanceContent.Convertor<Conv, StringBuilder> {
106.1690 - private final String str;
106.1691 - private Conv (String str) {
106.1692 - this.str = str;
106.1693 - }
106.1694 -
106.1695 - public StringBuilder convert(Conv obj) {
106.1696 - return new StringBuilder (str);
106.1697 - }
106.1698 -
106.1699 - public Class<? extends StringBuilder> type(Conv obj) {
106.1700 - return StringBuilder.class;
106.1701 - }
106.1702 -
106.1703 - public String id(Conv obj) {
106.1704 - return "Foo";
106.1705 - }
106.1706 -
106.1707 - public String displayName(Conv obj) {
106.1708 - return "Foo";
106.1709 - }
106.1710 - } // end of Conv
106.1711 -
106.1712 - public void testCanGCResults() throws Exception {
106.1713 - class L implements LookupListener {
106.1714 - int cnt;
106.1715 -
106.1716 - public void resultChanged(LookupEvent ev) {
106.1717 - cnt++;
106.1718 - }
106.1719 -
106.1720 - }
106.1721 - L listener1 = new L();
106.1722 - L listener2 = new L();
106.1723 -
106.1724 - Lookup.Result<String> res1 = this.instanceLookup.lookupResult(String.class);
106.1725 - Lookup.Result<String> res2 = this.lookup.lookupResult(String.class);
106.1726 -
106.1727 - assertEquals("Empty1", 0, res1.allItems().size());
106.1728 - assertEquals("Empty2", 0, res2.allItems().size());
106.1729 -
106.1730 - res1.addLookupListener(listener1);
106.1731 - res2.addLookupListener(listener2);
106.1732 -
106.1733 - addInstances(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
106.1734 - this.ic.add("Ahoj");
106.1735 -
106.1736 - assertEquals("Change1", 1, listener1.cnt);
106.1737 - assertEquals("Change2", 1, listener2.cnt);
106.1738 -
106.1739 - assertEquals("Full1", 1, res1.allItems().size());
106.1740 - assertEquals("Full2", 1, res2.allItems().size());
106.1741 -
106.1742 -
106.1743 - Reference<Object> ref2 = new WeakReference<Object>(res2);
106.1744 - res2 = null;
106.1745 - assertGC("Result can disappear", ref2);
106.1746 - }
106.1747 -
106.1748 - void beforeActualTest(String n) {
106.1749 - if (n.equals("testEqualsIsNotCalledTooMuch")) {
106.1750 - CntPair.cnt = 0;
106.1751 - CntPair.hashCnt = 0;
106.1752 - CntPair.instances = 0;
106.1753 - int how = 1000;
106.1754 -
106.1755 - for(int i = 0; i < how; i++) {
106.1756 - this.ic.addPair(new CntPair("x" + i));
106.1757 - }
106.1758 -
106.1759 - assertEquals("No equals called", 0, CntPair.cnt);
106.1760 - assertEquals("1000 instances ", how, CntPair.instances);
106.1761 - }
106.1762 - }
106.1763 -
106.1764 - public void testEqualsIsNotCalledTooMuch() throws Exception {
106.1765 - // most of the work done in beforeActualTest
106.1766 -
106.1767 - // desirable: assertEquals("no comparitions", 0, CntPair.cnt);
106.1768 - // works for InheritanceTree, but not for ArrayStorage, but array
106.1769 - // storages are generally small
106.1770 -
106.1771 - if (CntPair.cnt > 12000) {
106.1772 - fail("Too much comparitions " + CntPair.cnt);
106.1773 - }
106.1774 - if (CntPair.hashCnt > 40000) {
106.1775 - fail("Too much hashes: " + CntPair.hashCnt);
106.1776 - }
106.1777 -
106.1778 - assertEquals("instaces is enough", 1000, CntPair.instances);
106.1779 - }
106.1780 -
106.1781 - /** Adds instances to the instance lookup.
106.1782 - */
106.1783 - private void addInstances (Object... instances) {
106.1784 - for (int i = 0; i < instances.length; i++) {
106.1785 - ic.add(instances[i]);
106.1786 - }
106.1787 - }
106.1788 -
106.1789 - /** Count instances of clazz in an array. */
106.1790 - private int countInstances (Object[] objs, Class clazz) {
106.1791 - int count = 0;
106.1792 - for (int i = 0; i < objs.length; i++) {
106.1793 - if (clazz.isInstance(objs[i])) count++;
106.1794 - }
106.1795 - return count;
106.1796 - }
106.1797 -
106.1798 - /** Counting listener */
106.1799 - protected static class LL implements LookupListener {
106.1800 - private int count = 0;
106.1801 - public Object source;
106.1802 - public Thread changesIn;
106.1803 -
106.1804 - public LL () {
106.1805 - this (null);
106.1806 - }
106.1807 -
106.1808 - public LL (Object source) {
106.1809 - this.source = source;
106.1810 - }
106.1811 -
106.1812 - public void resultChanged(LookupEvent ev) {
106.1813 - if (changesIn != null) {
106.1814 - assertEquals("Changes in the same thread", changesIn, Thread.currentThread());
106.1815 - } else {
106.1816 - changesIn = Thread.currentThread();
106.1817 - }
106.1818 - ++count;
106.1819 - if (source != null) {
106.1820 - assertSame ("Source is the same", source, ev.getSource ());
106.1821 -// assertSame ("Result is the same", source, ev.getResult ());
106.1822 - }
106.1823 - }
106.1824 -
106.1825 - public int getCount() {
106.1826 - int i = count;
106.1827 - count = 0;
106.1828 - return i;
106.1829 - }
106.1830 - };
106.1831 -
106.1832 - /** A set of interfaces for testInterfaceInheritance
106.1833 - */
106.1834 - interface TestInterfaceInheritanceA {}
106.1835 - interface TestInterfaceInheritanceB extends TestInterfaceInheritanceA, java.rmi.Remote {}
106.1836 - interface TestInterfaceInheritanceBB extends TestInterfaceInheritanceB {}
106.1837 - interface TestInterfaceInheritanceC extends TestInterfaceInheritanceA, java.rmi.Remote {}
106.1838 - interface TestInterfaceInheritanceD extends TestInterfaceInheritanceA {}
106.1839 -
106.1840 - /** A special class for garbage test */
106.1841 - public static final class Garbage extends Object implements Serializable {
106.1842 - static final long serialVersionUID = 435340912534L;
106.1843 - }
106.1844 -
106.1845 -
106.1846 - /* A classloader that can load one class in a special way */
106.1847 - private static class CL extends ClassLoader {
106.1848 - public CL () {
106.1849 - super (null);
106.1850 - }
106.1851 -
106.1852 - public @Override Class findClass(String name) throws ClassNotFoundException {
106.1853 - if (name.equals (Garbage.class.getName ())) {
106.1854 - String n = name.replace ('.', '/');
106.1855 - java.io.InputStream is = getClass ().getResourceAsStream ("/" + n + ".class");
106.1856 - byte[] arr = new byte[8096];
106.1857 - try {
106.1858 - int cnt = is.read (arr);
106.1859 - if (cnt == arr.length) {
106.1860 - fail ("Buffer to load the class is not big enough");
106.1861 - }
106.1862 -
106.1863 - return defineClass (name, arr, 0, cnt);
106.1864 - } catch (java.io.IOException ex) {
106.1865 - ex.printStackTrace();
106.1866 - fail ("IO Exception");
106.1867 - return null;
106.1868 - }
106.1869 - } else {
106.1870 - return null;
106.1871 - }
106.1872 - }
106.1873 -
106.1874 - /** Convert obj to other object. There is no need to implement
106.1875 - * cache mechanism. It is provided by AbstractLookup.Item.getInstance().
106.1876 - * Method should be called more than once because Lookup holds
106.1877 - * just weak reference.
106.1878 - */
106.1879 - public Object convert(Object obj) {
106.1880 - return null;
106.1881 - }
106.1882 -
106.1883 - /** Return type of converted object. */
106.1884 - public Class type(Object obj) {
106.1885 - try {
106.1886 - return loadClass (Garbage.class.getName ());
106.1887 - } catch (ClassNotFoundException ex) {
106.1888 - fail ("Class not found");
106.1889 - throw new InternalError ();
106.1890 - }
106.1891 - }
106.1892 - }
106.1893 -
106.1894 - private static final class CntPair extends AbstractLookup.Pair {
106.1895 - private static int instances;
106.1896 - private String txt;
106.1897 -
106.1898 - public CntPair(String txt) {
106.1899 - this.txt = txt;
106.1900 - instances++;
106.1901 - }
106.1902 -
106.1903 - public static int hashCnt;
106.1904 - @Override
106.1905 - public int hashCode() {
106.1906 - hashCnt++;
106.1907 - return txt.hashCode() + 3777;
106.1908 - }
106.1909 -
106.1910 - public static int cnt;
106.1911 - @Override
106.1912 - public boolean equals(Object obj) {
106.1913 - cnt++;
106.1914 -
106.1915 - if (obj == null) {
106.1916 - return false;
106.1917 - }
106.1918 - if (getClass() != obj.getClass()) {
106.1919 - return false;
106.1920 - }
106.1921 - final CntPair other = (CntPair) obj;
106.1922 - if (this.txt != other.txt && (this.txt == null || !this.txt.equals(other.txt))) {
106.1923 - return false;
106.1924 - }
106.1925 - return true;
106.1926 - }
106.1927 -
106.1928 - protected boolean instanceOf(Class c) {
106.1929 - return c.isAssignableFrom(String.class);
106.1930 - }
106.1931 -
106.1932 - protected boolean creatorOf(Object obj) {
106.1933 - return obj == txt;
106.1934 - }
106.1935 -
106.1936 - public Object getInstance() {
106.1937 - return txt;
106.1938 - }
106.1939 -
106.1940 - public Class getType() {
106.1941 - return String.class;
106.1942 - }
106.1943 -
106.1944 - public String getId() {
106.1945 - return txt;
106.1946 - }
106.1947 -
106.1948 - public String getDisplayName() {
106.1949 - return txt;
106.1950 - }
106.1951 -
106.1952 - }
106.1953 -
106.1954 - public static final class SerialPair extends AbstractLookup.Pair
106.1955 - implements java.io.Serializable {
106.1956 - static final long serialVersionUID = 54305834L;
106.1957 - private Object value;
106.1958 - public transient int countInstanceOf;
106.1959 -
106.1960 - public SerialPair (Object value) {
106.1961 - this.value = value;
106.1962 - }
106.1963 -
106.1964 - protected boolean creatorOf(Object obj) {
106.1965 - return obj == value;
106.1966 - }
106.1967 -
106.1968 - public String getDisplayName() {
106.1969 - return getId ();
106.1970 - }
106.1971 -
106.1972 - public String getId() {
106.1973 - return value.toString();
106.1974 - }
106.1975 -
106.1976 - public Object getInstance() {
106.1977 - return value;
106.1978 - }
106.1979 -
106.1980 - public Class getType() {
106.1981 - return value.getClass ();
106.1982 - }
106.1983 -
106.1984 - protected boolean instanceOf(Class c) {
106.1985 - countInstanceOf++;
106.1986 - return c.isInstance(value);
106.1987 - }
106.1988 - } // end of SerialPair
106.1989 -
106.1990 - private static class BrokenPair extends AbstractLookup.Pair {
106.1991 - private transient ThreadLocal IN = new ThreadLocal ();
106.1992 - private boolean checkModify;
106.1993 - private boolean checkQuery;
106.1994 -
106.1995 - public BrokenPair (boolean checkModify, boolean checkQuery) {
106.1996 - this.checkModify = checkModify;
106.1997 - this.checkQuery = checkQuery;
106.1998 - }
106.1999 -
106.2000 - protected boolean creatorOf(Object obj) { return this == obj; }
106.2001 - public String getDisplayName() { return "Broken"; }
106.2002 - public String getId() { return "broken"; }
106.2003 - public Object getInstance() { return this; }
106.2004 - public Class getType() { return getClass (); }
106.2005 - protected boolean instanceOf(Class c) {
106.2006 -
106.2007 - if (checkQuery) {
106.2008 - if (IN.get () == null) {
106.2009 - try {
106.2010 - IN.set (this);
106.2011 - // broken behaviour, tries to modify the lookup
106.2012 - // queries have to survive
106.2013 -
106.2014 - running.lookup.lookup (java.awt.List.class);
106.2015 -
106.2016 - //
106.2017 - // creation of new result has to survive as well
106.2018 - Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.Button.class));
106.2019 - Collection all = myQuery.allItems ();
106.2020 - } finally {
106.2021 - IN.set (null);
106.2022 - }
106.2023 - }
106.2024 - }
106.2025 -
106.2026 -
106.2027 - if (checkModify) {
106.2028 - //
106.2029 - // modifications should fail
106.2030 - //
106.2031 -
106.2032 - try {
106.2033 - running.ic.addPair (new SerialPair (""));
106.2034 - fail ("Modification from a query should be prohibited");
106.2035 - } catch (IllegalStateException ex) {
106.2036 - }
106.2037 -
106.2038 - try {
106.2039 - running.ic.removePair (this);
106.2040 - fail ("This has to throw the exception");
106.2041 - } catch (IllegalStateException ex) {
106.2042 - }
106.2043 - try {
106.2044 - running.ic.setPairs (Collections.EMPTY_SET);
106.2045 - fail ("This has to throw the exception as well");
106.2046 - } catch (IllegalStateException ex) {
106.2047 - }
106.2048 - }
106.2049 -
106.2050 - return c.isAssignableFrom(getType ());
106.2051 - }
106.2052 - } // end of BrokenPair
106.2053 -
106.2054 - private static class Broken2Pair extends AbstractLookup.Pair {
106.2055 - static final long serialVersionUID = 4532587018501L;
106.2056 - public transient ThreadLocal IN;
106.2057 -
106.2058 - public Broken2Pair () {
106.2059 - }
106.2060 -
106.2061 - private void writeObject (java.io.ObjectOutputStream oos) throws java.io.IOException {
106.2062 - }
106.2063 -
106.2064 - private void readObject (java.io.ObjectInputStream ois) throws java.io.IOException, ClassNotFoundException {
106.2065 - IN = new ThreadLocal ();
106.2066 - }
106.2067 -
106.2068 - protected boolean creatorOf(Object obj) { return this == obj; }
106.2069 - public String getDisplayName() { return "Broken"; }
106.2070 - public String getId() { return "broken"; }
106.2071 - public Object getInstance() { return this; }
106.2072 - public Class getType() { return getClass (); }
106.2073 - protected boolean instanceOf(Class c) {
106.2074 -
106.2075 - // behaviour gets broken only after deserialization
106.2076 - if (IN != null && IN.get () == null) {
106.2077 - try {
106.2078 - IN.set (this);
106.2079 -
106.2080 - // creation of new result has to survive as well
106.2081 - Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.List.class));
106.2082 - Collection all = myQuery.allItems ();
106.2083 - } finally {
106.2084 - IN.set (null);
106.2085 - }
106.2086 - }
106.2087 -
106.2088 - return c.isAssignableFrom(getType ());
106.2089 - }
106.2090 - } // end of Broken2Pair
106.2091 -}
107.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupExecutorTest.java Sat Oct 31 15:06:58 2009 +0100
107.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
107.3 @@ -1,98 +0,0 @@
107.4 -/*
107.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
107.6 - *
107.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
107.8 - *
107.9 - * The contents of this file are subject to the terms of either the GNU
107.10 - * General Public License Version 2 only ("GPL") or the Common
107.11 - * Development and Distribution License("CDDL") (collectively, the
107.12 - * "License"). You may not use this file except in compliance with the
107.13 - * License. You can obtain a copy of the License at
107.14 - * http://www.netbeans.org/cddl-gplv2.html
107.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
107.16 - * specific language governing permissions and limitations under the
107.17 - * License. When distributing the software, include this License Header
107.18 - * Notice in each file and include the License file at
107.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
107.20 - * particular file as subject to the "Classpath" exception as provided
107.21 - * by Sun in the GPL Version 2 section of the License file that
107.22 - * accompanied this code. If applicable, add the following below the
107.23 - * License Header, with the fields enclosed by brackets [] replaced by
107.24 - * your own identifying information:
107.25 - * "Portions Copyrighted [year] [name of copyright owner]"
107.26 - *
107.27 - * Contributor(s):
107.28 - *
107.29 - * The Original Software is NetBeans. The Initial Developer of the Original
107.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
107.31 - * Microsystems, Inc. All Rights Reserved.
107.32 - *
107.33 - * If you wish your version of this file to be governed by only the CDDL
107.34 - * or only the GPL Version 2, indicate your decision by adding
107.35 - * "[Contributor] elects to include this software in this distribution
107.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
107.37 - * single choice of license, a recipient has the option to distribute
107.38 - * your version of this file under either the CDDL, the GPL Version 2 or
107.39 - * to extend the choice of license to its licensees as provided above.
107.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
107.41 - * Version 2 license, then the option applies only if the new code is
107.42 - * made subject to such option by the copyright holder.
107.43 - */
107.44 -
107.45 -package org.openide.util.lookup;
107.46 -
107.47 -import java.util.concurrent.Executor;
107.48 -import org.openide.util.Lookup;
107.49 -import org.openide.util.LookupEvent;
107.50 -import org.openide.util.LookupListener;
107.51 -
107.52 -public class AbstractLookupExecutorTest extends AbstractLookupBaseHid
107.53 -implements AbstractLookupBaseHid.Impl, Executor, LookupListener {
107.54 - Lookup.Result<?> res;
107.55 -
107.56 -
107.57 - public AbstractLookupExecutorTest(java.lang.String testName) {
107.58 - super(testName, null);
107.59 - }
107.60 -
107.61 - //
107.62 - // Impl of AbstractLookupBaseHid.Impl
107.63 - //
107.64 -
107.65 - /** Creates the initial abstract lookup.
107.66 - */
107.67 - public Lookup createInstancesLookup (InstanceContent ic) {
107.68 - ic.attachExecutor(this);
107.69 - Lookup l = new AbstractLookup (ic, new InheritanceTree ());
107.70 - return l;
107.71 - }
107.72 -
107.73 - /** Creates an lookup for given lookup. This class just returns
107.74 - * the object passed in, but subclasses can be different.
107.75 - * @param lookup in lookup
107.76 - * @return a lookup to use
107.77 - */
107.78 - public Lookup createLookup (Lookup lookup) {
107.79 - res = lookup.lookupResult(Object.class);
107.80 - res.addLookupListener(this);
107.81 - return lookup;
107.82 - }
107.83 -
107.84 - public void clearCaches () {
107.85 - }
107.86 -
107.87 - ThreadLocal<Object> ME = new ThreadLocal<Object>();
107.88 - public void execute(Runnable command) {
107.89 - assertEquals("Not yet set", null, ME.get());
107.90 - ME.set(this);
107.91 - try {
107.92 - command.run();
107.93 - } finally {
107.94 - ME.set(null);
107.95 - }
107.96 - }
107.97 -
107.98 - public void resultChanged(LookupEvent ev) {
107.99 - assertEquals("Changes delivered only from execute method", this, ME.get());
107.100 - }
107.101 -}
108.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupMemoryTest.java Sat Oct 31 15:06:58 2009 +0100
108.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
108.3 @@ -1,158 +0,0 @@
108.4 -/*
108.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
108.6 - *
108.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
108.8 - *
108.9 - * The contents of this file are subject to the terms of either the GNU
108.10 - * General Public License Version 2 only ("GPL") or the Common
108.11 - * Development and Distribution License("CDDL") (collectively, the
108.12 - * "License"). You may not use this file except in compliance with the
108.13 - * License. You can obtain a copy of the License at
108.14 - * http://www.netbeans.org/cddl-gplv2.html
108.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
108.16 - * specific language governing permissions and limitations under the
108.17 - * License. When distributing the software, include this License Header
108.18 - * Notice in each file and include the License file at
108.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
108.20 - * particular file as subject to the "Classpath" exception as provided
108.21 - * by Sun in the GPL Version 2 section of the License file that
108.22 - * accompanied this code. If applicable, add the following below the
108.23 - * License Header, with the fields enclosed by brackets [] replaced by
108.24 - * your own identifying information:
108.25 - * "Portions Copyrighted [year] [name of copyright owner]"
108.26 - *
108.27 - * Contributor(s):
108.28 - *
108.29 - * The Original Software is NetBeans. The Initial Developer of the Original
108.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
108.31 - * Microsystems, Inc. All Rights Reserved.
108.32 - *
108.33 - * If you wish your version of this file to be governed by only the CDDL
108.34 - * or only the GPL Version 2, indicate your decision by adding
108.35 - * "[Contributor] elects to include this software in this distribution
108.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
108.37 - * single choice of license, a recipient has the option to distribute
108.38 - * your version of this file under either the CDDL, the GPL Version 2 or
108.39 - * to extend the choice of license to its licensees as provided above.
108.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
108.41 - * Version 2 license, then the option applies only if the new code is
108.42 - * made subject to such option by the copyright holder.
108.43 - */
108.44 -
108.45 -package org.openide.util.lookup;
108.46 -
108.47 -import java.util.*;
108.48 -import org.netbeans.junit.*;
108.49 -import org.netbeans.modules.openide.util.ActiveQueue;
108.50 -import org.openide.util.Lookup;
108.51 -
108.52 -/** Testing memory consumption of various AbstractLookup aspects.
108.53 - */
108.54 -public class AbstractLookupMemoryTest extends NbTestCase {
108.55 - public AbstractLookupMemoryTest(java.lang.String testName) {
108.56 - super(testName);
108.57 - }
108.58 -
108.59 - public static void main(java.lang.String[] args) {
108.60 - junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupMemoryTest.class));
108.61 - }
108.62 -
108.63 - public void testEmptySize () {
108.64 - AbstractLookup instanceLookup = new AbstractLookup ();
108.65 - assertSize ("Empty lookup should be small", 16, instanceLookup);
108.66 -
108.67 - InstanceContent ic = new InstanceContent ();
108.68 - instanceLookup = new AbstractLookup (ic);
108.69 - assertSize ("Lookup with InstanceContent should be small as well", 16, instanceLookup);
108.70 - }
108.71 -
108.72 - public void testPairSize () {
108.73 - AbstractLookup.Pair pair = new EmptyPair ();
108.74 - assertSize ("Pair occupies only 16 bytes", 16, pair);
108.75 - }
108.76 -
108.77 - public void testPairWithOnePointerSize () {
108.78 - AbstractLookup.Pair pair = new OneItemPair ();
108.79 - assertSize ("Pair occupies only 16 bytes", 16, pair);
108.80 - }
108.81 -
108.82 - public void testLookupWithPairs () {
108.83 - Lookup.Template<Object> t = new Lookup.Template<Object>(Object.class);
108.84 - class L implements org.openide.util.LookupListener {
108.85 - public int cnt;
108.86 - public void resultChanged (org.openide.util.LookupEvent ev) {
108.87 - cnt++;
108.88 - }
108.89 - }
108.90 - L listener = new L ();
108.91 - L listener2 = new L ();
108.92 -
108.93 - EmptyPair[] pairs = {
108.94 - new EmptyPair(),
108.95 - new EmptyPair(),
108.96 - new EmptyPair(),
108.97 - new EmptyPair(),
108.98 - };
108.99 - Object[] ignore = {
108.100 - pairs[0],
108.101 - pairs[1],
108.102 - pairs[2],
108.103 - pairs[3],
108.104 - t,
108.105 - ActiveQueue.queue(),
108.106 - listener,
108.107 - listener2,
108.108 - new Integer (11) // trashhold is shared
108.109 - };
108.110 -
108.111 - AbstractLookup.Content c = new AbstractLookup.Content ();
108.112 - AbstractLookup l = new AbstractLookup (c, (Integer)ignore[ignore.length - 1]);
108.113 -
108.114 - c.addPair ((EmptyPair)ignore[0]);
108.115 - assertSize ("Should be really small (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
108.116 -
108.117 - c.addPair ((EmptyPair)ignore[1]);
108.118 - assertSize ("Is bigger I guess (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
108.119 -
108.120 - c.setPairs(Arrays.asList(pairs).subList(0, 3));
108.121 - assertSize ("Even bigger (not counting the pair sizes)", Collections.singleton (l), 64, ignore);
108.122 -
108.123 - c.setPairs(Arrays.asList(pairs).subList(0, 4));
108.124 - assertSize ("Now not that much(not counting the pair sizes)", Collections.singleton (l), 64, ignore);
108.125 -
108.126 - Lookup.Result res = l.lookup (t);
108.127 -
108.128 - assertSize ("After creating a result", Collections.singleton (l), 120, ignore);
108.129 -
108.130 - res.addLookupListener (listener);
108.131 -
108.132 - assertSize ("And attaching one listener", Collections.singleton (l), 120, ignore);
108.133 -
108.134 - res.addLookupListener (listener2);
108.135 - assertSize ("Second listener makes the situation much worse", Collections.singleton (l), 200, ignore);
108.136 - res.removeLookupListener(listener2);
108.137 - assertSize ("But removing it returns us back to original size", Collections.singleton (l), 120, ignore);
108.138 -
108.139 -
108.140 - assertEquals ("Current for pairs are in", res.allItems ().size (), 4); // also activates the listener
108.141 - assertSize ("and making the listener to work", Collections.singleton (l), 120, ignore);
108.142 -
108.143 - c.removePair ((EmptyPair)ignore[0]);
108.144 - assertEquals ("A changes has been delivered", 1, listener.cnt);
108.145 - }
108.146 -
108.147 - /** Simple pair with no data */
108.148 - private static class EmptyPair extends AbstractLookup.Pair {
108.149 - protected boolean creatorOf(Object obj) { return false; }
108.150 - public String getDisplayName() { return ""; }
108.151 - public String getId() { return ""; }
108.152 - public Object getInstance() { return null; }
108.153 - public Class getType() { return Object.class; }
108.154 - protected boolean instanceOf(Class c) { return c == getType (); }
108.155 - } // end of EmptyPair
108.156 -
108.157 - /** Pair with one item (like InstanceContent.Pair) */
108.158 - private static class OneItemPair extends EmptyPair {
108.159 - private Object pointer;
108.160 - }
108.161 -}
109.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupTest.java Sat Oct 31 15:06:58 2009 +0100
109.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
109.3 @@ -1,356 +0,0 @@
109.4 -/*
109.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
109.6 - *
109.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
109.8 - *
109.9 - * The contents of this file are subject to the terms of either the GNU
109.10 - * General Public License Version 2 only ("GPL") or the Common
109.11 - * Development and Distribution License("CDDL") (collectively, the
109.12 - * "License"). You may not use this file except in compliance with the
109.13 - * License. You can obtain a copy of the License at
109.14 - * http://www.netbeans.org/cddl-gplv2.html
109.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
109.16 - * specific language governing permissions and limitations under the
109.17 - * License. When distributing the software, include this License Header
109.18 - * Notice in each file and include the License file at
109.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
109.20 - * particular file as subject to the "Classpath" exception as provided
109.21 - * by Sun in the GPL Version 2 section of the License file that
109.22 - * accompanied this code. If applicable, add the following below the
109.23 - * License Header, with the fields enclosed by brackets [] replaced by
109.24 - * your own identifying information:
109.25 - * "Portions Copyrighted [year] [name of copyright owner]"
109.26 - *
109.27 - * Contributor(s):
109.28 - *
109.29 - * The Original Software is NetBeans. The Initial Developer of the Original
109.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
109.31 - * Microsystems, Inc. All Rights Reserved.
109.32 - *
109.33 - * If you wish your version of this file to be governed by only the CDDL
109.34 - * or only the GPL Version 2, indicate your decision by adding
109.35 - * "[Contributor] elects to include this software in this distribution
109.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
109.37 - * single choice of license, a recipient has the option to distribute
109.38 - * your version of this file under either the CDDL, the GPL Version 2 or
109.39 - * to extend the choice of license to its licensees as provided above.
109.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
109.41 - * Version 2 license, then the option applies only if the new code is
109.42 - * made subject to such option by the copyright holder.
109.43 - */
109.44 -
109.45 -package org.openide.util.lookup;
109.46 -
109.47 -import java.util.concurrent.ExecutionException;
109.48 -
109.49 -import java.lang.ref.WeakReference;
109.50 -import java.util.*;
109.51 -import java.util.concurrent.Executors;
109.52 -import java.util.concurrent.TimeUnit;
109.53 -import org.netbeans.junit.*;
109.54 -import org.openide.util.Lookup;
109.55 -import org.openide.util.lookup.AbstractLookup.Pair;
109.56 -
109.57 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
109.58 -public class AbstractLookupTest extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
109.59 - public AbstractLookupTest(java.lang.String testName) {
109.60 - super(testName, null);
109.61 - }
109.62 -
109.63 - //
109.64 - // Impl of AbstractLookupBaseHid.Impl
109.65 - //
109.66 -
109.67 - /** Creates the initial abstract lookup.
109.68 - */
109.69 - public Lookup createInstancesLookup (InstanceContent ic) {
109.70 - return new AbstractLookup (ic, new InheritanceTree ());
109.71 - }
109.72 -
109.73 - /** Creates an lookup for given lookup. This class just returns
109.74 - * the object passed in, but subclasses can be different.
109.75 - * @param lookup in lookup
109.76 - * @return a lookup to use
109.77 - */
109.78 - public Lookup createLookup (Lookup lookup) {
109.79 - return lookup;
109.80 - }
109.81 -
109.82 - public void clearCaches () {
109.83 - }
109.84 -
109.85 - public static void main(java.lang.String[] args) {
109.86 - junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupTest.class));
109.87 - }
109.88 -
109.89 - static class LkpResultCanBeGargageCollectedAndClearsTheResult extends AbstractLookup {
109.90 - public int cleared;
109.91 - public int dirty;
109.92 -
109.93 - synchronized @Override boolean cleanUpResult(Template t) {
109.94 - boolean res = super.cleanUpResult (t);
109.95 - if (res) {
109.96 - cleared++;
109.97 - } else {
109.98 - dirty++;
109.99 - }
109.100 -
109.101 - notifyAll ();
109.102 -
109.103 - return res;
109.104 - }
109.105 - }
109.106 - public void testResultCanBeGargageCollectedAndClearsTheResult () throws Exception {
109.107 - LkpResultCanBeGargageCollectedAndClearsTheResult lkp = new LkpResultCanBeGargageCollectedAndClearsTheResult ();
109.108 - assertSize ("24 for AbstractLookup, 8 for two ints", 32, lkp);
109.109 - synchronized (lkp) {
109.110 - Lookup.Result res = lkp.lookup (new Lookup.Template (getClass ()));
109.111 - res.allItems();
109.112 -
109.113 - WeakReference ref = new WeakReference (res);
109.114 - res = null;
109.115 - assertGC ("Reference can get cleared", ref);
109.116 -
109.117 - // wait till we
109.118 - while (lkp.cleared == 0 && lkp.dirty == 0) {
109.119 - lkp.wait ();
109.120 - }
109.121 -
109.122 - assertEquals ("No dirty cleanups", 0, lkp.dirty);
109.123 - assertEquals ("One final cleanup", 1, lkp.cleared);
109.124 - }
109.125 - //assertSize ("Everything has been cleaned to original size", 32, lkp);
109.126 -
109.127 - }
109.128 -
109.129 - public void testPairCannotBeUsedInMoreThanOneLookupAtOnce () throws Exception {
109.130 - /** Simple pair with no data */
109.131 - class EmptyPair extends AbstractLookup.Pair {
109.132 - protected boolean creatorOf(Object obj) { return false; }
109.133 - public String getDisplayName() { return "Empty"; }
109.134 - public String getId() { return "empty"; }
109.135 - public Object getInstance() { return null; }
109.136 - public Class getType() { return Object.class; }
109.137 - protected boolean instanceOf(Class c) { return c == getType (); }
109.138 - } // end of EmptyPair
109.139 -
109.140 - AbstractLookup.Content c1 = new AbstractLookup.Content ();
109.141 - AbstractLookup.Content c2 = new AbstractLookup.Content ();
109.142 - AbstractLookup l1 = new AbstractLookup (c1);
109.143 - AbstractLookup l2 = new AbstractLookup (c2);
109.144 -
109.145 - EmptyPair empty = new EmptyPair ();
109.146 - c1.addPair (empty);
109.147 - Lookup.Result res = l1.lookup (new Lookup.Template (Object.class));
109.148 - assertEquals (
109.149 - "Pair is really found", empty,
109.150 - res.allItems ().iterator().next ()
109.151 - );
109.152 - try {
109.153 - c2.addPair (empty);
109.154 - fail ("It should not be possible to add pair to two lookups");
109.155 - } catch (IllegalStateException ex) {
109.156 - // ok, exception is fine
109.157 - }
109.158 - assertEquals (
109.159 - "L2 is still empty", Collections.EMPTY_LIST,
109.160 - new ArrayList (l2.lookup (new Lookup.Template (Object.class)).allItems ())
109.161 - );
109.162 - }
109.163 -
109.164 - public void testInitializationCanBeDoneFromAnotherThread () {
109.165 - class MyLkp extends AbstractLookup implements Runnable {
109.166 - private InstanceContent ic;
109.167 - private boolean direct;
109.168 -
109.169 - public MyLkp (boolean direct) {
109.170 - this (direct, new InstanceContent ());
109.171 - }
109.172 -
109.173 - private MyLkp (boolean direct, InstanceContent ic) {
109.174 - super (ic);
109.175 - this.direct = direct;
109.176 - this.ic = ic;
109.177 - }
109.178 -
109.179 - protected @Override void initialize() {
109.180 - if (direct) {
109.181 - run ();
109.182 - } else {
109.183 - try {
109.184 - Executors.newSingleThreadScheduledExecutor().schedule(this, 0, TimeUnit.MICROSECONDS).get();
109.185 - } catch (InterruptedException ex) {
109.186 - ex.printStackTrace();
109.187 - } catch (ExecutionException ex) {
109.188 - ex.printStackTrace();
109.189 - }
109.190 - }
109.191 - }
109.192 -
109.193 - public void run () {
109.194 - ic.add (this);
109.195 - ic.remove (this);
109.196 - ic.set (Collections.nCopies(10, this), null);
109.197 - ic.set (Collections.EMPTY_LIST, null);
109.198 - ic.add (AbstractLookupTest.this);
109.199 - }
109.200 - }
109.201 -
109.202 - assertEquals ("The test should be there", this, new MyLkp (true).lookup (Object.class));
109.203 - assertEquals ("and in async mode as well", this, new MyLkp (false).lookup (Object.class));
109.204 - }
109.205 -
109.206 - public void testBeforeLookupIsCalled () {
109.207 - class BeforeL extends AbstractLookup {
109.208 - public ArrayList list = new ArrayList ();
109.209 - public String toAdd;
109.210 - public InstanceContent ic;
109.211 -
109.212 - public BeforeL () {
109.213 - this (new InstanceContent ());
109.214 - }
109.215 -
109.216 - private BeforeL (InstanceContent c) {
109.217 - super (c);
109.218 - this.ic = c;
109.219 - }
109.220 -
109.221 - protected @Override void beforeLookup(Template t) {
109.222 - if (toAdd != null) {
109.223 - list.add (0, new SerialPair (toAdd));
109.224 - setPairs (list);
109.225 - } else {
109.226 - ic.add (new Integer (1));
109.227 - }
109.228 - }
109.229 - }
109.230 -
109.231 - BeforeL lookup = new BeforeL ();
109.232 -
109.233 - lookup.toAdd = "First";
109.234 - assertEquals ("First if found", "First", lookup.lookup (String.class));
109.235 -
109.236 - lookup.toAdd = "2";
109.237 - assertEquals ("2 is not first", "2", lookup.lookup (String.class));
109.238 -
109.239 - Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
109.240 - for (int i = 3; i < 20; i++) {
109.241 - lookup.toAdd = String.valueOf (i);
109.242 - assertEquals (i + " items are now there", i, res.allInstances ().size ());
109.243 - }
109.244 - for (int i = 20; i < 35; i++) {
109.245 - lookup.toAdd = String.valueOf (i);
109.246 - assertEquals (i + " items are now there", i, res.allItems ().size ());
109.247 - }
109.248 -
109.249 - assertEquals ("Just strings are there now", 1, res.allClasses ().size ());
109.250 - lookup.toAdd = null; // this will add integer
109.251 - assertEquals ("Two classes now", 2, res.allClasses ().size ());
109.252 - }
109.253 -
109.254 - public void testInconsistentAfterDeserIssue71744() throws Exception {
109.255 - InheritanceTree inhTree = new InheritanceTree();
109.256 -
109.257 - AbstractLookup al = new AbstractLookup(new AbstractLookup.Content(), inhTree);
109.258 - {
109.259 -
109.260 - Collection r = al.lookup(new Lookup.Template(Integer.class)).allInstances();
109.261 - assertEquals("None", 0, r.size());
109.262 - }
109.263 -
109.264 - ICP item = new ICP(new Integer(10));
109.265 - al.addPair(item);
109.266 - al.removePair(item);
109.267 -
109.268 - AbstractLookup newLookup = (AbstractLookup)reserialize(al);
109.269 -
109.270 - newLookup.lookup(Number.class);
109.271 -
109.272 -
109.273 - newLookup.addPair(new ICP(new Long(20)));
109.274 -
109.275 - {
109.276 -
109.277 - Collection r = newLookup.lookup(new Lookup.Template(Number.class)).allInstances();
109.278 - assertEquals("one", 1, r.size());
109.279 -/*
109.280 - Iterator it = r.iterator();
109.281 - assertEquals(new Integer(10), it.next());
109.282 - assertEquals(new Long(20), it.next());*/
109.283 - }
109.284 - }
109.285 -
109.286 - public void testMatchesIssue130673() {
109.287 - class BrokenPairReturningNullID extends Pair<Object> {
109.288 - @Override
109.289 - protected boolean instanceOf(Class<?> c) {
109.290 - return false;
109.291 - }
109.292 -
109.293 - @Override
109.294 - protected boolean creatorOf(Object obj) {
109.295 - return false;
109.296 - }
109.297 -
109.298 - @Override
109.299 - public Object getInstance() {
109.300 - return null;
109.301 - }
109.302 -
109.303 - @Override
109.304 - public Class<? extends Object> getType() {
109.305 - return null;
109.306 - }
109.307 -
109.308 - @Override
109.309 - public String getId() {
109.310 - return null;
109.311 - }
109.312 -
109.313 - @Override
109.314 - public String getDisplayName() {
109.315 - return null;
109.316 - }
109.317 - }
109.318 - BrokenPairReturningNullID broken = new BrokenPairReturningNullID();
109.319 -
109.320 -
109.321 - Lookup.Template<String> t = new Lookup.Template<String>(String.class, "ID", null);
109.322 - boolean not = AbstractLookup.matches(t, broken, true);
109.323 - assertFalse("Does not match the template, but throws no exception", not);
109.324 - }
109.325 -
109.326 - private static final class ICP extends AbstractLookup.Pair {
109.327 - private Number s;
109.328 -
109.329 - public ICP (Number s) {
109.330 - this.s = s;
109.331 - }
109.332 -
109.333 -
109.334 - protected boolean instanceOf(Class c) {
109.335 - return c.isInstance(s);
109.336 - }
109.337 -
109.338 - protected boolean creatorOf(Object obj) {
109.339 - return s == obj;
109.340 - }
109.341 -
109.342 - public Object getInstance() {
109.343 - return s;
109.344 - }
109.345 -
109.346 - public Class getType() {
109.347 - return s.getClass();
109.348 - }
109.349 -
109.350 - public String getId() {
109.351 - return s.toString();
109.352 - }
109.353 -
109.354 - public String getDisplayName() {
109.355 - return getId();
109.356 - }
109.357 -
109.358 - }
109.359 -}
110.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java Sat Oct 31 15:06:58 2009 +0100
110.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
110.3 @@ -1,228 +0,0 @@
110.4 -/*
110.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
110.6 - *
110.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
110.8 - *
110.9 - * The contents of this file are subject to the terms of either the GNU
110.10 - * General Public License Version 2 only ("GPL") or the Common
110.11 - * Development and Distribution License("CDDL") (collectively, the
110.12 - * "License"). You may not use this file except in compliance with the
110.13 - * License. You can obtain a copy of the License at
110.14 - * http://www.netbeans.org/cddl-gplv2.html
110.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
110.16 - * specific language governing permissions and limitations under the
110.17 - * License. When distributing the software, include this License Header
110.18 - * Notice in each file and include the License file at
110.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
110.20 - * particular file as subject to the "Classpath" exception as provided
110.21 - * by Sun in the GPL Version 2 section of the License file that
110.22 - * accompanied this code. If applicable, add the following below the
110.23 - * License Header, with the fields enclosed by brackets [] replaced by
110.24 - * your own identifying information:
110.25 - * "Portions Copyrighted [year] [name of copyright owner]"
110.26 - *
110.27 - * Contributor(s):
110.28 - *
110.29 - * The Original Software is NetBeans. The Initial Developer of the Original
110.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
110.31 - * Microsystems, Inc. All Rights Reserved.
110.32 - *
110.33 - * If you wish your version of this file to be governed by only the CDDL
110.34 - * or only the GPL Version 2, indicate your decision by adding
110.35 - * "[Contributor] elects to include this software in this distribution
110.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
110.37 - * single choice of license, a recipient has the option to distribute
110.38 - * your version of this file under either the CDDL, the GPL Version 2 or
110.39 - * to extend the choice of license to its licensees as provided above.
110.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
110.41 - * Version 2 license, then the option applies only if the new code is
110.42 - * made subject to such option by the copyright holder.
110.43 - */
110.44 -
110.45 -package org.openide.util.lookup;
110.46 -
110.47 -import java.util.*;
110.48 -import org.openide.util.Lookup;
110.49 -
110.50 -/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
110.51 - */
110.52 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
110.53 -public class ExcludingLookupTest extends AbstractLookupBaseHid
110.54 -implements AbstractLookupBaseHid.Impl {
110.55 - public ExcludingLookupTest(java.lang.String testName) {
110.56 - super(testName, null);
110.57 - }
110.58 -
110.59 - public Lookup createLookup (final Lookup lookup) {
110.60 - return Lookups.exclude (lookup, new Class[0]);
110.61 - }
110.62 -
110.63 - public Lookup createInstancesLookup (InstanceContent ic) {
110.64 - return new AbstractLookup (ic);
110.65 - }
110.66 -
110.67 - public void clearCaches () {
110.68 - }
110.69 -
110.70 - public void testWeCanRemoveInteger () throws Exception {
110.71 - doBasicFilteringTest (Integer.class, Integer.class, 0);
110.72 - }
110.73 -
110.74 - public void testWeCanRemoveIntegersEvenByAskingForRemoveOfAllNumbers () throws Exception {
110.75 - doBasicFilteringTest (Number.class, Integer.class, 0);
110.76 - }
110.77 - public void testFunWithInterfaces () throws Exception {
110.78 - doBasicFilteringTest (java.io.Serializable.class, Integer.class, 0);
110.79 - }
110.80 -
110.81 - public void testWeCanGetInstanceOfSerializableEvenItIsExcludedIfWeAskForClassNotExtendingIt () throws Exception {
110.82 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { java.io.Serializable.class });
110.83 - Lookup.Template t = new Lookup.Template (Object.class);
110.84 - Lookup.Result res = lookup.lookup (t);
110.85 -
110.86 - LL ll = new LL ();
110.87 - res.addLookupListener (ll);
110.88 - assertEquals ("Nothing is there", 0, res.allItems ().size ());
110.89 -
110.90 - Object inst = new Integer (3);
110.91 - ic.add (inst);
110.92 -
110.93 - assertEquals ("Not Filtered out", inst, lookup.lookup (Object.class));
110.94 - assertEquals ("Not Filtered out2", inst, lookup.lookupItem (t).getInstance ());
110.95 - assertEquals ("One is there - 2", 1, res.allItems ().size ());
110.96 - assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
110.97 - assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
110.98 - assertEquals ("Right # of events", 1, ll.getCount ());
110.99 -
110.100 - ic.remove (inst);
110.101 - assertEquals ("Filtered out3", null, lookup.lookupItem (t));
110.102 - assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
110.103 - assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
110.104 - assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
110.105 - assertEquals ("Of course it is not there", null, lookup.lookup (Object.class));
110.106 - assertEquals ("Right # of events", 1, ll.getCount ());
110.107 - }
110.108 -
110.109 - public void testIntegersQueriedThruObject () throws Exception {
110.110 - doBasicFilteringTest (Number.class, Object.class, 1);
110.111 - }
110.112 -
110.113 - private void doBasicFilteringTest (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
110.114 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
110.115 - Lookup.Template t = new Lookup.Template (theQuery);
110.116 - Lookup.Result res = lookup.lookup (t);
110.117 -
110.118 - LL ll = new LL ();
110.119 - res.addLookupListener (ll);
110.120 - assertEquals ("Nothing is there", 0, res.allItems ().size ());
110.121 -
110.122 - Object inst = new Integer (3);
110.123 - ic.add (inst);
110.124 -
110.125 - assertEquals ("Filtered out", null, lookup.lookup (theQuery));
110.126 - assertEquals ("Filtered out2", null, lookup.lookupItem (t));
110.127 - assertEquals ("Nothing is there - 2", 0, res.allItems ().size ());
110.128 - assertEquals ("Nothing is there - 2a", 0, res.allInstances ().size ());
110.129 - assertEquals ("Nothing is there - 2b", 0, res.allClasses ().size ());
110.130 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
110.131 -
110.132 - ic.remove (inst);
110.133 - assertEquals ("Filtered out3", null, lookup.lookupItem (t));
110.134 - assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
110.135 - assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
110.136 - assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
110.137 - assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
110.138 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
110.139 -
110.140 - }
110.141 -
110.142 - public void testSizeOfTheLookup () throws Exception {
110.143 - Class exclude = String.class;
110.144 -
110.145 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { exclude });
110.146 -
110.147 - assertSize ("Should be pretty lightweight", Collections.singleton (lookup), 16,
110.148 - new Object[] { this.instanceLookup, exclude });
110.149 - }
110.150 - public void testSizeOfTheLookupForMultipleFiltersIsHigher () throws Exception {
110.151 - Class exclude = String.class;
110.152 - Class exclude2 = Integer.class;
110.153 - Class[] arr = new Class[] { exclude, exclude2 };
110.154 -
110.155 - Lookup lookup = Lookups.exclude (this.instanceLookup, arr);
110.156 -
110.157 - assertSize ("Is fatter", Collections.singleton (lookup), 40,
110.158 - new Object[] { this.instanceLookup, exclude, exclude2 });
110.159 - assertSize ("But only due to the array", Collections.singleton (lookup), 16,
110.160 - new Object[] { this.instanceLookup, exclude, exclude2, arr });
110.161 - }
110.162 -
110.163 - public void testFilteringOfSomething () throws Exception {
110.164 - doFilteringOfSomething (Runnable.class, java.io.Serializable.class, 1);
110.165 - }
110.166 -
110.167 - private void doFilteringOfSomething (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
110.168 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
110.169 - Lookup.Template t = new Lookup.Template (theQuery);
110.170 - Lookup.Result res = lookup.lookup (t);
110.171 -
110.172 - LL ll = new LL ();
110.173 - res.addLookupListener (ll);
110.174 - assertEquals ("Nothing is there", 0, res.allItems ().size ());
110.175 -
110.176 - Object inst = new Integer (3);
110.177 - ic.add (inst);
110.178 -
110.179 - assertEquals ("Accepted", inst, lookup.lookup (theQuery));
110.180 - assertNotNull ("Accepted too", lookup.lookupItem (t));
110.181 - assertEquals ("One is there - 2", 1, res.allItems ().size ());
110.182 - assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
110.183 - assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
110.184 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
110.185 -
110.186 - Object inst2 = new Thread (); // implements Runnable
110.187 - ic.add (inst2);
110.188 - assertEquals ("Accepted - 2", inst, lookup.lookup (theQuery));
110.189 - assertNotNull ("Accepted too -2", lookup.lookupItem (t));
110.190 - assertEquals ("One is there - 3", 1, res.allItems ().size ());
110.191 - assertEquals ("One is there - 3a", 1, res.allInstances ().size ());
110.192 - assertEquals ("One is there - 3b", 1, res.allClasses ().size ());
110.193 - assertEquals ("Right # of events", 0, ll.getCount ());
110.194 -
110.195 -
110.196 - ic.remove (inst);
110.197 - assertEquals ("Filtered out3", null, lookup.lookupItem (t));
110.198 - assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
110.199 - assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
110.200 - assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
110.201 - assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
110.202 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
110.203 - }
110.204 -
110.205 - public void testTheBehaviourAsRequestedByDavidAndDescribedByJesse () throws Exception {
110.206 - class C implements Runnable, java.io.Serializable {
110.207 - public void run () {}
110.208 - }
110.209 - Object c = new C();
110.210 - Lookup l1 = Lookups.singleton(c);
110.211 - Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
110.212 - assertNull(l2.lookup(Runnable.class));
110.213 - assertEquals(c, l2.lookup(java.io.Serializable.class));
110.214 - }
110.215 -
110.216 - public void testTheBehaviourAsRequestedByDavidAndDescribedByJesseWithUsageOfResult () throws Exception {
110.217 - class C implements Runnable, java.io.Serializable {
110.218 - public void run () {}
110.219 - }
110.220 - Object c = new C();
110.221 - Lookup l1 = Lookups.singleton(c);
110.222 - Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
110.223 -
110.224 - Lookup.Result run = l2.lookup (new Lookup.Template (Runnable.class));
110.225 - Lookup.Result ser = l2.lookup (new Lookup.Template (java.io.Serializable.class));
110.226 -
110.227 - assertEquals ("Runnables filtered out", 0, run.allItems ().size ());
110.228 - assertEquals ("One serialiazble", 1, ser.allItems ().size ());
110.229 - assertEquals ("And it is c", c, ser.allInstances ().iterator ().next ());
110.230 - }
110.231 -}
111.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/InheritanceTreeTest.java Sat Oct 31 15:06:58 2009 +0100
111.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
111.3 @@ -1,77 +0,0 @@
111.4 -/*
111.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
111.6 - *
111.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
111.8 - *
111.9 - * The contents of this file are subject to the terms of either the GNU
111.10 - * General Public License Version 2 only ("GPL") or the Common
111.11 - * Development and Distribution License("CDDL") (collectively, the
111.12 - * "License"). You may not use this file except in compliance with the
111.13 - * License. You can obtain a copy of the License at
111.14 - * http://www.netbeans.org/cddl-gplv2.html
111.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
111.16 - * specific language governing permissions and limitations under the
111.17 - * License. When distributing the software, include this License Header
111.18 - * Notice in each file and include the License file at
111.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
111.20 - * particular file as subject to the "Classpath" exception as provided
111.21 - * by Sun in the GPL Version 2 section of the License file that
111.22 - * accompanied this code. If applicable, add the following below the
111.23 - * License Header, with the fields enclosed by brackets [] replaced by
111.24 - * your own identifying information:
111.25 - * "Portions Copyrighted [year] [name of copyright owner]"
111.26 - *
111.27 - * Contributor(s):
111.28 - *
111.29 - * The Original Software is NetBeans. The Initial Developer of the Original
111.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
111.31 - * Microsystems, Inc. All Rights Reserved.
111.32 - *
111.33 - * If you wish your version of this file to be governed by only the CDDL
111.34 - * or only the GPL Version 2, indicate your decision by adding
111.35 - * "[Contributor] elects to include this software in this distribution
111.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
111.37 - * single choice of license, a recipient has the option to distribute
111.38 - * your version of this file under either the CDDL, the GPL Version 2 or
111.39 - * to extend the choice of license to its licensees as provided above.
111.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
111.41 - * Version 2 license, then the option applies only if the new code is
111.42 - * made subject to such option by the copyright holder.
111.43 - */
111.44 -package org.openide.util.lookup;
111.45 -
111.46 -import junit.framework.TestCase;
111.47 -import junit.framework.*;
111.48 -import org.openide.util.Lookup;
111.49 -import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
111.50 -import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
111.51 -import java.io.*;
111.52 -import java.lang.ref.WeakReference;
111.53 -import java.util.*;
111.54 -
111.55 -/**
111.56 - *
111.57 - * @author Jaroslav Tulach
111.58 - */
111.59 -public class InheritanceTreeTest extends TestCase {
111.60 -
111.61 - public InheritanceTreeTest(String testName) {
111.62 - super(testName);
111.63 - }
111.64 -
111.65 - protected void setUp() throws Exception {
111.66 - }
111.67 -
111.68 - protected void tearDown() throws Exception {
111.69 - }
111.70 -
111.71 - public void testDeserOfNode() {
111.72 - InheritanceTree inh = new InheritanceTree();
111.73 - InheritanceTree.Node n = new InheritanceTree.Node(String.class);
111.74 - n.markDeserialized();
111.75 - n.markDeserialized();
111.76 -
111.77 - n.assignItem(inh, new InstanceContent.SimpleItem("Ahoj"));
111.78 - }
111.79 -
111.80 -}
112.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/InitializationBug44134Test.java Sat Oct 31 15:06:58 2009 +0100
112.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
112.3 @@ -1,126 +0,0 @@
112.4 -/*
112.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
112.6 - *
112.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
112.8 - *
112.9 - * The contents of this file are subject to the terms of either the GNU
112.10 - * General Public License Version 2 only ("GPL") or the Common
112.11 - * Development and Distribution License("CDDL") (collectively, the
112.12 - * "License"). You may not use this file except in compliance with the
112.13 - * License. You can obtain a copy of the License at
112.14 - * http://www.netbeans.org/cddl-gplv2.html
112.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
112.16 - * specific language governing permissions and limitations under the
112.17 - * License. When distributing the software, include this License Header
112.18 - * Notice in each file and include the License file at
112.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
112.20 - * particular file as subject to the "Classpath" exception as provided
112.21 - * by Sun in the GPL Version 2 section of the License file that
112.22 - * accompanied this code. If applicable, add the following below the
112.23 - * License Header, with the fields enclosed by brackets [] replaced by
112.24 - * your own identifying information:
112.25 - * "Portions Copyrighted [year] [name of copyright owner]"
112.26 - *
112.27 - * Contributor(s):
112.28 - *
112.29 - * The Original Software is NetBeans. The Initial Developer of the Original
112.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
112.31 - * Microsystems, Inc. All Rights Reserved.
112.32 - *
112.33 - * If you wish your version of this file to be governed by only the CDDL
112.34 - * or only the GPL Version 2, indicate your decision by adding
112.35 - * "[Contributor] elects to include this software in this distribution
112.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
112.37 - * single choice of license, a recipient has the option to distribute
112.38 - * your version of this file under either the CDDL, the GPL Version 2 or
112.39 - * to extend the choice of license to its licensees as provided above.
112.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
112.41 - * Version 2 license, then the option applies only if the new code is
112.42 - * made subject to such option by the copyright holder.
112.43 - */
112.44 -
112.45 -package org.openide.util.lookup;
112.46 -
112.47 -import java.util.*;
112.48 -import org.netbeans.junit.*;
112.49 -import org.openide.util.Lookup;
112.50 -
112.51 -public class InitializationBug44134Test extends NbTestCase {
112.52 - public InitializationBug44134Test (java.lang.String testName) {
112.53 - super(testName);
112.54 - }
112.55 -
112.56 - public static void main(java.lang.String[] args) {
112.57 - junit.textui.TestRunner.run(new NbTestSuite(InitializationBug44134Test.class));
112.58 - }
112.59 -
112.60 - public void testThereShouldBe18Integers () throws Exception {
112.61 - FooManifestLookup foo = new FooManifestLookup ();
112.62 -
112.63 - Collection items = foo.lookup (new Lookup.Template (Integer.class)).allItems ();
112.64 -
112.65 - assertEquals ("18 of them", 18, items.size ());
112.66 -
112.67 - Iterator it = items.iterator ();
112.68 - while (it.hasNext()) {
112.69 - Lookup.Item t = (Lookup.Item)it.next ();
112.70 - assertEquals ("Is Integer", Integer.class, t.getInstance ().getClass ());
112.71 - }
112.72 - }
112.73 -
112.74 -
112.75 - public class FooManifestLookup extends AbstractLookup {
112.76 - public FooManifestLookup() {
112.77 - super();
112.78 - }
112.79 -
112.80 - @Override
112.81 - protected void initialize() {
112.82 - for (int i=0; i<18; i++) {
112.83 - try {
112.84 - String id= "__" + i;
112.85 -
112.86 - addPair(new FooLookupItem(new Integer(i),id));
112.87 - }
112.88 - catch (Exception e) {
112.89 - }
112.90 - }
112.91 - }
112.92 -
112.93 - public class FooLookupItem extends AbstractLookup.Pair {
112.94 - public FooLookupItem(Integer data, String id) {
112.95 - super();
112.96 - this.data=data;
112.97 - this.id=id;
112.98 - }
112.99 -
112.100 - protected boolean creatorOf(Object obj) {
112.101 - return obj == data;
112.102 - }
112.103 -
112.104 - public String getDisplayName() {
112.105 - return data.toString();
112.106 - }
112.107 -
112.108 - public Class getType () {
112.109 - return Integer.class;
112.110 - }
112.111 -
112.112 - protected boolean instanceOf (Class c) {
112.113 - return c.isInstance(data);
112.114 - }
112.115 -
112.116 - public Object getInstance() {
112.117 - return data;
112.118 - }
112.119 -
112.120 - public String getId() {
112.121 - return id;
112.122 - }
112.123 -
112.124 - private Integer data;
112.125 - private String id;
112.126 - }
112.127 - }
112.128 -
112.129 -}
113.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/KomrskaLookupTest.java Sat Oct 31 15:06:58 2009 +0100
113.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
113.3 @@ -1,177 +0,0 @@
113.4 -/*
113.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
113.6 - *
113.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
113.8 - *
113.9 - * The contents of this file are subject to the terms of either the GNU
113.10 - * General Public License Version 2 only ("GPL") or the Common
113.11 - * Development and Distribution License("CDDL") (collectively, the
113.12 - * "License"). You may not use this file except in compliance with the
113.13 - * License. You can obtain a copy of the License at
113.14 - * http://www.netbeans.org/cddl-gplv2.html
113.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
113.16 - * specific language governing permissions and limitations under the
113.17 - * License. When distributing the software, include this License Header
113.18 - * Notice in each file and include the License file at
113.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
113.20 - * particular file as subject to the "Classpath" exception as provided
113.21 - * by Sun in the GPL Version 2 section of the License file that
113.22 - * accompanied this code. If applicable, add the following below the
113.23 - * License Header, with the fields enclosed by brackets [] replaced by
113.24 - * your own identifying information:
113.25 - * "Portions Copyrighted [year] [name of copyright owner]"
113.26 - *
113.27 - * If you wish your version of this file to be governed by only the CDDL
113.28 - * or only the GPL Version 2, indicate your decision by adding
113.29 - * "[Contributor] elects to include this software in this distribution
113.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
113.31 - * single choice of license, a recipient has the option to distribute
113.32 - * your version of this file under either the CDDL, the GPL Version 2 or
113.33 - * to extend the choice of license to its licensees as provided above.
113.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
113.35 - * Version 2 license, then the option applies only if the new code is
113.36 - * made subject to such option by the copyright holder.
113.37 - *
113.38 - * Contributor(s):
113.39 - *
113.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
113.41 - */
113.42 -package org.openide.util.lookup;
113.43 -
113.44 -import org.junit.After;
113.45 -import org.junit.Before;
113.46 -import org.junit.Test;
113.47 -import org.openide.util.Lookup;
113.48 -import org.openide.util.LookupEvent;
113.49 -import org.openide.util.LookupListener;
113.50 -import static org.junit.Assert.*;
113.51 -
113.52 -/**
113.53 - * Test donated by Mr. Komrska. Seems to pass with 6.5.
113.54 - * @author komrska
113.55 - */
113.56 -public final class KomrskaLookupTest {
113.57 - private TestLookupManager lookupManager=null;
113.58 - private StringBuffer result=null;
113.59 -
113.60 - //
113.61 -
113.62 - private void addToLookup(final TestLookupItemA object) {
113.63 - result.append('A');
113.64 - lookupManager.add(object);
113.65 - }
113.66 - private void removeFromLookup(final TestLookupItemA object) {
113.67 - result.append('A');
113.68 - lookupManager.remove(object);
113.69 - }
113.70 -
113.71 - private void addToLookup(final TestLookupItemB object) {
113.72 - result.append('B');
113.73 - lookupManager.add(object);
113.74 - }
113.75 - private void removeFromLookup(final TestLookupItemB object) {
113.76 - result.append('B');
113.77 - lookupManager.remove(object);
113.78 - }
113.79 -
113.80 - public String getResult() {
113.81 - return result.toString();
113.82 - }
113.83 -
113.84 - //
113.85 -
113.86 - @Before
113.87 - public void setUp() {
113.88 - lookupManager=new TestLookupManager();
113.89 - result=new StringBuffer();
113.90 - }
113.91 -
113.92 - @After
113.93 - public void tearDown() {
113.94 - lookupManager=null;
113.95 - result=null;
113.96 - }
113.97 -
113.98 - @Test
113.99 - public void testLookupBug() {
113.100 - TestLookupItemA itemA1=new TestLookupItemA();
113.101 - TestLookupItemB itemB1=new TestLookupItemB();
113.102 - //
113.103 - addToLookup(itemA1);
113.104 - addToLookup(itemB1);
113.105 - removeFromLookup(itemA1);
113.106 - removeFromLookup(itemB1);
113.107 - addToLookup(itemB1);
113.108 - removeFromLookup(itemB1);
113.109 - //
113.110 - addToLookup(itemA1);
113.111 - addToLookup(itemB1);
113.112 - removeFromLookup(itemA1);
113.113 - removeFromLookup(itemB1);
113.114 - addToLookup(itemB1);
113.115 - removeFromLookup(itemB1);
113.116 - //
113.117 - addToLookup(itemA1);
113.118 - addToLookup(itemB1);
113.119 - removeFromLookup(itemA1);
113.120 - removeFromLookup(itemB1);
113.121 - addToLookup(itemB1);
113.122 - removeFromLookup(itemB1);
113.123 - //
113.124 - assertEquals(getResult(),lookupManager.getResult());
113.125 - }
113.126 -
113.127 - public static final class TestLookupItemA {}
113.128 - public static final class TestLookupItemB {}
113.129 - public static final class TestLookupManager {
113.130 - private InstanceContent instanceContent=new InstanceContent();
113.131 - private AbstractLookup abstractLookup=new AbstractLookup(instanceContent);
113.132 -
113.133 - private Lookup.Result<TestLookupItemA> resultA=null;
113.134 - private Lookup.Result<TestLookupItemB> resultB=null;
113.135 -
113.136 - private LookupListener listenerA=new LookupListener() {
113.137 - public void resultChanged(LookupEvent event) {
113.138 - result.append('A');
113.139 - }
113.140 - };
113.141 - private LookupListener listenerB=new LookupListener() {
113.142 - public void resultChanged(LookupEvent event) {
113.143 - result.append('B');
113.144 - }
113.145 - };
113.146 -
113.147 - private StringBuffer result=new StringBuffer();
113.148 -
113.149 - //
113.150 -
113.151 - public TestLookupManager() {
113.152 - Lookup.Template<TestLookupItemA> templateA=
113.153 - new Lookup.Template<TestLookupItemA>(TestLookupItemA.class);
113.154 - resultA=abstractLookup.lookup(templateA);
113.155 - resultA.addLookupListener(listenerA);
113.156 - resultA.allInstances().size();
113.157 - //
113.158 - Lookup.Template<TestLookupItemB> templateB=
113.159 - new Lookup.Template<TestLookupItemB>(TestLookupItemB.class);
113.160 - resultB=abstractLookup.lookup(templateB);
113.161 - resultB.addLookupListener(listenerB);
113.162 - resultB.allInstances().size();
113.163 - // WORKAROUND
113.164 - // instanceContent.add(Boolean.TRUE);
113.165 - }
113.166 -
113.167 - //
113.168 -
113.169 - public void add(Object item) {
113.170 - instanceContent.add(item);
113.171 - }
113.172 - public void remove(Object item) {
113.173 - instanceContent.remove(item);
113.174 - }
113.175 - public String getResult() {
113.176 - return result.toString();
113.177 - }
113.178 - }
113.179 -
113.180 -}
114.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/LookupBugTest.java Sat Oct 31 15:06:58 2009 +0100
114.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
114.3 @@ -1,79 +0,0 @@
114.4 -package org.openide.util.lookup;
114.5 -
114.6 -import java.util.logging.Logger;
114.7 -import org.junit.Before;
114.8 -import org.junit.Test;
114.9 -import org.openide.util.Lookup;
114.10 -import org.openide.util.LookupEvent;
114.11 -import org.openide.util.LookupListener;
114.12 -import static org.junit.Assert.*;
114.13 -
114.14 -/**
114.15 - * Test of a Lookup bug seen in NetBeans platforms 6.0-6.5M1.
114.16 - * @author rlee
114.17 - */
114.18 -public class LookupBugTest implements LookupListener
114.19 -{
114.20 - private static final int MAX_LOOPS = 1000;
114.21 -
114.22 - private AbstractLookup lookup;
114.23 - private InstanceContent content;
114.24 - private Lookup.Result<String> wordResult;
114.25 - private Lookup.Result<Integer> numberResult;
114.26 - private String word;
114.27 - private Integer number;
114.28 - private Logger LOG;
114.29 -
114.30 - private boolean fired;
114.31 - private int i;
114.32 -
114.33 - @Before
114.34 - public void setUp()
114.35 - {
114.36 - LOG = Logger.getLogger("test.LookupBugTest");
114.37 - content = new InstanceContent();
114.38 - lookup = new AbstractLookup(content);
114.39 - wordResult = lookup.lookupResult(java.lang.String.class);
114.40 - wordResult.addLookupListener(this);
114.41 - numberResult = lookup.lookupResult(java.lang.Integer.class);
114.42 - numberResult.addLookupListener(this);
114.43 -
114.44 - fired = false;
114.45 - }
114.46 -
114.47 - @Test
114.48 - public void lookupTest()
114.49 - {
114.50 - for(i = 0; i < MAX_LOOPS; i++ )
114.51 - {
114.52 - word = String.valueOf(i);
114.53 - number = new Integer(i);
114.54 - content.add(word);
114.55 - assertTrue( "word on loop " + i, checkLookupEventFired() );
114.56 - content.add(number);
114.57 - assertTrue( "number on loop " + i, checkLookupEventFired() );
114.58 - content.remove(word);
114.59 - assertTrue( "remove word on loop " + i, checkLookupEventFired() );
114.60 - content.remove(number);
114.61 - assertTrue( "remove number on loop " + i, checkLookupEventFired() );
114.62 -
114.63 - assertTrue("The lookup still needs to stay simple", AbstractLookup.isSimple(lookup));
114.64 - }
114.65 - }
114.66 -
114.67 - public void resultChanged(LookupEvent ev)
114.68 - {
114.69 - fired = true;
114.70 - }
114.71 -
114.72 - public boolean checkLookupEventFired()
114.73 - {
114.74 - LOG.fine(" round: " + i + " word = " + word + " number = " + number);
114.75 - if( fired )
114.76 - {
114.77 - fired = false;
114.78 - return true;
114.79 - }
114.80 - else return false;
114.81 - }
114.82 -}
115.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/LookupsProxyTest.java Sat Oct 31 15:06:58 2009 +0100
115.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
115.3 @@ -1,282 +0,0 @@
115.4 -/*
115.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
115.6 - *
115.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
115.8 - *
115.9 - * The contents of this file are subject to the terms of either the GNU
115.10 - * General Public License Version 2 only ("GPL") or the Common
115.11 - * Development and Distribution License("CDDL") (collectively, the
115.12 - * "License"). You may not use this file except in compliance with the
115.13 - * License. You can obtain a copy of the License at
115.14 - * http://www.netbeans.org/cddl-gplv2.html
115.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
115.16 - * specific language governing permissions and limitations under the
115.17 - * License. When distributing the software, include this License Header
115.18 - * Notice in each file and include the License file at
115.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
115.20 - * particular file as subject to the "Classpath" exception as provided
115.21 - * by Sun in the GPL Version 2 section of the License file that
115.22 - * accompanied this code. If applicable, add the following below the
115.23 - * License Header, with the fields enclosed by brackets [] replaced by
115.24 - * your own identifying information:
115.25 - * "Portions Copyrighted [year] [name of copyright owner]"
115.26 - *
115.27 - * Contributor(s):
115.28 - *
115.29 - * The Original Software is NetBeans. The Initial Developer of the Original
115.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
115.31 - * Microsystems, Inc. All Rights Reserved.
115.32 - *
115.33 - * If you wish your version of this file to be governed by only the CDDL
115.34 - * or only the GPL Version 2, indicate your decision by adding
115.35 - * "[Contributor] elects to include this software in this distribution
115.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
115.37 - * single choice of license, a recipient has the option to distribute
115.38 - * your version of this file under either the CDDL, the GPL Version 2 or
115.39 - * to extend the choice of license to its licensees as provided above.
115.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
115.41 - * Version 2 license, then the option applies only if the new code is
115.42 - * made subject to such option by the copyright holder.
115.43 - */
115.44 -
115.45 -package org.openide.util.lookup;
115.46 -
115.47 -import java.io.Serializable;
115.48 -
115.49 -import java.util.*;
115.50 -import org.netbeans.junit.*;
115.51 -import org.openide.util.Lookup;
115.52 -import org.openide.util.LookupEvent;
115.53 -import org.openide.util.LookupListener;
115.54 -
115.55 -/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
115.56 - */
115.57 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
115.58 -public class LookupsProxyTest extends AbstractLookupBaseHid
115.59 -implements AbstractLookupBaseHid.Impl {
115.60 - public LookupsProxyTest(java.lang.String testName) {
115.61 - super(testName, null);
115.62 - }
115.63 -
115.64 - public static void main(java.lang.String[] args) {
115.65 - junit.textui.TestRunner.run(new NbTestSuite (LookupsProxyTest.class));
115.66 - }
115.67 -
115.68 - /** Creates an lookup for given lookup. This class just returns
115.69 - * the object passed in, but subclasses can be different.
115.70 - * @param lookup in lookup
115.71 - * @return a lookup to use
115.72 - */
115.73 - public Lookup createLookup (final Lookup lookup) {
115.74 - return org.openide.util.lookup.Lookups.proxy (
115.75 - new Lookup.Provider () {
115.76 - public Lookup getLookup () {
115.77 - return lookup;
115.78 - }
115.79 - }
115.80 - );
115.81 - }
115.82 -
115.83 - public Lookup createInstancesLookup (InstanceContent ic) {
115.84 - return new AbstractLookup (ic);
115.85 - }
115.86 -
115.87 - public void clearCaches () {
115.88 - }
115.89 -
115.90 -
115.91 -
115.92 - /** Check whether setLookups method does not fire when there is no
115.93 - * change in the lookups.
115.94 - */
115.95 - public void testProxyListener () {
115.96 - Changer ch = new Changer (Lookup.EMPTY);
115.97 -
115.98 - Lookup lookup = Lookups.proxy(ch);
115.99 - Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
115.100 -
115.101 - LL ll = new LL ();
115.102 - res.addLookupListener (ll);
115.103 - Collection allRes = res.allInstances ();
115.104 -
115.105 - ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
115.106 - lookup.lookup (Object.class); // does the refresh
115.107 -
115.108 - assertEquals("Replacing an empty by empty does not generate an event", 0, ll.getCount());
115.109 -
115.110 - InstanceContent content = new InstanceContent ();
115.111 - AbstractLookup del = new AbstractLookup (content);
115.112 - content.add (this);
115.113 - ch.setLookup (del);
115.114 - lookup.lookup (Object.class);
115.115 -
115.116 - if (ll.getCount () != 1) {
115.117 - fail ("Changing lookups with different content generates an event");
115.118 - }
115.119 -
115.120 - ch.setLookup (del);
115.121 - lookup.lookup (Object.class);
115.122 -
115.123 - if (ll.getCount () != 0) {
115.124 - fail ("Not changing the lookups does not generate any event");
115.125 - }
115.126 - }
115.127 -
115.128 -
115.129 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
115.130 - doListeningAndQueryingByTwoListenersSetLookups(0, 1, false);
115.131 - }
115.132 - public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
115.133 - doListeningAndQueryingByTwoListenersSetLookups(1, 1, false);
115.134 - }
115.135 - public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
115.136 - doListeningAndQueryingByTwoListenersSetLookups(2, 1, false);
115.137 - }
115.138 -
115.139 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
115.140 - doListeningAndQueryingByTwoListenersSetLookups(0, 2, false);
115.141 - }
115.142 - public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
115.143 - doListeningAndQueryingByTwoListenersSetLookups(1, 2, false);
115.144 - }
115.145 - public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
115.146 - doListeningAndQueryingByTwoListenersSetLookups(2, 2, false);
115.147 - }
115.148 -
115.149 - public void testListeningAndQueryingByTwoListenersInstancesSetLookupsWithProxy() {
115.150 - doListeningAndQueryingByTwoListenersSetLookups(0, 1, true);
115.151 - }
115.152 - public void testListeningAndQueryingByTwoListenersClassesSetLookupsWithProxy() {
115.153 - doListeningAndQueryingByTwoListenersSetLookups(1, 1, true);
115.154 - }
115.155 - public void testListeningAndQueryingByTwoListenersItemsSetLookupsWithProxy() {
115.156 - doListeningAndQueryingByTwoListenersSetLookups(2, 1, true);
115.157 - }
115.158 -
115.159 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups2WithProxy() {
115.160 - doListeningAndQueryingByTwoListenersSetLookups(0, 2, true);
115.161 - }
115.162 - public void testListeningAndQueryingByTwoListenersClassesSetLookups2WithProxy() {
115.163 - doListeningAndQueryingByTwoListenersSetLookups(1, 2, true);
115.164 - }
115.165 - public void testListeningAndQueryingByTwoListenersItemsSetLookups2WithProxy() {
115.166 - doListeningAndQueryingByTwoListenersSetLookups(2, 2, true);
115.167 - }
115.168 -
115.169 - /* XXX: these are pretty slow, seems there is a performance problem 2^22
115.170 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
115.171 - doListeningAndQueryingByTwoListenersSetLookups(0, 22);
115.172 - }
115.173 - public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
115.174 - doListeningAndQueryingByTwoListenersSetLookups(1, 22);
115.175 - }
115.176 - public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
115.177 - doListeningAndQueryingByTwoListenersSetLookups(2, 22);
115.178 - }
115.179 - */
115.180 -
115.181 - private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth, boolean cacheOnTop) {
115.182 - Changer orig = new Changer(Lookup.EMPTY);
115.183 - Lookup on = Lookups.proxy(orig);
115.184 - Lookup first = on;
115.185 -
115.186 - while (--depth > 0) {
115.187 - Changer next = new Changer(on);
115.188 - on = Lookups.proxy(next);
115.189 - }
115.190 -
115.191 -
115.192 - final Lookup lookup = cacheOnTop ? new ProxyLookup(new Lookup[] { on }) : on;
115.193 -
115.194 - class L implements LookupListener {
115.195 - Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
115.196 - Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
115.197 - Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
115.198 -
115.199 - {
115.200 - integer.addLookupListener(this);
115.201 - number.addLookupListener(this);
115.202 - serial.addLookupListener(this);
115.203 - }
115.204 -
115.205 - int round;
115.206 -
115.207 - public void resultChanged(LookupEvent ev) {
115.208 - Collection c1 = get(type, integer);
115.209 - Collection c2 = get(type, number);
115.210 - Collection c3 = get(type, serial);
115.211 -
115.212 - assertEquals("round " + round + " c1 vs. c2", c1, c2);
115.213 - assertEquals("round " + round + " c1 vs. c3", c1, c3);
115.214 - assertEquals("round " + round + " c2 vs. c3", c2, c3);
115.215 -
115.216 - round++;
115.217 - }
115.218 -
115.219 - private Collection get(int type, Lookup.Result res) {
115.220 - Collection c;
115.221 - switch(type) {
115.222 - case 0: c = res.allInstances(); break;
115.223 - case 1: c = res.allClasses(); break;
115.224 - case 2: c = res.allItems(); break;
115.225 - default: c = null; fail("Type: " + type); break;
115.226 - }
115.227 -
115.228 - assertNotNull(c);
115.229 - return new ArrayList(c);
115.230 - }
115.231 - }
115.232 -
115.233 - L listener = new L();
115.234 - listener.resultChanged(null);
115.235 - ArrayList arr = new ArrayList();
115.236 - for(int i = 0; i < 100; i++) {
115.237 - arr.add(new Integer(i));
115.238 -
115.239 - orig.lookup = Lookups.fixed(arr.toArray());
115.240 - // do the refresh
115.241 - first.lookup((Class)null);
115.242 - }
115.243 -
115.244 - assertEquals("3x100+1 checks", 301, listener.round);
115.245 - }
115.246 -
115.247 -
115.248 - public void testRefreshWithoutAllInstances103300 () {
115.249 - Changer ch = new Changer (Lookup.EMPTY);
115.250 -
115.251 - Lookup lookup = Lookups.proxy(ch);
115.252 -
115.253 - ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
115.254 - assertNull("Nothing there", lookup.lookup (Object.class)); // does the refresh
115.255 -
115.256 - InstanceContent content = new InstanceContent ();
115.257 - AbstractLookup del = new AbstractLookup (content);
115.258 - content.add (this);
115.259 - ch.setLookup (del);
115.260 - assertEquals("Can see me", this, lookup.lookup (Object.class));
115.261 -
115.262 - ch.setLookup (del);
115.263 - assertEquals("Still can see me", this, lookup.lookup (Object.class));
115.264 -
115.265 - assertEquals("I am visible", this, lookup.lookup(LookupsProxyTest.class));
115.266 - }
115.267 -
115.268 -
115.269 - private static final class Changer implements Lookup.Provider {
115.270 - private Lookup lookup;
115.271 -
115.272 - public Changer (Lookup lookup) {
115.273 - setLookup (lookup);
115.274 - }
115.275 -
115.276 - public void setLookup (Lookup lookup) {
115.277 - this.lookup = lookup;
115.278 - }
115.279 -
115.280 - public Lookup getLookup() {
115.281 - return lookup;
115.282 - }
115.283 - }
115.284 -
115.285 -}
116.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTest.java Sat Oct 31 15:06:58 2009 +0100
116.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
116.3 @@ -1,550 +0,0 @@
116.4 -/*
116.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
116.6 - *
116.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
116.8 - *
116.9 - * The contents of this file are subject to the terms of either the GNU
116.10 - * General Public License Version 2 only ("GPL") or the Common
116.11 - * Development and Distribution License("CDDL") (collectively, the
116.12 - * "License"). You may not use this file except in compliance with the
116.13 - * License. You can obtain a copy of the License at
116.14 - * http://www.netbeans.org/cddl-gplv2.html
116.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
116.16 - * specific language governing permissions and limitations under the
116.17 - * License. When distributing the software, include this License Header
116.18 - * Notice in each file and include the License file at
116.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
116.20 - * particular file as subject to the "Classpath" exception as provided
116.21 - * by Sun in the GPL Version 2 section of the License file that
116.22 - * accompanied this code. If applicable, add the following below the
116.23 - * License Header, with the fields enclosed by brackets [] replaced by
116.24 - * your own identifying information:
116.25 - * "Portions Copyrighted [year] [name of copyright owner]"
116.26 - *
116.27 - * Contributor(s):
116.28 - *
116.29 - * The Original Software is NetBeans. The Initial Developer of the Original
116.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
116.31 - * Microsystems, Inc. All Rights Reserved.
116.32 - *
116.33 - * If you wish your version of this file to be governed by only the CDDL
116.34 - * or only the GPL Version 2, indicate your decision by adding
116.35 - * "[Contributor] elects to include this software in this distribution
116.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
116.37 - * single choice of license, a recipient has the option to distribute
116.38 - * your version of this file under either the CDDL, the GPL Version 2 or
116.39 - * to extend the choice of license to its licensees as provided above.
116.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
116.41 - * Version 2 license, then the option applies only if the new code is
116.42 - * made subject to such option by the copyright holder.
116.43 - */
116.44 -
116.45 -package org.openide.util.lookup;
116.46 -
116.47 -import java.io.ByteArrayInputStream;
116.48 -import java.io.File;
116.49 -import java.io.FileOutputStream;
116.50 -import java.io.IOException;
116.51 -import java.io.InputStream;
116.52 -import java.io.InputStreamReader;
116.53 -import java.lang.ref.Reference;
116.54 -import java.lang.ref.WeakReference;
116.55 -import java.net.URL;
116.56 -import java.net.URLClassLoader;
116.57 -import java.net.URLConnection;
116.58 -import java.net.URLStreamHandler;
116.59 -import java.util.ArrayList;
116.60 -import java.util.Collection;
116.61 -import java.util.Collections;
116.62 -import java.util.Comparator;
116.63 -import java.util.Enumeration;
116.64 -import java.util.HashSet;
116.65 -import java.util.Iterator;
116.66 -import java.util.List;
116.67 -import java.util.Map;
116.68 -import java.util.Set;
116.69 -import java.util.TreeSet;
116.70 -import java.util.WeakHashMap;
116.71 -import java.util.concurrent.atomic.AtomicBoolean;
116.72 -import java.util.jar.JarEntry;
116.73 -import java.util.jar.JarOutputStream;
116.74 -import java.util.logging.Level;
116.75 -import java.util.logging.Logger;
116.76 -import java.util.regex.Matcher;
116.77 -import java.util.regex.Pattern;
116.78 -import org.bar.Comparator2;
116.79 -import org.netbeans.junit.MockServices;
116.80 -import org.netbeans.junit.NbTestCase;
116.81 -import org.openide.util.Enumerations;
116.82 -import org.openide.util.Exceptions;
116.83 -import org.openide.util.Lookup;
116.84 -import org.openide.util.LookupEvent;
116.85 -import org.openide.util.LookupListener;
116.86 -import org.openide.util.test.MockLookup;
116.87 -
116.88 -/** Test finding services from manifest.
116.89 - * @author Jesse Glick
116.90 - */
116.91 -public class MetaInfServicesLookupTest extends NbTestCase {
116.92 - private Logger LOG;
116.93 - private Map<ClassLoader,Lookup> lookups = new WeakHashMap<ClassLoader,Lookup>();
116.94 -
116.95 - public MetaInfServicesLookupTest(String name) {
116.96 - super(name);
116.97 - LOG = Logger.getLogger("Test." + name);
116.98 - }
116.99 -
116.100 - protected String prefix() {
116.101 - return "META-INF/services/";
116.102 - }
116.103 -
116.104 - protected Lookup createLookup(ClassLoader c) {
116.105 - return Lookups.metaInfServices(c);
116.106 - }
116.107 -
116.108 - @Override
116.109 - protected Level logLevel() {
116.110 - return Level.INFO;
116.111 - }
116.112 -
116.113 - private Lookup getTestedLookup(ClassLoader c) {
116.114 - MockServices.setServices();
116.115 - Lookup l = lookups.get(c);
116.116 - if (l == null) {
116.117 - l = createLookup(c);
116.118 - lookups.put(c, l);
116.119 - }
116.120 - return l;
116.121 - }
116.122 -
116.123 - private URL findJar(String n) throws IOException {
116.124 - LOG.info("Looking for " + n);
116.125 - File jarDir = new File(getWorkDir(), "jars");
116.126 - jarDir.mkdirs();
116.127 - File jar = new File(jarDir, n);
116.128 - if (jar.exists()) {
116.129 - return jar.toURI().toURL();
116.130 - }
116.131 -
116.132 - LOG.info("generating " + jar);
116.133 -
116.134 - URL data = MetaInfServicesLookupTest.class.getResource(n.replaceAll("\\.jar", "\\.txt"));
116.135 - assertNotNull("Data found", data);
116.136 - StringBuffer sb = new StringBuffer();
116.137 - InputStreamReader r = new InputStreamReader(data.openStream());
116.138 - for(;;) {
116.139 - int ch = r.read();
116.140 - if (ch == -1) {
116.141 - break;
116.142 - }
116.143 - sb.append((char)ch);
116.144 - }
116.145 -
116.146 - JarOutputStream os = new JarOutputStream(new FileOutputStream(jar));
116.147 -
116.148 - Pattern p = Pattern.compile(":([^:]+):([^:]*)", Pattern.MULTILINE | Pattern.DOTALL);
116.149 - Matcher m = p.matcher(sb);
116.150 - Pattern foobar = Pattern.compile("^(org\\.(foo|bar)\\..*)$", Pattern.MULTILINE);
116.151 - Set<String> names = new TreeSet<String>();
116.152 - while (m.find()) {
116.153 - assert m.groupCount() == 2;
116.154 - String entryName = prefix() + m.group(1);
116.155 - LOG.info("putting there entry: " + entryName);
116.156 - os.putNextEntry(new JarEntry(entryName));
116.157 - os.write(m.group(2).getBytes());
116.158 - os.closeEntry();
116.159 -
116.160 - Matcher fb = foobar.matcher(m.group(2));
116.161 - while (fb.find()) {
116.162 - String clazz = fb.group(1).replace('.', '/') + ".class";
116.163 - LOG.info("will copy " + clazz);
116.164 - names.add(clazz);
116.165 - }
116.166 - }
116.167 -
116.168 - for (String copy : names) {
116.169 - os.putNextEntry(new JarEntry(copy));
116.170 - LOG.info("copying " + copy);
116.171 - InputStream from = MetaInfServicesLookupTest.class.getResourceAsStream("/" + copy);
116.172 - assertNotNull(copy, from);
116.173 - for (;;) {
116.174 - int ch = from.read();
116.175 - if (ch == -1) {
116.176 - break;
116.177 - }
116.178 - os.write(ch);
116.179 - }
116.180 - from.close();
116.181 - os.closeEntry();
116.182 - }
116.183 - os.close();
116.184 - LOG.info("done " + jar);
116.185 - return jar.toURI().toURL();
116.186 - }
116.187 -
116.188 - ClassLoader c1, c2, c2a, c3, c4;
116.189 -
116.190 - @Override
116.191 - protected void setUp() throws Exception {
116.192 - clearWorkDir();
116.193 - ClassLoader app = getClass().getClassLoader().getParent();
116.194 - ClassLoader c0 = app;
116.195 -
116.196 - c1 = new URLClassLoader(new URL[] {
116.197 - findJar("services-jar-1.jar"),
116.198 - }, c0);
116.199 - c2 = new URLClassLoader(new URL[] {
116.200 - findJar("services-jar-2.jar"),
116.201 - }, c1);
116.202 - c2a = new URLClassLoader(new URL[] {
116.203 - findJar("services-jar-2.jar"),
116.204 - }, c1);
116.205 - c3 = new URLClassLoader(new URL[] { findJar("services-jar-2.jar") },
116.206 - c0
116.207 - );
116.208 - c4 = new URLClassLoader(new URL[] {
116.209 - findJar("services-jar-1.jar"),
116.210 - findJar("services-jar-2.jar"),
116.211 - }, c0);
116.212 - }
116.213 -
116.214 - @Override
116.215 - protected void tearDown() throws Exception {
116.216 - Set<Reference<Lookup>> weak = new HashSet<Reference<Lookup>>();
116.217 - for (Lookup l : lookups.values()) {
116.218 - weak.add(new WeakReference<Lookup>(l));
116.219 - }
116.220 -
116.221 - lookups = null;
116.222 -
116.223 - for(Reference<Lookup> ref : weak) {
116.224 - assertGC("Lookup can disappear", ref);
116.225 - }
116.226 - }
116.227 -
116.228 - public void testBasicUsage() throws Exception {
116.229 - Lookup l = getTestedLookup(c2);
116.230 - Class<?> xface = c1.loadClass("org.foo.Interface");
116.231 - List<?> results = new ArrayList<Object>(l.lookupAll(xface));
116.232 - assertEquals("Two items in result: " + results, 2, results.size());
116.233 - // Note that they have to be in order:
116.234 - assertEquals("org.foo.impl.Implementation1", results.get(0).getClass().getName());
116.235 - assertEquals("org.bar.Implementation2", results.get(1).getClass().getName());
116.236 - // Make sure it does not gratuitously replace items:
116.237 - List<?> results2 = new ArrayList<Object>(l.lookupAll(xface));
116.238 - assertEquals(results, results2);
116.239 - }
116.240 -
116.241 - public void testLoaderSkew() throws Exception {
116.242 - Class<?> xface1 = c1.loadClass("org.foo.Interface");
116.243 - Lookup l3 = getTestedLookup(c3);
116.244 - // If we cannot load Interface, there should be no impls of course... quietly!
116.245 - assertEquals(Collections.emptyList(),
116.246 - new ArrayList<Object>(l3.lookupAll(xface1)));
116.247 - Lookup l4 = getTestedLookup(c4);
116.248 - // If we can load Interface but it is the wrong one, ignore it.
116.249 - assertEquals(Collections.emptyList(),
116.250 - new ArrayList<Object>(l4.lookupAll(xface1)));
116.251 - // Make sure l4 is really OK - it can load from its own JARs.
116.252 - Class<?> xface4 = c4.loadClass("org.foo.Interface");
116.253 - assertEquals(2, l4.lookupAll(xface4).size());
116.254 - }
116.255 -
116.256 - public void testStability() throws Exception {
116.257 - Lookup l = getTestedLookup(c2);
116.258 - Class<?> xface = c1.loadClass("org.foo.Interface");
116.259 - Object first = l.lookup(xface);
116.260 - assertEquals(first, l.lookupAll(xface).iterator().next());
116.261 - l = getTestedLookup(c2a);
116.262 - Object second = l.lookup(xface);
116.263 - assertEquals(first, second);
116.264 - }
116.265 -
116.266 - public void testMaskingOfResources() throws Exception {
116.267 - Lookup l1 = getTestedLookup(c1);
116.268 - Lookup l2 = getTestedLookup(c2);
116.269 - Lookup l4 = getTestedLookup(c4);
116.270 -
116.271 - assertNotNull("services1.jar defines a class that implements runnable", l1.lookup(Runnable.class));
116.272 - assertNull("services2.jar does not defines a class that implements runnable", l2.lookup(Runnable.class));
116.273 - assertNull("services1.jar defines Runnable, but services2.jar masks it out", l4.lookup(Runnable.class));
116.274 - }
116.275 -
116.276 - public void testOrdering() throws Exception {
116.277 - Lookup l = getTestedLookup(c1);
116.278 - Class<?> xface = c1.loadClass("java.util.Comparator");
116.279 - List<?> results = new ArrayList<Object>(l.lookupAll(xface));
116.280 - assertEquals(1, results.size());
116.281 -
116.282 - l = getTestedLookup(c2);
116.283 - xface = c2.loadClass("java.util.Comparator");
116.284 - results = new ArrayList<Object>(l.lookupAll(xface));
116.285 - assertEquals(2, results.size());
116.286 - // Test order:
116.287 - assertEquals("org.bar.Comparator2", results.get(0).getClass().getName());
116.288 - assertEquals("org.foo.impl.Comparator1", results.get(1).getClass().getName());
116.289 -
116.290 - // test that items without position are always at the end
116.291 - l = getTestedLookup(c2);
116.292 - xface = c2.loadClass("java.util.Iterator");
116.293 - results = new ArrayList<Object>(l.lookupAll(xface));
116.294 - assertEquals(2, results.size());
116.295 - // Test order:
116.296 - assertEquals("org.bar.Iterator2", results.get(0).getClass().getName());
116.297 - assertEquals("org.foo.impl.Iterator1", results.get(1).getClass().getName());
116.298 - }
116.299 -
116.300 - public void testNoCallToGetResourceForObjectIssue65124() throws Exception {
116.301 - class Loader extends ClassLoader {
116.302 - private int counter;
116.303 -
116.304 - @Override
116.305 - protected URL findResource(String name) {
116.306 - if (name.equals(prefix() + "java.lang.Object")) {
116.307 - counter++;
116.308 - }
116.309 -
116.310 - URL retValue;
116.311 -
116.312 - retValue = super.findResource(name);
116.313 - return retValue;
116.314 - }
116.315 -
116.316 - @Override
116.317 - protected Enumeration<URL> findResources(String name) throws IOException {
116.318 - if (name.equals(prefix() + "java.lang.Object")) {
116.319 - counter++;
116.320 - }
116.321 - return super.findResources(name);
116.322 - }
116.323 - }
116.324 - Loader loader = new Loader();
116.325 - Lookup l = getTestedLookup(loader);
116.326 -
116.327 - Object no = l.lookup(String.class);
116.328 - assertNull("Not found of course", no);
116.329 - assertEquals("No lookup of Object", 0, loader.counter);
116.330 - }
116.331 -
116.332 - public void testCanGarbageCollectClasses() throws Exception {
116.333 - class Loader extends ClassLoader {
116.334 - public Loader() {
116.335 - super(Loader.class.getClassLoader().getParent());
116.336 - }
116.337 -
116.338 - @Override
116.339 - protected URL findResource(String name) {
116.340 - if (name.equals(prefix() + "java.lang.Runnable")) {
116.341 - return Loader.class.getResource("MetaInfServicesLookupTestRunnable.txt");
116.342 - }
116.343 -
116.344 - URL retValue;
116.345 -
116.346 - retValue = super.findResource(name);
116.347 - return retValue;
116.348 - }
116.349 -
116.350 - @Override
116.351 - protected Class<?> findClass(String name) throws ClassNotFoundException {
116.352 - if (name.equals("org.openide.util.lookup.MetaInfServicesLookupTestRunnable")) {
116.353 - try {
116.354 - InputStream is = getClass().getResourceAsStream("MetaInfServicesLookupTestRunnable.class");
116.355 - byte[] arr = new byte[is.available()];
116.356 - int read = is.read(arr);
116.357 - assertEquals("Fully read", arr.length, read);
116.358 - return defineClass(name, arr, 0, arr.length);
116.359 - } catch (IOException ex) {
116.360 - throw new ClassNotFoundException("Cannot load", ex);
116.361 - }
116.362 - }
116.363 - throw new ClassNotFoundException();
116.364 - }
116.365 -
116.366 -
116.367 -
116.368 - @Override
116.369 - protected Enumeration<URL> findResources(String name) throws IOException {
116.370 - if (name.equals(prefix() + "java.lang.Runnable")) {
116.371 - return Collections.enumeration(Collections.singleton(findResource(name)));
116.372 - }
116.373 - return super.findResources(name);
116.374 - }
116.375 - }
116.376 - Loader loader = new Loader();
116.377 - Lookup l = getTestedLookup(loader);
116.378 -
116.379 -
116.380 - Object no = l.lookup(Runnable.class);
116.381 - assertNotNull("Found of course", no);
116.382 - assertEquals("The right name", "MetaInfServicesLookupTestRunnable", no.getClass().getSimpleName());
116.383 - if (no.getClass().getClassLoader() != loader) {
116.384 - fail("Wrong classloader: " + no.getClass().getClassLoader());
116.385 - }
116.386 -
116.387 - WeakReference<Object> ref = new WeakReference<Object>(no.getClass());
116.388 - loader = null;
116.389 - no = null;
116.390 - l = null;
116.391 - lookups.clear();
116.392 - MockLookup.setInstances();
116.393 - Thread.currentThread().setContextClassLoader(null);
116.394 - assertGC("Class can be garbage collected", ref);
116.395 - }
116.396 -
116.397 - public void testSuperTypes() throws Exception {
116.398 - doTestSuperTypes(createLookup(c2));
116.399 - doTestSuperTypes(new ProxyLookup(createLookup(c2)));
116.400 - }
116.401 - private void doTestSuperTypes(Lookup l) throws Exception {
116.402 - final Class<?> xface = c1.loadClass("org.foo.Interface");
116.403 - final Lookup.Result<Object> res = l.lookupResult(Object.class);
116.404 - assertEquals("Nothing yet", 0, res.allInstances().size());
116.405 - final AtomicBoolean event = new AtomicBoolean();
116.406 - final Thread here = Thread.currentThread();
116.407 - res.addLookupListener(new LookupListener() {
116.408 - public void resultChanged(LookupEvent ev) {
116.409 - if (Thread.currentThread() == here) {
116.410 - event.set(true);
116.411 - }
116.412 - }
116.413 - });
116.414 - assertNotNull("Interface found", l.lookup(xface));
116.415 - assertFalse(event.get());
116.416 - class W implements Runnable {
116.417 - boolean ok;
116.418 - public synchronized void run() {
116.419 - ok = true;
116.420 - notifyAll();
116.421 - }
116.422 -
116.423 - public synchronized void await() throws Exception {
116.424 - while (!ok) {
116.425 - wait();
116.426 - }
116.427 - }
116.428 - }
116.429 - W w = new W();
116.430 - MetaInfServicesLookup.RP.execute(w);
116.431 - w.await();
116.432 - assertEquals("Now two", 2, res.allInstances().size());
116.433 - }
116.434 -
116.435 - public void testWrongOrderAsInIssue100320() throws Exception {
116.436 - ClassLoader app = getClass().getClassLoader().getParent();
116.437 - ClassLoader c0 = app;
116.438 - ClassLoader ctmp = new URLClassLoader(new URL[] {
116.439 - findJar("problem100320.jar"),
116.440 - }, c0);
116.441 - Lookup lookup = Lookups.metaInfServices(ctmp, prefix());
116.442 -
116.443 - Collection<?> colAWT = lookup.lookupAll(IOException.class);
116.444 - assertEquals("There is enough objects to switch to InheritanceTree", 12, colAWT.size());
116.445 -
116.446 -
116.447 - List<?> col1 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
116.448 - assertEquals("Two", 2, col1.size());
116.449 - Collection<?> col2 = lookup.lookupAll(ctmp.loadClass(Comparator2.class.getName()));
116.450 - assertEquals("One", 1, col2.size());
116.451 - List<?> col3 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
116.452 - assertEquals("Two2", 2, col3.size());
116.453 -
116.454 - Iterator<?> it1 = col1.iterator();
116.455 - Iterator<?> it3 = col3.iterator();
116.456 - if (
116.457 - it1.next() != it3.next() ||
116.458 - it1.next() != it3.next()
116.459 - ) {
116.460 - fail("Collections are different:\nFirst: " + col1 + "\nLast: " + col3);
116.461 - }
116.462 - }
116.463 -
116.464 - public void testContentionWhenLoadingMetainfServices() throws Exception {
116.465 - class My extends ClassLoader implements Runnable {
116.466 - Lookup query;
116.467 - Integer value;
116.468 -
116.469 - public void run() {
116.470 - value = query.lookup(Integer.class);
116.471 - }
116.472 -
116.473 -
116.474 - @Override
116.475 - protected URL findResource(String name) {
116.476 - waitForTask(name);
116.477 - return super.findResource(name);
116.478 - }
116.479 -
116.480 - @Override
116.481 - protected Enumeration<URL> findResources(String name) throws IOException {
116.482 - waitForTask(name);
116.483 - return super.findResources(name);
116.484 - }
116.485 -
116.486 - private synchronized void waitForTask(String name) {
116.487 - if (name.startsWith(prefix()) && Thread.currentThread().getName().contains("block")) {
116.488 - try {
116.489 - wait();
116.490 - } catch (InterruptedException ex) {
116.491 - Exceptions.printStackTrace(ex);
116.492 - }
116.493 - }
116.494 - }
116.495 - }
116.496 -
116.497 - My loader = new My();
116.498 - loader.query = createLookup(loader);
116.499 - Thread t = new Thread(loader, "block when querying");
116.500 - t.start();
116.501 - t.join(1000);
116.502 -
116.503 - // this blocks waiting for the waitForTask to finish
116.504 - // right now
116.505 - Float f = loader.query.lookup(Float.class);
116.506 - assertNull("Nothing found", f);
116.507 -
116.508 - synchronized (loader) {
116.509 - loader.notifyAll();
116.510 - }
116.511 - t.join();
116.512 -
116.513 - assertNull("Nothing found", loader.value);
116.514 - }
116.515 -
116.516 - public void testInitializerRobustness() throws Exception { // #174055
116.517 - check(Broken1.class.getName());
116.518 - check(Broken2.class.getName());
116.519 - }
116.520 - private void check(final String n) {
116.521 - assertNull(Lookups.metaInfServices(new ClassLoader() {
116.522 - protected @Override Enumeration<URL> findResources(String name) throws IOException {
116.523 - if (name.equals("META-INF/services/java.lang.Object")) {
116.524 - return Enumerations.singleton(new URL(null, "dummy:stuff", new URLStreamHandler() {
116.525 - protected URLConnection openConnection(URL u) throws IOException {
116.526 - return new URLConnection(u) {
116.527 - public void connect() throws IOException {}
116.528 - public @Override InputStream getInputStream() throws IOException {
116.529 - return new ByteArrayInputStream(n.getBytes("UTF-8"));
116.530 - }
116.531 - };
116.532 - }
116.533 - }));
116.534 - } else {
116.535 - return Enumerations.empty();
116.536 - }
116.537 - }
116.538 - }).lookup(Object.class));
116.539 - }
116.540 - public static class Broken1 {
116.541 - public Broken1() {
116.542 - throw new NullPointerException("broken1");
116.543 - }
116.544 - }
116.545 - public static class Broken2 {
116.546 - static {
116.547 - if (true) { // otherwise javac complains
116.548 - throw new NullPointerException("broken2");
116.549 - }
116.550 - }
116.551 - }
116.552 -
116.553 -}
117.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTestRunnable.java Sat Oct 31 15:06:58 2009 +0100
117.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
117.3 @@ -1,50 +0,0 @@
117.4 -/*
117.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
117.6 - *
117.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
117.8 - *
117.9 - * The contents of this file are subject to the terms of either the GNU
117.10 - * General Public License Version 2 only ("GPL") or the Common
117.11 - * Development and Distribution License("CDDL") (collectively, the
117.12 - * "License"). You may not use this file except in compliance with the
117.13 - * License. You can obtain a copy of the License at
117.14 - * http://www.netbeans.org/cddl-gplv2.html
117.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
117.16 - * specific language governing permissions and limitations under the
117.17 - * License. When distributing the software, include this License Header
117.18 - * Notice in each file and include the License file at
117.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
117.20 - * particular file as subject to the "Classpath" exception as provided
117.21 - * by Sun in the GPL Version 2 section of the License file that
117.22 - * accompanied this code. If applicable, add the following below the
117.23 - * License Header, with the fields enclosed by brackets [] replaced by
117.24 - * your own identifying information:
117.25 - * "Portions Copyrighted [year] [name of copyright owner]"
117.26 - *
117.27 - * Contributor(s):
117.28 - *
117.29 - * The Original Software is NetBeans. The Initial Developer of the Original
117.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
117.31 - * Microsystems, Inc. All Rights Reserved.
117.32 - *
117.33 - * If you wish your version of this file to be governed by only the CDDL
117.34 - * or only the GPL Version 2, indicate your decision by adding
117.35 - * "[Contributor] elects to include this software in this distribution
117.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
117.37 - * single choice of license, a recipient has the option to distribute
117.38 - * your version of this file under either the CDDL, the GPL Version 2 or
117.39 - * to extend the choice of license to its licensees as provided above.
117.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
117.41 - * Version 2 license, then the option applies only if the new code is
117.42 - * made subject to such option by the copyright holder.
117.43 - */
117.44 -
117.45 -package org.openide.util.lookup;
117.46 -
117.47 -
117.48 -/**
117.49 - */
117.50 -public final class MetaInfServicesLookupTestRunnable implements Runnable {
117.51 - public void run() {
117.52 - }
117.53 -}
118.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTestRunnable.txt Sat Oct 31 15:06:58 2009 +0100
118.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
118.3 @@ -1,1 +0,0 @@
118.4 -org.openide.util.lookup.MetaInfServicesLookupTestRunnable
119.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/NamedServicesLookupTest.java Sat Oct 31 15:06:58 2009 +0100
119.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
119.3 @@ -1,85 +0,0 @@
119.4 -/*
119.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
119.6 - *
119.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
119.8 - *
119.9 - * The contents of this file are subject to the terms of either the GNU
119.10 - * General Public License Version 2 only ("GPL") or the Common
119.11 - * Development and Distribution License("CDDL") (collectively, the
119.12 - * "License"). You may not use this file except in compliance with the
119.13 - * License. You can obtain a copy of the License at
119.14 - * http://www.netbeans.org/cddl-gplv2.html
119.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
119.16 - * specific language governing permissions and limitations under the
119.17 - * License. When distributing the software, include this License Header
119.18 - * Notice in each file and include the License file at
119.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
119.20 - * particular file as subject to the "Classpath" exception as provided
119.21 - * by Sun in the GPL Version 2 section of the License file that
119.22 - * accompanied this code. If applicable, add the following below the
119.23 - * License Header, with the fields enclosed by brackets [] replaced by
119.24 - * your own identifying information:
119.25 - * "Portions Copyrighted [year] [name of copyright owner]"
119.26 - *
119.27 - * Contributor(s):
119.28 - *
119.29 - * The Original Software is NetBeans. The Initial Developer of the Original
119.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
119.31 - * Microsystems, Inc. All Rights Reserved.
119.32 - *
119.33 - * If you wish your version of this file to be governed by only the CDDL
119.34 - * or only the GPL Version 2, indicate your decision by adding
119.35 - * "[Contributor] elects to include this software in this distribution
119.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
119.37 - * single choice of license, a recipient has the option to distribute
119.38 - * your version of this file under either the CDDL, the GPL Version 2 or
119.39 - * to extend the choice of license to its licensees as provided above.
119.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
119.41 - * Version 2 license, then the option applies only if the new code is
119.42 - * made subject to such option by the copyright holder.
119.43 - */
119.44 -
119.45 -package org.openide.util.lookup;
119.46 -
119.47 -import org.openide.util.Lookup;
119.48 -import org.openide.util.test.MockLookup;
119.49 -
119.50 -
119.51 -/** Test finding services from manifest.
119.52 - * @author Jaroslav Tulach
119.53 - */
119.54 -public class NamedServicesLookupTest extends MetaInfServicesLookupTest {
119.55 - static {
119.56 - MockLookup.init();
119.57 - }
119.58 - public NamedServicesLookupTest(String name) {
119.59 - super(name);
119.60 - }
119.61 -
119.62 - @Override
119.63 - protected String prefix() {
119.64 - return "META-INF/namedservices/sub/path/";
119.65 - }
119.66 -
119.67 - @Override
119.68 - protected Lookup createLookup(ClassLoader c) {
119.69 - MockLookup.setInstances(c);
119.70 - Thread.currentThread().setContextClassLoader(c);
119.71 - Lookup l = Lookups.forPath("sub/path");
119.72 - return l;
119.73 - }
119.74 -
119.75 - //
119.76 - // this is not much inheriting test, as we mask most of the tested methods
119.77 - // anyway, but the infrastructure to generate the JAR files is useful
119.78 - //
119.79 -
119.80 - public @Override void testLoaderSkew() {}
119.81 - public @Override void testStability() throws Exception {}
119.82 - public @Override void testMaskingOfResources() throws Exception {}
119.83 - public @Override void testOrdering() throws Exception {}
119.84 - public @Override void testNoCallToGetResourceForObjectIssue65124() throws Exception {}
119.85 - public @Override void testSuperTypes() throws Exception {}
119.86 - public @Override void testWrongOrderAsInIssue100320() throws Exception {}
119.87 -
119.88 -}
120.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/PathInLookupTest.java Sat Oct 31 15:06:58 2009 +0100
120.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
120.3 @@ -1,112 +0,0 @@
120.4 -/*
120.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
120.6 - *
120.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
120.8 - *
120.9 - * The contents of this file are subject to the terms of either the GNU
120.10 - * General Public License Version 2 only ("GPL") or the Common
120.11 - * Development and Distribution License("CDDL") (collectively, the
120.12 - * "License"). You may not use this file except in compliance with the
120.13 - * License. You can obtain a copy of the License at
120.14 - * http://www.netbeans.org/cddl-gplv2.html
120.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
120.16 - * specific language governing permissions and limitations under the
120.17 - * License. When distributing the software, include this License Header
120.18 - * Notice in each file and include the License file at
120.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
120.20 - * particular file as subject to the "Classpath" exception as provided
120.21 - * by Sun in the GPL Version 2 section of the License file that
120.22 - * accompanied this code. If applicable, add the following below the
120.23 - * License Header, with the fields enclosed by brackets [] replaced by
120.24 - * your own identifying information:
120.25 - * "Portions Copyrighted [year] [name of copyright owner]"
120.26 - *
120.27 - * Contributor(s):
120.28 - *
120.29 - * The Original Software is NetBeans. The Initial Developer of the Original
120.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
120.31 - * Microsystems, Inc. All Rights Reserved.
120.32 - *
120.33 - * If you wish your version of this file to be governed by only the CDDL
120.34 - * or only the GPL Version 2, indicate your decision by adding
120.35 - * "[Contributor] elects to include this software in this distribution
120.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
120.37 - * single choice of license, a recipient has the option to distribute
120.38 - * your version of this file under either the CDDL, the GPL Version 2 or
120.39 - * to extend the choice of license to its licensees as provided above.
120.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
120.41 - * Version 2 license, then the option applies only if the new code is
120.42 - * made subject to such option by the copyright holder.
120.43 - */
120.44 -
120.45 -package org.openide.util.lookup;
120.46 -
120.47 -import java.util.logging.Level;
120.48 -import org.netbeans.junit.MockServices;
120.49 -import org.netbeans.junit.NbTestCase;
120.50 -import org.netbeans.modules.openide.util.NamedServicesProvider;
120.51 -import org.openide.util.Lookup;
120.52 -
120.53 -/**
120.54 - * @author Jaroslav Tulach
120.55 - */
120.56 -public class PathInLookupTest extends NbTestCase {
120.57 - static {
120.58 - System.setProperty("org.openide.util.Lookup.paths", "MyServices:YourServices");
120.59 - MockServices.setServices(P.class);
120.60 - Lookup.getDefault();
120.61 - }
120.62 -
120.63 - public PathInLookupTest(String name) {
120.64 - super(name);
120.65 - }
120.66 -
120.67 - @Override
120.68 - protected Level logLevel() {
120.69 - return Level.FINE;
120.70 - }
120.71 -
120.72 - public void testInterfaceFoundInMyServices() throws Exception {
120.73 - assertNull("not found", Lookup.getDefault().lookup(Shared.class));
120.74 - Shared v = new Shared();
120.75 - P.ic1.add(v);
120.76 - assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
120.77 - P.ic1.remove(v);
120.78 - assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
120.79 - }
120.80 - public void testInterfaceFoundInMyServices2() throws Exception {
120.81 - assertNull("not found", Lookup.getDefault().lookup(Shared.class));
120.82 - Shared v = new Shared();
120.83 - P.ic2.add(v);
120.84 - assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
120.85 - P.ic2.remove(v);
120.86 - assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
120.87 - }
120.88 -
120.89 - static final class Shared extends Object {}
120.90 -
120.91 - public static final class P extends NamedServicesProvider {
120.92 - static InstanceContent ic1 = new InstanceContent();
120.93 - static InstanceContent ic2 = new InstanceContent();
120.94 - static AbstractLookup[] arr = {
120.95 - new AbstractLookup(ic1), new AbstractLookup(ic2)
120.96 - };
120.97 -
120.98 -
120.99 - @Override
120.100 - public Lookup create(String path) {
120.101 - int indx = -1;
120.102 - if (path.equals("MyServices/")) {
120.103 - indx = 0;
120.104 - }
120.105 - if (path.equals("YourServices/")) {
120.106 - indx = 1;
120.107 - }
120.108 - if (indx == -1) {
120.109 - fail("Unexpected lookup query: " + path);
120.110 - }
120.111 - return arr[indx];
120.112 - }
120.113 - }
120.114 -
120.115 -}
121.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/PrefixServicesLookupTest.java Sat Oct 31 15:06:58 2009 +0100
121.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
121.3 @@ -1,63 +0,0 @@
121.4 -/*
121.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
121.6 - *
121.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
121.8 - *
121.9 - * The contents of this file are subject to the terms of either the GNU
121.10 - * General Public License Version 2 only ("GPL") or the Common
121.11 - * Development and Distribution License("CDDL") (collectively, the
121.12 - * "License"). You may not use this file except in compliance with the
121.13 - * License. You can obtain a copy of the License at
121.14 - * http://www.netbeans.org/cddl-gplv2.html
121.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
121.16 - * specific language governing permissions and limitations under the
121.17 - * License. When distributing the software, include this License Header
121.18 - * Notice in each file and include the License file at
121.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
121.20 - * particular file as subject to the "Classpath" exception as provided
121.21 - * by Sun in the GPL Version 2 section of the License file that
121.22 - * accompanied this code. If applicable, add the following below the
121.23 - * License Header, with the fields enclosed by brackets [] replaced by
121.24 - * your own identifying information:
121.25 - * "Portions Copyrighted [year] [name of copyright owner]"
121.26 - *
121.27 - * Contributor(s):
121.28 - *
121.29 - * The Original Software is NetBeans. The Initial Developer of the Original
121.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
121.31 - * Microsystems, Inc. All Rights Reserved.
121.32 - *
121.33 - * If you wish your version of this file to be governed by only the CDDL
121.34 - * or only the GPL Version 2, indicate your decision by adding
121.35 - * "[Contributor] elects to include this software in this distribution
121.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
121.37 - * single choice of license, a recipient has the option to distribute
121.38 - * your version of this file under either the CDDL, the GPL Version 2 or
121.39 - * to extend the choice of license to its licensees as provided above.
121.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
121.41 - * Version 2 license, then the option applies only if the new code is
121.42 - * made subject to such option by the copyright holder.
121.43 - */
121.44 -
121.45 -package org.openide.util.lookup;
121.46 -
121.47 -import org.openide.util.Lookup;
121.48 -
121.49 -
121.50 -/** Test finding services from manifest.
121.51 - * @author Jaroslav Tulach
121.52 - */
121.53 -public class PrefixServicesLookupTest extends MetaInfServicesLookupTest {
121.54 - public PrefixServicesLookupTest(String name) {
121.55 - super(name);
121.56 - }
121.57 -
121.58 - protected String prefix() {
121.59 - return "META-INF/netbeans/prefix/services/test/";
121.60 - }
121.61 -
121.62 - protected Lookup createLookup(ClassLoader c) {
121.63 - return Lookups.metaInfServices(c, prefix());
121.64 - }
121.65 -
121.66 -}
122.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupEventIssue136866Test.java Sat Oct 31 15:06:58 2009 +0100
122.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
122.3 @@ -1,56 +0,0 @@
122.4 -package org.openide.util.lookup;
122.5 -
122.6 -import junit.framework.TestCase;
122.7 -import org.openide.util.Lookup;
122.8 -import org.openide.util.LookupEvent;
122.9 -import org.openide.util.LookupListener;
122.10 -
122.11 -/**
122.12 - * Test case which demonstrates that ProxyLookup does not fire
122.13 - * an event when it should.
122.14 - */
122.15 -public class ProxyLookupEventIssue136866Test extends TestCase {
122.16 -
122.17 - public ProxyLookupEventIssue136866Test(String testName) {
122.18 - super(testName);
122.19 - }
122.20 -
122.21 - public void testAbstractLookupFiresEventWhenContentChanged() {
122.22 - InstanceContent ic = new InstanceContent();
122.23 - AbstractLookup al = new AbstractLookup(ic);
122.24 -
122.25 - final int[] counts = {0}; // Number of items observed upon a LookupEvent
122.26 - final Lookup.Result<String> result = al.lookupResult(String.class);
122.27 -
122.28 - result.addLookupListener(new LookupListener() {
122.29 - public void resultChanged(LookupEvent ev) {
122.30 - // this gets called as expected
122.31 - assertSame(result, ev.getSource());
122.32 - counts[0] = result.allInstances().size();
122.33 - }
122.34 - });
122.35 -
122.36 - ic.add("hello1");
122.37 - assertEquals(1, counts[0]);
122.38 - }
122.39 -
122.40 - public void testProxyLookupFailsToFireEventWhenProxiedLookupChanged() {
122.41 - InstanceContent ic = new InstanceContent();
122.42 -// AbstractLookup al = new AbstractLookup(ic);
122.43 - Lookup proxy = new AbstractLookup(ic);
122.44 -
122.45 - final int[] counts = {0}; // Number of items observed upon a LookupEvent
122.46 - final Lookup.Result<String> result = proxy.lookupResult(String.class);
122.47 -
122.48 - result.addLookupListener(new LookupListener() {
122.49 - public void resultChanged(LookupEvent ev) {
122.50 - // this should be called but never is
122.51 - assertSame(result, ev.getSource());
122.52 - counts[0] = result.allInstances().size();
122.53 - }
122.54 - });
122.55 -
122.56 - ic.add("hello1");
122.57 - assertEquals(1, counts[0]);
122.58 - }
122.59 -}
123.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java Sat Oct 31 15:06:58 2009 +0100
123.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
123.3 @@ -1,655 +0,0 @@
123.4 -/*
123.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
123.6 - *
123.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
123.8 - *
123.9 - * The contents of this file are subject to the terms of either the GNU
123.10 - * General Public License Version 2 only ("GPL") or the Common
123.11 - * Development and Distribution License("CDDL") (collectively, the
123.12 - * "License"). You may not use this file except in compliance with the
123.13 - * License. You can obtain a copy of the License at
123.14 - * http://www.netbeans.org/cddl-gplv2.html
123.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
123.16 - * specific language governing permissions and limitations under the
123.17 - * License. When distributing the software, include this License Header
123.18 - * Notice in each file and include the License file at
123.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
123.20 - * particular file as subject to the "Classpath" exception as provided
123.21 - * by Sun in the GPL Version 2 section of the License file that
123.22 - * accompanied this code. If applicable, add the following below the
123.23 - * License Header, with the fields enclosed by brackets [] replaced by
123.24 - * your own identifying information:
123.25 - * "Portions Copyrighted [year] [name of copyright owner]"
123.26 - *
123.27 - * Contributor(s):
123.28 - *
123.29 - * The Original Software is NetBeans. The Initial Developer of the Original
123.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
123.31 - * Microsystems, Inc. All Rights Reserved.
123.32 - *
123.33 - * If you wish your version of this file to be governed by only the CDDL
123.34 - * or only the GPL Version 2, indicate your decision by adding
123.35 - * "[Contributor] elects to include this software in this distribution
123.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
123.37 - * single choice of license, a recipient has the option to distribute
123.38 - * your version of this file under either the CDDL, the GPL Version 2 or
123.39 - * to extend the choice of license to its licensees as provided above.
123.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
123.41 - * Version 2 license, then the option applies only if the new code is
123.42 - * made subject to such option by the copyright holder.
123.43 - */
123.44 -
123.45 -package org.openide.util.lookup;
123.46 -
123.47 -import java.io.Serializable;
123.48 -
123.49 -import java.lang.ref.Reference;
123.50 -import java.lang.ref.WeakReference;
123.51 -import java.util.*;
123.52 -import java.util.concurrent.Executor;
123.53 -import junit.framework.*;
123.54 -import org.netbeans.junit.*;
123.55 -import org.netbeans.modules.openide.util.ActiveQueue;
123.56 -import org.openide.util.Lookup;
123.57 -import org.openide.util.Lookup.Result;
123.58 -import org.openide.util.LookupEvent;
123.59 -import org.openide.util.LookupListener;
123.60 -
123.61 -/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
123.62 - */
123.63 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
123.64 -public class ProxyLookupTest extends AbstractLookupBaseHid
123.65 -implements AbstractLookupBaseHid.Impl {
123.66 - public ProxyLookupTest(java.lang.String testName) {
123.67 - super(testName, null);
123.68 - }
123.69 -
123.70 - public static Test suite() {
123.71 - return new NbTestSuite (ProxyLookupTest.class);
123.72 -// return new ProxyLookupTest("testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679");
123.73 - }
123.74 -
123.75 - /** Creates an lookup for given lookup. This class just returns
123.76 - * the object passed in, but subclasses can be different.
123.77 - * @param lookup in lookup
123.78 - * @return a lookup to use
123.79 - */
123.80 - public Lookup createLookup (Lookup lookup) {
123.81 - return new ProxyLookup (new Lookup[] { lookup });
123.82 - }
123.83 -
123.84 - public Lookup createInstancesLookup (InstanceContent ic) {
123.85 - return new AbstractLookup (ic);
123.86 - }
123.87 -
123.88 -
123.89 - public void clearCaches () {
123.90 - }
123.91 -
123.92 -
123.93 - /** Check whether setLookups method does not fire when there is no
123.94 - * change in the lookups.
123.95 - */
123.96 - public void testProxyListener () {
123.97 - ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
123.98 -
123.99 - final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
123.100 - final Object[] IGNORE = {
123.101 - ProxyLookup.ImmutableInternalData.EMPTY,
123.102 - ProxyLookup.ImmutableInternalData.EMPTY_ARR,
123.103 - ActiveQueue.queue(),
123.104 - Collections.emptyMap(),
123.105 - Collections.emptyList(),
123.106 - Collections.emptySet()
123.107 - };
123.108 -
123.109 - assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
123.110 -
123.111 - Lookup.Result<Object> res = lookup.lookup (template);
123.112 -
123.113 - assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
123.114 -
123.115 - LL ll = new LL ();
123.116 - res.addLookupListener (ll);
123.117 - Collection allRes = res.allInstances ();
123.118 -
123.119 - lookup.setLookups (new Lookup[0]);
123.120 -
123.121 - if (ll.getCount () != 0) {
123.122 - fail ("Calling setLookups (emptyarray) fired a change");
123.123 - }
123.124 -
123.125 - InstanceContent t = new InstanceContent();
123.126 - Lookup del = new AbstractLookup (t);
123.127 - t.add("Ahoj");
123.128 - lookup.setLookups (new Lookup[] { del });
123.129 -
123.130 - if (ll.getCount () != 1) {
123.131 - fail ("Changing lookups did not generate an event");
123.132 - }
123.133 -
123.134 - lookup.setLookups (new Lookup[] { del });
123.135 -
123.136 - if (ll.getCount () != 0) {
123.137 - fail ("Calling setLookups (thesamearray) fired a change");
123.138 - }
123.139 - }
123.140 -
123.141 - public void testNoListenersProxyListener () {
123.142 - ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
123.143 - class E implements Executor {
123.144 - Runnable r;
123.145 - public void execute(Runnable command) {
123.146 - assertNull("NO previous", r);
123.147 - r = command;
123.148 - }
123.149 - public void perform() {
123.150 - assertNotNull("We shall have a runnable", r);
123.151 - r.run();
123.152 - r = null;
123.153 - }
123.154 - }
123.155 - E executor = new E();
123.156 -
123.157 -
123.158 - final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
123.159 - final Object[] IGNORE = {
123.160 - ProxyLookup.ImmutableInternalData.EMPTY,
123.161 - ProxyLookup.ImmutableInternalData.EMPTY_ARR,
123.162 - ActiveQueue.queue(),
123.163 - Collections.emptyMap(),
123.164 - Collections.emptyList(),
123.165 - Collections.emptySet()
123.166 - };
123.167 -
123.168 - assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
123.169 -
123.170 - Lookup.Result<Object> res = lookup.lookup (template);
123.171 -
123.172 - assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
123.173 -
123.174 - LL ll = new LL ();
123.175 - res.addLookupListener (ll);
123.176 - Collection allRes = res.allInstances ();
123.177 -
123.178 - lookup.setLookups (executor, new Lookup[0]);
123.179 - if (ll.getCount () != 0) {
123.180 - fail ("Calling setLookups (emptyarray) fired a change");
123.181 - }
123.182 -
123.183 - InstanceContent t = new InstanceContent();
123.184 - Lookup del = new AbstractLookup (t);
123.185 - t.add("Ahoj");
123.186 - lookup.setLookups (executor, new Lookup[] { del });
123.187 - assertEquals("No change yet", 0, ll.getCount());
123.188 - executor.perform();
123.189 - if (ll.getCount () != 1) {
123.190 - fail ("Changing lookups did not generate an event");
123.191 - }
123.192 -
123.193 - lookup.setLookups (executor, new Lookup[] { del });
123.194 - if (ll.getCount () != 0) {
123.195 - fail ("Calling setLookups (thesamearray) fired a change");
123.196 - }
123.197 - }
123.198 -
123.199 - public void testSetLookups () throws Exception {
123.200 - AbstractLookup a1 = new AbstractLookup (new InstanceContent ());
123.201 - AbstractLookup a2 = new AbstractLookup (new InstanceContent ());
123.202 -
123.203 - InstanceContent i3 = new InstanceContent ();
123.204 - i3.add (i3);
123.205 - AbstractLookup a3 = new AbstractLookup (i3);
123.206 -
123.207 - final ProxyLookup p = new ProxyLookup (new Lookup[] { a1, a2 });
123.208 - final Lookup.Result res1 = p.lookup (new Lookup.Template (Object.class));
123.209 - Collection c1 = res1.allInstances();
123.210 -
123.211 - Lookup.Result res2 = p.lookup (new Lookup.Template (String.class));
123.212 - Collection c2 = res2.allInstances ();
123.213 -
123.214 -
123.215 - assertTrue ("We need two results", res1 != res2);
123.216 -
123.217 - final Object blocked = new Object ();
123.218 -
123.219 - class L extends Object implements LookupListener {
123.220 - public void resultChanged (LookupEvent ev) {
123.221 - try {
123.222 - res1.removeLookupListener(this);
123.223 -
123.224 - // waiting for second thread to start #111#
123.225 - blocked.wait ();
123.226 -
123.227 - } catch (Exception ex) {
123.228 - ex.printStackTrace();
123.229 - fail ("An exception occured ");
123.230 - }
123.231 - }
123.232 - }
123.233 -
123.234 - final L listener1 = new L ();
123.235 - res1.addLookupListener (listener1);
123.236 -
123.237 -
123.238 - Runnable newLookupSetter = new Runnable() {
123.239 - public void run () {
123.240 - synchronized (blocked) {
123.241 - try {
123.242 - p.setLookups (new Lookup[0]);
123.243 - } catch (Exception ex) {
123.244 - ex.printStackTrace();
123.245 - fail ("setLookups failed.");
123.246 - } finally {
123.247 - // starts the main thread #111#
123.248 - blocked.notify ();
123.249 - }
123.250 - }
123.251 - }
123.252 - };
123.253 -
123.254 - synchronized (blocked) {
123.255 - new Thread (newLookupSetter).start ();
123.256 -
123.257 - p.setLookups (new Lookup[] { a1, a2, a3 });
123.258 - }
123.259 - }
123.260 -
123.261 - public void testProxyLookupTemplateCaching(){
123.262 - Lookup lookups[] = new Lookup[1];
123.263 - doProxyLookupTemplateCaching(lookups, false);
123.264 - }
123.265 -
123.266 - public void testProxyLookupTemplateCachingOnSizeTwoArray() {
123.267 - Lookup lookups[] = new Lookup[2];
123.268 - lookups[1] = Lookup.EMPTY;
123.269 - doProxyLookupTemplateCaching(lookups, false);
123.270 - }
123.271 - public void testProxyLookupShallNotAllowModificationOfGetLookups(){
123.272 - Lookup lookups[] = new Lookup[1];
123.273 - doProxyLookupTemplateCaching(lookups, true);
123.274 - }
123.275 -
123.276 - public void testProxyLookupShallNotAllowModificationOfGetLookupsOnSizeTwoArray() {
123.277 - Lookup lookups[] = new Lookup[2];
123.278 - lookups[1] = Lookup.EMPTY;
123.279 - doProxyLookupTemplateCaching(lookups, true);
123.280 - }
123.281 -
123.282 - /** Index 0 of lookups will be modified, the rest is up to the
123.283 - * setup code.
123.284 - */
123.285 - private void doProxyLookupTemplateCaching(Lookup[] lookups, boolean reget) {
123.286 - // Create MyProxyLookup with one lookup containing the String object
123.287 - InstanceContent inst = new InstanceContent();
123.288 - inst.add(new String("Hello World")); //NOI18N
123.289 - lookups[0] = new AbstractLookup(inst);
123.290 - ProxyLookup proxy = new ProxyLookup(lookups);
123.291 - if (reget) {
123.292 - lookups = proxy.getLookups();
123.293 - }
123.294 -
123.295 - // Performing template lookup for String object
123.296 - Lookup.Result result = proxy.lookup(new Lookup.Template(String.class, null, null));
123.297 - int stringTemplateResultSize = result.allInstances().size();
123.298 - assertEquals ("Ensure, there is only one instance of String.class in proxyLookup:", //NOI18N
123.299 - 1, stringTemplateResultSize);
123.300 -
123.301 - // Changing lookup in proxy lookup, now it will contain
123.302 - // StringBuffer Object instead of String
123.303 - InstanceContent ic2 = new InstanceContent();
123.304 - ic2.add(new Integer(1234567890));
123.305 - lookups[0] = new AbstractLookup(ic2);
123.306 - proxy.setLookups(lookups);
123.307 -
123.308 - assertEquals ("the old result is updated", 0, result.allInstances().size());
123.309 -
123.310 - // Instance of String.class should not appear in proxyLookup
123.311 - Lookup.Result r2 = proxy.lookup(new Lookup.Template(String.class, null, null));
123.312 - assertEquals ("Instance of String.class should not appear in proxyLookup:", //NOI18N
123.313 - 0, r2.allInstances().size());
123.314 -
123.315 - Lookup.Result r3 = proxy.lookup(new Lookup.Template(Integer.class, null, null));
123.316 - assertEquals ("There is only one instance of Integer.class in proxyLookup:", //NOI18N
123.317 - 1, r3.allInstances().size());
123.318 - }
123.319 -
123.320 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
123.321 - doListeningAndQueryingByTwoListenersSetLookups(0, 1);
123.322 - }
123.323 - public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
123.324 - doListeningAndQueryingByTwoListenersSetLookups(1, 1);
123.325 - }
123.326 - public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
123.327 - doListeningAndQueryingByTwoListenersSetLookups(2, 1);
123.328 - }
123.329 -
123.330 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
123.331 - doListeningAndQueryingByTwoListenersSetLookups(0, 2);
123.332 - }
123.333 - public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
123.334 - doListeningAndQueryingByTwoListenersSetLookups(1, 2);
123.335 - }
123.336 - public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
123.337 - doListeningAndQueryingByTwoListenersSetLookups(2, 2);
123.338 - }
123.339 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
123.340 - doListeningAndQueryingByTwoListenersSetLookups(0, 22);
123.341 - }
123.342 - public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
123.343 - doListeningAndQueryingByTwoListenersSetLookups(1, 22);
123.344 - }
123.345 - public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
123.346 - doListeningAndQueryingByTwoListenersSetLookups(2, 22);
123.347 - }
123.348 -
123.349 - private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth) {
123.350 - ProxyLookup orig = new ProxyLookup();
123.351 - ProxyLookup on = orig;
123.352 -
123.353 - while (--depth > 0) {
123.354 - on = new ProxyLookup(new Lookup[] { on });
123.355 - }
123.356 -
123.357 -
123.358 - final ProxyLookup lookup = on;
123.359 -
123.360 - class L implements LookupListener {
123.361 - Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
123.362 - Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
123.363 - Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
123.364 -
123.365 - {
123.366 - integer.addLookupListener(this);
123.367 - number.addLookupListener(this);
123.368 - serial.addLookupListener(this);
123.369 - }
123.370 -
123.371 - int round;
123.372 -
123.373 - public void resultChanged(LookupEvent ev) {
123.374 - Collection c1 = get(type, integer);
123.375 - Collection c2 = get(type, number);
123.376 - Collection c3 = get(type, serial);
123.377 -
123.378 - assertEquals("round " + round + " c1 vs. c2", c1, c2);
123.379 - assertEquals("round " + round + " c1 vs. c3", c1, c3);
123.380 - assertEquals("round " + round + " c2 vs. c3", c2, c3);
123.381 -
123.382 - round++;
123.383 - }
123.384 -
123.385 - private Collection get(int type, Lookup.Result res) {
123.386 - Collection c;
123.387 - switch(type) {
123.388 - case 0: c = res.allInstances(); break;
123.389 - case 1: c = res.allClasses(); break;
123.390 - case 2: c = res.allItems(); break;
123.391 - default: c = null; fail("Type: " + type); break;
123.392 - }
123.393 -
123.394 - assertNotNull(c);
123.395 - return new ArrayList(c);
123.396 - }
123.397 - }
123.398 -
123.399 - L listener = new L();
123.400 - listener.resultChanged(null);
123.401 - ArrayList arr = new ArrayList();
123.402 - for(int i = 0; i < 100; i++) {
123.403 - arr.add(new Integer(i));
123.404 -
123.405 - orig.setLookups(new Lookup[] { Lookups.fixed(arr.toArray()) });
123.406 - }
123.407 -
123.408 - assertEquals("3x100+1 checks", 301, listener.round);
123.409 - }
123.410 -
123.411 - static Object holder;
123.412 -
123.413 - public void testProxyWithLiveResultCanBeCollected() {
123.414 - Lookup layer0 = Lookups.singleton("Hello");
123.415 - Lookup layer1 = new ProxyLookup(new Lookup[] { layer0 });
123.416 - Lookup layer2 = new ProxyLookup(new Lookup[] { layer1 });
123.417 - Lookup.Result result1 = layer1.lookup(new Lookup.Template(String.class));
123.418 -
123.419 - assertEquals("One instance", 1, result1.allInstances().size());
123.420 -
123.421 - // this will create ProxyLookup$R which listens on origResult
123.422 - Lookup.Result result2 = layer2.lookup(new Lookup.Template(String.class));
123.423 -
123.424 - // this line is necessary. W/o actually querying the result,
123.425 - // it will nether compute it nor attach the listener.
123.426 - assertEquals("One instance", 1, result2.allInstances().size());
123.427 -
123.428 - result2.addLookupListener(new LookupListener() {
123.429 - public void resultChanged(LookupEvent ev) {}
123.430 - });
123.431 -
123.432 - Reference ref = new WeakReference(layer2);
123.433 - layer2 = null;
123.434 - result2 = null;
123.435 - try {
123.436 - holder = result1;
123.437 - assertGC ("The proxy lookup not been garbage collected!", ref);
123.438 - } finally {
123.439 - holder = null;
123.440 - }
123.441 - }
123.442 -
123.443 - public void testArrayIndexAsInIssue119292() throws Exception {
123.444 - final ProxyLookup pl = new ProxyLookup();
123.445 - final int[] cnt = { 0 };
123.446 -
123.447 - class L extends Lookup {
123.448 - L[] set;
123.449 - Lookup l;
123.450 -
123.451 - public L(String s) {
123.452 - l = Lookups.singleton(s);
123.453 - }
123.454 -
123.455 - @Override
123.456 - public <T> T lookup(Class<T> clazz) {
123.457 - return l.lookup(clazz);
123.458 - }
123.459 -
123.460 - @Override
123.461 - public <T> Result<T> lookup(Template<T> template) {
123.462 - return l.lookup(template);
123.463 - }
123.464 -
123.465 - @Override
123.466 - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
123.467 - public boolean equals(Object obj) {
123.468 - if (set != null) {
123.469 - cnt[0]++;
123.470 - pl.setLookups(set);
123.471 - }
123.472 - return super.equals(obj);
123.473 - }
123.474 -
123.475 - @Override
123.476 - public int hashCode() {
123.477 - int hash = 3;
123.478 - return hash;
123.479 - }
123.480 - }
123.481 -
123.482 - Result<String> res = pl.lookupResult(String.class);
123.483 - assertEquals(Collections.EMPTY_LIST, res.allItems());
123.484 -
123.485 - L[] old = { new L("A"), new L("B") };
123.486 - L[] now = { new L("C") };
123.487 -
123.488 - pl.setLookups(old);
123.489 - cnt[0] = 0;
123.490 -
123.491 - old[0].set = new L[0];
123.492 - pl.setLookups(now);
123.493 -
123.494 - assertEquals("No call to equals", 0, cnt[0]);
123.495 -
123.496 - assertEquals("Still assigned to C", Collections.singletonList("C"), res.allInstances());
123.497 - }
123.498 -
123.499 - public void testArrayIndexWithAddRemoveListenerAsInIssue119292() throws Exception {
123.500 - final ProxyLookup pl = new ProxyLookup();
123.501 - final int[] cnt = { 0 };
123.502 -
123.503 - class L extends Lookup {
123.504 - L[] set;
123.505 - Lookup l;
123.506 -
123.507 - public L(String s) {
123.508 - l = Lookups.singleton(s);
123.509 - }
123.510 -
123.511 - @Override
123.512 - public <T> T lookup(Class<T> clazz) {
123.513 - return l.lookup(clazz);
123.514 - }
123.515 -
123.516 - @Override
123.517 - public <T> Result<T> lookup(Template<T> template) {
123.518 - Result<T> r = l.lookup(template);
123.519 - return new R<T>(r);
123.520 - }
123.521 -
123.522 - final class R<T> extends Result<T> {
123.523 - private Result<T> delegate;
123.524 -
123.525 - public R(Result<T> delegate) {
123.526 - this.delegate = delegate;
123.527 - }
123.528 -
123.529 - @Override
123.530 - public void addLookupListener(LookupListener l) {
123.531 - cnt[0]++;
123.532 - if (set != null) {
123.533 - pl.setLookups(set);
123.534 - }
123.535 - delegate.addLookupListener(l);
123.536 - }
123.537 -
123.538 - @Override
123.539 - public void removeLookupListener(LookupListener l) {
123.540 - cnt[0]++;
123.541 - if (set != null) {
123.542 - pl.setLookups(set);
123.543 - }
123.544 - delegate.removeLookupListener(l);
123.545 - }
123.546 -
123.547 - @Override
123.548 - public Collection<? extends T> allInstances() {
123.549 - return delegate.allInstances();
123.550 - }
123.551 - }
123.552 - }
123.553 -
123.554 - Result<String> res = pl.lookupResult(String.class);
123.555 - assertEquals(Collections.EMPTY_LIST, res.allItems());
123.556 -
123.557 - L[] old = { new L("A"), new L("B") };
123.558 - L[] now = { new L("C") };
123.559 -
123.560 - pl.setLookups(old);
123.561 - cnt[0] = 0;
123.562 -
123.563 - old[0].set = new L[0];
123.564 - pl.setLookups(now);
123.565 -
123.566 - if (cnt[0] == 0) {
123.567 - fail("There should be calls to listeners");
123.568 - }
123.569 -
123.570 - assertEquals("C is overriden from removeLookupListener", Collections.emptyList(), res.allInstances());
123.571 - }
123.572 -
123.573 -
123.574 - public void testArrayIndexWithSetLookupAsInIssue123679() throws Exception {
123.575 - final ProxyLookup pl = new ProxyLookup();
123.576 - final int[] cnt = { 0 };
123.577 -
123.578 - class L extends Lookup {
123.579 - L[] set;
123.580 - Lookup l;
123.581 - Collection<? extends Serializable> res;
123.582 -
123.583 - public L(String s) {
123.584 - l = Lookups.singleton(s);
123.585 - }
123.586 -
123.587 - @Override
123.588 - public <T> T lookup(Class<T> clazz) {
123.589 - return l.lookup(clazz);
123.590 - }
123.591 -
123.592 - @Override
123.593 - public <T> Result<T> lookup(Template<T> template) {
123.594 - cnt[0]++;
123.595 - if (set != null) {
123.596 - pl.setLookups(set);
123.597 - res = pl.lookupAll(Serializable.class);
123.598 - }
123.599 - Result<T> r = l.lookup(template);
123.600 - return r;
123.601 - }
123.602 - }
123.603 -
123.604 - L[] now = { new L("A"), new L("B") };
123.605 - L[] old = { new L("C") };
123.606 - pl.setLookups(old);
123.607 - old[0].set = now;
123.608 -
123.609 - Result<String> res = pl.lookupResult(String.class);
123.610 - assertEquals("New items visible", 2, res.allItems().size());
123.611 -
123.612 -
123.613 - pl.setLookups(new L("X"), new L("Y"), new L("Z"));
123.614 - }
123.615 -
123.616 - public void testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679() throws Exception {
123.617 - final ProxyLookup pl = new ProxyLookup();
123.618 - final int[] cnt = { 0 };
123.619 -
123.620 - class L extends Lookup {
123.621 - L[] set;
123.622 - Lookup l;
123.623 - Collection<? extends Serializable> res;
123.624 -
123.625 - public L(String s) {
123.626 - l = Lookups.singleton(s);
123.627 - }
123.628 -
123.629 - @Override
123.630 - public <T> T lookup(Class<T> clazz) {
123.631 - return l.lookup(clazz);
123.632 - }
123.633 -
123.634 - @Override
123.635 - public <T> Result<T> lookup(Template<T> template) {
123.636 - cnt[0]++;
123.637 - if (set != null) {
123.638 - pl.setLookups(set);
123.639 - res = pl.lookupAll(Serializable.class);
123.640 - }
123.641 - Result<T> r = l.lookup(template);
123.642 - return r;
123.643 - }
123.644 - }
123.645 -
123.646 - L dupl = new L("A");
123.647 - L[] now = { dupl };
123.648 - L[] old = { new L("C") };
123.649 - pl.setLookups(old);
123.650 - old[0].set = now;
123.651 -
123.652 - Result<String> res = pl.lookupResult(String.class);
123.653 - assertEquals("New items visible", 1, res.allItems().size());
123.654 -
123.655 -
123.656 - pl.setLookups(old);
123.657 - }
123.658 -}
124.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleLookupTest.java Sat Oct 31 15:06:58 2009 +0100
124.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
124.3 @@ -1,351 +0,0 @@
124.4 -/*
124.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
124.6 - *
124.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
124.8 - *
124.9 - * The contents of this file are subject to the terms of either the GNU
124.10 - * General Public License Version 2 only ("GPL") or the Common
124.11 - * Development and Distribution License("CDDL") (collectively, the
124.12 - * "License"). You may not use this file except in compliance with the
124.13 - * License. You can obtain a copy of the License at
124.14 - * http://www.netbeans.org/cddl-gplv2.html
124.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
124.16 - * specific language governing permissions and limitations under the
124.17 - * License. When distributing the software, include this License Header
124.18 - * Notice in each file and include the License file at
124.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
124.20 - * particular file as subject to the "Classpath" exception as provided
124.21 - * by Sun in the GPL Version 2 section of the License file that
124.22 - * accompanied this code. If applicable, add the following below the
124.23 - * License Header, with the fields enclosed by brackets [] replaced by
124.24 - * your own identifying information:
124.25 - * "Portions Copyrighted [year] [name of copyright owner]"
124.26 - *
124.27 - * Contributor(s):
124.28 - *
124.29 - * The Original Software is NetBeans. The Initial Developer of the Original
124.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
124.31 - * Microsystems, Inc. All Rights Reserved.
124.32 - *
124.33 - * If you wish your version of this file to be governed by only the CDDL
124.34 - * or only the GPL Version 2, indicate your decision by adding
124.35 - * "[Contributor] elects to include this software in this distribution
124.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
124.37 - * single choice of license, a recipient has the option to distribute
124.38 - * your version of this file under either the CDDL, the GPL Version 2 or
124.39 - * to extend the choice of license to its licensees as provided above.
124.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
124.41 - * Version 2 license, then the option applies only if the new code is
124.42 - * made subject to such option by the copyright holder.
124.43 - */
124.44 -
124.45 -package org.openide.util.lookup;
124.46 -
124.47 -import java.util.ArrayList;
124.48 -import java.util.Arrays;
124.49 -import java.util.Collection;
124.50 -import java.util.List;
124.51 -import java.util.Set;
124.52 -import org.netbeans.junit.NbTestCase;
124.53 -import org.openide.util.Lookup;
124.54 -
124.55 -/**
124.56 - * Tests for class SimpleLookup.
124.57 - * @author David Strupl
124.58 - */
124.59 -public class SimpleLookupTest extends NbTestCase {
124.60 -
124.61 - public SimpleLookupTest(String testName) {
124.62 - super(testName);
124.63 - }
124.64 -
124.65 - public void testEmptyLookup() {
124.66 - assertSize("Lookup.EMPTY should be small", 8, Lookup.EMPTY);
124.67 - }
124.68 -
124.69 - /**
124.70 - * Simple tests testing singleton lookup.
124.71 - */
124.72 - public void testSingleton() {
124.73 - //
124.74 - Object orig = new Object();
124.75 - Lookup p1 = Lookups.singleton(orig);
124.76 - Object obj = p1.lookup(Object.class);
124.77 - assertTrue(obj == orig);
124.78 - assertNull(p1.lookup(String.class));
124.79 - assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
124.80 - //
124.81 - Lookup p2 = Lookups.singleton("test");
124.82 - assertNotNull(p2.lookup(Object.class));
124.83 - assertNotNull(p2.lookup(String.class));
124.84 - assertNotNull(p2.lookup(java.io.Serializable.class));
124.85 - }
124.86 -
124.87 - public void testEmptyFixed() {
124.88 - Lookup l = Lookups.fixed();
124.89 - assertSize("Lookups.fixed() for empty list of items should be small", 8, l);
124.90 - assertSame(Lookup.EMPTY, l);
124.91 - }
124.92 -
124.93 - public void testSingleItemFixed() {
124.94 - Object o = new Object();
124.95 - Lookup l = Lookups.fixed(o);
124.96 - assertSize("Lookups.fixed(o) for a single item should be small", 24, l);
124.97 - }
124.98 -
124.99 - /**
124.100 - * Simple tests testing fixed lookup.
124.101 - */
124.102 - public void testFixed() {
124.103 - //
124.104 - Object[] orig = new Object[] { new Object(), new Object() };
124.105 - Lookup p1 = Lookups.fixed(orig);
124.106 - Object obj = p1.lookup(Object.class);
124.107 - assertTrue(obj == orig[0] || obj == orig[1]);
124.108 - assertNull(p1.lookup(String.class));
124.109 - //
124.110 - String[] s = new String[] { "test1", "test2" };
124.111 - Lookup p2 = Lookups.fixed((Object[]) s);
124.112 - Object obj2 = p2.lookup(Object.class);
124.113 - assertNotNull(obj2);
124.114 - if (obj2 != s[0] && obj2 != s[1]) {
124.115 - fail("Returned objects are not the originals");
124.116 - }
124.117 - assertNotNull(p2.lookup(String.class));
124.118 - assertNotNull(p2.lookup(java.io.Serializable.class));
124.119 - Lookup.Template<String> t = new Lookup.Template<String>(String.class);
124.120 - Lookup.Result<String> r = p2.lookup(t);
124.121 - Collection<? extends String> all = r.allInstances();
124.122 - assertTrue(all.size() == 2);
124.123 - for (String o : all) {
124.124 - assertTrue("allInstances contains wrong objects", o.equals(s[0]) || o.equals(s[1]));
124.125 - }
124.126 -
124.127 - try {
124.128 - Lookups.fixed(new Object[] {null});
124.129 - fail("No nulls are allowed");
124.130 - } catch (NullPointerException ex) {
124.131 - // ok, NPE is what we want
124.132 - }
124.133 - }
124.134 -
124.135 - public void testFixedSubtypes() {
124.136 - class A {}
124.137 - class B extends A {}
124.138 - Lookup l = Lookups.fixed(new A(), new B());
124.139 - assertEquals(1, l.lookupAll(B.class).size());
124.140 - assertEquals(2, l.lookupAll(A.class).size());
124.141 - }
124.142 -
124.143 - /**
124.144 - * Simple tests testing converting lookup.
124.145 - */
124.146 - public void testConverting() {
124.147 - //
124.148 - String[] orig = new String[] { TestConvertor.TEST1, TestConvertor.TEST2 };
124.149 - TestConvertor convertor = new TestConvertor();
124.150 - Lookup p1 = Lookups.fixed(orig, convertor);
124.151 - assertNull("Converting from String to Integer - it should not find String in result", p1.lookup(String.class));
124.152 - assertNotNull(p1.lookup(Integer.class));
124.153 - assertNotNull(p1.lookup(Integer.class));
124.154 - assertTrue("Convertor should be called only once.", convertor.getNumberOfConvertCalls() == 1);
124.155 - Lookup.Template<Integer> t = new Lookup.Template<Integer>(Integer.class);
124.156 - Lookup.Result<Integer> r = p1.lookup(t);
124.157 - Collection<? extends Integer> all = r.allInstances();
124.158 - assertTrue(all.size() == 2);
124.159 - for (int i : all) {
124.160 - assertTrue("allInstances contains wrong objects", i == TestConvertor.t1 || i == TestConvertor.t2);
124.161 - }
124.162 - }
124.163 -
124.164 - private static class TestConvertor implements InstanceContent.Convertor<String,Integer> {
124.165 - static final String TEST1 = "test1";
124.166 - static final int t1 = 1;
124.167 - static final String TEST2 = "test2";
124.168 - static final int t2 = 2;
124.169 -
124.170 - private int numberOfConvertCalls = 0;
124.171 -
124.172 - public Integer convert(String obj) {
124.173 - numberOfConvertCalls++;
124.174 - if (obj.equals(TEST1)) {
124.175 - return t1;
124.176 - }
124.177 - if (obj.equals(TEST2)) {
124.178 - return t2;
124.179 - }
124.180 - throw new IllegalArgumentException();
124.181 - }
124.182 -
124.183 - public String displayName(String obj) {
124.184 - return obj;
124.185 - }
124.186 -
124.187 - public String id(String obj) {
124.188 - if (obj.equals(TEST1)) {
124.189 - return TEST1;
124.190 - }
124.191 - if (obj.equals(TEST2)) {
124.192 - return TEST2;
124.193 - }
124.194 - return null;
124.195 - }
124.196 -
124.197 - public Class<? extends Integer> type(String obj) {
124.198 - return Integer.class;
124.199 - }
124.200 -
124.201 - int getNumberOfConvertCalls() {
124.202 - return numberOfConvertCalls;
124.203 - }
124.204 - }
124.205 -
124.206 - public void testLookupItem() {
124.207 - SomeInst inst = new SomeInst();
124.208 - Lookup.Item item = Lookups.lookupItem(inst, "XYZ");
124.209 -
124.210 - assertTrue("Wrong instance", item.getInstance() == inst);
124.211 - assertTrue("Wrong instance class", item.getType() == inst.getClass());
124.212 - assertEquals("Wrong id", "XYZ", item.getId());
124.213 -
124.214 - item = Lookups.lookupItem(inst, null);
124.215 - assertNotNull("Id must never be null", item.getId());
124.216 - }
124.217 -
124.218 - public void testLookupItemEquals() {
124.219 - SomeInst instA = new SomeInst();
124.220 - SomeInst instB = new SomeInst();
124.221 - Lookup.Item itemA = Lookups.lookupItem(instA, null);
124.222 - Lookup.Item itemB = Lookups.lookupItem(instB, null);
124.223 -
124.224 - assertTrue("Lookup items shouldn't be equal", !itemA.equals(itemB) && !itemB.equals(itemA));
124.225 -
124.226 - itemA = Lookups.lookupItem(instA, null);
124.227 - itemB = Lookups.lookupItem(instA, null); // same instance
124.228 -
124.229 - assertTrue("Lookup items should be equal", itemA.equals(itemB) && itemB.equals(itemA));
124.230 - assertTrue("Lookup items hashcode should be same", itemA.hashCode() == itemB.hashCode());
124.231 -
124.232 - itemA = Lookups.lookupItem(new String("VOKURKA"), null);
124.233 - itemB = Lookups.lookupItem(new String("VOKURKA"), null);
124.234 -
124.235 - assertTrue("Lookup items shouldn't be equal (2)", !itemA.equals(itemB) && !itemB.equals(itemA));
124.236 - }
124.237 -
124.238 - public void testAllClassesIssue42399 () throws Exception {
124.239 - Object[] arr = { "Ahoj", new Object () };
124.240 -
124.241 - Lookup l = Lookups.fixed (arr);
124.242 -
124.243 - Set<Class<? extends Object>> s = l.lookup(new Lookup.Template<Object>(Object.class)).allClasses();
124.244 -
124.245 - assertEquals ("Two there", 2, s.size ());
124.246 - assertTrue ("Contains Object.class", s.contains (Object.class));
124.247 - assertTrue ("Contains string", s.contains (String.class));
124.248 -
124.249 - }
124.250 -
124.251 - public void testLookupItemEarlyInitializationProblem() {
124.252 - InstanceContent ic = new InstanceContent();
124.253 - AbstractLookup al = new AbstractLookup(ic);
124.254 - LI item = new LI();
124.255 - List<AbstractLookup.Pair> pairs1 = new ArrayList<AbstractLookup.Pair>();
124.256 - List<AbstractLookup.Pair> pairs2 = new ArrayList<AbstractLookup.Pair>();
124.257 -
124.258 - assertEquals("Item's instance shouldn't be requested", 0, item.cnt);
124.259 -
124.260 - pairs1.add(new ItemPair<Object>(Lookups.<Object>lookupItem(new SomeInst(), null)));
124.261 - pairs1.add(new ItemPair<Object>(item));
124.262 - pairs1.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
124.263 -
124.264 - pairs2.add(new ItemPair<Object>(item));
124.265 - pairs2.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
124.266 -
124.267 - ic.setPairs(pairs1);
124.268 - ic.setPairs(pairs2);
124.269 -
124.270 - assertEquals("Item's instance shouldn't be requested when added to lookup", 0, item.cnt);
124.271 -
124.272 - LI item2 = al.lookup(LI.class);
124.273 - assertEquals("Item's instance should be requested", 1, item.cnt);
124.274 - }
124.275 -
124.276 - public void testConvenienceMethods() throws Exception {
124.277 - // Just check signatures and basic behavior of #73848.
124.278 - Lookup l = Lookups.fixed(new Object[] {1, "hello", 2, "goodbye"});
124.279 - Collection<? extends Integer> ints = l.lookupAll(Integer.class);
124.280 - assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
124.281 - Lookup.Result<Integer> r = l.lookupResult(Integer.class);
124.282 - ints = r.allInstances();
124.283 - assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
124.284 - }
124.285 -
124.286 - private static class SomeInst { }
124.287 -
124.288 - private static class LI extends Lookup.Item<Object> {
124.289 -
124.290 - public long cnt = 0;
124.291 -
124.292 - public String getDisplayName() {
124.293 - return getId();
124.294 - }
124.295 -
124.296 - public String getId() {
124.297 - return getClass() + "@" + hashCode();
124.298 - }
124.299 -
124.300 - public Object getInstance() {
124.301 - cnt++;
124.302 - return this;
124.303 - }
124.304 -
124.305 - public Class<? extends Object> getType() {
124.306 - return getClass();
124.307 - }
124.308 - } // End of LI class
124.309 -
124.310 - private static class ItemPair<T> extends AbstractLookup.Pair<T> {
124.311 -
124.312 - private AbstractLookup.Item<T> item;
124.313 -
124.314 - public ItemPair(Lookup.Item<T> i) {
124.315 - this.item = i;
124.316 - }
124.317 -
124.318 - protected boolean creatorOf(Object obj) {
124.319 - return item.getInstance() == obj;
124.320 - }
124.321 -
124.322 - public String getDisplayName() {
124.323 - return item.getDisplayName ();
124.324 - }
124.325 -
124.326 - public String getId() {
124.327 - return item.getId ();
124.328 - }
124.329 -
124.330 - public T getInstance() {
124.331 - return item.getInstance ();
124.332 - }
124.333 -
124.334 - public Class<? extends T> getType() {
124.335 - return item.getType ();
124.336 - }
124.337 -
124.338 - protected boolean instanceOf(Class<?> c) {
124.339 - return c.isAssignableFrom(getType());
124.340 - }
124.341 -
124.342 - public @Override boolean equals(Object o) {
124.343 - if (o instanceof ItemPair) {
124.344 - ItemPair p = (ItemPair)o;
124.345 - return item.equals (p.item);
124.346 - }
124.347 - return false;
124.348 - }
124.349 -
124.350 - public @Override int hashCode() {
124.351 - return item.hashCode ();
124.352 - }
124.353 - } // end of ItemPair
124.354 -}
125.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleProxyLookupIssue42244Test.java Sat Oct 31 15:06:58 2009 +0100
125.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
125.3 @@ -1,120 +0,0 @@
125.4 -/*
125.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
125.6 - *
125.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
125.8 - *
125.9 - * The contents of this file are subject to the terms of either the GNU
125.10 - * General Public License Version 2 only ("GPL") or the Common
125.11 - * Development and Distribution License("CDDL") (collectively, the
125.12 - * "License"). You may not use this file except in compliance with the
125.13 - * License. You can obtain a copy of the License at
125.14 - * http://www.netbeans.org/cddl-gplv2.html
125.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
125.16 - * specific language governing permissions and limitations under the
125.17 - * License. When distributing the software, include this License Header
125.18 - * Notice in each file and include the License file at
125.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
125.20 - * particular file as subject to the "Classpath" exception as provided
125.21 - * by Sun in the GPL Version 2 section of the License file that
125.22 - * accompanied this code. If applicable, add the following below the
125.23 - * License Header, with the fields enclosed by brackets [] replaced by
125.24 - * your own identifying information:
125.25 - * "Portions Copyrighted [year] [name of copyright owner]"
125.26 - *
125.27 - * Contributor(s):
125.28 - *
125.29 - * The Original Software is NetBeans. The Initial Developer of the Original
125.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
125.31 - * Microsystems, Inc. All Rights Reserved.
125.32 - *
125.33 - * If you wish your version of this file to be governed by only the CDDL
125.34 - * or only the GPL Version 2, indicate your decision by adding
125.35 - * "[Contributor] elects to include this software in this distribution
125.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
125.37 - * single choice of license, a recipient has the option to distribute
125.38 - * your version of this file under either the CDDL, the GPL Version 2 or
125.39 - * to extend the choice of license to its licensees as provided above.
125.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
125.41 - * Version 2 license, then the option applies only if the new code is
125.42 - * made subject to such option by the copyright holder.
125.43 - */
125.44 -
125.45 -package org.openide.util.lookup;
125.46 -
125.47 -import java.lang.ref.WeakReference;
125.48 -import java.util.*;
125.49 -import junit.framework.*;
125.50 -import org.netbeans.junit.*;
125.51 -import org.openide.util.Lookup;
125.52 -
125.53 -/** To simulate issue 42244.
125.54 - */
125.55 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
125.56 -public class SimpleProxyLookupIssue42244Test extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
125.57 - public SimpleProxyLookupIssue42244Test (java.lang.String testName) {
125.58 - super(testName, null);
125.59 - }
125.60 -
125.61 - public static Test suite() {
125.62 - // return new SimpleProxyLookupIssue42244Test("testGarbageCollect");
125.63 - return new NbTestSuite(SimpleProxyLookupIssue42244Test.class);
125.64 - }
125.65 -
125.66 - /** Creates an lookup for given lookup. This class just returns
125.67 - * the object passed in, but subclasses can be different.
125.68 - * @param lookup in lookup
125.69 - * @return a lookup to use
125.70 - */
125.71 - public Lookup createLookup (final Lookup lookup) {
125.72 - class C implements Lookup.Provider {
125.73 - public Lookup getLookup () {
125.74 - return lookup;
125.75 - }
125.76 - }
125.77 - return Lookups.proxy (new C ());
125.78 - }
125.79 -
125.80 - public Lookup createInstancesLookup (InstanceContent ic) {
125.81 - return new KeepResultsProxyLookup (new AbstractLookup (ic));
125.82 - }
125.83 -
125.84 - public void clearCaches () {
125.85 - KeepResultsProxyLookup k = (KeepResultsProxyLookup)this.instanceLookup;
125.86 -
125.87 - ArrayList toGC = new ArrayList ();
125.88 - Iterator it = k.allQueries.iterator ();
125.89 - while (it.hasNext ()) {
125.90 - Lookup.Result r = (Lookup.Result)it.next ();
125.91 - toGC.add (new WeakReference (r));
125.92 - }
125.93 -
125.94 - k.allQueries = null;
125.95 -
125.96 - it = toGC.iterator ();
125.97 - while (it.hasNext ()) {
125.98 - WeakReference r = (WeakReference)it.next ();
125.99 - assertGC ("Trying to release all results from memory", r);
125.100 - }
125.101 - }
125.102 -
125.103 - class KeepResultsProxyLookup extends ProxyLookup {
125.104 - private ArrayList allQueries = new ArrayList ();
125.105 - private ThreadLocal in = new ThreadLocal ();
125.106 -
125.107 - public KeepResultsProxyLookup (Lookup delegate) {
125.108 - super (new Lookup[] { delegate });
125.109 - }
125.110 -
125.111 - @Override
125.112 - protected void beforeLookup (org.openide.util.Lookup.Template template) {
125.113 - super.beforeLookup (template);
125.114 - if (allQueries != null && in.get () == null) {
125.115 - in.set (this);
125.116 - Lookup.Result res = lookup (template);
125.117 - allQueries.add (res);
125.118 - in.set (null);
125.119 - }
125.120 - }
125.121 -
125.122 - }
125.123 -}
126.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleProxyLookupSpeedIssue42244Test.java Sat Oct 31 15:06:58 2009 +0100
126.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
126.3 @@ -1,118 +0,0 @@
126.4 -/*
126.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
126.6 - *
126.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
126.8 - *
126.9 - * The contents of this file are subject to the terms of either the GNU
126.10 - * General Public License Version 2 only ("GPL") or the Common
126.11 - * Development and Distribution License("CDDL") (collectively, the
126.12 - * "License"). You may not use this file except in compliance with the
126.13 - * License. You can obtain a copy of the License at
126.14 - * http://www.netbeans.org/cddl-gplv2.html
126.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
126.16 - * specific language governing permissions and limitations under the
126.17 - * License. When distributing the software, include this License Header
126.18 - * Notice in each file and include the License file at
126.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
126.20 - * particular file as subject to the "Classpath" exception as provided
126.21 - * by Sun in the GPL Version 2 section of the License file that
126.22 - * accompanied this code. If applicable, add the following below the
126.23 - * License Header, with the fields enclosed by brackets [] replaced by
126.24 - * your own identifying information:
126.25 - * "Portions Copyrighted [year] [name of copyright owner]"
126.26 - *
126.27 - * Contributor(s):
126.28 - *
126.29 - * The Original Software is NetBeans. The Initial Developer of the Original
126.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
126.31 - * Microsystems, Inc. All Rights Reserved.
126.32 - *
126.33 - * If you wish your version of this file to be governed by only the CDDL
126.34 - * or only the GPL Version 2, indicate your decision by adding
126.35 - * "[Contributor] elects to include this software in this distribution
126.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
126.37 - * single choice of license, a recipient has the option to distribute
126.38 - * your version of this file under either the CDDL, the GPL Version 2 or
126.39 - * to extend the choice of license to its licensees as provided above.
126.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
126.41 - * Version 2 license, then the option applies only if the new code is
126.42 - * made subject to such option by the copyright holder.
126.43 - */
126.44 -
126.45 -package org.openide.util.lookup;
126.46 -
126.47 -import java.util.HashSet;
126.48 -import java.util.Set;
126.49 -import org.netbeans.junit.NbTestCase;
126.50 -
126.51 -import org.netbeans.junit.RandomlyFails;
126.52 -import org.openide.util.Lookup;
126.53 -
126.54 -/**
126.55 - * @author Petr Nejedly, adapted to test by Jaroslav Tulach
126.56 - */
126.57 -@RandomlyFails // NB-Core-Build #1847
126.58 -public class SimpleProxyLookupSpeedIssue42244Test extends NbTestCase {
126.59 -
126.60 - public SimpleProxyLookupSpeedIssue42244Test (String name) {
126.61 - super (name);
126.62 - }
126.63 -
126.64 - public void testCompareTheSpeed () {
126.65 - String content1 = "String1";
126.66 - String content2 = "String2";
126.67 -
126.68 - Lookup fixed1 = Lookups.singleton(content1);
126.69 - Lookup fixed2 = Lookups.singleton(content2);
126.70 -
126.71 - MyProvider provider = new MyProvider();
126.72 - provider.setLookup(fixed1);
126.73 -
126.74 - Lookup top = Lookups.proxy(provider);
126.75 -
126.76 - Lookup.Result<String> r0 = top.lookupResult(String.class);
126.77 - r0.allInstances();
126.78 -
126.79 - long time = System.currentTimeMillis();
126.80 - top.lookupAll(String.class);
126.81 - long withOneResult = System.currentTimeMillis() - time;
126.82 -
126.83 -
126.84 - Set<Object> results = new HashSet<Object>();
126.85 - for (int i=0; i<10000; i++) {
126.86 - Lookup.Result<String> res = top.lookupResult(String.class);
126.87 - results.add (res);
126.88 - res.allInstances();
126.89 - }
126.90 -
126.91 - provider.setLookup(fixed2);
126.92 -
126.93 - time = System.currentTimeMillis();
126.94 - top.lookupAll(String.class);
126.95 - long withManyResults = System.currentTimeMillis() - time;
126.96 -
126.97 - // if the measurement takes less then 10ms, pretend 10ms
126.98 - if (withManyResults < 10) {
126.99 - withManyResults = 10;
126.100 - }
126.101 - if (withOneResult < 10) {
126.102 - withOneResult = 10;
126.103 - }
126.104 -
126.105 - if (withManyResults >= 10 * withOneResult) {
126.106 - fail ("With many results the test runs too long.\n With many: " + withManyResults + "\n With one : " + withOneResult);
126.107 - }
126.108 - }
126.109 -
126.110 - private static class MyProvider implements Lookup.Provider {
126.111 - private Lookup lookup;
126.112 - public Lookup getLookup() {
126.113 - return lookup;
126.114 - }
126.115 -
126.116 - void setLookup(Lookup lookup) {
126.117 - this.lookup = lookup;
126.118 - }
126.119 - }
126.120 -
126.121 -}
127.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleProxyLookupTest.java Sat Oct 31 15:06:58 2009 +0100
127.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
127.3 @@ -1,73 +0,0 @@
127.4 -/*
127.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
127.6 - *
127.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
127.8 - *
127.9 - * The contents of this file are subject to the terms of either the GNU
127.10 - * General Public License Version 2 only ("GPL") or the Common
127.11 - * Development and Distribution License("CDDL") (collectively, the
127.12 - * "License"). You may not use this file except in compliance with the
127.13 - * License. You can obtain a copy of the License at
127.14 - * http://www.netbeans.org/cddl-gplv2.html
127.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
127.16 - * specific language governing permissions and limitations under the
127.17 - * License. When distributing the software, include this License Header
127.18 - * Notice in each file and include the License file at
127.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
127.20 - * particular file as subject to the "Classpath" exception as provided
127.21 - * by Sun in the GPL Version 2 section of the License file that
127.22 - * accompanied this code. If applicable, add the following below the
127.23 - * License Header, with the fields enclosed by brackets [] replaced by
127.24 - * your own identifying information:
127.25 - * "Portions Copyrighted [year] [name of copyright owner]"
127.26 - *
127.27 - * Contributor(s):
127.28 - *
127.29 - * The Original Software is NetBeans. The Initial Developer of the Original
127.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
127.31 - * Microsystems, Inc. All Rights Reserved.
127.32 - *
127.33 - * If you wish your version of this file to be governed by only the CDDL
127.34 - * or only the GPL Version 2, indicate your decision by adding
127.35 - * "[Contributor] elects to include this software in this distribution
127.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
127.37 - * single choice of license, a recipient has the option to distribute
127.38 - * your version of this file under either the CDDL, the GPL Version 2 or
127.39 - * to extend the choice of license to its licensees as provided above.
127.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
127.41 - * Version 2 license, then the option applies only if the new code is
127.42 - * made subject to such option by the copyright holder.
127.43 - */
127.44 -
127.45 -package org.openide.util.lookup;
127.46 -
127.47 -import java.lang.ref.WeakReference;
127.48 -import org.netbeans.junit.NbTestCase;
127.49 -import org.openide.util.Lookup;
127.50 -import org.openide.util.Lookup.Provider;
127.51 -
127.52 -/**
127.53 - *
127.54 - * @author Jan Lahoda
127.55 - */
127.56 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
127.57 -public class SimpleProxyLookupTest extends NbTestCase {
127.58 -
127.59 - public SimpleProxyLookupTest(String testName) {
127.60 - super(testName);
127.61 - }
127.62 -
127.63 - public void test69810() throws Exception {
127.64 - Lookup.Template t = new Lookup.Template(String.class);
127.65 - SimpleProxyLookup spl = new SimpleProxyLookup(new Provider() {
127.66 - public Lookup getLookup() {
127.67 - return Lookups.fixed(new Object[] {"test1", "test2"});
127.68 - }
127.69 - });
127.70 -
127.71 - assertGC("", new WeakReference(spl.lookup(t)));
127.72 -
127.73 - spl.lookup(new Lookup.Template(Object.class)).allInstances();
127.74 - }
127.75 -
127.76 -}
128.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SingletonLookupTest.java Sat Oct 31 15:06:58 2009 +0100
128.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
128.3 @@ -1,113 +0,0 @@
128.4 -/*
128.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
128.6 - *
128.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
128.8 - *
128.9 - * The contents of this file are subject to the terms of either the GNU
128.10 - * General Public License Version 2 only ("GPL") or the Common
128.11 - * Development and Distribution License("CDDL") (collectively, the
128.12 - * "License"). You may not use this file except in compliance with the
128.13 - * License. You can obtain a copy of the License at
128.14 - * http://www.netbeans.org/cddl-gplv2.html
128.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
128.16 - * specific language governing permissions and limitations under the
128.17 - * License. When distributing the software, include this License Header
128.18 - * Notice in each file and include the License file at
128.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
128.20 - * particular file as subject to the "Classpath" exception as provided
128.21 - * by Sun in the GPL Version 2 section of the License file that
128.22 - * accompanied this code. If applicable, add the following below the
128.23 - * License Header, with the fields enclosed by brackets [] replaced by
128.24 - * your own identifying information:
128.25 - * "Portions Copyrighted [year] [name of copyright owner]"
128.26 - *
128.27 - * If you wish your version of this file to be governed by only the CDDL
128.28 - * or only the GPL Version 2, indicate your decision by adding
128.29 - * "[Contributor] elects to include this software in this distribution
128.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
128.31 - * single choice of license, a recipient has the option to distribute
128.32 - * your version of this file under either the CDDL, the GPL Version 2 or
128.33 - * to extend the choice of license to its licensees as provided above.
128.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
128.35 - * Version 2 license, then the option applies only if the new code is
128.36 - * made subject to such option by the copyright holder.
128.37 - *
128.38 - * Contributor(s):
128.39 - *
128.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
128.41 - */
128.42 -
128.43 -package org.openide.util.lookup;
128.44 -
128.45 -import java.util.Collection;
128.46 -import org.netbeans.junit.NbTestCase;
128.47 -import org.openide.util.Lookup;
128.48 -
128.49 -/**
128.50 - * Contains tests of class {@code SingletonLookup}.
128.51 - *
128.52 - * @author Marian Petras
128.53 - */
128.54 -public class SingletonLookupTest extends NbTestCase {
128.55 -
128.56 - public SingletonLookupTest(String testName) {
128.57 - super(testName);
128.58 - }
128.59 -
128.60 - public void testBasics() {
128.61 - Object orig = new Object();
128.62 - Lookup p1 = new SingletonLookup(orig);
128.63 - Object obj = p1.lookup(Object.class);
128.64 - assertTrue(obj == orig);
128.65 - assertNull(p1.lookup(String.class));
128.66 - assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
128.67 - //
128.68 - Lookup p2 = new SingletonLookup("test");
128.69 - assertNotNull(p2.lookup(Object.class));
128.70 - assertNotNull(p2.lookup(String.class));
128.71 - assertNotNull(p2.lookup(java.io.Serializable.class));
128.72 - }
128.73 -
128.74 - public void testId() {
128.75 - Object orig = new Object();
128.76 - Collection allInstances;
128.77 -
128.78 - Lookup l = new SingletonLookup(orig, "id");
128.79 -
128.80 - allInstances = l.lookup(new Lookup.Template<Object>(Object.class, null, null)).allInstances();
128.81 - assertNotNull(allInstances);
128.82 - assertFalse(allInstances.isEmpty());
128.83 - assertEquals(1, allInstances.size());
128.84 - assertTrue(allInstances.iterator().next() == orig);
128.85 -
128.86 - allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "id", null)).allInstances();
128.87 - assertNotNull(allInstances);
128.88 - assertFalse(allInstances.isEmpty());
128.89 - assertEquals(1, allInstances.size());
128.90 - assertTrue(allInstances.iterator().next() == orig);
128.91 -
128.92 - allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "not", null)).allInstances();
128.93 - assertNotNull(allInstances);
128.94 - assertTrue(allInstances.isEmpty());
128.95 -
128.96 - allInstances = l.lookup(new Lookup.Template<String>(String.class, null, null)).allInstances();
128.97 - assertNotNull(allInstances);
128.98 - assertTrue(allInstances.isEmpty());
128.99 -
128.100 - allInstances = l.lookup(new Lookup.Template<String>(String.class, "id", null)).allInstances();
128.101 - assertNotNull(allInstances);
128.102 - assertTrue(allInstances.isEmpty());
128.103 -
128.104 - allInstances = l.lookup(new Lookup.Template<String>(String.class, "not", null)).allInstances();
128.105 - assertNotNull(allInstances);
128.106 - assertTrue(allInstances.isEmpty());
128.107 - }
128.108 -
128.109 - public void testSize() {
128.110 - final Object obj = new Object();
128.111 - assertSize("The singleton lookup instance should be small",
128.112 - 24,
128.113 - new SingletonLookup(obj));
128.114 - }
128.115 -
128.116 -}
129.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/problem100320.txt Sat Oct 31 15:06:58 2009 +0100
129.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
129.3 @@ -1,17 +0,0 @@
129.4 -:java.io.IOException:
129.5 -java.nio.charset.CharacterCodingException
129.6 -java.io.EOFException
129.7 -java.io.FileNotFoundException
129.8 -java.io.InterruptedIOException
129.9 -java.net.MalformedURLException
129.10 -java.io.IOException
129.11 -java.io.UnsupportedEncodingException
129.12 -java.io.NotActiveException
129.13 -java.io.StreamCorruptedException
129.14 -java.io.UTFDataFormatException
129.15 -java.util.zip.ZipException
129.16 -java.util.jar.JarException
129.17 -:java.util.Comparator:
129.18 -org.bar.Comparator3
129.19 -org.bar.Comparator2
129.20 -#position=5
130.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/services-jar-1.txt Sat Oct 31 15:06:58 2009 +0100
130.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
130.3 @@ -1,17 +0,0 @@
130.4 -:somedummyfile:
130.5 -org.foo.Interface
130.6 -:java.lang.Runnable:
130.7 -org.foo.impl.Runnable1
130.8 -:java.util.Comparator:
130.9 -#some comment
130.10 -org.foo.impl.Comparator1
130.11 -#position=10
130.12 -#som comment2
130.13 -:java.util.Iterator:
130.14 -org.foo.impl.Iterator1
130.15 -:org.foo.Interface:
130.16 -# Some header info, maybe.
130.17 -
130.18 -# Our first impl here
130.19 -org.foo.impl.Implementation1
130.20 -
131.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/services-jar-2.txt Sat Oct 31 15:06:58 2009 +0100
131.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
131.3 @@ -1,10 +0,0 @@
131.4 -:java.lang.Runnable:
131.5 -#-org.foo.impl.Runnable1
131.6 -:java.util.Comparator:
131.7 -org.bar.Comparator2
131.8 -#position=5
131.9 -:java.util.Iterator:
131.10 -org.bar.Iterator2
131.11 -#position=100
131.12 -:org.foo.Interface:
131.13 -org.bar.Implementation2
132.1 --- a/openide.util/test/unit/src/org/openide/util/test/MockLookup.java Sat Oct 31 15:06:58 2009 +0100
132.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
132.3 @@ -1,135 +0,0 @@
132.4 -/*
132.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
132.6 - *
132.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
132.8 - *
132.9 - * The contents of this file are subject to the terms of either the GNU
132.10 - * General Public License Version 2 only ("GPL") or the Common
132.11 - * Development and Distribution License("CDDL") (collectively, the
132.12 - * "License"). You may not use this file except in compliance with the
132.13 - * License. You can obtain a copy of the License at
132.14 - * http://www.netbeans.org/cddl-gplv2.html
132.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
132.16 - * specific language governing permissions and limitations under the
132.17 - * License. When distributing the software, include this License Header
132.18 - * Notice in each file and include the License file at
132.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
132.20 - * particular file as subject to the "Classpath" exception as provided
132.21 - * by Sun in the GPL Version 2 section of the License file that
132.22 - * accompanied this code. If applicable, add the following below the
132.23 - * License Header, with the fields enclosed by brackets [] replaced by
132.24 - * your own identifying information:
132.25 - * "Portions Copyrighted [year] [name of copyright owner]"
132.26 - *
132.27 - * Contributor(s):
132.28 - *
132.29 - * The Original Software is NetBeans. The Initial Developer of the Original
132.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
132.31 - * Microsystems, Inc. All Rights Reserved.
132.32 - *
132.33 - * If you wish your version of this file to be governed by only the CDDL
132.34 - * or only the GPL Version 2, indicate your decision by adding
132.35 - * "[Contributor] elects to include this software in this distribution
132.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
132.37 - * single choice of license, a recipient has the option to distribute
132.38 - * your version of this file under either the CDDL, the GPL Version 2 or
132.39 - * to extend the choice of license to its licensees as provided above.
132.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
132.41 - * Version 2 license, then the option applies only if the new code is
132.42 - * made subject to such option by the copyright holder.
132.43 - */
132.44 -
132.45 -package org.openide.util.test;
132.46 -
132.47 -import java.lang.reflect.Field;
132.48 -import java.util.Collection;
132.49 -import static junit.framework.Assert.*;
132.50 -import org.openide.util.Lookup;
132.51 -import org.openide.util.lookup.Lookups;
132.52 -import org.openide.util.lookup.ProxyLookup;
132.53 -
132.54 -/**
132.55 - * Mock implementation of system default lookup suitable for use in unit tests.
132.56 - * The initial value just contains classpath services.
132.57 - */
132.58 -public class MockLookup extends ProxyLookup {
132.59 -
132.60 - private static MockLookup DEFAULT;
132.61 - private static boolean making = false;
132.62 - private static volatile boolean ready;
132.63 -
132.64 - static {
132.65 - making = true;
132.66 - try {
132.67 - System.setProperty("org.openide.util.Lookup", MockLookup.class.getName());
132.68 - if (Lookup.getDefault().getClass() != MockLookup.class) {
132.69 - // Someone else initialized lookup first. Try to force our way.
132.70 - Field defaultLookup = Lookup.class.getDeclaredField("defaultLookup");
132.71 - defaultLookup.setAccessible(true);
132.72 - defaultLookup.set(null, null);
132.73 - }
132.74 - assertEquals(MockLookup.class, Lookup.getDefault().getClass());
132.75 - } catch (Exception x) {
132.76 - throw new ExceptionInInitializerError(x);
132.77 - } finally {
132.78 - making = false;
132.79 - }
132.80 - }
132.81 -
132.82 - /** Do not call this directly! */
132.83 - public MockLookup() {
132.84 - assertTrue(making);
132.85 - assertNull(DEFAULT);
132.86 - DEFAULT = this;
132.87 - }
132.88 -
132.89 - /**
132.90 - * Just ensures that this lookup is default lookup, but does not actually change its content.
132.91 - * Useful mainly if you have some test utility method which calls foreign code which might use default lookup,
132.92 - * and you want to ensure that any users of mock lookup will see the correct default lookup right away,
132.93 - * even if they have not yet called {@link #setLookup} or {@link #setInstances}.
132.94 - */
132.95 - public static void init() {
132.96 - if (!ready) {
132.97 - setInstances();
132.98 - }
132.99 - }
132.100 -
132.101 - /**
132.102 - * Sets the global default lookup with zero or more delegate lookups.
132.103 - * Caution: if you don't include Lookups.metaInfServices, you may have trouble,
132.104 - * e.g. {@link #makeScratchDir} will not work.
132.105 - * Most of the time you should use {@link #setInstances} instead.
132.106 - */
132.107 - public static void setLookup(Lookup... lookups) {
132.108 - ready = true;
132.109 - DEFAULT.setLookups(lookups);
132.110 - }
132.111 -
132.112 - /**
132.113 - * Sets the global default lookup with some fixed instances.
132.114 - * Will also include (at a lower priority) a {@link ClassLoader},
132.115 - * and services found from <code>META-INF/services/*</code> in the classpath.
132.116 - */
132.117 - public static void setInstances(Object... instances) {
132.118 - ClassLoader l = MockLookup.class.getClassLoader();
132.119 - setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
132.120 - }
132.121 - /**
132.122 - * Sets the global default lookup with some fixed instances and
132.123 - * content read from Services folder from system file system.
132.124 - * Will also include (at a lower priority) a {@link ClassLoader},
132.125 - * and services found from <code>META-INF/services/*</code> in the classpath.
132.126 - */
132.127 - public static void setLayersAndInstances(Object... instances) {
132.128 - ClassLoader l = MockLookup.class.getClassLoader();
132.129 - if (l != Lookup.getDefault().lookup(ClassLoader.class)) {
132.130 - setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
132.131 - }
132.132 - Lookup projects = Lookups.forPath("Services");
132.133 - Collection<?> initialize = projects.lookupAll(Object.class);
132.134 - //System.err.println("all: " + initialize);
132.135 - setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l), projects);
132.136 - }
132.137 -
132.138 -}
133.1 --- a/openide.util/test/unit/src/org/openide/util/test/MockLookupTest.java Sat Oct 31 15:06:58 2009 +0100
133.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
133.3 @@ -1,66 +0,0 @@
133.4 -/*
133.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
133.6 - *
133.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
133.8 - *
133.9 - * The contents of this file are subject to the terms of either the GNU
133.10 - * General Public License Version 2 only ("GPL") or the Common
133.11 - * Development and Distribution License("CDDL") (collectively, the
133.12 - * "License"). You may not use this file except in compliance with the
133.13 - * License. You can obtain a copy of the License at
133.14 - * http://www.netbeans.org/cddl-gplv2.html
133.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
133.16 - * specific language governing permissions and limitations under the
133.17 - * License. When distributing the software, include this License Header
133.18 - * Notice in each file and include the License file at
133.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
133.20 - * particular file as subject to the "Classpath" exception as provided
133.21 - * by Sun in the GPL Version 2 section of the License file that
133.22 - * accompanied this code. If applicable, add the following below the
133.23 - * License Header, with the fields enclosed by brackets [] replaced by
133.24 - * your own identifying information:
133.25 - * "Portions Copyrighted [year] [name of copyright owner]"
133.26 - *
133.27 - * Contributor(s):
133.28 - *
133.29 - * The Original Software is NetBeans. The Initial Developer of the Original
133.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
133.31 - * Microsystems, Inc. All Rights Reserved.
133.32 - *
133.33 - * If you wish your version of this file to be governed by only the CDDL
133.34 - * or only the GPL Version 2, indicate your decision by adding
133.35 - * "[Contributor] elects to include this software in this distribution
133.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
133.37 - * single choice of license, a recipient has the option to distribute
133.38 - * your version of this file under either the CDDL, the GPL Version 2 or
133.39 - * to extend the choice of license to its licensees as provided above.
133.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
133.41 - * Version 2 license, then the option applies only if the new code is
133.42 - * made subject to such option by the copyright holder.
133.43 - */
133.44 -
133.45 -package org.openide.util.test;
133.46 -
133.47 -import junit.framework.TestCase;
133.48 -import org.openide.util.Lookup;
133.49 -
133.50 -public class MockLookupTest extends TestCase {
133.51 -
133.52 - // XXX test:
133.53 - // setLookup with one or more lookup args does not use M-I/s
133.54 - // still works if another Lookup.getDefault was set before
133.55 -
133.56 - public MockLookupTest(String n) {
133.57 - super(n);
133.58 - }
133.59 -
133.60 - public void testSetLookup() throws Exception {
133.61 - MockLookup.setInstances("hello");
133.62 - assertEquals("initial lookup works", "hello", Lookup.getDefault().lookup(String.class));
133.63 - MockLookup.setInstances("goodbye");
133.64 - assertEquals("modified lookup works", "goodbye", Lookup.getDefault().lookup(String.class));
133.65 - MockLookup.setInstances();
133.66 - assertEquals("cleared lookup works", null, Lookup.getDefault().lookup(String.class));
133.67 - }
133.68 -
133.69 -}