1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/openide.util.lookup/apichanges.xml Mon Dec 14 20:58:39 2009 +0100
1.3 @@ -0,0 +1,448 @@
1.4 +<?xml version="1.0" encoding="UTF-8"?>
1.5 +<!--
1.6 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
1.7 +
1.8 +Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
1.9 +
1.10 +
1.11 +The contents of this file are subject to the terms of either the GNU
1.12 +General Public License Version 2 only ("GPL") or the Common
1.13 +Development and Distribution License("CDDL") (collectively, the
1.14 +"License"). You may not use this file except in compliance with the
1.15 +License. You can obtain a copy of the License at
1.16 +http://www.netbeans.org/cddl-gplv2.html
1.17 +or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
1.18 +specific language governing permissions and limitations under the
1.19 +License. When distributing the software, include this License Header
1.20 +Notice in each file and include the License file at
1.21 +nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
1.22 +particular file as subject to the "Classpath" exception as provided
1.23 +by Sun in the GPL Version 2 section of the License file that
1.24 +accompanied this code. If applicable, add the following below the
1.25 +License Header, with the fields enclosed by brackets [] replaced by
1.26 +your own identifying information:
1.27 +"Portions Copyrighted [year] [name of copyright owner]"
1.28 +
1.29 +Contributor(s):
1.30 +
1.31 +The Original Software is NetBeans. The Initial Developer of the Original
1.32 +Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
1.33 +Microsystems, Inc. All Rights Reserved.
1.34 +
1.35 +If you wish your version of this file to be governed by only the CDDL
1.36 +or only the GPL Version 2, indicate your decision by adding
1.37 +"[Contributor] elects to include this software in this distribution
1.38 +under the [CDDL or GPL Version 2] license." If you do not indicate a
1.39 +single choice of license, a recipient has the option to distribute
1.40 +your version of this file under either the CDDL, the GPL Version 2 or
1.41 +to extend the choice of license to its licensees as provided above.
1.42 +However, if you add GPL Version 2 code and therefore, elected the GPL
1.43 +Version 2 license, then the option applies only if the new code is
1.44 +made subject to such option by the copyright holder.
1.45 +-->
1.46 +<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../nbbuild/javadoctools/apichanges.dtd">
1.47 +<apichanges>
1.48 +<apidefs>
1.49 + <apidef name="lookup">Lookup API</apidef>
1.50 +</apidefs>
1.51 +<changes>
1.52 + <change id="org.openide.util.Lookup.paths">
1.53 + <api name="lookup"/>
1.54 + <summary>Added
1.55 + <code>org.openide.util.Lookup.paths</code> property
1.56 + </summary>
1.57 + <version major="7" minor="24"/>
1.58 + <date day="19" month="6" year="2009"/>
1.59 + <author login="jtulach"/>
1.60 + <compatibility addition="yes"/>
1.61 + <description>
1.62 + <p>
1.63 + Better way to integrate Lookup.getDefault() and system filesystem.
1.64 + </p>
1.65 + </description>
1.66 + <class package="org.openide.util" name="Lookup"/>
1.67 + <issue number="166782"/>
1.68 + </change>
1.69 + <change id="ServiceProvider">
1.70 + <api name="lookup"/>
1.71 + <summary>Added <code>ServiceProvider</code> annotation</summary>
1.72 + <version major="7" minor="20"/>
1.73 + <date day="1" month="11" year="2008"/>
1.74 + <author login="jglick"/>
1.75 + <compatibility addition="yes">
1.76 + <p>
1.77 + Modules registering services using <code>META-INF/services</code>
1.78 + files in the source tree are encouraged to switch to the annotation.
1.79 + </p>
1.80 + </compatibility>
1.81 + <description>
1.82 + <p>
1.83 + Added annotations <code>ServiceProvider</code> and <code>ServiceProviders</code>
1.84 + to simplify registration of global singleton services.
1.85 + </p>
1.86 + </description>
1.87 + <class package="org.openide.util.lookup" name="ServiceProvider"/>
1.88 + <class package="org.openide.util.lookup" name="ServiceProviders"/>
1.89 + <issue number="150447"/>
1.90 + </change>
1.91 + <change id="Lookup.asynchronous">
1.92 + <api name="lookup"/>
1.93 + <summary>AbstractLookup and ProxyLookup fire changes asynchronously</summary>
1.94 + <version major="7" minor="16"/>
1.95 + <date day="27" month="6" year="2008"/>
1.96 + <author login="jtulach"/>
1.97 + <compatibility addition="yes" binary="compatible" semantic="compatible"/>
1.98 + <description>
1.99 + <p>
1.100 + All modification methods in <code>AbstractLookup</code> and <code>ProxyLookup</code>
1.101 + were extended to accept an
1.102 + <a href="@JDK@/java/util/concurrent/Executor.html">Executor</a>.
1.103 + If not null, it is used to dispatch events to listeners sometime
1.104 + "later". Also the <code>AbstractLookup.Content</code>
1.105 + and <code>InstanceContent</code> constructors
1.106 + have been extended to accept such <code>Executor</code>s.
1.107 + </p>
1.108 + </description>
1.109 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.110 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.111 + <class package="org.openide.util.lookup" name="InstanceContent"/>
1.112 + <issue number="134297"/>
1.113 + </change>
1.114 +
1.115 + <change id="Lookups.forPath">
1.116 + <api name="lookup"/>
1.117 + <summary>Added simplified support for named lookups <code>Lookups.forPath</code></summary>
1.118 + <version major="7" minor="9"/>
1.119 + <date day="17" month="4" year="2007"/>
1.120 + <author login="jtulach"/>
1.121 + <compatibility addition="yes"/>
1.122 + <description>
1.123 + <p>
1.124 + New method <a href="@TOP@/org/openide/util/lookup/Lookups.html#forPath(java.lang.String)">Lookups.forPath(String)</a>
1.125 + has been added to replace now deprecated <a href="@org-openide-loaders@/org/openide/loaders/FolderLookup.html">FolderLookup</a>
1.126 + and allow modules who wants to read settings from layers
1.127 + to do so with a simpler code, without dependency on DataSystems API.
1.128 + </p>
1.129 + </description>
1.130 + <class package="org.openide.util.lookup" name="Lookups"/>
1.131 + <issue number="98426"/>
1.132 + </change>
1.133 +
1.134 + <change id="lookupAll-lookupResult">
1.135 + <api name="lookup"/>
1.136 + <summary>Convenience methods added to <code>Lookup</code></summary>
1.137 + <version major="6" minor="10"/>
1.138 + <date day="3" month="4" year="2006"/>
1.139 + <author login="jglick"/>
1.140 + <compatibility addition="yes" binary="compatible" source="incompatible">
1.141 + <p>
1.142 + Could conceivably conflict with existing subclass method with same signature
1.143 + with different semantics or return type.
1.144 + </p>
1.145 + </compatibility>
1.146 + <description>
1.147 + <p>
1.148 + Two methods, <code>lookupResult</code> and <code>lookupAll</code>, were
1.149 + added to <code>Lookup</code> to encapsulate the most common usage patterns
1.150 + with less typing, and more importantly avoiding the need to explicitly
1.151 + make a <code>Lookup.Template</code> object.
1.152 + </p>
1.153 + </description>
1.154 + <class package="org.openide.util" name="Lookup"/>
1.155 + <issue number="73848"/>
1.156 + </change>
1.157 + <change id="less-events-from-proxylookup" >
1.158 + <api name="lookup"/>
1.159 + <summary>Less change notifications from ProxyLookup</summary>
1.160 + <version major="6" minor="7"/>
1.161 + <date day="11" month="11" year="2005"/>
1.162 + <author login="jtulach"/>
1.163 + <compatibility addition="no" modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no"/>
1.164 + <description>
1.165 + <a href="@TOP@/org/openide/util/lookup/ProxyLookup.html">ProxyLookup.setLookups</a>
1.166 + used to fire <a href="@TOP@/org/openide/util/LookupEvent.html">LookupEvent</a> every
1.167 + time it was called. Now it always checks whether there was a change to the
1.168 + previous state. This will reduce the number of events delivered when a small
1.169 + change is made. Also results from both
1.170 + <a href="@TOP@/org/openide/util/lookup/ProxyLookup.html">ProxyLookup</a>
1.171 + and <a href="@TOP@/org/openide/util/lookup/AbstractLookup.html">AbstractLookup</a>
1.172 + were modified to return immutable <code>Collection</code>s.
1.173 + So do not try to modify them. It was always documented that the
1.174 + results, are immutable and also it was never said that a change is
1.175 + delivered when there is no change in the result, so this is considered
1.176 + compatible change, even it is know that at least one piece of code
1.177 + in NetBeans relied on this behaviour.
1.178 + </description>
1.179 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.180 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.181 + <issue number="68031"/>
1.182 + </change>
1.183 +
1.184 +
1.185 + <change id="excluding-lookup">
1.186 + <api name="lookup"/>
1.187 + <summary>
1.188 +<code>Lookups.exclude</code> added to simplify writing of lookups that filter content of other lookups</summary>
1.189 + <version major="5" minor="4"/>
1.190 + <date day="14" month="1" year="2005"/>
1.191 + <author login="jtulach"/>
1.192 + <compatibility binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no" modification="no"/>
1.193 + <description>
1.194 + <p>New method that takes lookup and set of classes and return new lookup
1.195 + which contains everything from the original one except instances of
1.196 + the specified classes has been added.
1.197 + </p>
1.198 + </description>
1.199 + <class package="org.openide.util.lookup" name="Lookups"/>
1.200 + <issue number="53058"/>
1.201 + </change>
1.202 + <change>
1.203 + <api name="lookup"/>
1.204 + <summary>Added ability to order items in META-INF/services/ lookup</summary>
1.205 + <version major="4" minor="34"/>
1.206 + <date day="9" month="5" year="2004"/>
1.207 + <author login="dkonecny"/>
1.208 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.209 + <description>
1.210 + Items in META-INF/services/ lookup can be followed by advisory
1.211 + "position" attribute. The resulting lookup will list first items with lower
1.212 + position value. Items without position attribute will be listed
1.213 + last. See documentation for more details on format.
1.214 + </description>
1.215 + <class package="org.openide.util.lookup" name="Lookups"/>
1.216 + <issue number="41606"/>
1.217 + </change>
1.218 + <change>
1.219 + <api name="lookup"/>
1.220 + <summary>New <code>lookupItem()</code> method in Lookups</summary>
1.221 + <version major="4" minor="8"/>
1.222 + <date day="9" month="7" year="2003"/>
1.223 + <author login="vstejskal"/>
1.224 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.225 + <description>
1.226 + New method that returns Lookup.Item implementation for given instance and key identifying
1.227 + that instance in the lookup. This method is useful when writing Looks which need to
1.228 + return some cookies (Collection of Lookup.Items).
1.229 + </description>
1.230 + <class package="org.openide.util.lookup" name="Lookups"/>
1.231 + </change>
1.232 + <change>
1.233 + <api name="lookup"/>
1.234 + <summary>New method Lookups.metaInfServices</summary>
1.235 + <version major="3" minor="35"/>
1.236 + <date day="5" month="2" year="2003"/>
1.237 + <author login="dstrupl"/>
1.238 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.239 + <description>
1.240 + A lookup that implements the JDK1.3 JAR services mechanism and delegates
1.241 + to META-INF/services/name.of.class files. This lookup was (is) used by core
1.242 + and the core had to use reflection to create an instance. Moreover can
1.243 + be usefull for module authors and in standalone library.
1.244 + </description>
1.245 + <class package="org.openide.util.lookup" name="Lookups"/>
1.246 + <issue number="29126"/>
1.247 + </change>
1.248 + <change>
1.249 + <api name="lookup"/>
1.250 + <summary>New method Lookups.proxy</summary>
1.251 + <version major="3" minor="9"/>
1.252 + <date day="20" month="9" year="2002"/>
1.253 + <author login="dstrupl"/>
1.254 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.255 + <description>
1.256 + Creates a lookup that delegates to another one but that one can change
1.257 + from time to time. The returned lookup checks every time somebody calls
1.258 + lookup or lookupItem method whether the provider still returns
1.259 + the same lookup. If not, it updates state of all Lookup.Results
1.260 + that it created (and that still exists).
1.261 + </description>
1.262 + <class package="org.openide.util.lookup" name="Lookups"/>
1.263 + <issue number="27425"/>
1.264 + </change>
1.265 + <change id="meta-inf-services">
1.266 + <api name="lookup"/>
1.267 + <summary>Modules can specify the content of Lookup.getDefault
1.268 + in META-INF/services</summary>
1.269 + <version major="3" minor="3"/>
1.270 + <date day="22" month="7" year="2002"/>
1.271 + <author login="jtulach"/>
1.272 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.273 + <description>
1.274 + The content of <code>Lookup.getDefault()</code> can be specified
1.275 + by a standard JDK registration mechanism, using JARs'
1.276 + <a href="http://java.sun.com/j2se/1.4/docs/guide/jar/jar.html#Service%20Provider" shape="rect">
1.277 + META-INF/services
1.278 + </a>
1.279 + directory. This is suitable for services that do not change,
1.280 + do not require user modification and that need to be ready
1.281 + soon during initialization of the system.
1.282 + </description>
1.283 + </change>
1.284 + <change>
1.285 + <api name="lookup"/>
1.286 + <summary>Added org.openide.util.lookup.Lookups</summary>
1.287 + <version major="2" minor="21"/>
1.288 + <date day="28" month="5" year="2002"/>
1.289 + <author login="dstrupl"/>
1.290 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.291 + <description>New utility class added. The class cannot be instantiated
1.292 + and contains following static methods:
1.293 + <pre xml:space="preserve">
1.294 +<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Lookup</span> <span class="function-name">singleton</span>(<span class="type">Object</span> <span class="variable-name">objectToLookup</span>);
1.295 +<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Lookup</span> <span class="function-name">fixed</span>(<span class="type">Object</span>[] <span class="variable-name">objectsToLookup</span>);
1.296 +<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Lookup</span> <span class="function-name">fixed</span>(<span class="type">Object</span>[] <span class="variable-name">keys</span>, <span class="type">InstanceContent.Convertor</span> <span class="variable-name">convertor</span>);
1.297 +</pre>
1.298 + The methods return an instance of simple lookup implementation
1.299 + that holds the objects passed a parameter.
1.300 + </description>
1.301 + <class package="org.openide.util.lookup" name="Lookups"/>
1.302 + <issue number="20550"/>
1.303 + </change>
1.304 + <change id="AbstractLookup.Content-ProxyLookup.beforeLookup">
1.305 + <api name="lookup"/>
1.306 + <summary>Enhanced usage of ProxyLookup & AbstractLookup.Content</summary>
1.307 + <version major="1" minor="31"/>
1.308 + <date day="18" month="8" year="2001"/>
1.309 + <author login="jtulach"/>
1.310 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.311 + <description>
1.312 + <code>AbstractLookup.Content</code> made public to allow its usage
1.313 + for objects that do not subclass AbstractLookup. <code>ProxyLookup.beforeLookup</code>
1.314 + added so subclasses can update themselves (call setLookups (...)) before the actual lookup is
1.315 + performed.
1.316 + </description>
1.317 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.318 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.319 + </change>
1.320 + <change>
1.321 + <api name="lookup"/>
1.322 + <summary>Instance content simplifies creation of lookups</summary>
1.323 + <version major="1" minor="25"/>
1.324 + <!-- XXX date unknown -->
1.325 + <author login="jtulach"/>
1.326 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.327 + <description>
1.328 + Added <code>AbstractLookup.Content</code> which can be passed to an
1.329 + abstract lookup in its constructor and used to control the contents
1.330 + easily. Also <code>InstanceLookup</code> provides the common easy
1.331 + implementation.
1.332 + </description>
1.333 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.334 + <class package="org.openide.util.lookup" name="InstanceContent"/>
1.335 + </change>
1.336 + <change>
1.337 + <api name="lookup"/>
1.338 + <summary>Folder lookup may be serialized</summary>
1.339 + <version major="3" minor="27"/>
1.340 + <date day="7" month="1" year="2003"/>
1.341 + <author login="jglick"/>
1.342 + <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no">
1.343 + Modules which rely on a data object under <samp>Services/</samp> gaining
1.344 + or losing <code>InstanceCookie</code> between sessions may not work
1.345 + correctly with the cache. This is probably very rare.
1.346 + </compatibility>
1.347 + <description>
1.348 + To implement lookup caching, some lookup implementations are now
1.349 + serializable: <code>AbstractLookup</code> as well as
1.350 + <code>FolderLookup</code>'s lookup. <code>ProxyLookup</code> has a
1.351 + protected subclass constructor permitting subclasses to be serializable.
1.352 + </description>
1.353 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.354 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.355 + <issue number="20190"/>
1.356 + </change>
1.357 + <change>
1.358 + <api name="lookup"/>
1.359 + <summary>Changes in access protection of proxy lookup</summary>
1.360 + <version major="1" minor="19"/>
1.361 + <date day="8" month="7" year="2001"/>
1.362 + <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no">
1.363 + Changes to newly added feature.
1.364 + </compatibility>
1.365 + <description>
1.366 + <code>ProxyLookup.setLookups</code> made protected instead of public so
1.367 + nobody can misuse the method except the creator of the object and
1.368 + <code>ProxyLookup.getLookups</code> added. <code>ProxyLookup</code> made
1.369 + non final.
1.370 + </description>
1.371 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.372 + </change>
1.373 + <change>
1.374 + <api name="lookup"/>
1.375 + <summary>Lookup service providers package created</summary>
1.376 + <version major="1" minor="9"/>
1.377 + <date day="1" month="6" year="2001"/>
1.378 + <author login="jtulach"/>
1.379 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.380 + <description>
1.381 + Package <code>org.openide.util.lookup</code> created, should hold SPI
1.382 + interfaces for lookup. Initially filled with <code>AbstractLookup</code>
1.383 + which introduces <code>AbstractLookup.Pair</code> and with
1.384 + <code>ProxyLookup</code>.
1.385 + </description>
1.386 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.387 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.388 + <package name="org.openide.util.lookup"/>
1.389 + </change>
1.390 + <change>
1.391 + <api name="lookup"/>
1.392 + <summary>Added lookup items and support APIs</summary>
1.393 + <version major="1" minor="8"/>
1.394 + <date day="25" month="5" year="2001"/>
1.395 + <author login="jtulach"/>
1.396 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.397 + <description>
1.398 + <code>Lookup</code> enhanced. Interface <code>Lookup.Item</code> and
1.399 + additional methods to access it also added.
1.400 + </description>
1.401 + <class package="org.openide.util" name="Lookup"/>
1.402 + </change>
1.403 + <change>
1.404 + <api name="lookup"/>
1.405 + <summary>Lookup system introduced</summary>
1.406 + <date day="1" month="3" year="2001"/>
1.407 + <author login="jtulach"/>
1.408 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.409 + <description>
1.410 + Better version of <code>Lookup</code> introduced. There is a
1.411 + <code>org.openide.util.Lookup</code> with bunch of inner classes and
1.412 + <code>org.openide.util.LookupListener</code> and
1.413 + <code>org.openide.util.LookupEvent</code>.
1.414 + </description>
1.415 + <class package="org.openide.util" name="Lookup"/>
1.416 + <class package="org.openide.util" name="LookupEvent"/>
1.417 + <class package="org.openide.util" name="LookupListener"/>
1.418 + </change>
1.419 +</changes>
1.420 +<htmlcontents>
1.421 +<head>
1.422 +<title>Change History for the Lookup API</title>
1.423 +<link rel="stylesheet" href="prose.css" type="text/css"/>
1.424 +</head>
1.425 +<body>
1.426 +<p class="overviewlink">
1.427 +<a href="overview-summary.html">Overview</a>
1.428 +</p>
1.429 +<h1>Introduction</h1>
1.430 +<h2>What do the Dates Mean?</h2>
1.431 +<p>The supplied dates indicate when the API change was made, on the CVS
1.432 +trunk. From this you can generally tell whether the change should be
1.433 +present in a given build or not; for trunk builds, simply whether it
1.434 +was made before or after the change; for builds on a stabilization
1.435 +branch, whether the branch was made before or after the given date. In
1.436 +some cases corresponding API changes have been made both in the trunk
1.437 +and in an in-progress stabilization branch, if they were needed for a
1.438 +bug fix; this ought to be marked in this list.</p>
1.439 +<ul>
1.440 +<li>The <code>release41</code> branch was made on Apr 03 '05 for use in the NetBeans 4.1 release.
1.441 +Specification versions: 6.0 begins after this point.</li>
1.442 +<li>The <code>release40</code> branch was made on Nov 01 '04 for use in the NetBeans 4.0 release.
1.443 +Specification versions: 5.0 begins after this point.</li>
1.444 +</ul>
1.445 +<hr/>
1.446 +<standard-changelists module-code-name="$codebase"/>
1.447 +<hr/>
1.448 +<p>@FOOTER@</p>
1.449 +</body>
1.450 +</htmlcontents>
1.451 +</apichanges>
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/openide.util.lookup/arch.xml Mon Dec 14 20:58:39 2009 +0100
2.3 @@ -0,0 +1,827 @@
2.4 +<?xml version="1.0" encoding="UTF-8"?>
2.5 +<!--
2.6 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
2.7 +
2.8 +Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
2.9 +
2.10 +
2.11 +The contents of this file are subject to the terms of either the GNU
2.12 +General Public License Version 2 only ("GPL") or the Common
2.13 +Development and Distribution License("CDDL") (collectively, the
2.14 +"License"). You may not use this file except in compliance with the
2.15 +License. You can obtain a copy of the License at
2.16 +http://www.netbeans.org/cddl-gplv2.html
2.17 +or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
2.18 +specific language governing permissions and limitations under the
2.19 +License. When distributing the software, include this License Header
2.20 +Notice in each file and include the License file at
2.21 +nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
2.22 +particular file as subject to the "Classpath" exception as provided
2.23 +by Sun in the GPL Version 2 section of the License file that
2.24 +accompanied this code. If applicable, add the following below the
2.25 +License Header, with the fields enclosed by brackets [] replaced by
2.26 +your own identifying information:
2.27 +"Portions Copyrighted [year] [name of copyright owner]"
2.28 +
2.29 +Contributor(s):
2.30 +
2.31 +The Original Software is NetBeans. The Initial Developer of the Original
2.32 +Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
2.33 +Microsystems, Inc. All Rights Reserved.
2.34 +
2.35 +If you wish your version of this file to be governed by only the CDDL
2.36 +or only the GPL Version 2, indicate your decision by adding
2.37 +"[Contributor] elects to include this software in this distribution
2.38 +under the [CDDL or GPL Version 2] license." If you do not indicate a
2.39 +single choice of license, a recipient has the option to distribute
2.40 +your version of this file under either the CDDL, the GPL Version 2 or
2.41 +to extend the choice of license to its licensees as provided above.
2.42 +However, if you add GPL Version 2 code and therefore, elected the GPL
2.43 +Version 2 license, then the option applies only if the new code is
2.44 +made subject to such option by the copyright holder.
2.45 +-->
2.46 +<!DOCTYPE api-answers PUBLIC "-//NetBeans//DTD Arch Answers//EN" "../nbbuild/antsrc/org/netbeans/nbbuild/Arch.dtd" [
2.47 + <!ENTITY api-questions SYSTEM "../nbbuild/antsrc/org/netbeans/nbbuild/Arch-api-questions.xml">
2.48 +]>
2.49 +
2.50 +<api-answers
2.51 + question-version="1.25"
2.52 + author="jtulach@netbeans.org"
2.53 +>
2.54 +
2.55 + &api-questions;
2.56 +
2.57 + <answer id="arch-overall">
2.58 + <p>
2.59 + Also this module defines the <a href="@TOP@/org/openide/util/Lookup.html">
2.60 + Lookup</a> which is the NetBeans way for dynamic registration
2.61 + and lookup of
2.62 + components in our modularized component system. It allows lookup and discovery
2.63 + of features by description of their interfaces. The classes are devided
2.64 + into two parts. The
2.65 + <api group="java" name="LookupAPI" type="export" category="official" url="@TOP@/org/openide/util/lookup/doc-files/lookup-api.html">
2.66 + allows the discovery</api> and the
2.67 + <api group="java" name="LookupSPI" type="export" category="official" url="@TOP@/org/openide/util/lookup/doc-files/lookup-spi.html">
2.68 + simplifies creation and registration of own lookup objects</api>.
2.69 + </p>
2.70 + </answer>
2.71 +
2.72 +
2.73 + <answer id="arch-quality">
2.74 + <p>
2.75 + There is a lot of unit tests in
2.76 + <a href="http://hg.netbeans.org/main-golden/openide.util.lookup/test/unit/src/">version control</a>
2.77 + system.
2.78 + </p>
2.79 + </answer>
2.80 +
2.81 + <answer id="arch-time">
2.82 + <p>
2.83 + The module has been around since 1997 and is continously being improved
2.84 + from time to time.
2.85 + </p>
2.86 + </answer>
2.87 +
2.88 +
2.89 +
2.90 + <answer id="arch-usecases">
2.91 +
2.92 + There is a great introduction to Lookup and its usage in its
2.93 + <a href="@TOP@/org/openide/util/Lookup.html">javadoc</a>. Here is just
2.94 + a list of frequently asked or interesting questions slowly expanding as
2.95 + people ask them:
2.96 +
2.97 + <h3>Lookup faq:</h3>
2.98 +
2.99 + <usecase id="lookup-on-certain-platform" name="How to specify that a service in Lookup should be available only on Windows?" >
2.100 +<em><b>Q:</b>
2.101 +Most of the time I specify interfaces that I want to add to the Lookup class in the layer.xml file.
2.102 +But, let's say I have a platform-specific interface (something on Windows only, for instance).</em>
2.103 +<p>
2.104 +<em>
2.105 +How can I specify (in the xml, or programmatically) that this service should only be added to the Lookup if the platform is Windows?
2.106 +</em>>
2.107 +</p>
2.108 +In general there are three ways to achieve this.
2.109 +<ul>
2.110 + <li><p>It is possible to write a specific module and enable it only on windows.
2.111 + See <a href="@org-openide-modules@/org/openide/modules/doc-files/api.html#how-os-specific">os specific modules</a> documentation.
2.112 + Then you can put a registration of your instance into your module's
2.113 + <a href="@org-openide-util@/org/openide/util/doc-files/api.html#service-lookup">META-INF/services</a> directory and it
2.114 + will be available only on Windows.</p>
2.115 + </li>
2.116 +
2.117 + <li><p>Another possibility that does not require new module, but which executes
2.118 + a code on startup (which may have performance implications) is to use <code>methodvalue</code>
2.119 + attribute. Register your instance in layer using <code>your-Object.instance</code> file
2.120 + as described at
2.121 + <a href="@org-openide-util@/org/openide/util/doc-files/api.html#ido-methodvalue">services
2.122 + </a> documentation and in your factory method either return the instance
2.123 + your want or <code>null</code> depending on result of <a href="@org-openide-util@/org/openide/util/Utilities.html#isWindows()">
2.124 + Utilities.isWindows()</a> call.</p>
2.125 + </li>
2.126 + <li>
2.127 + <p>
2.128 + In some cases, the interface for which you will register an implementation permits a
2.129 + no-operation semantics. For example, <code>InstalledFileLocator.locate(...)</code> can
2.130 + return a valid <code>File</code>, or null. You could always register an
2.131 + <code>InstalledFileLocator</code> instance yet disable it on non-Windows platforms
2.132 + (always returning null).
2.133 + </p>
2.134 + </li>
2.135 +</ul>
2.136 +
2.137 + </usecase>
2.138 +
2.139 + <usecase id="lookup-extension-point" name="How shall I write an extension point for my module?" >
2.140 + <p>
2.141 + <em><b>Q:</b>
2.142 + I have more modules one of them providing the core functionality and
2.143 + few more that wish to extend it. What is the right way to do it?
2.144 + How does the Netbeans platform declare such extension point?
2.145 + </em>
2.146 + </p>
2.147 +
2.148 + <p>
2.149 +
2.150 + Start with declaring an extension interface in your
2.151 + core module and put it into the module's <em>public packages</em>. Imagine
2.152 + for example that the core module is in JAR file <code>org-my-netbeans-coremodule.jar</code>
2.153 + and already contains in manifests line like
2.154 + <code>OpenIDE-Module: org.my.netbeans.coremodule/1</code> and wants
2.155 + to display various tips of the day provided by other modules and thus defines:
2.156 + </p><pre>
2.157 +<span class="java-keywords">package</span> <span class="java-identifier">org</span><span class="java-operators">.</span><span class="java-identifier">my</span><span class="java-operators">.</span><span class="java-identifier">netbeans</span><span class="java-operators">.</span><span class="java-identifier">coremodule</span><span class="java-operators">;</span>
2.158 +
2.159 +<span class="java-keywords">public</span> <span class="java-keywords">interface</span> <span class="java-identifier">TipsOfTheDayProvider</span> <span class="java-operators">{</span>
2.160 + <span class="java-keywords">public</span> <span class="java-identifier">String</span> <span class="java-layer-method">provideTipOfTheDay</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">;</span>
2.161 +<span class="java-operators">}</span>
2.162 +</pre><p>
2.163 + And in its manifest adds line
2.164 + <code>OpenIDE-Module-Public-Packages: org.my.netbeans.coremodule.*</code>
2.165 + to specify that this package contains exported API and shall be
2.166 + accessible to other modules.
2.167 + </p>
2.168 + <p>
2.169 + When the core module is about to display the tip of the day it can ask
2.170 + the system for all registered instances of the <code>TipsOfTheDayProvider</code>,
2.171 + randomly select one of them:
2.172 + </p><pre>
2.173 +<span class="java-keywords">import</span> <span class="java-identifier">java</span><span class="java-operators">.</span><span class="java-identifier">util</span><span class="java-operators">.</span><span class="java-identifier">Collection</span><span class="java-operators">;</span>
2.174 +<span class="java-keywords">import</span> <span class="java-identifier">java</span><span class="java-operators">.</span><span class="java-identifier">util</span><span class="java-operators">.</span><span class="java-identifier">Collections</span><span class="java-operators">;</span>
2.175 +<span class="java-keywords">import</span> <span class="java-identifier">org</span><span class="java-operators">.</span><span class="java-identifier">openide</span><span class="java-operators">.</span><span class="java-identifier">util</span><span class="java-operators">.</span><span class="java-identifier">Lookup</span><span class="java-operators">;</span>
2.176 +
2.177 +<a href="@TOP@org/openide/util/Lookup.Result.html"><span class="java-identifier">Lookup</span><span class="java-operators">.</span><span class="java-identifier">Result</span></a> <span class="java-identifier">result</span> <span class="java-operators">=</span> <a href="@TOP@org/openide/util/Lookup.html"><span class="java-identifier">Lookup</span></a><span class="java-operators">.</span><span class="java-layer-method">getDefault</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">.</span><span class="java-layer-method">lookup</span> <span class="java-operators">(</span><span class="java-keywords">new</span> <a href="@TOP@org/openide/util/Lookup.Template.html"><span class="java-identifier">Lookup</span><span class="java-operators">.</span><span class="java-layer-method">Template</span></a> <span class="java-operators">(</span><span class="java-identifier">TipsOfTheDayProvider</span><span class="java-operators">.</span><span class="java-keywords">class</span><span class="java-operators">)</span><span class="java-operators">)</span><span class="java-operators">;</span>
2.178 +<span class="java-identifier">Collection</span> <span class="java-identifier">c</span> <span class="java-operators">=</span> <span class="java-identifier">result</span><span class="java-operators">.</span><a href="@TOP@org/openide/util/Lookup.Result.html#allInstances()"><span class="java-layer-method">allInstances</span></a> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">;</span>
2.179 +<span class="java-identifier">Collections</span><span class="java-operators">.</span><span class="java-layer-method">shuffle</span> <span class="java-operators">(</span><span class="java-identifier">c</span><span class="java-operators">)</span><span class="java-operators">;</span>
2.180 +<span class="java-identifier">TipsOfTheDayProvider</span> <span class="java-identifier">selected</span> <span class="java-operators">=</span> <span class="java-operators">(</span><span class="java-identifier">TipsOfTheDayProvider</span><span class="java-operators">)</span><span class="java-identifier">c</span><span class="java-operators">.</span><span class="java-layer-method">iterator</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">.</span><span class="java-layer-method">next</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">;</span>
2.181 +</pre><p>
2.182 + and then display the tip. Simple, trivial, just by the usage of
2.183 + <a href="@TOP@org/openide/util/Lookup.html">Lookup</a> interface once
2.184 + creates a registry that other modules can enhance. But such enhancing
2.185 + of course requires work on the other side. Each module that would like
2.186 + to register its <code>TipsOfTheDayProvider</code> needs to depend on the
2.187 + core module - add
2.188 + <code>OpenIDE-Module-Module-Dependencies: org.my.netbeans.coremodule/1</code>
2.189 + into its manifest and write a class with its own implementation of the
2.190 + provider:</p><pre>
2.191 +<span class="java-keywords">package</span> <span class="java-identifier">org</span><span class="java-operators">.</span><span class="java-identifier">my</span><span class="java-operators">.</span><span class="java-identifier">netbeans</span><span class="java-operators">.</span><span class="java-identifier">extramodule</span><span class="java-operators">;</span>
2.192 +
2.193 +<span class="java-keywords">class</span> <span class="java-identifier">ExtraTip</span> <span class="java-keywords">implements</span> <span class="java-identifier">TipsOfTheDayProvider</span> <span class="java-operators">{</span>
2.194 + <span class="java-keywords">public</span> <span class="java-identifier">String</span> <span class="java-layer-method">provideTipOfTheDay</span> <span class="java-operators">(</span><span class="java-operators">)</span> <span class="java-operators">{</span>
2.195 + <span class="java-keywords">return</span> <span class="java-string-literal">"Do you know that in order to write extension point you should use Lookup?"</span><span class="java-operators">;</span>
2.196 + <span class="java-operators">}</span>
2.197 +<span class="java-operators">}</span>
2.198 +</pre><p>
2.199 + Then, the only necessary thing is to register such class by using the
2.200 + J2SE standard <api name="ProviderRegistrationMechanism"
2.201 + type="import"
2.202 + category="standard"
2.203 + group="java" /> into plain text file
2.204 + <code>META-INF/services/org.my.netbeans.coremodule.TipsOfTheDayProvider</code>
2.205 + in the module JAR containing just one line: </p><pre>
2.206 +org.my.netbeans.extramodule.ExtraTip
2.207 +</pre><p>
2.208 + and your modules are now ready to communicate
2.209 + using your own <em>extension point</em>.
2.210 + </p>
2.211 +
2.212 + </usecase>
2.213 + </answer>
2.214 +
2.215 +
2.216 +
2.217 + <answer id="arch-what">
2.218 + <p>
2.219 + Described in the <a href="@TOP@/architecture-summary.html#answer-arch-overall">overall</a> answer.
2.220 + </p>
2.221 + </answer>
2.222 +
2.223 +
2.224 +
2.225 + <answer id="compat-standards">
2.226 + <p>
2.227 + The default lookup registration follows the JDK's
2.228 + <api name="ProviderRegistrationMechanism"
2.229 + type="import"
2.230 + category="standard"
2.231 + url="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Provider%20Configuration%20File"
2.232 + group="java"
2.233 + />
2.234 + but enhances it to also support the
2.235 + <api
2.236 + name="ProviderRegistrationRemoval"
2.237 + type="export"
2.238 + category="devel"
2.239 + url="@org-openide-util@/org/openide/util/doc-files/api.html#service-lookup"
2.240 + group="java"
2.241 + />.
2.242 + </p>
2.243 + </answer>
2.244 +
2.245 + <answer id="compat-version">
2.246 + <p>
2.247 + This module has no settings.
2.248 + </p>
2.249 + </answer>
2.250 +
2.251 +
2.252 +
2.253 + <answer id="dep-jre">
2.254 + <p>
2.255 + Currently JRE 1.5 is needed.
2.256 + </p>
2.257 + </answer>
2.258 +
2.259 +
2.260 +
2.261 + <answer id="dep-jrejdk">
2.262 + <p>
2.263 + JRE is enough.
2.264 + </p>
2.265 + </answer>
2.266 +
2.267 +
2.268 + <answer id="dep-nb">
2.269 + <p>N/A</p>
2.270 + </answer>
2.271 +
2.272 + <answer id="dep-platform">
2.273 + <p>
2.274 + Platform independent.
2.275 + </p>
2.276 + </answer>
2.277 +
2.278 +
2.279 + <answer id="deploy-dependencies">
2.280 + <p>
2.281 + Nothing.
2.282 + </p>
2.283 + </answer>
2.284 +
2.285 +
2.286 +
2.287 + <answer id="deploy-jar">
2.288 + <p>
2.289 + <api category="devel" group="java.io.File" name="FileLocation" type="export" >
2.290 + the JAR file is located in platform cluster under <code>lib/org-openide-util-lookup.jar</code>
2.291 + </api>.
2.292 + </p>
2.293 + </answer>
2.294 +
2.295 + <answer id="deploy-shared">
2.296 + <p>
2.297 + Module is on real java classpath and as such it has to be in the shared directory.
2.298 + </p>
2.299 + </answer>
2.300 +
2.301 +
2.302 + <answer id="exec-ant-tasks">
2.303 + <p>
2.304 + No.
2.305 + </p>
2.306 + </answer>
2.307 +
2.308 +
2.309 +
2.310 + <answer id="exec-classloader">
2.311 + <p>
2.312 + No, we do not create own classloader.
2.313 + </p>
2.314 + </answer>
2.315 +
2.316 +
2.317 +
2.318 +<answer id="exec-privateaccess">
2.319 + <p>
2.320 + No.
2.321 + </p>
2.322 + </answer>
2.323 +
2.324 + <answer id="exec-process">
2.325 + <p>
2.326 + No external processes executed.
2.327 + </p>
2.328 + </answer>
2.329 +
2.330 +
2.331 + <answer id="exec-property">
2.332 + <ul>
2.333 + <li>
2.334 + <api type="export" group="property" name="org.openide.util.Lookup" category="devel">
2.335 + checked by the initialization of the
2.336 + <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
2.337 + and can
2.338 + contain name of a class that extends <code>org.openide.util.Lookup</code> and
2.339 + has public constructor, that should be instantiated and returned from
2.340 + <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
2.341 + the class will be loaded by
2.342 + <a href="@JDK@/java/lang/Thread.html#getContextClassLoader()">
2.343 + Thread.currentThread().getContextClassLoader()</a>
2.344 + classloader the first time <code>Lookup.getDefault</code> is invoked.
2.345 + <p/>
2.346 + The property can also contain value <code>"-"</code> which means to completely
2.347 + disable the lookup instantiation and return <a href="@TOP@/org/openide/util/Lookup.html#EMPTY">Lookup.EMPTY</a>
2.348 + from <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>.
2.349 + <p/>
2.350 + If the property is unspecified, the default <code>MetaInfServicesLookup</code>
2.351 + is constructed for <code>Thread.currentThread().getContextclassLoader()</code>
2.352 + that implements the <a href="architecture-summary.html#answer-compat-standards">JDK's standard</a>. If, by
2.353 + a chance an instance of
2.354 + <a href="@TOP@/org/openide/util/Lookup.Provider.html">Lookup.Provider</a>
2.355 + is found
2.356 + in there, its lookup is returned as result. Otherwise the <code>MetaInfServicesLookup</code>
2.357 + is the result of <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>.
2.358 + </api>
2.359 + </li>
2.360 +
2.361 + <li>
2.362 + <api type="export" group="property" name="org.openide.util.Lookup.paths" category="devel">
2.363 + Sometimes it may be useful for the Lookup to contains objects from
2.364 + some system file system folder. This can be done with
2.365 + <code>org.openide.util.Lookup.paths=Folder1:Folder2:Folder3</code>.
2.366 + If this property is set prior to first call to
2.367 + <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>,
2.368 + it is split into pieces (separator is <code>':'</code>) and individual
2.369 + parts are then used to construct <code>Lookups.forPath("Folder1")</code>,
2.370 + etc. All these lookups then become part of the
2.371 + <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
2.372 + one. This property works since version 7.24
2.373 + </api>
2.374 + </li>
2.375 +
2.376 + </ul>
2.377 + </answer>
2.378 +
2.379 +
2.380 +
2.381 + <answer id="exec-reflection">
2.382 + <p>
2.383 + <api category="devel" group="java" name="Lookups.metaInfServices" type="export" url="@TOP@/org/openide/util/lookup/Lookups.html#metaInfServices(java.lang.ClassLoader)">
2.384 + calls constructor of registered classes using reflection
2.385 + </api>.
2.386 + <api category="friend" group="java" name="Lookup.resetDefaultLookup" type="export">
2.387 + There is a static private method <code>Lookup.resetDefaultLookup</code> that
2.388 + is called by NbJUnit's <code>MockServices</code> to properly reset default
2.389 + lookup and fire changes to all registred listeners.
2.390 + </api>.
2.391 +
2.392 + </p>
2.393 + </answer>
2.394 +
2.395 + <answer id="exec-threading">
2.396 + <p>
2.397 + Everything is synchronous, except pluggable use of <code>java.util.concurrent.Executor</code>
2.398 + that allows to make calls asynchronous. The default implementation only delivers
2.399 + changes from <a href="@TOP@/org/openide/util/lookup/Lookups.html#metaInfServices(java.lang.ClassLoader)">metaInfServices</a>
2.400 + lookup in asynchronous thread.
2.401 + </p>
2.402 + </answer>
2.403 +
2.404 +
2.405 +
2.406 + <answer id="format-clipboard">
2.407 + <p>
2.408 + Not used.
2.409 + </p>
2.410 + </answer>
2.411 +
2.412 +
2.413 +
2.414 + <answer id="format-dnd">
2.415 + <p>
2.416 + The same as for clipboard.
2.417 + </p>
2.418 + </answer>
2.419 +
2.420 + <answer id="format-types">
2.421 + <p>
2.422 + No.
2.423 + </p>
2.424 + </answer>
2.425 +
2.426 +
2.427 +
2.428 + <answer id="lookup-lookup">
2.429 + <ul>
2.430 + <li><api name="LookupInitializationLookup" category="devel" group="lookup" type="export" url="#property-org.openide.util.Lookup">
2.431 + during
2.432 + initialization of the <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
2.433 + the <a href="@TOP@/org/openide/util/Lookup.Provider.html">Lookup.Provider</a>
2.434 + is being searched</api>.
2.435 + </li>
2.436 +
2.437 + <li><api name="LookupSharedClassObject" category="devel" group="lookup" type="export">
2.438 + singleton subclasses of <a href="@org-openide-util@/org/openide/util/SharedClassObject.html">SharedClassObject</a>
2.439 + are searched for using Lookup.
2.440 + </api>.</li>
2.441 +
2.442 + <li><api name="LookupClassLoader" category="devel" group="lookup" type="export">
2.443 + Nearly all resource looking functions and reflective code
2.444 + uses <a href="@JDK@/java/lang/ClassLoader.html">ClassLoader</a>
2.445 + obtained from <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
2.446 + for loading system wide resources.
2.447 + </api>.</li>
2.448 +
2.449 + </ul>
2.450 + </answer>
2.451 +
2.452 +
2.453 +
2.454 + <answer id="lookup-register">
2.455 + <p>
2.456 + No.
2.457 + </p>
2.458 + </answer>
2.459 +
2.460 +
2.461 +
2.462 +<!--
2.463 + <question id="lookup-remove" when="final">
2.464 + Do you remove entries of other modules from lookup?
2.465 + <hint>
2.466 + Why? Of course, that is possible, but it can be dangerous. Is the module
2.467 + your are masking resource from aware of what you are doing?
2.468 + </hint>
2.469 + </question>
2.470 +-->
2.471 + <answer id="lookup-remove">
2.472 + <p>
2.473 + No.
2.474 + </p>
2.475 + </answer>
2.476 +
2.477 +
2.478 +
2.479 +<!--
2.480 + <question id="perf-exit" when="final">
2.481 + Does your module run any code on exit?
2.482 + </question>
2.483 +-->
2.484 + <answer id="perf-exit">
2.485 + <p>
2.486 + Nothing.
2.487 + </p>
2.488 + </answer>
2.489 +
2.490 +
2.491 +
2.492 +<!--
2.493 + <question id="perf-huge_dialogs" when="final">
2.494 + Does your module contain any dialogs or wizards with a large number of
2.495 + GUI controls such as combo boxes, lists, trees, or text areas?
2.496 + </question>
2.497 +-->
2.498 + <answer id="perf-huge_dialogs">
2.499 + <p>
2.500 + No.
2.501 + </p>
2.502 + </answer>
2.503 +
2.504 +
2.505 +
2.506 +<!--
2.507 + <question id="perf-limit" when="init">
2.508 + Are there any hard-coded or practical limits in the number or size of
2.509 + elements your code can handle?
2.510 + </question>
2.511 +-->
2.512 + <answer id="perf-limit">
2.513 + <p>
2.514 + The default implementation of the <code>MetaInfServicesLookup</code> just
2.515 + keeps hashmap between queried classes and their implementations. The amount
2.516 + of memory is linear to amount of registered classes, but of course we
2.517 + are not counting the memory occupied by the instances which the lookup
2.518 + creates, that can be arbitrary.
2.519 + </p>
2.520 + </answer>
2.521 +
2.522 +
2.523 +
2.524 +<!--
2.525 + <question id="perf-mem" when="final">
2.526 + How much memory does your component consume? Estimate
2.527 + with a relation to the number of windows, etc.
2.528 + </question>
2.529 +-->
2.530 + <answer id="perf-mem">
2.531 + <p>
2.532 + There are no big data structures. The amount of memory occupied by
2.533 + instances of <a href="@TOP@/org/openide/util/lookup/AbstractLookup.html">AbstractLookup</a>
2.534 + is measured by unit tests.
2.535 + </p>
2.536 + </answer>
2.537 +
2.538 +
2.539 +
2.540 +<!--
2.541 + <question id="perf-menus" when="final">
2.542 + Does your module use dynamically updated context menus, or
2.543 + context-sensitive actions with complicated and slow enablement logic?
2.544 + <hint>
2.545 + If you do a lot of tricks when adding actions to regular or context menus, you can significantly
2.546 + slow down display of the menu, even when the user is not using your action. Pay attention to
2.547 + actions you add to the main menu bar, and to context menus of foreign nodes or components. If
2.548 + the action is conditionally enabled, or changes its display dynamically, you need to check the
2.549 + impact on performance. In some cases it may be more appropriate to make a simple action that is
2.550 + always enabled but does more detailed checks in a dialog if it is actually run.
2.551 + </hint>
2.552 + </question>
2.553 +-->
2.554 + <answer id="perf-menus">
2.555 + <p>
2.556 + There are no menus.
2.557 + </p>
2.558 + </answer>
2.559 +
2.560 +
2.561 +
2.562 +<!--
2.563 + <question id="perf-progress" when="final">
2.564 + Does your module execute any long-running tasks?
2.565 +
2.566 + <hint>Long running tasks should never block
2.567 + AWT thread as it badly hurts the UI
2.568 + <a href="http://performance.netbeans.org/responsiveness/issues.html">
2.569 + responsiveness</a>.
2.570 + Tasks like connecting over
2.571 + network, computing huge amount of data, compilation
2.572 + be done asynchronously (for example
2.573 + using <code>RequestProcessor</code>), definitively it should
2.574 + not block AWT thread.
2.575 + </hint>
2.576 + </question>
2.577 +-->
2.578 + <answer id="perf-progress">
2.579 + <p>
2.580 + No.
2.581 + </p>
2.582 + </answer>
2.583 +
2.584 +
2.585 +
2.586 +<!--
2.587 + <question id="perf-scale" when="init">
2.588 + Which external criteria influence the performance of your
2.589 + program (size of file in editor, number of files in menu,
2.590 + in source directory, etc.) and how well your code scales?
2.591 + <hint>
2.592 + Please include some estimates, there are other more detailed
2.593 + questions to answer in later phases of implementation.
2.594 + </hint>
2.595 + </question>
2.596 +-->
2.597 + <answer id="perf-scale">
2.598 + <p>
2.599 + Lookup code scales linearily.
2.600 + </p>
2.601 + </answer>
2.602 +
2.603 +
2.604 +
2.605 +<!--
2.606 + <question id="perf-spi" when="init">
2.607 + How the performance of the plugged in code will be enforced?
2.608 + <hint>
2.609 + If you allow foreign code to be plugged into your own module, how
2.610 + do you enforce that it will behave correctly and quickly and will not
2.611 + negatively influence the performance of your own module?
2.612 + </hint>
2.613 + </question>
2.614 +-->
2.615 + <answer id="perf-spi">
2.616 + <p>
2.617 + No enforcing is done.
2.618 + </p>
2.619 + </answer>
2.620 +
2.621 +
2.622 +
2.623 +<!--
2.624 + <question id="perf-startup" when="final">
2.625 + Does your module run any code on startup?
2.626 + </question>
2.627 +-->
2.628 + <answer id="perf-startup">
2.629 + <p>
2.630 + No.
2.631 + </p>
2.632 + </answer>
2.633 +
2.634 +
2.635 +
2.636 +<!--
2.637 + <question id="perf-wakeup" when="final">
2.638 + Does any piece of your code wake up periodically and do something
2.639 + even when the system is otherwise idle (no user interaction)?
2.640 + </question>
2.641 +-->
2.642 + <answer id="perf-wakeup">
2.643 + <p>
2.644 + No.
2.645 + </p>
2.646 + </answer>
2.647 +
2.648 +
2.649 +
2.650 +<!--
2.651 + <question id="resources-file" when="final">
2.652 + Does your module use <code>java.io.File</code> directly?
2.653 +
2.654 + <hint>
2.655 + NetBeans provide a logical wrapper over plain files called
2.656 + <code>org.openide.filesystems.FileObject</code> that
2.657 + provides uniform access to such resources and is the preferred
2.658 + way that should be used. But of course there can be situations when
2.659 + this is not suitable.
2.660 + </hint>
2.661 + </question>
2.662 +-->
2.663 + <answer id="resources-file">
2.664 + <p>
2.665 + No.
2.666 + </p>
2.667 + </answer>
2.668 +
2.669 +
2.670 +
2.671 +<!--
2.672 + <question id="resources-layer" when="final">
2.673 + Does your module provide own layer? Does it create any files or
2.674 + folders in it? What it is trying to communicate by that and with which
2.675 + components?
2.676 +
2.677 + <hint>
2.678 + NetBeans allows automatic and declarative installation of resources
2.679 + by module layers. Module register files into appropriate places
2.680 + and other components use that information to perform their task
2.681 + (build menu, toolbar, window layout, list of templates, set of
2.682 + options, etc.).
2.683 + </hint>
2.684 + </question>
2.685 +-->
2.686 + <answer id="resources-layer">
2.687 + <p>
2.688 + No.
2.689 + </p>
2.690 + </answer>
2.691 +
2.692 +
2.693 +
2.694 +<!--
2.695 + <question id="resources-mask" when="final">
2.696 + Does your module mask/hide/override any resources provided by other modules in
2.697 + their layers?
2.698 +
2.699 + <hint>
2.700 + If you mask a file provided by another module, you probably depend
2.701 + on that and do not want the other module to (for example) change
2.702 + the file's name. That module shall thus make that file available as an API
2.703 + of some stability category.
2.704 + </hint>
2.705 + </question>
2.706 +-->
2.707 + <answer id="resources-mask">
2.708 + <p>
2.709 + No.
2.710 + </p>
2.711 + </answer>
2.712 +
2.713 +
2.714 +
2.715 +<!--
2.716 + <question id="resources-read" when="final">
2.717 + Does your module read any resources from layers? For what purpose?
2.718 +
2.719 + <hint>
2.720 + As this is some kind of intermodule dependency, it is a kind of API.
2.721 + Please describe it and classify according to
2.722 + <a href="http://openide.netbeans.org/tutorial/api-design.html#categories">
2.723 + common stability categories</a>.
2.724 + </hint>
2.725 + </question>
2.726 +-->
2.727 + <answer id="resources-read">
2.728 + <p>
2.729 + No.
2.730 + </p>
2.731 + </answer>
2.732 +
2.733 +
2.734 +
2.735 +<!--
2.736 + <question id="security-grant" when="final">
2.737 + Does your code grant additional rights to some other code?
2.738 + <hint>Avoid using a class loader that adds extra
2.739 + permissions to loaded code unless really necessary.
2.740 + Also note that your API implementation
2.741 + can also expose unneeded permissions to enemy code by
2.742 + calling AccessController.doPrivileged().</hint>
2.743 + </question>
2.744 +-->
2.745 + <answer id="security-grant">
2.746 + <p>
2.747 + No security permitions manipulated.
2.748 + </p>
2.749 + </answer>
2.750 +
2.751 +
2.752 +
2.753 +<!--
2.754 + <question id="security-policy" when="final">
2.755 + Does your functionality require modifications to the standard policy file?
2.756 + <hint>Your code might pass control to third-party code not
2.757 + coming from trusted domains. This could be code downloaded over the
2.758 + network or code coming from libraries that are not bundled
2.759 + with NetBeans. Which permissions need to be granted to which domains?</hint>
2.760 + </question>
2.761 +-->
2.762 + <answer id="security-policy">
2.763 + <p>
2.764 + No security permissions manipulated.
2.765 + </p>
2.766 + </answer>
2.767 +
2.768 +
2.769 +
2.770 +
2.771 +<!--
2.772 + <question id="arch-where" when="init">
2.773 + Where one can find sources for your module?
2.774 + <hint>
2.775 + Please provide link to the CVS web client at
2.776 + http://www.netbeans.org/download/source_browse.html
2.777 + or just use tag defaultanswer generate='here'
2.778 + </hint>
2.779 + </question>
2.780 +-->
2.781 + <answer id="arch-where">
2.782 + <defaultanswer generate='here' />
2.783 + </answer>
2.784 +
2.785 +
2.786 +
2.787 +
2.788 +<!--
2.789 + <question id="compat-deprecation" when="init">
2.790 + How the introduction of your project influences functionality
2.791 + provided by previous version of the product?
2.792 + <hint>
2.793 + If you are planning to deprecate/remove/change any existing APIs,
2.794 + list them here accompanied with the reason explaining why you
2.795 + are doing so.
2.796 + </hint>
2.797 + </question>
2.798 +-->
2.799 + <answer id="compat-deprecation">
2.800 + <p>
2.801 + XXX no answer for compat-deprecation
2.802 + </p>
2.803 + </answer>
2.804 +
2.805 +
2.806 +
2.807 +<!--
2.808 + <question id="resources-preferences" when="final">
2.809 + Does your module uses preferences via Preferences API? Does your module use NbPreferences or
2.810 + or regular JDK Preferences ? Does it read, write or both ?
2.811 + Does it share preferences with other modules ? If so, then why ?
2.812 + <hint>
2.813 + You may use
2.814 + <api type="export" group="preferences"
2.815 + name="preference node name" category="private">
2.816 + description of individual keys, where it is used, what it
2.817 + influences, whether the module reads/write it, etc.
2.818 + </api>
2.819 + Due to XML ID restrictions, rather than /org/netbeans/modules/foo give the "name" as org.netbeans.modules.foo.
2.820 + Note that if you use NbPreferences this name will then be the same as the code name base of the module.
2.821 + </hint>
2.822 + </question>
2.823 +-->
2.824 + <answer id="resources-preferences">
2.825 + <p>
2.826 + XXX no answer for resources-preferences
2.827 + </p>
2.828 + </answer>
2.829 +
2.830 +</api-answers>
3.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
3.2 +++ b/openide.util.lookup/build.xml Mon Dec 14 20:58:39 2009 +0100
3.3 @@ -0,0 +1,5 @@
3.4 +<?xml version="1.0" encoding="UTF-8"?>
3.5 +<project basedir="." default="netbeans" name="openide.util.lookup">
3.6 + <description>Builds, tests, and runs the project org.openide.util.lookup</description>
3.7 + <import file="../nbbuild/templates/projectized.xml"/>
3.8 +</project>
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/openide.util.lookup/manifest.mf Mon Dec 14 20:58:39 2009 +0100
4.3 @@ -0,0 +1,5 @@
4.4 +Manifest-Version: 1.0
4.5 +OpenIDE-Module: org.openide.util.lookup
4.6 +OpenIDE-Module-Implementation-Version: 1
4.7 +OpenIDE-Module-Localizing-Bundle: org/openide/util/lookup/Bundle.properties
4.8 +
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
5.2 +++ b/openide.util.lookup/nbproject/project.properties Mon Dec 14 20:58:39 2009 +0100
5.3 @@ -0,0 +1,47 @@
5.4 +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5.5 +#
5.6 +# Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
5.7 +#
5.8 +# The contents of this file are subject to the terms of either the GNU
5.9 +# General Public License Version 2 only ("GPL") or the Common
5.10 +# Development and Distribution License("CDDL") (collectively, the
5.11 +# "License"). You may not use this file except in compliance with the
5.12 +# License. You can obtain a copy of the License at
5.13 +# http://www.netbeans.org/cddl-gplv2.html
5.14 +# or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
5.15 +# specific language governing permissions and limitations under the
5.16 +# License. When distributing the software, include this License Header
5.17 +# Notice in each file and include the License file at
5.18 +# nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
5.19 +# particular file as subject to the "Classpath" exception as provided
5.20 +# by Sun in the GPL Version 2 section of the License file that
5.21 +# accompanied this code. If applicable, add the following below the
5.22 +# License Header, with the fields enclosed by brackets [] replaced by
5.23 +# your own identifying information:
5.24 +# "Portions Copyrighted [year] [name of copyright owner]"
5.25 +#
5.26 +# Contributor(s):
5.27 +#
5.28 +# The Original Software is NetBeans. The Initial Developer of the Original
5.29 +# Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
5.30 +# Microsystems, Inc. All Rights Reserved.
5.31 +#
5.32 +# If you wish your version of this file to be governed by only the CDDL
5.33 +# or only the GPL Version 2, indicate your decision by adding
5.34 +# "[Contributor] elects to include this software in this distribution
5.35 +# under the [CDDL or GPL Version 2] license." If you do not indicate a
5.36 +# single choice of license, a recipient has the option to distribute
5.37 +# your version of this file under either the CDDL, the GPL Version 2 or
5.38 +# to extend the choice of license to its licensees as provided above.
5.39 +# However, if you add GPL Version 2 code and therefore, elected the GPL
5.40 +# Version 2 license, then the option applies only if the new code is
5.41 +# made subject to such option by the copyright holder.
5.42 +
5.43 +module.jar.dir=lib
5.44 +javac.source=1.5
5.45 +javac.compilerargs=-Xlint -Xlint:-serial
5.46 +spec.version.base=8.0.0
5.47 +
5.48 +
5.49 +javadoc.arch=${basedir}/arch.xml
5.50 +javadoc.apichanges=${basedir}/apichanges.xml
6.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
6.2 +++ b/openide.util.lookup/nbproject/project.xml Mon Dec 14 20:58:39 2009 +0100
6.3 @@ -0,0 +1,28 @@
6.4 +<?xml version="1.0" encoding="UTF-8"?>
6.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
6.6 + <type>org.netbeans.modules.apisupport.project</type>
6.7 + <configuration>
6.8 + <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
6.9 + <code-name-base>org.openide.util.lookup</code-name-base>
6.10 + <module-dependencies/>
6.11 + <test-dependencies>
6.12 + <test-type>
6.13 + <name>unit</name>
6.14 + <test-dependency>
6.15 + <code-name-base>org.netbeans.libs.junit4</code-name-base>
6.16 + <compile-dependency/>
6.17 + </test-dependency>
6.18 + <test-dependency>
6.19 + <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
6.20 + <recursive/>
6.21 + <compile-dependency/>
6.22 + </test-dependency>
6.23 + </test-type>
6.24 + </test-dependencies>
6.25 + <public-packages>
6.26 + <package>org.openide.util</package>
6.27 + <package>org.openide.util.lookup</package>
6.28 + </public-packages>
6.29 + </data>
6.30 + </configuration>
6.31 +</project>
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/openide.util.lookup/src/META-INF/services/javax.annotation.processing.Processor Mon Dec 14 20:58:39 2009 +0100
7.3 @@ -0,0 +1,1 @@
7.4 +org.netbeans.modules.openide.util.ServiceProviderProcessor
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/AbstractServiceProviderProcessor.java Mon Dec 14 20:58:39 2009 +0100
8.3 @@ -0,0 +1,289 @@
8.4 +/*
8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
8.6 + *
8.7 + * Copyright 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 + * If you wish your version of this file to be governed by only the CDDL
8.28 + * or only the GPL Version 2, indicate your decision by adding
8.29 + * "[Contributor] elects to include this software in this distribution
8.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
8.31 + * single choice of license, a recipient has the option to distribute
8.32 + * your version of this file under either the CDDL, the GPL Version 2 or
8.33 + * to extend the choice of license to its licensees as provided above.
8.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
8.35 + * Version 2 license, then the option applies only if the new code is
8.36 + * made subject to such option by the copyright holder.
8.37 + *
8.38 + * Contributor(s):
8.39 + *
8.40 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
8.41 + */
8.42 +
8.43 +package org.netbeans.modules.openide.util;
8.44 +
8.45 +import java.io.BufferedReader;
8.46 +import java.io.FileNotFoundException;
8.47 +import java.io.IOException;
8.48 +import java.io.InputStream;
8.49 +import java.io.InputStreamReader;
8.50 +import java.io.OutputStream;
8.51 +import java.io.OutputStreamWriter;
8.52 +import java.io.PrintWriter;
8.53 +import java.lang.annotation.Annotation;
8.54 +import java.util.ArrayList;
8.55 +import java.util.HashMap;
8.56 +import java.util.List;
8.57 +import java.util.Map;
8.58 +import java.util.Set;
8.59 +import java.util.WeakHashMap;
8.60 +import javax.annotation.processing.AbstractProcessor;
8.61 +import javax.annotation.processing.ProcessingEnvironment;
8.62 +import javax.annotation.processing.RoundEnvironment;
8.63 +import javax.lang.model.element.AnnotationMirror;
8.64 +import javax.lang.model.element.AnnotationValue;
8.65 +import javax.lang.model.element.Element;
8.66 +import javax.lang.model.element.ExecutableElement;
8.67 +import javax.lang.model.element.Modifier;
8.68 +import javax.lang.model.element.TypeElement;
8.69 +import javax.lang.model.type.TypeMirror;
8.70 +import javax.lang.model.util.ElementFilter;
8.71 +import javax.tools.Diagnostic.Kind;
8.72 +import javax.tools.FileObject;
8.73 +import javax.tools.StandardLocation;
8.74 +
8.75 +/**
8.76 + * Infrastructure for generating {@code META-INF/services/*} and
8.77 + * {@code META-INF/namedservices/*} registrations from annotations.
8.78 + */
8.79 +public abstract class AbstractServiceProviderProcessor extends AbstractProcessor {
8.80 +
8.81 + private final Map<ProcessingEnvironment,Map<String,List<String>>> outputFilesByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<String>>>();
8.82 + private final Map<ProcessingEnvironment,Map<String,List<Element>>> originatingElementsByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<Element>>>();
8.83 + private final Map<TypeElement,Boolean> verifiedClasses = new WeakHashMap<TypeElement,Boolean>();
8.84 +
8.85 + /** For access by subclasses. */
8.86 + protected AbstractServiceProviderProcessor() {}
8.87 +
8.88 + public @Override final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
8.89 + if (roundEnv.errorRaised()) {
8.90 + return false;
8.91 + }
8.92 + if (roundEnv.processingOver()) {
8.93 + writeServices();
8.94 + outputFilesByProcessor.clear();
8.95 + originatingElementsByProcessor.clear();
8.96 + return true;
8.97 + } else {
8.98 + return handleProcess(annotations, roundEnv);
8.99 + }
8.100 + }
8.101 +
8.102 + /**
8.103 + * The regular body of {@link #process}.
8.104 + * Called during regular rounds if there are no outstanding errors.
8.105 + * In the last round, one of the processors will write out generated registrations.
8.106 + * @param annotations as in {@link #process}
8.107 + * @param roundEnv as in {@link #process}
8.108 + * @return as in {@link #process}
8.109 + */
8.110 + protected abstract boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);
8.111 +
8.112 + /**
8.113 + * Register a service.
8.114 + * If the class does not have an appropriate signature, an error will be printed and the registration skipped.
8.115 + * @param clazz the service implementation type
8.116 + * @param annotation the (top-level) annotation registering the service, for diagnostic purposes
8.117 + * @param type the type to which the implementation must be assignable
8.118 + * @param path a path under which to register, or "" if inapplicable
8.119 + * @param position a position at which to register, or {@link Integer#MAX_VALUE} to skip
8.120 + * @param supersedes possibly empty list of implementation to supersede
8.121 + */
8.122 + protected final void register(TypeElement clazz, Class<? extends Annotation> annotation,
8.123 + TypeMirror type, String path, int position, String[] supersedes) {
8.124 + Boolean verify = verifiedClasses.get(clazz);
8.125 + if (verify == null) {
8.126 + verify = verifyServiceProviderSignature(clazz, annotation);
8.127 + verifiedClasses.put(clazz, verify);
8.128 + }
8.129 + if (!verify) {
8.130 + return;
8.131 + }
8.132 + String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
8.133 + String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
8.134 + if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
8.135 + AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
8.136 + processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
8.137 + clazz, ann, findAnnotationValue(ann, "service"));
8.138 + return;
8.139 + }
8.140 + processingEnv.getMessager().printMessage(Kind.NOTE,
8.141 + impl + " to be registered as a " + xface + (path.length() > 0 ? " under " + path : ""));
8.142 + String rsrc = (path.length() > 0 ? "META-INF/namedservices/" + path + "/" : "META-INF/services/") + xface;
8.143 + {
8.144 + Map<String,List<Element>> originatingElements = originatingElementsByProcessor.get(processingEnv);
8.145 + if (originatingElements == null) {
8.146 + originatingElements = new HashMap<String,List<Element>>();
8.147 + originatingElementsByProcessor.put(processingEnv, originatingElements);
8.148 + }
8.149 + List<Element> origEls = originatingElements.get(rsrc);
8.150 + if (origEls == null) {
8.151 + origEls = new ArrayList<Element>();
8.152 + originatingElements.put(rsrc, origEls);
8.153 + }
8.154 + origEls.add(clazz);
8.155 + }
8.156 + Map<String,List<String>> outputFiles = outputFilesByProcessor.get(processingEnv);
8.157 + if (outputFiles == null) {
8.158 + outputFiles = new HashMap<String,List<String>>();
8.159 + outputFilesByProcessor.put(processingEnv, outputFiles);
8.160 + }
8.161 + List<String> lines = outputFiles.get(rsrc);
8.162 + if (lines == null) {
8.163 + lines = new ArrayList<String>();
8.164 + try {
8.165 + try {
8.166 + FileObject in = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", rsrc);
8.167 + in.openInputStream().close();
8.168 + processingEnv.getMessager().printMessage(Kind.ERROR,
8.169 + "Cannot generate " + rsrc + " because it already exists in sources: " + in.toUri());
8.170 + return;
8.171 + } catch (FileNotFoundException x) {
8.172 + // Good.
8.173 + }
8.174 + try {
8.175 + FileObject in = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", rsrc);
8.176 + InputStream is = in.openInputStream();
8.177 + try {
8.178 + BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
8.179 + String line;
8.180 + while ((line = r.readLine()) != null) {
8.181 + lines.add(line);
8.182 + }
8.183 + } finally {
8.184 + is.close();
8.185 + }
8.186 + } catch (FileNotFoundException x) {
8.187 + // OK, created for the first time
8.188 + }
8.189 + } catch (IOException x) {
8.190 + processingEnv.getMessager().printMessage(Kind.ERROR, x.toString());
8.191 + return;
8.192 + }
8.193 + outputFiles.put(rsrc, lines);
8.194 + }
8.195 + int idx = lines.indexOf(impl);
8.196 + if (idx != -1) {
8.197 + lines.remove(idx);
8.198 + while (lines.size() > idx && lines.get(idx).matches("#position=.+|#-.+")) {
8.199 + lines.remove(idx);
8.200 + }
8.201 + }
8.202 + lines.add(impl);
8.203 + if (position != Integer.MAX_VALUE) {
8.204 + lines.add("#position=" + position);
8.205 + }
8.206 + for (String exclude : supersedes) {
8.207 + lines.add("#-" + exclude);
8.208 + }
8.209 + }
8.210 +
8.211 + /**
8.212 + * @param element a source element
8.213 + * @param annotation a type of annotation
8.214 + * @return the instance of that annotation on the element, or null if not found
8.215 + */
8.216 + private AnnotationMirror findAnnotationMirror(Element element, Class<? extends Annotation> annotation) {
8.217 + for (AnnotationMirror ann : element.getAnnotationMirrors()) {
8.218 + if (processingEnv.getElementUtils().getBinaryName((TypeElement) ann.getAnnotationType().asElement()).
8.219 + contentEquals(annotation.getName())) {
8.220 + return ann;
8.221 + }
8.222 + }
8.223 + return null;
8.224 + }
8.225 +
8.226 + /**
8.227 + * @param annotation an annotation instance (null permitted)
8.228 + * @param name the name of an attribute of that annotation
8.229 + * @return the corresponding value if found
8.230 + */
8.231 + private AnnotationValue findAnnotationValue(AnnotationMirror annotation, String name) {
8.232 + if (annotation != null) {
8.233 + for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()) {
8.234 + if (entry.getKey().getSimpleName().contentEquals(name)) {
8.235 + return entry.getValue();
8.236 + }
8.237 + }
8.238 + }
8.239 + return null;
8.240 + }
8.241 +
8.242 + private final boolean verifyServiceProviderSignature(TypeElement clazz, Class<? extends Annotation> annotation) {
8.243 + AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
8.244 + if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
8.245 + processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must be public", clazz, ann);
8.246 + return false;
8.247 + }
8.248 + if (clazz.getModifiers().contains(Modifier.ABSTRACT)) {
8.249 + processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must not be abstract", clazz, ann);
8.250 + return false;
8.251 + }
8.252 + {
8.253 + boolean hasDefaultCtor = false;
8.254 + for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
8.255 + if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) {
8.256 + hasDefaultCtor = true;
8.257 + break;
8.258 + }
8.259 + }
8.260 + if (!hasDefaultCtor) {
8.261 + processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must have a public no-argument constructor", clazz, ann);
8.262 + return false;
8.263 + }
8.264 + }
8.265 + return true;
8.266 + }
8.267 +
8.268 + private void writeServices() {
8.269 + for (Map.Entry<ProcessingEnvironment,Map<String,List<String>>> outputFiles : outputFilesByProcessor.entrySet()) {
8.270 + for (Map.Entry<String, List<String>> entry : outputFiles.getValue().entrySet()) {
8.271 + try {
8.272 + FileObject out = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", entry.getKey(),
8.273 + originatingElementsByProcessor.get(outputFiles.getKey()).get(entry.getKey()).toArray(new Element[0]));
8.274 + OutputStream os = out.openOutputStream();
8.275 + try {
8.276 + PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
8.277 + for (String line : entry.getValue()) {
8.278 + w.println(line);
8.279 + }
8.280 + w.flush();
8.281 + w.close();
8.282 + } finally {
8.283 + os.close();
8.284 + }
8.285 + } catch (IOException x) {
8.286 + processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
8.287 + }
8.288 + }
8.289 + }
8.290 + }
8.291 +
8.292 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/ActiveQueue.java Mon Dec 14 20:58:39 2009 +0100
9.3 @@ -0,0 +1,108 @@
9.4 +package org.netbeans.modules.openide.util;
9.5 +
9.6 +import java.lang.ref.Reference;
9.7 +import java.lang.ref.ReferenceQueue;
9.8 +import java.util.logging.Level;
9.9 +import java.util.logging.Logger;
9.10 +
9.11 +/**
9.12 + * Implementation of the active reference queue.
9.13 + */
9.14 +public final class ActiveQueue extends ReferenceQueue<Object> implements Runnable {
9.15 +
9.16 + private static final Logger LOGGER = Logger.getLogger(ActiveQueue.class.getName().replace('$', '.'));
9.17 + private static ActiveQueue activeReferenceQueue;
9.18 +
9.19 + /** number of known outstanding references */
9.20 + private int count;
9.21 + private boolean deprecated;
9.22 +
9.23 + ActiveQueue(boolean deprecated) {
9.24 + super();
9.25 + this.deprecated = deprecated;
9.26 + }
9.27 +
9.28 + public static synchronized ReferenceQueue<Object> queue() {
9.29 + if (activeReferenceQueue == null) {
9.30 + activeReferenceQueue = new ActiveQueue(false);
9.31 + }
9.32 +
9.33 + activeReferenceQueue.ping();
9.34 +
9.35 + return activeReferenceQueue;
9.36 + }
9.37 +
9.38 + @Override
9.39 + public Reference<Object> poll() {
9.40 + throw new UnsupportedOperationException();
9.41 + }
9.42 +
9.43 + @Override
9.44 + public Reference<Object> remove(long timeout) throws IllegalArgumentException, InterruptedException {
9.45 + throw new InterruptedException();
9.46 + }
9.47 +
9.48 + @Override
9.49 + public Reference<Object> remove() throws InterruptedException {
9.50 + throw new InterruptedException();
9.51 + }
9.52 +
9.53 + public void run() {
9.54 + while (true) {
9.55 + try {
9.56 + Reference<?> ref = super.remove(0);
9.57 + LOGGER.finer("dequeued reference");
9.58 + if (!(ref instanceof Runnable)) {
9.59 + LOGGER.warning("A reference not implementing runnable has been added to the Utilities.activeReferenceQueue(): " + ref.getClass());
9.60 + continue;
9.61 + }
9.62 + if (deprecated) {
9.63 + LOGGER.warning("Utilities.ACTIVE_REFERENCE_QUEUE has been deprecated for " + ref.getClass() + " use Utilities.activeReferenceQueue");
9.64 + }
9.65 + // do the cleanup
9.66 + try {
9.67 + ((Runnable) ref).run();
9.68 + } catch (ThreadDeath td) {
9.69 + throw td;
9.70 + } catch (Throwable t) {
9.71 + // Should not happen.
9.72 + // If it happens, it is a bug in client code, notify!
9.73 + LOGGER.log(Level.WARNING, null, t);
9.74 + } finally {
9.75 + // to allow GC
9.76 + ref = null;
9.77 + }
9.78 + } catch (InterruptedException ex) {
9.79 + // Can happen during VM shutdown, it seems. Ignore.
9.80 + continue;
9.81 + }
9.82 + synchronized (this) {
9.83 + assert count > 0;
9.84 + count--;
9.85 + if (count == 0) {
9.86 + // We have processed all we have to process (for now at least).
9.87 + // Could be restarted later if ping() called again.
9.88 + // This could also happen in case someone called queue() once and tried
9.89 + // to use it for several references; in that case run() might never be called on
9.90 + // the later ones to be collected. Can't really protect against that situation.
9.91 + // See issue #86625 for details.
9.92 + LOGGER.fine("stopping thread");
9.93 + break;
9.94 + }
9.95 + }
9.96 + }
9.97 + }
9.98 +
9.99 + synchronized void ping() {
9.100 + if (count == 0) {
9.101 + Thread t = new Thread(this, "Active Reference Queue Daemon");
9.102 + t.setPriority(Thread.MIN_PRIORITY);
9.103 + t.setDaemon(true);
9.104 + t.start();
9.105 + LOGGER.fine("starting thread");
9.106 + } else {
9.107 + LOGGER.finer("enqueuing reference");
9.108 + }
9.109 + count++;
9.110 + }
9.111 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/NamedServicesProvider.java Mon Dec 14 20:58:39 2009 +0100
10.3 @@ -0,0 +1,81 @@
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.
10.31 + *
10.32 + * Portions Copyrighted 2006 Sun Microsystems, Inc.
10.33 + */
10.34 +
10.35 +package org.netbeans.modules.openide.util;
10.36 +
10.37 +import java.lang.ref.Reference;
10.38 +import java.lang.ref.WeakReference;
10.39 +import java.util.Collections;
10.40 +import java.util.HashMap;
10.41 +import java.util.Map;
10.42 +import org.openide.util.Lookup;
10.43 +import org.openide.util.lookup.Lookups;
10.44 +
10.45 +/** Interface for core/startup and core/settings
10.46 + * to provide lookup over system filesystem.
10.47 + *
10.48 + * @author Jaroslav Tulach
10.49 + */
10.50 +public abstract class NamedServicesProvider {
10.51 +
10.52 + private static final Map<String,Reference<Lookup>> map = Collections.synchronizedMap(new HashMap<String,Reference<Lookup>>());
10.53 +
10.54 + public abstract Lookup create(String path);
10.55 +
10.56 + public static Lookup find(String path) {
10.57 + if (!path.endsWith("/")) {
10.58 + path = path + "/";
10.59 + }
10.60 +
10.61 + Reference<Lookup> ref = map.get(path);
10.62 + Lookup lkp = ref == null ? null : ref.get();
10.63 + if (lkp != null) {
10.64 + return lkp;
10.65 + }
10.66 + NamedServicesProvider prov = Lookup.getDefault().lookup(NamedServicesProvider.class);
10.67 + if (prov != null && /* avoid stack overflow during initialization */ !path.startsWith(URLStreamHandlerRegistrationProcessor.REGISTRATION_PREFIX)) {
10.68 + lkp = prov.create(path);
10.69 + } else {
10.70 + ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
10.71 + if (l == null) {
10.72 + l = Thread.currentThread().getContextClassLoader();
10.73 + if (l == null) {
10.74 + l = NamedServicesProvider.class.getClassLoader();
10.75 + }
10.76 + }
10.77 + lkp = Lookups.metaInfServices(l, "META-INF/namedservices/" + path);
10.78 + }
10.79 +
10.80 + map.put(path, new WeakReference<Lookup>(lkp));
10.81 + return lkp;
10.82 + }
10.83 +
10.84 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java Mon Dec 14 20:58:39 2009 +0100
11.3 @@ -0,0 +1,173 @@
11.4 +/*
11.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
11.6 + *
11.7 + * Copyright 2008 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 + * If you wish your version of this file to be governed by only the CDDL
11.28 + * or only the GPL Version 2, indicate your decision by adding
11.29 + * "[Contributor] elects to include this software in this distribution
11.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
11.31 + * single choice of license, a recipient has the option to distribute
11.32 + * your version of this file under either the CDDL, the GPL Version 2 or
11.33 + * to extend the choice of license to its licensees as provided above.
11.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
11.35 + * Version 2 license, then the option applies only if the new code is
11.36 + * made subject to such option by the copyright holder.
11.37 + *
11.38 + * Contributor(s):
11.39 + *
11.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
11.41 + */
11.42 +
11.43 +package org.netbeans.modules.openide.util;
11.44 +
11.45 +import java.lang.annotation.Annotation;
11.46 +import java.util.Arrays;
11.47 +import java.util.Collection;
11.48 +import java.util.Collections;
11.49 +import java.util.HashSet;
11.50 +import java.util.LinkedList;
11.51 +import java.util.List;
11.52 +import java.util.Set;
11.53 +import javax.annotation.processing.Completion;
11.54 +import javax.annotation.processing.RoundEnvironment;
11.55 +import javax.annotation.processing.SupportedSourceVersion;
11.56 +import javax.lang.model.SourceVersion;
11.57 +import javax.lang.model.element.AnnotationMirror;
11.58 +import javax.lang.model.element.Element;
11.59 +import javax.lang.model.element.ExecutableElement;
11.60 +import javax.lang.model.element.TypeElement;
11.61 +import javax.lang.model.type.MirroredTypeException;
11.62 +import javax.lang.model.type.TypeKind;
11.63 +import javax.lang.model.type.TypeMirror;
11.64 +import org.openide.util.lookup.ServiceProvider;
11.65 +import org.openide.util.lookup.ServiceProviders;
11.66 +
11.67 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
11.68 +public class ServiceProviderProcessor extends AbstractServiceProviderProcessor {
11.69 +
11.70 + public @Override Set<String> getSupportedAnnotationTypes() {
11.71 + return new HashSet<String>(Arrays.asList(
11.72 + ServiceProvider.class.getCanonicalName(),
11.73 + ServiceProviders.class.getCanonicalName()
11.74 + ));
11.75 + }
11.76 +
11.77 + /** public for ServiceLoader */
11.78 + public ServiceProviderProcessor() {}
11.79 +
11.80 + protected boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
11.81 + for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
11.82 + TypeElement clazz = (TypeElement) el;
11.83 + ServiceProvider sp = clazz.getAnnotation(ServiceProvider.class);
11.84 + register(clazz, ServiceProvider.class, sp);
11.85 + }
11.86 + for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProviders.class)) {
11.87 + TypeElement clazz = (TypeElement) el;
11.88 + ServiceProviders spp = clazz.getAnnotation(ServiceProviders.class);
11.89 + for (ServiceProvider sp : spp.value()) {
11.90 + register(clazz, ServiceProviders.class, sp);
11.91 + }
11.92 + }
11.93 + return true;
11.94 + }
11.95 +
11.96 + private void register(TypeElement clazz, Class<? extends Annotation> annotation, ServiceProvider svc) {
11.97 + try {
11.98 + svc.service();
11.99 + assert false;
11.100 + return;
11.101 + } catch (MirroredTypeException e) {
11.102 + register(clazz, annotation, e.getTypeMirror(), svc.path(), svc.position(), svc.supersedes());
11.103 + }
11.104 + }
11.105 +
11.106 + @Override
11.107 + public Iterable<? extends Completion> getCompletions(Element annotated, AnnotationMirror annotation, ExecutableElement attr, String userText) {
11.108 + if (processingEnv == null || annotated == null || !annotated.getKind().isClass()) {
11.109 + return Collections.emptyList();
11.110 + }
11.111 +
11.112 + if ( annotation == null
11.113 + || !"org.openide.util.lookup.ServiceProvider".contentEquals(((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName())) {
11.114 + return Collections.emptyList();
11.115 + }
11.116 +
11.117 + if (!"service".contentEquals(attr.getSimpleName())) {
11.118 + return Collections.emptyList();
11.119 + }
11.120 +
11.121 + TypeElement jlObject = processingEnv.getElementUtils().getTypeElement("java.lang.Object");
11.122 +
11.123 + if (jlObject == null) {
11.124 + return Collections.emptyList();
11.125 + }
11.126 +
11.127 + Collection<Completion> result = new LinkedList<Completion>();
11.128 + List<TypeElement> toProcess = new LinkedList<TypeElement>();
11.129 +
11.130 + toProcess.add((TypeElement) annotated);
11.131 +
11.132 + while (!toProcess.isEmpty()) {
11.133 + TypeElement c = toProcess.remove(0);
11.134 +
11.135 + result.add(new TypeCompletion(c.getQualifiedName().toString() + ".class"));
11.136 +
11.137 + List<TypeMirror> parents = new LinkedList<TypeMirror>();
11.138 +
11.139 + parents.add(c.getSuperclass());
11.140 + parents.addAll(c.getInterfaces());
11.141 +
11.142 + for (TypeMirror tm : parents) {
11.143 + if (tm == null || tm.getKind() != TypeKind.DECLARED) {
11.144 + continue;
11.145 + }
11.146 +
11.147 + TypeElement type = (TypeElement) processingEnv.getTypeUtils().asElement(tm);
11.148 +
11.149 + if (!jlObject.equals(type)) {
11.150 + toProcess.add(type);
11.151 + }
11.152 + }
11.153 + }
11.154 +
11.155 + return result;
11.156 + }
11.157 +
11.158 + private static final class TypeCompletion implements Completion {
11.159 +
11.160 + private final String type;
11.161 +
11.162 + public TypeCompletion(String type) {
11.163 + this.type = type;
11.164 + }
11.165 +
11.166 + public String getValue() {
11.167 + return type;
11.168 + }
11.169 +
11.170 + public String getMessage() {
11.171 + return null;
11.172 + }
11.173 +
11.174 + }
11.175 +
11.176 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/openide.util.lookup/src/org/openide/util/Lookup.java Mon Dec 14 20:58:39 2009 +0100
12.3 @@ -0,0 +1,544 @@
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 +
12.45 +package org.openide.util;
12.46 +
12.47 +import java.util.ArrayList;
12.48 +import java.util.Collection;
12.49 +import java.util.Collections;
12.50 +import java.util.Iterator;
12.51 +import java.util.List;
12.52 +import java.util.Set;
12.53 +import org.openide.util.lookup.Lookups;
12.54 +import org.openide.util.lookup.ProxyLookup;
12.55 +import org.openide.util.lookup.ServiceProvider;
12.56 +
12.57 +/**
12.58 + * A general registry permitting clients to find instances of services
12.59 + * (implementation of a given interface).
12.60 + * This class is inspired by the
12.61 + * <a href="http://www.jini.org/">Jini</a>
12.62 + * registration and lookup mechanism. The difference is that the methods do
12.63 + * not throw checked exceptions (as they usually work only locally and not over the network)
12.64 + * and that the Lookup API concentrates on the lookup, not on the registration
12.65 + * (although {@link Lookup#getDefault} is strongly encouraged to support
12.66 + * {@link Lookups#metaInfServices} for registration in addition to whatever
12.67 + * else it decides to support).
12.68 + * <p>
12.69 + * For a general talk about the idea behind the lookup pattern please see
12.70 + * <UL>
12.71 + * <LI><a href="lookup/doc-files/index.html">The Solution to Communication Between Components</a>
12.72 + * page
12.73 + * <LI>the introduction to the <a href="lookup/doc-files/lookup-api.html">lookup API via
12.74 + * use cases</a>
12.75 + * <LI>the examples of <a href="lookup/doc-files/lookup-spi.html">how to write your own lookup</a>
12.76 + * </UL>
12.77 + *
12.78 + * @see org.openide.util.lookup.AbstractLookup
12.79 + * @see Lookups
12.80 + * @see LookupListener
12.81 + * @see LookupEvent
12.82 + * @author Jaroslav Tulach
12.83 + */
12.84 +public abstract class Lookup {
12.85 + /** A dummy lookup that never returns any results.
12.86 + */
12.87 + public static final Lookup EMPTY = new Empty();
12.88 +
12.89 + /** default instance */
12.90 + private static Lookup defaultLookup;
12.91 +
12.92 + /** Empty constructor for use by subclasses. */
12.93 + public Lookup() {
12.94 + }
12.95 +
12.96 + /** Static method to obtain the global lookup in the whole system.
12.97 + * The actual returned implementation can be different in different
12.98 + * systems, but the default one is based on
12.99 + * {@link org.openide.util.lookup.Lookups#metaInfServices}
12.100 + * with the context classloader of the first caller. Each system is
12.101 + * adviced to honor this and include some form of <code>metaInfServices</code>
12.102 + * implementation in the returned lookup as usage of <code>META-INF/services</code>
12.103 + * is a JDK standard.
12.104 + *
12.105 + * @return the global lookup in the system
12.106 + * @see ServiceProvider
12.107 + */
12.108 + public static synchronized Lookup getDefault() {
12.109 + if (defaultLookup != null) {
12.110 + return defaultLookup;
12.111 + }
12.112 +
12.113 + // You can specify a Lookup impl using a system property if you like.
12.114 + String className = System.getProperty("org.openide.util.Lookup" // NOI18N
12.115 + );
12.116 +
12.117 + if ("-".equals(className)) { // NOI18N
12.118 +
12.119 + // Suppress even MetaInfServicesLookup.
12.120 + return EMPTY;
12.121 + }
12.122 +
12.123 + ClassLoader l = Thread.currentThread().getContextClassLoader();
12.124 +
12.125 + try {
12.126 + if (className != null) {
12.127 + defaultLookup = (Lookup) Class.forName(className, true, l).newInstance();
12.128 +
12.129 + return defaultLookup;
12.130 + }
12.131 + } catch (Exception e) {
12.132 + // do not use ErrorManager because we are in the startup code
12.133 + // and ErrorManager might not be ready
12.134 + e.printStackTrace();
12.135 + }
12.136 +
12.137 + // OK, none specified (successfully) in a system property.
12.138 + // Try MetaInfServicesLookup as a default, which may also
12.139 + // have a org.openide.util.Lookup line specifying the lookup.
12.140 + Lookup misl = Lookups.metaInfServices(l);
12.141 + defaultLookup = misl.lookup(Lookup.class);
12.142 +
12.143 + if (defaultLookup != null) {
12.144 + return defaultLookup;
12.145 + }
12.146 +
12.147 + // You may also specify a Lookup.Provider.
12.148 + Lookup.Provider prov = misl.lookup(Lookup.Provider.class);
12.149 +
12.150 + if (prov != null) {
12.151 + defaultLookup = Lookups.proxy(prov);
12.152 +
12.153 + return defaultLookup;
12.154 + }
12.155 +
12.156 + DefLookup def = new DefLookup();
12.157 + def.init(l, misl, false);
12.158 + defaultLookup = def;
12.159 + def.init(l, misl, true);
12.160 + return defaultLookup;
12.161 + }
12.162 +
12.163 + private static final class DefLookup extends ProxyLookup {
12.164 + public DefLookup() {
12.165 + super(new Lookup[0]);
12.166 + }
12.167 +
12.168 + public void init(ClassLoader loader, Lookup metaInfLookup, boolean addPath) {
12.169 + // Had no such line, use simple impl.
12.170 + // It does however need to have ClassLoader available or many things will break.
12.171 + // Use the thread context classloader in effect now.
12.172 + Lookup clLookup = Lookups.singleton(loader);
12.173 + List<Lookup> arr = new ArrayList<Lookup>();
12.174 + arr.add(metaInfLookup);
12.175 + arr.add(clLookup);
12.176 + String paths = System.getProperty("org.openide.util.Lookup.paths"); // NOI18N
12.177 + if (addPath && paths != null) {
12.178 + for (String p : paths.split(":")) { // NOI18N
12.179 + arr.add(Lookups.forPath(p));
12.180 + }
12.181 + }
12.182 + setLookups(arr.toArray(new Lookup[0]));
12.183 + }
12.184 + }
12.185 +
12.186 + /** Called from MockServices to reset default lookup in case services change
12.187 + */
12.188 + private static void resetDefaultLookup() {
12.189 + if (defaultLookup instanceof DefLookup) {
12.190 + DefLookup def = (DefLookup)defaultLookup;
12.191 + ClassLoader l = Thread.currentThread().getContextClassLoader();
12.192 + def.init(l, Lookups.metaInfServices(l), true);
12.193 + }
12.194 + }
12.195 +
12.196 + /** Look up an object matching a given interface.
12.197 + * This is the simplest method to use.
12.198 + * If more than one object matches, the first will be returned.
12.199 + * The template class may be a class or interface; the instance is
12.200 + * guaranteed to be assignable to it.
12.201 + *
12.202 + * @param clazz class of the object we are searching for
12.203 + * @return an object implementing the given class or <code>null</code> if no such
12.204 + * implementation is found
12.205 + */
12.206 + public abstract <T> T lookup(Class<T> clazz);
12.207 +
12.208 + /** The general lookup method. Callers can get list of all instances and classes
12.209 + * that match the given <code>template</code>, request more info about
12.210 + * them in form of {@link Lookup.Item} and attach a listener to
12.211 + * this be notified about changes. The general interface does not
12.212 + * specify whether subsequent calls with the same template produce new
12.213 + * instance of the {@link Lookup.Result} or return shared instance. The
12.214 + * prefered behaviour however is to return shared one.
12.215 + *
12.216 + * @param template a template describing the services to look for
12.217 + * @return an object containing the results
12.218 + */
12.219 + public abstract <T> Result<T> lookup(Template<T> template);
12.220 +
12.221 + /** Look up the first item matching a given template.
12.222 + * Includes not only the instance but other associated information.
12.223 + * @param template the template to check
12.224 + * @return a matching item or <code>null</code>
12.225 + *
12.226 + * @since 1.8
12.227 + */
12.228 + public <T> Item<T> lookupItem(Template<T> template) {
12.229 + Result<T> res = lookup(template);
12.230 + Iterator<? extends Item<T>> it = res.allItems().iterator();
12.231 + return it.hasNext() ? it.next() : null;
12.232 + }
12.233 +
12.234 + /**
12.235 + * Find a result corresponding to a given class.
12.236 + * Equivalent to calling {@link #lookup(Lookup.Template)} but slightly more convenient.
12.237 + * Subclasses may override this method to produce the same semantics more efficiently.
12.238 + * @param clazz the supertype of the result
12.239 + * @return a live object representing instances of that type
12.240 + * @since org.openide.util 6.10
12.241 + */
12.242 + public <T> Lookup.Result<T> lookupResult(Class<T> clazz) {
12.243 + return lookup(new Lookup.Template<T>(clazz));
12.244 + }
12.245 +
12.246 + /**
12.247 + * Find all instances corresponding to a given class.
12.248 + * Equivalent to calling {@link #lookupResult} and asking for {@link Lookup.Result#allInstances} but slightly more convenient.
12.249 + * Subclasses may override this method to produce the same semantics more efficiently.
12.250 + * <div class="nonnormative">
12.251 + * <p>Example usage:</p>
12.252 + * <pre>
12.253 + * for (MyService svc : Lookup.getDefault().lookupAll(MyService.class)) {
12.254 + * svc.useMe();
12.255 + * }
12.256 + * </pre>
12.257 + * </div>
12.258 + * @param clazz the supertype of the result
12.259 + * @return all currently available instances of that type
12.260 + * @since org.openide.util 6.10
12.261 + */
12.262 + public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
12.263 + return lookupResult(clazz).allInstances();
12.264 + }
12.265 +
12.266 + /**
12.267 + * Objects implementing interface Lookup.Provider are capable of
12.268 + * and willing to provide a lookup (usually bound to the object).
12.269 + * @since 3.6
12.270 + */
12.271 + public interface Provider {
12.272 + /**
12.273 + * Returns lookup associated with the object.
12.274 + * @return fully initialized lookup instance provided by this object
12.275 + */
12.276 + Lookup getLookup();
12.277 + }
12.278 +
12.279 + /*
12.280 + * I expect this class to grow in the future, but for now, it is
12.281 + * enough to start with something simple.
12.282 + */
12.283 +
12.284 + /** Template defining a pattern to filter instances by.
12.285 + */
12.286 + public static final class Template<T> extends Object {
12.287 + /** cached hash code */
12.288 + private int hashCode;
12.289 +
12.290 + /** type of the service */
12.291 + private Class<T> type;
12.292 +
12.293 + /** identity to search for */
12.294 + private String id;
12.295 +
12.296 + /** instance to search for */
12.297 + private T instance;
12.298 +
12.299 + /** General template to find all possible instances.
12.300 + * @deprecated Use <code>new Template (Object.class)</code> which
12.301 + * is going to be better typed with JDK1.5 templates and should produce
12.302 + * the same result.
12.303 + */
12.304 + @Deprecated
12.305 + public Template() {
12.306 + this(null);
12.307 + }
12.308 +
12.309 + /** Create a simple template matching by class.
12.310 + * @param type the class of service we are looking for (subclasses will match)
12.311 + */
12.312 + public Template(Class<T> type) {
12.313 + this(type, null, null);
12.314 + }
12.315 +
12.316 + /** Constructor to create new template.
12.317 + * @param type the class of service we are looking for or <code>null</code> to leave unspecified
12.318 + * @param id the ID of the item/service we are looking for or <code>null</code> to leave unspecified
12.319 + * @param instance a specific known instance to look for or <code>null</code> to leave unspecified
12.320 + */
12.321 + public Template(Class<T> type, String id, T instance) {
12.322 + this.type = extractType(type);
12.323 + this.id = id;
12.324 + this.instance = instance;
12.325 + }
12.326 +
12.327 + @SuppressWarnings("unchecked")
12.328 + private Class<T> extractType(Class<T> type) {
12.329 + return (type == null) ? (Class<T>)Object.class : type;
12.330 + }
12.331 +
12.332 + /** Get the class (or superclass or interface) to search for.
12.333 + * If it was not specified in the constructor, <code>Object</code> is used as
12.334 + * this will match any instance.
12.335 + * @return the class to search for
12.336 + */
12.337 + public Class<T> getType() {
12.338 + return type;
12.339 + }
12.340 +
12.341 + /** Get the persistent identifier being searched for, if any.
12.342 + * @return the ID or <code>null</code>
12.343 + * @see Lookup.Item#getId
12.344 + *
12.345 + * @since 1.8
12.346 + */
12.347 + public String getId() {
12.348 + return id;
12.349 + }
12.350 +
12.351 + /** Get the specific instance being searched for, if any.
12.352 + * Most useful for finding an <code>Item</code> when the instance
12.353 + * is already known.
12.354 + *
12.355 + * @return the object to find or <code>null</code>
12.356 + *
12.357 + * @since 1.8
12.358 + */
12.359 + public T getInstance() {
12.360 + return instance;
12.361 + }
12.362 +
12.363 + /* Computes hashcode for this template. The hashcode is cached.
12.364 + * @return hashcode
12.365 + */
12.366 + @Override
12.367 + public int hashCode() {
12.368 + if (hashCode != 0) {
12.369 + return hashCode;
12.370 + }
12.371 +
12.372 + hashCode = ((type == null) ? 1 : type.hashCode()) + ((id == null) ? 2 : id.hashCode()) +
12.373 + ((instance == null) ? 3 : 0);
12.374 +
12.375 + return hashCode;
12.376 + }
12.377 +
12.378 + /* Checks whether two templates represent the same query.
12.379 + * @param obj another template to check
12.380 + * @return true if so, false otherwise
12.381 + */
12.382 + @Override
12.383 + public boolean equals(Object obj) {
12.384 + if (!(obj instanceof Template)) {
12.385 + return false;
12.386 + }
12.387 +
12.388 + Template t = (Template) obj;
12.389 +
12.390 + if (hashCode() != t.hashCode()) {
12.391 + // this is an optimalization - the hashCodes should have been
12.392 + // precomputed
12.393 + return false;
12.394 + }
12.395 +
12.396 + if (type != t.type) {
12.397 + return false;
12.398 + }
12.399 +
12.400 + if (id == null) {
12.401 + if (t.id != null) {
12.402 + return false;
12.403 + }
12.404 + } else {
12.405 + if (!id.equals(t.id)) {
12.406 + return false;
12.407 + }
12.408 + }
12.409 +
12.410 + if (instance == null) {
12.411 + return (t.instance == null);
12.412 + } else {
12.413 + return instance.equals(t.instance);
12.414 + }
12.415 + }
12.416 +
12.417 + /* for debugging */
12.418 + @Override
12.419 + public String toString() {
12.420 + return "Lookup.Template[type=" + type + ",id=" + id + ",instance=" + instance + "]"; // NOI18N
12.421 + }
12.422 + }
12.423 +
12.424 + /** Result of a lookup request.
12.425 + * Allows access to all matching instances at once.
12.426 + * Also permits listening to changes in the result.
12.427 + * Result can contain duplicate items.
12.428 + */
12.429 + public static abstract class Result<T> extends Object {
12.430 + /** Registers a listener that is invoked when there is a possible
12.431 + * change in this result.
12.432 + *
12.433 + * @param l the listener to add
12.434 + */
12.435 + public abstract void addLookupListener(LookupListener l);
12.436 +
12.437 + /** Unregisters a listener previously added.
12.438 + * @param l the listener to remove
12.439 + */
12.440 + public abstract void removeLookupListener(LookupListener l);
12.441 +
12.442 + /** Get all instances in the result. The return value type
12.443 + * should be List instead of Collection, but it is too late to change it.
12.444 + * @return unmodifiable collection of all instances that will never change its content
12.445 + */
12.446 + public abstract Collection<? extends T> allInstances();
12.447 +
12.448 + /** Get all classes represented in the result.
12.449 + * That is, the set of concrete classes
12.450 + * used by instances present in the result.
12.451 + * All duplicate classes will be omitted.
12.452 + * @return unmodifiable set of <code>Class</code> objects that will never change its content
12.453 + *
12.454 + * @since 1.8
12.455 + */
12.456 + public Set<Class<? extends T>> allClasses() {
12.457 + return Collections.emptySet();
12.458 + }
12.459 +
12.460 + /** Get all registered items.
12.461 + * This should include all pairs of instances together
12.462 + * with their classes, IDs, and so on. The return value type
12.463 + * should be List instead of Collection, but it is too late to change it.
12.464 + * @return unmodifiable collection of {@link Lookup.Item} that will never change its content
12.465 + *
12.466 + * @since 1.8
12.467 + */
12.468 + public Collection<? extends Item<T>> allItems() {
12.469 + return Collections.emptyList();
12.470 + }
12.471 + }
12.472 +
12.473 + /** A single item in a lookup result.
12.474 + * This wrapper provides unified access to not just the instance,
12.475 + * but its class, a possible persistent identifier, and so on.
12.476 + *
12.477 + * @since 1.25
12.478 + */
12.479 + public static abstract class Item<T> extends Object {
12.480 + /** Get the instance itself.
12.481 + * @return the instance or null if the instance cannot be created
12.482 + */
12.483 + public abstract T getInstance();
12.484 +
12.485 + /** Get the implementing class of the instance.
12.486 + * @return the class of the item
12.487 + */
12.488 + public abstract Class<? extends T> getType();
12.489 +
12.490 + // XXX can it be null??
12.491 +
12.492 + /** Get a persistent indentifier for the item.
12.493 + * This identifier should uniquely represent the item
12.494 + * within its containing lookup (and if possible within the
12.495 + * global lookup as a whole). For example, it might represent
12.496 + * the source of the instance as a file name. The ID may be
12.497 + * persisted and in a later session used to find the same instance
12.498 + * as was encountered earlier, by means of passing it into a
12.499 + * lookup template.
12.500 + *
12.501 + * @return a string ID of the item
12.502 + */
12.503 + public abstract String getId();
12.504 +
12.505 + /** Get a human presentable name for the item.
12.506 + * This might be used when summarizing all the items found in a
12.507 + * lookup result in some part of a GUI.
12.508 + * @return the string suitable for presenting the object to a user
12.509 + */
12.510 + public abstract String getDisplayName();
12.511 +
12.512 + /* show ID for debugging */
12.513 + @Override
12.514 + public String toString() {
12.515 + return getId();
12.516 + }
12.517 + }
12.518 +
12.519 + //
12.520 + // Implementation of the default lookup
12.521 + //
12.522 + private static final class Empty extends Lookup {
12.523 + private static final Result NO_RESULT = new Result() {
12.524 + public void addLookupListener(LookupListener l) {
12.525 + }
12.526 +
12.527 + public void removeLookupListener(LookupListener l) {
12.528 + }
12.529 +
12.530 + public Collection allInstances() {
12.531 + return Collections.EMPTY_SET;
12.532 + }
12.533 + };
12.534 +
12.535 + Empty() {
12.536 + }
12.537 +
12.538 + public <T> T lookup(Class<T> clazz) {
12.539 + return null;
12.540 + }
12.541 +
12.542 + @SuppressWarnings("unchecked")
12.543 + public <T> Result<T> lookup(Template<T> template) {
12.544 + return NO_RESULT;
12.545 + }
12.546 + }
12.547 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/openide.util.lookup/src/org/openide/util/LookupEvent.java Mon Dec 14 20:58:39 2009 +0100
13.3 @@ -0,0 +1,57 @@
13.4 +/*
13.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
13.6 + *
13.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
13.8 + *
13.9 + * The contents of this file are subject to the terms of either the GNU
13.10 + * General Public License Version 2 only ("GPL") or the Common
13.11 + * Development and Distribution License("CDDL") (collectively, the
13.12 + * "License"). You may not use this file except in compliance with the
13.13 + * License. You can obtain a copy of the License at
13.14 + * http://www.netbeans.org/cddl-gplv2.html
13.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13.16 + * specific language governing permissions and limitations under the
13.17 + * License. When distributing the software, include this License Header
13.18 + * Notice in each file and include the License file at
13.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
13.20 + * particular file as subject to the "Classpath" exception as provided
13.21 + * by Sun in the GPL Version 2 section of the License file that
13.22 + * accompanied this code. If applicable, add the following below the
13.23 + * License Header, with the fields enclosed by brackets [] replaced by
13.24 + * your own identifying information:
13.25 + * "Portions Copyrighted [year] [name of copyright owner]"
13.26 + *
13.27 + * Contributor(s):
13.28 + *
13.29 + * The Original Software is NetBeans. The Initial Developer of the Original
13.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
13.31 + * Microsystems, Inc. All Rights Reserved.
13.32 + *
13.33 + * If you wish your version of this file to be governed by only the CDDL
13.34 + * or only the GPL Version 2, indicate your decision by adding
13.35 + * "[Contributor] elects to include this software in this distribution
13.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
13.37 + * single choice of license, a recipient has the option to distribute
13.38 + * your version of this file under either the CDDL, the GPL Version 2 or
13.39 + * to extend the choice of license to its licensees as provided above.
13.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
13.41 + * Version 2 license, then the option applies only if the new code is
13.42 + * made subject to such option by the copyright holder.
13.43 + */
13.44 +package org.openide.util;
13.45 +
13.46 +import java.util.*;
13.47 +
13.48 +
13.49 +/** An event describing the change in the lookup's result.
13.50 + *
13.51 + * @author Jaroslav Tulach
13.52 + */
13.53 +public final class LookupEvent extends EventObject {
13.54 + /** Create a new lookup event.
13.55 + * @param source the lookup result which has changed
13.56 + */
13.57 + public LookupEvent(Lookup.Result source) {
13.58 + super(source);
13.59 + }
13.60 +}
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/openide.util.lookup/src/org/openide/util/LookupListener.java Mon Dec 14 20:58:39 2009 +0100
14.3 @@ -0,0 +1,59 @@
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;
14.45 +
14.46 +import java.util.*;
14.47 +
14.48 +
14.49 +/** General listener for changes in lookup.
14.50 + *
14.51 + * @author Jaroslav Tulach
14.52 + */
14.53 +public interface LookupListener extends EventListener {
14.54 + /** A change in lookup occured. Please note that this method
14.55 + * should never block since it might be called from lookup implementation
14.56 + * internal threads. If you block here you are in risk that the thread
14.57 + * you wait for might in turn to wait for the lookup internal thread to
14.58 + * finish its work.
14.59 + * @param ev event describing the change
14.60 + */
14.61 + public void resultChanged(LookupEvent ev);
14.62 +}
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ALPairComparator.java Mon Dec 14 20:58:39 2009 +0100
15.3 @@ -0,0 +1,88 @@
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.util.Comparator;
15.47 +import org.openide.util.lookup.AbstractLookup.Pair;
15.48 +
15.49 +
15.50 +/** Implementation of comparator for AbstractLookup.Pair
15.51 + *
15.52 + * @author Jaroslav Tulach
15.53 + */
15.54 +final class ALPairComparator implements Comparator<Pair<?>> {
15.55 + public static final Comparator<Pair<?>> DEFAULT = new ALPairComparator();
15.56 +
15.57 + /** Creates a new instance of ALPairComparator */
15.58 + private ALPairComparator() {
15.59 + }
15.60 +
15.61 + /** Compares two items.
15.62 + */
15.63 + public int compare(Pair<?> i1, Pair<?> i2) {
15.64 + int result = i1.getIndex() - i2.getIndex();
15.65 +
15.66 + if (result == 0) {
15.67 + if (i1 != i2) {
15.68 + java.io.ByteArrayOutputStream bs = new java.io.ByteArrayOutputStream();
15.69 + java.io.PrintStream ps = new java.io.PrintStream(bs);
15.70 +
15.71 + ps.println(
15.72 + "Duplicate pair in tree" + // NOI18N
15.73 + "Pair1: " + i1 + " pair2: " + i2 + " index1: " + i1.getIndex() + " index2: " +
15.74 + i2.getIndex() // NOI18N
15.75 + +" item1: " + i1.getInstance() + " item2: " + i2.getInstance() // NOI18N
15.76 + +" id1: " + Integer.toHexString(System.identityHashCode(i1)) // NOI18N
15.77 + +" id2: " + Integer.toHexString(System.identityHashCode(i2)) // NOI18N
15.78 + );
15.79 +
15.80 + // print (ps, false);
15.81 + ps.close();
15.82 +
15.83 + throw new IllegalStateException(bs.toString());
15.84 + }
15.85 +
15.86 + return 0;
15.87 + }
15.88 +
15.89 + return result;
15.90 + }
15.91 +}
16.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
16.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/AbstractLookup.java Mon Dec 14 20:58:39 2009 +0100
16.3 @@ -0,0 +1,1467 @@
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 java.io.PrintStream;
16.47 +import org.openide.util.Lookup;
16.48 +import org.openide.util.LookupEvent;
16.49 +import org.openide.util.LookupListener;
16.50 +
16.51 +import java.io.IOException;
16.52 +import java.io.ObjectOutputStream;
16.53 +import java.io.Serializable;
16.54 +
16.55 +import java.lang.ref.ReferenceQueue;
16.56 +import java.lang.ref.WeakReference;
16.57 +import java.util.ArrayList;
16.58 +import java.util.Arrays;
16.59 +import java.util.Collection;
16.60 +import java.util.Collections;
16.61 +import java.util.Enumeration;
16.62 +import java.util.HashMap;
16.63 +import java.util.HashSet;
16.64 +import java.util.Iterator;
16.65 +import java.util.LinkedHashSet;
16.66 +import java.util.Map;
16.67 +import java.util.Set;
16.68 +import java.util.TreeSet;
16.69 +
16.70 +import java.util.concurrent.Executor;
16.71 +import org.netbeans.modules.openide.util.ActiveQueue;
16.72 +
16.73 +
16.74 +/** Implementation of the lookup from OpenAPIs that is based on the
16.75 + * introduction of Item. This class should provide the default way
16.76 + * of how to store (Class, Object) pairs in the lookups. It offers
16.77 + * protected methods for subclasses to register the pairs.
16.78 + * <p>Serializable since 3.27.
16.79 + * @author Jaroslav Tulach
16.80 + * @since 1.9
16.81 + */
16.82 +public class AbstractLookup extends Lookup implements Serializable {
16.83 + static final long serialVersionUID = 5L;
16.84 +
16.85 + /** lock for initialization of the maps of lookups */
16.86 + private static final Object treeLock = new Object();
16.87 +
16.88 + /** the tree that registers all items (or Integer as a treshold size) */
16.89 + private Object tree;
16.90 +
16.91 + /** count of items in to lookup */
16.92 + private int count;
16.93 +
16.94 + /** Constructor to create this lookup and associate it with given
16.95 + * Content. The content than allows the creator to invoke protected
16.96 + * methods which are not accessible for any other user of the lookup.
16.97 + *
16.98 + * @param content the content to assciate with
16.99 + *
16.100 + * @since 1.25
16.101 + */
16.102 + public AbstractLookup(Content content) {
16.103 + content.attach(this);
16.104 + }
16.105 +
16.106 + /** Constructor for testing purposes that allows specification of storage
16.107 + * as mechanism as well.
16.108 + */
16.109 + AbstractLookup(Content content, Storage<?> storage) {
16.110 + this(content);
16.111 + this.tree = storage;
16.112 + initialize();
16.113 + }
16.114 +
16.115 + /** Constructor for testing purposes that allows specification of storage
16.116 + * as mechanism as well.
16.117 + * @param trashhold number of Pair to "remain small"
16.118 + */
16.119 + AbstractLookup(Content content, Integer trashhold) {
16.120 + this(content);
16.121 + this.tree = trashhold;
16.122 + }
16.123 +
16.124 + /** Default constructor for subclasses that do not need to provide a content
16.125 + */
16.126 + protected AbstractLookup() {
16.127 + }
16.128 +
16.129 + @Override
16.130 + public String toString() {
16.131 + if (tree instanceof Storage) {
16.132 + return "AbstractLookup" + lookup(new Lookup.Template<Object>(Object.class)).allItems(); // NOI18N
16.133 + } else {
16.134 + return super.toString();
16.135 + }
16.136 + }
16.137 +
16.138 + /** Entres the storage management system.
16.139 + */
16.140 + @SuppressWarnings("unchecked")
16.141 + private <T> AbstractLookup.Storage<T> enterStorage() {
16.142 + for (;;) {
16.143 + synchronized (treeLock) {
16.144 + if (tree instanceof AbstractLookup.Storage) {
16.145 + if (tree instanceof DelegatingStorage) {
16.146 + // somebody is using the lookup right now
16.147 + DelegatingStorage del = (DelegatingStorage) tree;
16.148 +
16.149 + // check whether there is not access from the same
16.150 + // thread (can throw exception)
16.151 + del.checkForTreeModification();
16.152 +
16.153 + try {
16.154 + treeLock.wait();
16.155 + } catch (InterruptedException ex) {
16.156 + // ignore and go on
16.157 + }
16.158 +
16.159 + continue;
16.160 + } else {
16.161 + // ok, tree is initialized and nobody is using it yet
16.162 + tree = new DelegatingStorage((Storage<T>) tree);
16.163 +
16.164 + return (Storage<T>) tree;
16.165 + }
16.166 + }
16.167 +
16.168 + // first time initialization of the tree
16.169 + if (tree instanceof Integer) {
16.170 + tree = new ArrayStorage((Integer) tree);
16.171 + } else {
16.172 + tree = new ArrayStorage();
16.173 + }
16.174 + }
16.175 +
16.176 + // the tree has not yet been initilized, initialize and go on again
16.177 + initialize();
16.178 + }
16.179 + }
16.180 +
16.181 + /** Exists tree ownership.
16.182 + */
16.183 + private AbstractLookup.Storage exitStorage() {
16.184 + synchronized (treeLock) {
16.185 + AbstractLookup.Storage stor = ((DelegatingStorage) tree).exitDelegate();
16.186 + tree = stor;
16.187 + treeLock.notifyAll();
16.188 +
16.189 + return stor;
16.190 + }
16.191 + }
16.192 +
16.193 + /** Method for subclasses to initialize them selves.
16.194 + */
16.195 + protected void initialize() {
16.196 + }
16.197 +
16.198 + /** Notifies subclasses that a query is about to be processed.
16.199 + * @param template the template
16.200 + */
16.201 + protected void beforeLookup(Template<?> template) {
16.202 + }
16.203 +
16.204 + /** The method to add instance to the lookup with.
16.205 + * @param pair class/instance pair
16.206 + */
16.207 + protected final void addPair(Pair<?> pair) {
16.208 + addPairImpl(pair, null);
16.209 + }
16.210 +
16.211 + /** The method to add instance to the lookup with.
16.212 + * @param pair class/instance pair
16.213 + * @param notifyIn the executor that will handle the notification of events
16.214 + * @since 7.16
16.215 + */
16.216 + protected final void addPair(Pair<?> pair, Executor notifyIn) {
16.217 + addPairImpl(pair, notifyIn);
16.218 + }
16.219 +
16.220 + private final <Transaction> void addPairImpl(Pair<?> pair, Executor notifyIn) {
16.221 + HashSet<R> toNotify = new HashSet<R>();
16.222 +
16.223 + AbstractLookup.Storage<Transaction> t = enterStorage();
16.224 + Transaction transaction = null;
16.225 +
16.226 + try {
16.227 + transaction = t.beginTransaction(-2);
16.228 +
16.229 + if (t.add(pair, transaction)) {
16.230 + try {
16.231 + pair.setIndex(t, count++);
16.232 + } catch (IllegalStateException ex) {
16.233 + // remove the pair
16.234 + t.remove(pair, transaction);
16.235 +
16.236 + // rethrow the exception
16.237 + throw ex;
16.238 + }
16.239 +
16.240 + // if the pair is newly added and was not there before
16.241 + t.endTransaction(transaction, toNotify);
16.242 + } else {
16.243 + // just finish the process by calling endTransaction
16.244 + t.endTransaction(transaction, new HashSet<R>());
16.245 + }
16.246 + } finally {
16.247 + exitStorage();
16.248 + }
16.249 +
16.250 + notifyIn(notifyIn, toNotify);
16.251 + }
16.252 +
16.253 + /** Remove instance.
16.254 + * @param pair class/instance pair
16.255 + */
16.256 + protected final void removePair(Pair<?> pair) {
16.257 + removePairImpl(pair, null);
16.258 + }
16.259 + /** Remove instance.
16.260 + * @param pair class/instance pair
16.261 + * @param notifyIn the executor that will handle the notification of events
16.262 + * @since 7.16
16.263 + */
16.264 + protected final void removePair(Pair<?> pair, Executor notifyIn) {
16.265 + removePairImpl(pair, notifyIn);
16.266 + }
16.267 +
16.268 + private <Transaction> void removePairImpl(Pair<?> pair, Executor notifyIn) {
16.269 + HashSet<R> toNotify = new HashSet<R>();
16.270 +
16.271 + AbstractLookup.Storage<Transaction> t = enterStorage();
16.272 + Transaction transaction = null;
16.273 +
16.274 + try {
16.275 + transaction = t.beginTransaction(-1);
16.276 + t.remove(pair, transaction);
16.277 + t.endTransaction(transaction, toNotify);
16.278 + } finally {
16.279 + exitStorage();
16.280 + }
16.281 +
16.282 + notifyIn(notifyIn, toNotify);
16.283 + }
16.284 +
16.285 + /** Changes all pairs in the lookup to new values.
16.286 + * @param collection the collection of (Pair) objects
16.287 + */
16.288 + protected final void setPairs(Collection<? extends Pair> collection) {
16.289 + setPairs(collection, null);
16.290 + }
16.291 +
16.292 + /** Changes all pairs in the lookup to new values, notifies listeners
16.293 + * using provided executor.
16.294 + *
16.295 + * @param collection the collection of (Pair) objects
16.296 + * @param notifyIn the executor that will handle the notification of events
16.297 + * @since 7.16
16.298 + */
16.299 + protected final void setPairs(Collection<? extends Pair> collection, Executor notifyIn) {
16.300 + HashSet<R> listeners = setPairsAndCollectListeners(collection);
16.301 + notifyIn(notifyIn, listeners);
16.302 + }
16.303 +
16.304 + private final void notifyIn(Executor notifyIn, final HashSet<R> listeners) {
16.305 + NotifyListeners notify = new NotifyListeners(listeners);
16.306 + if (notify.shallRun()) {
16.307 + if (notifyIn == null) {
16.308 + notify.run();
16.309 + } else {
16.310 + notifyIn.execute(notify);
16.311 + }
16.312 + }
16.313 + }
16.314 +
16.315 + /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
16.316 + * @return a LinkedHashSet that can be modified
16.317 + */
16.318 + final LinkedHashSet<Pair<?>> getPairsAsLHS() {
16.319 + AbstractLookup.Storage<?> t = enterStorage();
16.320 +
16.321 + try {
16.322 + Enumeration<Pair<Object>> en = t.lookup(Object.class);
16.323 + TreeSet<Pair<?>> arr = new TreeSet<Pair<?>>(ALPairComparator.DEFAULT);
16.324 + while (en.hasMoreElements()) {
16.325 + Pair<Object> item = en.nextElement();
16.326 + arr.add(item);
16.327 + }
16.328 + return new LinkedHashSet<Pair<?>>(arr);
16.329 + } finally {
16.330 + exitStorage();
16.331 + }
16.332 + }
16.333 +
16.334 + /** Collects listeners without notification. Needed in MetaInfServicesLookup
16.335 + * right now, but maybe will become an API later.
16.336 + */
16.337 + final <Transaction> HashSet<R> setPairsAndCollectListeners(Collection<? extends Pair> collection) {
16.338 + HashSet<R> toNotify = new HashSet<R>(27);
16.339 +
16.340 + AbstractLookup.Storage<Transaction> t = enterStorage();
16.341 + Transaction transaction = null;
16.342 +
16.343 + try {
16.344 + // map between the Items and their indexes (Integer)
16.345 + HashMap<Item<?>,Info> shouldBeThere = new HashMap<Item<?>,Info>(collection.size() * 2);
16.346 +
16.347 + count = 0;
16.348 +
16.349 + Iterator it = collection.iterator();
16.350 + transaction = t.beginTransaction(collection.size());
16.351 +
16.352 + while (it.hasNext()) {
16.353 + Pair item = (Pair) it.next();
16.354 +
16.355 + if (t.add(item, transaction)) {
16.356 + // the item has not been there yet
16.357 + //t.endTransaction(transaction, toNotify);
16.358 + }
16.359 +
16.360 + // remeber the item, because it should not be removed
16.361 + shouldBeThere.put(item, new Info(count++, transaction));
16.362 +
16.363 + // arr.clear ();
16.364 + }
16.365 +
16.366 + // Object transaction = t.beginTransaction ();
16.367 + // deletes all objects that should not be there and
16.368 + t.retainAll(shouldBeThere, transaction);
16.369 +
16.370 + // collect listeners
16.371 + t.endTransaction(transaction, toNotify);
16.372 +
16.373 + /*
16.374 + // check consistency
16.375 + Enumeration en = t.lookup (java.lang.Object.class);
16.376 + boolean[] max = new boolean[count];
16.377 + int mistake = -1;
16.378 + while (en.hasMoreElements ()) {
16.379 + Pair item = (Pair)en.nextElement ();
16.380 +
16.381 + if (max[item.index]) {
16.382 + mistake = item.index;
16.383 + }
16.384 + max[item.index] = true;
16.385 + }
16.386 +
16.387 + if (mistake != -1) {
16.388 + System.err.println ("Mistake at: " + mistake);
16.389 + tree.print (System.err, true);
16.390 + }
16.391 + */
16.392 + } finally {
16.393 + exitStorage();
16.394 + }
16.395 +
16.396 + return toNotify;
16.397 + }
16.398 +
16.399 + private final void writeObject(ObjectOutputStream oos)
16.400 + throws IOException {
16.401 + AbstractLookup.Storage s = enterStorage();
16.402 +
16.403 + try {
16.404 + // #36830: Serializing only InheritanceTree no ArrayStorage
16.405 + s.beginTransaction(Integer.MAX_VALUE);
16.406 +
16.407 + // #32040: don't write half-made changes
16.408 + oos.defaultWriteObject();
16.409 + } finally {
16.410 + exitStorage();
16.411 + }
16.412 + }
16.413 +
16.414 + public final <T> T lookup(Class<T> clazz) {
16.415 + Lookup.Item<T> item = lookupItem(new Lookup.Template<T>(clazz));
16.416 + return (item == null) ? null : item.getInstance();
16.417 + }
16.418 +
16.419 + @Override
16.420 + public final <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
16.421 + AbstractLookup.this.beforeLookup(template);
16.422 +
16.423 + ArrayList<Pair<T>> list = null;
16.424 + AbstractLookup.Storage<?> t = enterStorage();
16.425 +
16.426 + try {
16.427 + Enumeration<Pair<T>> en;
16.428 +
16.429 + try {
16.430 + en = t.lookup(template.getType());
16.431 +
16.432 + return findSmallest(en, template, false);
16.433 + } catch (AbstractLookup.ISE ex) {
16.434 + // not possible to enumerate the exception, ok, copy it
16.435 + // to create new
16.436 + list = new ArrayList<Pair<T>>();
16.437 + en = t.lookup(null); // this should get all the items without any checks
16.438 +
16.439 + // the checks will be done out side of the storage
16.440 + while (en.hasMoreElements()) {
16.441 + list.add(en.nextElement());
16.442 + }
16.443 + }
16.444 + } finally {
16.445 + exitStorage();
16.446 + }
16.447 +
16.448 + return findSmallest(Collections.enumeration(list), template, true);
16.449 + }
16.450 +
16.451 + private static <T> Pair<T> findSmallest(Enumeration<Pair<T>> en, Lookup.Template<T> template, boolean deepCheck) {
16.452 + int smallest = InheritanceTree.unsorted(en) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
16.453 + Pair<T> res = null;
16.454 +
16.455 + while (en.hasMoreElements()) {
16.456 + Pair<T> item = en.nextElement();
16.457 +
16.458 + if (matches(template, item, deepCheck)) {
16.459 + if (smallest == Integer.MIN_VALUE) {
16.460 + // ok, sorted enumeration the first that matches is fine
16.461 + return item;
16.462 + } else {
16.463 + // check for the smallest item
16.464 + if (smallest > item.getIndex()) {
16.465 + smallest = item.getIndex();
16.466 + res = item;
16.467 + }
16.468 + }
16.469 + }
16.470 + }
16.471 +
16.472 + return res;
16.473 + }
16.474 +
16.475 + public final <T> Lookup.Result<T> lookup(Lookup.Template<T> template) {
16.476 + for (;;) {
16.477 + AbstractLookup.ISE toRun = null;
16.478 +
16.479 + AbstractLookup.Storage<?> t = enterStorage();
16.480 +
16.481 + try {
16.482 + R<T> r = new R<T>();
16.483 + ReferenceToResult<T> newRef = new ReferenceToResult<T>(r, this, template);
16.484 + newRef.next = t.registerReferenceToResult(newRef);
16.485 +
16.486 + return r;
16.487 + } catch (AbstractLookup.ISE ex) {
16.488 + toRun = ex;
16.489 + } finally {
16.490 + exitStorage();
16.491 + }
16.492 +
16.493 + toRun.recover(this);
16.494 +
16.495 + // and try again
16.496 + }
16.497 + }
16.498 +
16.499 + /** Notifies listeners.
16.500 + * @param allAffectedResults set of R
16.501 + */
16.502 + static final class NotifyListeners implements Runnable {
16.503 + private final ArrayList<Object> evAndListeners;
16.504 +
16.505 + public NotifyListeners(Set<R> allAffectedResults) {
16.506 + if (allAffectedResults.isEmpty()) {
16.507 + evAndListeners = null;
16.508 + return;
16.509 + }
16.510 +
16.511 + evAndListeners = new ArrayList<Object>();
16.512 + {
16.513 + for (R<?> result : allAffectedResults) {
16.514 + result.collectFires(evAndListeners);
16.515 + }
16.516 + }
16.517 + }
16.518 +
16.519 + public boolean shallRun() {
16.520 + return evAndListeners != null && !evAndListeners.isEmpty();
16.521 + }
16.522 +
16.523 + public void run() {
16.524 + Iterator it = evAndListeners.iterator();
16.525 + while (it.hasNext()) {
16.526 + LookupEvent ev = (LookupEvent)it.next();
16.527 + LookupListener l = (LookupListener)it.next();
16.528 + l.resultChanged(ev);
16.529 + }
16.530 + }
16.531 + }
16.532 +
16.533 + /**
16.534 + * Call resultChanged on all listeners.
16.535 + * @param listeners array of listeners in the format used by
16.536 + * javax.swing.EventListenerList. It means that there are Class
16.537 + * objects on even positions and the listeners on odd positions
16.538 + * @param ev the event to fire
16.539 + */
16.540 + static void notifyListeners(Object[] listeners, LookupEvent ev, Collection<Object> evAndListeners) {
16.541 + for (int i = listeners.length - 1; i >= 0; i--) {
16.542 + if (! (listeners[i] instanceof LookupListener)) {
16.543 + continue;
16.544 + }
16.545 + LookupListener ll = (LookupListener)listeners[i];
16.546 +
16.547 + try {
16.548 + if (evAndListeners != null) {
16.549 + if (ll instanceof WaitableResult) {
16.550 + WaitableResult<?> wr = (WaitableResult<?>)ll;
16.551 + wr.collectFires(evAndListeners);
16.552 + } else {
16.553 + evAndListeners.add(ev);
16.554 + evAndListeners.add(ll);
16.555 + }
16.556 + } else {
16.557 + ll.resultChanged(ev);
16.558 + }
16.559 + } catch (StackOverflowError err) {
16.560 + throw new CycleError(evAndListeners); // NOI18N
16.561 + } catch (RuntimeException e) {
16.562 + // Such as e.g. occurred in #32040. Do not halt other things.
16.563 + e.printStackTrace();
16.564 + }
16.565 + }
16.566 + }
16.567 +
16.568 + private static class CycleError extends StackOverflowError {
16.569 + private final Collection<Object> print;
16.570 + public CycleError(Collection<Object> evAndListeners) {
16.571 + this.print = evAndListeners;
16.572 + }
16.573 +
16.574 + @Override
16.575 + public String getMessage() {
16.576 + StringBuilder sb = new StringBuilder();
16.577 + sb.append("StackOverflowError, here are the listeners:\n"); // NOI18N
16.578 + for (Object o : print) {
16.579 + sb.append('\n').append(o);
16.580 + if (sb.length() > 10000) {
16.581 + break;
16.582 + }
16.583 + }
16.584 + return sb.toString();
16.585 + }
16.586 + } // end of CycleError
16.587 +
16.588 + /** A method that defines matching between Item and Template.
16.589 + * @param t template providing the criteria
16.590 + * @param item the item to match
16.591 + * @param deepCheck true if type of the pair should be tested, false if it is already has been tested
16.592 + * @return true if item matches the template requirements, false if not
16.593 + */
16.594 + static boolean matches(Template<?> t, Pair<?> item, boolean deepCheck) {
16.595 + String id = t.getId();
16.596 +
16.597 + if (id != null && !id.equals(item.getId())) {
16.598 + return false;
16.599 + }
16.600 +
16.601 + Object instance = t.getInstance();
16.602 +
16.603 + if ((instance != null) && !item.creatorOf(instance)) {
16.604 + return false;
16.605 + }
16.606 +
16.607 + if (deepCheck) {
16.608 + return item.instanceOf(t.getType());
16.609 + } else {
16.610 + return true;
16.611 + }
16.612 + }
16.613 +
16.614 + /**
16.615 + * Compares the array elements for equality.
16.616 + * @return true if all elements in the arrays are equal
16.617 + * (by calling equals(Object x) method)
16.618 + */
16.619 + private static boolean compareArrays(Object[] a, Object[] b) {
16.620 + // handle null values
16.621 + if (a == null) {
16.622 + return (b == null);
16.623 + } else {
16.624 + if (b == null) {
16.625 + return false;
16.626 + }
16.627 + }
16.628 +
16.629 + if (a.length != b.length) {
16.630 + return false;
16.631 + }
16.632 +
16.633 + for (int i = 0; i < a.length; i++) {
16.634 + // handle null values for individual elements
16.635 + if (a[i] == null) {
16.636 + if (b[i] != null) {
16.637 + return false;
16.638 + }
16.639 +
16.640 + // both are null --> ok, take next
16.641 + continue;
16.642 + } else {
16.643 + if (b[i] == null) {
16.644 + return false;
16.645 + }
16.646 + }
16.647 +
16.648 + // perform the comparison
16.649 + if (!a[i].equals(b[i])) {
16.650 + return false;
16.651 + }
16.652 + }
16.653 +
16.654 + return true;
16.655 + }
16.656 +
16.657 + /** Method to be called when a result is cleared to signal that the list
16.658 + * of all result should be checked for clearing.
16.659 + * @param template the template the result was for
16.660 + * @return true if the hash map with all items has been cleared
16.661 + */
16.662 + <T> boolean cleanUpResult(Lookup.Template<T> template) {
16.663 + AbstractLookup.Storage<?> t = enterStorage();
16.664 +
16.665 + try {
16.666 + return t.cleanUpResult(template) == null;
16.667 + } finally {
16.668 + exitStorage();
16.669 + }
16.670 + }
16.671 +
16.672 + /** Storage check for tests. */
16.673 + static boolean isSimple(AbstractLookup l) {
16.674 + return DelegatingStorage.isSimple((Storage)l.tree);
16.675 + }
16.676 +
16.677 + /** Generic support for listeners, so it can be used in other results
16.678 + * as well.
16.679 + * @param add true to add it, false to modify
16.680 + * @param l listener to modify
16.681 + * @param ref the value of the reference to listener or listener list
16.682 + * @return new value to the reference to listener or list
16.683 + */
16.684 + @SuppressWarnings("unchecked")
16.685 + static Object modifyListenerList(boolean add, LookupListener l, Object ref) {
16.686 + if (add) {
16.687 + if (ref == null) {
16.688 + return l;
16.689 + }
16.690 +
16.691 + if (ref instanceof LookupListener) {
16.692 + ArrayList arr = new ArrayList();
16.693 + arr.add(ref);
16.694 + ref = arr;
16.695 + }
16.696 +
16.697 + ((ArrayList) ref).add(l);
16.698 +
16.699 + return ref;
16.700 + } else {
16.701 + // remove
16.702 + if (ref == null) {
16.703 + return null;
16.704 + }
16.705 +
16.706 + if (ref == l) {
16.707 + return null;
16.708 + }
16.709 +
16.710 + ArrayList arr = (ArrayList) ref;
16.711 + arr.remove(l);
16.712 +
16.713 + if (arr.size() == 1) {
16.714 + return arr.iterator().next();
16.715 + } else {
16.716 + return arr;
16.717 + }
16.718 + }
16.719 + }
16.720 +
16.721 + private static ReferenceQueue<Object> activeQueue() {
16.722 + return ActiveQueue.queue();
16.723 + }
16.724 +
16.725 + /** Storage to keep the internal structure of Pairs and to answer
16.726 + * different queries.
16.727 + */
16.728 + interface Storage<Transaction> {
16.729 + /** Initializes a modification operation by creating an object
16.730 + * that will be passsed to all add, remove, retainAll methods
16.731 + * and should collect enough information about the change to
16.732 + * notify listeners about the transaction later
16.733 + *
16.734 + * @param ensure the amount of items that will appear in the storage
16.735 + * after the modifications (-1 == remove one, -2 == add one, >= 0
16.736 + * the amount of objects at the end
16.737 + * @return a token to identify the transaction
16.738 + */
16.739 + public Transaction beginTransaction(int ensure);
16.740 +
16.741 + /** Collects all affected results R that were modified in the
16.742 + * given transaction.
16.743 + *
16.744 + * @param modified place to add results R to
16.745 + * @param transaction the transaction indentification
16.746 + */
16.747 + public void endTransaction(Transaction transaction, Set<R> modifiedResults);
16.748 +
16.749 + /** Adds an item into the storage.
16.750 + * @param item to add
16.751 + * @param transaction transaction token
16.752 + * @return true if the Item has been added for the first time or false if some other
16.753 + * item equal to this one already existed in the lookup
16.754 + */
16.755 + public boolean add(AbstractLookup.Pair<?> item, Transaction transaction);
16.756 +
16.757 + /** Removes an item.
16.758 + */
16.759 + public void remove(AbstractLookup.Pair item, Transaction transaction);
16.760 +
16.761 + /** Removes all items that are not present in the provided collection.
16.762 + * @param retain collection of Pairs to keep them in
16.763 + * @param transaction the transaction context
16.764 + */
16.765 + public void retainAll(Map retain, Transaction transaction);
16.766 +
16.767 + /** Queries for instances of given class.
16.768 + * @param clazz the class to check
16.769 + * @return enumeration of Item
16.770 + * @see #unsorted
16.771 + */
16.772 + public <T> Enumeration<Pair<T>> lookup(Class<T> clazz);
16.773 +
16.774 + /** Registers another reference to a result with the storage. This method
16.775 + * has also a special meaning.
16.776 + *
16.777 + * @param newRef the new reference to remember
16.778 + * @return the previous reference that was kept (null if newRef is the first one)
16.779 + * the applications is expected to link from newRef to this returned
16.780 + * value to form a linked list
16.781 + */
16.782 + public ReferenceToResult<?> registerReferenceToResult(ReferenceToResult<?> newRef);
16.783 +
16.784 + /** Given the provided template, Do cleanup the results.
16.785 + * @param templ template of a result(s) that should be checked
16.786 + * @return null if all references for this template were cleared or one of them
16.787 + */
16.788 + public ReferenceToResult<?> cleanUpResult(Lookup.Template<?> templ);
16.789 + }
16.790 +
16.791 + /** Extension to the default lookup item that offers additional information
16.792 + * for the data structures use in AbstractLookup
16.793 + */
16.794 + public static abstract class Pair<T> extends Lookup.Item<T> implements Serializable {
16.795 + private static final long serialVersionUID = 1L;
16.796 +
16.797 + /** possition of this item in the lookup, manipulated in addPair, removePair, setPairs methods */
16.798 + private int index = -1;
16.799 +
16.800 + /** For use by subclasses. */
16.801 + protected Pair() {
16.802 + }
16.803 +
16.804 + final int getIndex() {
16.805 + return index;
16.806 + }
16.807 +
16.808 + final void setIndex(AbstractLookup.Storage<?> tree, int x) {
16.809 + if (tree == null) {
16.810 + this.index = x;
16.811 +
16.812 + return;
16.813 + }
16.814 +
16.815 + if (this.index == -1) {
16.816 + this.index = x;
16.817 + } else {
16.818 + throw new IllegalStateException("You cannot use " + this + " in more than one AbstractLookup. Prev: " + this.index + " new: " + x); // NOI18N
16.819 + }
16.820 + }
16.821 +
16.822 + /** Tests whether this item can produce object
16.823 + * of class c.
16.824 + */
16.825 + protected abstract boolean instanceOf(Class<?> c);
16.826 +
16.827 + /** Method that can test whether an instance of a class has been created
16.828 + * by this item.
16.829 + *
16.830 + * @param obj the instance
16.831 + * @return if the item has already create an instance and it is the same
16.832 + * as obj.
16.833 + */
16.834 + protected abstract boolean creatorOf(Object obj);
16.835 + }
16.836 +
16.837 + /** Result based on one instance returned.
16.838 + */
16.839 + static final class R<T> extends WaitableResult<T> {
16.840 + /** reference our result is attached to (do not modify) */
16.841 + public ReferenceToResult<T> reference;
16.842 +
16.843 + /** listeners on the results or pointer to one listener */
16.844 + private Object listeners;
16.845 +
16.846 + public R() {
16.847 + }
16.848 +
16.849 + /** Checks whether we have simple behaviour of complex.
16.850 + */
16.851 + private boolean isSimple() {
16.852 + Storage s = (Storage) reference.lookup.tree;
16.853 +
16.854 + return DelegatingStorage.isSimple(s);
16.855 + }
16.856 +
16.857 + //
16.858 + // Handling cache management for both cases, no caches
16.859 + // for simple (but mark that we needed them, so refresh can
16.860 + // be done in cloneList) and complex when all 3 types
16.861 + // of result are cached
16.862 + //
16.863 + private Object getFromCache(int indx) {
16.864 + if (isSimple()) {
16.865 + return null;
16.866 + }
16.867 +
16.868 + Object maybeArray = reference.caches;
16.869 +
16.870 + if (maybeArray instanceof Object[]) {
16.871 + return ((Object[]) maybeArray)[indx];
16.872 + }
16.873 +
16.874 + return null;
16.875 + }
16.876 +
16.877 + @SuppressWarnings("unchecked")
16.878 + private Set<Class<? extends T>> getClassesCache() {
16.879 + return (Set<Class<? extends T>>) getFromCache(0);
16.880 + }
16.881 +
16.882 + private void setClassesCache(Set s) {
16.883 + if (isSimple()) {
16.884 + // mark it as being used
16.885 + reference.caches = reference;
16.886 +
16.887 + return;
16.888 + }
16.889 +
16.890 + if (!(reference.caches instanceof Object[])) {
16.891 + reference.caches = new Object[3];
16.892 + }
16.893 +
16.894 + ((Object[]) reference.caches)[0] = s;
16.895 + }
16.896 +
16.897 + @SuppressWarnings("unchecked")
16.898 + private Collection<T> getInstancesCache() {
16.899 + return (Collection<T>) getFromCache(1);
16.900 + }
16.901 +
16.902 + private void setInstancesCache(Collection c) {
16.903 + if (isSimple()) {
16.904 + // mark it as being used
16.905 + reference.caches = reference;
16.906 +
16.907 + return;
16.908 + }
16.909 +
16.910 + if (!(reference.caches instanceof Object[])) {
16.911 + reference.caches = new Object[3];
16.912 + }
16.913 +
16.914 + ((Object[]) reference.caches)[1] = c;
16.915 + }
16.916 +
16.917 + @SuppressWarnings("unchecked")
16.918 + private Pair<T>[] getItemsCache() {
16.919 + return (Pair<T>[]) getFromCache(2);
16.920 + }
16.921 +
16.922 + private void setItemsCache(Collection<?> c) {
16.923 + if (isSimple()) {
16.924 + // mark it as being used
16.925 + reference.caches = reference;
16.926 +
16.927 + return;
16.928 + }
16.929 +
16.930 + if (!(reference.caches instanceof Object[])) {
16.931 + reference.caches = new Object[3];
16.932 + }
16.933 +
16.934 + ((Object[]) reference.caches)[2] = c.toArray(new Pair[0]);
16.935 + }
16.936 +
16.937 + private void clearCaches() {
16.938 + if (reference.caches instanceof Object[]) {
16.939 + reference.caches = new Object[3];
16.940 + }
16.941 + }
16.942 +
16.943 + /** Ok, register listeners to all classes and super classes.
16.944 + */
16.945 + public synchronized void addLookupListener(LookupListener l) {
16.946 + listeners = modifyListenerList(true, l, listeners);
16.947 + }
16.948 +
16.949 + /** Ok, register listeners to all classes and super classes.
16.950 + */
16.951 + public synchronized void removeLookupListener(LookupListener l) {
16.952 + listeners = modifyListenerList(false, l, listeners);
16.953 + }
16.954 +
16.955 + /** Delete all cached values, the template changed.
16.956 + */
16.957 + protected void collectFires(Collection<Object> evAndListeners) {
16.958 + Object[] previousItems = getItemsCache();
16.959 + clearCaches();
16.960 +
16.961 + if (previousItems != null) {
16.962 + Object[] newArray = allItemsWithoutBeforeLookup().toArray();
16.963 +
16.964 + if (compareArrays(previousItems, newArray)) {
16.965 + // do not fire any change if nothing has been changed
16.966 + return;
16.967 + }
16.968 + }
16.969 +
16.970 + LookupListener[] arr;
16.971 +
16.972 + synchronized (this) {
16.973 + if (listeners == null) {
16.974 + return;
16.975 + }
16.976 +
16.977 + if (listeners instanceof LookupListener) {
16.978 + arr = new LookupListener[] { (LookupListener) listeners };
16.979 + } else {
16.980 + ArrayList<?> l = (ArrayList<?>) listeners;
16.981 + arr = l.toArray(new LookupListener[l.size()]);
16.982 + }
16.983 + }
16.984 +
16.985 + final LookupListener[] ll = arr;
16.986 + final LookupEvent ev = new LookupEvent(this);
16.987 + notifyListeners(ll, ev, evAndListeners);
16.988 + }
16.989 +
16.990 + public Collection<T> allInstances() {
16.991 + reference.lookup.beforeLookup(reference.template);
16.992 +
16.993 + Collection<T> s = getInstancesCache();
16.994 +
16.995 + if (s != null) {
16.996 + return s;
16.997 + }
16.998 +
16.999 + Collection<Pair<T>> items = allItemsWithoutBeforeLookup();
16.1000 + ArrayList<T> list = new ArrayList<T>(items.size());
16.1001 +
16.1002 + Iterator<Pair<T>> it = items.iterator();
16.1003 +
16.1004 + while (it.hasNext()) {
16.1005 + Pair<T> item = it.next();
16.1006 + T obj = item.getInstance();
16.1007 +
16.1008 + if (reference.template.getType().isInstance(obj)) {
16.1009 + list.add(obj);
16.1010 + }
16.1011 + }
16.1012 +
16.1013 + s = Collections.unmodifiableList(list);
16.1014 + setInstancesCache(s);
16.1015 +
16.1016 + return s;
16.1017 + }
16.1018 +
16.1019 + /** Set of all classes.
16.1020 + *
16.1021 + */
16.1022 + @Override
16.1023 + public Set<Class<? extends T>> allClasses() {
16.1024 + reference.lookup.beforeLookup(reference.template);
16.1025 +
16.1026 + Set<Class<? extends T>> s = getClassesCache();
16.1027 +
16.1028 + if (s != null) {
16.1029 + return s;
16.1030 + }
16.1031 +
16.1032 + s = new HashSet<Class<? extends T>>();
16.1033 +
16.1034 + for (Pair<T> item : allItemsWithoutBeforeLookup()) {
16.1035 + Class<? extends T> clazz = item.getType();
16.1036 +
16.1037 + if (clazz != null) {
16.1038 + s.add(clazz);
16.1039 + }
16.1040 + }
16.1041 +
16.1042 + s = Collections.unmodifiableSet(s);
16.1043 + setClassesCache(s);
16.1044 +
16.1045 + return s;
16.1046 + }
16.1047 +
16.1048 + /** Items are stored directly in the allItems.
16.1049 + */
16.1050 + @Override
16.1051 + public Collection<? extends Item<T>> allItems() {
16.1052 + reference.lookup.beforeLookup(reference.template);
16.1053 +
16.1054 + return allItemsWithoutBeforeLookup();
16.1055 + }
16.1056 +
16.1057 + /** Implements the search for allItems, but without asking for before lookup */
16.1058 + private Collection<Pair<T>> allItemsWithoutBeforeLookup() {
16.1059 + Pair<T>[] c = getItemsCache();
16.1060 +
16.1061 + if (c != null) {
16.1062 + return Collections.unmodifiableList(Arrays.asList(c));
16.1063 + }
16.1064 +
16.1065 + ArrayList<Pair<Object>> saferCheck = null;
16.1066 + AbstractLookup.Storage<?> t = reference.lookup.enterStorage();
16.1067 +
16.1068 + try {
16.1069 + try {
16.1070 + return Collections.unmodifiableCollection(initItems(t));
16.1071 + } catch (AbstractLookup.ISE ex) {
16.1072 + // do less effective evaluation of items outside of the
16.1073 + // locked storage
16.1074 + saferCheck = new ArrayList<Pair<Object>>();
16.1075 +
16.1076 + Enumeration<Pair<Object>> en = t.lookup(null); // get all Pairs
16.1077 +
16.1078 + while (en.hasMoreElements()) {
16.1079 + Pair<Object> i = en.nextElement();
16.1080 + saferCheck.add(i);
16.1081 + }
16.1082 + }
16.1083 + } finally {
16.1084 + reference.lookup.exitStorage();
16.1085 + }
16.1086 + return extractPairs(saferCheck);
16.1087 + }
16.1088 +
16.1089 + @SuppressWarnings("unchecked")
16.1090 + private Collection<Pair<T>> extractPairs(final ArrayList<Pair<Object>> saferCheck) {
16.1091 + TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
16.1092 + for (Pair<Object> i : saferCheck) {
16.1093 + if (matches(reference.template, i, false)) {
16.1094 + items.add((Pair<T>)i);
16.1095 + }
16.1096 + }
16.1097 + return Collections.unmodifiableCollection(items);
16.1098 + }
16.1099 +
16.1100 + /** Initializes items.
16.1101 + */
16.1102 + private Collection<Pair<T>> initItems(Storage<?> t) {
16.1103 + // manipulation with the tree must be synchronized
16.1104 + Enumeration<Pair<T>> en = t.lookup(reference.template.getType());
16.1105 +
16.1106 + // InheritanceTree is comparator for AbstractLookup.Pairs
16.1107 + TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
16.1108 +
16.1109 + while (en.hasMoreElements()) {
16.1110 + Pair<T> i = en.nextElement();
16.1111 +
16.1112 + if (matches(reference.template, i, false)) {
16.1113 + items.add(i);
16.1114 + }
16.1115 + }
16.1116 +
16.1117 + // create a correctly sorted copy using the tree as the comparator
16.1118 + setItemsCache(items);
16.1119 +
16.1120 + return items;
16.1121 + }
16.1122 +
16.1123 + /** Used by proxy results to synchronize before lookup.
16.1124 + */
16.1125 + protected void beforeLookup(Lookup.Template t) {
16.1126 + if (t.getType() == reference.template.getType()) {
16.1127 + reference.lookup.beforeLookup(t);
16.1128 + }
16.1129 + }
16.1130 +
16.1131 + /* Do not need to implement it, the default way is ok.
16.1132 + public boolean equals(java.lang.Object obj) {
16.1133 + return obj == this;
16.1134 + }
16.1135 + */
16.1136 + @Override
16.1137 + public String toString() {
16.1138 + return super.toString() + " for " + reference.template;
16.1139 + }
16.1140 + }
16.1141 + // end of R
16.1142 +
16.1143 + /** A class that can be used by the creator of the AbstractLookup to
16.1144 + * control its content. It can be passed to AbstractLookup constructor
16.1145 + * and used to add and remove pairs.
16.1146 + *
16.1147 + * @since 1.25
16.1148 + */
16.1149 + public static class Content extends Object implements Serializable {
16.1150 + private static final long serialVersionUID = 1L;
16.1151 +
16.1152 + // one of them is always null (except attach stage)
16.1153 +
16.1154 + /** abstract lookup we are connected to */
16.1155 + private AbstractLookup al;
16.1156 + private transient Object notifyIn;
16.1157 +
16.1158 + /** Default constructor.
16.1159 + */
16.1160 + public Content() {
16.1161 + this(null);
16.1162 + }
16.1163 +
16.1164 + /** Creates a content associated with an executor to handle dispatch
16.1165 + * of changes.
16.1166 + * @param notifyIn the executor to notify changes in
16.1167 + * @since 7.16
16.1168 + */
16.1169 + public Content(Executor notifyIn) {
16.1170 + this.notifyIn = notifyIn;
16.1171 + }
16.1172 +
16.1173 + /** for testing purposes */
16.1174 + final void attachExecutor(Executor notifyIn) {
16.1175 + this.notifyIn = notifyIn;
16.1176 + }
16.1177 +
16.1178 + /** A lookup attaches to this object.
16.1179 + */
16.1180 + final synchronized void attach(AbstractLookup al) {
16.1181 + if (this.al == null) {
16.1182 + this.al = al;
16.1183 +
16.1184 + ArrayList<Pair> ep = getEarlyPairs();
16.1185 + if (ep != null) {
16.1186 + notifyIn = null;
16.1187 + setPairs(ep);
16.1188 + }
16.1189 + } else {
16.1190 + throw new IllegalStateException(
16.1191 + "Trying to use content for " + al + " but it is already used for " + this.al
16.1192 + ); // NOI18N
16.1193 + }
16.1194 + }
16.1195 +
16.1196 + /** The method to add instance to the lookup with.
16.1197 + * @param pair class/instance pair
16.1198 + */
16.1199 + public final void addPair(Pair<?> pair) {
16.1200 + AbstractLookup a = al;
16.1201 + Executor e = getExecutor();
16.1202 +
16.1203 + if (a != null || e != null) {
16.1204 + a.addPair(pair, e);
16.1205 + } else {
16.1206 + if (notifyIn == null) {
16.1207 + notifyIn = new ArrayList<Pair>(3);
16.1208 + }
16.1209 +
16.1210 + getEarlyPairs().add(pair);
16.1211 + }
16.1212 + }
16.1213 +
16.1214 + /** Remove instance.
16.1215 + * @param pair class/instance pair
16.1216 + */
16.1217 + public final void removePair(Pair<?> pair) {
16.1218 + AbstractLookup a = al;
16.1219 + Executor e = getExecutor();
16.1220 +
16.1221 + if (a != null || e != null) {
16.1222 + a.removePair(pair, e);
16.1223 + } else {
16.1224 + if (notifyIn == null) {
16.1225 + notifyIn = new ArrayList<Pair>(3);
16.1226 + }
16.1227 +
16.1228 + getEarlyPairs().remove(pair);
16.1229 + }
16.1230 + }
16.1231 +
16.1232 + /** Changes all pairs in the lookup to new values.
16.1233 + * @param c the collection of (Pair) objects
16.1234 + */
16.1235 + public final void setPairs(Collection<? extends Pair> c) {
16.1236 + AbstractLookup a = al;
16.1237 + Executor e = getExecutor();
16.1238 +
16.1239 + if (a != null || e != null) {
16.1240 + a.setPairs(c, e);
16.1241 + } else {
16.1242 + notifyIn = new ArrayList<Pair>(c);
16.1243 + }
16.1244 + }
16.1245 +
16.1246 + @SuppressWarnings("unchecked")
16.1247 + private ArrayList<Pair> getEarlyPairs() {
16.1248 + Object o = notifyIn;
16.1249 + return o instanceof ArrayList ? (ArrayList<Pair>)o : null;
16.1250 + }
16.1251 +
16.1252 + private Executor getExecutor() {
16.1253 + Object o = notifyIn;
16.1254 + return o instanceof Executor ? (Executor)o : null;
16.1255 + }
16.1256 + }
16.1257 + // end of Content
16.1258 +
16.1259 + /** Just a holder for index & modified values.
16.1260 + */
16.1261 + final static class Info extends Object {
16.1262 + public int index;
16.1263 + public Object transaction;
16.1264 +
16.1265 + public Info(int i, Object t) {
16.1266 + index = i;
16.1267 + transaction = t;
16.1268 + }
16.1269 + }
16.1270 +
16.1271 + /** Reference to a result R
16.1272 + */
16.1273 + static final class ReferenceToResult<T> extends WeakReference<R<T>> implements Runnable {
16.1274 + /** next refernece in chain, modified only from AbstractLookup or this */
16.1275 + private ReferenceToResult<?> next;
16.1276 +
16.1277 + /** the template for the result */
16.1278 + public final Template<T> template;
16.1279 +
16.1280 + /** the lookup we are attached to */
16.1281 + public final AbstractLookup lookup;
16.1282 +
16.1283 + /** caches for results */
16.1284 + public Object caches;
16.1285 +
16.1286 + /** Creates a weak refernece to a new result R in context of lookup
16.1287 + * for given template
16.1288 + */
16.1289 + private ReferenceToResult(R<T> result, AbstractLookup lookup, Template<T> template) {
16.1290 + super(result, activeQueue());
16.1291 + this.template = template;
16.1292 + this.lookup = lookup;
16.1293 + getResult().reference = this;
16.1294 + }
16.1295 +
16.1296 + /** Returns the result or null
16.1297 + */
16.1298 + R<T> getResult() {
16.1299 + return get();
16.1300 + }
16.1301 +
16.1302 + /** Cleans the reference. Implements Runnable interface, do not call
16.1303 + * directly.
16.1304 + */
16.1305 + public void run() {
16.1306 + lookup.cleanUpResult(this.template);
16.1307 + }
16.1308 +
16.1309 + /** Clones the reference list to given Storage.
16.1310 + * @param storage storage to clone to
16.1311 + */
16.1312 + public void cloneList(AbstractLookup.Storage<?> storage) {
16.1313 + ReferenceIterator it = new ReferenceIterator(this);
16.1314 +
16.1315 + while (it.next()) {
16.1316 + ReferenceToResult<?> current = it.current();
16.1317 + ReferenceToResult<?> newRef = current.cloneRef();
16.1318 + newRef.next = storage.registerReferenceToResult(newRef);
16.1319 + newRef.caches = current.caches;
16.1320 +
16.1321 + if (current.caches == current) {
16.1322 + current.getResult().initItems(storage);
16.1323 + }
16.1324 + }
16.1325 + }
16.1326 +
16.1327 + private ReferenceToResult<T> cloneRef() {
16.1328 + return new ReferenceToResult<T>(getResult(), lookup, template);
16.1329 + }
16.1330 + }
16.1331 + // end of ReferenceToResult
16.1332 +
16.1333 + /** Supporting class to iterate over linked list of ReferenceToResult
16.1334 + * Use:
16.1335 + * <PRE>
16.1336 + * ReferenceIterator it = new ReferenceIterator (this.ref);
16.1337 + * while (it.next ()) {
16.1338 + * it.current (): // do some work
16.1339 + * }
16.1340 + * this.ref = it.first (); // remember the first one
16.1341 + */
16.1342 + static final class ReferenceIterator extends Object {
16.1343 + private ReferenceToResult<?> first;
16.1344 + private ReferenceToResult<?> current;
16.1345 +
16.1346 + /** hard reference to current result, so it is not GCed meanwhile */
16.1347 + private R<?> currentResult;
16.1348 +
16.1349 + /** Initializes the iterator with first reference.
16.1350 + */
16.1351 + public ReferenceIterator(ReferenceToResult<?> first) {
16.1352 + this.first = first;
16.1353 + }
16.1354 +
16.1355 + /** Moves the current to next possition */
16.1356 + public boolean next() {
16.1357 + ReferenceToResult<?> prev;
16.1358 + ReferenceToResult<?> ref;
16.1359 +
16.1360 + if (current == null) {
16.1361 + ref = first;
16.1362 + prev = null;
16.1363 + } else {
16.1364 + prev = current;
16.1365 + ref = current.next;
16.1366 + }
16.1367 +
16.1368 + while (ref != null) {
16.1369 + R<?> result = ref.get();
16.1370 +
16.1371 + if (result == null) {
16.1372 + if (prev == null) {
16.1373 + // move the head
16.1374 + first = ref.next;
16.1375 + } else {
16.1376 + // skip over this reference
16.1377 + prev.next = ref.next;
16.1378 + }
16.1379 +
16.1380 + prev = ref;
16.1381 + ref = ref.next;
16.1382 + } else {
16.1383 + // we have found next item
16.1384 + currentResult = result;
16.1385 + current = ref;
16.1386 +
16.1387 + return true;
16.1388 + }
16.1389 + }
16.1390 +
16.1391 + currentResult = null;
16.1392 + current = null;
16.1393 +
16.1394 + return false;
16.1395 + }
16.1396 +
16.1397 + /** Access to current reference.
16.1398 + */
16.1399 + public ReferenceToResult<?> current() {
16.1400 + return current;
16.1401 + }
16.1402 +
16.1403 + /** Access to reference that is supposed to be the first one.
16.1404 + */
16.1405 + public ReferenceToResult<?> first() {
16.1406 + return first;
16.1407 + }
16.1408 + }
16.1409 +
16.1410 + /** Signals that a lookup is being modified from a lookup query.
16.1411 + *
16.1412 + * @author Jaroslav Tulach
16.1413 + */
16.1414 + static final class ISE extends IllegalStateException {
16.1415 + static final long serialVersionUID = 100L;
16.1416 +
16.1417 + /** list of jobs to execute. */
16.1418 + private java.util.List<Job> jobs;
16.1419 +
16.1420 + /** @param msg message
16.1421 + */
16.1422 + public ISE(String msg) {
16.1423 + super(msg);
16.1424 + }
16.1425 +
16.1426 + /** Registers a job to be executed partially out and partially in
16.1427 + * the lock over storage.
16.1428 + */
16.1429 + public void registerJob(Job job) {
16.1430 + if (jobs == null) {
16.1431 + jobs = new java.util.ArrayList<Job>();
16.1432 + }
16.1433 +
16.1434 + jobs.add(job);
16.1435 + }
16.1436 +
16.1437 + /** Executes the jobs outside, and then inside a locked session.
16.1438 + */
16.1439 + public void recover(AbstractLookup lookup) {
16.1440 + if (jobs == null) {
16.1441 + // no recovery plan, throw itself
16.1442 + throw this;
16.1443 + }
16.1444 +
16.1445 + for (Job j : jobs) {
16.1446 + j.before();
16.1447 + }
16.1448 +
16.1449 + AbstractLookup.Storage s = lookup.enterStorage();
16.1450 +
16.1451 + try {
16.1452 + for (Job j : jobs) {
16.1453 + j.inside();
16.1454 + }
16.1455 + } finally {
16.1456 + lookup.exitStorage();
16.1457 + }
16.1458 + }
16.1459 +
16.1460 + /** A job to be executed partially outside and partially inside
16.1461 + * the storage lock.
16.1462 + */
16.1463 + static interface Job {
16.1464 + public void before();
16.1465 +
16.1466 + public void inside();
16.1467 + }
16.1468 + }
16.1469 + // end of ISE
16.1470 +}
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ArrayStorage.java Mon Dec 14 20:58:39 2009 +0100
17.3 @@ -0,0 +1,477 @@
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;
17.47 +
17.48 +
17.49 +
17.50 +import java.util.*;
17.51 +import org.openide.util.lookup.AbstractLookup.Pair;
17.52 +
17.53 +
17.54 +/** ArrayStorage of Pairs from AbstractLookup.
17.55 + * @author Jaroslav Tulach
17.56 + */
17.57 +final class ArrayStorage extends Object
17.58 +implements AbstractLookup.Storage<ArrayStorage.Transaction> {
17.59 + /** default trashold */
17.60 + static final Integer DEFAULT_TRASH = new Integer(11);
17.61 +
17.62 + /** list of items */
17.63 + private Object content;
17.64 +
17.65 + /** linked list of refernces to results */
17.66 + private transient AbstractLookup.ReferenceToResult<?> results;
17.67 +
17.68 + /** Constructor
17.69 + */
17.70 + public ArrayStorage() {
17.71 + this(DEFAULT_TRASH);
17.72 + }
17.73 +
17.74 + /** Constructs new ArrayStorage */
17.75 + public ArrayStorage(Integer treshhold) {
17.76 + this.content = treshhold;
17.77 + }
17.78 +
17.79 + /** Adds an item into the tree.
17.80 + * @param item to add
17.81 + * @return true if the Item has been added for the first time or false if some other
17.82 + * item equal to this one already existed in the lookup
17.83 + */
17.84 + public boolean add(AbstractLookup.Pair<?> item, Transaction changed) {
17.85 + Object[] arr = changed.current;
17.86 +
17.87 + if (changed.arr == null) {
17.88 + // just simple add of one item
17.89 + for (int i = 0; i < arr.length; i++) {
17.90 + if (arr[i] == null) {
17.91 + arr[i] = item;
17.92 + changed.add(item);
17.93 +
17.94 + return true;
17.95 + }
17.96 +
17.97 + if (arr[i].equals(item)) {
17.98 + // reassign the item number
17.99 + item.setIndex(null, ((AbstractLookup.Pair) arr[i]).getIndex());
17.100 +
17.101 + // already there, but update it
17.102 + arr[i] = item;
17.103 +
17.104 + return false;
17.105 + }
17.106 + }
17.107 +
17.108 + // cannot happen as the beginTransaction ensured we can finish
17.109 + // correctly
17.110 + throw new IllegalStateException();
17.111 + } else {
17.112 + // doing remainAll after that, let Transaction hold the new array
17.113 + int newIndex = changed.addPair(item);
17.114 +
17.115 + for (int i = 0; i < arr.length; i++) {
17.116 + if (arr[i] == null) {
17.117 + changed.add(item);
17.118 +
17.119 + return true;
17.120 + }
17.121 +
17.122 + if (arr[i].equals(item)) {
17.123 + // already there
17.124 + if (i != newIndex) {
17.125 + // change in index
17.126 + changed.add(item);
17.127 +
17.128 + return false;
17.129 + } else {
17.130 + // no change
17.131 + return false;
17.132 + }
17.133 + }
17.134 + }
17.135 +
17.136 + // if not found in the original array
17.137 + changed.add(item);
17.138 +
17.139 + return true;
17.140 + }
17.141 + }
17.142 +
17.143 + /** Removes an item.
17.144 + */
17.145 + public void remove(AbstractLookup.Pair item, Transaction changed) {
17.146 + Object[] arr = changed.current;
17.147 + if (arr == null) {
17.148 + return;
17.149 + }
17.150 +
17.151 + int found = -1;
17.152 +
17.153 + for (int i = 0; i < arr.length;) {
17.154 + if (arr[i] == null) {
17.155 + // end of task
17.156 + return;
17.157 + }
17.158 +
17.159 + if ((found == -1) && arr[i].equals(item)) {
17.160 + // already there
17.161 + Pair<?> p = (Pair<?>)arr[i];
17.162 + p.setIndex(null, -1);
17.163 + changed.add(p);
17.164 + found = i;
17.165 + }
17.166 +
17.167 + i++;
17.168 +
17.169 + if (found != -1) {
17.170 + if (i < arr.length && !(arr[i] instanceof Integer)) {
17.171 + // moving the array
17.172 + arr[i - 1] = arr[i];
17.173 + } else {
17.174 + arr[i - 1] = null;
17.175 + }
17.176 + }
17.177 + }
17.178 + }
17.179 +
17.180 + /** Removes all items that are not present in the provided collection.
17.181 + * @param retain Pair -> AbstractLookup.Info map
17.182 + * @param notify set of Classes that has possibly changed
17.183 + */
17.184 + public void retainAll(Map retain, Transaction changed) {
17.185 + Object[] arr = changed.current;
17.186 +
17.187 + for (int from = 0; from < arr.length; from++) {
17.188 + if (!(arr[from] instanceof AbstractLookup.Pair)) {
17.189 + // end of content
17.190 + break;
17.191 + }
17.192 +
17.193 + AbstractLookup.Pair p = (AbstractLookup.Pair) arr[from];
17.194 +
17.195 + AbstractLookup.Info info = (AbstractLookup.Info) retain.get(p);
17.196 +
17.197 + if (info == null) {
17.198 + // was removed
17.199 +
17.200 + /*
17.201 + if (info != null) {
17.202 + if (info.index < arr.length) {
17.203 + newArr[info.index] = p;
17.204 + }
17.205 +
17.206 + if (p.getIndex() != info.index) {
17.207 + p.setIndex (null, info.index);
17.208 + changed.add (p);
17.209 + }
17.210 + } else {
17.211 + // removed
17.212 + */
17.213 + changed.add(p);
17.214 + }
17.215 + }
17.216 + }
17.217 +
17.218 + /** Queries for instances of given class.
17.219 + * @param clazz the class to check
17.220 + * @return enumeration of Item
17.221 + * @see #unsorted
17.222 + */
17.223 + public <T> Enumeration<Pair<T>> lookup(final Class<T> clazz) {
17.224 + if (content instanceof Object[]) {
17.225 + final Enumeration<Object> all = InheritanceTree.arrayEn((Object[]) content);
17.226 + class JustPairs implements Enumeration<Pair<T>> {
17.227 + private Pair<T> next;
17.228 +
17.229 + @SuppressWarnings("unchecked")
17.230 + private Pair<T> findNext() {
17.231 + for (;;) {
17.232 + if (next != null) {
17.233 + return next;
17.234 + }
17.235 + if (!all.hasMoreElements()) {
17.236 + return null;
17.237 + }
17.238 + Object o = all.nextElement();
17.239 + boolean ok;
17.240 + if (o instanceof AbstractLookup.Pair) {
17.241 + ok = (clazz == null) || ((AbstractLookup.Pair<?>) o).instanceOf(clazz);
17.242 + } else {
17.243 + ok = false;
17.244 + }
17.245 +
17.246 + next = ok ? (Pair<T>) o : null;
17.247 + }
17.248 + }
17.249 +
17.250 + public boolean hasMoreElements() {
17.251 + return findNext() != null;
17.252 + }
17.253 +
17.254 + public Pair<T> nextElement() {
17.255 + Pair<T> r = findNext();
17.256 + if (r == null) {
17.257 + throw new NoSuchElementException();
17.258 + }
17.259 + next = null;
17.260 + return r;
17.261 + }
17.262 + } // end of JustPairs
17.263 + return new JustPairs();
17.264 + } else {
17.265 + return InheritanceTree.emptyEn();
17.266 + }
17.267 + }
17.268 +
17.269 + /** Associates another result with this storage.
17.270 + */
17.271 + public AbstractLookup.ReferenceToResult registerReferenceToResult(AbstractLookup.ReferenceToResult<?> newRef) {
17.272 + AbstractLookup.ReferenceToResult prev = this.results;
17.273 + this.results = newRef;
17.274 +
17.275 + return prev;
17.276 + }
17.277 +
17.278 + /** Cleanup the references
17.279 + */
17.280 + public AbstractLookup.ReferenceToResult cleanUpResult(Lookup.Template<?> templ) {
17.281 + AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
17.282 +
17.283 + while (it.next()) {
17.284 + // empty
17.285 + }
17.286 +
17.287 + return this.results = it.first();
17.288 + }
17.289 +
17.290 + /** We use a hash set of all modified Pair to handle the transaction */
17.291 + public Transaction beginTransaction(int ensure) {
17.292 + return new Transaction(ensure, content);
17.293 + }
17.294 +
17.295 + /** Extract all results.
17.296 + */
17.297 + public void endTransaction(Transaction changed, Set<AbstractLookup.R> modified) {
17.298 + AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
17.299 +
17.300 + if (changed.arr == null) {
17.301 + // either add or remove, only check the content of check HashSet
17.302 + while (it.next()) {
17.303 + AbstractLookup.ReferenceToResult ref = it.current();
17.304 + Iterator<Pair<?>> pairs = changed.iterator();
17.305 +
17.306 + while (pairs.hasNext()) {
17.307 + AbstractLookup.Pair p = (AbstractLookup.Pair) pairs.next();
17.308 +
17.309 + if (AbstractLookup.matches(ref.template, p, true)) {
17.310 + modified.add(ref.getResult());
17.311 + }
17.312 + }
17.313 + }
17.314 + } else {
17.315 + // do full check of changes
17.316 + while (it.next()) {
17.317 + AbstractLookup.ReferenceToResult ref = it.current();
17.318 +
17.319 + int oldIndex = -1;
17.320 + int newIndex = -1;
17.321 +
17.322 + for (;;) {
17.323 + oldIndex = findMatching(ref.template, changed.current, oldIndex);
17.324 + newIndex = findMatching(ref.template, changed.arr, newIndex);
17.325 +
17.326 + if ((oldIndex == -1) && (newIndex == -1)) {
17.327 + break;
17.328 + }
17.329 +
17.330 + if (
17.331 + (oldIndex == -1) || (newIndex == -1) ||
17.332 + !changed.current[oldIndex].equals(changed.arr[newIndex])
17.333 + ) {
17.334 + modified.add(ref.getResult());
17.335 +
17.336 + break;
17.337 + }
17.338 + }
17.339 + }
17.340 + }
17.341 +
17.342 + this.results = it.first();
17.343 + this.content = changed.newContent(this.content);
17.344 + }
17.345 +
17.346 + private static int findMatching(Lookup.Template t, Object[] arr, int from) {
17.347 + while (++from < arr.length) {
17.348 + if (arr[from] instanceof AbstractLookup.Pair) {
17.349 + if (AbstractLookup.matches(t, (AbstractLookup.Pair) arr[from], true)) {
17.350 + return from;
17.351 + }
17.352 + }
17.353 + }
17.354 +
17.355 + return -1;
17.356 + }
17.357 +
17.358 + /** HashSet with additional field for new array which is callocated
17.359 + * in case we are doing replace to hold all new items.
17.360 + */
17.361 + static final class Transaction extends HashSet<Pair<?>> {
17.362 + /** array with current objects */
17.363 + public final Object[] current;
17.364 +
17.365 + /** array with new objects */
17.366 + public final Object[] arr;
17.367 +
17.368 + /** number of objects in the array */
17.369 + private int cnt;
17.370 +
17.371 + public Transaction(int ensure, Object currentContent) {
17.372 + Integer trashold;
17.373 + Object[] _arr;
17.374 +
17.375 + if (currentContent instanceof Integer) {
17.376 + trashold = (Integer) currentContent;
17.377 + _arr = null;
17.378 + } else {
17.379 + _arr = (Object[]) currentContent;
17.380 +
17.381 + if (_arr[_arr.length - 1] instanceof Integer) {
17.382 + trashold = (Integer) _arr[_arr.length - 1];
17.383 + } else {
17.384 + // nowhere to grow we have reached the limit
17.385 + trashold = null;
17.386 + }
17.387 + }
17.388 +
17.389 + int maxSize = (trashold == null) ? _arr.length : trashold.intValue();
17.390 +
17.391 + if (ensure > maxSize) {
17.392 + throw new UnsupportedOperationException();
17.393 + }
17.394 +
17.395 + if (ensure == -1) {
17.396 + // remove => it is ok
17.397 + this.current = currentContent instanceof Integer ? null : (Object[]) currentContent;
17.398 + this.arr = null;
17.399 +
17.400 + return;
17.401 + }
17.402 +
17.403 + if (ensure == -2) {
17.404 + // adding one
17.405 + if (_arr == null) {
17.406 + // first time add, let's allocate the array
17.407 + _arr = new Object[2];
17.408 + _arr[1] = trashold;
17.409 + } else {
17.410 + if (_arr[_arr.length - 1] instanceof AbstractLookup.Pair) {
17.411 + // we are full
17.412 + throw new UnsupportedOperationException();
17.413 + } else {
17.414 + // ensure we have allocated enough space
17.415 + if (_arr.length < 2 || _arr[_arr.length - 2] != null) {
17.416 + // double the array
17.417 + int newSize = (_arr.length - 1) * 2;
17.418 +
17.419 + if (newSize <= 1) {
17.420 + newSize = 2;
17.421 + }
17.422 +
17.423 + if (newSize > maxSize) {
17.424 + newSize = maxSize;
17.425 +
17.426 + if (newSize <= _arr.length) {
17.427 + // no space to get in
17.428 + throw new UnsupportedOperationException();
17.429 + }
17.430 +
17.431 + _arr = new Object[newSize];
17.432 + } else {
17.433 + // still a lot of space
17.434 + _arr = new Object[newSize + 1];
17.435 + _arr[newSize] = trashold;
17.436 + }
17.437 +
17.438 + // copy content of original array without the last Integer into
17.439 + // the new one
17.440 + System.arraycopy(currentContent, 0, _arr, 0, ((Object[]) currentContent).length - 1);
17.441 + }
17.442 + }
17.443 + }
17.444 +
17.445 + this.current = _arr;
17.446 + this.arr = null;
17.447 + } else {
17.448 + // allocate array for complete replacement
17.449 + if (ensure == maxSize) {
17.450 + this.arr = new Object[ensure];
17.451 + } else {
17.452 + this.arr = new Object[ensure + 1];
17.453 + this.arr[ensure] = trashold;
17.454 + }
17.455 +
17.456 + this.current = (currentContent instanceof Object[]) ? (Object[]) currentContent : new Object[0];
17.457 + }
17.458 + }
17.459 +
17.460 + public int addPair(AbstractLookup.Pair<?> p) {
17.461 + p.setIndex(null, cnt);
17.462 + arr[cnt++] = p;
17.463 +
17.464 + return p.getIndex();
17.465 + }
17.466 +
17.467 + public Object newContent(Object prev) {
17.468 + if (arr == null) {
17.469 + if (current == null) {
17.470 + return prev;
17.471 + } else {
17.472 + return current;
17.473 + }
17.474 + } else {
17.475 + return arr;
17.476 + }
17.477 + }
17.478 + }
17.479 + // end of Transaction
17.480 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/Bundle.properties Mon Dec 14 20:58:39 2009 +0100
18.3 @@ -0,0 +1,1 @@
18.4 +OpenIDE-Module-Name=Lookup
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/DelegatingStorage.java Mon Dec 14 20:58:39 2009 +0100
19.3 @@ -0,0 +1,180 @@
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 +package org.openide.util.lookup;
19.45 +
19.46 +import org.openide.util.Lookup;
19.47 +
19.48 +import java.io.*;
19.49 +
19.50 +import java.lang.ref.WeakReference;
19.51 +
19.52 +import java.util.*;
19.53 +import org.openide.util.lookup.AbstractLookup.Pair;
19.54 +
19.55 +
19.56 +/** Storages that can switch between another storages.
19.57 + * @author Jaroslav Tulach
19.58 + */
19.59 +final class DelegatingStorage<Transaction> extends Object
19.60 +implements Serializable, AbstractLookup.Storage<Transaction> {
19.61 + /** object to delegate to */
19.62 + private AbstractLookup.Storage<Transaction> delegate;
19.63 +
19.64 + /** thread just accessing the storage */
19.65 + private Thread owner;
19.66 +
19.67 + public DelegatingStorage(AbstractLookup.Storage<Transaction> d) {
19.68 + this.delegate = d;
19.69 + this.owner = Thread.currentThread();
19.70 + }
19.71 +
19.72 + /** Never serialize yourself, always put there the delegate */
19.73 + public Object writeReplace() {
19.74 + return this.delegate;
19.75 + }
19.76 +
19.77 + /** Method to check whether there is not multiple access from the same thread.
19.78 + */
19.79 + public void checkForTreeModification() {
19.80 + if (Thread.currentThread() == owner) {
19.81 + throw new AbstractLookup.ISE("You are trying to modify lookup from lookup query!"); // NOI18N
19.82 + }
19.83 + }
19.84 +
19.85 + /** Checks whether we have simple behaviour or complex.
19.86 + */
19.87 + public static boolean isSimple(AbstractLookup.Storage s) {
19.88 + if (s instanceof DelegatingStorage) {
19.89 + return ((DelegatingStorage) s).delegate instanceof ArrayStorage;
19.90 + } else {
19.91 + return s instanceof ArrayStorage;
19.92 + }
19.93 + }
19.94 +
19.95 + /** Exits from the owners ship of the storage.
19.96 + */
19.97 + public AbstractLookup.Storage<Transaction> exitDelegate() {
19.98 + if (Thread.currentThread() != owner) {
19.99 + throw new IllegalStateException("Onwer: " + owner + " caller: " + Thread.currentThread()); // NOI18N
19.100 + }
19.101 +
19.102 + AbstractLookup.Storage<Transaction> d = delegate;
19.103 + delegate = null;
19.104 +
19.105 + return d;
19.106 + }
19.107 +
19.108 + public boolean add(AbstractLookup.Pair<?> item, Transaction transaction) {
19.109 + return delegate.add(item, transaction);
19.110 + }
19.111 +
19.112 + public void remove(org.openide.util.lookup.AbstractLookup.Pair item, Transaction transaction) {
19.113 + delegate.remove(item, transaction);
19.114 + }
19.115 +
19.116 + public void retainAll(Map retain, Transaction transaction) {
19.117 + delegate.retainAll(retain, transaction);
19.118 + }
19.119 +
19.120 + /** A special method to change the backing storage.
19.121 + * In fact it is not much typesafe as it changes the
19.122 + * type of Transaction but we know that nobody is currently
19.123 + * holding a transaction object, so there cannot be inconsitencies.
19.124 + */
19.125 + @SuppressWarnings("unchecked")
19.126 + private void changeDelegate(InheritanceTree st) {
19.127 + delegate = (AbstractLookup.Storage<Transaction>)st;
19.128 + }
19.129 +
19.130 + public Transaction beginTransaction(int ensure) {
19.131 + try {
19.132 + return delegate.beginTransaction(ensure);
19.133 + } catch (UnsupportedOperationException ex) {
19.134 + // let's convert to InheritanceTree
19.135 + ArrayStorage arr = (ArrayStorage) delegate;
19.136 + InheritanceTree inh = new InheritanceTree();
19.137 + changeDelegate(inh);
19.138 +
19.139 + //
19.140 + // Copy content
19.141 + //
19.142 + Enumeration<Pair<Object>> en = arr.lookup(Object.class);
19.143 +
19.144 + while (en.hasMoreElements()) {
19.145 + if (!inh.add(en.nextElement(), new ArrayList<Class>())) {
19.146 + throw new IllegalStateException("All objects have to be accepted"); // NOI18N
19.147 + }
19.148 + }
19.149 +
19.150 + //
19.151 + // Copy listeners
19.152 + //
19.153 + AbstractLookup.ReferenceToResult<?> ref = arr.cleanUpResult(null);
19.154 +
19.155 + if (ref != null) {
19.156 + ref.cloneList(inh);
19.157 + }
19.158 +
19.159 + // we have added the current content and now we can start transaction
19.160 + return delegate.beginTransaction(ensure);
19.161 + }
19.162 + }
19.163 +
19.164 + public org.openide.util.lookup.AbstractLookup.ReferenceToResult cleanUpResult(
19.165 + org.openide.util.Lookup.Template templ
19.166 + ) {
19.167 + return delegate.cleanUpResult(templ);
19.168 + }
19.169 +
19.170 + public void endTransaction(Transaction transaction, Set<AbstractLookup.R> modified) {
19.171 + delegate.endTransaction(transaction, modified);
19.172 + }
19.173 +
19.174 + public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
19.175 + return delegate.lookup(clazz);
19.176 + }
19.177 +
19.178 + public org.openide.util.lookup.AbstractLookup.ReferenceToResult registerReferenceToResult(
19.179 + org.openide.util.lookup.AbstractLookup.ReferenceToResult newRef
19.180 + ) {
19.181 + return delegate.registerReferenceToResult(newRef);
19.182 + }
19.183 +}
20.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
20.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ExcludingLookup.java Mon Dec 14 20:58:39 2009 +0100
20.3 @@ -0,0 +1,428 @@
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 +package org.openide.util.lookup;
20.45 +
20.46 +import java.lang.ref.Reference;
20.47 +import java.lang.ref.WeakReference;
20.48 +import org.openide.util.Lookup;
20.49 +import org.openide.util.LookupListener;
20.50 +
20.51 +import java.util.*;
20.52 +import org.openide.util.LookupEvent;
20.53 +
20.54 +
20.55 +/** Allows exclusion of certain instances from lookup.
20.56 + *
20.57 + * @author Jaroslav Tulach
20.58 + */
20.59 +final class ExcludingLookup extends org.openide.util.Lookup {
20.60 + /** the other lookup that we delegate to */
20.61 + private Lookup delegate;
20.62 +
20.63 + /** classes to exclude (Class[]) or just one class (Class) */
20.64 + private Object classes;
20.65 +
20.66 + /**
20.67 + * Creates new Result object with supplied instances parameter.
20.68 + * @param instances to be used to return from the lookup
20.69 + */
20.70 + ExcludingLookup(Lookup delegate, Class[] classes) {
20.71 + this.delegate = delegate;
20.72 +
20.73 + for (Class c : classes) {
20.74 + if (c == null) {
20.75 + throw new NullPointerException();
20.76 + }
20.77 + }
20.78 + if (classes.length == 1) {
20.79 + this.classes = classes[0];
20.80 + } else {
20.81 + this.classes = classes;
20.82 + }
20.83 + }
20.84 +
20.85 + @Override
20.86 + public String toString() {
20.87 + return "ExcludingLookup: " + delegate + " excludes: " + Arrays.asList(classes()); // NOI18N
20.88 + }
20.89 +
20.90 + public <T> Result<T> lookup(Template<T> template) {
20.91 + if (template == null) {
20.92 + throw new NullPointerException();
20.93 + }
20.94 +
20.95 + if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
20.96 + // empty result
20.97 + return Lookup.EMPTY.lookup(template);
20.98 + }
20.99 +
20.100 + return new R<T>(template.getType(), delegate.lookup(template));
20.101 + }
20.102 +
20.103 + public <T> T lookup(Class<T> clazz) {
20.104 + if (areSubclassesOfThisClassAlwaysExcluded(clazz)) {
20.105 + return null;
20.106 + }
20.107 +
20.108 + T res = delegate.lookup(clazz);
20.109 +
20.110 + if (isObjectAccessible(clazz, res, 0)) {
20.111 + return res;
20.112 + } else {
20.113 + return null;
20.114 + }
20.115 + }
20.116 +
20.117 + @Override
20.118 + public <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
20.119 + if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
20.120 + return null;
20.121 + }
20.122 +
20.123 + Lookup.Item<T> retValue = delegate.lookupItem(template);
20.124 +
20.125 + if (isObjectAccessible(template.getType(), retValue, 2)) {
20.126 + return retValue;
20.127 + } else {
20.128 + return null;
20.129 + }
20.130 + }
20.131 +
20.132 + /** @return true if the instance of class c shall never be returned from this lookup
20.133 + */
20.134 + private boolean areSubclassesOfThisClassAlwaysExcluded(Class<?> c) {
20.135 + Class<?>[] arr = classes();
20.136 +
20.137 + for (int i = 0; i < arr.length; i++) {
20.138 + if (arr[i].isAssignableFrom(c)) {
20.139 + return true;
20.140 + }
20.141 + }
20.142 +
20.143 + return false;
20.144 + }
20.145 +
20.146 + /** Returns the array of classes this lookup filters.
20.147 + */
20.148 + final Class<?>[] classes() {
20.149 + if (classes instanceof Class[]) {
20.150 + return (Class[]) classes;
20.151 + } else {
20.152 + return new Class[] { (Class) classes };
20.153 + }
20.154 + }
20.155 +
20.156 + /** Does a check whether two classes are accessible (in the super/sub class)
20.157 + * releation ship without walking thru any of the classes mentioned in the
20.158 + * barrier.
20.159 + */
20.160 + private static boolean isAccessible(Class<?>[] barriers, Class<?> from, Class<?> to) {
20.161 + if ((to == null) || !from.isAssignableFrom(to)) {
20.162 + // no way to reach each other by walking up
20.163 + return false;
20.164 + }
20.165 +
20.166 + for (int i = 0; i < barriers.length; i++) {
20.167 + if (to == barriers[i]) {
20.168 + return false;
20.169 + }
20.170 + }
20.171 +
20.172 + if (from == to) {
20.173 + return true;
20.174 + }
20.175 +
20.176 + //
20.177 + // depth first search
20.178 + //
20.179 + if (isAccessible(barriers, from, to.getSuperclass())) {
20.180 + return true;
20.181 + }
20.182 +
20.183 + Class[] interfaces = to.getInterfaces();
20.184 +
20.185 + for (int i = 0; i < interfaces.length; i++) {
20.186 + if (isAccessible(barriers, from, interfaces[i])) {
20.187 + return true;
20.188 + }
20.189 + }
20.190 +
20.191 + return false;
20.192 + }
20.193 +
20.194 + /** based on type decides whether the class accepts or not anObject
20.195 + * @param from the base type of the query
20.196 + * @param to depending on value of type either Object, Class or Item
20.197 + * @param type 0,1,2 for Object, Class or Item
20.198 + * @return true if we can access the to from from by walking around the bariers
20.199 + */
20.200 + private final boolean isObjectAccessible(Class from, Object to, int type) {
20.201 + if (to == null) {
20.202 + return false;
20.203 + }
20.204 +
20.205 + return isObjectAccessible(classes(), from, to, type);
20.206 + }
20.207 +
20.208 + /** based on type decides whether the class accepts or not anObject
20.209 + * @param barriers classes to avoid when testing reachability
20.210 + * @param from the base type of the query
20.211 + * @param to depending on value of type either Object, Class or Item
20.212 + * @param type 0,1,2 for Object, Class or Item
20.213 + * @return true if we can access the to from from by walking around the bariers
20.214 + */
20.215 + static final boolean isObjectAccessible(Class[] barriers, Class from, Object to, int type) {
20.216 + if (to == null) {
20.217 + return false;
20.218 + }
20.219 +
20.220 + switch (type) {
20.221 + case 0:
20.222 + return isAccessible(barriers, from, to.getClass());
20.223 +
20.224 + case 1:
20.225 + return isAccessible(barriers, from, (Class) to);
20.226 +
20.227 + case 2: {
20.228 + Item item = (Item) to;
20.229 +
20.230 + return isAccessible(barriers, from, item.getType());
20.231 + }
20.232 +
20.233 + default:
20.234 + throw new IllegalStateException("Type: " + type);
20.235 + }
20.236 + }
20.237 +
20.238 + /** Filters collection accroding to set of given filters.
20.239 + */
20.240 + final <E, T extends Collection<E>> T filter(
20.241 + Class<?>[] arr, Class<?> from, T c, int type, T prototype
20.242 + ) {
20.243 + T ret = null;
20.244 +
20.245 +
20.246 +// optimistic strategy expecting we will not need to filter
20.247 +TWICE:
20.248 + for (;;) {
20.249 + Iterator<E> it = c.iterator();
20.250 +BIG:
20.251 + while (it.hasNext()) {
20.252 + E res = it.next();
20.253 +
20.254 + if (!isObjectAccessible(arr, from, res, type)) {
20.255 + if (ret == null) {
20.256 + // we need to restart the scanning again
20.257 + // as there is an active filter
20.258 + ret = prototype;
20.259 + continue TWICE;
20.260 + }
20.261 +
20.262 + continue BIG;
20.263 + }
20.264 +
20.265 + if (ret != null) {
20.266 + // if we are running the second round from TWICE
20.267 + ret.add(res);
20.268 + }
20.269 + }
20.270 +
20.271 + // ok, processed
20.272 + break TWICE;
20.273 + }
20.274 +
20.275 + return (ret != null) ? ret : c;
20.276 + }
20.277 +
20.278 + /** Delegating result that filters unwanted items and instances.
20.279 + */
20.280 + private final class R<T> extends WaitableResult<T> implements LookupListener {
20.281 + private Result<T> result;
20.282 + private WeakResult<T> weak;
20.283 + private Object listeners;
20.284 + private Class<?> from;
20.285 +
20.286 + R(Class<?> from, Result<T> delegate) {
20.287 + this.from = from;
20.288 + this.result = delegate;
20.289 + this.weak = new WeakResult<T>(this, delegate);
20.290 + }
20.291 +
20.292 + protected void beforeLookup(Template t) {
20.293 + if (result instanceof WaitableResult) {
20.294 + ((WaitableResult) result).beforeLookup(t);
20.295 + }
20.296 + }
20.297 +
20.298 + public void addLookupListener(LookupListener l) {
20.299 + boolean add;
20.300 +
20.301 + synchronized (this) {
20.302 + listeners = AbstractLookup.modifyListenerList(true, l, listeners);
20.303 + add = listeners != null;
20.304 + }
20.305 +
20.306 + if (add) {
20.307 + result.addLookupListener(weak);
20.308 + }
20.309 + }
20.310 +
20.311 + public void removeLookupListener(LookupListener l) {
20.312 + boolean remove;
20.313 +
20.314 + synchronized (this) {
20.315 + listeners = AbstractLookup.modifyListenerList(false, l, listeners);
20.316 + remove = listeners == null;
20.317 + }
20.318 +
20.319 + if (remove) {
20.320 + result.removeLookupListener(weak);
20.321 + }
20.322 + }
20.323 +
20.324 + public Collection<? extends T> allInstances() {
20.325 + return openCol(result.allInstances(), 0);
20.326 + }
20.327 +
20.328 + private <S> Collection<S> openCol(Collection<S> c, int type) {
20.329 + return filter(classes(), from, c, type, new ArrayList<S>(c.size()));
20.330 + }
20.331 +
20.332 + @Override
20.333 + public Set<Class<? extends T>> allClasses() {
20.334 + return filter(classes(), from, result.allClasses(), 1, new HashSet<Class<? extends T>>());
20.335 + }
20.336 +
20.337 + @Override
20.338 + public Collection<? extends Item<T>> allItems() {
20.339 + return openCol(result.allItems(), 2);
20.340 + }
20.341 +
20.342 + public void resultChanged(org.openide.util.LookupEvent ev) {
20.343 + if (ev.getSource() == result) {
20.344 + collectFires(null);
20.345 + }
20.346 + }
20.347 +
20.348 + protected void collectFires(Collection<Object> evAndListeners) {
20.349 + LookupListener[] arr;
20.350 +
20.351 + synchronized (this) {
20.352 + if (listeners == null) {
20.353 + return;
20.354 + }
20.355 +
20.356 + if (listeners instanceof LookupListener) {
20.357 + arr = new LookupListener[] { (LookupListener) listeners };
20.358 + } else {
20.359 + ArrayList<?> l = (ArrayList<?>) listeners;
20.360 + arr = l.toArray(new LookupListener[l.size()]);
20.361 + }
20.362 + }
20.363 +
20.364 + final LookupListener[] ll = arr;
20.365 + final org.openide.util.LookupEvent newev = new org.openide.util.LookupEvent(this);
20.366 + AbstractLookup.notifyListeners(ll, newev, evAndListeners);
20.367 + }
20.368 + } // end of R
20.369 +
20.370 + private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
20.371 + private Lookup.Result source;
20.372 + private Reference<R<T>> result;
20.373 +
20.374 + public WeakResult(R<T> r, Lookup.Result<T> s) {
20.375 + this.result = new WeakReference<R<T>>(r);
20.376 + this.source = s;
20.377 + }
20.378 +
20.379 + protected void beforeLookup(Lookup.Template t) {
20.380 + R r = (R)result.get();
20.381 + if (r != null) {
20.382 + r.beforeLookup(t);
20.383 + } else {
20.384 + source.removeLookupListener(this);
20.385 + }
20.386 + }
20.387 +
20.388 + protected void collectFires(Collection<Object> evAndListeners) {
20.389 + R<T> r = result.get();
20.390 + if (r != null) {
20.391 + r.collectFires(evAndListeners);
20.392 + } else {
20.393 + source.removeLookupListener(this);
20.394 + }
20.395 + }
20.396 +
20.397 + public void addLookupListener(LookupListener l) {
20.398 + assert false;
20.399 + }
20.400 +
20.401 + public void removeLookupListener(LookupListener l) {
20.402 + assert false;
20.403 + }
20.404 +
20.405 + public Collection<T> allInstances() {
20.406 + assert false;
20.407 + return null;
20.408 + }
20.409 +
20.410 + public void resultChanged(LookupEvent ev) {
20.411 + R r = (R)result.get();
20.412 + if (r != null) {
20.413 + r.resultChanged(ev);
20.414 + } else {
20.415 + source.removeLookupListener(this);
20.416 + }
20.417 + }
20.418 +
20.419 + @Override
20.420 + public Collection<? extends Item<T>> allItems() {
20.421 + assert false;
20.422 + return null;
20.423 + }
20.424 +
20.425 + @Override
20.426 + public Set<Class<? extends T>> allClasses() {
20.427 + assert false;
20.428 + return null;
20.429 + }
20.430 + } // end of WeakResult
20.431 +}
21.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
21.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/InheritanceTree.java Mon Dec 14 20:58:39 2009 +0100
21.3 @@ -0,0 +1,1276 @@
21.4 +/*
21.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
21.6 + *
21.7 + * Copyright 1997-2009 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 + * Contributor(s):
21.28 + *
21.29 + * The Original Software is NetBeans. The Initial Developer of the Original
21.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
21.31 + * Microsystems, Inc. All Rights Reserved.
21.32 + *
21.33 + * If you wish your version of this file to be governed by only the CDDL
21.34 + * or only the GPL Version 2, indicate your decision by adding
21.35 + * "[Contributor] elects to include this software in this distribution
21.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
21.37 + * single choice of license, a recipient has the option to distribute
21.38 + * your version of this file under either the CDDL, the GPL Version 2 or
21.39 + * to extend the choice of license to its licensees as provided above.
21.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
21.41 + * Version 2 license, then the option applies only if the new code is
21.42 + * made subject to such option by the copyright holder.
21.43 + */
21.44 +package org.openide.util.lookup;
21.45 +
21.46 +import org.openide.util.Lookup;
21.47 +import org.openide.util.lookup.AbstractLookup.Pair;
21.48 +import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
21.49 +import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
21.50 +
21.51 +import java.io.*;
21.52 +
21.53 +import java.lang.ref.WeakReference;
21.54 +
21.55 +import java.util.*;
21.56 +
21.57 +
21.58 +/** A tree to represent classes with inheritance. Description of the
21.59 + * data structure by Petr Nejedly:
21.60 + * <P>
21.61 + * So pretend I'm Lookup implementation. I've got a bunch of Items (e.g.
21.62 + * setPairs() method),
21.63 + * didn't do anything on them yet (no startup penalty) so I know nothing
21.64 + * about them.
21.65 + * Then I'll be asked for all instances implementing given interface or a
21.66 + * class. I surely need
21.67 + * to check all the Items now, as I don't know anything abou them. I surely
21.68 + * don't want to call
21.69 + * Item.getClass() as it will dismiss the whole effort. So all I have is
21.70 + * Item.instanceOf()
21.71 + * and I'll call it on every Item. I'll cache results, so the next time
21.72 + * you'll ask me for
21.73 + * the same interface/class, I'll answer immediatelly. But what if you ask
21.74 + * me for another
21.75 + * interface/class? I'll have to scan all Items for it again, unless I can
21.76 + * be sure some
21.77 + * of them can't implement it. The only source of this knowledge are the
21.78 + * previous questions
21.79 + * and my rulings on them. Here the algorithm have to be split into two
21.80 + * paths. If you
21.81 + * previously asked me for interfaces only, I'll have no hint for
21.82 + * subsequent queries,
21.83 + * but if you asked me for a class in history, and then for another class
21.84 + * and these classes
21.85 + * are not in inheritance relation (I can check hierarchy of lookup
21.86 + * arguments, because
21.87 + * they are already resolved/loaded) I can tell that those returned in
21.88 + * previous query can't
21.89 + * implement the newly asked class (they are in different hierarchy branch)
21.90 + * and I need to
21.91 + * ask less Items.
21.92 + * <P>
21.93 + * So if we use mostly classes for asking for services (and it is a trend
21.94 + * to use
21.95 + * abstract classes for this purpose in IDE anyway), this could be usable.
21.96 + * <P>
21.97 + * The data structure for separating the Items based on previous queries is
21.98 + * simple
21.99 + * tree, with every node tagged with one class. The tree's root is,
21.100 + * naturally,
21.101 + * java.lang.Object, is marked invited and initially contains all the
21.102 + * Items.
21.103 + * For every class query, the missing part of class hierarchy tree is
21.104 + * created,
21.105 + * the node of the class looked up is marked as invited and all Items from
21.106 + * nearest
21.107 + * invited parent (sperclass) are dragged to this node. The result are then
21.108 + * all
21.109 + * Items from this node and all the nodes deeper in hierarchy. Because it
21.110 + * may
21.111 + * be too complicated to walk through the children nodes, the results could
21.112 + * be
21.113 + * cached in the map.
21.114 + * For interface lookup, there is a little hint in reality (interfaces
21.115 + * and superinterfaces), but it would be harder to exploit it, so we could
21.116 + * fall-back
21.117 + * to walking through all the Items and cache results.
21.118 + *
21.119 + *
21.120 + * @author Jaroslav Tulach
21.121 + */
21.122 +final class InheritanceTree extends Object
21.123 +implements Serializable, AbstractLookup.Storage<ArrayList<Class>> {
21.124 + private static final long serialVersionUID = 1L;
21.125 +
21.126 + /** the root item (represents Object) */
21.127 + private transient Node object;
21.128 +
21.129 + /** Map of queried interfaces.
21.130 + * <p>Type: <code>Map<Class, (Collection<AbstractLookup.Pair> | AbstractLookup.Pair)></code>
21.131 + */
21.132 + private transient Map<Class,Object> interfaces;
21.133 +
21.134 + /** Map (Class, ReferenceToResult) of all listeners that are waiting in
21.135 + * changes in class Class
21.136 + */
21.137 + private transient Map<Class,ReferenceToResult> reg;
21.138 +
21.139 + /** Constructor
21.140 + */
21.141 + public InheritanceTree() {
21.142 + object = new Node(java.lang.Object.class);
21.143 + }
21.144 +
21.145 + private void writeObject(ObjectOutputStream oos) throws IOException {
21.146 + oos.writeObject(object);
21.147 +
21.148 + if (interfaces != null) {
21.149 + Iterator it = interfaces.entrySet().iterator();
21.150 +
21.151 + while (it.hasNext()) {
21.152 + Map.Entry e = (Map.Entry) it.next();
21.153 + Class c = (Class) e.getKey();
21.154 + oos.writeObject(c.getName());
21.155 +
21.156 + Object o = e.getValue();
21.157 +
21.158 + if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
21.159 + throw new ClassCastException(String.valueOf(o));
21.160 + }
21.161 +
21.162 + oos.writeObject(o);
21.163 + }
21.164 + }
21.165 +
21.166 + oos.writeObject(null);
21.167 + }
21.168 +
21.169 + private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
21.170 + object = (Node) ois.readObject();
21.171 + interfaces = new WeakHashMap<Class,Object>();
21.172 +
21.173 + String clazz;
21.174 + ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
21.175 +
21.176 + while ((clazz = (String) ois.readObject()) != null) {
21.177 + Object o = ois.readObject();
21.178 +
21.179 + if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
21.180 + throw new ClassCastException(String.valueOf(o));
21.181 + }
21.182 +
21.183 + Class c = Class.forName(clazz, false, l);
21.184 + interfaces.put(c, o);
21.185 + }
21.186 + }
21.187 +
21.188 + /** Adds an item into the tree.
21.189 + * @param item to add
21.190 + * @return true if the Item has been added for the first time or false if some other
21.191 + * item equal to this one already existed in the lookup
21.192 + */
21.193 + public boolean add(AbstractLookup.Pair<?> item, ArrayList<Class> affected) {
21.194 + Node node = registerClass(object, item);
21.195 +
21.196 + affected.add(node.getType());
21.197 +
21.198 + if (node.assignItem(this, item)) {
21.199 + // this is the first item added to n.items
21.200 + // ok, we have to test interfaces too
21.201 + } else {
21.202 + // equal item is already there => stop processing
21.203 + return false;
21.204 + }
21.205 +
21.206 + boolean registeredAsInterface = registerInterface(item, affected);
21.207 +
21.208 + return registeredAsInterface;
21.209 + }
21.210 +
21.211 + /** Removes an item.
21.212 + */
21.213 + public void remove(AbstractLookup.Pair item, ArrayList<Class> affected) {
21.214 + Node n = removeClass(object, item);
21.215 +
21.216 + if (n != null) {
21.217 + affected.add(n.getType());
21.218 + }
21.219 +
21.220 + removeInterface(item, affected);
21.221 + }
21.222 +
21.223 + /** Removes all items that are not present in the provided collection.
21.224 + * @param retain collection of Pairs to keep them in
21.225 + * @param notify set of Classes that has possibly changed
21.226 + */
21.227 + public void retainAll(Map retain, ArrayList<Class> notify) {
21.228 + retainAllInterface(retain, notify);
21.229 + retainAllClasses(object, retain, notify);
21.230 + }
21.231 +
21.232 + /** Queries for instances of given class.
21.233 + * @param clazz the class to check
21.234 + * @return enumeration of Item
21.235 + * @see #unsorted
21.236 + */
21.237 + @SuppressWarnings("unchecked")
21.238 + public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
21.239 + if ((clazz != null) && clazz.isInterface()) {
21.240 + return (Enumeration)searchInterface(clazz);
21.241 + } else {
21.242 + return (Enumeration)searchClass(object, clazz);
21.243 + }
21.244 + }
21.245 +
21.246 + /** A method to check whether the enumeration returned from
21.247 + * lookup method is sorted or is not
21.248 + * @param en enumeration to check
21.249 + * @return true if it is unsorted and needs to be sorted to find
21.250 + * pair with smallest index
21.251 + */
21.252 + public static boolean unsorted(Enumeration en) {
21.253 + return en instanceof NeedsSortEnum;
21.254 + }
21.255 +
21.256 + /** Prints debug messages.
21.257 + * @param out stream to output to
21.258 + * @param instances print also instances of the
21.259 + */
21.260 + public void print(java.io.PrintStream out, boolean instances) {
21.261 + printNode(object, "", out, instances); // NOI18N
21.262 + }
21.263 +
21.264 + //
21.265 + // methods to work on classes which are not interfaces
21.266 + //
21.267 +
21.268 + /** Searches the subtree and register the item where necessary.
21.269 + * @return the node that should contain the item
21.270 + */
21.271 + private static Node registerClass(Node n, AbstractLookup.Pair item) {
21.272 + if (!n.accepts(item)) {
21.273 + return null;
21.274 + }
21.275 +
21.276 + if (n.children != null) {
21.277 + Iterator it = n.children.iterator();
21.278 +
21.279 + for (;;) {
21.280 + Node ch = extractNode(it);
21.281 +
21.282 + if (ch == null) {
21.283 + break;
21.284 + }
21.285 +
21.286 + Node result = registerClass(ch, item);
21.287 +
21.288 + if (result != null) {
21.289 + // it is in subclass, in case of classes, it cannot
21.290 + // be any other class
21.291 + return result;
21.292 + }
21.293 + }
21.294 + }
21.295 +
21.296 + // ok, nobody of our subclasses wants the class, I'll take it
21.297 + return n;
21.298 + }
21.299 +
21.300 + /** Removes the item from the tree of objects.
21.301 + * @return most narrow class that this item was removed from
21.302 + */
21.303 + private static Node removeClass(Node n, AbstractLookup.Pair item) {
21.304 + if (!n.accepts(item)) {
21.305 + return null;
21.306 + }
21.307 +
21.308 + if ((n.items != null) && n.items.remove(item)) {
21.309 + // this node really contains the item
21.310 + return n;
21.311 + }
21.312 +
21.313 + if (n.children != null) {
21.314 + Iterator it = n.children.iterator();
21.315 +
21.316 + for (;;) {
21.317 + Node ch = extractNode(it);
21.318 +
21.319 + if (ch == null) {
21.320 + break;
21.321 + }
21.322 +
21.323 + Node result = removeClass(ch, item);
21.324 +
21.325 + // If the children node was emptied, remove it if possible.
21.326 + if (((ch.items == null) || ch.items.isEmpty()) && ((ch.children == null) || ch.children.isEmpty())) {
21.327 + it.remove();
21.328 + }
21.329 +
21.330 + if (result != null) {
21.331 + // it is in subclass, in case of classes, it cannot
21.332 + // be any other class
21.333 + return result;
21.334 + }
21.335 + }
21.336 + }
21.337 +
21.338 + // nobody found
21.339 + return null;
21.340 + }
21.341 +
21.342 + /** Finds a node that represents a class.
21.343 + * @param n node to search from
21.344 + * @param clazz the clazz to find
21.345 + * @return node that represents clazz in the tree or null if the clazz is not
21.346 + * represented under the node n
21.347 + */
21.348 + private Node classToNode(final Node n, final Class<?> clazz) {
21.349 + if (!n.accepts(clazz)) {
21.350 + // nothing from us
21.351 + return null;
21.352 + }
21.353 +
21.354 + if (n.getType() == clazz) {
21.355 + // we have found what we need
21.356 + return n;
21.357 + }
21.358 +
21.359 + if (n.children != null) {
21.360 + // have to proceed to children
21.361 + Iterator it = n.children.iterator();
21.362 +
21.363 + for (;;) {
21.364 + final Node ch = extractNode(it);
21.365 +
21.366 + if (ch == null) {
21.367 + break;
21.368 + }
21.369 +
21.370 + Node found = classToNode(ch, clazz);
21.371 +
21.372 + if ((found != null) && ch.deserialized()) {
21.373 + class VerifyJob implements AbstractLookup.ISE.Job {
21.374 + private AbstractLookup.Pair<?>[] pairs;
21.375 + private boolean[] answers;
21.376 +
21.377 + public VerifyJob(Collection<Pair> items) {
21.378 + if (items != null) {
21.379 + pairs = items.toArray(new AbstractLookup.Pair[0]);
21.380 + }
21.381 + }
21.382 +
21.383 + public void before() {
21.384 + // make sure the node is converted into deserialized state
21.385 + ch.deserialized();
21.386 +
21.387 + if (pairs != null) {
21.388 + answers = new boolean[pairs.length];
21.389 +
21.390 + for (int i = 0; i < pairs.length; i++) {
21.391 + answers[i] = pairs[i].instanceOf(clazz);
21.392 + }
21.393 + }
21.394 + }
21.395 +
21.396 + public void inside() {
21.397 + if (pairs != null) {
21.398 + for (int i = 0; i < pairs.length; i++) {
21.399 + if (answers[i]) {
21.400 + ch.assignItem(InheritanceTree.this, pairs[i]);
21.401 + n.items.remove(pairs[i]);
21.402 + }
21.403 + }
21.404 + }
21.405 +
21.406 + if (n.children != null) {
21.407 + // consolidate all nodes that represent the same class
21.408 + HashMap<Class,Node> nodes = new HashMap<Class,Node>(n.children.size() * 3);
21.409 +
21.410 + Iterator child = n.children.iterator();
21.411 +
21.412 + while (child.hasNext()) {
21.413 + Node node = extractNode(child);
21.414 + if (node == null) {
21.415 + continue;
21.416 + }
21.417 + Node prev = nodes.put(node.getType(), node);
21.418 +
21.419 + if (prev != null) {
21.420 + child.remove();
21.421 + nodes.put(node.getType(), prev);
21.422 +
21.423 + // mark as being deserialized
21.424 + prev.markDeserialized();
21.425 +
21.426 + if (prev.children == null) {
21.427 + prev.children = node.children;
21.428 + } else {
21.429 + if (node.children != null) {
21.430 + prev.children.addAll(node.children);
21.431 + }
21.432 + }
21.433 +
21.434 + if (node.items != null) {
21.435 + Iterator items = node.items.iterator();
21.436 +
21.437 + while (items.hasNext()) {
21.438 + AbstractLookup.Pair item = (AbstractLookup.Pair) items.next();
21.439 + prev.assignItem(InheritanceTree.this, item);
21.440 + }
21.441 + }
21.442 + }
21.443 + }
21.444 + }
21.445 + }
21.446 + }
21.447 +
21.448 + VerifyJob verify = new VerifyJob(n.items);
21.449 +
21.450 + try {
21.451 + verify.before();
21.452 + } catch (AbstractLookup.ISE ex) {
21.453 + // mark deserialized again
21.454 + ch.markDeserialized();
21.455 + ex.registerJob(verify);
21.456 + throw ex;
21.457 + }
21.458 +
21.459 + verify.inside();
21.460 +
21.461 + found = classToNode(ch, clazz);
21.462 + }
21.463 +
21.464 + if (found != null) {
21.465 + // class found in one of subnodes
21.466 + return found;
21.467 + }
21.468 + }
21.469 + }
21.470 +
21.471 + class TwoJobs implements AbstractLookup.ISE.Job {
21.472 + private AbstractLookup.Pair[] pairs;
21.473 + private boolean[] answers;
21.474 + private Node newNode;
21.475 +
21.476 + public void before() {
21.477 + // have to create new subnode and possibly reparent one of my own
21.478 + // but all changes can be done only if we will not be interrupted from
21.479 + // outside - e.g. instanceOf methods will not throw exception
21.480 + // first of all let's compute the answers to method instanceOf
21.481 + AbstractLookup.Pair[] arr = null;
21.482 + boolean[] boolArr = null;
21.483 +
21.484 + if (n.items != null) {
21.485 + arr = new AbstractLookup.Pair[n.items.size()];
21.486 + boolArr = new boolean[n.items.size()];
21.487 +
21.488 + int i = 0;
21.489 + Iterator<Pair> it = n.items.iterator();
21.490 +
21.491 + while (it.hasNext()) {
21.492 + AbstractLookup.Pair<?> item = it.next();
21.493 + arr[i] = item;
21.494 + boolArr[i] = item.instanceOf(clazz);
21.495 + i++;
21.496 + }
21.497 + }
21.498 +
21.499 + pairs = arr;
21.500 + answers = boolArr;
21.501 + }
21.502 +
21.503 + public void inside() {
21.504 + // test if the query has not chagned since
21.505 + if (pairs != null) {
21.506 + if (!Arrays.equals(n.items.toArray(), pairs)) {
21.507 + // ok, let try once more
21.508 + return;
21.509 + }
21.510 + }
21.511 +
21.512 + internal();
21.513 + }
21.514 +
21.515 + public void internal() {
21.516 + ArrayList<Node> reparent = null;
21.517 +
21.518 + if (n.children == null) {
21.519 + n.children = new ArrayList<Node>();
21.520 + } else {
21.521 + // scan thru all my nodes if some of them are not a subclass
21.522 + // of clazz => then they would need to become child of newNode
21.523 + Iterator it = n.children.iterator();
21.524 +
21.525 + for (;;) {
21.526 + Node r = extractNode(it);
21.527 +
21.528 + if (r == null) {
21.529 + break;
21.530 + }
21.531 +
21.532 + if (clazz.isAssignableFrom(r.getType())) {
21.533 + if (reparent == null) {
21.534 + reparent = new ArrayList<Node>();
21.535 + }
21.536 +
21.537 + reparent.add(r);
21.538 + it.remove();
21.539 + }
21.540 + }
21.541 + }
21.542 +
21.543 + newNode = new Node(clazz);
21.544 + n.children.add(newNode);
21.545 +
21.546 + if (reparent != null) {
21.547 + // reassing reparent node as a child of newNode
21.548 + newNode.children = reparent;
21.549 + }
21.550 +
21.551 + // now take all my items that are instances of that class and
21.552 + // reasign them
21.553 + if (n.items != null) {
21.554 + Iterator it = n.items.iterator();
21.555 + int i = 0;
21.556 +
21.557 + while (it.hasNext()) {
21.558 + AbstractLookup.Pair item = (AbstractLookup.Pair) it.next();
21.559 +
21.560 + if (answers[i]) { // answers[i] is precomputed value of item.instanceOf (clazz))
21.561 + it.remove();
21.562 + newNode.assignItem(InheritanceTree.this, pairs[i]);
21.563 + }
21.564 +
21.565 + i++;
21.566 + }
21.567 + }
21.568 + }
21.569 + }
21.570 +
21.571 + TwoJobs j = new TwoJobs();
21.572 +
21.573 + try {
21.574 + j.before();
21.575 + } catch (AbstractLookup.ISE ex) {
21.576 + // ok, it is not possible to call instanceOf now, let's
21.577 + // schedule it for later
21.578 + // so register recovery job
21.579 + ex.registerJob(j);
21.580 + throw ex;
21.581 + }
21.582 +
21.583 + j.internal();
21.584 +
21.585 + // newNode represents my clazz
21.586 + return j.newNode;
21.587 + }
21.588 +
21.589 + /** Search for a requested class.
21.590 + * @return enumeration of Pair
21.591 + */
21.592 + private Enumeration<Pair> searchClass(Node n, Class<?> clazz) {
21.593 + if (clazz != null) {
21.594 + n = classToNode(n, clazz);
21.595 + }
21.596 +
21.597 + if (n == null) {
21.598 + // not for us
21.599 + return emptyEn();
21.600 + } else {
21.601 + return nodeToEnum(n);
21.602 + }
21.603 + }
21.604 +
21.605 + /** Retains all classes. Removes nodes which items and children are emptied, works
21.606 + * recursivelly from specified root node.
21.607 + * @param node root node from which to start to process the tree
21.608 + * @param retain a map from (Item, AbstractLookup.Info) that describes which items to retain
21.609 + * and witch integer to assign them
21.610 + * @param notify collection of classes will be changed
21.611 + * @return <code>true<code> if some items were changed and node items and children are emptied,
21.612 + * those nodes, excluding root, will be removed from tree */
21.613 + private boolean retainAllClasses(Node node, Map retain, Collection<Class> notify) {
21.614 + boolean retained = false;
21.615 +
21.616 + if ((node.items != null) && (retain != null)) {
21.617 + Iterator<Pair> it = node.items.iterator();
21.618 +
21.619 + while (it.hasNext()) {
21.620 + AbstractLookup.Pair<?> item = it.next();
21.621 + AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(item);
21.622 +
21.623 + if (n == null) {
21.624 + // remove this item, it should not be there
21.625 + it.remove();
21.626 + retained = true;
21.627 + } else {
21.628 + // change the index
21.629 + if (item.getIndex() != n.index) {
21.630 + item.setIndex(null, n.index);
21.631 +
21.632 + // notify.addAll ((ArrayList)n.transaction);
21.633 + }
21.634 + }
21.635 + }
21.636 +
21.637 + if (retained && (notify != null)) {
21.638 + // type of this node has been changed
21.639 + notify.add(node.getType());
21.640 + }
21.641 + }
21.642 +
21.643 + if (node.children != null) {
21.644 + for (Iterator it = node.children.iterator();;) {
21.645 + Node ch = extractNode(it);
21.646 +
21.647 + if (ch == null) {
21.648 + break;
21.649 + }
21.650 +
21.651 + boolean result = retainAllClasses(ch, retain, notify);
21.652 +
21.653 + if (result) {
21.654 + // The children node was emptied and has no children -> remove it.
21.655 + it.remove();
21.656 + }
21.657 + }
21.658 + }
21.659 +
21.660 + return retained && node.items.isEmpty() && ((node.children == null) || node.children.isEmpty());
21.661 + }
21.662 +
21.663 + /** A method that creates enumeration of all items under given node.
21.664 + *
21.665 + * @param n node to create enumeration for
21.666 + * @return enumeration of Pairs
21.667 + */
21.668 + private static Enumeration<Pair> nodeToEnum(Node n) {
21.669 + if (n.children == null) {
21.670 + // create a simple enumeration because we do not have children
21.671 + Enumeration<Pair> e;
21.672 + if (n.items == null) {
21.673 + e = emptyEn();
21.674 + } else {
21.675 + e = Collections.enumeration(n.items);
21.676 + }
21.677 + return e;
21.678 + }
21.679 +
21.680 + // create enumeration of Items
21.681 + return new NeedsSortEnum(n);
21.682 + }
21.683 +
21.684 + //
21.685 + // Methods to work on interfaces
21.686 + //
21.687 +
21.688 + /** Registers an item with interfaces.
21.689 + * @param item item to register
21.690 + * @param affected list of classes that were affected
21.691 + * @return false if similar item has already been registered
21.692 + */
21.693 + @SuppressWarnings("unchecked")
21.694 + private boolean registerInterface(AbstractLookup.Pair<?> item, Collection<Class> affected) {
21.695 + if (interfaces == null) {
21.696 + return true;
21.697 + }
21.698 +
21.699 + Iterator<Map.Entry<Class,Object>> it = interfaces.entrySet().iterator();
21.700 +
21.701 + while (it.hasNext()) {
21.702 + Map.Entry<Class,Object> entry = it.next();
21.703 + Class<?> iface = entry.getKey();
21.704 +
21.705 + if (item.instanceOf(iface)) {
21.706 + Object value = entry.getValue();
21.707 +
21.708 + if (value instanceof Collection) {
21.709 + Collection<Object> set = (Collection<Object>) value;
21.710 +
21.711 + if (!set.add(item)) {
21.712 + // item is already there, probably (if everything is correct) is registered in
21.713 + // all other ifaces too, so stop additional testing
21.714 + return false;
21.715 + }
21.716 + } else {
21.717 + // there is just one pair right now
21.718 + if (value.equals(item)) {
21.719 + // item is there => stop processing (same as above)
21.720 + return false;
21.721 + }
21.722 +
21.723 + // otherwise replace the single item with ArrayList
21.724 + ArrayList<Object> ll = new ArrayList<Object>(3);
21.725 + ll.add(value);
21.726 + ll.add(item);
21.727 + entry.setValue(ll);
21.728 + }
21.729 +
21.730 + affected.add(iface);
21.731 + }
21.732 + }
21.733 +
21.734 + return true;
21.735 + }
21.736 +
21.737 + /** Removes interface.
21.738 + * @param item item to register
21.739 + * @param affected list of classes that were affected
21.740 + */
21.741 + @SuppressWarnings("unchecked")
21.742 + private void removeInterface(AbstractLookup.Pair item, Collection affected) {
21.743 + if (interfaces == null) {
21.744 + return;
21.745 + }
21.746 +
21.747 + Iterator it = interfaces.entrySet().iterator();
21.748 +
21.749 + while (it.hasNext()) {
21.750 + Map.Entry entry = (Map.Entry) it.next();
21.751 + Object value = entry.getValue();
21.752 +
21.753 + if (value instanceof Collection) {
21.754 + Collection set = (Collection) value;
21.755 +
21.756 + if (set.remove(item)) {
21.757 + if (set.size() == 1) {
21.758 + // if there is just one item remaining change to single item mode
21.759 + entry.setValue(set.iterator().next());
21.760 + }
21.761 +
21.762 + // adds the Class the item was register to into affected
21.763 + affected.add(entry.getKey());
21.764 + }
21.765 + } else {
21.766 + // single item value
21.767 + if (value.equals(item)) {
21.768 + // Emptied -> remove.
21.769 + it.remove();
21.770 +
21.771 + affected.add(entry.getKey());
21.772 + }
21.773 + }
21.774 + }
21.775 + }
21.776 +
21.777 + /** Retains some items.
21.778 + * @param retainItems items to retain and their mapping to index numbers
21.779 + * (AbstractLookup.Pair -> AbstractLookup.Info)
21.780 + * @param affected list of classes that were affected
21.781 + */
21.782 + @SuppressWarnings("unchecked")
21.783 + private void retainAllInterface(Map retainItems, Collection affected) {
21.784 + if (interfaces == null) {
21.785 + return;
21.786 + }
21.787 +
21.788 + Iterator it = interfaces.entrySet().iterator();
21.789 +
21.790 + while (it.hasNext()) {
21.791 + Map.Entry entry = (Map.Entry) it.next();
21.792 + Object value = entry.getValue();
21.793 +
21.794 + HashMap<?,?> retain = new HashMap(retainItems);
21.795 +
21.796 + Iterator elems;
21.797 + boolean multi = value instanceof Collection;
21.798 +
21.799 + if (multi) {
21.800 + // collection mode
21.801 + elems = ((Collection) value).iterator();
21.802 + } else {
21.803 + // single item mode
21.804 + elems = Collections.singleton(value).iterator();
21.805 + }
21.806 +
21.807 + boolean changed = false;
21.808 + boolean reordered = false;
21.809 +
21.810 + while (elems.hasNext()) {
21.811 + AbstractLookup.Pair p = (AbstractLookup.Pair) elems.next();
21.812 +
21.813 + AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(p);
21.814 +
21.815 + if (n == null) {
21.816 + if (multi) {
21.817 + // remove it
21.818 + elems.remove();
21.819 + }
21.820 +
21.821 + changed = true;
21.822 + } else {
21.823 + if (p.getIndex() != n.index) {
21.824 + // improve the index
21.825 + p.setIndex(null, n.index);
21.826 +
21.827 + // affected.addAll ((ArrayList)n.transaction);
21.828 + reordered = true;
21.829 + }
21.830 + }
21.831 + }
21.832 +
21.833 + if (reordered && value instanceof List) {
21.834 + // if reordered, than update the order in the collection
21.835 + List l = (List) value;
21.836 + Collections.sort(l, ALPairComparator.DEFAULT);
21.837 + }
21.838 +
21.839 + if (changed) {
21.840 + if (multi) {
21.841 + Collection c = (Collection) value;
21.842 +
21.843 + if (c.size() == 1) {
21.844 + // back to single item mode
21.845 + entry.setValue(c.iterator().next());
21.846 + }
21.847 + } else {
21.848 + // remove in single mode => remove completely
21.849 + it.remove();
21.850 + }
21.851 +
21.852 + // adds the Class the item was register to into affected
21.853 + affected.add(entry.getKey());
21.854 + }
21.855 + }
21.856 + }
21.857 +
21.858 + /** Searches for a clazz between interfaces.
21.859 + * @param clazz class to search for
21.860 + * @return enumeration of Items
21.861 + */
21.862 + @SuppressWarnings("unchecked")
21.863 + private Enumeration<Pair> searchInterface(final Class<?> clazz) {
21.864 + if (interfaces == null) {
21.865 + // first call for interface, only initialize
21.866 + interfaces = new WeakHashMap();
21.867 + }
21.868 +
21.869 + Object obj = interfaces.get(clazz);
21.870 +
21.871 + if (obj == null) {
21.872 + // set of items
21.873 + AbstractLookup.Pair one = null;
21.874 + ArrayList items = null;
21.875 +
21.876 + Enumeration en = lookup(Object.class);
21.877 +
21.878 + while (en.hasMoreElements()) {
21.879 + AbstractLookup.Pair it = (AbstractLookup.Pair) en.nextElement();
21.880 +
21.881 + if (it.instanceOf(clazz)) {
21.882 + // ok, this item implements given clazz
21.883 + if (one == null) {
21.884 + one = it;
21.885 + } else {
21.886 + if (items == null) {
21.887 + items = new ArrayList(3);
21.888 + items.add(one);
21.889 + }
21.890 +
21.891 + items.add(it);
21.892 + }
21.893 + }
21.894 + }
21.895 +
21.896 + if ((items == null) && (one != null)) {
21.897 + // single item mode
21.898 + interfaces.put(clazz, one);
21.899 +
21.900 + return singletonEn(one);
21.901 + } else {
21.902 + if (items == null) {
21.903 + items = new ArrayList(2);
21.904 + }
21.905 +
21.906 + interfaces.put(clazz, items);
21.907 +
21.908 + return Collections.enumeration(items);
21.909 + }
21.910 + } else {
21.911 + if (obj instanceof Collection) {
21.912 + return Collections.enumeration((Collection) obj);
21.913 + } else {
21.914 + // single item mode
21.915 + return singletonEn((Pair)obj);
21.916 + }
21.917 + }
21.918 + }
21.919 +
21.920 + /** Extracts a node from an iterator, returning null if no next element found
21.921 + */
21.922 + private static Node extractNode(Iterator it) {
21.923 + while (it.hasNext()) {
21.924 + Node n = (Node) it.next();
21.925 +
21.926 + if (n.get() == null) {
21.927 + it.remove();
21.928 + } else {
21.929 + return n;
21.930 + }
21.931 + }
21.932 +
21.933 + return null;
21.934 + }
21.935 +
21.936 + /** Prints debug info about the node.
21.937 + * @param n node to print
21.938 + * @param sp spaces to add
21.939 + * @param out where
21.940 + * @param instances print also instances
21.941 + */
21.942 + private static void printNode(Node n, String sp, java.io.PrintStream out, boolean instances) {
21.943 + int i;
21.944 + Iterator it;
21.945 +
21.946 + Class type = n.getType();
21.947 +
21.948 + out.print(sp);
21.949 + out.println("Node for: " + type + "\t" + ((type == null) ? null : type.getClassLoader())); // NOI18N
21.950 +
21.951 + if (n.items != null) {
21.952 + i = 0;
21.953 + it = new ArrayList<Pair>(n.items).iterator();
21.954 +
21.955 + while (it.hasNext()) {
21.956 + AbstractLookup.Pair p = (AbstractLookup.Pair) it.next();
21.957 + out.print(sp);
21.958 + out.print(" item (" + i++ + "): ");
21.959 + out.print(p); // NOI18N
21.960 + out.print(" id: " + Integer.toHexString(System.identityHashCode(p))); // NOI18N
21.961 + out.print(" index: "); // NOI18N
21.962 + out.print(p.getIndex());
21.963 +
21.964 + if (instances) {
21.965 + out.print(" I: " + p.getInstance());
21.966 + }
21.967 +
21.968 + out.println();
21.969 + }
21.970 + }
21.971 +
21.972 + if (n.children != null) {
21.973 + i = 0;
21.974 + it = n.children.iterator();
21.975 +
21.976 + while (it.hasNext()) {
21.977 + Node ch = (Node) it.next();
21.978 + printNode(ch, sp + " ", out, instances); // NOI18N
21.979 + }
21.980 + }
21.981 + }
21.982 +
21.983 + public ReferenceToResult registerReferenceToResult(ReferenceToResult<?> newRef) {
21.984 + if (reg == null) {
21.985 + reg = new HashMap<Class,ReferenceToResult>();
21.986 + }
21.987 +
21.988 + Class<? extends Object> clazz = newRef.template.getType();
21.989 +
21.990 + // initialize the data structures if not yet
21.991 + lookup(clazz);
21.992 +
21.993 + // newRef will be the new head of the list
21.994 + return reg.put(clazz, newRef);
21.995 + }
21.996 +
21.997 + public ReferenceToResult cleanUpResult(Lookup.Template templ) {
21.998 + collectListeners(null, templ.getType());
21.999 +
21.1000 + return (reg == null) ? null : reg.get(templ.getType());
21.1001 + }
21.1002 +
21.1003 + public ArrayList<Class> beginTransaction(int ensure) {
21.1004 + return new ArrayList<Class>();
21.1005 + }
21.1006 +
21.1007 + public void endTransaction(ArrayList<Class> list, Set<AbstractLookup.R> allAffectedResults) {
21.1008 + if (list.size() == 1) {
21.1009 + // probably the most common case
21.1010 + collectListeners(allAffectedResults, list.get(0));
21.1011 + } else {
21.1012 + Iterator it = list.iterator();
21.1013 +
21.1014 + while (it.hasNext()) {
21.1015 + collectListeners(allAffectedResults, (Class) it.next());
21.1016 + }
21.1017 + }
21.1018 + }
21.1019 +
21.1020 + /** Notifies all listeners that are interested in changes in this class.
21.1021 + * Should be called from synchronized places.
21.1022 + * @param allAffectedResults adds Results into this set
21.1023 + * @param c the class that has changed
21.1024 + */
21.1025 + private void collectListeners(Set<AbstractLookup.R> allAffectedResults, Class c) {
21.1026 + if (reg == null) {
21.1027 + return;
21.1028 + }
21.1029 +
21.1030 + while (c != null) {
21.1031 + ReferenceToResult first = reg.get(c);
21.1032 + ReferenceIterator it = new ReferenceIterator(first);
21.1033 +
21.1034 + while (it.next()) {
21.1035 + AbstractLookup.R result = it.current().getResult();
21.1036 +
21.1037 + if (allAffectedResults != null) {
21.1038 + // add result
21.1039 + allAffectedResults.add(result);
21.1040 + }
21.1041 + }
21.1042 +
21.1043 + if (first != it.first()) {
21.1044 + if (it.first() == null) {
21.1045 + // we do not need have more results on this object
21.1046 + reg.remove(c);
21.1047 + } else {
21.1048 + // move the head of the list
21.1049 + reg.put(c, it.first());
21.1050 + }
21.1051 + }
21.1052 +
21.1053 + c = c.getSuperclass();
21.1054 + }
21.1055 +
21.1056 + if (reg.isEmpty()) {
21.1057 + // clean up the list of all results if we do not need them anymore
21.1058 + reg = null;
21.1059 + }
21.1060 + }
21.1061 +
21.1062 + /** Node in the tree.
21.1063 + */
21.1064 + static final class Node extends WeakReference<Class> implements Serializable {
21.1065 + static final long serialVersionUID = 3L;
21.1066 +
21.1067 + /** children nodes */
21.1068 + public ArrayList<Node> children;
21.1069 +
21.1070 + /** list of items assigned to this node (suspect to be subclasses) */
21.1071 + public Collection<Pair> items;
21.1072 +
21.1073 + /** Constructor.
21.1074 + */
21.1075 + public Node(Class clazz) {
21.1076 + super(clazz);
21.1077 + }
21.1078 +
21.1079 + /** Returns true if the object was deserialized also clears the serialized flag.
21.1080 + * @return true if so.
21.1081 + */
21.1082 + public boolean deserialized() {
21.1083 + if ((items == null) || items instanceof LinkedHashSet) {
21.1084 + return false;
21.1085 + }
21.1086 +
21.1087 + if (items.isEmpty()) {
21.1088 + items = null;
21.1089 + } else {
21.1090 + items = new LinkedHashSet<Pair>(items);
21.1091 + }
21.1092 +
21.1093 + return true;
21.1094 + }
21.1095 +
21.1096 + /** Marks this item as being deserialized.
21.1097 + */
21.1098 + public void markDeserialized() {
21.1099 + if (items == null || items == Collections.EMPTY_LIST) {
21.1100 + items = Collections.emptyList();
21.1101 + } else {
21.1102 + items = Collections.synchronizedCollection(items);
21.1103 + }
21.1104 + }
21.1105 +
21.1106 + /** Getter for the type associated with this node.
21.1107 + */
21.1108 + public Class<?> getType() {
21.1109 + Class<?> c = get();
21.1110 +
21.1111 + // if garbage collected, then return a garbage
21.1112 + return (c == null) ? Void.TYPE : c;
21.1113 + }
21.1114 +
21.1115 + /** Checks whether a node can represent an class.
21.1116 + */
21.1117 + public boolean accepts(Class<?> clazz) {
21.1118 + if (getType() == Object.class) {
21.1119 + return true;
21.1120 + }
21.1121 +
21.1122 + return getType().isAssignableFrom(clazz);
21.1123 + }
21.1124 +
21.1125 + /** Checks whether item is instance of this node.
21.1126 + */
21.1127 + public boolean accepts(AbstractLookup.Pair<?> item) {
21.1128 + if (getType() == Object.class) {
21.1129 + // Object.class
21.1130 + return true;
21.1131 + }
21.1132 +
21.1133 + return item.instanceOf(getType());
21.1134 + }
21.1135 +
21.1136 + /** Assings an item to this node.
21.1137 + * @param item the item
21.1138 + * @return true if item has been added as new
21.1139 + */
21.1140 + public boolean assignItem(InheritanceTree tree, AbstractLookup.Pair<?> item) {
21.1141 + if ((items == null) || (items == Collections.EMPTY_LIST)) {
21.1142 + items = new LinkedHashSet<Pair>();
21.1143 + items.add(item);
21.1144 +
21.1145 + return true;
21.1146 + }
21.1147 +
21.1148 + if (items.contains(item)) {
21.1149 + Iterator<Pair> it = items.iterator();
21.1150 + Pair old;
21.1151 + for (;;) {
21.1152 + old = it.next();
21.1153 + if (item.equals(old)) {
21.1154 + break;
21.1155 + }
21.1156 + }
21.1157 +
21.1158 + if (old != item) {
21.1159 + // replace the items there
21.1160 + item.setIndex(tree, old.getIndex());
21.1161 + }
21.1162 +
21.1163 + it.remove();
21.1164 + items.add(item);
21.1165 +
21.1166 + return false;
21.1167 + }
21.1168 +
21.1169 + items.add(item);
21.1170 +
21.1171 + return true;
21.1172 + }
21.1173 +
21.1174 + private Object writeReplace() {
21.1175 + return new R(this);
21.1176 + }
21.1177 +
21.1178 + @Override
21.1179 + public String toString() {
21.1180 + return "Node for " + get();
21.1181 + }
21.1182 + }
21.1183 + // End of class Node.
21.1184 +
21.1185 + private static final class R implements Serializable {
21.1186 + static final long serialVersionUID = 1L;
21.1187 + private static ClassLoader l;
21.1188 + private String clazzName;
21.1189 + private transient Class<?> clazz;
21.1190 + private ArrayList<Node> children;
21.1191 + private Collection<Pair> items;
21.1192 +
21.1193 + public R(Node n) {
21.1194 + this.clazzName = n.getType().getName();
21.1195 + this.children = n.children;
21.1196 +
21.1197 + if (n.items instanceof LinkedHashSet || (n.items == null)) {
21.1198 + this.items = n.items;
21.1199 + } else {
21.1200 + this.items = new LinkedHashSet<Pair>(n.items);
21.1201 + }
21.1202 + }
21.1203 +
21.1204 + private void readObject(ObjectInputStream ois)
21.1205 + throws IOException, ClassNotFoundException {
21.1206 + ois.defaultReadObject();
21.1207 +
21.1208 + if (l == null) {
21.1209 + l = Lookup.getDefault().lookup(ClassLoader.class);
21.1210 + }
21.1211 +
21.1212 + clazz = Class.forName(clazzName, false, l);
21.1213 + }
21.1214 +
21.1215 + private Object readResolve() throws ObjectStreamException {
21.1216 + Node n = new Node(clazz);
21.1217 + n.children = children;
21.1218 + n.items = items;
21.1219 + n.markDeserialized();
21.1220 +
21.1221 + return n;
21.1222 + }
21.1223 + }
21.1224 + // end of R
21.1225 +
21.1226 + static Enumeration<Object> arrayEn(Object[] object) {
21.1227 + return Collections.enumeration(Arrays.asList(object));
21.1228 + }
21.1229 + static <T> Enumeration<T> singletonEn(T object) {
21.1230 + return Collections.enumeration(Collections.singleton(object));
21.1231 + }
21.1232 + static <T> Enumeration<T> emptyEn() {
21.1233 + return Collections.enumeration(Collections.<T>emptyList());
21.1234 + }
21.1235 +
21.1236 + /** Just a marker class to be able to do instanceof and find out
21.1237 + * that this enumeration is not sorted
21.1238 + */
21.1239 + private static final class NeedsSortEnum extends LinkedList<Node>
21.1240 + implements Enumeration<Pair> {
21.1241 + private Enumeration<Pair> en;
21.1242 +
21.1243 + public NeedsSortEnum(Node n) {
21.1244 + add(n);
21.1245 + }
21.1246 +
21.1247 + private boolean ensureNext() {
21.1248 + for (;;) {
21.1249 + if (en != null && en.hasMoreElements()) {
21.1250 + return true;
21.1251 + }
21.1252 + if (isEmpty()) {
21.1253 + return false;
21.1254 + }
21.1255 +
21.1256 + Node n2 = poll();
21.1257 + if (n2.children != null) {
21.1258 + addAll(n2.children);
21.1259 + }
21.1260 +
21.1261 + if (n2.items != null && !n2.items.isEmpty()) {
21.1262 + en = Collections.enumeration(n2.items);
21.1263 + }
21.1264 + }
21.1265 + }
21.1266 +
21.1267 + public boolean hasMoreElements() {
21.1268 + return ensureNext();
21.1269 + }
21.1270 +
21.1271 + public Pair nextElement() {
21.1272 + if (!ensureNext()) {
21.1273 + throw new NoSuchElementException();
21.1274 + }
21.1275 + return en.nextElement();
21.1276 + }
21.1277 + }
21.1278 + // end of NeedsSortEnum
21.1279 +}
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/InstanceContent.java Mon Dec 14 20:58:39 2009 +0100
22.3 @@ -0,0 +1,378 @@
22.4 +/*
22.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
22.6 + *
22.7 + * Copyright 1997-2009 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 + * Contributor(s):
22.28 + *
22.29 + * The Original Software is NetBeans. The Initial Developer of the Original
22.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
22.31 + * Microsystems, Inc. All Rights Reserved.
22.32 + *
22.33 + * If you wish your version of this file to be governed by only the CDDL
22.34 + * or only the GPL Version 2, indicate your decision by adding
22.35 + * "[Contributor] elects to include this software in this distribution
22.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
22.37 + * single choice of license, a recipient has the option to distribute
22.38 + * your version of this file under either the CDDL, the GPL Version 2 or
22.39 + * to extend the choice of license to its licensees as provided above.
22.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
22.41 + * Version 2 license, then the option applies only if the new code is
22.42 + * made subject to such option by the copyright holder.
22.43 + */
22.44 +package org.openide.util.lookup;
22.45 +
22.46 +import org.openide.util.lookup.AbstractLookup.Pair;
22.47 +
22.48 +import java.lang.ref.WeakReference;
22.49 +
22.50 +import java.util.*;
22.51 +import java.util.concurrent.Executor;
22.52 +import org.openide.util.Lookup.Item;
22.53 +
22.54 +
22.55 +/** A special content implementation that can be passed to AbstractLookup
22.56 + * and provides methods for registration of instances and lazy instances.
22.57 + * <PRE>
22.58 + * InstanceContent ic = new InstanceContent ();
22.59 + * AbstractLookup al = new AbstractLookup (ic);
22.60 + *
22.61 + * ic.add (new Object ());
22.62 + * ic.add (new Dimension (...));
22.63 + *
22.64 + * Dimension theDim = (Dimension)al.lookup (Dimension.class);
22.65 + * </PRE>
22.66 + *
22.67 + * @author Jaroslav Tulach
22.68 + *
22.69 + * @since 1.25
22.70 + */
22.71 +public final class InstanceContent extends AbstractLookup.Content {
22.72 + /**
22.73 + * Create a new, empty content.
22.74 + */
22.75 + public InstanceContent() {
22.76 + }
22.77 +
22.78 + /** Creates a content associated with an executor to handle dispatch
22.79 + * of changes.
22.80 + * @param notifyIn the executor to notify changes in
22.81 + * @since 7.16
22.82 + */
22.83 + public InstanceContent(Executor notifyIn) {
22.84 + super(notifyIn);
22.85 + }
22.86 + /** The method to add instance to the lookup with.
22.87 + * @param inst instance
22.88 + */
22.89 + public final void add(Object inst) {
22.90 + addPair(new SimpleItem<Object>(inst));
22.91 + }
22.92 +
22.93 + /** Adds a convertible instance into the lookup. The <code>inst</code>
22.94 + * argument is just a key, not the actual value to appear in the lookup.
22.95 + * The value will be created on demand, later when it is really needed
22.96 + * by calling <code>convertor</code> methods.
22.97 + * <p>
22.98 + * This method is useful to delay creation of heavy weight objects.
22.99 + * Instead just register lightweight key and a convertor.
22.100 + * <p>
22.101 + * To remove registered object from lookup use {@link #remove(java.lang.Object, org.openide.util.lookup.InstanceContent.Convertor)}
22.102 + * with the same arguments.
22.103 + *
22.104 + * @param inst instance
22.105 + * @param conv convertor which postponing an instantiation,
22.106 + * if <code>conv==null</code> then the instance is registered directly.
22.107 + */
22.108 + public final <T,R> void add(T inst, Convertor<T,R> conv) {
22.109 + addPair(new ConvertingItem<T,R>(inst, conv));
22.110 + }
22.111 +
22.112 + /** Remove instance.
22.113 + * @param inst instance
22.114 + */
22.115 + public final void remove(Object inst) {
22.116 + removePair(new SimpleItem<Object>(inst));
22.117 + }
22.118 +
22.119 + /** Remove instance added with a convertor.
22.120 + * @param inst instance
22.121 + * @param conv convertor, if <code>conv==null</code> it is same like
22.122 + * remove(Object)
22.123 + */
22.124 + public final <T,R> void remove(T inst, Convertor<T,R> conv) {
22.125 + removePair(new ConvertingItem<T,R>(inst, conv));
22.126 + }
22.127 +
22.128 + /** Changes all pairs in the lookup to new values. Converts collection of
22.129 + * instances to collection of pairs.
22.130 + * @param col the collection of (Item) objects
22.131 + * @param conv the convertor to use or null
22.132 + */
22.133 + public final <T,R> void set(Collection<T> col, Convertor<T,R> conv) {
22.134 + ArrayList<Pair<?>> l = new ArrayList<Pair<?>>(col.size());
22.135 + Iterator<T> it = col.iterator();
22.136 +
22.137 + if (conv == null) {
22.138 + while (it.hasNext()) {
22.139 + l.add(new SimpleItem<T>(it.next()));
22.140 + }
22.141 + } else {
22.142 + while (it.hasNext()) {
22.143 + l.add(new ConvertingItem<T,R>(it.next(), conv));
22.144 + }
22.145 + }
22.146 +
22.147 + setPairs(l);
22.148 + }
22.149 +
22.150 + /** Convertor postpones an instantiation of an object.
22.151 + * @since 1.25
22.152 + */
22.153 + public static interface Convertor<T,R> {
22.154 + /** Convert obj to other object. There is no need to implement
22.155 + * cache mechanism. It is provided by
22.156 + * {@link Item#getInstance()} method itself. However the
22.157 + * method can be called more than once because instance is held
22.158 + * just by weak reference.
22.159 + *
22.160 + * @param obj the registered object
22.161 + * @return the object converted from this object
22.162 + */
22.163 + public R convert(T obj);
22.164 +
22.165 + /** Return type of converted object. Accessible via
22.166 + * {@link Item#getType()}
22.167 + * @param obj the registered object
22.168 + * @return the class that will be produced from this object (class or
22.169 + * superclass of convert (obj))
22.170 + */
22.171 + public Class<? extends R> type(T obj);
22.172 +
22.173 + /** Computes the ID of the resulted object. Accessible via
22.174 + * {@link Item#getId()}.
22.175 + * @param obj the registered object
22.176 + * @return the ID for the object
22.177 + */
22.178 + public String id(T obj);
22.179 +
22.180 + /** The human presentable name for the object. Accessible via
22.181 + * {@link Item#getDisplayName()}.
22.182 + * @param obj the registered object
22.183 + * @return the name representing the object for the user
22.184 + */
22.185 + public String displayName(T obj);
22.186 + }
22.187 +
22.188 + /** Instance of one item representing an object.
22.189 + */
22.190 + final static class SimpleItem<T> extends Pair<T> {
22.191 + private T obj;
22.192 +
22.193 + /** Create an item.
22.194 + * @obj object to register
22.195 + */
22.196 + public SimpleItem(T obj) {
22.197 + if (obj == null) {
22.198 + throw new NullPointerException();
22.199 + }
22.200 + this.obj = obj;
22.201 + }
22.202 +
22.203 + /** Tests whether this item can produce object
22.204 + * of class c.
22.205 + */
22.206 + public boolean instanceOf(Class<?> c) {
22.207 + return c.isInstance(obj);
22.208 + }
22.209 +
22.210 + /** Get instance of registered object. If convertor is specified then
22.211 + * method InstanceLookup.Convertor.convertor is used and weak reference
22.212 + * to converted object is saved.
22.213 + * @return the instance of the object.
22.214 + */
22.215 + public T getInstance() {
22.216 + return obj;
22.217 + }
22.218 +
22.219 + @Override
22.220 + public boolean equals(Object o) {
22.221 + if (o instanceof SimpleItem) {
22.222 + return obj.equals(((SimpleItem) o).obj);
22.223 + } else {
22.224 + return false;
22.225 + }
22.226 + }
22.227 +
22.228 + @Override
22.229 + public int hashCode() {
22.230 + return obj.hashCode();
22.231 + }
22.232 +
22.233 + /** An identity of the item.
22.234 + * @return string representing the item, that can be used for
22.235 + * persistance purposes to locate the same item next time
22.236 + */
22.237 + public String getId() {
22.238 + return "IL[" + obj.toString(); // NOI18N
22.239 + }
22.240 +
22.241 + /** Getter for display name of the item.
22.242 + */
22.243 + public String getDisplayName() {
22.244 + return obj.toString();
22.245 + }
22.246 +
22.247 + /** Method that can test whether an instance of a class has been created
22.248 + * by this item.
22.249 + *
22.250 + * @param obj the instance
22.251 + * @return if the item has already create an instance and it is the same
22.252 + * as obj.
22.253 + */
22.254 + protected boolean creatorOf(Object obj) {
22.255 + return obj == this.obj;
22.256 + }
22.257 +
22.258 + /** The class of this item.
22.259 + * @return the correct class
22.260 + */
22.261 + @SuppressWarnings("unchecked")
22.262 + public Class<? extends T> getType() {
22.263 + return (Class<? extends T>)obj.getClass();
22.264 + }
22.265 + }
22.266 + // end of SimpleItem
22.267 +
22.268 + /** Instance of one item registered in the map.
22.269 + */
22.270 + final static class ConvertingItem<T,R> extends Pair<R> {
22.271 + /** registered object */
22.272 + private T obj;
22.273 +
22.274 + /** Reference to converted object. */
22.275 + private WeakReference<R> ref;
22.276 +
22.277 + /** convertor to use */
22.278 + private Convertor<? super T,R> conv;
22.279 +
22.280 + /** Create an item.
22.281 + * @obj object to register
22.282 + * @conv a convertor, can be <code>null</code>.
22.283 + */
22.284 + public ConvertingItem(T obj, Convertor<? super T,R> conv) {
22.285 + this.obj = obj;
22.286 + this.conv = conv;
22.287 + }
22.288 +
22.289 + /** Tests whether this item can produce object
22.290 + * of class c.
22.291 + */
22.292 + public boolean instanceOf(Class<?> c) {
22.293 + return c.isAssignableFrom(getType());
22.294 + }
22.295 +
22.296 + /** Returns converted object or null if obj has not been converted yet
22.297 + * or reference was cleared by garbage collector.
22.298 + */
22.299 + private R getConverted() {
22.300 + if (ref == null) {
22.301 + return null;
22.302 + }
22.303 +
22.304 + return ref.get();
22.305 + }
22.306 +
22.307 + /** Get instance of registered object. If convertor is specified then
22.308 + * method InstanceLookup.Convertor.convertor is used and weak reference
22.309 + * to converted object is saved.
22.310 + * @return the instance of the object.
22.311 + */
22.312 + public synchronized R getInstance() {
22.313 + R converted = getConverted();
22.314 +
22.315 + if (converted == null) {
22.316 + converted = conv.convert(obj);
22.317 + ref = new WeakReference<R>(converted);
22.318 + }
22.319 +
22.320 + return converted;
22.321 + }
22.322 +
22.323 + @Override
22.324 + public boolean equals(Object o) {
22.325 + if (o instanceof ConvertingItem) {
22.326 + return obj.equals(((ConvertingItem) o).obj);
22.327 + } else {
22.328 + return false;
22.329 + }
22.330 + }
22.331 +
22.332 + @Override
22.333 + public int hashCode() {
22.334 + return obj.hashCode();
22.335 + }
22.336 +
22.337 + /** An identity of the item.
22.338 + * @return string representing the item, that can be used for
22.339 + * persistance purposes to locate the same item next time
22.340 + */
22.341 + public String getId() {
22.342 + return conv.id(obj);
22.343 + }
22.344 +
22.345 + /** Getter for display name of the item.
22.346 + */
22.347 + public String getDisplayName() {
22.348 + return conv.displayName(obj);
22.349 + }
22.350 +
22.351 + /** Method that can test whether an instance of a class has been created
22.352 + * by this item.
22.353 + *
22.354 + * @param obj the instance
22.355 + * @return if the item has already create an instance and it is the same
22.356 + * as obj.
22.357 + */
22.358 + protected boolean creatorOf(Object obj) {
22.359 + if (conv == null) {
22.360 + return obj == this.obj;
22.361 + } else {
22.362 + return obj == getConverted();
22.363 + }
22.364 + }
22.365 +
22.366 + /** The class of this item.
22.367 + * @return the correct class
22.368 + */
22.369 + @SuppressWarnings("unchecked")
22.370 + public Class<? extends R> getType() {
22.371 + R converted = getConverted();
22.372 +
22.373 + if (converted == null) {
22.374 + return conv.type(obj);
22.375 + }
22.376 +
22.377 + return (Class<? extends R>)converted.getClass();
22.378 + }
22.379 + }
22.380 + // end of ConvertingItem
22.381 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/Lookups.java Mon Dec 14 20:58:39 2009 +0100
23.3 @@ -0,0 +1,317 @@
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-2009 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 +
23.45 +package org.openide.util.lookup;
23.46 +
23.47 +import java.util.Arrays;
23.48 +import org.netbeans.modules.openide.util.NamedServicesProvider;
23.49 +import org.openide.util.Lookup;
23.50 +
23.51 +/**
23.52 + * Static factory methods for creating common lookup implementations.
23.53 + *
23.54 + * @author David Strupl
23.55 + * @since 2.21
23.56 + */
23.57 +public class Lookups {
23.58 +
23.59 + /** static methods only */
23.60 + private Lookups() {}
23.61 +
23.62 + /**
23.63 + * Creates a singleton lookup. It means lookup that contains only
23.64 + * one object specified via the supplied parameter. The lookup will
23.65 + * either return the object or null if the supplied template does
23.66 + * not match the class. If the specified argument is null the method
23.67 + * will end with NullPointerException.
23.68 + * @return Fully initialized lookup object ready to use
23.69 + * @throws NullPointerException if the supplied argument is null
23.70 + * @since 2.21
23.71 + */
23.72 + public static Lookup singleton(Object objectToLookup) {
23.73 + if (objectToLookup == null) {
23.74 + throw new NullPointerException();
23.75 + }
23.76 +
23.77 + return new SingletonLookup(objectToLookup);
23.78 + }
23.79 +
23.80 + /**
23.81 + * Creates a lookup that contains an array of objects specified via the
23.82 + * parameter. The resulting lookup is fixed in the following sense: it
23.83 + * contains only fixed set of objects passed in by the array parameter.
23.84 + * Its contents never changes so registering listeners on such lookup
23.85 + * does not have any observable effect (the listeners are never called).
23.86 + *
23.87 + * @param objectsToLookup list of objects to include
23.88 + * @return Fully initialized lookup object ready to use
23.89 + * @throws NullPointerException if the supplied argument is null
23.90 + * @since 2.21
23.91 + *
23.92 + */
23.93 + public static Lookup fixed(Object... objectsToLookup) {
23.94 + if (objectsToLookup == null) {
23.95 + throw new NullPointerException();
23.96 + }
23.97 +
23.98 + if (objectsToLookup.length == 0) {
23.99 + return Lookup.EMPTY;
23.100 + }
23.101 +
23.102 + if (objectsToLookup.length == 1) {
23.103 + return singleton(objectsToLookup[0]);
23.104 + }
23.105 +
23.106 + return new SimpleLookup(Arrays.asList(objectsToLookup));
23.107 + }
23.108 +
23.109 + /**
23.110 + * Creates a lookup that contains an array of objects specified via the
23.111 + * parameter. The resulting lookup is fixed in the following sense: it
23.112 + * contains only fixed set of objects passed in by the array parameter.
23.113 + * The objects returned from this lookup are converted to real objects
23.114 + * before they are returned by the lookup.
23.115 + * Its contents never changes so registering listeners on such lookup
23.116 + * does not have any observable effect (the listeners are never called).
23.117 + *
23.118 + * @return Fully initialized lookup object ready to use
23.119 + * @throws NullPointerException if the any of the arguments is null
23.120 + * @since 2.21
23.121 + *
23.122 + */
23.123 + public static <T,R> Lookup fixed(T[] keys, InstanceContent.Convertor<? super T,R> convertor) {
23.124 + if (keys == null) {
23.125 + throw new NullPointerException();
23.126 + }
23.127 +
23.128 + if (convertor == null) {
23.129 + throw new NullPointerException();
23.130 + }
23.131 +
23.132 + return new SimpleLookup(Arrays.asList(keys), convertor);
23.133 + }
23.134 +
23.135 + /** Creates a lookup that delegates to another one but that one can change
23.136 + * from time to time. The returned lookup checks every time somebody calls
23.137 + * <code>lookup</code> or <code>lookupItem</code> method whether the
23.138 + * provider still returns the same lookup. If not, it updates state of
23.139 + * all {@link org.openide.util.Lookup.Result}s
23.140 + * that it created (and that still exists).
23.141 + * <P>
23.142 + * The user of this method has to implement its provider's <code>getLookup</code>
23.143 + * method (must be thread safe and fast, will be called often and from any thread)
23.144 + * pass it to this method and use the returned lookup. Whenever the user
23.145 + * changes the return value from the <code>getLookup</code> method and wants
23.146 + * to notify listeners on the lookup about that it should trigger the event
23.147 + * firing, for example by calling <code>lookup.lookup (Object.class)</code>
23.148 + * directly on the lookup returned by this method
23.149 + * that forces a check of the return value of {@link org.openide.util.Lookup.Provider#getLookup}</code>.
23.150 + *
23.151 + * @param provider the provider that returns a lookup to delegate to
23.152 + * @return lookup delegating to the lookup returned by the provider
23.153 + * @since 3.9
23.154 + */
23.155 + public static Lookup proxy(Lookup.Provider provider) {
23.156 + return new SimpleProxyLookup(provider);
23.157 + }
23.158 +
23.159 + /** Returns a lookup that implements the JDK1.3 JAR services mechanism and delegates
23.160 + * to META-INF/services/name.of.class files.
23.161 + * <p>Some extensions to the JAR services specification are implemented:
23.162 + * <ol>
23.163 + * <li>An entry may be followed by a line of the form <code>#position=<i>integer</i></code>
23.164 + * to specify ordering. (Smaller numbers first, entries with unspecified position last.)
23.165 + * <li>A line of the form <code>#-<i>classname</i></code> suppresses an entry registered
23.166 + * in another file, so can be used to supersede one implementation with another.
23.167 + * </ol>
23.168 + * <p>Note: It is not dynamic - so if you need to change the classloader or JARs,
23.169 + * wrap it in a {@link ProxyLookup} and change the delegate when necessary.
23.170 + * Existing instances will be kept if the implementation classes are unchanged,
23.171 + * so there is "stability" in doing this provided some parent loaders are the same
23.172 + * as the previous ones.
23.173 + * @since 3.35
23.174 + * @see ServiceProvider
23.175 + */
23.176 + public static Lookup metaInfServices(ClassLoader classLoader) {
23.177 + return new MetaInfServicesLookup(classLoader, "META-INF/services/"); // NOI18N
23.178 + }
23.179 +
23.180 + /** Returns a lookup that behaves exactly like {@link #metaInfServices(ClassLoader)}
23.181 + * except that it does not read data from <code>META-INF/services/</code>, but instead
23.182 + * from the specified prefix.
23.183 + * @param classLoader class loader to use for loading
23.184 + * @param prefix prefix to prepend to the class name when searching
23.185 + * @since 7.9
23.186 + */
23.187 + public static Lookup metaInfServices(ClassLoader classLoader, String prefix) {
23.188 + return new MetaInfServicesLookup(classLoader, prefix);
23.189 + }
23.190 +
23.191 + /** Creates a <q>named</q> lookup.
23.192 + * It is a lookup identified by a given path.
23.193 + * Two lookups with the same path should have the same content.
23.194 + * <p>It is expected that each <q>named</q> lookup
23.195 + * will contain a superset of what would be created by:
23.196 + * <code>{@linkplain #metaInfServices(ClassLoader,String) metaInfServices}(theRightLoader, "META-INF/namedservices/" + path + "/")</code>
23.197 + *
23.198 + * <p class="nonnormative">Various environments can add their own
23.199 + * extensions to its content. As such
23.200 + * {@link Lookups#forPath(java.lang.String)} can combine lookups
23.201 + * from several sources. In current NetBeans Runtime Container, two lookups are used:
23.202 + * </p>
23.203 + * <ul class="nonnormative">
23.204 + * <li><code>Lookups.metaInfServices("META-INF/namedservices/" + path)</code></li>
23.205 + * <li><code>org.openide.loaders.FolderLookup(path)</code></li>
23.206 + * </ul>
23.207 + * <p class="nonnormative">
23.208 + * Please note that these lookups differ in the way they inspect sub-folders.
23.209 + * The first lookup just returns instances from the given path, ignoring
23.210 + * sub-folders, the second one retrieves instances from the whole sub-tree.
23.211 + * </p>
23.212 + * <p>
23.213 + * Read more about the <a href="@org-openide-util@/org/openide/util/doc-files/api.html#folderlookup">usage of this method</a>.
23.214 + *
23.215 + * @param path the path identifying the lookup, e.g. <code>Projects/Actions</code>
23.216 + * @return lookup associated with this path
23.217 + * @since 7.9
23.218 + */
23.219 + public static Lookup forPath(String path) {
23.220 + return NamedServicesProvider.find(path);
23.221 + }
23.222 +
23.223 + /** Creates a lookup that wraps another one and filters out instances
23.224 + * of specified classes. If you have a lookup and
23.225 + * you want to remove all instances of ActionMap you can use:
23.226 + * <pre>
23.227 + * l = Lookups.exclude(lookup, ActionMap.class);
23.228 + * </pre>
23.229 + * Then anybody who asks for <code>l.lookup(ActionMap.class)</code> or
23.230 + * subclass will get <code>null</code>. Even if the original lookup contains the
23.231 + * value.
23.232 + * To create empty lookup (well, just an example, otherwise use {@link Lookup#EMPTY}) one could use:
23.233 + * <pre>
23.234 + * Lookup.exclude(anyLookup, Object.class);
23.235 + * </pre>
23.236 + * as any instance in any lookup is of type Object and thus would be excluded.
23.237 + * <p>
23.238 + * The complete behavior can be described as <code>classes</code> being
23.239 + * a barrier. For an object not to be excluded, there has to be an inheritance
23.240 + * path between the queried class and the actual class of the instance,
23.241 + * that is not blocked by any of the excluded classes:
23.242 + * <pre>
23.243 + * interface A {}
23.244 + * interface B {}
23.245 + * class C implements A, B {}
23.246 + * Object c = new C();
23.247 + * Lookup l1 = Lookups.singleton(c);
23.248 + * Lookup l2 = Lookups.exclude(l1, A.class);
23.249 + * assertNull("A is directly excluded", l2.lookup(A.class));
23.250 + * assertEquals("Returns C as A.class is not between B and C", c, l2.lookup(B.class));
23.251 + * </pre>
23.252 + * For more info check the
23.253 + * <a href="http://hg.netbeans.org/main-golden/annotate/4883eaeda744/openide.util/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java">
23.254 + * excluding lookup tests</a> and the discussion in issue
23.255 + * <a href="http://openide.netbeans.org/issues/show_bug.cgi?id=53058">53058</a>.
23.256 + *
23.257 + * @param lookup the original lookup that should be filtered
23.258 + * @param classes array of classes those instances should be excluded
23.259 + * @since 5.4
23.260 + */
23.261 + public static Lookup exclude(Lookup lookup, Class... classes) {
23.262 + return new ExcludingLookup(lookup, classes);
23.263 + }
23.264 +
23.265 + /** Creates <code>Lookup.Item</code> representing the instance passed in.
23.266 + *
23.267 + * @param instance the object for which Lookup.Item should be creted
23.268 + * @param id unique identification of the object, for details see {@link org.openide.util.Lookup.Item#getId},
23.269 + * can be <code>null</code>
23.270 + * @return lookup item representing instance
23.271 + * @since 4.8
23.272 + */
23.273 + public static <T> Lookup.Item<T> lookupItem(T instance, String id) {
23.274 + return new LookupItem<T>(instance, id);
23.275 + }
23.276 +
23.277 + private static class LookupItem<T> extends Lookup.Item<T> {
23.278 + private String id;
23.279 + private T instance;
23.280 +
23.281 + public LookupItem(T instance) {
23.282 + this(instance, null);
23.283 + }
23.284 +
23.285 + public LookupItem(T instance, String id) {
23.286 + this.id = id;
23.287 + this.instance = instance;
23.288 + }
23.289 +
23.290 + public String getDisplayName() {
23.291 + return getId();
23.292 + }
23.293 +
23.294 + public String getId() {
23.295 + return (id == null) ? instance.toString() : id;
23.296 + }
23.297 +
23.298 + public T getInstance() {
23.299 + return instance;
23.300 + }
23.301 +
23.302 + @SuppressWarnings("unchecked")
23.303 + public Class<? extends T> getType() {
23.304 + return (Class<? extends T>)instance.getClass();
23.305 + }
23.306 +
23.307 + public @Override boolean equals(Object object) {
23.308 + if (object instanceof LookupItem) {
23.309 + return instance == ((LookupItem) object).getInstance();
23.310 + }
23.311 +
23.312 + return false;
23.313 + }
23.314 +
23.315 + public @Override int hashCode() {
23.316 + return instance.hashCode();
23.317 + }
23.318 + }
23.319 + // End of LookupItem class
23.320 +}
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/MetaInfServicesLookup.java Mon Dec 14 20:58:39 2009 +0100
24.3 @@ -0,0 +1,563 @@
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 +
24.45 +package org.openide.util.lookup;
24.46 +
24.47 +import java.io.BufferedReader;
24.48 +import java.io.IOException;
24.49 +import java.io.InputStream;
24.50 +import java.io.InputStreamReader;
24.51 +import java.lang.ref.Reference;
24.52 +import java.lang.ref.WeakReference;
24.53 +import java.lang.reflect.Method;
24.54 +import java.net.URL;
24.55 +import java.util.ArrayList;
24.56 +import java.util.Collection;
24.57 +import java.util.Enumeration;
24.58 +import java.util.HashSet;
24.59 +import java.util.LinkedHashSet;
24.60 +import java.util.List;
24.61 +import java.util.Map;
24.62 +import java.util.WeakHashMap;
24.63 +import java.util.concurrent.Executor;
24.64 +import java.util.concurrent.Executors;
24.65 +import java.util.logging.Level;
24.66 +import java.util.logging.Logger;
24.67 +import org.openide.util.Lookup;
24.68 +
24.69 +/**
24.70 + * @author Jaroslav Tulach, Jesse Glick
24.71 + * @see Lookups#metaInfServices(ClassLoader,String)
24.72 + * @see "#14722"
24.73 + */
24.74 +final class MetaInfServicesLookup extends AbstractLookup {
24.75 +
24.76 + private static final Logger LOGGER = Logger.getLogger(MetaInfServicesLookup.class.getName());
24.77 + static final Executor RP = Executors.newSingleThreadExecutor();
24.78 + /*TBD: Inject RequestProcessor somehow
24.79 + new RequestProcessor(MetaInfServicesLookup.class.getName(), 1);
24.80 + */
24.81 + private static int knownInstancesCount;
24.82 + private static final List<Reference<Object>> knownInstances;
24.83 + static {
24.84 + knownInstances = new ArrayList<Reference<Object>>();
24.85 + for (int i = 0; i < 512; i++) {
24.86 + knownInstances.add(null);
24.87 + }
24.88 + }
24.89 +
24.90 + /** A set of all requested classes.
24.91 + * Note that classes that we actually succeeded on can never be removed
24.92 + * from here because we hold a strong reference to the loader.
24.93 + * However we also hold classes which are definitely not loadable by
24.94 + * our loader.
24.95 + */
24.96 + private final Map<Class,Object> classes = new WeakHashMap<Class,Object>();
24.97 +
24.98 + /** class loader to use */
24.99 + private final ClassLoader loader;
24.100 + /** prefix to prepend */
24.101 + private final String prefix;
24.102 +
24.103 + /** Create a lookup reading from a specified classloader.
24.104 + */
24.105 + public MetaInfServicesLookup(ClassLoader loader, String prefix) {
24.106 + this.loader = loader;
24.107 + this.prefix = prefix;
24.108 +
24.109 + LOGGER.log(Level.FINE, "Created: {0}", this);
24.110 + }
24.111 +
24.112 + @Override
24.113 + public String toString() {
24.114 + return "MetaInfServicesLookup[" + loader + "]"; // NOI18N
24.115 + }
24.116 +
24.117 + /* Tries to load appropriate resources from manifest files.
24.118 + */
24.119 + @Override
24.120 + protected final void beforeLookup(Lookup.Template t) {
24.121 + Class c = t.getType();
24.122 +
24.123 + Collection<AbstractLookup.Pair<?>> toAdd = null;
24.124 + synchronized (this) {
24.125 + if (classes.get(c) == null) { // NOI18N
24.126 + toAdd = new ArrayList<Pair<?>>();
24.127 + } else {
24.128 + // ok, nothing needs to be done
24.129 + return;
24.130 + }
24.131 + }
24.132 + if (toAdd != null) {
24.133 + search(c, toAdd);
24.134 + }
24.135 + synchronized (this) {
24.136 + if (classes.put(c, "") == null) { // NOI18N
24.137 + // Added new class, search for it.
24.138 + LinkedHashSet<AbstractLookup.Pair<?>> arr = getPairsAsLHS();
24.139 + arr.addAll(toAdd);
24.140 + setPairs(arr, RP);
24.141 + }
24.142 + }
24.143 + }
24.144 +
24.145 + /** Finds all pairs and adds them to the collection.
24.146 + *
24.147 + * @param clazz class to find
24.148 + * @param result collection to add Pair to
24.149 + */
24.150 + private void search(Class<?> clazz, Collection<AbstractLookup.Pair<?>> result) {
24.151 + if (LOGGER.isLoggable(Level.FINER)) {
24.152 + LOGGER.log(Level.FINER, "Searching for " + clazz.getName() + " in " + clazz.getClassLoader() + " from " + this);
24.153 + }
24.154 +
24.155 + String res = prefix + clazz.getName(); // NOI18N
24.156 + Enumeration<URL> en;
24.157 +
24.158 + try {
24.159 + en = loader.getResources(res);
24.160 + } catch (IOException ioe) {
24.161 + // do not use ErrorManager because we are in the startup code
24.162 + // and ErrorManager might not be ready
24.163 + ioe.printStackTrace();
24.164 +
24.165 + return;
24.166 + }
24.167 +
24.168 + // Do not create multiple instances in case more than one JAR
24.169 + // has the same entry in it (and they load to the same class).
24.170 + // Probably would not happen, assuming JARs only list classes
24.171 + // they own, but just in case...
24.172 + List<Item> foundClasses = new ArrayList<Item>();
24.173 + Collection<Class> removeClasses = new ArrayList<Class>();
24.174 +
24.175 + boolean foundOne = false;
24.176 +
24.177 + while (en.hasMoreElements()) {
24.178 + if (!foundOne) {
24.179 + foundOne = true;
24.180 +
24.181 + // Double-check that in fact we can load the *interface* class.
24.182 + // For example, say class I is defined in two JARs, J1 and J2.
24.183 + // There is also an implementation M1 defined in J1, and another
24.184 + // implementation M2 defined in J2.
24.185 + // Classloaders C1 and C2 are made from J1 and J2.
24.186 + // A MetaInfServicesLookup is made from C1. Then the user asks to
24.187 + // lookup I as loaded from C2. J1 has the services line and lists
24.188 + // M1, and we can in fact make it. However it is not of the desired
24.189 + // type to be looked up. Don't do this check, which could be expensive,
24.190 + // unless we expect to be getting some results, however.
24.191 + Class realMcCoy = null;
24.192 +
24.193 + try {
24.194 + realMcCoy = loader.loadClass(clazz.getName());
24.195 + } catch (ClassNotFoundException cnfe) {
24.196 + // our loader does not know about it, OK
24.197 + }
24.198 +
24.199 + if (realMcCoy != clazz) {
24.200 + // Either the interface class is not available at all in our loader,
24.201 + // or it is not the same version as we expected. Don't provide results.
24.202 + if (LOGGER.isLoggable(Level.WARNING)) {
24.203 + if (realMcCoy != null) {
24.204 + LOGGER.log(Level.WARNING,
24.205 + clazz.getName() + " is not the real McCoy! Actually found it in " +
24.206 + realMcCoy.getClassLoader()
24.207 + ); // NOI18N
24.208 + } else {
24.209 + LOGGER.log(Level.WARNING, clazz.getName() + " could not be found in " + loader); // NOI18N
24.210 + }
24.211 + }
24.212 +
24.213 + return;
24.214 + }
24.215 + }
24.216 +
24.217 + URL url = en.nextElement();
24.218 + Item currentItem = null;
24.219 +
24.220 + try {
24.221 + InputStream is = url.openStream();
24.222 +
24.223 + try {
24.224 + BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // NOI18N
24.225 +
24.226 + while (true) {
24.227 + String line = reader.readLine();
24.228 +
24.229 + if (line == null) {
24.230 + break;
24.231 + }
24.232 +
24.233 + line = line.trim();
24.234 +
24.235 + // is it position attribute?
24.236 + if (line.startsWith("#position=")) {
24.237 + if (currentItem == null) {
24.238 + LOGGER.log(Level.WARNING, "Found line '{0}' in {1} but there is no item to associate it with", new Object[] {line, url});
24.239 + continue;
24.240 + }
24.241 +
24.242 + try {
24.243 + currentItem.position = Integer.parseInt(line.substring(10));
24.244 + } catch (NumberFormatException e) {
24.245 + // do not use ErrorManager because we are in the startup code
24.246 + // and ErrorManager might not be ready
24.247 + e.printStackTrace();
24.248 + }
24.249 + }
24.250 +
24.251 + if (currentItem != null) {
24.252 + insertItem(currentItem, foundClasses);
24.253 + currentItem = null;
24.254 + }
24.255 +
24.256 + // Ignore blank lines and comments.
24.257 + if (line.length() == 0) {
24.258 + continue;
24.259 + }
24.260 +
24.261 + boolean remove = false;
24.262 +
24.263 + if (line.charAt(0) == '#') {
24.264 + if ((line.length() == 1) || (line.charAt(1) != '-')) {
24.265 + continue;
24.266 + }
24.267 +
24.268 + // line starting with #- is a sign to remove that class from lookup
24.269 + remove = true;
24.270 + line = line.substring(2);
24.271 + }
24.272 +
24.273 + Class inst = null;
24.274 +
24.275 + try {
24.276 + // Most lines are fully-qualified class names.
24.277 + inst = Class.forName(line, false, loader);
24.278 + } catch (ClassNotFoundException cnfe) {
24.279 + if (remove) {
24.280 + // if we are removing somthing and the something
24.281 + // cannot be found it is ok to do nothing
24.282 + continue;
24.283 + } else {
24.284 + // but if we are not removing just rethrow
24.285 + throw cnfe;
24.286 + }
24.287 + }
24.288 +
24.289 + if (!clazz.isAssignableFrom(inst)) {
24.290 + throw new ClassNotFoundException(clazzToString(inst) + " not a subclass of " + clazzToString(clazz)); // NOI18N
24.291 + }
24.292 +
24.293 + if (remove) {
24.294 + removeClasses.add(inst);
24.295 + } else {
24.296 + // create new item here, but do not put it into
24.297 + // foundClasses array yet because following line
24.298 + // might specify its position
24.299 + currentItem = new Item();
24.300 + currentItem.clazz = inst;
24.301 + }
24.302 + }
24.303 +
24.304 + if (currentItem != null) {
24.305 + insertItem(currentItem, foundClasses);
24.306 + currentItem = null;
24.307 + }
24.308 + } finally {
24.309 + is.close();
24.310 + }
24.311 + } catch (ClassNotFoundException ex) {
24.312 + LOGGER.log(Level.WARNING, null, ex);
24.313 + } catch (IOException ex) {
24.314 + LOGGER.log(Level.WARNING, null, ex);
24.315 + }
24.316 + }
24.317 +
24.318 + LOGGER.log(Level.FINER, "Found impls of {0}: {1} and removed: {2} from: {3}", new Object[] {clazz.getName(), foundClasses, removeClasses, this});
24.319 +
24.320 + foundClasses.removeAll(removeClasses);
24.321 +
24.322 + for (Item item : foundClasses) {
24.323 + if (removeClasses.contains(item.clazz)) {
24.324 + continue;
24.325 + }
24.326 +
24.327 + result.add(new P(item.clazz));
24.328 + }
24.329 + }
24.330 + private static String clazzToString(Class clazz) {
24.331 + return clazz.getName() + "@" + clazz.getClassLoader() + ":" + clazz.getProtectionDomain().getCodeSource().getLocation(); // NOI18N
24.332 + }
24.333 +
24.334 + /**
24.335 + * Insert item to the list according to item.position value.
24.336 + */
24.337 + private void insertItem(Item item, List<Item> list) {
24.338 + // no position? -> add it to the end
24.339 + if (item.position == -1) {
24.340 + list.add(item);
24.341 +
24.342 + return;
24.343 + }
24.344 +
24.345 + int index = -1;
24.346 + for (Item i : list) {
24.347 + index++;
24.348 +
24.349 + if (i.position == -1) {
24.350 + list.add(index, item);
24.351 +
24.352 + return;
24.353 + } else {
24.354 + if (i.position > item.position) {
24.355 + list.add(index, item);
24.356 +
24.357 + return;
24.358 + }
24.359 + }
24.360 + }
24.361 +
24.362 + list.add(item);
24.363 + }
24.364 +
24.365 + private static class Item {
24.366 + private Class clazz;
24.367 + private int position = -1;
24.368 + @Override
24.369 + public String toString() {
24.370 + return "MetaInfServicesLookup.Item[" + clazz.getName() + "]"; // NOI18N
24.371 + }
24.372 + }
24.373 +
24.374 + /** Pair that holds name of a class and maybe the instance.
24.375 + */
24.376 + private static final class P extends AbstractLookup.Pair<Object> {
24.377 + /** May be one of three things:
24.378 + * 1. The implementation class which was named in the services file.
24.379 + * 2. An instance of it.
24.380 + * 3. Null, if creation of the instance resulted in an error.
24.381 + */
24.382 + private Object object;
24.383 +
24.384 + public P(Class<?> clazz) {
24.385 + this.object = clazz;
24.386 + }
24.387 +
24.388 + /** Finds the class.
24.389 + */
24.390 + private Class<? extends Object> clazz() {
24.391 + Object o = object;
24.392 +
24.393 + if (o instanceof Class) {
24.394 + return (Class<? extends Object>) o;
24.395 + } else if (o != null) {
24.396 + return o.getClass();
24.397 + } else {
24.398 + // Broken.
24.399 + return Object.class;
24.400 + }
24.401 + }
24.402 +
24.403 + @Override
24.404 + public boolean equals(Object o) {
24.405 + if (o instanceof P) {
24.406 + return ((P) o).clazz().equals(clazz());
24.407 + }
24.408 +
24.409 + return false;
24.410 + }
24.411 +
24.412 + @Override
24.413 + public int hashCode() {
24.414 + return clazz().hashCode();
24.415 + }
24.416 +
24.417 + protected boolean instanceOf(Class<?> c) {
24.418 + return c.isAssignableFrom(clazz());
24.419 + }
24.420 +
24.421 + public Class<?> getType() {
24.422 + return clazz();
24.423 + }
24.424 +
24.425 + public Object getInstance() {
24.426 + Object o = object; // keeping local copy to avoid another
24.427 +
24.428 + // thread to modify it under my hands
24.429 + if (o instanceof Class) {
24.430 + synchronized (o) { // o is Class and we will not create
24.431 + // 2 instances of the same class
24.432 +
24.433 + try {
24.434 + Class<?> c = ((Class) o);
24.435 + o = null;
24.436 +
24.437 + synchronized (knownInstances) { // guards only the static cache
24.438 + int size = knownInstances.size();
24.439 + int index = c.hashCode() % size;
24.440 + for (int i = 0; i < size; i++) {
24.441 + Reference<Object> ref = knownInstances.get(index);
24.442 + Object obj = ref == null ? null : ref.get();
24.443 + if (obj == null) {
24.444 + break;
24.445 + }
24.446 + if (c == obj.getClass()) {
24.447 + o = obj;
24.448 + break;
24.449 + }
24.450 + if (++index == size) {
24.451 + index = 0;
24.452 + }
24.453 + }
24.454 + }
24.455 +
24.456 + if (o == null) {
24.457 + o = createInstance(c);
24.458 +
24.459 + synchronized (knownInstances) { // guards only the static cache
24.460 + hashPut(o);
24.461 +
24.462 + int size = knownInstances.size();
24.463 + if (knownInstancesCount > size * 2 / 3) {
24.464 + LOGGER.log(Level.CONFIG, "Cache of size {0} is 2/3 full. Rehashing.", size);
24.465 + HashSet<Reference<Object>> all = new HashSet<Reference<Object>>();
24.466 + all.addAll(knownInstances);
24.467 + for (int i = 0; i < size; i++) {
24.468 + knownInstances.set(i, null);
24.469 + }
24.470 + for (int i = 0; i < size; i++) {
24.471 + knownInstances.add(null);
24.472 + }
24.473 + knownInstancesCount = 0;
24.474 + for (Reference<Object> r : all) {
24.475 + if (r == null) {
24.476 + continue;
24.477 + }
24.478 + Object instance = r.get();
24.479 + if (instance == null) {
24.480 + continue;
24.481 + }
24.482 + hashPut(instance);
24.483 + }
24.484 + }
24.485 +
24.486 + }
24.487 + }
24.488 +
24.489 + // Do not assign to instance var unless there is a complete synch
24.490 + // block between the newInstance and this line. Otherwise we could
24.491 + // be assigning a half-constructed instance that another thread
24.492 + // could see and return immediately.
24.493 + object = o;
24.494 + } catch (Exception ex) {
24.495 + LOGGER.log(Level.WARNING, "Cannot create " + object, ex);
24.496 + object = null;
24.497 + } catch (ExceptionInInitializerError x) { // #174055
24.498 + LOGGER.log(Level.WARNING, "Cannot create " + object, x);
24.499 + object = null;
24.500 + }
24.501 + }
24.502 + }
24.503 +
24.504 + return object;
24.505 + }
24.506 +
24.507 + public String getDisplayName() {
24.508 + return clazz().getName();
24.509 + }
24.510 +
24.511 + public String getId() {
24.512 + return clazz().getName();
24.513 + }
24.514 +
24.515 + protected boolean creatorOf(Object obj) {
24.516 + return obj == object;
24.517 + }
24.518 +
24.519 + private static void hashPut(Object o) {
24.520 + Class<?> c = o.getClass();
24.521 + int size = knownInstances.size();
24.522 + int index = c.hashCode() % size;
24.523 + for (int i = 0; i < size; i++) {
24.524 + Reference<Object> ref = knownInstances.get(index);
24.525 + Object obj = ref == null ? null : ref.get();
24.526 + if (obj == null) {
24.527 + knownInstances.set(index, new WeakReference<Object>(o));
24.528 + knownInstancesCount++;
24.529 + break;
24.530 + }
24.531 + if (++index == size) {
24.532 + index = 0;
24.533 + }
24.534 + }
24.535 + }
24.536 +
24.537 + private static boolean findSharedClassObjectSkip;
24.538 + private static Method findSharedClassObject;
24.539 + /** Basically does c.newInstance(), however the method is complicated
24.540 + * with a special behaviour for old and almost obsoleted NetBeans
24.541 + * class: SharedClassObject.
24.542 + */
24.543 + private static Object createInstance(Class<?> c) throws InstantiationException, IllegalAccessException {
24.544 + if (!findSharedClassObjectSkip) {
24.545 + try {
24.546 + if (findSharedClassObject == null) {
24.547 + Class<?> sco;
24.548 + try {
24.549 + sco = Class.forName("org.openide.util.SharedClassObject"); // NOI18N
24.550 + } catch (ClassNotFoundException ex) {
24.551 + findSharedClassObjectSkip = true;
24.552 + return c.newInstance();
24.553 + }
24.554 + findSharedClassObject = sco.getMethod("findObject", Class.class, boolean.class);
24.555 + }
24.556 + if (findSharedClassObject.getReturnType().isAssignableFrom(c)) {
24.557 + return findSharedClassObject.invoke(null, c, true);
24.558 + }
24.559 + } catch (Exception problem) {
24.560 + throw (InstantiationException)new InstantiationException(problem.getMessage()).initCause(problem);
24.561 + }
24.562 + }
24.563 + return c.newInstance();
24.564 + }
24.565 + }
24.566 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ProxyLookup.java Mon Dec 14 20:58:39 2009 +0100
25.3 @@ -0,0 +1,980 @@
25.4 +/*
25.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
25.6 + *
25.7 + * Copyright 1997-2009 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 + * Contributor(s):
25.28 + *
25.29 + * The Original Software is NetBeans. The Initial Developer of the Original
25.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
25.31 + * Microsystems, Inc. All Rights Reserved.
25.32 + *
25.33 + * If you wish your version of this file to be governed by only the CDDL
25.34 + * or only the GPL Version 2, indicate your decision by adding
25.35 + * "[Contributor] elects to include this software in this distribution
25.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
25.37 + * single choice of license, a recipient has the option to distribute
25.38 + * your version of this file under either the CDDL, the GPL Version 2 or
25.39 + * to extend the choice of license to its licensees as provided above.
25.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
25.41 + * Version 2 license, then the option applies only if the new code is
25.42 + * made subject to such option by the copyright holder.
25.43 + */
25.44 +
25.45 +package org.openide.util.lookup;
25.46 +
25.47 +import java.lang.ref.Reference;
25.48 +import java.lang.ref.WeakReference;
25.49 +import java.util.ArrayList;
25.50 +import java.util.Arrays;
25.51 +import java.util.Collection;
25.52 +import java.util.Collections;
25.53 +import java.util.HashMap;
25.54 +import java.util.HashSet;
25.55 +import java.util.IdentityHashMap;
25.56 +import java.util.Iterator;
25.57 +import java.util.List;
25.58 +import java.util.Map;
25.59 +import java.util.Map.Entry;
25.60 +import java.util.Set;
25.61 +import java.util.concurrent.Executor;
25.62 +import javax.swing.event.EventListenerList;
25.63 +import org.openide.util.Lookup;
25.64 +import org.openide.util.LookupEvent;
25.65 +import org.openide.util.LookupListener;
25.66 +
25.67 +/** Implementation of lookup that can delegate to others.
25.68 + *
25.69 + * @author Jaroslav Tulach
25.70 + * @since 1.9
25.71 + */
25.72 +public class ProxyLookup extends Lookup {
25.73 + /** data representing the state of the lookup */
25.74 + private ImmutableInternalData data;
25.75 +
25.76 + /** Create a proxy to some other lookups.
25.77 + * @param lookups the initial delegates
25.78 + */
25.79 + public ProxyLookup(Lookup... lookups) {
25.80 + data = ImmutableInternalData.EMPTY.setLookupsNoFire(lookups, true);
25.81 + }
25.82 +
25.83 + /**
25.84 + * Create a lookup initially proxying to no others.
25.85 + * Permits serializable subclasses.
25.86 + * @since 3.27
25.87 + */
25.88 + protected ProxyLookup() {
25.89 + data = ImmutableInternalData.EMPTY;
25.90 + }
25.91 +
25.92 + @Override
25.93 + public synchronized String toString() {
25.94 + return "ProxyLookup(class=" + getClass() + ")->" + Arrays.asList(getData().getLookups(false)); // NOI18N
25.95 + }
25.96 +
25.97 + /** Getter for the delegates.
25.98 + * @return the array of lookups we delegate to
25.99 + * @since 1.19
25.100 + */
25.101 + protected final Lookup[] getLookups() {
25.102 + synchronized (ProxyLookup.this) {
25.103 + return getData().getLookups(true);
25.104 + }
25.105 + }
25.106 +
25.107 + private Set<Lookup> identityHashSet(Collection<Lookup> current) {
25.108 + Map<Lookup,Void> map = new IdentityHashMap<Lookup, Void>();
25.109 + for (Lookup lookup : current) {
25.110 + map.put(lookup, null);
25.111 + }
25.112 + return map.keySet();
25.113 + }
25.114 +
25.115 + /**
25.116 + * Changes the delegates.
25.117 + *
25.118 + * @param lookups the new lookups to delegate to
25.119 + * @since 1.19 protected
25.120 + */
25.121 + protected final void setLookups(Lookup... lookups) {
25.122 + setLookups(null, lookups);
25.123 + }
25.124 +
25.125 + /**
25.126 + * Changes the delegates immediatelly, notifies the listeners in provided
25.127 + * executor, potentially later.
25.128 + *
25.129 + * @param lookups the new lookups to delegate to
25.130 + * @param notifyIn executor to deliver the notification to listeners or null
25.131 + * @since 7.16
25.132 + */
25.133 + protected final void setLookups(Executor notifyIn, Lookup... lookups) {
25.134 + Collection<Reference<R>> arr;
25.135 + Set<Lookup> newL;
25.136 + Set<Lookup> current;
25.137 + Lookup[] old;
25.138 +
25.139 + Map<Result,LookupListener> toRemove = new IdentityHashMap<Lookup.Result, LookupListener>();
25.140 + Map<Result,LookupListener> toAdd = new IdentityHashMap<Lookup.Result, LookupListener>();
25.141 +
25.142 + ImmutableInternalData orig;
25.143 + synchronized (ProxyLookup.this) {
25.144 + orig = getData();
25.145 + ImmutableInternalData newData = getData().setLookupsNoFire(lookups, false);
25.146 + if (newData == getData()) {
25.147 + return;
25.148 + }
25.149 + arr = setData(newData, lookups, toAdd, toRemove);
25.150 + }
25.151 +
25.152 + // better to do this later than in synchronized block
25.153 + for (Map.Entry<Result, LookupListener> e : toRemove.entrySet()) {
25.154 + e.getKey().removeLookupListener(e.getValue());
25.155 + }
25.156 + for (Map.Entry<Result, LookupListener> e : toAdd.entrySet()) {
25.157 + e.getKey().addLookupListener(e.getValue());
25.158 + }
25.159 +
25.160 +
25.161 + // this cannot be done from the synchronized block
25.162 + final ArrayList<Object> evAndListeners = new ArrayList<Object>();
25.163 + for (Reference<R> ref : arr) {
25.164 + R<?> r = ref.get();
25.165 + if (r != null) {
25.166 + r.collectFires(evAndListeners);
25.167 + }
25.168 + }
25.169 +
25.170 + class Notify implements Runnable {
25.171 + public void run() {
25.172 + Iterator it = evAndListeners.iterator();
25.173 + while (it.hasNext()) {
25.174 + LookupEvent ev = (LookupEvent)it.next();
25.175 + LookupListener l = (LookupListener)it.next();
25.176 + l.resultChanged(ev);
25.177 + }
25.178 + }
25.179 + }
25.180 + Notify n = new Notify();
25.181 + if (notifyIn == null) {
25.182 + n.run();
25.183 + } else {
25.184 + notifyIn.execute(n);
25.185 + }
25.186 + }
25.187 +
25.188 + /** Notifies subclasses that a query is about to be processed.
25.189 + * Subclasses can update its state before the actual processing
25.190 + * begins. It is allowed to call <code>setLookups</code> method
25.191 + * to change/update the set of objects the proxy delegates to.
25.192 + *
25.193 + * @param template the template of the query
25.194 + * @since 1.31
25.195 + */
25.196 + protected void beforeLookup(Template<?> template) {
25.197 + }
25.198 +
25.199 + public final <T> T lookup(Class<T> clazz) {
25.200 + beforeLookup(new Template<T>(clazz));
25.201 +
25.202 + Lookup[] tmpLkps;
25.203 + synchronized (ProxyLookup.this) {
25.204 + tmpLkps = getData().getLookups(false);
25.205 + }
25.206 +
25.207 + for (int i = 0; i < tmpLkps.length; i++) {
25.208 + T o = tmpLkps[i].lookup(clazz);
25.209 +
25.210 + if (o != null) {
25.211 + return o;
25.212 + }
25.213 + }
25.214 +
25.215 + return null;
25.216 + }
25.217 +
25.218 + @Override
25.219 + public final <T> Item<T> lookupItem(Template<T> template) {
25.220 + beforeLookup(template);
25.221 +
25.222 + Lookup[] tmpLkps;
25.223 + synchronized (ProxyLookup.this) {
25.224 + tmpLkps = getData().getLookups(false);
25.225 + }
25.226 +
25.227 + for (int i = 0; i < tmpLkps.length; i++) {
25.228 + Item<T> o = tmpLkps[i].lookupItem(template);
25.229 +
25.230 + if (o != null) {
25.231 + return o;
25.232 + }
25.233 + }
25.234 +
25.235 + return null;
25.236 + }
25.237 +
25.238 + @SuppressWarnings("unchecked")
25.239 + private static <T> R<T> convertResult(R r) {
25.240 + return (R<T>)r;
25.241 + }
25.242 +
25.243 + public final <T> Result<T> lookup(Lookup.Template<T> template) {
25.244 + synchronized (ProxyLookup.this) {
25.245 + ImmutableInternalData[] res = { null };
25.246 + R<T> newR = getData().findResult(this, res, template);
25.247 + setData(res[0], getData().getLookups(false), null, null);
25.248 + return newR;
25.249 + }
25.250 + }
25.251 +
25.252 + /** Unregisters a template from the has map.
25.253 + */
25.254 + private final void unregisterTemplate(Template<?> template) {
25.255 + synchronized (ProxyLookup.this) {
25.256 + ImmutableInternalData id = getData();
25.257 + if (id == null) {
25.258 + return;
25.259 + }
25.260 + setData(id.removeTemplate(this, template), getData().getLookups(false), null, null);
25.261 + }
25.262 + }
25.263 +
25.264 + private ImmutableInternalData getData() {
25.265 + assert Thread.holdsLock(this);
25.266 + return data;
25.267 + }
25.268 +
25.269 + private Collection<Reference<R>> setData(
25.270 + ImmutableInternalData newData, Lookup[] current,
25.271 + Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
25.272 + ) {
25.273 + assert Thread.holdsLock(ProxyLookup.this);
25.274 + assert newData != null;
25.275 +
25.276 + ImmutableInternalData previous = this.getData();
25.277 +
25.278 + if (previous == newData) {
25.279 + return Collections.emptyList();
25.280 + }
25.281 +
25.282 + if (newData.isEmpty()) {
25.283 + this.setData(newData);
25.284 + // no affected results => exit
25.285 + return Collections.emptyList();
25.286 + }
25.287 +
25.288 + Collection<Reference<R>> arr = newData.references();
25.289 +
25.290 + Set<Lookup> removed = identityHashSet(previous.getLookupsList());
25.291 + Set<Lookup> currentSet = identityHashSet(Arrays.asList(current));
25.292 + Set<Lookup> newL = identityHashSet(currentSet);
25.293 + removed.removeAll(currentSet); // current contains just those lookups that have disappeared
25.294 + newL.removeAll(previous.getLookupsList()); // really new lookups
25.295 +
25.296 + for (Reference<R> ref : arr) {
25.297 + R<?> r = ref.get();
25.298 + if (r != null) {
25.299 + r.lookupChange(newData, current, previous, newL, removed, toAdd, toRemove);
25.300 + if (this.getData() != previous) {
25.301 + // the data were changed by an re-entrant call
25.302 + // skip any other change processing, as it is not needed
25.303 + // anymore
25.304 + }
25.305 + }
25.306 + }
25.307 + for (Reference<R> ref : arr) {
25.308 + R<?> r = ref.get();
25.309 + if (r != null) {
25.310 + r.data = newData;
25.311 + }
25.312 + }
25.313 + this.setData(newData);
25.314 + return arr;
25.315 + }
25.316 +
25.317 + private void setData(ImmutableInternalData data) {
25.318 + this.data = data;
25.319 + }
25.320 +
25.321 + /** Result of a lookup request. Allows access to single object
25.322 + * that was found (not too useful) and also to all objects found
25.323 + * (more useful).
25.324 + */
25.325 + private static final class R<T> extends WaitableResult<T> {
25.326 + /** weak listener & result */
25.327 + private final WeakResult<T> weakL;
25.328 +
25.329 + /** list of listeners added */
25.330 + private javax.swing.event.EventListenerList listeners;
25.331 +
25.332 + /** collection of Objects */
25.333 + private Collection[] cache;
25.334 +
25.335 +
25.336 + /** associated lookup */
25.337 + private ImmutableInternalData data;
25.338 +
25.339 + /** Constructor.
25.340 + */
25.341 + public R(ProxyLookup proxy, Lookup.Template<T> t) {
25.342 + this.weakL = new WeakResult<T>(proxy, this, t);
25.343 + }
25.344 +
25.345 + private ProxyLookup proxy() {
25.346 + return weakL.result.proxy;
25.347 + }
25.348 +
25.349 + @SuppressWarnings("unchecked")
25.350 + private Result<T>[] newResults(int len) {
25.351 + return new Result[len];
25.352 + }
25.353 +
25.354 + @Override
25.355 + protected void finalize() {
25.356 + weakL.result.run();
25.357 + }
25.358 +
25.359 + /** initializes the results
25.360 + */
25.361 + private Result<T>[] initResults() {
25.362 + BIG_LOOP: for (;;) {
25.363 + Lookup[] myLkps;
25.364 + ImmutableInternalData current;
25.365 + synchronized (proxy()) {
25.366 + if (weakL.getResults() != null) {
25.367 + return weakL.getResults();
25.368 + }
25.369 + myLkps = data.getLookups(false);
25.370 + current = data;
25.371 + }
25.372 +
25.373 + Result<T>[] arr = newResults(myLkps.length);
25.374 +
25.375 + for (int i = 0; i < arr.length; i++) {
25.376 + arr[i] = myLkps[i].lookup(weakL.result.template);
25.377 + }
25.378 +
25.379 + synchronized (proxy()) {
25.380 + if (current != data) {
25.381 + continue;
25.382 + }
25.383 +
25.384 + Lookup[] currentLkps = data.getLookups(false);
25.385 + if (currentLkps.length != myLkps.length) {
25.386 + continue BIG_LOOP;
25.387 + }
25.388 + for (int i = 0; i < currentLkps.length; i++) {
25.389 + if (currentLkps[i] != myLkps[i]) {
25.390 + continue BIG_LOOP;
25.391 + }
25.392 + }
25.393 +
25.394 + // some other thread might compute the result mean while.
25.395 + // if not finish the computation yourself
25.396 + if (weakL.getResults() != null) {
25.397 + return weakL.getResults();
25.398 + }
25.399 +
25.400 + weakL.setResults(arr);
25.401 + }
25.402 + for (int i = 0; i < arr.length; i++) {
25.403 + arr[i].addLookupListener(weakL);
25.404 + }
25.405 + return arr;
25.406 + }
25.407 + }
25.408 +
25.409 + /** Called when there is a change in the list of proxied lookups.
25.410 + * @param added set of added lookups
25.411 + * @param remove set of removed lookups
25.412 + * @param current array of current lookups
25.413 + */
25.414 + final void lookupChange(
25.415 + ImmutableInternalData newData, Lookup[] current, ImmutableInternalData oldData,
25.416 + Set<Lookup> added, Set<Lookup> removed,
25.417 + Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
25.418 + ) {
25.419 + if (weakL.getResults() == null) {
25.420 + // not computed yet, do not need to do anything
25.421 + return;
25.422 + }
25.423 +
25.424 + Lookup[] old = oldData.getLookups(false);
25.425 +
25.426 + // map (Lookup, Lookup.Result)
25.427 + Map<Lookup,Result<T>> map = new IdentityHashMap<Lookup,Result<T>>(old.length * 2);
25.428 +
25.429 + for (int i = 0; i < old.length; i++) {
25.430 + if (removed.contains(old[i])) {
25.431 + // removed lookup
25.432 + if (toRemove != null) {
25.433 + toRemove.put(weakL.getResults()[i], weakL);
25.434 + }
25.435 + } else {
25.436 + // remember the association
25.437 + map.put(old[i], weakL.getResults()[i]);
25.438 + }
25.439 + }
25.440 +
25.441 + Lookup.Result<T>[] arr = newResults(current.length);
25.442 +
25.443 + for (int i = 0; i < current.length; i++) {
25.444 + if (added.contains(current[i])) {
25.445 + // new lookup
25.446 + arr[i] = current[i].lookup(weakL.result.template);
25.447 + if (toAdd != null) {
25.448 + toAdd.put(arr[i], weakL);
25.449 + }
25.450 + } else {
25.451 + // old lookup
25.452 + arr[i] = map.get(current[i]);
25.453 +
25.454 + if (arr[i] == null) {
25.455 + // assert
25.456 + throw new IllegalStateException();
25.457 + }
25.458 + }
25.459 + }
25.460 +
25.461 + // remember the new results
25.462 + weakL.setResults(arr);
25.463 + }
25.464 +
25.465 + /** Just delegates.
25.466 + */
25.467 + public void addLookupListener(LookupListener l) {
25.468 + synchronized (proxy()) {
25.469 + if (listeners == null) {
25.470 + listeners = new EventListenerList();
25.471 + }
25.472 + }
25.473 +
25.474 + listeners.add(LookupListener.class, l);
25.475 + initResults();
25.476 + }
25.477 +
25.478 + /** Just delegates.
25.479 + */
25.480 + public void removeLookupListener(LookupListener l) {
25.481 + if (listeners != null) {
25.482 + listeners.remove(LookupListener.class, l);
25.483 + }
25.484 + }
25.485 +
25.486 + /** Access to all instances in the result.
25.487 + * @return collection of all instances
25.488 + */
25.489 + @SuppressWarnings("unchecked")
25.490 + public java.util.Collection<T> allInstances() {
25.491 + return computeResult(0);
25.492 + }
25.493 +
25.494 + /** Classes of all results. Set of the most concreate classes
25.495 + * that are registered in the system.
25.496 + * @return set of Class objects
25.497 + */
25.498 + @SuppressWarnings("unchecked")
25.499 + @Override
25.500 + public java.util.Set<Class<? extends T>> allClasses() {
25.501 + return (java.util.Set<Class<? extends T>>) computeResult(1);
25.502 + }
25.503 +
25.504 + /** All registered items. The collection of all pairs of
25.505 + * ii and their classes.
25.506 + * @return collection of Lookup.Item
25.507 + */
25.508 + @SuppressWarnings("unchecked")
25.509 + @Override
25.510 + public java.util.Collection<? extends Item<T>> allItems() {
25.511 + return computeResult(2);
25.512 + }
25.513 +
25.514 + /** Computes results from proxied lookups.
25.515 + * @param indexToCache 0 = allInstances, 1 = allClasses, 2 = allItems
25.516 + * @return the collection or set of the objects
25.517 + */
25.518 + private java.util.Collection computeResult(int indexToCache) {
25.519 + // results to use
25.520 + Lookup.Result<T>[] arr = myBeforeLookup();
25.521 +
25.522 + // if the call to beforeLookup resulted in deletion of caches
25.523 + synchronized (proxy()) {
25.524 + Collection[] cc = getCache();
25.525 + if (cc != null && cc != NO_CACHE) {
25.526 + Collection result = cc[indexToCache];
25.527 + if (result != null) {
25.528 + return result;
25.529 + }
25.530 + }
25.531 + }
25.532 +
25.533 + // initialize the collection to hold result
25.534 + Collection<Object> compute;
25.535 + Collection<Object> ret;
25.536 +
25.537 + if (indexToCache == 1) {
25.538 + HashSet<Object> s = new HashSet<Object>();
25.539 + compute = s;
25.540 + ret = Collections.unmodifiableSet(s);
25.541 + } else {
25.542 + List<Object> l = new ArrayList<Object>(arr.length * 2);
25.543 + compute = l;
25.544 + ret = Collections.unmodifiableList(l);
25.545 + }
25.546 +
25.547 + // fill the collection
25.548 + for (int i = 0; i < arr.length; i++) {
25.549 + switch (indexToCache) {
25.550 + case 0:
25.551 + compute.addAll(arr[i].allInstances());
25.552 + break;
25.553 + case 1:
25.554 + compute.addAll(arr[i].allClasses());
25.555 + break;
25.556 + case 2:
25.557 + compute.addAll(arr[i].allItems());
25.558 + break;
25.559 + default:
25.560 + assert false : "Wrong index: " + indexToCache;
25.561 + }
25.562 + }
25.563 +
25.564 +
25.565 +
25.566 + synchronized (proxy()) {
25.567 + Collection[] cc = getCache();
25.568 + if (cc == null || cc == NO_CACHE) {
25.569 + // initialize the cache to indicate this result is in use
25.570 + setCache(cc = new Collection[3]);
25.571 + }
25.572 +
25.573 + if (arr == weakL.getResults()) {
25.574 + // updates the results, if the results have not been
25.575 + // changed during the computation of allInstances
25.576 + cc[indexToCache] = ret;
25.577 + }
25.578 + }
25.579 +
25.580 + return ret;
25.581 + }
25.582 +
25.583 + /** When the result changes, fire the event.
25.584 + */
25.585 + public void resultChanged(LookupEvent ev) {
25.586 + collectFires(null);
25.587 + }
25.588 +
25.589 + protected void collectFires(Collection<Object> evAndListeners) {
25.590 + boolean modified = true;
25.591 +
25.592 + try {
25.593 + // clear cached instances
25.594 + Collection oldItems;
25.595 + Collection oldInstances;
25.596 + synchronized (proxy()) {
25.597 + final Collection[] cc = getCache();
25.598 + if (cc == NO_CACHE) {
25.599 + return;
25.600 + }
25.601 +
25.602 + oldInstances = cc == null ? null : cc[0];
25.603 + oldItems = cc == null ? null : cc[2];
25.604 +
25.605 +
25.606 + if (listeners == null || listeners.getListenerCount() == 0) {
25.607 + // clear the cache
25.608 + setCache(new Collection[3]);
25.609 + return;
25.610 + }
25.611 +
25.612 + // ignore events if they arrive as a result of call to allItems
25.613 + // or allInstances, bellow...
25.614 + setCache(NO_CACHE);
25.615 + }
25.616 +
25.617 + if (oldItems != null) {
25.618 + Collection newItems = allItems();
25.619 + if (oldItems.equals(newItems)) {
25.620 + modified = false;
25.621 + }
25.622 + } else {
25.623 + if (oldInstances != null) {
25.624 + Collection newInstances = allInstances();
25.625 + if (oldInstances.equals(newInstances)) {
25.626 + modified = false;
25.627 + }
25.628 + } else {
25.629 + synchronized (proxy()) {
25.630 + if (getCache() == NO_CACHE) {
25.631 + // we have to initialize the cache
25.632 + // to show that the result has been initialized
25.633 + setCache(new Collection[3]);
25.634 + }
25.635 + }
25.636 + }
25.637 + }
25.638 + } finally {
25.639 + synchronized (proxy()) {
25.640 + if (getCache() == NO_CACHE) {
25.641 + setCache(null);
25.642 + }
25.643 + }
25.644 + }
25.645 +
25.646 + if (modified) {
25.647 + LookupEvent ev = new LookupEvent(this);
25.648 + AbstractLookup.notifyListeners(listeners.getListenerList(), ev, evAndListeners);
25.649 + }
25.650 + }
25.651 +
25.652 + /** Implementation of my before lookup.
25.653 + * @return results to work on.
25.654 + */
25.655 + private Lookup.Result<T>[] myBeforeLookup() {
25.656 + Template<T> template = weakL.result.template;
25.657 +
25.658 + proxy().beforeLookup(template);
25.659 +
25.660 + Lookup.Result<T>[] arr = initResults();
25.661 +
25.662 + // invoke update on the results
25.663 + for (int i = 0; i < arr.length; i++) {
25.664 + if (arr[i] instanceof WaitableResult) {
25.665 + WaitableResult w = (WaitableResult) arr[i];
25.666 + w.beforeLookup(template);
25.667 + }
25.668 + }
25.669 +
25.670 + return arr;
25.671 + }
25.672 +
25.673 + /** Used by proxy results to synchronize before lookup.
25.674 + */
25.675 + protected void beforeLookup(Lookup.Template t) {
25.676 + if (t.getType() == weakL.result.template.getType()) {
25.677 + myBeforeLookup();
25.678 + }
25.679 + }
25.680 +
25.681 + private Collection[] getCache() {
25.682 + return cache;
25.683 + }
25.684 +
25.685 + private void setCache(Collection[] cache) {
25.686 + assert Thread.holdsLock(proxy());
25.687 + this.cache = cache;
25.688 + }
25.689 + private static final Collection[] NO_CACHE = new Collection[0];
25.690 + }
25.691 + private static final class WeakRef<T> extends WeakReference<R> implements Runnable {
25.692 + final WeakResult<T> result;
25.693 + final ProxyLookup proxy;
25.694 + final Template<T> template;
25.695 +
25.696 + public WeakRef(R r, WeakResult<T> result, ProxyLookup proxy, Template<T> template) {
25.697 + super(r);
25.698 + this.result = result;
25.699 + this.template = template;
25.700 + this.proxy = proxy;
25.701 + }
25.702 +
25.703 + public void run() {
25.704 + result.removeListeners();
25.705 + proxy.unregisterTemplate(template);
25.706 + }
25.707 + }
25.708 +
25.709 +
25.710 + private static final class WeakResult<T> extends WaitableResult<T> implements LookupListener, Runnable {
25.711 + /** all results */
25.712 + private Lookup.Result<T>[] results;
25.713 + private final WeakRef<T> result;
25.714 +
25.715 + public WeakResult(ProxyLookup proxy, R r, Template<T> t) {
25.716 + this.result = new WeakRef<T>(r, this, proxy, t);
25.717 + }
25.718 +
25.719 + final void removeListeners() {
25.720 + Lookup.Result<T>[] arr = this.getResults();
25.721 + if (arr == null) {
25.722 + return;
25.723 + }
25.724 +
25.725 + for(int i = 0; i < arr.length; i++) {
25.726 + arr[i].removeLookupListener(this);
25.727 + }
25.728 + }
25.729 +
25.730 + protected void beforeLookup(Lookup.Template t) {
25.731 + R r = result.get();
25.732 + if (r != null) {
25.733 + r.beforeLookup(t);
25.734 + } else {
25.735 + removeListeners();
25.736 + }
25.737 + }
25.738 +
25.739 + protected void collectFires(Collection<Object> evAndListeners) {
25.740 + R<?> r = result.get();
25.741 + if (r != null) {
25.742 + r.collectFires(evAndListeners);
25.743 + } else {
25.744 + removeListeners();
25.745 + }
25.746 + }
25.747 +
25.748 + public void addLookupListener(LookupListener l) {
25.749 + assert false;
25.750 + }
25.751 +
25.752 + public void removeLookupListener(LookupListener l) {
25.753 + assert false;
25.754 + }
25.755 +
25.756 + public Collection<T> allInstances() {
25.757 + assert false;
25.758 + return null;
25.759 + }
25.760 +
25.761 + public void resultChanged(LookupEvent ev) {
25.762 + R r = result.get();
25.763 + if (r != null) {
25.764 + r.resultChanged(ev);
25.765 + } else {
25.766 + removeListeners();
25.767 + }
25.768 + }
25.769 +
25.770 + @Override
25.771 + public Collection<? extends Item<T>> allItems() {
25.772 + assert false;
25.773 + return null;
25.774 + }
25.775 +
25.776 + @Override
25.777 + public Set<Class<? extends T>> allClasses() {
25.778 + assert false;
25.779 + return null;
25.780 + }
25.781 +
25.782 + public void run() {
25.783 + removeListeners();
25.784 + }
25.785 +
25.786 + private Lookup.Result<T>[] getResults() {
25.787 + return results;
25.788 + }
25.789 +
25.790 + private void setResults(Lookup.Result<T>[] results) {
25.791 + this.results = results;
25.792 + }
25.793 + } // end of WeakResult
25.794 +
25.795 + static abstract class ImmutableInternalData extends Object {
25.796 + static final ImmutableInternalData EMPTY = new EmptyInternalData();
25.797 + static final Lookup[] EMPTY_ARR = new Lookup[0];
25.798 +
25.799 +
25.800 + protected ImmutableInternalData() {
25.801 + }
25.802 +
25.803 + public static ImmutableInternalData create(Object lkp, Map<Template, Reference<R>> results) {
25.804 + if (results.size() == 0 && lkp == EMPTY_ARR) {
25.805 + return EMPTY;
25.806 + }
25.807 + if (results.size() == 1) {
25.808 + Entry<Template,Reference<R>> e = results.entrySet().iterator().next();
25.809 + return new SingleInternalData(lkp, e.getKey(), e.getValue());
25.810 + }
25.811 +
25.812 + return new RealInternalData(lkp, results);
25.813 + }
25.814 +
25.815 + protected abstract boolean isEmpty();
25.816 + protected abstract Map<Template, Reference<R>> getResults();
25.817 + protected abstract Object getRawLookups();
25.818 +
25.819 + final Collection<Reference<R>> references() {
25.820 + return getResults().values();
25.821 + }
25.822 +
25.823 + final <T> ImmutableInternalData removeTemplate(ProxyLookup proxy, Template<T> template) {
25.824 + if (getResults().containsKey(template)) {
25.825 + HashMap<Template,Reference<R>> c = new HashMap<Template, Reference<ProxyLookup.R>>(getResults());
25.826 + Reference<R> ref = c.remove(template);
25.827 + if (ref != null && ref.get() != null) {
25.828 + // seems like there is a reference to a result for this template
25.829 + // thta is still alive
25.830 + return this;
25.831 + }
25.832 + return create(getRawLookups(), c);
25.833 + } else {
25.834 + return this;
25.835 + }
25.836 + }
25.837 +
25.838 + <T> R<T> findResult(ProxyLookup proxy, ImmutableInternalData[] newData, Template<T> template) {
25.839 + assert Thread.holdsLock(proxy);
25.840 +
25.841 + Map<Template,Reference<R>> map = getResults();
25.842 +
25.843 + Reference<R> ref = map.get(template);
25.844 + R r = (ref == null) ? null : ref.get();
25.845 +
25.846 + if (r != null) {
25.847 + newData[0] = this;
25.848 + return convertResult(r);
25.849 + }
25.850 +
25.851 + HashMap<Template, Reference<R>> res = new HashMap<Template, Reference<R>>(map);
25.852 + R<T> newR = new R<T>(proxy, template);
25.853 + res.put(template, new java.lang.ref.SoftReference<R>(newR));
25.854 + newR.data = newData[0] = create(getRawLookups(), res);
25.855 + return newR;
25.856 + }
25.857 + final ImmutableInternalData setLookupsNoFire(Lookup[] lookups, boolean skipCheck) {
25.858 + Object l;
25.859 +
25.860 + if (!skipCheck) {
25.861 + Lookup[] previous = getLookups(false);
25.862 + if (previous == lookups) {
25.863 + return this;
25.864 + }
25.865 +
25.866 + if (previous.length == lookups.length) {
25.867 + int same = 0;
25.868 + for (int i = 0; i < previous.length; i++) {
25.869 + if (lookups[i] != previous[i]) {
25.870 + break;
25.871 + }
25.872 + same++;
25.873 + }
25.874 + if (same == previous.length) {
25.875 + return this;
25.876 + }
25.877 + }
25.878 + }
25.879 +
25.880 + if (lookups.length == 1) {
25.881 + l = lookups[0];
25.882 + assert l != null : "Cannot assign null delegate";
25.883 + } else {
25.884 + if (lookups.length == 0) {
25.885 + l = EMPTY_ARR;
25.886 + } else {
25.887 + l = lookups.clone();
25.888 + }
25.889 + }
25.890 +
25.891 + if (isEmpty() && l == EMPTY_ARR) {
25.892 + return this;
25.893 + }
25.894 +
25.895 + return create(l, getResults());
25.896 + }
25.897 + final Lookup[] getLookups(boolean clone) {
25.898 + Object l = this.getRawLookups();
25.899 + if (l instanceof Lookup) {
25.900 + return new Lookup[] { (Lookup)l };
25.901 + } else {
25.902 + Lookup[] arr = (Lookup[])l;
25.903 + if (clone) {
25.904 + arr = arr.clone();
25.905 + }
25.906 + return arr;
25.907 + }
25.908 + }
25.909 + final List<Lookup> getLookupsList() {
25.910 + return Arrays.asList(getLookups(false));
25.911 + }
25.912 +
25.913 + } // end of ImmutableInternalData
25.914 +
25.915 + private static final class SingleInternalData extends ImmutableInternalData {
25.916 + /** lookups to delegate to (either Lookup or array of Lookups) */
25.917 + private final Object lookups;
25.918 + private final Template template;
25.919 + private final Reference<ProxyLookup.R> result;
25.920 +
25.921 + public SingleInternalData(Object lookups, Template<?> template, Reference<ProxyLookup.R> result) {
25.922 + this.lookups = lookups;
25.923 + this.template = template;
25.924 + this.result = result;
25.925 + }
25.926 +
25.927 + protected final boolean isEmpty() {
25.928 + return false;
25.929 + }
25.930 +
25.931 + protected Map<Template, Reference<R>> getResults() {
25.932 + return Collections.singletonMap(template, result);
25.933 + }
25.934 +
25.935 + protected Object getRawLookups() {
25.936 + return lookups;
25.937 + }
25.938 + }
25.939 + private static final class RealInternalData extends ImmutableInternalData {
25.940 + /** lookups to delegate to (either Lookup or array of Lookups) */
25.941 + private final Object lookups;
25.942 +
25.943 + /** map of templates to currently active results */
25.944 + private final Map<Template,Reference<R>> results;
25.945 +
25.946 + public RealInternalData(Object lookups, Map<Template, Reference<ProxyLookup.R>> results) {
25.947 + this.results = results;
25.948 + this.lookups = lookups;
25.949 + }
25.950 +
25.951 + protected final boolean isEmpty() {
25.952 + return false;
25.953 + }
25.954 +
25.955 + protected Map<Template, Reference<R>> getResults() {
25.956 + boolean strict = false;
25.957 + assert strict = true;
25.958 + return strict ? Collections.unmodifiableMap(results) : results;
25.959 + }
25.960 +
25.961 + protected Object getRawLookups() {
25.962 + return lookups;
25.963 + }
25.964 + }
25.965 +
25.966 + private static final class EmptyInternalData extends ImmutableInternalData {
25.967 + EmptyInternalData() {
25.968 + }
25.969 +
25.970 + protected final boolean isEmpty() {
25.971 + return true;
25.972 + }
25.973 +
25.974 + protected Map<Template, Reference<R>> getResults() {
25.975 + return Collections.emptyMap();
25.976 + }
25.977 +
25.978 + @Override
25.979 + protected Object getRawLookups() {
25.980 + return EMPTY_ARR;
25.981 + }
25.982 + } // end of EmptyInternalData
25.983 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ServiceProvider.java Mon Dec 14 20:58:39 2009 +0100
26.3 @@ -0,0 +1,102 @@
26.4 +/*
26.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
26.6 + *
26.7 + * Copyright 2008 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 + * If you wish your version of this file to be governed by only the CDDL
26.28 + * or only the GPL Version 2, indicate your decision by adding
26.29 + * "[Contributor] elects to include this software in this distribution
26.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
26.31 + * single choice of license, a recipient has the option to distribute
26.32 + * your version of this file under either the CDDL, the GPL Version 2 or
26.33 + * to extend the choice of license to its licensees as provided above.
26.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
26.35 + * Version 2 license, then the option applies only if the new code is
26.36 + * made subject to such option by the copyright holder.
26.37 + *
26.38 + * Contributor(s):
26.39 + *
26.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
26.41 + */
26.42 +
26.43 +package org.openide.util.lookup;
26.44 +
26.45 +import java.lang.annotation.ElementType;
26.46 +import java.lang.annotation.Retention;
26.47 +import java.lang.annotation.RetentionPolicy;
26.48 +import java.lang.annotation.Target;
26.49 +import org.openide.util.Lookup;
26.50 +
26.51 +/**
26.52 + * Declarative registration of a singleton service provider.
26.53 + * By marking an implementation class with this annotation,
26.54 + * you automatically register that implementation, normally in {@link Lookup#getDefault}.
26.55 + * The class must be public and have a public no-argument constructor.
26.56 + * <p>Example of usage:
26.57 + * <pre>
26.58 + * package my.module;
26.59 + * import org.netbeans.spi.whatever.Thing;
26.60 + * import org.openide.util.lookup.ServiceProvider;
26.61 + * @ServiceProvider(service=Thing.class)
26.62 + * public class MyThing implements Thing {...}
26.63 + * </pre>
26.64 + * <p>would result in a resource file <code>META-INF/services/org.netbeans.spi.whatever.Thing</code>
26.65 + * containing the single line of text: <code>my.module.MyThing</code>
26.66 + * @see Lookups#metaInfServices(ClassLoader)
26.67 + * @since org.openide.util 7.20
26.68 + */
26.69 +@Retention(RetentionPolicy.SOURCE)
26.70 +@Target(ElementType.TYPE)
26.71 +public @interface ServiceProvider {
26.72 +
26.73 + /**
26.74 + * The interface (or abstract class) to register this implementation under.
26.75 + * It is an error if the implementation class is not in fact assignable to the interface.
26.76 + * <p>If you need to register one class under multiple interfaces, use {@link ServiceProviders}.
26.77 + * <p>Requests to look up the specified interface should result in this implementation.
26.78 + * Requests for any other types may or may not result in this implementation even if the
26.79 + * implementation is assignable to those types.
26.80 + */
26.81 + Class<?> service();
26.82 +
26.83 + /**
26.84 + * An optional position in which to register this service relative to others.
26.85 + * Lower-numbered services are returned in the lookup result first.
26.86 + * Services with no specified position are returned last.
26.87 + */
26.88 + int position() default Integer.MAX_VALUE;
26.89 +
26.90 + /**
26.91 + * An optional list of implementations (given as fully-qualified class names) which this implementation supersedes.
26.92 + * If specified, those implementations will not be loaded even if they were registered.
26.93 + * Useful on occasion to cancel a generic implementation and replace it with a more advanced one.
26.94 + */
26.95 + String[] supersedes() default {};
26.96 +
26.97 + /**
26.98 + * An optional path to register this implementation in.
26.99 + * For example, <code>Projects/sometype/Nodes</code> could be used.
26.100 + * This style of registration would be recognized by {@link Lookups#forPath}
26.101 + * rather than {@link Lookup#getDefault}.
26.102 + */
26.103 + String path() default "";
26.104 +
26.105 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/ServiceProviders.java Mon Dec 14 20:58:39 2009 +0100
27.3 @@ -0,0 +1,60 @@
27.4 +/*
27.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
27.6 + *
27.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
27.8 + *
27.9 + * The contents of this file are subject to the terms of either the GNU
27.10 + * General Public License Version 2 only ("GPL") or the Common
27.11 + * Development and Distribution License("CDDL") (collectively, the
27.12 + * "License"). You may not use this file except in compliance with the
27.13 + * License. You can obtain a copy of the License at
27.14 + * http://www.netbeans.org/cddl-gplv2.html
27.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
27.16 + * specific language governing permissions and limitations under the
27.17 + * License. When distributing the software, include this License Header
27.18 + * Notice in each file and include the License file at
27.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
27.20 + * particular file as subject to the "Classpath" exception as provided
27.21 + * by Sun in the GPL Version 2 section of the License file that
27.22 + * accompanied this code. If applicable, add the following below the
27.23 + * License Header, with the fields enclosed by brackets [] replaced by
27.24 + * your own identifying information:
27.25 + * "Portions Copyrighted [year] [name of copyright owner]"
27.26 + *
27.27 + * If you wish your version of this file to be governed by only the CDDL
27.28 + * or only the GPL Version 2, indicate your decision by adding
27.29 + * "[Contributor] elects to include this software in this distribution
27.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
27.31 + * single choice of license, a recipient has the option to distribute
27.32 + * your version of this file under either the CDDL, the GPL Version 2 or
27.33 + * to extend the choice of license to its licensees as provided above.
27.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
27.35 + * Version 2 license, then the option applies only if the new code is
27.36 + * made subject to such option by the copyright holder.
27.37 + *
27.38 + * Contributor(s):
27.39 + *
27.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
27.41 + */
27.42 +
27.43 +package org.openide.util.lookup;
27.44 +
27.45 +import java.lang.annotation.ElementType;
27.46 +import java.lang.annotation.Retention;
27.47 +import java.lang.annotation.RetentionPolicy;
27.48 +import java.lang.annotation.Target;
27.49 +
27.50 +/**
27.51 + * Similar to {@link ServiceProvider} but permits multiple registrations of one class.
27.52 + * @since org.openide.util 7.20
27.53 + */
27.54 +@Retention(RetentionPolicy.SOURCE)
27.55 +@Target(ElementType.TYPE)
27.56 +public @interface ServiceProviders {
27.57 +
27.58 + /**
27.59 + * List of service provider registrations.
27.60 + */
27.61 + ServiceProvider[] value();
27.62 +
27.63 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/SimpleLookup.java Mon Dec 14 20:58:39 2009 +0100
28.3 @@ -0,0 +1,250 @@
28.4 +/*
28.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
28.6 + *
28.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
28.8 + *
28.9 + * The contents of this file are subject to the terms of either the GNU
28.10 + * General Public License Version 2 only ("GPL") or the Common
28.11 + * Development and Distribution License("CDDL") (collectively, the
28.12 + * "License"). You may not use this file except in compliance with the
28.13 + * License. You can obtain a copy of the License at
28.14 + * http://www.netbeans.org/cddl-gplv2.html
28.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
28.16 + * specific language governing permissions and limitations under the
28.17 + * License. When distributing the software, include this License Header
28.18 + * Notice in each file and include the License file at
28.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
28.20 + * particular file as subject to the "Classpath" exception as provided
28.21 + * by Sun in the GPL Version 2 section of the License file that
28.22 + * accompanied this code. If applicable, add the following below the
28.23 + * License Header, with the fields enclosed by brackets [] replaced by
28.24 + * your own identifying information:
28.25 + * "Portions Copyrighted [year] [name of copyright owner]"
28.26 + *
28.27 + * Contributor(s):
28.28 + *
28.29 + * The Original Software is NetBeans. The Initial Developer of the Original
28.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28.31 + * Microsystems, Inc. All Rights Reserved.
28.32 + *
28.33 + * If you wish your version of this file to be governed by only the CDDL
28.34 + * or only the GPL Version 2, indicate your decision by adding
28.35 + * "[Contributor] elects to include this software in this distribution
28.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
28.37 + * single choice of license, a recipient has the option to distribute
28.38 + * your version of this file under either the CDDL, the GPL Version 2 or
28.39 + * to extend the choice of license to its licensees as provided above.
28.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
28.41 + * Version 2 license, then the option applies only if the new code is
28.42 + * made subject to such option by the copyright holder.
28.43 + */
28.44 +package org.openide.util.lookup;
28.45 +
28.46 +import org.openide.util.Lookup;
28.47 +import org.openide.util.LookupListener;
28.48 +
28.49 +import java.util.*;
28.50 +
28.51 +
28.52 +/**
28.53 + * Simple lookup implementation. It can be used to create temporary lookups
28.54 + * that do not change over time. The result stores references to all objects
28.55 + * passed in the constructor. Those objecst are the only ones returned as
28.56 + * result.
28.57 + * @author David Strupl
28.58 + */
28.59 +class SimpleLookup extends org.openide.util.Lookup {
28.60 + /** This variable is initialized in constructor and thus null
28.61 + * value is not allowed as its value. */
28.62 + private Collection<Item<?>> allItems;
28.63 +
28.64 + /**
28.65 + * Creates new Result object with supplied instances parameter.
28.66 + * @param instances to be used to return from the lookup
28.67 + */
28.68 + SimpleLookup(Collection<Object> instances) {
28.69 + allItems = new ArrayList<Item<?>>(instances.size());
28.70 +
28.71 + for (Iterator i = instances.iterator(); i.hasNext();) {
28.72 + allItems.add(new InstanceContent.SimpleItem<Object>(i.next()));
28.73 + }
28.74 + }
28.75 +
28.76 + <T,R> SimpleLookup(Collection<T> keys, InstanceContent.Convertor<? super T,R> conv) {
28.77 + allItems = new ArrayList<Item<?>>(keys.size());
28.78 +
28.79 + for (T item : keys) {
28.80 + allItems.add(new InstanceContent.ConvertingItem<T,R>(item, conv));
28.81 + }
28.82 + }
28.83 +
28.84 + public String toString() {
28.85 + return "SimpleLookup" + lookup(new Template<Object>(Object.class)).allInstances();
28.86 + }
28.87 +
28.88 + public <T> Result<T> lookup(Template<T> template) {
28.89 + if (template == null) {
28.90 + throw new NullPointerException();
28.91 + }
28.92 +
28.93 + return new SimpleResult<T>(template);
28.94 + }
28.95 +
28.96 + public <T> T lookup(Class<T> clazz) {
28.97 + for (Iterator i = allItems.iterator(); i.hasNext();) {
28.98 + Object o = i.next();
28.99 +
28.100 + if (o instanceof AbstractLookup.Pair) {
28.101 + AbstractLookup.Pair<?> p = (AbstractLookup.Pair<?>)o;
28.102 + if (p.instanceOf(clazz)) {
28.103 + Object ret = p.getInstance();
28.104 + if (clazz.isInstance(ret)) {
28.105 + return clazz.cast(ret);
28.106 + }
28.107 + }
28.108 + }
28.109 + }
28.110 + return null;
28.111 + }
28.112 +
28.113 + /** A method that defines matching between Item and Template.
28.114 + * @param item the item to match
28.115 + * @return true if item matches the template requirements, false if not
28.116 + */
28.117 + private static boolean matches(Template<?> t, AbstractLookup.Pair<?> item) {
28.118 + if (!AbstractLookup.matches(t, item, true)) {
28.119 + return false;
28.120 + }
28.121 +
28.122 + Class<?> type = t.getType();
28.123 +
28.124 + if ((type != null) && !type.isAssignableFrom(item.getType())) {
28.125 + return false;
28.126 + }
28.127 +
28.128 + return true;
28.129 + }
28.130 +
28.131 + /**
28.132 + * Result used in SimpleLookup. It holds a reference to the collection
28.133 + * passed in constructor. As the contents of this lookup result never
28.134 + * changes the addLookupListener and removeLookupListener are empty.
28.135 + */
28.136 + private class SimpleResult<T> extends Lookup.Result<T> {
28.137 + /** can be null and is initialized lazily */
28.138 + private Set<Class<? extends T>> classes;
28.139 +
28.140 + /** can be null and is initialized lazily */
28.141 + private Collection<? extends Item<T>> items;
28.142 +
28.143 + /** Template used for this result. It is never null.*/
28.144 + private Template<T> template;
28.145 +
28.146 + /** can be null and is initialized lazily */
28.147 + private Collection<T> results;
28.148 +
28.149 + /** Just remembers the supplied argument in variable template.*/
28.150 + SimpleResult(Template<T> template) {
28.151 + this.template = template;
28.152 + }
28.153 +
28.154 + /**
28.155 + * Intentionally does nothing because the lookup does not change
28.156 + * and no notification is needed.
28.157 + */
28.158 + public void addLookupListener(LookupListener l) {
28.159 + }
28.160 +
28.161 + /**
28.162 + * Intentionally does nothing because the lookup does not change
28.163 + * and no notification is needed.
28.164 + */
28.165 + public void removeLookupListener(LookupListener l) {
28.166 + }
28.167 +
28.168 + /**
28.169 + * Lazy initializes the results collection. Uses a call to allItems
28.170 + * to obtain the instances.
28.171 + */
28.172 + public java.util.Collection<? extends T> allInstances() {
28.173 + synchronized (this) {
28.174 + if (results != null) {
28.175 + return results;
28.176 + }
28.177 + }
28.178 +
28.179 +
28.180 + Collection<T> res = new ArrayList<T>(allItems.size());
28.181 +
28.182 + for (Item<T> item : allItems()) {
28.183 + res.add(item.getInstance());
28.184 + }
28.185 +
28.186 + synchronized (this) {
28.187 + results = Collections.unmodifiableCollection(res);
28.188 + }
28.189 +
28.190 + return results;
28.191 + }
28.192 +
28.193 + /**
28.194 + * Lazy initializes variable classes. Uses a call to allItems to
28.195 + * compute the result.
28.196 + */
28.197 + public Set<Class<? extends T>> allClasses() {
28.198 + synchronized (this) {
28.199 + if (classes != null) {
28.200 + return classes;
28.201 + }
28.202 + }
28.203 +
28.204 + Set<Class<? extends T>> res = new HashSet<Class<? extends T>>();
28.205 +
28.206 + for (Item<T> item : allItems()) {
28.207 + res.add(item.getType());
28.208 + }
28.209 +
28.210 + synchronized (this) {
28.211 + classes = Collections.unmodifiableSet(res);
28.212 + }
28.213 +
28.214 + return classes;
28.215 + }
28.216 +
28.217 + /**
28.218 + * Lazy initializes variable items. Creates an item for each
28.219 + * element in the instances collection. It puts either SimpleItem
28.220 + * or ConvertingItem to the collection.
28.221 + */
28.222 + public Collection<? extends Item<T>> allItems() {
28.223 + synchronized (this) {
28.224 + if (items != null) {
28.225 + return items;
28.226 + }
28.227 + }
28.228 +
28.229 + Collection<Item<T>> res = new ArrayList<Item<T>>(allItems.size());
28.230 +
28.231 + for (Iterator<Item<?>> i = allItems.iterator(); i.hasNext();) {
28.232 + Item<?> o = i.next();
28.233 +
28.234 + if (o instanceof AbstractLookup.Pair) {
28.235 + if (matches(template, (AbstractLookup.Pair) o)) {
28.236 + res.add(cast(o));
28.237 + }
28.238 + }
28.239 + }
28.240 +
28.241 + synchronized (this) {
28.242 + items = Collections.unmodifiableCollection(res);
28.243 + }
28.244 +
28.245 + return items;
28.246 + }
28.247 +
28.248 + @SuppressWarnings("unchecked")
28.249 + private Item<T> cast(Item<?> i) {
28.250 + return (Item<T>)i;
28.251 + }
28.252 + }
28.253 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/SimpleProxyLookup.java Mon Dec 14 20:58:39 2009 +0100
29.3 @@ -0,0 +1,359 @@
29.4 +/*
29.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
29.6 + *
29.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
29.8 + *
29.9 + * The contents of this file are subject to the terms of either the GNU
29.10 + * General Public License Version 2 only ("GPL") or the Common
29.11 + * Development and Distribution License("CDDL") (collectively, the
29.12 + * "License"). You may not use this file except in compliance with the
29.13 + * License. You can obtain a copy of the License at
29.14 + * http://www.netbeans.org/cddl-gplv2.html
29.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
29.16 + * specific language governing permissions and limitations under the
29.17 + * License. When distributing the software, include this License Header
29.18 + * Notice in each file and include the License file at
29.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
29.20 + * particular file as subject to the "Classpath" exception as provided
29.21 + * by Sun in the GPL Version 2 section of the License file that
29.22 + * accompanied this code. If applicable, add the following below the
29.23 + * License Header, with the fields enclosed by brackets [] replaced by
29.24 + * your own identifying information:
29.25 + * "Portions Copyrighted [year] [name of copyright owner]"
29.26 + *
29.27 + * Contributor(s):
29.28 + *
29.29 + * The Original Software is NetBeans. The Initial Developer of the Original
29.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
29.31 + * Microsystems, Inc. All Rights Reserved.
29.32 + *
29.33 + * If you wish your version of this file to be governed by only the CDDL
29.34 + * or only the GPL Version 2, indicate your decision by adding
29.35 + * "[Contributor] elects to include this software in this distribution
29.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
29.37 + * single choice of license, a recipient has the option to distribute
29.38 + * your version of this file under either the CDDL, the GPL Version 2 or
29.39 + * to extend the choice of license to its licensees as provided above.
29.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
29.41 + * Version 2 license, then the option applies only if the new code is
29.42 + * made subject to such option by the copyright holder.
29.43 + */
29.44 +package org.openide.util.lookup;
29.45 +
29.46 +import java.lang.ref.Reference;
29.47 +import java.lang.ref.WeakReference;
29.48 +import org.openide.util.Lookup;
29.49 +import org.openide.util.LookupEvent;
29.50 +import org.openide.util.LookupListener;
29.51 +
29.52 +import java.util.*;
29.53 +
29.54 +
29.55 +/**
29.56 + * Simple proxy lookup. Keeps reference to a lookup it delegates to and
29.57 + * forwards all requests.
29.58 + *
29.59 + * @author Jaroslav Tulach
29.60 + */
29.61 +final class SimpleProxyLookup extends org.openide.util.Lookup {
29.62 + /** the provider to check for the status */
29.63 + private Provider provider;
29.64 +
29.65 + /** the lookup we currently delegate to */
29.66 + private Lookup delegate;
29.67 +
29.68 + /** map of all templates to Reference (results) associated to this lookup */
29.69 + private WeakHashMap<Template<?>,Reference<ProxyResult<?>>> results;
29.70 +
29.71 + /**
29.72 + * @param provider provider to delegate to
29.73 + */
29.74 + SimpleProxyLookup(Provider provider) {
29.75 + this.provider = provider;
29.76 + }
29.77 +
29.78 + /** Checks whether we still delegate to the same lookup */
29.79 + private Lookup checkLookup() {
29.80 + Lookup l = provider.getLookup();
29.81 +
29.82 + // iterator over Reference (ProxyResult)
29.83 + Iterator<Reference<ProxyResult<?>>> toCheck = null;
29.84 +
29.85 + synchronized (this) {
29.86 + if (l != delegate) {
29.87 + this.delegate = l;
29.88 +
29.89 + if (results != null) {
29.90 + toCheck = new ArrayList<Reference<ProxyResult<?>>>(results.values()).iterator();
29.91 + }
29.92 + }
29.93 + }
29.94 +
29.95 + if (toCheck != null) {
29.96 + // update
29.97 + ArrayList<Object> evAndListeners = new ArrayList<Object>();
29.98 + for (Iterator<Reference<ProxyResult<?>>> it = toCheck; it.hasNext(); ) {
29.99 + java.lang.ref.Reference<ProxyResult<?>> ref = it.next();
29.100 + if (ref == null) {
29.101 + continue;
29.102 + }
29.103 +
29.104 + ProxyResult<?> p = ref.get();
29.105 +
29.106 + if (p != null && p.updateLookup(l)) {
29.107 + p.collectFires(evAndListeners);
29.108 + }
29.109 + }
29.110 +
29.111 + for (Iterator it = evAndListeners.iterator(); it.hasNext(); ) {
29.112 + LookupEvent ev = (LookupEvent)it.next();
29.113 + LookupListener ll = (LookupListener)it.next();
29.114 + ll.resultChanged(ev);
29.115 + }
29.116 + }
29.117 +
29.118 + return delegate;
29.119 + }
29.120 +
29.121 + @SuppressWarnings("unchecked")
29.122 + private static <T> ProxyResult<T> cast(ProxyResult<?> p) {
29.123 + return (ProxyResult<T>)p;
29.124 + }
29.125 +
29.126 + public <T> Result<T> lookup(Template<T> template) {
29.127 + synchronized (this) {
29.128 + if (results == null) {
29.129 + results = new WeakHashMap<Template<?>,Reference<ProxyResult<?>>>();
29.130 + } else {
29.131 + Reference<ProxyResult<?>> ref = results.get(template);
29.132 +
29.133 + if (ref != null) {
29.134 + ProxyResult<?> p = ref.get();
29.135 +
29.136 + if (p != null) {
29.137 + return cast(p);
29.138 + }
29.139 + }
29.140 + }
29.141 +
29.142 + ProxyResult<T> p = new ProxyResult<T>(template);
29.143 + Reference<ProxyResult<?>> ref = new WeakReference<ProxyResult<?>>(p);
29.144 + results.put(template, ref);
29.145 +
29.146 + return p;
29.147 + }
29.148 + }
29.149 +
29.150 + public <T> T lookup(Class<T> clazz) {
29.151 + if (clazz == null) {
29.152 + checkLookup();
29.153 + return null;
29.154 + }
29.155 + return checkLookup().lookup(clazz);
29.156 + }
29.157 +
29.158 + public <T> Item<T> lookupItem(Template<T> template) {
29.159 + return checkLookup().lookupItem(template);
29.160 + }
29.161 +
29.162 + /**
29.163 + * Result used in SimpleLookup. It holds a reference to the collection
29.164 + * passed in constructor. As the contents of this lookup result never
29.165 + * changes the addLookupListener and removeLookupListener are empty.
29.166 + */
29.167 + private final class ProxyResult<T> extends WaitableResult<T> implements LookupListener {
29.168 + /** Template used for this result. It is never null.*/
29.169 + private Template<T> template;
29.170 +
29.171 + /** result to delegate to */
29.172 + private Lookup.Result<T> delegate;
29.173 +
29.174 + /** listeners set */
29.175 + private javax.swing.event.EventListenerList listeners;
29.176 + private LookupListener lastListener;
29.177 +
29.178 + /** Just remembers the supplied argument in variable template.*/
29.179 + ProxyResult(Template<T> template) {
29.180 + this.template = template;
29.181 + }
29.182 +
29.183 + /** Checks state of the result
29.184 + */
29.185 + private Result<T> checkResult() {
29.186 + updateLookup(checkLookup());
29.187 +
29.188 + return this.delegate;
29.189 + }
29.190 +
29.191 + /** Updates the state of the lookup.
29.192 + * @return true if the lookup really changed
29.193 + */
29.194 + public boolean updateLookup(Lookup l) {
29.195 + Collection<? extends Item<T>> oldPairs = (delegate != null) ? delegate.allItems() : null;
29.196 +
29.197 + LookupListener removedListener;
29.198 +
29.199 + synchronized (this) {
29.200 + if ((delegate != null) && (lastListener != null)) {
29.201 + removedListener = lastListener;
29.202 + delegate.removeLookupListener(lastListener);
29.203 + } else {
29.204 + removedListener = null;
29.205 + }
29.206 + }
29.207 +
29.208 + // cannot call to foreign code
29.209 + Lookup.Result<T> res = l.lookup(template);
29.210 +
29.211 + synchronized (this) {
29.212 + if (removedListener == lastListener) {
29.213 + delegate = res;
29.214 + lastListener = new WeakResult<T>(this, delegate);
29.215 + delegate.addLookupListener(lastListener);
29.216 + }
29.217 + }
29.218 +
29.219 + if (oldPairs == null) {
29.220 + // nobody knows about a change
29.221 + return false;
29.222 + }
29.223 +
29.224 + Collection<? extends Item<T>> newPairs = delegate.allItems();
29.225 +
29.226 + // See #34961 for explanation.
29.227 + if (!(oldPairs instanceof List)) {
29.228 + if (oldPairs == Collections.EMPTY_SET) {
29.229 + // avoid allocation
29.230 + oldPairs = Collections.emptyList();
29.231 + } else {
29.232 + oldPairs = new ArrayList<Item<T>>(oldPairs);
29.233 + }
29.234 + }
29.235 +
29.236 + if (!(newPairs instanceof List)) {
29.237 + newPairs = new ArrayList<Item<T>>(newPairs);
29.238 + }
29.239 +
29.240 + return !oldPairs.equals(newPairs);
29.241 + }
29.242 +
29.243 + public synchronized void addLookupListener(LookupListener l) {
29.244 + if (listeners == null) {
29.245 + listeners = new javax.swing.event.EventListenerList();
29.246 + }
29.247 +
29.248 + listeners.add(LookupListener.class, l);
29.249 + }
29.250 +
29.251 + public synchronized void removeLookupListener(LookupListener l) {
29.252 + if (listeners != null) {
29.253 + listeners.remove(LookupListener.class, l);
29.254 + }
29.255 + }
29.256 +
29.257 + public java.util.Collection<? extends T> allInstances() {
29.258 + return checkResult().allInstances();
29.259 + }
29.260 +
29.261 + public Set<Class<? extends T>> allClasses() {
29.262 + return checkResult().allClasses();
29.263 + }
29.264 +
29.265 + public Collection<? extends Item<T>> allItems() {
29.266 + return checkResult().allItems();
29.267 + }
29.268 +
29.269 + protected void beforeLookup(Lookup.Template t) {
29.270 + Lookup.Result r = checkResult();
29.271 +
29.272 + if (r instanceof WaitableResult) {
29.273 + ((WaitableResult) r).beforeLookup(t);
29.274 + }
29.275 + }
29.276 +
29.277 + /** A change in lookup occured.
29.278 + * @param ev event describing the change
29.279 + *
29.280 + */
29.281 + public void resultChanged(LookupEvent anEvent) {
29.282 + collectFires(null);
29.283 + }
29.284 +
29.285 + protected void collectFires(Collection<Object> evAndListeners) {
29.286 + javax.swing.event.EventListenerList l = this.listeners;
29.287 +
29.288 + if (l == null) {
29.289 + return;
29.290 + }
29.291 +
29.292 + Object[] listeners = l.getListenerList();
29.293 +
29.294 + if (listeners.length == 0) {
29.295 + return;
29.296 + }
29.297 +
29.298 + LookupEvent ev = new LookupEvent(this);
29.299 + AbstractLookup.notifyListeners(listeners, ev, evAndListeners);
29.300 + }
29.301 + }
29.302 + // end of ProxyResult
29.303 + private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
29.304 + private Lookup.Result source;
29.305 + private Reference<ProxyResult<T>> result;
29.306 +
29.307 + public WeakResult(ProxyResult<T> r, Lookup.Result<T> s) {
29.308 + this.result = new WeakReference<ProxyResult<T>>(r);
29.309 + this.source = s;
29.310 + }
29.311 +
29.312 + protected void beforeLookup(Lookup.Template t) {
29.313 + ProxyResult r = (ProxyResult)result.get();
29.314 + if (r != null) {
29.315 + r.beforeLookup(t);
29.316 + } else {
29.317 + source.removeLookupListener(this);
29.318 + }
29.319 + }
29.320 +
29.321 + protected void collectFires(Collection<Object> evAndListeners) {
29.322 + ProxyResult<T> r = result.get();
29.323 + if (r != null) {
29.324 + r.collectFires(evAndListeners);
29.325 + } else {
29.326 + source.removeLookupListener(this);
29.327 + }
29.328 + }
29.329 +
29.330 + public void addLookupListener(LookupListener l) {
29.331 + assert false;
29.332 + }
29.333 +
29.334 + public void removeLookupListener(LookupListener l) {
29.335 + assert false;
29.336 + }
29.337 +
29.338 + public Collection<T> allInstances() {
29.339 + assert false;
29.340 + return null;
29.341 + }
29.342 +
29.343 + public void resultChanged(LookupEvent ev) {
29.344 + ProxyResult r = (ProxyResult)result.get();
29.345 + if (r != null) {
29.346 + r.resultChanged(ev);
29.347 + } else {
29.348 + source.removeLookupListener(this);
29.349 + }
29.350 + }
29.351 +
29.352 + public Collection<? extends Item<T>> allItems() {
29.353 + assert false;
29.354 + return null;
29.355 + }
29.356 +
29.357 + public Set<Class<? extends T>> allClasses() {
29.358 + assert false;
29.359 + return null;
29.360 + }
29.361 + } // end of WeakResult
29.362 +}
30.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
30.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/SingletonLookup.java Mon Dec 14 20:58:39 2009 +0100
30.3 @@ -0,0 +1,173 @@
30.4 +/*
30.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
30.6 + *
30.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
30.8 + *
30.9 + * The contents of this file are subject to the terms of either the GNU
30.10 + * General Public License Version 2 only ("GPL") or the Common
30.11 + * Development and Distribution License("CDDL") (collectively, the
30.12 + * "License"). You may not use this file except in compliance with the
30.13 + * License. You can obtain a copy of the License at
30.14 + * http://www.netbeans.org/cddl-gplv2.html
30.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
30.16 + * specific language governing permissions and limitations under the
30.17 + * License. When distributing the software, include this License Header
30.18 + * Notice in each file and include the License file at
30.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
30.20 + * particular file as subject to the "Classpath" exception as provided
30.21 + * by Sun in the GPL Version 2 section of the License file that
30.22 + * accompanied this code. If applicable, add the following below the
30.23 + * License Header, with the fields enclosed by brackets [] replaced by
30.24 + * your own identifying information:
30.25 + * "Portions Copyrighted [year] [name of copyright owner]"
30.26 + *
30.27 + * If you wish your version of this file to be governed by only the CDDL
30.28 + * or only the GPL Version 2, indicate your decision by adding
30.29 + * "[Contributor] elects to include this software in this distribution
30.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
30.31 + * single choice of license, a recipient has the option to distribute
30.32 + * your version of this file under either the CDDL, the GPL Version 2 or
30.33 + * to extend the choice of license to its licensees as provided above.
30.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
30.35 + * Version 2 license, then the option applies only if the new code is
30.36 + * made subject to such option by the copyright holder.
30.37 + *
30.38 + * Contributor(s):
30.39 + *
30.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
30.41 + */
30.42 +
30.43 +package org.openide.util.lookup;
30.44 +
30.45 +import java.util.Collection;
30.46 +import java.util.Collections;
30.47 +import java.util.Set;
30.48 +import org.openide.util.Lookup;
30.49 +import org.openide.util.LookupListener;
30.50 +
30.51 +/**
30.52 + * Unmodifiable lookup that contains just one fixed object.
30.53 + *
30.54 + * @author Marian Petras
30.55 + */
30.56 +class SingletonLookup extends Lookup {
30.57 +
30.58 + private final Object objectToLookup;
30.59 + private final String id;
30.60 +
30.61 + SingletonLookup(Object objectToLookup) {
30.62 + this(objectToLookup, null);
30.63 + }
30.64 +
30.65 + SingletonLookup(Object objectToLookup, String id) {
30.66 + if (objectToLookup == null) {
30.67 + throw new IllegalArgumentException("null"); //NOI18N
30.68 + }
30.69 +
30.70 + this.objectToLookup = objectToLookup;
30.71 + this.id = id;
30.72 + }
30.73 +
30.74 + @Override
30.75 + public <T> T lookup(Class<T> clazz) {
30.76 + if (clazz == null) {
30.77 + throw new IllegalArgumentException("null"); //NOI18N
30.78 + }
30.79 +
30.80 + return (clazz.isInstance(objectToLookup))
30.81 + ? clazz.cast(objectToLookup)
30.82 + : null;
30.83 + }
30.84 +
30.85 + @Override
30.86 + public <T> Result<T> lookup(Template<T> template) {
30.87 + if (template == null) {
30.88 + throw new IllegalArgumentException("null"); //NOI18N
30.89 + }
30.90 +
30.91 + Lookup.Item<T> item = lookupItem(template);
30.92 + if (item != null) {
30.93 + return new SingletonResult<T>(item);
30.94 + } else {
30.95 + return Lookup.EMPTY.lookup(template);
30.96 + }
30.97 + }
30.98 +
30.99 + @Override
30.100 + public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
30.101 + if (clazz == null) {
30.102 + throw new IllegalArgumentException("null"); //NOI18N
30.103 + }
30.104 +
30.105 + return (clazz.isInstance(objectToLookup))
30.106 + ? Collections.singletonList(clazz.cast(objectToLookup))
30.107 + : Collections.<T>emptyList();
30.108 + }
30.109 +
30.110 + @Override
30.111 + @SuppressWarnings("unchecked")
30.112 + public <T> Item<T> lookupItem(Template<T> template) {
30.113 + if (template == null) {
30.114 + throw new IllegalArgumentException("null"); //NOI18N
30.115 + }
30.116 +
30.117 + String templateId = template.getId();
30.118 + if ((templateId != null) && !templateId.equals(id)) {
30.119 + return null;
30.120 + }
30.121 +
30.122 + Object templateInst = template.getInstance();
30.123 + if ((templateInst != null) && (objectToLookup != templateInst)) {
30.124 + return null;
30.125 + }
30.126 +
30.127 + Class<T> clazz = template.getType();
30.128 + if ((clazz != null) && !clazz.isInstance(objectToLookup)) {
30.129 + return null;
30.130 + }
30.131 +
30.132 + Lookup.Item<T> item;
30.133 + if (clazz != null) {
30.134 + item = Lookups.lookupItem(clazz.cast(objectToLookup), id);
30.135 + } else {
30.136 + item = Lookups.lookupItem((T) objectToLookup, id);
30.137 + }
30.138 + return item;
30.139 + }
30.140 +
30.141 + static class SingletonResult<T> extends Lookup.Result<T> {
30.142 +
30.143 + private final Lookup.Item<T> item;
30.144 +
30.145 + SingletonResult(Lookup.Item<T> item) {
30.146 + this.item = item;
30.147 + }
30.148 +
30.149 + @Override
30.150 + public void addLookupListener(LookupListener l) {
30.151 + // this result never changes - no need to register a listener
30.152 + }
30.153 +
30.154 + @Override
30.155 + public void removeLookupListener(LookupListener l) {
30.156 + // this result never changes - no need to register a listener
30.157 + }
30.158 +
30.159 + @Override
30.160 + public Set<Class<? extends T>> allClasses() {
30.161 + return Collections.<Class<? extends T>>singleton(item.getType());
30.162 + }
30.163 +
30.164 + @Override
30.165 + public Collection<? extends Item<T>> allItems() {
30.166 + return Collections.singletonList(item);
30.167 + }
30.168 +
30.169 + @Override
30.170 + public Collection<? extends T> allInstances() {
30.171 + return Collections.singletonList(item.getInstance());
30.172 + }
30.173 +
30.174 + }
30.175 +
30.176 +}
31.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
31.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/WaitableResult.java Mon Dec 14 20:58:39 2009 +0100
31.3 @@ -0,0 +1,62 @@
31.4 +/*
31.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
31.6 + *
31.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
31.8 + *
31.9 + * The contents of this file are subject to the terms of either the GNU
31.10 + * General Public License Version 2 only ("GPL") or the Common
31.11 + * Development and Distribution License("CDDL") (collectively, the
31.12 + * "License"). You may not use this file except in compliance with the
31.13 + * License. You can obtain a copy of the License at
31.14 + * http://www.netbeans.org/cddl-gplv2.html
31.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
31.16 + * specific language governing permissions and limitations under the
31.17 + * License. When distributing the software, include this License Header
31.18 + * Notice in each file and include the License file at
31.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
31.20 + * particular file as subject to the "Classpath" exception as provided
31.21 + * by Sun in the GPL Version 2 section of the License file that
31.22 + * accompanied this code. If applicable, add the following below the
31.23 + * License Header, with the fields enclosed by brackets [] replaced by
31.24 + * your own identifying information:
31.25 + * "Portions Copyrighted [year] [name of copyright owner]"
31.26 + *
31.27 + * Contributor(s):
31.28 + *
31.29 + * The Original Software is NetBeans. The Initial Developer of the Original
31.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
31.31 + * Microsystems, Inc. All Rights Reserved.
31.32 + *
31.33 + * If you wish your version of this file to be governed by only the CDDL
31.34 + * or only the GPL Version 2, indicate your decision by adding
31.35 + * "[Contributor] elects to include this software in this distribution
31.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
31.37 + * single choice of license, a recipient has the option to distribute
31.38 + * your version of this file under either the CDDL, the GPL Version 2 or
31.39 + * to extend the choice of license to its licensees as provided above.
31.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
31.41 + * Version 2 license, then the option applies only if the new code is
31.42 + * made subject to such option by the copyright holder.
31.43 + */
31.44 +package org.openide.util.lookup;
31.45 +
31.46 +import java.util.Collection;
31.47 +import org.openide.util.Lookup;
31.48 +
31.49 +
31.50 +/** A special subclass of lookup that is able to wait before queries.
31.51 + *
31.52 + * @author Jaroslav Tulach
31.53 + */
31.54 +abstract class WaitableResult<T> extends Lookup.Result<T> {
31.55 + /** Used by proxy results to synchronize before lookup.
31.56 + */
31.57 + protected abstract void beforeLookup(Lookup.Template t);
31.58 +
31.59 + /** Needed to group notification of outside the package listeners
31.60 + * after all AbstractLookup and ProxyLookups have been updated.
31.61 + * @param evAndListeners LookupEvent, LookupListener, LookupEvent, LookupListener, etc.
31.62 + */
31.63 + protected abstract void collectFires(Collection<Object> evAndListeners);
31.64 +
31.65 +}
32.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
32.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/doc-files/index.html Mon Dec 14 20:58:39 2009 +0100
32.3 @@ -0,0 +1,208 @@
32.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
32.5 +<!--
32.6 + - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
32.7 + -
32.8 + - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
32.9 + -
32.10 + - The contents of this file are subject to the terms of either the GNU
32.11 + - General Public License Version 2 only ("GPL") or the Common
32.12 + - Development and Distribution License("CDDL") (collectively, the
32.13 + - "License"). You may not use this file except in compliance with the
32.14 + - License. You can obtain a copy of the License at
32.15 + - http://www.netbeans.org/cddl-gplv2.html
32.16 + - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
32.17 + - specific language governing permissions and limitations under the
32.18 + - License. When distributing the software, include this License Header
32.19 + - Notice in each file and include the License file at
32.20 + - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
32.21 + - particular file as subject to the "Classpath" exception as provided
32.22 + - by Sun in the GPL Version 2 section of the License file that
32.23 + - accompanied this code. If applicable, add the following below the
32.24 + - License Header, with the fields enclosed by brackets [] replaced by
32.25 + - your own identifying information:
32.26 + - "Portions Copyrighted [year] [name of copyright owner]"
32.27 + -
32.28 + - Contributor(s):
32.29 + -
32.30 + - The Original Software is NetBeans. The Initial Developer of the Original
32.31 + - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
32.32 + - Microsystems, Inc. All Rights Reserved.
32.33 + -
32.34 + - If you wish your version of this file to be governed by only the CDDL
32.35 + - or only the GPL Version 2, indicate your decision by adding
32.36 + - "[Contributor] elects to include this software in this distribution
32.37 + - under the [CDDL or GPL Version 2] license." If you do not indicate a
32.38 + - single choice of license, a recipient has the option to distribute
32.39 + - your version of this file under either the CDDL, the GPL Version 2 or
32.40 + - to extend the choice of license to its licensees as provided above.
32.41 + - However, if you add GPL Version 2 code and therefore, elected the GPL
32.42 + - Version 2 license, then the option applies only if the new code is
32.43 + - made subject to such option by the copyright holder.
32.44 + -->
32.45 +<HTML>
32.46 +<HEAD>
32.47 +<TITLE>Lookup Library</TITLE>
32.48 +<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
32.49 +</HEAD>
32.50 +<BODY>
32.51 +
32.52 +<P>
32.53 +
32.54 +This is the home page of the <em>lookup library</em> implementation, which
32.55 +is intended to solve a general problem that every <cite>component-based system</CITE>
32.56 +has had to face: how different components <b>register</b> to the system
32.57 +and how other parts of the system can <b>look</b> them <b>up</B>.
32.58 +<P>
32.59 +There already are libraries trying to solve this problem, usually by querying for
32.60 +an interface and finding its appropriate implementaion. The most famous is
32.61 +<A href="http://www.jini.org/">Jini</A>, the platform for development of
32.62 +distributed network services. Our library does something similar, but tries
32.63 +to stay small and easy
32.64 +to use. The NetBeans <em>Lookup
32.65 +Library</EM>'s main focus is a modular application consisting of independent modules
32.66 +that want to communicate with each other. It does not try to solve networking or
32.67 +legacy application integration. It is simple but powerful.
32.68 +
32.69 +<H2>Why would you want to use it?</H2>
32.70 +
32.71 +A well-written modular program separates <em>development</EM>
32.72 +and <em>deployment</EM>.
32.73 +There are many situations where a component needs some functionality but
32.74 +does not actually care about the implementation. It is up to the <em>system
32.75 +adminstrator</em> that deploys (installs) the application to decide which
32.76 +implementation to use.
32.77 +<P>
32.78 +The most simple and most often used method for allowing other implementations
32.79 +to be plugged in is the <em>system property</em> pattern:
32.80 +
32.81 +<pre>
32.82 + <font class="keyword">public</font> <font class="type">Toolkit</font> <font class="function-name">getDefaultToolkit</font> () {
32.83 + java.awt.<font class="type">Toolkit</font> <font class="variable-name">t</font> = <font class="constant">null</font>;
32.84 + <font class="type">String</font> <font class="variable-name">classname</font> = System.getProperty (<font class="string">"java.awt.Toolkit"</font>);
32.85 + <font class="keyword">if</font> (classname != <font class="constant">null</font>) {
32.86 + <font class="keyword">try</font> {
32.87 + <font class="type">Class</font> <font class="variable-name">c</font> = Class.forName (classname);
32.88 + t = (java.awt.<font class="type">Toolkit</font>)c.newInstance ();
32.89 + } <font class="keyword">catch</font> (<font class="type">Exception</font> <font class="variable-name">ex</font>) {
32.90 + System.out.println (<font class="string">"Cannot initialize toolkit: "</font> + classname);
32.91 + ex.printStackTrace ();
32.92 + }
32.93 + }
32.94 + <font class="comment">// fallback </font>
32.95 + <font class="keyword">if</font> (t == <font class="constant">null</font>) {
32.96 + t = <font class="keyword">new</font> <font class="type">GenericAWTToolkit</font> ();
32.97 + }
32.98 + }
32.99 +</pre>
32.100 +
32.101 +
32.102 +The idea is simple. The <em>deployer</em> can start the Java VM with the flag
32.103 +<code>-Djava.awt.Toolkit=org.myorg.MyToolkit</code> where the <code>MyToolkit</code>
32.104 +is his class with default constructor and the code in the <code>getDefaultToolkit</CODE>
32.105 +method will instantiate the class and use it.
32.106 +<P>
32.107 +In principle this is general enough of a solution and works well, except that writing the
32.108 +code above is error prone and it also requires passing the arguments to the virtual machine.
32.109 +It would be much nicer if the registation could be done just by putting a JAR file with the <code>MyToolkit</code> class
32.110 +into the application classpath.
32.111 +<P>
32.112 +Actually this has been realized also by the JDK development team and addressed in
32.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>.
32.114 +The <code>MyToolkit</code> could be registered by adding a file
32.115 +<code>/META-INF/services/java.awt.Toolkit</code> with one line
32.116 +<code>org.myorg.MyToolkit</code> into the JAR file that contains the
32.117 +<code>MyToolkit</CODE> implementation. The code in <code>getDefaultToolkit</CODE>
32.118 +will scan all JAR files in classpath and search for that file,
32.119 +create an instance of <code>MyToolkit</code> and use it.
32.120 +The deployer can influence which toolkit will be created by
32.121 +adding the right JAR files into the classpath.
32.122 +<P>
32.123 +Of course the code to access the <code>META-INF/services/</code> files is even
32.124 +more error prone than the <em>property pattern</EM>. And this is exactly the
32.125 +place where the <em>lookup library</em> can help. It provides an implementation of
32.126 +the search algorithm with an easy interface. Just write:
32.127 +<pre>
32.128 + <font class="keyword">import</font> <font class="type">java.awt.Toolkit</font>;
32.129 + <font class="keyword">import</font> <font class="type">org.openide.util.Lookup;</font>;
32.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>);
32.131 +</PRE>
32.132 +and if the JAR with <code>MyToolkit</CODE> is in the class path, the simple call
32.133 +above will do the rest.
32.134 +<P>
32.135 +So whenever one writes an application divided into several independent modules (jar files)
32.136 +that are being developed and deployed independently, there is a need for registering
32.137 +and discovering components. First of all, a set of interfaces can be defined to enable
32.138 +inter-module communication (like the abstract class <code>java.awt.Toolkit</CODE>).
32.139 +After that a set of modules providing implementation can written (<code>MyToolkit</code> and other concurent implementations)
32.140 +and after that, whenever a module trying to utilitize the functionality wants to access
32.141 +the <code>Toolkit</code> via lookup, the real implementation is returned.
32.142 +<P>
32.143 +It is the responsibility of lookup to find a suitable implementation of the
32.144 +requested service and return an object implementing the service. This is the
32.145 +the basic functionality and while the library provides you with a little bit
32.146 +more, even this simple usage might be extremaly useful: the client code knows
32.147 +nothing about the implementation and the implementation can be switched in
32.148 +deployment time by simply replacing one implementation jar with other. There
32.149 +is no code change required.
32.150 +
32.151 +<H2> Local lookup usage </H2>
32.152 +The example in previous paragraph demostrated the usage of lookup as a global
32.153 +registry (by using the <CODE>Lookup.getDefault()</CODE> call). One can also
32.154 +consider another scenario where the lookup can help.
32.155 +<P>
32.156 +Let's switch hats to be an API designer for a while. The goal is to introduce a
32.157 +new object into the system. But you either are not sure yet what all the roles
32.158 +of the new object will be or you (more importantly) want to be able to add (or
32.159 +change) roles of the object dynamically. So why not to introduce following
32.160 +method to the object's interface:
32.161 +<pre>
32.162 +<font class="keyword">public class </FONT> <font class="type">MorphingObject</FONT> {
32.163 + <font class="keyword">public</FONT> <font class="type"><a href="@TOP@org/openide/util/Lookup.html">Lookup</A></FONT> getLookup() {
32.164 + <font class="keyword">return</FONT> <font class="variable-name">myLookup;</FONT>
32.165 + }
32.166 + ...
32.167 +}
32.168 +</pre>
32.169 +By exposing the method getLookup you can attach different functionality to the
32.170 +MorphingObject at runtime and whoever gets a reference to your object can ask it
32.171 +whether the object supports a given interface like this:
32.172 +<pre>
32.173 +<font class="type">MorphingObject</FONT> <font class="variable-name">morph</FONT> = ...
32.174 +<font class="type">AnInterface</font> <font class="variable-name">impl</font> = (<font
32.175 +class="type">AnInterface</font>)morph.getLookup().<a
32.176 +href="@TOP@org/openide/util/Lookup.html#lookup(java.lang.Class)">lookup</a>(AnInterface.<font class="keyword">class</font>);
32.177 +<font class="keyword">if</font> (impl == <font class="constant">null</font>) {
32.178 + <font class="keyword">return;</font><font class="comment">/* AnInterface not supported now! */</font>
32.179 +}
32.180 +impl.useIt();
32.181 +</PRE>
32.182 +
32.183 +<H2>Additional functionality</H2>
32.184 +The NetBeans lookup library also provides:
32.185 +<UL>
32.186 +<LI>Support for dynamically changing the lookup content.</LI>
32.187 +<LI>The ability to return multiple results.</LI>
32.188 +<LI>Notification of changes. After retrieving the result, the client can attach a
32.189 +listener and be notified when the result of the lookup is changed.</LI>
32.190 +<LI>Lazy initialization of the implementation. The implementation objects are
32.191 +initialized only after someone asks for them. Even the implementation classes
32.192 +are not loaded if they are not going to be used! </LI>
32.193 +</UL>
32.194 +
32.195 +<H2>Further information</H2>
32.196 +<UL>
32.197 + <LI><A HREF="lookup-api.html">Lookup Library APIs</A> for those writing the client code.
32.198 +Specifying the query, getting the result and listenning on changes.</LI>
32.199 + <LI><A HREF="lookup-spi.html">Lookup Library SPIs</A> for those writing the
32.200 +implementaion code and registering it with lookup. Includes also writing own
32.201 +lookup implementation.</LI>
32.202 + <LI>Download <A HREF="http://www.netbeans.org/">NetBeans platform</A> which
32.203 +contains <code>org-openide-util.jar</code></LI>
32.204 + <A HREF="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/lookup/">
32.205 + implementation package (org.openide.util.lookup) </A>
32.206 + + classes Lookup, LookupEvent, LookupListener in
32.207 + <A href="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/">util package</A></LI>
32.208 + <li><a href="http://www.martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a> (Martin Fowler)</li>
32.209 +</UL>
32.210 +</BODY>
32.211 +</HTML>
33.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
33.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/doc-files/lookup-api.html Mon Dec 14 20:58:39 2009 +0100
33.3 @@ -0,0 +1,188 @@
33.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
33.5 +<!--
33.6 + - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
33.7 + -
33.8 + - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
33.9 + -
33.10 + - The contents of this file are subject to the terms of either the GNU
33.11 + - General Public License Version 2 only ("GPL") or the Common
33.12 + - Development and Distribution License("CDDL") (collectively, the
33.13 + - "License"). You may not use this file except in compliance with the
33.14 + - License. You can obtain a copy of the License at
33.15 + - http://www.netbeans.org/cddl-gplv2.html
33.16 + - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
33.17 + - specific language governing permissions and limitations under the
33.18 + - License. When distributing the software, include this License Header
33.19 + - Notice in each file and include the License file at
33.20 + - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
33.21 + - particular file as subject to the "Classpath" exception as provided
33.22 + - by Sun in the GPL Version 2 section of the License file that
33.23 + - accompanied this code. If applicable, add the following below the
33.24 + - License Header, with the fields enclosed by brackets [] replaced by
33.25 + - your own identifying information:
33.26 + - "Portions Copyrighted [year] [name of copyright owner]"
33.27 + -
33.28 + - Contributor(s):
33.29 + -
33.30 + - The Original Software is NetBeans. The Initial Developer of the Original
33.31 + - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
33.32 + - Microsystems, Inc. All Rights Reserved.
33.33 + -
33.34 + - If you wish your version of this file to be governed by only the CDDL
33.35 + - or only the GPL Version 2, indicate your decision by adding
33.36 + - "[Contributor] elects to include this software in this distribution
33.37 + - under the [CDDL or GPL Version 2] license." If you do not indicate a
33.38 + - single choice of license, a recipient has the option to distribute
33.39 + - your version of this file under either the CDDL, the GPL Version 2 or
33.40 + - to extend the choice of license to its licensees as provided above.
33.41 + - However, if you add GPL Version 2 code and therefore, elected the GPL
33.42 + - Version 2 license, then the option applies only if the new code is
33.43 + - made subject to such option by the copyright holder.
33.44 + -->
33.45 +<HTML>
33.46 +<HEAD>
33.47 +<TITLE>Lookup Library API</TITLE>
33.48 +<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
33.49 +</HEAD>
33.50 +<BODY>
33.51 +<H1>Lookup library API</H1>
33.52 +<p>
33.53 +This document describes usage of the API provided by the Lookup Library. In this
33.54 +document we assume that someone has already provided us with a lookup
33.55 +implementation (for those seeking how to write a lookup implementation please
33.56 +check <A href="lookup-spi.html">the SPI document</A>).
33.57 +
33.58 +<H2> Getting the lookup </H2>
33.59 +
33.60 +The first question you might ask is this: how can I get hold of a
33.61 +lookup instance? There are basically two ways how you can get it.
33.62 +
33.63 +<H3> Global lookup </H3>
33.64 +As you can see in the
33.65 +
33.66 +<a href="@TOP@org/openide/util/Lookup.html">Lookup</a>
33.67 +
33.68 +Javadoc there is a static method
33.69 +
33.70 +<pre><a href="@TOP@org/openide/util/Lookup.html#getDefault()">public static Lookup getDefault()</a></pre>
33.71 +
33.72 +The object returned from this method is
33.73 +a global lookup that can serve as a central place for registering services.
33.74 +The default implementation is a lookup that implements
33.75 +<a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">
33.76 +the JDK JAR services</A>
33.77 +mechanism and delegates to <samp>META-INF/services/name.of.Class</samp> files.
33.78 +<P>
33.79 +If you want to add your class to this lookup just create a file in your
33.80 +jar file under the <code>META-INF</code> directory (e.g. <samp>META-INF/services/com.my.APIClass</samp>)
33.81 +and let the file contain only one line of text
33.82 +
33.83 +<pre>com.foo.impl.ImplOfTheAPI</pre>
33.84 +
33.85 +<p>(This is more easily done using the <code>@ServiceProvider</code> annotation.)</p>
33.86 +
33.87 +The following code will return you a newly created instance of
33.88 +<code>com.foo.impl.ImplOfTheAPI</code>:
33.89 +
33.90 +<PRE>
33.91 + <font class="keyword">import</FONT> org.openide.util.Lookup;
33.92 + return Lookup.getDefault().lookup(com.my.APIClass.class);
33.93 +</PRE>
33.94 +
33.95 +<H3> Local lookup </H3>
33.96 +
33.97 +This is just a reminder that whenever you find a method called getLookup
33.98 +or similar returning a lookup instance, the provided lookup is <EM>not</EM> the
33.99 +general lookup described in the previous paragraph. Rather, it is a private lookup
33.100 +implementation that is usually bound to the object you invoked the method on.
33.101 +
33.102 +<H2> Use of Lookup.Template and Lookup.Result </H2>
33.103 +
33.104 +There are more ways how you can ask lookup besides the variant with one class
33.105 +parameter. If you want more functionality, you have to implement the interface
33.106 +Lookup.Template and pass an instance of such object to the lookup call.
33.107 +<p>
33.108 +<EM>Note:</EM> If you use Lookup.Template, the object returned from the lookup is
33.109 +<EM>not</EM> the object you are looking for but rather a result object
33.110 +(Lookup.Result). You can call methods on such a result object to get the actual
33.111 +results.
33.112 +<p>
33.113 +Let's examine following example:
33.114 +
33.115 +<pre>
33.116 + <font class="keyword">import</FONT> org.openide.util.Lookup;
33.117 +
33.118 + <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
33.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>);
33.120 + Lookup.<font class="type">Result</font> <font class="variable-name">result</font> = lookup.lookup(template);
33.121 + <font class="type">Collection</font> <font class="variable-name">c</font> = result.allInstances();
33.122 + <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = c.iterator(); i.hasNext(); ) {
33.123 + <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
33.124 + s.callMyService();
33.125 + }
33.126 +</pre>
33.127 +
33.128 +In this example the call to method lookup(...) returns immediately because the
33.129 +result object can be constructed even without real results. The first time you
33.130 +ask for the result object by calling r.allInstances(), the lookup has to supply you
33.131 +the real results and this method can block until the required data are really
33.132 +available.
33.133 +<p>
33.134 +If you are not interested in all objects as in the previous example, you can use the
33.135 +template to ask for one resulting object (wrapped in special Item instance):
33.136 +<pre>
33.137 + <font class="keyword">import</FONT> org.openide.util.Lookup;
33.138 +
33.139 + <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
33.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>);
33.141 + Lookup.<font class="type">Item</font> <font class="variable-name">item</font> = lookup.lookupItem(template);
33.142 + <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)item.getInstance();
33.143 + s.callMyService();
33.144 +</pre>
33.145 +
33.146 +Again, the Item object can construct the real instance only if you call
33.147 +getInstance. The item can be useful even without calling getInstance - you can get
33.148 +its display name or an unique id. You can use this information, for example, for
33.149 +constructing menu items without the need to instantiate (or even load!)
33.150 +the class implementing the functionality. Only when the real functionality is
33.151 +needed (e.g. the user has selected the menu item) you can call getInstance
33.152 +and call the real meat of the implementation.
33.153 +
33.154 +<H2> Listenning on lookup changes </H2>
33.155 +There is one additional piece of functionality bound to the Lookup.Result object worth
33.156 +mentioning: you can attach a listener to it and be informed about any changes in
33.157 +the lookup. This might be extremly usefull when the lookup dynamically changes
33.158 +(from other threads). The listener can keep state of your object up-to-date even
33.159 +in cases where the lookup changes asynchronously.
33.160 +<p>
33.161 +So here is some sample code using the listenner:
33.162 +
33.163 +<pre>
33.164 + <font class="keyword">import</FONT> org.openide.util.Lookup;
33.165 + <font class="keyword">import</FONT> org.openide.util.LookupListener;
33.166 + <font class="keyword">import</FONT> org.openide.util.LookupEvent;
33.167 +
33.168 + <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
33.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>);
33.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);
33.171 + result.addLookupListener(<font class="keyword">new</font> <font class="type">LookupListener</font>() {
33.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>) {
33.173 + reaction(result);
33.174 + }
33.175 + });
33.176 + reaction(result);
33.177 + }
33.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>) {
33.179 + <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = r.allInstances().iterator(); i.hasNext(); ) {
33.180 + <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
33.181 + s.callMyService();
33.182 + }
33.183 + }
33.184 +</pre>
33.185 +
33.186 +Please note that we first attach a listener and then call the reaction method.
33.187 +This ensures that we always get the newest possible state. Also you must be
33.188 +careful in the reaction method since it can be called from two different
33.189 +threads simultaneously (your code has to be prepared for this).
33.190 +</BODY>
33.191 +</HTML>
34.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
34.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/doc-files/lookup-spi.html Mon Dec 14 20:58:39 2009 +0100
34.3 @@ -0,0 +1,147 @@
34.4 +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
34.5 +<!--
34.6 + - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
34.7 + -
34.8 + - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
34.9 + -
34.10 + - The contents of this file are subject to the terms of either the GNU
34.11 + - General Public License Version 2 only ("GPL") or the Common
34.12 + - Development and Distribution License("CDDL") (collectively, the
34.13 + - "License"). You may not use this file except in compliance with the
34.14 + - License. You can obtain a copy of the License at
34.15 + - http://www.netbeans.org/cddl-gplv2.html
34.16 + - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
34.17 + - specific language governing permissions and limitations under the
34.18 + - License. When distributing the software, include this License Header
34.19 + - Notice in each file and include the License file at
34.20 + - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
34.21 + - particular file as subject to the "Classpath" exception as provided
34.22 + - by Sun in the GPL Version 2 section of the License file that
34.23 + - accompanied this code. If applicable, add the following below the
34.24 + - License Header, with the fields enclosed by brackets [] replaced by
34.25 + - your own identifying information:
34.26 + - "Portions Copyrighted [year] [name of copyright owner]"
34.27 + -
34.28 + - Contributor(s):
34.29 + -
34.30 + - The Original Software is NetBeans. The Initial Developer of the Original
34.31 + - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
34.32 + - Microsystems, Inc. All Rights Reserved.
34.33 + -
34.34 + - If you wish your version of this file to be governed by only the CDDL
34.35 + - or only the GPL Version 2, indicate your decision by adding
34.36 + - "[Contributor] elects to include this software in this distribution
34.37 + - under the [CDDL or GPL Version 2] license." If you do not indicate a
34.38 + - single choice of license, a recipient has the option to distribute
34.39 + - your version of this file under either the CDDL, the GPL Version 2 or
34.40 + - to extend the choice of license to its licensees as provided above.
34.41 + - However, if you add GPL Version 2 code and therefore, elected the GPL
34.42 + - Version 2 license, then the option applies only if the new code is
34.43 + - made subject to such option by the copyright holder.
34.44 + -->
34.45 +<HTML>
34.46 +<HEAD>
34.47 +<TITLE>Lookup Library SPI</TITLE>
34.48 +<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
34.49 +</HEAD>
34.50 +<BODY>
34.51 +<H1>Lookup library SPI</H1>
34.52 +This document describe usage of the SPI provided by the Lookup Library
34.53 +(for those seeking how to use lookup instance please
34.54 +check <A href="lookup-api.html">the API document</A>).
34.55 +<p>
34.56 +By using the SPI you can create lookups that can be used by the users of the
34.57 +Lookup API. While the Lookup API consists of a couple of classes in the package
34.58 +<em>org.openide.util.*</EM>,
34.59 +the SPI has its own package <em>org.openide.util.lookup.*</EM>.
34.60 +
34.61 +<H2> Simple lookups </H2>
34.62 +Let us start with the simplest case. You have decided that your newly created
34.63 +object will provide an API in the form of a getLookup() method. You have to
34.64 +return a functional lookup from this call. You can use static methods in class
34.65 +<a href="@TOP@org/openide/util/lookup/Lookups.html">
34.66 +<code>Lookups</code></A> to create a lookup for you. If you want only one
34.67 +object to be returned, just call
34.68 +<a href="@TOP@org/openide/util/lookup/Lookups.html#singleton(java.lang.Object)">
34.69 +<code>Lookups.singleton(x)</code></A> where x is the object to be
34.70 +returned by the lookup. Or if you want to supply more objects, use a call to the method
34.71 +<a href="@TOP@org/openide/util/lookup/Lookups.html#fixed(java.lang.Object...)">
34.72 +<code>fixed(Object []x)</CODE></A>.
34.73 +<EM> Note: </EM> The lookups returned from methods <code>singleton(...)</code> and
34.74 +<code>fixed(...)</code> do <EM>
34.75 +not </EM> support dynamic changes and attaching listeners. Their content is
34.76 +fixed from the time you call the creating method.
34.77 +
34.78 +<H2> ProxyLookup </H2>
34.79 +There can be situations where you get a lookup object from someone else and you
34.80 +want your lookup to return exactly the instances from the original lookup plus
34.81 +your own results. Here the class ProxyLookup comes into the play.
34.82 +<p>
34.83 +You simply create a new lookup like this:
34.84 +
34.85 +<pre>
34.86 + <font class="keyword">import</FONT> org.openide.util.Lookup;
34.87 + <font class="keyword">import</FONT> org.openide.util.lookup.*;
34.88 +
34.89 + <font class="type">Lookup</font> <font class="variable-name">lookup1</font> = ...;
34.90 +
34.91 + <font class="type">Lookup</font> <font class="variable-name">lookup2</font> = Lookups.singleton(MyService.<font class="keyword">class</font>);
34.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 });
34.93 +</pre>
34.94 +
34.95 +<H2> AbstractLookup </H2>
34.96 +<!-- This paragraph originally copied from
34.97 +@TOP@org/openide/doc-files/services-api.html#lookup-impl
34.98 +-->
34.99 +
34.100 +<p>The most powerful way to provide a lookup is to directly define
34.101 +what instances and items it should provide, by subclassing. For this,
34.102 +
34.103 +<a href="@TOP@org/openide/util/lookup/AbstractLookup.html"><code>AbstractLookup</code></a>
34.104 +
34.105 +is recommended as it is easiest to use.
34.106 +
34.107 +<p>The simplest way to use <code>AbstractLookup</code> is to use its
34.108 +public constructor (in which case you need not subclass it). Here you
34.109 +provide an
34.110 +
34.111 +<a href="@TOP@org/openide/util/lookup/AbstractLookup.Content.html"><code>AbstractLookup.Content</code></a>
34.112 +
34.113 +object which you have created and hold on to privately, and which
34.114 +keeps track of instances and permits them to be registered and
34.115 +deregistered. Often
34.116 +
34.117 +<a href="@TOP@org/openide/util/lookup/InstanceContent.html"><code>InstanceContent</code></a>
34.118 +
34.119 +is used as the content implementation. To add something to the lookup,
34.120 +simply use
34.121 +
34.122 +<a href="@TOP@org/openide/util/lookup/InstanceContent.html#add(java.lang.Object)"><code>add(Object)</code></a>
34.123 +
34.124 +(and <code>remove(Object)</code> for the reverse). These may be called
34.125 +at any time and will update the set of registered instances (firing
34.126 +result changes as needed).
34.127 +
34.128 +<pre>
34.129 + <font class="keyword">import</FONT> org.openide.util.lookup.*;
34.130 + <font class="type">InstanceContent</font> <font class="variable-name">ic</font> = <font class="keyword">new</font> <font class="type">InstanceContent</font> ();
34.131 + ic.add(firstObject);
34.132 + <font class="keyword">return</font> <font class="keyword">new</font> <font class="type">AbstractLookup</font> (ic);
34.133 +</pre>
34.134 +
34.135 +<p>In case it is expensive to actually compute the object in the
34.136 +lookup, but there is some cheap "key" which can easily generate it,
34.137 +you may instead register the key by passing in an
34.138 +
34.139 +<a href="@TOP@org/openide/util/lookup/InstanceContent.Convertor.html"><code>InstanceContent.Convertor</code></a>.
34.140 +
34.141 +This convertor translates the key to the real instance that the lookup
34.142 +client sees, if and when needed. For example, if you have a long list
34.143 +of class names and wish to register default instances of each class,
34.144 +you might actually register the class name as the key, and supply a
34.145 +convertor which really loads the class and instantiates it. This makes
34.146 +it easy to set up the lookup, but nothing is really loaded until
34.147 +someone asks for it.
34.148 +
34.149 +</BODY>
34.150 +</HTML>
35.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
35.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/package.html Mon Dec 14 20:58:39 2009 +0100
35.3 @@ -0,0 +1,48 @@
35.4 +<!--
35.5 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
35.6 +
35.7 +Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
35.8 +
35.9 +
35.10 +The contents of this file are subject to the terms of either the GNU
35.11 +General Public License Version 2 only ("GPL") or the Common
35.12 +Development and Distribution License("CDDL") (collectively, the
35.13 +"License"). You may not use this file except in compliance with the
35.14 +License. You can obtain a copy of the License at
35.15 +http://www.netbeans.org/cddl-gplv2.html
35.16 +or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
35.17 +specific language governing permissions and limitations under the
35.18 +License. When distributing the software, include this License Header
35.19 +Notice in each file and include the License file at
35.20 +nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
35.21 +particular file as subject to the "Classpath" exception as provided
35.22 +by Sun in the GPL Version 2 section of the License file that
35.23 +accompanied this code. If applicable, add the following below the
35.24 +License Header, with the fields enclosed by brackets [] replaced by
35.25 +your own identifying information:
35.26 +"Portions Copyrighted [year] [name of copyright owner]"
35.27 +
35.28 +Contributor(s):
35.29 +
35.30 +The Original Software is NetBeans. The Initial Developer of the Original
35.31 +Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
35.32 +Microsystems, Inc. All Rights Reserved.
35.33 +
35.34 +If you wish your version of this file to be governed by only the CDDL
35.35 +or only the GPL Version 2, indicate your decision by adding
35.36 +"[Contributor] elects to include this software in this distribution
35.37 +under the [CDDL or GPL Version 2] license." If you do not indicate a
35.38 +single choice of license, a recipient has the option to distribute
35.39 +your version of this file under either the CDDL, the GPL Version 2 or
35.40 +to extend the choice of license to its licensees as provided above.
35.41 +However, if you add GPL Version 2 code and therefore, elected the GPL
35.42 +Version 2 license, then the option applies only if the new code is
35.43 +made subject to such option by the copyright holder.
35.44 +-->
35.45 +
35.46 +<html>
35.47 +<body>
35.48 +Support classes for the Registration and {@link org.openide.util.Lookup} extension mechanism.
35.49 +Read more: <a href="doc-files/index.html">Lookup Library</a>
35.50 +</body>
35.51 +</html>
36.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
36.2 +++ b/openide.util.lookup/src/org/openide/util/package.html Mon Dec 14 20:58:39 2009 +0100
36.3 @@ -0,0 +1,50 @@
36.4 +<!--
36.5 + - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
36.6 + -
36.7 + - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
36.8 + -
36.9 + - The contents of this file are subject to the terms of either the GNU
36.10 + - General Public License Version 2 only ("GPL") or the Common
36.11 + - Development and Distribution License("CDDL") (collectively, the
36.12 + - "License"). You may not use this file except in compliance with the
36.13 + - License. You can obtain a copy of the License at
36.14 + - http://www.netbeans.org/cddl-gplv2.html
36.15 + - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
36.16 + - specific language governing permissions and limitations under the
36.17 + - License. When distributing the software, include this License Header
36.18 + - Notice in each file and include the License file at
36.19 + - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
36.20 + - particular file as subject to the "Classpath" exception as provided
36.21 + - by Sun in the GPL Version 2 section of the License file that
36.22 + - accompanied this code. If applicable, add the following below the
36.23 + - License Header, with the fields enclosed by brackets [] replaced by
36.24 + - your own identifying information:
36.25 + - "Portions Copyrighted [year] [name of copyright owner]"
36.26 + -
36.27 + - Contributor(s):
36.28 + -
36.29 + - The Original Software is NetBeans. The Initial Developer of the Original
36.30 + - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
36.31 + - Microsystems, Inc. All Rights Reserved.
36.32 + -
36.33 + - If you wish your version of this file to be governed by only the CDDL
36.34 + - or only the GPL Version 2, indicate your decision by adding
36.35 + - "[Contributor] elects to include this software in this distribution
36.36 + - under the [CDDL or GPL Version 2] license." If you do not indicate a
36.37 + - single choice of license, a recipient has the option to distribute
36.38 + - your version of this file under either the CDDL, the GPL Version 2 or
36.39 + - to extend the choice of license to its licensees as provided above.
36.40 + - However, if you add GPL Version 2 code and therefore, elected the GPL
36.41 + - Version 2 license, then the option applies only if the new code is
36.42 + - made subject to such option by the copyright holder.
36.43 + -->
36.44 +
36.45 +<html>
36.46 +<body>
36.47 +
36.48 +Client API part of the
36.49 +<a href="http://top/org/openide/util/lookup/doc-files/lookup-api.html">Lookup</a>
36.50 +interfaces.
36.51 +
36.52 +</body>
36.53 +</html>
37.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
37.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Comparator2.java Mon Dec 14 20:58:39 2009 +0100
37.3 @@ -0,0 +1,7 @@
37.4 +
37.5 +package org.bar;
37.6 +
37.7 +public class Comparator2 implements java.util.Comparator {
37.8 + public int compare(Object o1, Object o2) {return 0;}
37.9 + public boolean equals(Object obj) {return true;}
37.10 +}
38.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
38.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Comparator3.java Mon Dec 14 20:58:39 2009 +0100
38.3 @@ -0,0 +1,7 @@
38.4 +
38.5 +package org.bar;
38.6 +
38.7 +public class Comparator3 implements java.util.Comparator {
38.8 + public int compare(Object o1, Object o2) {return 0;}
38.9 + public boolean equals(Object obj) {return true;}
38.10 +}
39.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
39.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Implementation2.java Mon Dec 14 20:58:39 2009 +0100
39.3 @@ -0,0 +1,3 @@
39.4 +package org.bar;
39.5 +import org.foo.Interface;
39.6 +public class Implementation2 implements Interface {}
40.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
40.2 +++ b/openide.util.lookup/test/unit/src/org/bar/Iterator2.java Mon Dec 14 20:58:39 2009 +0100
40.3 @@ -0,0 +1,11 @@
40.4 +
40.5 +package org.bar;
40.6 +
40.7 +public class Iterator2 implements java.util.Iterator {
40.8 + public boolean hasNext() {return false;}
40.9 +
40.10 + public Object next() {return null;}
40.11 +
40.12 + public void remove() {}
40.13 +
40.14 +}
41.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
41.2 +++ b/openide.util.lookup/test/unit/src/org/foo/Interface.java Mon Dec 14 20:58:39 2009 +0100
41.3 @@ -0,0 +1,2 @@
41.4 +package org.foo;
41.5 +public interface Interface {}
42.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
42.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Comparator1.java Mon Dec 14 20:58:39 2009 +0100
42.3 @@ -0,0 +1,7 @@
42.4 +
42.5 +package org.foo.impl;
42.6 +
42.7 +public class Comparator1 implements java.util.Comparator {
42.8 + public int compare(Object o1, Object o2) {return 0;}
42.9 + public boolean equals(Object obj) {return true;}
42.10 +}
43.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
43.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Implementation1.java Mon Dec 14 20:58:39 2009 +0100
43.3 @@ -0,0 +1,3 @@
43.4 +package org.foo.impl;
43.5 +import org.foo.Interface;
43.6 +public class Implementation1 implements Interface {}
44.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
44.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Iterator1.java Mon Dec 14 20:58:39 2009 +0100
44.3 @@ -0,0 +1,11 @@
44.4 +
44.5 +package org.foo.impl;
44.6 +
44.7 +public class Iterator1 implements java.util.Iterator {
44.8 + public boolean hasNext() {return false;}
44.9 +
44.10 + public Object next() {return null;}
44.11 +
44.12 + public void remove() {}
44.13 +
44.14 +}
45.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
45.2 +++ b/openide.util.lookup/test/unit/src/org/foo/impl/Runnable1.java Mon Dec 14 20:58:39 2009 +0100
45.3 @@ -0,0 +1,6 @@
45.4 +
45.5 +package org.foo.impl;
45.6 +
45.7 +public class Runnable1 implements Runnable {
45.8 + public void run () {}
45.9 +}
46.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
46.2 +++ b/openide.util.lookup/test/unit/src/org/netbeans/modules/openide/util/ActiveQueueTest.java Mon Dec 14 20:58:39 2009 +0100
46.3 @@ -0,0 +1,132 @@
46.4 +/*
46.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
46.6 + *
46.7 + * Copyright 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 + * If you wish your version of this file to be governed by only the CDDL
46.28 + * or only the GPL Version 2, indicate your decision by adding
46.29 + * "[Contributor] elects to include this software in this distribution
46.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
46.31 + * single choice of license, a recipient has the option to distribute
46.32 + * your version of this file under either the CDDL, the GPL Version 2 or
46.33 + * to extend the choice of license to its licensees as provided above.
46.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
46.35 + * Version 2 license, then the option applies only if the new code is
46.36 + * made subject to such option by the copyright holder.
46.37 + *
46.38 + * Contributor(s):
46.39 + *
46.40 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
46.41 + */
46.42 +
46.43 +package org.netbeans.modules.openide.util;
46.44 +
46.45 +import java.lang.ref.Reference;
46.46 +import java.lang.ref.ReferenceQueue;
46.47 +import java.lang.ref.WeakReference;
46.48 +import java.net.URL;
46.49 +import java.net.URLClassLoader;
46.50 +import org.netbeans.junit.NbTestCase;
46.51 +
46.52 +/**
46.53 + *
46.54 + * @author Jaroslav Tulach <jtulach@netbeans.org>
46.55 + */
46.56 +public class ActiveQueueTest extends NbTestCase{
46.57 +
46.58 + public ActiveQueueTest(String name) {
46.59 + super(name);
46.60 + }
46.61 +
46.62 + public void testMemoryLeak() throws Exception {
46.63 + final Class<?> u1 = ActiveQueue.class;
46.64 + class L extends URLClassLoader {
46.65 + public L() {
46.66 + super(new URL[] {u1.getProtectionDomain().getCodeSource().getLocation()}, u1.getClassLoader().getParent());
46.67 + }
46.68 + @Override
46.69 + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
46.70 + if (name.equals(u1.getName()) || name.startsWith(u1.getName() + "$")) {
46.71 + Class c = findLoadedClass(name);
46.72 + if (c == null) {
46.73 + c = findClass(name);
46.74 + }
46.75 + if (resolve) {
46.76 + resolveClass(c);
46.77 + }
46.78 + return c;
46.79 + } else {
46.80 + return super.loadClass(name, resolve);
46.81 + }
46.82 + }
46.83 + }
46.84 + ClassLoader l = new L();
46.85 + Class<?> u2 = l.loadClass(u1.getName());
46.86 + assertEquals(l, u2.getClassLoader());
46.87 + Object obj = new Object();
46.88 + @SuppressWarnings("unchecked")
46.89 + ReferenceQueue<Object> q = (ReferenceQueue<Object>) u2.getMethod("queue").invoke(null);
46.90 + RunnableRef ref = new RunnableRef(obj, q);
46.91 + synchronized (ref) {
46.92 + obj = null;
46.93 + assertGC("Ref should be GC'ed as usual", ref);
46.94 + ref.wait();
46.95 + assertTrue("Run method has been executed", ref.executed);
46.96 + }
46.97 + Reference<?> r = new WeakReference<Object>(u2);
46.98 + q = null;
46.99 + u2 = null;
46.100 + l = null;
46.101 + assertGC("#86625: Utilities.class can also be collected now", r);
46.102 + }
46.103 +
46.104 +
46.105 + private static class RunnableRef extends WeakReference<Object>
46.106 + implements Runnable {
46.107 + public boolean wait;
46.108 + public boolean entered;
46.109 + public boolean executed;
46.110 +
46.111 + public RunnableRef (Object o) {
46.112 + this(o, ActiveQueue.queue());
46.113 + }
46.114 +
46.115 + public RunnableRef(Object o, ReferenceQueue<Object> q) {
46.116 + super(o, q);
46.117 + }
46.118 +
46.119 + public synchronized void run () {
46.120 + entered = true;
46.121 + if (wait) {
46.122 + // notify we are here
46.123 + notify ();
46.124 + try {
46.125 + wait ();
46.126 + } catch (InterruptedException ex) {
46.127 + }
46.128 + }
46.129 + executed = true;
46.130 +
46.131 + notifyAll ();
46.132 + }
46.133 + }
46.134 +
46.135 +}
46.136 \ No newline at end of file
47.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
47.2 +++ b/openide.util.lookup/test/unit/src/org/netbeans/modules/openide/util/ServiceProviderProcessorTest.java Mon Dec 14 20:58:39 2009 +0100
47.3 @@ -0,0 +1,180 @@
47.4 +/*
47.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
47.6 + *
47.7 + * Copyright 2008 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 + * If you wish your version of this file to be governed by only the CDDL
47.28 + * or only the GPL Version 2, indicate your decision by adding
47.29 + * "[Contributor] elects to include this software in this distribution
47.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
47.31 + * single choice of license, a recipient has the option to distribute
47.32 + * your version of this file under either the CDDL, the GPL Version 2 or
47.33 + * to extend the choice of license to its licensees as provided above.
47.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
47.35 + * Version 2 license, then the option applies only if the new code is
47.36 + * made subject to such option by the copyright holder.
47.37 + *
47.38 + * Contributor(s):
47.39 + *
47.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
47.41 + */
47.42 +
47.43 +package org.netbeans.modules.openide.util;
47.44 +
47.45 +import java.io.ByteArrayOutputStream;
47.46 +import java.io.File;
47.47 +import java.util.ArrayList;
47.48 +import java.util.Arrays;
47.49 +import java.util.Collections;
47.50 +import java.util.Comparator;
47.51 +import java.util.List;
47.52 +import org.netbeans.junit.NbTestCase;
47.53 +import org.openide.util.Lookup;
47.54 +import org.openide.util.lookup.Lookups;
47.55 +import org.openide.util.lookup.ServiceProvider;
47.56 +import org.openide.util.lookup.ServiceProviders;
47.57 +import org.openide.util.test.AnnotationProcessorTestUtils;
47.58 +
47.59 +public class ServiceProviderProcessorTest extends NbTestCase {
47.60 +
47.61 + public ServiceProviderProcessorTest(String n) {
47.62 + super(n);
47.63 + }
47.64 +
47.65 + private static List<Class<?>> classesOf(Iterable<?> objects) {
47.66 + List<Class<?>> cs = new ArrayList<Class<?>>();
47.67 + for (Object o : objects) {
47.68 + cs.add(o.getClass());
47.69 + }
47.70 + return cs;
47.71 + }
47.72 +
47.73 + private static List<Class<?>> classesOfLookup(Class<?> xface) {
47.74 + return classesOf(Lookup.getDefault().lookupAll(xface));
47.75 + }
47.76 +
47.77 + private static List<Class<?>> sortClassList(List<Class<?>> classes) {
47.78 + List<Class<?>> sorted = new ArrayList<Class<?>>(classes);
47.79 + Collections.sort(sorted, new Comparator<Class<?>>() {
47.80 + public int compare(Class<?> c1, Class<?> c2) {
47.81 + return c1.getName().compareTo(c2.getName());
47.82 + }
47.83 + });
47.84 + return sorted;
47.85 + }
47.86 +
47.87 + public void testBasicUsage() throws Exception {
47.88 + assertEquals(Collections.singletonList(Implementation.class), classesOfLookup(Interface.class));
47.89 + }
47.90 + public interface Interface {}
47.91 + @ServiceProvider(service=Interface.class)
47.92 + public static class Implementation implements Interface {}
47.93 +
47.94 + public void testPosition() throws Exception {
47.95 + assertEquals(Arrays.<Class<?>>asList(OrderedImpl3.class, OrderedImpl2.class, OrderedImpl1.class), classesOfLookup(OrderedInterface.class));
47.96 + }
47.97 + public interface OrderedInterface {}
47.98 + @ServiceProvider(service=OrderedInterface.class)
47.99 + public static class OrderedImpl1 implements OrderedInterface {}
47.100 + @ServiceProvider(service=OrderedInterface.class, position=200)
47.101 + public static class OrderedImpl2 implements OrderedInterface {}
47.102 + @ServiceProvider(service=OrderedInterface.class, position=100)
47.103 + public static class OrderedImpl3 implements OrderedInterface {}
47.104 +
47.105 + public void testPath() throws Exception {
47.106 + assertEquals(Collections.singletonList(PathImplementation.class), classesOf(Lookups.forPath("some/path").lookupAll(Interface.class)));
47.107 + }
47.108 + @ServiceProvider(service=Interface.class, path="some/path")
47.109 + public static class PathImplementation implements Interface {}
47.110 +
47.111 + public void testSupersedes() throws Exception {
47.112 + assertEquals(Arrays.<Class<?>>asList(Overrider.class, Unrelated.class), sortClassList(classesOfLookup(CancellableInterface.class)));
47.113 + }
47.114 + public interface CancellableInterface {}
47.115 + @ServiceProvider(service=CancellableInterface.class)
47.116 + public static class Overridden implements CancellableInterface {}
47.117 + @ServiceProvider(service=CancellableInterface.class, supersedes="org.netbeans.modules.openide.util.ServiceProviderProcessorTest$Overridden")
47.118 + public static class Overrider implements CancellableInterface {}
47.119 + @ServiceProvider(service=CancellableInterface.class)
47.120 + public static class Unrelated implements CancellableInterface {}
47.121 +
47.122 + public void testMultipleRegistrations() throws Exception {
47.123 + assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface1.class));
47.124 + assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface2.class));
47.125 + }
47.126 + public interface Interface1 {}
47.127 + public interface Interface2 {}
47.128 + @ServiceProviders({@ServiceProvider(service=Interface1.class), @ServiceProvider(service=Interface2.class)})
47.129 + public static class Multitasking implements Interface1, Interface2 {}
47.130 +
47.131 + public void testErrorReporting() throws Exception {
47.132 + clearWorkDir();
47.133 + File src = new File(getWorkDir(), "src");
47.134 + File dest = new File(getWorkDir(), "classes");
47.135 + String xfaceName = Interface.class.getCanonicalName();
47.136 +
47.137 + AnnotationProcessorTestUtils.makeSource(src, "p.C1",
47.138 + "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
47.139 + "public class C1 implements " + xfaceName + " {}");
47.140 + ByteArrayOutputStream baos = new ByteArrayOutputStream();
47.141 + assertTrue(AnnotationProcessorTestUtils.runJavac(src, "C1", dest, null, baos));
47.142 +
47.143 + AnnotationProcessorTestUtils.makeSource(src, "p.C2",
47.144 + "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
47.145 + "class C2 implements " + xfaceName + " {}");
47.146 + baos = new ByteArrayOutputStream();
47.147 + assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C2", dest, null, baos));
47.148 + assertTrue(baos.toString(), baos.toString().contains("public"));
47.149 +
47.150 + AnnotationProcessorTestUtils.makeSource(src, "p.C3",
47.151 + "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
47.152 + "public class C3 implements " + xfaceName + " {",
47.153 + "public C3(boolean x) {}",
47.154 + "}");
47.155 + baos = new ByteArrayOutputStream();
47.156 + assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C3", dest, null, baos));
47.157 + assertTrue(baos.toString(), baos.toString().contains("constructor"));
47.158 +
47.159 + AnnotationProcessorTestUtils.makeSource(src, "p.C4",
47.160 + "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
47.161 + "public class C4 implements " + xfaceName + " {",
47.162 + "C4() {}",
47.163 + "}");
47.164 + baos = new ByteArrayOutputStream();
47.165 + assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C4", dest, null, baos));
47.166 + assertTrue(baos.toString(), baos.toString().contains("constructor"));
47.167 +
47.168 + AnnotationProcessorTestUtils.makeSource(src, "p.C5",
47.169 + "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
47.170 + "public abstract class C5 implements " + xfaceName + " {}");
47.171 + baos = new ByteArrayOutputStream();
47.172 + assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C5", dest, null, baos));
47.173 + assertTrue(baos.toString(), baos.toString().contains("abstract"));
47.174 +
47.175 + AnnotationProcessorTestUtils.makeSource(src, "p.C6",
47.176 + "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
47.177 + "public class C6 {}");
47.178 + baos = new ByteArrayOutputStream();
47.179 + assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C6", dest, null, baos));
47.180 + assertTrue(baos.toString(), baos.toString().contains("assignable"));
47.181 + }
47.182 +
47.183 +}
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/AbstractLookupArrayStorageTest.java Mon Dec 14 20:58:39 2009 +0100
48.3 @@ -0,0 +1,120 @@
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 junit.framework.*;
48.48 +import org.netbeans.junit.*;
48.49 +import org.openide.util.Lookup;
48.50 +
48.51 +public class AbstractLookupArrayStorageTest extends AbstractLookupBaseHid {
48.52 + public AbstractLookupArrayStorageTest(java.lang.String testName) {
48.53 + super(testName, null);
48.54 + }
48.55 +
48.56 + public static TestSuite suite () {
48.57 + NbTestSuite suite = new NbTestSuite ();
48.58 + suite.addTest (new PL (2));
48.59 + suite.addTest (new AL (1));
48.60 + suite.addTest (new AL (-1));
48.61 + suite.addTest (new PL (-1));
48.62 + suite.addTest (new AL (5));
48.63 + suite.addTest (new PL (3));
48.64 + suite.addTest (new AL (2000));
48.65 + suite.addTest (new PL (2000));
48.66 + return suite;
48.67 + }
48.68 +
48.69 + static final class AL extends ArrayTestSuite {
48.70 + public AL (int trash) {
48.71 + super (trash);
48.72 + }
48.73 +
48.74 + public Lookup createLookup (Lookup lookup) {
48.75 + return lookup;
48.76 + }
48.77 +
48.78 + public void clearCaches () {
48.79 + }
48.80 +
48.81 + }
48.82 +
48.83 + static final class PL extends ArrayTestSuite {
48.84 + public PL (int trash) {
48.85 + super (trash);
48.86 + }
48.87 +
48.88 + public Lookup createLookup (Lookup lookup) {
48.89 + return new ProxyLookup (new Lookup[] { lookup });
48.90 + }
48.91 +
48.92 + public void clearCaches () {
48.93 + }
48.94 +
48.95 + }
48.96 +
48.97 + private static abstract class ArrayTestSuite extends NbTestSuite
48.98 + implements AbstractLookupBaseHid.Impl {
48.99 + private int trash;
48.100 +
48.101 + public ArrayTestSuite (int trash) {
48.102 + super (AbstractLookupArrayStorageTest.class);
48.103 + this.trash = trash;
48.104 +
48.105 + int cnt = this.countTestCases();
48.106 + for (int i = 0; i < cnt; i++) {
48.107 + Object o = this.testAt (i);
48.108 + AbstractLookupBaseHid t = (AbstractLookupBaseHid)o;
48.109 + t.impl = this;
48.110 + }
48.111 + }
48.112 +
48.113 + public Lookup createInstancesLookup (InstanceContent ic) {
48.114 + if (trash == -1) {
48.115 + return new AbstractLookup (ic, new ArrayStorage ());
48.116 + } else {
48.117 + return new AbstractLookup (ic, new ArrayStorage (new Integer (trash)));
48.118 + }
48.119 + }
48.120 +
48.121 +
48.122 + }
48.123 +}
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/AbstractLookupAsynchExecutorTest.java Mon Dec 14 20:58:39 2009 +0100
49.3 @@ -0,0 +1,108 @@
49.4 +/*
49.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
49.6 + *
49.7 + * Copyright 1997-2009 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 + * Contributor(s):
49.28 + *
49.29 + * The Original Software is NetBeans. The Initial Developer of the Original
49.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
49.31 + * Microsystems, Inc. All Rights Reserved.
49.32 + *
49.33 + * If you wish your version of this file to be governed by only the CDDL
49.34 + * or only the GPL Version 2, indicate your decision by adding
49.35 + * "[Contributor] elects to include this software in this distribution
49.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
49.37 + * single choice of license, a recipient has the option to distribute
49.38 + * your version of this file under either the CDDL, the GPL Version 2 or
49.39 + * to extend the choice of license to its licensees as provided above.
49.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
49.41 + * Version 2 license, then the option applies only if the new code is
49.42 + * made subject to such option by the copyright holder.
49.43 + */
49.44 +
49.45 +package org.openide.util.lookup;
49.46 +
49.47 +import java.util.ArrayList;
49.48 +import java.util.List;
49.49 +import java.util.concurrent.Executor;
49.50 +import org.netbeans.junit.NbTestCase;
49.51 +import org.openide.util.Lookup;
49.52 +import org.openide.util.LookupEvent;
49.53 +import org.openide.util.LookupListener;
49.54 +
49.55 +public class AbstractLookupAsynchExecutorTest extends NbTestCase implements Executor {
49.56 + private List<Runnable> toRun = new ArrayList<Runnable>();
49.57 +
49.58 +
49.59 + public AbstractLookupAsynchExecutorTest(java.lang.String testName) {
49.60 + super(testName);
49.61 + }
49.62 +
49.63 + public void testCanProxyLookupHaveWrongResults() {
49.64 + final InstanceContent ic = new InstanceContent(this);
49.65 + final AbstractLookup lookup = new AbstractLookup(ic);
49.66 +
49.67 + class L implements LookupListener {
49.68 + ProxyLookup pl;
49.69 + Lookup.Result<String> original;
49.70 + Lookup.Result<String> wrapped;
49.71 + boolean ok;
49.72 +
49.73 + public void test() {
49.74 + pl = new ProxyLookup(lookup);
49.75 + original = lookup.lookupResult(String.class);
49.76 +
49.77 + original.addLookupListener(this);
49.78 +
49.79 + wrapped = pl.lookupResult(String.class);
49.80 +
49.81 + assertEquals("Original empty", 0, original.allInstances().size());
49.82 + assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
49.83 +
49.84 + ic.add("Hello!");
49.85 + }
49.86 +
49.87 + public void resultChanged(LookupEvent ev) {
49.88 + ok = true;
49.89 + assertContainsHello();
49.90 + }
49.91 +
49.92 + public void assertContainsHello() {
49.93 + assertEquals("Original has hello", 1, original.allInstances().size());
49.94 + assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
49.95 + }
49.96 +
49.97 + }
49.98 + L listener = new L();
49.99 + listener.test();
49.100 + listener.assertContainsHello();
49.101 + for (Runnable r : toRun) {
49.102 + r.run();
49.103 + }
49.104 + assertTrue("Listener called", listener.ok);
49.105 + }
49.106 +
49.107 + public void execute(Runnable command) {
49.108 + toRun.add(command);
49.109 + }
49.110 +
49.111 +}
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/AbstractLookupBaseHid.java Mon Dec 14 20:58:39 2009 +0100
50.3 @@ -0,0 +1,2088 @@
50.4 +/*
50.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
50.6 + *
50.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
50.8 + *
50.9 + * The contents of this file are subject to the terms of either the GNU
50.10 + * General Public License Version 2 only ("GPL") or the Common
50.11 + * Development and Distribution License("CDDL") (collectively, the
50.12 + * "License"). You may not use this file except in compliance with the
50.13 + * License. You can obtain a copy of the License at
50.14 + * http://www.netbeans.org/cddl-gplv2.html
50.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
50.16 + * specific language governing permissions and limitations under the
50.17 + * License. When distributing the software, include this License Header
50.18 + * Notice in each file and include the License file at
50.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
50.20 + * particular file as subject to the "Classpath" exception as provided
50.21 + * by Sun in the GPL Version 2 section of the License file that
50.22 + * accompanied this code. If applicable, add the following below the
50.23 + * License Header, with the fields enclosed by brackets [] replaced by
50.24 + * your own identifying information:
50.25 + * "Portions Copyrighted [year] [name of copyright owner]"
50.26 + *
50.27 + * Contributor(s):
50.28 + *
50.29 + * The Original Software is NetBeans. The Initial Developer of the Original
50.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
50.31 + * Microsystems, Inc. All Rights Reserved.
50.32 + *
50.33 + * If you wish your version of this file to be governed by only the CDDL
50.34 + * or only the GPL Version 2, indicate your decision by adding
50.35 + * "[Contributor] elects to include this software in this distribution
50.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
50.37 + * single choice of license, a recipient has the option to distribute
50.38 + * your version of this file under either the CDDL, the GPL Version 2 or
50.39 + * to extend the choice of license to its licensees as provided above.
50.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
50.41 + * Version 2 license, then the option applies only if the new code is
50.42 + * made subject to such option by the copyright holder.
50.43 + */
50.44 +
50.45 +package org.openide.util.lookup;
50.46 +
50.47 +import java.io.ByteArrayInputStream;
50.48 +import java.io.ByteArrayOutputStream;
50.49 +import java.io.ObjectInputStream;
50.50 +import java.io.ObjectOutputStream;
50.51 +import java.io.Serializable;
50.52 +import java.lang.ref.WeakReference;
50.53 +import java.lang.ref.Reference;
50.54 +import java.util.ArrayList;
50.55 +import java.util.Arrays;
50.56 +import java.util.Collection;
50.57 +import java.util.Collections;
50.58 +import java.util.Iterator;
50.59 +import java.util.LinkedList;
50.60 +import java.util.List;
50.61 +import java.util.concurrent.Executors;
50.62 +import java.util.concurrent.TimeUnit;
50.63 +import javax.swing.ActionMap;
50.64 +import javax.swing.InputMap;
50.65 +import org.netbeans.junit.NbTestCase;
50.66 +import org.openide.util.Lookup;
50.67 +import org.openide.util.Lookup.Template;
50.68 +import org.openide.util.LookupEvent;
50.69 +import org.openide.util.LookupListener;
50.70 +
50.71 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
50.72 +public class AbstractLookupBaseHid extends NbTestCase {
50.73 + private static AbstractLookupBaseHid running;
50.74 +
50.75 + /** instance content to work with */
50.76 + InstanceContent ic;
50.77 + /** the lookup to work on */
50.78 + protected Lookup instanceLookup;
50.79 + /** the lookup created to work with */
50.80 + private Lookup lookup;
50.81 + /** implementation of methods that can influence the behaviour */
50.82 + Impl impl;
50.83 +
50.84 + protected AbstractLookupBaseHid(String testName, Impl impl) {
50.85 + super(testName);
50.86 + if (impl == null && (this instanceof Impl)) {
50.87 + impl = (Impl)this;
50.88 + }
50.89 + this.impl = impl;
50.90 + }
50.91 +
50.92 + protected @Override void setUp() {
50.93 + this.ic = new InstanceContent ();
50.94 +
50.95 + beforeActualTest(getName());
50.96 +
50.97 + this.instanceLookup = createInstancesLookup (ic);
50.98 + this.lookup = createLookup (instanceLookup);
50.99 + running = this;
50.100 + }
50.101 +
50.102 + protected @Override void tearDown() {
50.103 + running = null;
50.104 + }
50.105 +
50.106 + /** The methods to influence test behaviour */
50.107 + public static interface Impl {
50.108 + /** Creates the initial abstract lookup.
50.109 + */
50.110 + public Lookup createInstancesLookup (InstanceContent ic);
50.111 + /** Creates an lookup for given lookup. This class just returns
50.112 + * the object passed in, but subclasses can be different.
50.113 + * @param lookup in lookup
50.114 + * @return a lookup to use
50.115 + */
50.116 + public Lookup createLookup (Lookup lookup);
50.117 +
50.118 + /** If the impl has any caches that would prevent the system
50.119 + * to not garbage collect correctly, then clear them now.
50.120 + */
50.121 + public void clearCaches ();
50.122 + }
50.123 +
50.124 + private Lookup createInstancesLookup (InstanceContent ic) {
50.125 + return impl.createInstancesLookup (ic);
50.126 + }
50.127 +
50.128 + private Lookup createLookup (Lookup lookup) {
50.129 + return impl.createLookup (lookup);
50.130 + }
50.131 +
50.132 + /** instances that we register */
50.133 + private static Object[] INSTANCES = new Object[] {
50.134 + new Integer (10),
50.135 + new Object ()
50.136 + };
50.137 +
50.138 + /** Test if first is really first.
50.139 + */
50.140 + public void testFirst () {
50.141 + Integer i1 = 1;
50.142 + Integer i2 = 2;
50.143 +
50.144 + ic.add (i1);
50.145 + ic.add (i2);
50.146 +
50.147 + Integer found = lookup.lookup(Integer.class);
50.148 + if (found != i1) {
50.149 + fail ("First object is not first: " + found + " != " + i1);
50.150 + }
50.151 +
50.152 + List<Integer> list = new ArrayList<Integer>();
50.153 + list.add (i2);
50.154 + list.add (i1);
50.155 + ic.set (list, null);
50.156 +
50.157 + found = lookup.lookup (Integer.class);
50.158 + if (found != i2) {
50.159 + fail ("Second object is not first after reorder: " + found + " != " + i2);
50.160 + }
50.161 +
50.162 + }
50.163 +
50.164 + public void testToString() {
50.165 + String txt = lookup.toString();
50.166 + assertNotNull("Something is there", txt);
50.167 + assertTrue("Something2: " + txt, txt.length() > 0);
50.168 + }
50.169 +
50.170 +
50.171 + /** Tests ordering of items in the lookup.
50.172 + */
50.173 + public void testOrder () {
50.174 + addInstances (INSTANCES);
50.175 +
50.176 + if (INSTANCES[0] != lookup.lookup (INSTANCES[0].getClass ())) {
50.177 + fail ("First object in intances not found");
50.178 + }
50.179 +
50.180 + Iterator<?> all = lookup.lookupAll(Object.class).iterator();
50.181 + checkIterator ("Difference between instances added and found", all, Arrays.asList (INSTANCES));
50.182 + }
50.183 +
50.184 + /** Checks the reorder of items in lookup reflects the result.
50.185 + * Testing both classes and interfaces, because they are often treated
50.186 + * especially.
50.187 + */
50.188 + public void testReorder () {
50.189 + String s1 = "s2";
50.190 + String s2 = "s1";
50.191 + Runnable r1 = new Runnable () {
50.192 + public void run () {}
50.193 + };
50.194 + Runnable r2 = new Runnable () {
50.195 + public void run () {}
50.196 + };
50.197 + List<Object> l = new ArrayList<Object>();
50.198 +
50.199 + l.add (s1);
50.200 + l.add (s2);
50.201 + l.add (r1);
50.202 + l.add (r2);
50.203 + ic.set (l, null);
50.204 +
50.205 + assertEquals ("s1 is found", s1, lookup.lookup (String.class));
50.206 + assertEquals ("r1 is found", r1, lookup.lookup (Runnable.class));
50.207 +
50.208 + Collections.reverse (l);
50.209 +
50.210 + ic.set (l, null);
50.211 +
50.212 + assertEquals ("s2 is found", s2, lookup.lookup (String.class));
50.213 + assertEquals ("r2 is found", r2, lookup.lookup (Runnable.class));
50.214 + }
50.215 +
50.216 + /** Tries to set empty collection to the lookup.
50.217 + */
50.218 + public void testSetEmpty () {
50.219 + ic.add ("A serializable string");
50.220 + lookup.lookup (Serializable.class);
50.221 +
50.222 + ic.set (Collections.emptyList(), null);
50.223 + }
50.224 +
50.225 + /** Tests a more complex reorder on nodes.
50.226 + */
50.227 + public void testComplexReorder () {
50.228 + Integer i1 = 1;
50.229 + Long i2 = 2L;
50.230 +
50.231 + List<Object> l = new ArrayList<Object>();
50.232 + l.add (i1);
50.233 + l.add (i2);
50.234 + ic.set (l, null);
50.235 +
50.236 + assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
50.237 + assertEquals ("Find long", i2, lookup.lookup (Long.class));
50.238 + assertEquals ("Find number", i1, lookup.lookup (Number.class));
50.239 +
50.240 + Collections.reverse (l);
50.241 +
50.242 + ic.set (l, null);
50.243 +
50.244 + assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
50.245 + assertEquals ("Find long", i2, lookup.lookup (Long.class));
50.246 + assertEquals ("Find number", i2, lookup.lookup (Number.class));
50.247 + }
50.248 +
50.249 + /** Checks whether setPairs keeps the order.
50.250 + */
50.251 + public void testSetPairs () {
50.252 + // test setPairs method
50.253 + List<Object> li = new ArrayList<Object>();
50.254 + li.addAll (Arrays.asList (INSTANCES));
50.255 + ic.set (li, null);
50.256 +
50.257 + Lookup.Result<Object> res = lookup.lookupResult(Object.class);
50.258 + Iterator<?> all = res.allInstances().iterator();
50.259 + checkIterator ("Original order not kept", all, li);
50.260 +
50.261 + // reverse the order
50.262 + Collections.reverse (li);
50.263 +
50.264 + // change the pairs
50.265 + LL listener = new LL (res);
50.266 + res.addLookupListener (listener);
50.267 + ic.set (li, null);
50.268 + if (listener.getCount () != 1) {
50.269 + fail ("Result has not changed even we set reversed order");
50.270 + }
50.271 +
50.272 + all = res.allInstances ().iterator ();
50.273 + checkIterator ("Reversed order not kept", all, li);
50.274 + }
50.275 +
50.276 + /** Checks whether setPairs fires correct events.
50.277 + */
50.278 + public void testSetPairsFire () {
50.279 + // test setPairs method
50.280 + List<Object> li = new ArrayList<Object>();
50.281 + li.addAll (Arrays.asList (INSTANCES));
50.282 + ic.set (li, null);
50.283 +
50.284 + Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
50.285 + Iterator<?> all = res.allInstances().iterator();
50.286 + checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
50.287 +
50.288 + // change the pairs
50.289 + LL listener = new LL (res);
50.290 + res.addLookupListener (listener);
50.291 +
50.292 + List<Object> l2 = new ArrayList<Object>(li);
50.293 + l2.remove (INSTANCES[0]);
50.294 + ic.set (l2, null);
50.295 +
50.296 + all = lookup.lookupAll(Object.class).iterator();
50.297 + checkIterator ("The removed integer is not noticed", all, l2);
50.298 +
50.299 + if (listener.getCount () != 1) {
50.300 + fail ("Nothing has not been fired");
50.301 + }
50.302 + }
50.303 +
50.304 + /** Checks whether set pairs does not fire when they should not.
50.305 + */
50.306 + public void testSetPairsDoesNotFire () {
50.307 + Object tmp = new Object ();
50.308 +
50.309 + List<Object> li = new ArrayList<Object>();
50.310 + li.add (tmp);
50.311 + li.addAll (Arrays.asList (INSTANCES));
50.312 + ic.set (li, null);
50.313 +
50.314 + Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
50.315 + Iterator<?> all = res.allInstances ().iterator ();
50.316 + checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
50.317 +
50.318 + // change the pairs
50.319 + LL listener = new LL (res);
50.320 + res.addLookupListener (listener);
50.321 +
50.322 + List<Object> l2 = new ArrayList<Object>(li);
50.323 + l2.remove (tmp);
50.324 + ic.set (l2, null);
50.325 +
50.326 + all = lookup.lookupAll(Object.class).iterator();
50.327 + checkIterator ("The removed integer is not noticed", all, l2);
50.328 +
50.329 + if (listener.getCount () != 0) {
50.330 + fail ("Something has been fired");
50.331 + }
50.332 + }
50.333 +
50.334 + /** Test whether after registration it is possible to find registered objects
50.335 + *
50.336 + */
50.337 + public void testLookupAndAdd () throws Exception {
50.338 + addInstances (INSTANCES);
50.339 +
50.340 + for (int i = 0; i < INSTANCES.length; i++) {
50.341 + Object obj = INSTANCES[i];
50.342 + findAll (lookup, obj.getClass (), true);
50.343 + }
50.344 + }
50.345 +
50.346 + /** Tries to find all classes and superclasses in the lookup.
50.347 + */
50.348 + private void findAll(Lookup lookup, Class<?> clazz, boolean shouldBeThere) {
50.349 + if (clazz == null) return;
50.350 +
50.351 + Object found = lookup.lookup (clazz);
50.352 + if (found == null) {
50.353 + if (shouldBeThere) {
50.354 + // should find at either instance or something else, but must
50.355 + // find at least something
50.356 + fail ("Lookup (" + clazz.getName () + ") found nothing");
50.357 + }
50.358 + } else {
50.359 + if (!shouldBeThere) {
50.360 + // should find at either instance or something else, but must
50.361 + // find at least something
50.362 + fail ("Lookup (" + clazz.getName () + ") found " + found);
50.363 + }
50.364 + }
50.365 +
50.366 + Lookup.Result<?> res = lookup.lookupResult(clazz);
50.367 + Collection<?> collection = res.allInstances();
50.368 +
50.369 + for (int i = 0; i < INSTANCES.length; i++) {
50.370 + boolean isSubclass = clazz.isInstance (INSTANCES[i]);
50.371 + boolean isThere = collection.contains (INSTANCES[i]);
50.372 +
50.373 + if (isSubclass != isThere) {
50.374 + // a problem found
50.375 + // should find at either instance or something else, but must
50.376 + // find at least something
50.377 + fail ("Lookup.Result (" + clazz.getName () + ") for " + INSTANCES[i] + " is subclass: " + isSubclass + " isThere: " + isThere);
50.378 + }
50.379 + }
50.380 +
50.381 + // go on for superclasses
50.382 +
50.383 + findAll (lookup, clazz.getSuperclass (), shouldBeThere);
50.384 +
50.385 + Class[] ies = clazz.getInterfaces ();
50.386 + for (int i = 0; i < ies.length; i++) {
50.387 + findAll (lookup, ies[i], shouldBeThere);
50.388 + }
50.389 + }
50.390 +
50.391 + /** Test if it is possible to remove a registered object. */
50.392 + public void testRemoveRegisteredObject() {
50.393 + Integer inst = new Integer(10);
50.394 +
50.395 + ic.add(inst);
50.396 + if (lookup.lookup(inst.getClass()) == null) {
50.397 + // should find an instance
50.398 + fail("Lookup (" + inst.getClass().getName () + ") found nothing");
50.399 + }
50.400 +
50.401 + ic.remove(inst);
50.402 + if (lookup.lookup(inst.getClass()) != null) {
50.403 + // should NOT find an instance
50.404 + fail("Lookup (" + inst.getClass().getName () +
50.405 + ") found an instance after remove operation");
50.406 + }
50.407 + }
50.408 +
50.409 + public void testCanReturnReallyStrangeResults () throws Exception {
50.410 + class QueryingPair extends AbstractLookup.Pair<Object> {
50.411 + private Integer i = 434;
50.412 +
50.413 + //
50.414 + // do the test
50.415 + //
50.416 +
50.417 + public void doTest () throws Exception {
50.418 + ic.add (i);
50.419 + ic.addPair (this);
50.420 +
50.421 + Object found = lookup.lookup (QueryingPair.class);
50.422 + assertEquals ("This object is found", this, found);
50.423 + }
50.424 +
50.425 +
50.426 + //
50.427 + // Implementation of pair
50.428 + //
50.429 +
50.430 + public String getId() {
50.431 + return getType ().toString();
50.432 + }
50.433 +
50.434 + public String getDisplayName() {
50.435 + return getId ();
50.436 + }
50.437 +
50.438 + public Class<?> getType() {
50.439 + return getClass ();
50.440 + }
50.441 +
50.442 + protected boolean creatorOf(Object obj) {
50.443 + return obj == this;
50.444 + }
50.445 +
50.446 + protected boolean instanceOf(Class<?> c) {
50.447 + assertEquals ("Integer found or exception is thrown", i, lookup.lookup (Integer.class));
50.448 + return c.isAssignableFrom(getType ());
50.449 + }
50.450 +
50.451 + public Object getInstance() {
50.452 + return this;
50.453 + }
50.454 +
50.455 +
50.456 + }
50.457 +
50.458 +
50.459 + QueryingPair qp = new QueryingPair ();
50.460 + qp.doTest ();
50.461 + }
50.462 +
50.463 + /** Test of firing events. */
50.464 + public void testLookupListener() {
50.465 + Object inst = 10;
50.466 + Lookup.Result<?> res = lookup.lookupResult(inst.getClass());
50.467 + res.allInstances ();
50.468 +
50.469 + LL listener = new LL(res);
50.470 + res.addLookupListener(listener);
50.471 +
50.472 + ic.add(inst);
50.473 + if (listener.getCount() == 0) {
50.474 + fail("None event fired during NbLookup.addPair()");
50.475 + }
50.476 +
50.477 + ic.remove(inst);
50.478 + if (listener.getCount() == 0) {
50.479 + fail("None event fired during NbLookup.removePair()");
50.480 + }
50.481 +
50.482 + ic.add(inst);
50.483 + if (listener.getCount() == 0) {
50.484 + fail("None event fired during second NbLookup.addPair()");
50.485 + }
50.486 +
50.487 + ic.remove(inst);
50.488 + if (listener.getCount() == 0) {
50.489 + fail("None event fired during second NbLookup.removePair()");
50.490 + }
50.491 + }
50.492 +
50.493 + /** Testing identity of the lookup.
50.494 + */
50.495 + public void testId () {
50.496 + Lookup.Template<?> templ;
50.497 + int cnt;
50.498 +
50.499 + addInstances (INSTANCES);
50.500 +
50.501 + Lookup.Result<?> res = lookup.lookupResult(Object.class);
50.502 + for (AbstractLookup.Item<?> item : res.allItems()) {
50.503 +
50.504 + templ = new Lookup.Template<Object>(null, item.getId(), null);
50.505 + cnt = lookup.lookup (templ).allInstances ().size ();
50.506 + if (cnt != 1) {
50.507 + fail ("Identity lookup failed. Instances = " + cnt);
50.508 + }
50.509 +
50.510 + templ = makeTemplate(item.getType(), item.getId());
50.511 + cnt = lookup.lookup (templ).allInstances ().size ();
50.512 + if (cnt != 1) {
50.513 + fail ("Identity lookup with type failed. Instances = " + cnt);
50.514 + }
50.515 +
50.516 + templ = makeTemplate(this.getClass(), item.getId());
50.517 + cnt = lookup.lookup (templ).allInstances ().size ();
50.518 + if (cnt != 0) {
50.519 + fail ("Identity lookup with wrong type failed. Instances = " + cnt);
50.520 + }
50.521 +
50.522 + templ = new Lookup.Template<Object>(null, null, item.getInstance());
50.523 + cnt = lookup.lookup (templ).allInstances ().size ();
50.524 + if (cnt != 1) {
50.525 + fail ("Instance lookup failed. Instances = " + cnt);
50.526 + }
50.527 +
50.528 + templ = new Lookup.Template<Object>(null, item.getId(), item.getInstance());
50.529 + cnt = lookup.lookup (templ).allInstances ().size ();
50.530 + if (cnt != 1) {
50.531 + fail ("Instance & identity lookup failed. Instances = " + cnt);
50.532 + }
50.533 +
50.534 + }
50.535 + }
50.536 + private static <T> Lookup.Template<T> makeTemplate(Class<T> clazz, String id) { // captures type parameter
50.537 + return new Lookup.Template<T>(clazz, id, null);
50.538 + }
50.539 +
50.540 + /** Tests adding and removing.
50.541 + */
50.542 + public void testAddAndRemove () throws Exception {
50.543 + Object map = new javax.swing.ActionMap ();
50.544 + LL ll = new LL ();
50.545 +
50.546 + Lookup.Result<?> res = lookup.lookupResult(map.getClass());
50.547 + res.allItems();
50.548 + res.addLookupListener (ll);
50.549 + ll.source = res;
50.550 +
50.551 + ic.add (map);
50.552 +
50.553 + assertEquals ("First change when adding", ll.getCount (), 1);
50.554 +
50.555 + ic.remove (map);
50.556 +
50.557 + assertEquals ("Second when removing", ll.getCount (), 1);
50.558 +
50.559 + ic.add (map);
50.560 +
50.561 + assertEquals ("Third when readding", ll.getCount (), 1);
50.562 +
50.563 + ic.remove (map);
50.564 +
50.565 + assertEquals ("Forth when reremoving", ll.getCount (), 1);
50.566 +
50.567 + }
50.568 +
50.569 + /** Will a class garbage collect even it is registered in lookup.
50.570 + */
50.571 + public void testGarbageCollect () throws Exception {
50.572 + ClassLoader l = new CL ();
50.573 + Class<?> c = l.loadClass(Garbage.class.getName());
50.574 + Reference<?> ref = new WeakReference<Object>(c);
50.575 +
50.576 + lookup.lookup (c);
50.577 +
50.578 + // now test garbage collection
50.579 + c = null;
50.580 + l = null;
50.581 + impl.clearCaches ();
50.582 + assertGC ("The classloader has not been garbage collected!", ref);
50.583 + }
50.584 +
50.585 + /** Items are the same as results.
50.586 + */
50.587 + public void testItemsAndIntances () {
50.588 + addInstances (INSTANCES);
50.589 +
50.590 + Lookup.Result<Object> r = lookup.lookupResult(Object.class);
50.591 + Collection<? extends Lookup.Item<?>> items = r.allItems();
50.592 + Collection<?> insts = r.allInstances();
50.593 +
50.594 + if (items.size () != insts.size ()) {
50.595 + fail ("Different size of sets");
50.596 + }
50.597 +
50.598 + for (Lookup.Item<?> item : items) {
50.599 + if (!insts.contains (item.getInstance ())) {
50.600 + fail ("Intance " + item.getInstance () + " is missing in " + insts);
50.601 + }
50.602 + }
50.603 + }
50.604 +
50.605 + /** Checks search for interface.
50.606 + */
50.607 + public void testSearchForInterface () {
50.608 + Lookup.Template<Serializable> t = new Lookup.Template<Serializable>(Serializable.class, null, null);
50.609 +
50.610 + assertNull("Nothing to find", lookup.lookupItem (t));
50.611 +
50.612 + Serializable s = new Serializable () {};
50.613 + ic.add (s);
50.614 +
50.615 + Lookup.Item item = lookup.lookupItem (t);
50.616 + assertNotNull ("Something found", item);
50.617 + }
50.618 +
50.619 + /** Test to add broken item if it incorrectly answers instanceOf questions.
50.620 + */
50.621 + public void testIncorectInstanceOf40364 () {
50.622 + final Long sharedLong = new Long (0);
50.623 +
50.624 + class P extends AbstractLookup.Pair<Object> {
50.625 + public boolean isLong;
50.626 +
50.627 + P (boolean b) {
50.628 + isLong = b;
50.629 + }
50.630 +
50.631 + protected boolean creatorOf (Object obj) {
50.632 + return obj == sharedLong;
50.633 + }
50.634 +
50.635 + public String getDisplayName () {
50.636 + return "";
50.637 + }
50.638 +
50.639 + public String getId () {
50.640 + return "";
50.641 + }
50.642 +
50.643 + public Object getInstance () {
50.644 + return sharedLong;
50.645 + }
50.646 +
50.647 + public Class<?> getType() {
50.648 + return isLong ? Long.class : Number.class;
50.649 + }
50.650 +
50.651 + protected boolean instanceOf(Class<?> c) {
50.652 + return c.isAssignableFrom (getType ());
50.653 + }
50.654 +
50.655 + public @Override int hashCode() {
50.656 + return getClass ().hashCode ();
50.657 + }
50.658 +
50.659 + public @Override boolean equals(Object obj) {
50.660 + return obj != null && getClass ().equals (obj.getClass ());
50.661 + }
50.662 + }
50.663 +
50.664 + // to create the right structure in the lookup
50.665 + lookup.lookup (Object.class);
50.666 + lookup.lookup (Long.class);
50.667 + lookup.lookup (Number.class);
50.668 +
50.669 + P lng1 = new P (true);
50.670 + ic.addPair (lng1);
50.671 +
50.672 + P lng2 = new P (false);
50.673 + ic.setPairs (Collections.singleton (lng2));
50.674 +
50.675 + Collection<? extends Lookup.Item<?>> res = lookup.lookupResult(Object.class).allItems();
50.676 + assertEquals ("Just one pair", 1, res.size ());
50.677 + }
50.678 +
50.679 + public void testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly () throws Exception {
50.680 + class X implements TestInterfaceInheritanceA, TestInterfaceInheritanceB {
50.681 + }
50.682 + final X shared = new X ();
50.683 +
50.684 + class P extends AbstractLookup.Pair<Object> {
50.685 + public int howLong;
50.686 +
50.687 + P (int b) {
50.688 + howLong = b;
50.689 + }
50.690 +
50.691 + protected boolean creatorOf (Object obj) {
50.692 + return obj == shared;
50.693 + }
50.694 +
50.695 + public String getDisplayName () {
50.696 + return "";
50.697 + }
50.698 +
50.699 + public String getId () {
50.700 + return "";
50.701 + }
50.702 +
50.703 + public Object getInstance () {
50.704 + return shared;
50.705 + }
50.706 +
50.707 + public Class<?> getType() {
50.708 + return howLong == 0 ? TestInterfaceInheritanceB.class : TestInterfaceInheritanceA.class;
50.709 + }
50.710 +
50.711 + protected boolean instanceOf(Class<?> c) {
50.712 + return c.isAssignableFrom (getType ());
50.713 + }
50.714 +
50.715 + public @Override int hashCode() {
50.716 + return getClass ().hashCode ();
50.717 + }
50.718 +
50.719 + public @Override boolean equals(Object obj) {
50.720 + if (obj instanceof P) {
50.721 + P p = (P)obj;
50.722 + if (this.howLong > 0) {
50.723 + this.howLong--;
50.724 + return false;
50.725 + }
50.726 + if (p.howLong > 0) {
50.727 + p.howLong--;
50.728 + return false;
50.729 + }
50.730 + return getClass ().equals (p.getClass ());
50.731 + }
50.732 + return false;
50.733 + }
50.734 + }
50.735 +
50.736 + // to create the right structure in the lookup
50.737 + Lookup.Result<?> a = lookup.lookupResult(TestInterfaceInheritanceA.class);
50.738 + Lookup.Result<?> b = lookup.lookupResult(TestInterfaceInheritanceB.class);
50.739 +
50.740 + P lng1 = new P (0);
50.741 + ic.addPair (lng1);
50.742 +
50.743 + assertEquals ("One in a", 1, a.allItems ().size ());
50.744 + assertEquals ("One in b", 1, b.allItems ().size ());
50.745 +
50.746 + P lng2 = new P (1);
50.747 +
50.748 +
50.749 + /* Following call used to generate this exception:
50.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
50.751 + at org.openide.util.lookup.ALPairComparator.compare(ALPairComparator.java:52)
50.752 + at java.util.Arrays.mergeSort(Arrays.java:1284)
50.753 + at java.util.Arrays.sort(Arrays.java:1223)
50.754 + at java.util.Collections.sort(Collections.java:159)
50.755 + at org.openide.util.lookup.InheritanceTree.retainAllInterface(InheritanceTree.java:753)
50.756 + at org.openide.util.lookup.InheritanceTree.retainAll(InheritanceTree.java:183)
50.757 + at org.openide.util.lookup.DelegatingStorage.retainAll(DelegatingStorage.java:83)
50.758 + at org.openide.util.lookup.AbstractLookup.setPairsAndCollectListeners(AbstractLookup.java:238)
50.759 + at org.openide.util.lookup.AbstractLookup.setPairs(AbstractLookup.java:203)
50.760 + at org.openide.util.lookup.AbstractLookup$Content.setPairs(AbstractLookup.java:885)
50.761 + at org.openide.util.lookup.AbstractLookupBaseHid.testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly(AbstractLookupBaseHid.java:696)
50.762 + at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
50.763 + at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
50.764 + at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
50.765 + at org.netbeans.junit.NbTestCase.run(NbTestCase.java:119)
50.766 + */
50.767 + ic.setPairs (Collections.singleton (lng2));
50.768 +
50.769 +
50.770 + }
50.771 +
50.772 + public void testInstancesArePreservedFoundWhenFixing48590 () throws Exception {
50.773 + class X implements Runnable, Serializable {
50.774 + public void run () {
50.775 +
50.776 + }
50.777 +
50.778 + public void assertOnlyMe (String msg, Lookup.Result<?> res) {
50.779 + Collection<?> col = res.allInstances();
50.780 + assertEquals (msg + " just one", 1, col.size ());
50.781 + assertSame (msg + " and it is me", this, col.iterator ().next ());
50.782 + }
50.783 + }
50.784 +
50.785 + Lookup.Result<?> runnable = lookup.lookupResult(Runnable.class);
50.786 + Lookup.Result<?> serial = lookup.lookupResult(Serializable.class);
50.787 +
50.788 +
50.789 + X x = new X ();
50.790 + ic.add (x);
50.791 +
50.792 +
50.793 + x.assertOnlyMe ("x implements it (1)", runnable);
50.794 + x.assertOnlyMe ("x implements it (2)", serial);
50.795 +
50.796 + ic.set (Collections.singleton (x), null);
50.797 +
50.798 + x.assertOnlyMe ("x implements it (3)", runnable);
50.799 + x.assertOnlyMe ("x implements it (4)", serial);
50.800 + }
50.801 +
50.802 + /** Testing lookup of inherited classes. */
50.803 + public void testInheritance() {
50.804 + class A {}
50.805 + class B extends A implements java.rmi.Remote {}
50.806 + class BB extends B {}
50.807 + class C extends A implements java.rmi.Remote {}
50.808 + class D extends A {}
50.809 +
50.810 + A[] types = {new B(), new BB(), new C(), new D()};
50.811 +
50.812 + for (int i = 0; i < types.length; i++) {
50.813 + ic.add(types[i]);
50.814 + if (lookup.lookup(types[i].getClass()) == null) {
50.815 + // should find an instance
50.816 + fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
50.817 + }
50.818 + }
50.819 +
50.820 + int size1, size2;
50.821 +
50.822 + //interface query
50.823 + size1 = lookup.lookupAll(java.rmi.Remote.class).size();
50.824 + size2 = countInstances(types, java.rmi.Remote.class);
50.825 +
50.826 + if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
50.827 +
50.828 + // superclass query
50.829 + size1 = lookup.lookupAll(A.class).size();
50.830 + size2 = countInstances(types, A.class);
50.831 +
50.832 + if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
50.833 + }
50.834 +
50.835 + /** Test interface inheritance.
50.836 + */
50.837 + public void testInterfaceInheritance() {
50.838 + TestInterfaceInheritanceA[] types = {
50.839 + new TestInterfaceInheritanceB() {},
50.840 + new TestInterfaceInheritanceBB() {},
50.841 + new TestInterfaceInheritanceC() {},
50.842 + new TestInterfaceInheritanceD() {}
50.843 + };
50.844 +
50.845 + for (int i = 0; i < types.length; i++) {
50.846 + ic.add(types[i]);
50.847 + if (lookup.lookup(types[i].getClass()) == null) {
50.848 + // should find an instance
50.849 + fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
50.850 + }
50.851 + }
50.852 +
50.853 + int size1, size2;
50.854 +
50.855 + //interface query
50.856 + LL l = new LL ();
50.857 + Lookup.Result<?> res = lookup.lookupResult(java.rmi.Remote.class);
50.858 + l.source = res;
50.859 + size1 = res.allInstances().size();
50.860 + size2 = countInstances(types, java.rmi.Remote.class);
50.861 +
50.862 + if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
50.863 +
50.864 + // superclass query
50.865 + size1 = lookup.lookupAll(TestInterfaceInheritanceA.class).size();
50.866 + size2 = countInstances(types, TestInterfaceInheritanceA.class);
50.867 +
50.868 + if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
50.869 +
50.870 + res.addLookupListener (l);
50.871 + ic.remove (types[0]);
50.872 +
50.873 + if (l.getCount () != 1) {
50.874 + fail ("No notification that a Remote is removed");
50.875 + }
50.876 + }
50.877 +
50.878 + /** Checks whether the AbstractLookup is guarded against modifications
50.879 + * while doing some kind of modification.
50.880 + */
50.881 + public void testModificationArePreventedWhenDoingModifications () throws Exception {
50.882 + BrokenPair broken = new BrokenPair (true, false);
50.883 + ic.addPair (broken);
50.884 +
50.885 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
50.886 + Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
50.887 + assertEquals ("Broken is found", broken, item);
50.888 + }
50.889 +
50.890 + public void testModificationArePreventedWhenDoingModificationsResult () throws Exception {
50.891 + BrokenPair broken = new BrokenPair (false, true);
50.892 + ic.addPair (broken);
50.893 +
50.894 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
50.895 +
50.896 + Collection<? extends BrokenPair> c = lookup.lookup (templ).allInstances();
50.897 + assertEquals ("One item", 1, c.size ());
50.898 + assertEquals ("Broken is found again", broken, c.iterator().next ());
50.899 + }
50.900 +
50.901 + public void testModificationArePreventedWhenDoingModificationsItemAndResult () throws Exception {
50.902 + BrokenPair broken = new BrokenPair (false, true);
50.903 + ic.addPair (broken);
50.904 +
50.905 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
50.906 + Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
50.907 + assertEquals ("Broken is found", broken, item);
50.908 +
50.909 + Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
50.910 + assertEquals ("One item", 1, c.size ());
50.911 + assertEquals ("Broken is found again", broken, c.iterator().next ());
50.912 + }
50.913 +
50.914 + public void testModificationArePreventedWhenDoingModificationsResultAndItem () throws Exception {
50.915 + BrokenPair broken = new BrokenPair (false, true);
50.916 + ic.addPair (broken);
50.917 +
50.918 + Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
50.919 + Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
50.920 + assertEquals ("One item", 1, c.size ());
50.921 + assertEquals ("Broken is found again", broken, c.iterator().next ());
50.922 +
50.923 + Object item = lookup.lookupItem (templ);
50.924 + assertEquals ("Broken is found", broken, item);
50.925 + }
50.926 +
50.927 + public void testAddALotOfPairsIntoTheLookupOneByOne () throws Exception {
50.928 + Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
50.929 + for (int i = 0; i < 1000; i++) {
50.930 + ic.add(i);
50.931 + }
50.932 + assertEquals (
50.933 + "there is the right count",
50.934 + 1000,
50.935 + res.allItems().size ()
50.936 + );
50.937 + }
50.938 +
50.939 + public void testAddALotOfPairsIntoTheLookup () throws Exception {
50.940 + List<Integer> arr = new ArrayList<Integer>();
50.941 + for (int i = 0; i < 1000; i++) {
50.942 + arr.add(i);
50.943 + }
50.944 + ic.set (arr, null);
50.945 +
50.946 + assertEquals (
50.947 + "there is the right count",
50.948 + 1000,
50.949 + lookup.lookupResult(Integer.class).allItems().size()
50.950 + );
50.951 + }
50.952 +
50.953 +
50.954 + public void testDoubleAddIssue35274 () throws Exception {
50.955 + class P extends AbstractLookup.Pair<Object> {
50.956 + protected boolean creatorOf(Object obj) { return false; }
50.957 + public String getDisplayName() { return ""; }
50.958 + public String getId() { return ""; }
50.959 + public Object getInstance() { return null; }
50.960 + public Class<?> getType() { return Object.class; }
50.961 + protected boolean instanceOf(Class<?> c) { return c.isAssignableFrom(getType ()); }
50.962 + public @Override int hashCode() {return getClass().hashCode();}
50.963 + public @Override boolean equals(Object obj) {return getClass() == obj.getClass();}
50.964 + }
50.965 +
50.966 + P p = new P ();
50.967 +
50.968 + ic.addPair (p);
50.969 + ic.addPair (p);
50.970 +
50.971 + Lookup.Result<Object> result = lookup.lookupResult(Object.class);
50.972 + Collection res = result.allItems ();
50.973 + assertEquals ("One item there", 1, res.size ());
50.974 + assertTrue ("It is the p", p == res.iterator ().next ());
50.975 +
50.976 + P p2 = new P ();
50.977 + ic.addPair (p2);
50.978 +
50.979 + Reference<?> ref = new WeakReference<Object>(result);
50.980 + result = null;
50.981 + assertGC ("The result can disappear", ref);
50.982 +
50.983 + impl.clearCaches ();
50.984 +
50.985 + result = lookup.lookupResult(Object.class);
50.986 + res = result.allItems ();
50.987 + assertEquals ("One item is still there", 1, res.size ());
50.988 + assertTrue ("But the p2 replaced p", p2 == res.iterator ().next ());
50.989 +
50.990 + }
50.991 +
50.992 + /** Test for proper serialization.
50.993 + */
50.994 + public void testSerializationSupport () throws Exception {
50.995 + doSerializationSupport (1);
50.996 + }
50.997 + public void testDoubleSerializationSupport () throws Exception {
50.998 + doSerializationSupport (2);
50.999 + }
50.1000 +
50.1001 + private void doSerializationSupport (int count) throws Exception {
50.1002 + if (lookup instanceof Serializable) {
50.1003 + ic.addPair (new SerialPair ("1"));
50.1004 + ic.addPair (new SerialPair ("2"));
50.1005 + ic.addPair (new SerialPair ("3"));
50.1006 +
50.1007 + Lookup l = (Lookup)reserialize(lookup);
50.1008 +
50.1009 + assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
50.1010 +
50.1011 + assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
50.1012 +
50.1013 + while (count-- > 0) {
50.1014 + l = (Lookup)reserialize(l);
50.1015 + }
50.1016 +
50.1017 + assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
50.1018 +
50.1019 + assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
50.1020 + }
50.1021 + }
50.1022 +
50.1023 + /** When a lookup with two different versions of the same class
50.1024 + * get's serialized, the results may be very bad.
50.1025 + */
50.1026 + public void testSerializationOfTwoClassesWithTheSameName () throws Exception {
50.1027 + if (lookup instanceof Serializable) {
50.1028 + doTwoSerializedClasses (false, false);
50.1029 + }
50.1030 + }
50.1031 + public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSave () throws Exception {
50.1032 + if (lookup instanceof Serializable) {
50.1033 + doTwoSerializedClasses (true, false);
50.1034 + }
50.1035 + }
50.1036 + public void testSerializationOfTwoClassesWithTheSameNameWithBroken () throws Exception {
50.1037 + if (lookup instanceof Serializable) {
50.1038 + doTwoSerializedClasses (false, true);
50.1039 + }
50.1040 + }
50.1041 + public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSaveWithBroken () throws Exception {
50.1042 + if (lookup instanceof Serializable) {
50.1043 + doTwoSerializedClasses (true, true);
50.1044 + }
50.1045 + }
50.1046 +
50.1047 + private void doTwoSerializedClasses (boolean queryBeforeSerialization, boolean useBroken) throws Exception {
50.1048 + ClassLoader loader = new CL ();
50.1049 + Class c = loader.loadClass (Garbage.class.getName ());
50.1050 +
50.1051 + // in case of InheritanceTree it creates a slot for class Garbage
50.1052 + lookup.lookup(c);
50.1053 +
50.1054 + // but creates new instance and adds it into the lookup
50.1055 + // without querying for it
50.1056 + loader = new CL ();
50.1057 + c = loader.loadClass (Garbage.class.getName ());
50.1058 +
50.1059 + Object theInstance = c.newInstance ();
50.1060 +
50.1061 + ic.addPair (new SerialPair (theInstance));
50.1062 +
50.1063 + Broken2Pair broken = null;
50.1064 + if (useBroken) {
50.1065 + broken = new Broken2Pair ();
50.1066 + ic.addPair (broken);
50.1067 +
50.1068 + assertNull (
50.1069 + "We need to create the slot for the List as " +
50.1070 + "the Broken2Pair will ask for it after deserialization",
50.1071 + lookup.lookup (java.awt.List.class)
50.1072 + );
50.1073 + }
50.1074 +
50.1075 + if (queryBeforeSerialization) {
50.1076 + assertEquals ("Instance is found", theInstance, lookup.lookup (c));
50.1077 + }
50.1078 +
50.1079 + // replace the old lookup with new one
50.1080 + lookup = (Lookup)reserialize(lookup);
50.1081 +
50.1082 + Lookup.Result result = lookup.lookup (new Lookup.Template (Garbage.class));
50.1083 + assertEquals ("One item is the result", 1, result.allInstances ().size ());
50.1084 + Object r = result.allInstances ().iterator ().next ();
50.1085 + assertNotNull("A value is found", r);
50.1086 + assertEquals ("It is of the right class", Garbage.class, r.getClass());
50.1087 + }
50.1088 +
50.1089 + /** Test of reorder and item change which used to fail on interfaces.
50.1090 + */
50.1091 + public void testReoderingIssue13779 () throws Exception {
50.1092 + LinkedList arr = new LinkedList ();
50.1093 +
50.1094 + class R extends Exception implements Cloneable {
50.1095 + }
50.1096 + Object o1 = new R ();
50.1097 + Object o2 = new R ();
50.1098 + Object o3 = new R ();
50.1099 +
50.1100 + arr.add (o1);
50.1101 + arr.add (o2);
50.1102 +
50.1103 + ic.set (arr, null);
50.1104 +
50.1105 + Lookup.Result objectResult = lookup.lookup (new Lookup.Template (Exception.class));
50.1106 + Lookup.Result interfaceResult = lookup.lookup (new Lookup.Template (Cloneable.class));
50.1107 + objectResult.allItems ();
50.1108 + interfaceResult.allItems ();
50.1109 +
50.1110 + LL l1 = new LL (objectResult);
50.1111 + LL l2 = new LL (interfaceResult);
50.1112 +
50.1113 + objectResult.addLookupListener(l1);
50.1114 + interfaceResult.addLookupListener(l2);
50.1115 +
50.1116 + arr.addFirst (o3);
50.1117 +
50.1118 + ic.set (arr, null);
50.1119 +
50.1120 + assertEquals ("One change on objects", 1, l1.getCount ());
50.1121 + assertEquals ("One change on interfaces", 1, l2.getCount ());
50.1122 +
50.1123 + arr.addFirst (new Cloneable () { });
50.1124 + ic.set (arr, null);
50.1125 +
50.1126 + assertEquals ("No change on objects", 0, l1.getCount ());
50.1127 + assertEquals ("But one change on interfaces", 1, l2.getCount ());
50.1128 +
50.1129 + }
50.1130 +
50.1131 + public void testDeadlockBetweenProxyResultAndLookupIssue47772 () throws Exception {
50.1132 + final String myModule = "My Module";
50.1133 + ic.add (myModule);
50.1134 +
50.1135 + class MyProxy extends ProxyLookup {
50.1136 + public MyProxy () {
50.1137 + super (new Lookup[] { lookup });
50.1138 + }
50.1139 + }
50.1140 + final MyProxy my = new MyProxy ();
50.1141 +
50.1142 + final Lookup.Result allModules = my.lookup (new Lookup.Template (String.class));
50.1143 +
50.1144 + class PairThatNeedsInfoAboutModules extends AbstractLookup.Pair {
50.1145 + public String getDisplayName () {
50.1146 + return "Need a module";
50.1147 + }
50.1148 + public String getId () {
50.1149 + return getDisplayName ();
50.1150 + }
50.1151 + public Class getType () {
50.1152 + return Integer.class;
50.1153 + }
50.1154 + protected boolean instanceOf (Class c) {
50.1155 + if (c == Integer.class) {
50.1156 + synchronized (this) {
50.1157 + notifyAll ();
50.1158 + try {
50.1159 + wait (1000);
50.1160 + } catch (InterruptedException ex) {
50.1161 + fail (ex.getMessage ());
50.1162 + }
50.1163 + }
50.1164 + java.util.Collection coll = allModules.allInstances ();
50.1165 + assertEquals ("Size is 1", 1, coll.size ());
50.1166 + assertEquals ("My module is there", myModule, coll.iterator ().next ());
50.1167 + }
50.1168 + return c.isAssignableFrom (Integer.class);
50.1169 + }
50.1170 +
50.1171 + public Object getInstance () {
50.1172 + return new Integer (10);
50.1173 + }
50.1174 +
50.1175 + protected boolean creatorOf (Object obj) {
50.1176 + return new Integer (10).equals (obj);
50.1177 + }
50.1178 + }
50.1179 +
50.1180 + PairThatNeedsInfoAboutModules pair = new PairThatNeedsInfoAboutModules ();
50.1181 + ic.addPair (pair);
50.1182 +
50.1183 + synchronized (pair) {
50.1184 + class BlockInInstanceOf implements Runnable {
50.1185 + public void run () {
50.1186 + Integer i = my.lookup(Integer.class);
50.1187 + assertEquals (new Integer (10), i);
50.1188 + }
50.1189 + }
50.1190 + BlockInInstanceOf blk = new BlockInInstanceOf ();
50.1191 + Executors.newSingleThreadScheduledExecutor().schedule(blk, 0, TimeUnit.MICROSECONDS);
50.1192 + pair.wait ();
50.1193 + }
50.1194 +
50.1195 + java.util.Collection coll = allModules.allInstances ();
50.1196 + assertEquals ("Size is 1", 1, coll.size ());
50.1197 + assertEquals ("My module is there", myModule, coll.iterator ().next ());
50.1198 + }
50.1199 +
50.1200 + public void testAWayToGenerateProblem13779 () {
50.1201 + ic.add (new Integer (1));
50.1202 + ic.add (new Integer (2));
50.1203 + ic.add (new Integer (1));
50.1204 + ic.add (new Integer (2));
50.1205 +
50.1206 + Collection c = lookup.lookup (new Lookup.Template (Integer.class)).allInstances ();
50.1207 + assertEquals ("There are two objects", 2, c.size ());
50.1208 +
50.1209 + }
50.1210 +
50.1211 + /** Replacing items with different objects.
50.1212 + */
50.1213 + public void testReplacingObjectsDoesNotGenerateException () throws Exception {
50.1214 + LinkedList arr = new LinkedList ();
50.1215 +
50.1216 + class R extends Exception implements Cloneable {
50.1217 + }
50.1218 + arr.add (new R ());
50.1219 + arr.add (new R ());
50.1220 +
50.1221 + ic.set (arr, null);
50.1222 +
50.1223 + arr.clear();
50.1224 +
50.1225 + arr.add (new R ());
50.1226 + arr.add (new R ());
50.1227 +
50.1228 + ic.set (arr, null);
50.1229 + }
50.1230 +
50.1231 + public void testAfterDeserializationNoQueryIsPeformedOnAlreadyQueriedObjects() throws Exception {
50.1232 + if (! (lookup instanceof Serializable)) {
50.1233 + // well this test works only for serializable lookups
50.1234 + return;
50.1235 + }
50.1236 +
50.1237 + SerialPair my = new SerialPair ("no");
50.1238 + ic.addPair (my);
50.1239 +
50.1240 + Lookup.Result res = lookup.lookup (new Lookup.Template (String.class));
50.1241 + assertEquals ("One instance", 1, res.allInstances().size ());
50.1242 + assertEquals ("my.instanceOf called once", 1, my.countInstanceOf);
50.1243 +
50.1244 + Lookup serial = (Lookup)reserialize(lookup);
50.1245 +
50.1246 + Lookup.Result r2 = serial.lookup(new Lookup.Template(String.class));
50.1247 +
50.1248 + assertEquals ("One item", 1, r2.allItems ().size ());
50.1249 + Object one = r2.allItems().iterator().next ();
50.1250 + assertEquals ("The right class", SerialPair.class, one.getClass());
50.1251 + SerialPair p = (SerialPair)one;
50.1252 +
50.1253 + assertEquals ("p.instanceOf has not been queried", 0, p.countInstanceOf);
50.1254 + }
50.1255 +
50.1256 + /** Checks the iterator */
50.1257 + private <T> void checkIterator(String msg, Iterator<? extends T> it1, List<? extends T> list) {
50.1258 + int cnt = 0;
50.1259 + Iterator<? extends T> it2 = list.iterator();
50.1260 + while (it1.hasNext () && it2.hasNext ()) {
50.1261 + T n1 = it1.next();
50.1262 + T n2 = it2.next();
50.1263 +
50.1264 + if (n1 != n2) {
50.1265 + fail (msg + " iterator[" + cnt + "] = " + n1 + " but list[" + cnt + "] = " + n2);
50.1266 + }
50.1267 +
50.1268 + cnt++;
50.1269 + }
50.1270 +
50.1271 + if (it1.hasNext ()) {
50.1272 + fail ("Iterator has more elements than list");
50.1273 + }
50.1274 +
50.1275 + if (it2.hasNext ()) {
50.1276 + fail ("List has more elements than iterator");
50.1277 + }
50.1278 + }
50.1279 +
50.1280 +
50.1281 + public void testResultsAreUnmodifyableOrAtLeastTheyDoNotPropagateToCache() throws Exception {
50.1282 + String s = "Ahoj";
50.1283 +
50.1284 + ic.add(s);
50.1285 +
50.1286 + Lookup.Result res = lookup.lookup(new Template(String.class));
50.1287 +
50.1288 + for (int i = 1; i < 5; i++) {
50.1289 + Collection c1 = res.allInstances();
50.1290 + Collection c2 = res.allClasses();
50.1291 + Collection c3 = res.allItems();
50.1292 +
50.1293 + assertTrue(i + ": c1 has it", c1.contains(s));
50.1294 + assertTrue(i + ": c2 has it", c2.contains(s.getClass()));
50.1295 + assertEquals(i + ": c3 has one", 1, c3.size());
50.1296 + Lookup.Item item = (Lookup.Item) c3.iterator().next();
50.1297 + assertEquals(i + ": c3 has it", s, item.getInstance());
50.1298 +
50.1299 + try {
50.1300 + c1.remove(s);
50.1301 + assertEquals("No elements now", 0, c1.size());
50.1302 + } catch (UnsupportedOperationException ex) {
50.1303 + // ok, this need not be supported
50.1304 + }
50.1305 + try {
50.1306 + c2.remove(s.getClass());
50.1307 + assertEquals("No elements now", 0, c2.size());
50.1308 + } catch (UnsupportedOperationException ex) {
50.1309 + // ok, this need not be supported
50.1310 + }
50.1311 + try {
50.1312 + c3.remove(item);
50.1313 + assertEquals("No elements now", 0, c3.size());
50.1314 + } catch (UnsupportedOperationException ex) {
50.1315 + // ok, this need not be supported
50.1316 + }
50.1317 + }
50.1318 + }
50.1319 +
50.1320 + public void testSomeProblemWithDVBFrameworkSeemsToBeInLookup() {
50.1321 + for (int i = 0; i < 5; i++) {
50.1322 + ic.add(lookup);
50.1323 + assertEquals("Can be found", lookup, lookup.lookup(lookup.getClass()));
50.1324 + ic.set(Collections.EMPTY_LIST, null);
50.1325 + }
50.1326 + }
50.1327 +
50.1328 + public void testListeningAndQueryingByTwoListenersInstances() {
50.1329 + doListeningAndQueryingByTwoListeners(0);
50.1330 + }
50.1331 + public void testListeningAndQueryingByTwoListenersClasses() {
50.1332 + doListeningAndQueryingByTwoListeners(1);
50.1333 + }
50.1334 + public void testListeningAndQueryingByTwoListenersItems() {
50.1335 + doListeningAndQueryingByTwoListeners(2);
50.1336 + }
50.1337 +
50.1338 +
50.1339 + private void doListeningAndQueryingByTwoListeners(final int type) {
50.1340 + class L implements LookupListener {
50.1341 + Lookup.Result integer = lookup.lookup(new Template(Integer.class));
50.1342 + Lookup.Result number = lookup.lookup(new Template(Number.class));
50.1343 + Lookup.Result serial = lookup.lookup(new Template(Serializable.class));
50.1344 +
50.1345 + {
50.1346 + integer.addLookupListener(this);
50.1347 + number.addLookupListener(this);
50.1348 + serial.addLookupListener(this);
50.1349 + }
50.1350 +
50.1351 + int round;
50.1352 +
50.1353 + public void resultChanged(LookupEvent ev) {
50.1354 + Collection c1 = get(type, integer);
50.1355 + Collection c2 = get(type, number);
50.1356 + Collection c3 = get(type, serial);
50.1357 +
50.1358 + assertEquals("round " + round + " c1 vs. c2", c1, c2);
50.1359 + assertEquals("round " + round + " c1 vs. c3", c1, c3);
50.1360 + assertEquals("round " + round + " c2 vs. c3", c2, c3);
50.1361 +
50.1362 + round++;
50.1363 + }
50.1364 +
50.1365 + private Collection get(int type, Lookup.Result res) {
50.1366 + Collection c;
50.1367 + switch(type) {
50.1368 + case 0: c = res.allInstances(); break;
50.1369 + case 1: c = res.allClasses(); break;
50.1370 + case 2: c = res.allItems(); break;
50.1371 + default: c = null; fail("Type: " + type); break;
50.1372 + }
50.1373 +
50.1374 + assertNotNull(c);
50.1375 + return new ArrayList(c);
50.1376 + }
50.1377 + }
50.1378 +
50.1379 + L listener = new L();
50.1380 + listener.resultChanged(null);
50.1381 +
50.1382 + for(int i = 0; i < 100; i++) {
50.1383 + ic.add(new Integer(i));
50.1384 + }
50.1385 +
50.1386 + assertEquals("3x100+1 checks", 301, listener.round);
50.1387 + }
50.1388 +
50.1389 + public void testChangeOfNodeDoesNotFireChangeInActionMap() {
50.1390 + ActionMap am = new ActionMap();
50.1391 + Lookup s = Lookups.singleton(am);
50.1392 + doChangeOfNodeDoesNotFireChangeInActionMap(am, s, false, 0);
50.1393 + }
50.1394 + public void testChangeOfNodeDoesNotFireChangeInActionMapSimple() {
50.1395 + ActionMap am = new ActionMap();
50.1396 + Lookup s = Lookups.singleton(am);
50.1397 + doChangeOfNodeDoesNotFireChangeInActionMap(am, s, true, 0);
50.1398 + }
50.1399 +
50.1400 + public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookupSimple() {
50.1401 + doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(true);
50.1402 + }
50.1403 +
50.1404 + public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup() {
50.1405 + doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(false);
50.1406 + }
50.1407 + private void doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(boolean wrapBySimple) {
50.1408 + final ActionMap am = new ActionMap();
50.1409 +
50.1410 + class Before extends AbstractLookup {
50.1411 + public InstanceContent ic;
50.1412 + public Before() {
50.1413 + this(new InstanceContent());
50.1414 + }
50.1415 +
50.1416 + private Before(InstanceContent ic) {
50.1417 + super(ic);
50.1418 + this.ic = ic;
50.1419 + }
50.1420 +
50.1421 + protected @Override void beforeLookup(Template template) {
50.1422 + if (ic != null) {
50.1423 + ic.add(am);
50.1424 + ic = null;
50.1425 + }
50.1426 + }
50.1427 + }
50.1428 +
50.1429 + Before s = new Before();
50.1430 + doChangeOfNodeDoesNotFireChangeInActionMap(am, s, wrapBySimple, 1);
50.1431 +
50.1432 + assertNull("beforeLookup called once", s.ic);
50.1433 + }
50.1434 +
50.1435 + private void doChangeOfNodeDoesNotFireChangeInActionMap(final ActionMap am, Lookup actionMapLookup, final boolean wrapBySimple, int firstChange) {
50.1436 + Lookup[] lookups = { lookup, actionMapLookup };
50.1437 +
50.1438 + class Provider implements Lookup.Provider {
50.1439 + ProxyLookup delegate;
50.1440 + Lookup query;
50.1441 +
50.1442 + public Provider(Lookup[] arr) {
50.1443 + if (wrapBySimple) {
50.1444 + delegate = new ProxyLookup(arr);
50.1445 + query = Lookups.proxy(this);
50.1446 + } else {
50.1447 + query = delegate = new ProxyLookup(arr);
50.1448 + }
50.1449 + }
50.1450 +
50.1451 + public Lookup getLookup() {
50.1452 + return delegate;
50.1453 + }
50.1454 +
50.1455 + public void setLookups(Lookup... arr) {
50.1456 + if (wrapBySimple) {
50.1457 + delegate = new ProxyLookup(arr);
50.1458 + } else {
50.1459 + delegate.setLookups(arr);
50.1460 + }
50.1461 + }
50.1462 + }
50.1463 +
50.1464 + Provider p = new Provider(lookups);
50.1465 +
50.1466 + Lookup.Result res = p.query.lookup(new Lookup.Template(ActionMap.class));
50.1467 + LL ll = new LL();
50.1468 + res.addLookupListener(ll);
50.1469 +
50.1470 + Collection c = res.allInstances();
50.1471 + assertFalse("Has next", c.isEmpty());
50.1472 +
50.1473 + ActionMap am1 = (ActionMap)c.iterator().next();
50.1474 + assertEquals("Am is there", am, am1);
50.1475 +
50.1476 + assertEquals("Correct # of changes in first get", firstChange, ll.getCount());
50.1477 +
50.1478 + Object m1 = new InputMap();
50.1479 + Object m2 = new InputMap();
50.1480 +
50.1481 + ic.add(m1);
50.1482 + assertEquals("No change in ActionMap 1", 0, ll.getCount());
50.1483 + ic.set(Collections.singletonList(m2), null);
50.1484 + assertEquals("No change in ActionMap 2", 0, ll.getCount());
50.1485 + ic.add(m2);
50.1486 + assertEquals("No change in ActionMap 3", 0, ll.getCount());
50.1487 + p.setLookups(lookup, actionMapLookup, Lookup.EMPTY);
50.1488 + assertEquals("No change in ActionMap 4", 0, ll.getCount());
50.1489 +
50.1490 + ActionMap am2 = p.query.lookup(ActionMap.class);
50.1491 + assertEquals("Still the same action map", am, am2);
50.1492 +
50.1493 +
50.1494 + class Before extends AbstractLookup {
50.1495 + public InstanceContent ic;
50.1496 + public Before() {
50.1497 + this(new InstanceContent());
50.1498 + }
50.1499 +
50.1500 + private Before(InstanceContent ic) {
50.1501 + super(ic);
50.1502 + this.ic = ic;
50.1503 + }
50.1504 +
50.1505 + protected @Override void beforeLookup(Template template) {
50.1506 + if (ic != null) {
50.1507 + ic.add(am);
50.1508 + ic = null;
50.1509 + }
50.1510 + }
50.1511 + }
50.1512 +
50.1513 + Before s = new Before();
50.1514 +
50.1515 + // adding different Before, but returning the same instance
50.1516 + // this happens with metaInfServices lookup often, moreover
50.1517 + // it adds the instance in beforeLookup, which confuses a lot
50.1518 + p.setLookups(new Lookup[]{ lookup, new Before() });
50.1519 + assertEquals("No change in ActionMap 5", 0, ll.getCount());
50.1520 +
50.1521 +
50.1522 + }
50.1523 +
50.1524 + public void testTasklistsCase() throws Exception {
50.1525 + ic.remove(new Object());
50.1526 + }
50.1527 +
50.1528 +
50.1529 +
50.1530 + public void testMultipleListeners() {
50.1531 + Object object = new ImplementationObject();
50.1532 + ic.add(object);
50.1533 +
50.1534 + Listener[] listeners = new Listener[4];
50.1535 + Lookup.Result result = lookup.lookup(new Lookup.Template(LookupObject.class));
50.1536 + for(int i = 0; i < listeners.length; ++i) {
50.1537 + listeners[i] = new Listener();
50.1538 + result.addLookupListener(listeners[i]);
50.1539 + }
50.1540 + // initialize listening
50.1541 + result.allItems();
50.1542 +
50.1543 + ic.remove(object);
50.1544 +
50.1545 + // Apparently, only odd-numbered listeners get called when there are multiple LookupListeners on a result
50.1546 + //for(int i = 0; i < listeners.length; ++i) {
50.1547 + // System.out.println("Listener " + i + ": " + listeners[i].wasCalled());
50.1548 + //}
50.1549 + for(int i = 0; i < listeners.length; ++i) {
50.1550 + assertTrue("Listener " + i + " called", listeners[i].wasCalled());
50.1551 + }
50.1552 + }
50.1553 +
50.1554 + static Object reserialize(Object o) throws Exception {
50.1555 + ByteArrayOutputStream os = new ByteArrayOutputStream();
50.1556 + ObjectOutputStream oos = new ObjectOutputStream(os);
50.1557 + oos.writeObject(o);
50.1558 + oos.close();
50.1559 +
50.1560 + ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
50.1561 + ObjectInputStream ois = new ObjectInputStream(is);
50.1562 + return ois.readObject();
50.1563 + }
50.1564 +
50.1565 + private class Listener implements LookupListener {
50.1566 + private boolean listenerCalled = false;
50.1567 +
50.1568 + public void resultChanged(LookupEvent ev) {
50.1569 + listenerCalled = true;
50.1570 + }
50.1571 +
50.1572 + public boolean wasCalled() {
50.1573 + return listenerCalled;
50.1574 + }
50.1575 +
50.1576 + public void reset() {
50.1577 + listenerCalled = false;
50.1578 + }
50.1579 + }
50.1580 +
50.1581 + private interface LookupObject {}
50.1582 + private class ImplementationObject implements LookupObject {}
50.1583 + private class NullObject implements LookupObject {}
50.1584 +
50.1585 +
50.1586 + public void testReturnSomethingElseThenYouClaimYouWillReturn() {
50.1587 + class Liar extends AbstractLookup.Pair {
50.1588 + public Object obj;
50.1589 +
50.1590 + protected boolean instanceOf(Class c) {
50.1591 + return c.isAssignableFrom(String.class);
50.1592 + }
50.1593 +
50.1594 + protected boolean creatorOf(Object obj) {
50.1595 + return this.obj == obj;
50.1596 + }
50.1597 +
50.1598 + public Object getInstance() {
50.1599 + return this.obj;
50.1600 + }
50.1601 +
50.1602 + public Class getType() {
50.1603 + return String.class;
50.1604 + }
50.1605 +
50.1606 + public String getId() {
50.1607 + return String.class.getName();
50.1608 + }
50.1609 +
50.1610 + public String getDisplayName() {
50.1611 + return getId();
50.1612 + }
50.1613 + }
50.1614 +
50.1615 +
50.1616 + Liar l = new Liar();
50.1617 + l.obj = new Integer(5);
50.1618 +
50.1619 + this.ic.addPair(l);
50.1620 +
50.1621 + Collection c = lookup.lookup(new Lookup.Template(String.class)).allInstances();
50.1622 + assertTrue("It is empty: " + c, c.isEmpty());
50.1623 + }
50.1624 +
50.1625 + public void testCanProxyLookupHaveWrongResults() {
50.1626 + class L implements LookupListener {
50.1627 + ProxyLookup pl;
50.1628 + Lookup.Result<String> original;
50.1629 + Lookup.Result<String> wrapped;
50.1630 + boolean ok;
50.1631 +
50.1632 + public void test() {
50.1633 + pl = new ProxyLookup(lookup);
50.1634 + original = lookup.lookupResult(String.class);
50.1635 +
50.1636 + original.addLookupListener(this);
50.1637 +
50.1638 + wrapped = pl.lookupResult(String.class);
50.1639 +
50.1640 + assertEquals("Original empty", 0, original.allInstances().size());
50.1641 + assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
50.1642 +
50.1643 + ic.add("Hello!");
50.1644 + }
50.1645 +
50.1646 + public void resultChanged(LookupEvent ev) {
50.1647 + ok = true;
50.1648 +
50.1649 + assertEquals("Original has hello", 1, original.allInstances().size());
50.1650 + assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
50.1651 + }
50.1652 +
50.1653 + }
50.1654 + L listener = new L();
50.1655 + listener.test();
50.1656 + assertTrue("Listener called", listener.ok);
50.1657 + }
50.1658 +
50.1659 + public void testObjectFromInstanceContentConverterDisappearsIfNotReferenced() {
50.1660 + Conv converter = new Conv("foo");
50.1661 + ic.add (converter, converter);
50.1662 + Lookup lkp = instanceLookup;
50.1663 + StringBuilder sb = lookup.lookup (StringBuilder.class);
50.1664 + assertNotNull (sb);
50.1665 + int hash = System.identityHashCode(sb);
50.1666 + assertEquals ("foo", sb.toString());
50.1667 + Reference<StringBuilder> r = new WeakReference<StringBuilder>(sb);
50.1668 + sb = null;
50.1669 + assertGC("Lookup held onto object", r);
50.1670 + sb = lookup.lookup (StringBuilder.class);
50.1671 + assertNotSame(hash, System.identityHashCode(sb));
50.1672 + r = new WeakReference<StringBuilder>(sb);
50.1673 + sb = null;
50.1674 + assertGC("Lookup held onto object", r);
50.1675 + ic.remove (converter, converter);
50.1676 + Reference <InstanceContent.Convertor> cref = new WeakReference<InstanceContent.Convertor>(converter);
50.1677 + converter = null;
50.1678 + assertGC("Converter still referenced", cref);
50.1679 +
50.1680 + sb = lkp.lookup(StringBuilder.class);
50.1681 + assertNull ("Converter removed from lookup, but object it " +
50.1682 + "created still present:'" + sb +"'", sb);
50.1683 + converter = new Conv("bar");
50.1684 + ic.add (converter, converter);
50.1685 + assertNotNull (lkp.lookup(StringBuilder.class));
50.1686 + assertEquals ("bar", lkp.lookup(StringBuilder.class).toString());
50.1687 + }
50.1688 +
50.1689 + private static class Conv implements InstanceContent.Convertor<Conv, StringBuilder> {
50.1690 + private final String str;
50.1691 + private Conv (String str) {
50.1692 + this.str = str;
50.1693 + }
50.1694 +
50.1695 + public StringBuilder convert(Conv obj) {
50.1696 + return new StringBuilder (str);
50.1697 + }
50.1698 +
50.1699 + public Class<? extends StringBuilder> type(Conv obj) {
50.1700 + return StringBuilder.class;
50.1701 + }
50.1702 +
50.1703 + public String id(Conv obj) {
50.1704 + return "Foo";
50.1705 + }
50.1706 +
50.1707 + public String displayName(Conv obj) {
50.1708 + return "Foo";
50.1709 + }
50.1710 + } // end of Conv
50.1711 +
50.1712 + public void testCanGCResults() throws Exception {
50.1713 + class L implements LookupListener {
50.1714 + int cnt;
50.1715 +
50.1716 + public void resultChanged(LookupEvent ev) {
50.1717 + cnt++;
50.1718 + }
50.1719 +
50.1720 + }
50.1721 + L listener1 = new L();
50.1722 + L listener2 = new L();
50.1723 +
50.1724 + Lookup.Result<String> res1 = this.instanceLookup.lookupResult(String.class);
50.1725 + Lookup.Result<String> res2 = this.lookup.lookupResult(String.class);
50.1726 +
50.1727 + assertEquals("Empty1", 0, res1.allItems().size());
50.1728 + assertEquals("Empty2", 0, res2.allItems().size());
50.1729 +
50.1730 + res1.addLookupListener(listener1);
50.1731 + res2.addLookupListener(listener2);
50.1732 +
50.1733 + addInstances(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
50.1734 + this.ic.add("Ahoj");
50.1735 +
50.1736 + assertEquals("Change1", 1, listener1.cnt);
50.1737 + assertEquals("Change2", 1, listener2.cnt);
50.1738 +
50.1739 + assertEquals("Full1", 1, res1.allItems().size());
50.1740 + assertEquals("Full2", 1, res2.allItems().size());
50.1741 +
50.1742 +
50.1743 + Reference<Object> ref2 = new WeakReference<Object>(res2);
50.1744 + res2 = null;
50.1745 + assertGC("Result can disappear", ref2);
50.1746 + }
50.1747 +
50.1748 + void beforeActualTest(String n) {
50.1749 + if (n.equals("testEqualsIsNotCalledTooMuch")) {
50.1750 + CntPair.cnt = 0;
50.1751 + CntPair.hashCnt = 0;
50.1752 + CntPair.instances = 0;
50.1753 + int how = 1000;
50.1754 +
50.1755 + for(int i = 0; i < how; i++) {
50.1756 + this.ic.addPair(new CntPair("x" + i));
50.1757 + }
50.1758 +
50.1759 + assertEquals("No equals called", 0, CntPair.cnt);
50.1760 + assertEquals("1000 instances ", how, CntPair.instances);
50.1761 + }
50.1762 + }
50.1763 +
50.1764 + public void testEqualsIsNotCalledTooMuch() throws Exception {
50.1765 + // most of the work done in beforeActualTest
50.1766 +
50.1767 + // desirable: assertEquals("no comparitions", 0, CntPair.cnt);
50.1768 + // works for InheritanceTree, but not for ArrayStorage, but array
50.1769 + // storages are generally small
50.1770 +
50.1771 + if (CntPair.cnt > 12000) {
50.1772 + fail("Too much comparitions " + CntPair.cnt);
50.1773 + }
50.1774 + if (CntPair.hashCnt > 40000) {
50.1775 + fail("Too much hashes: " + CntPair.hashCnt);
50.1776 + }
50.1777 +
50.1778 + assertEquals("instaces is enough", 1000, CntPair.instances);
50.1779 + }
50.1780 +
50.1781 + /** Adds instances to the instance lookup.
50.1782 + */
50.1783 + private void addInstances (Object... instances) {
50.1784 + for (int i = 0; i < instances.length; i++) {
50.1785 + ic.add(instances[i]);
50.1786 + }
50.1787 + }
50.1788 +
50.1789 + /** Count instances of clazz in an array. */
50.1790 + private int countInstances (Object[] objs, Class clazz) {
50.1791 + int count = 0;
50.1792 + for (int i = 0; i < objs.length; i++) {
50.1793 + if (clazz.isInstance(objs[i])) count++;
50.1794 + }
50.1795 + return count;
50.1796 + }
50.1797 +
50.1798 + /** Counting listener */
50.1799 + protected static class LL implements LookupListener {
50.1800 + private int count = 0;
50.1801 + public Object source;
50.1802 + public Thread changesIn;
50.1803 +
50.1804 + public LL () {
50.1805 + this (null);
50.1806 + }
50.1807 +
50.1808 + public LL (Object source) {
50.1809 + this.source = source;
50.1810 + }
50.1811 +
50.1812 + public void resultChanged(LookupEvent ev) {
50.1813 + if (changesIn != null) {
50.1814 + assertEquals("Changes in the same thread", changesIn, Thread.currentThread());
50.1815 + } else {
50.1816 + changesIn = Thread.currentThread();
50.1817 + }
50.1818 + ++count;
50.1819 + if (source != null) {
50.1820 + assertSame ("Source is the same", source, ev.getSource ());
50.1821 +// assertSame ("Result is the same", source, ev.getResult ());
50.1822 + }
50.1823 + }
50.1824 +
50.1825 + public int getCount() {
50.1826 + int i = count;
50.1827 + count = 0;
50.1828 + return i;
50.1829 + }
50.1830 + };
50.1831 +
50.1832 + /** A set of interfaces for testInterfaceInheritance
50.1833 + */
50.1834 + interface TestInterfaceInheritanceA {}
50.1835 + interface TestInterfaceInheritanceB extends TestInterfaceInheritanceA, java.rmi.Remote {}
50.1836 + interface TestInterfaceInheritanceBB extends TestInterfaceInheritanceB {}
50.1837 + interface TestInterfaceInheritanceC extends TestInterfaceInheritanceA, java.rmi.Remote {}
50.1838 + interface TestInterfaceInheritanceD extends TestInterfaceInheritanceA {}
50.1839 +
50.1840 + /** A special class for garbage test */
50.1841 + public static final class Garbage extends Object implements Serializable {
50.1842 + static final long serialVersionUID = 435340912534L;
50.1843 + }
50.1844 +
50.1845 +
50.1846 + /* A classloader that can load one class in a special way */
50.1847 + private static class CL extends ClassLoader {
50.1848 + public CL () {
50.1849 + super (null);
50.1850 + }
50.1851 +
50.1852 + public @Override Class findClass(String name) throws ClassNotFoundException {
50.1853 + if (name.equals (Garbage.class.getName ())) {
50.1854 + String n = name.replace ('.', '/');
50.1855 + java.io.InputStream is = getClass ().getResourceAsStream ("/" + n + ".class");
50.1856 + byte[] arr = new byte[8096];
50.1857 + try {
50.1858 + int cnt = is.read (arr);
50.1859 + if (cnt == arr.length) {
50.1860 + fail ("Buffer to load the class is not big enough");
50.1861 + }
50.1862 +
50.1863 + return defineClass (name, arr, 0, cnt);
50.1864 + } catch (java.io.IOException ex) {
50.1865 + ex.printStackTrace();
50.1866 + fail ("IO Exception");
50.1867 + return null;
50.1868 + }
50.1869 + } else {
50.1870 + return null;
50.1871 + }
50.1872 + }
50.1873 +
50.1874 + /** Convert obj to other object. There is no need to implement
50.1875 + * cache mechanism. It is provided by AbstractLookup.Item.getInstance().
50.1876 + * Method should be called more than once because Lookup holds
50.1877 + * just weak reference.
50.1878 + */
50.1879 + public Object convert(Object obj) {
50.1880 + return null;
50.1881 + }
50.1882 +
50.1883 + /** Return type of converted object. */
50.1884 + public Class type(Object obj) {
50.1885 + try {
50.1886 + return loadClass (Garbage.class.getName ());
50.1887 + } catch (ClassNotFoundException ex) {
50.1888 + fail ("Class not found");
50.1889 + throw new InternalError ();
50.1890 + }
50.1891 + }
50.1892 + }
50.1893 +
50.1894 + private static final class CntPair extends AbstractLookup.Pair {
50.1895 + private static int instances;
50.1896 + private String txt;
50.1897 +
50.1898 + public CntPair(String txt) {
50.1899 + this.txt = txt;
50.1900 + instances++;
50.1901 + }
50.1902 +
50.1903 + public static int hashCnt;
50.1904 + @Override
50.1905 + public int hashCode() {
50.1906 + hashCnt++;
50.1907 + return txt.hashCode() + 3777;
50.1908 + }
50.1909 +
50.1910 + public static int cnt;
50.1911 + @Override
50.1912 + public boolean equals(Object obj) {
50.1913 + cnt++;
50.1914 +
50.1915 + if (obj == null) {
50.1916 + return false;
50.1917 + }
50.1918 + if (getClass() != obj.getClass()) {
50.1919 + return false;
50.1920 + }
50.1921 + final CntPair other = (CntPair) obj;
50.1922 + if (this.txt != other.txt && (this.txt == null || !this.txt.equals(other.txt))) {
50.1923 + return false;
50.1924 + }
50.1925 + return true;
50.1926 + }
50.1927 +
50.1928 + protected boolean instanceOf(Class c) {
50.1929 + return c.isAssignableFrom(String.class);
50.1930 + }
50.1931 +
50.1932 + protected boolean creatorOf(Object obj) {
50.1933 + return obj == txt;
50.1934 + }
50.1935 +
50.1936 + public Object getInstance() {
50.1937 + return txt;
50.1938 + }
50.1939 +
50.1940 + public Class getType() {
50.1941 + return String.class;
50.1942 + }
50.1943 +
50.1944 + public String getId() {
50.1945 + return txt;
50.1946 + }
50.1947 +
50.1948 + public String getDisplayName() {
50.1949 + return txt;
50.1950 + }
50.1951 +
50.1952 + }
50.1953 +
50.1954 + public static final class SerialPair extends AbstractLookup.Pair
50.1955 + implements java.io.Serializable {
50.1956 + static final long serialVersionUID = 54305834L;
50.1957 + private Object value;
50.1958 + public transient int countInstanceOf;
50.1959 +
50.1960 + public SerialPair (Object value) {
50.1961 + this.value = value;
50.1962 + }
50.1963 +
50.1964 + protected boolean creatorOf(Object obj) {
50.1965 + return obj == value;
50.1966 + }
50.1967 +
50.1968 + public String getDisplayName() {
50.1969 + return getId ();
50.1970 + }
50.1971 +
50.1972 + public String getId() {
50.1973 + return value.toString();
50.1974 + }
50.1975 +
50.1976 + public Object getInstance() {
50.1977 + return value;
50.1978 + }
50.1979 +
50.1980 + public Class getType() {
50.1981 + return value.getClass ();
50.1982 + }
50.1983 +
50.1984 + protected boolean instanceOf(Class c) {
50.1985 + countInstanceOf++;
50.1986 + return c.isInstance(value);
50.1987 + }
50.1988 + } // end of SerialPair
50.1989 +
50.1990 + private static class BrokenPair extends AbstractLookup.Pair {
50.1991 + private transient ThreadLocal IN = new ThreadLocal ();
50.1992 + private boolean checkModify;
50.1993 + private boolean checkQuery;
50.1994 +
50.1995 + public BrokenPair (boolean checkModify, boolean checkQuery) {
50.1996 + this.checkModify = checkModify;
50.1997 + this.checkQuery = checkQuery;
50.1998 + }
50.1999 +
50.2000 + protected boolean creatorOf(Object obj) { return this == obj; }
50.2001 + public String getDisplayName() { return "Broken"; }
50.2002 + public String getId() { return "broken"; }
50.2003 + public Object getInstance() { return this; }
50.2004 + public Class getType() { return getClass (); }
50.2005 + protected boolean instanceOf(Class c) {
50.2006 +
50.2007 + if (checkQuery) {
50.2008 + if (IN.get () == null) {
50.2009 + try {
50.2010 + IN.set (this);
50.2011 + // broken behaviour, tries to modify the lookup
50.2012 + // queries have to survive
50.2013 +
50.2014 + running.lookup.lookup (java.awt.List.class);
50.2015 +
50.2016 + //
50.2017 + // creation of new result has to survive as well
50.2018 + Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.Button.class));
50.2019 + Collection all = myQuery.allItems ();
50.2020 + } finally {
50.2021 + IN.set (null);
50.2022 + }
50.2023 + }
50.2024 + }
50.2025 +
50.2026 +
50.2027 + if (checkModify) {
50.2028 + //
50.2029 + // modifications should fail
50.2030 + //
50.2031 +
50.2032 + try {
50.2033 + running.ic.addPair (new SerialPair (""));
50.2034 + fail ("Modification from a query should be prohibited");
50.2035 + } catch (IllegalStateException ex) {
50.2036 + }
50.2037 +
50.2038 + try {
50.2039 + running.ic.removePair (this);
50.2040 + fail ("This has to throw the exception");
50.2041 + } catch (IllegalStateException ex) {
50.2042 + }
50.2043 + try {
50.2044 + running.ic.setPairs (Collections.EMPTY_SET);
50.2045 + fail ("This has to throw the exception as well");
50.2046 + } catch (IllegalStateException ex) {
50.2047 + }
50.2048 + }
50.2049 +
50.2050 + return c.isAssignableFrom(getType ());
50.2051 + }
50.2052 + } // end of BrokenPair
50.2053 +
50.2054 + private static class Broken2Pair extends AbstractLookup.Pair {
50.2055 + static final long serialVersionUID = 4532587018501L;
50.2056 + public transient ThreadLocal IN;
50.2057 +
50.2058 + public Broken2Pair () {
50.2059 + }
50.2060 +
50.2061 + private void writeObject (java.io.ObjectOutputStream oos) throws java.io.IOException {
50.2062 + }
50.2063 +
50.2064 + private void readObject (java.io.ObjectInputStream ois) throws java.io.IOException, ClassNotFoundException {
50.2065 + IN = new ThreadLocal ();
50.2066 + }
50.2067 +
50.2068 + protected boolean creatorOf(Object obj) { return this == obj; }
50.2069 + public String getDisplayName() { return "Broken"; }
50.2070 + public String getId() { return "broken"; }
50.2071 + public Object getInstance() { return this; }
50.2072 + public Class getType() { return getClass (); }
50.2073 + protected boolean instanceOf(Class c) {
50.2074 +
50.2075 + // behaviour gets broken only after deserialization
50.2076 + if (IN != null && IN.get () == null) {
50.2077 + try {
50.2078 + IN.set (this);
50.2079 +
50.2080 + // creation of new result has to survive as well
50.2081 + Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.List.class));
50.2082 + Collection all = myQuery.allItems ();
50.2083 + } finally {
50.2084 + IN.set (null);
50.2085 + }
50.2086 + }
50.2087 +
50.2088 + return c.isAssignableFrom(getType ());
50.2089 + }
50.2090 + } // end of Broken2Pair
50.2091 +}
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/AbstractLookupExecutorTest.java Mon Dec 14 20:58:39 2009 +0100
51.3 @@ -0,0 +1,98 @@
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.util.concurrent.Executor;
51.48 +import org.openide.util.Lookup;
51.49 +import org.openide.util.LookupEvent;
51.50 +import org.openide.util.LookupListener;
51.51 +
51.52 +public class AbstractLookupExecutorTest extends AbstractLookupBaseHid
51.53 +implements AbstractLookupBaseHid.Impl, Executor, LookupListener {
51.54 + Lookup.Result<?> res;
51.55 +
51.56 +
51.57 + public AbstractLookupExecutorTest(java.lang.String testName) {
51.58 + super(testName, null);
51.59 + }
51.60 +
51.61 + //
51.62 + // Impl of AbstractLookupBaseHid.Impl
51.63 + //
51.64 +
51.65 + /** Creates the initial abstract lookup.
51.66 + */
51.67 + public Lookup createInstancesLookup (InstanceContent ic) {
51.68 + ic.attachExecutor(this);
51.69 + Lookup l = new AbstractLookup (ic, new InheritanceTree ());
51.70 + return l;
51.71 + }
51.72 +
51.73 + /** Creates an lookup for given lookup. This class just returns
51.74 + * the object passed in, but subclasses can be different.
51.75 + * @param lookup in lookup
51.76 + * @return a lookup to use
51.77 + */
51.78 + public Lookup createLookup (Lookup lookup) {
51.79 + res = lookup.lookupResult(Object.class);
51.80 + res.addLookupListener(this);
51.81 + return lookup;
51.82 + }
51.83 +
51.84 + public void clearCaches () {
51.85 + }
51.86 +
51.87 + ThreadLocal<Object> ME = new ThreadLocal<Object>();
51.88 + public void execute(Runnable command) {
51.89 + assertEquals("Not yet set", null, ME.get());
51.90 + ME.set(this);
51.91 + try {
51.92 + command.run();
51.93 + } finally {
51.94 + ME.set(null);
51.95 + }
51.96 + }
51.97 +
51.98 + public void resultChanged(LookupEvent ev) {
51.99 + assertEquals("Changes delivered only from execute method", this, ME.get());
51.100 + }
51.101 +}
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/AbstractLookupMemoryTest.java Mon Dec 14 20:58:39 2009 +0100
52.3 @@ -0,0 +1,158 @@
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.util.*;
52.48 +import org.netbeans.junit.*;
52.49 +import org.netbeans.modules.openide.util.ActiveQueue;
52.50 +import org.openide.util.Lookup;
52.51 +
52.52 +/** Testing memory consumption of various AbstractLookup aspects.
52.53 + */
52.54 +public class AbstractLookupMemoryTest extends NbTestCase {
52.55 + public AbstractLookupMemoryTest(java.lang.String testName) {
52.56 + super(testName);
52.57 + }
52.58 +
52.59 + public static void main(java.lang.String[] args) {
52.60 + junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupMemoryTest.class));
52.61 + }
52.62 +
52.63 + public void testEmptySize () {
52.64 + AbstractLookup instanceLookup = new AbstractLookup ();
52.65 + assertSize ("Empty lookup should be small", 16, instanceLookup);
52.66 +
52.67 + InstanceContent ic = new InstanceContent ();
52.68 + instanceLookup = new AbstractLookup (ic);
52.69 + assertSize ("Lookup with InstanceContent should be small as well", 16, instanceLookup);
52.70 + }
52.71 +
52.72 + public void testPairSize () {
52.73 + AbstractLookup.Pair pair = new EmptyPair ();
52.74 + assertSize ("Pair occupies only 16 bytes", 16, pair);
52.75 + }
52.76 +
52.77 + public void testPairWithOnePointerSize () {
52.78 + AbstractLookup.Pair pair = new OneItemPair ();
52.79 + assertSize ("Pair occupies only 16 bytes", 16, pair);
52.80 + }
52.81 +
52.82 + public void testLookupWithPairs () {
52.83 + Lookup.Template<Object> t = new Lookup.Template<Object>(Object.class);
52.84 + class L implements org.openide.util.LookupListener {
52.85 + public int cnt;
52.86 + public void resultChanged (org.openide.util.LookupEvent ev) {
52.87 + cnt++;
52.88 + }
52.89 + }
52.90 + L listener = new L ();
52.91 + L listener2 = new L ();
52.92 +
52.93 + EmptyPair[] pairs = {
52.94 + new EmptyPair(),
52.95 + new EmptyPair(),
52.96 + new EmptyPair(),
52.97 + new EmptyPair(),
52.98 + };
52.99 + Object[] ignore = {
52.100 + pairs[0],
52.101 + pairs[1],
52.102 + pairs[2],
52.103 + pairs[3],
52.104 + t,
52.105 + ActiveQueue.queue(),
52.106 + listener,
52.107 + listener2,
52.108 + new Integer (11) // trashhold is shared
52.109 + };
52.110 +
52.111 + AbstractLookup.Content c = new AbstractLookup.Content ();
52.112 + AbstractLookup l = new AbstractLookup (c, (Integer)ignore[ignore.length - 1]);
52.113 +
52.114 + c.addPair ((EmptyPair)ignore[0]);
52.115 + assertSize ("Should be really small (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
52.116 +
52.117 + c.addPair ((EmptyPair)ignore[1]);
52.118 + assertSize ("Is bigger I guess (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
52.119 +
52.120 + c.setPairs(Arrays.asList(pairs).subList(0, 3));
52.121 + assertSize ("Even bigger (not counting the pair sizes)", Collections.singleton (l), 64, ignore);
52.122 +
52.123 + c.setPairs(Arrays.asList(pairs).subList(0, 4));
52.124 + assertSize ("Now not that much(not counting the pair sizes)", Collections.singleton (l), 64, ignore);
52.125 +
52.126 + Lookup.Result res = l.lookup (t);
52.127 +
52.128 + assertSize ("After creating a result", Collections.singleton (l), 120, ignore);
52.129 +
52.130 + res.addLookupListener (listener);
52.131 +
52.132 + assertSize ("And attaching one listener", Collections.singleton (l), 120, ignore);
52.133 +
52.134 + res.addLookupListener (listener2);
52.135 + assertSize ("Second listener makes the situation much worse", Collections.singleton (l), 200, ignore);
52.136 + res.removeLookupListener(listener2);
52.137 + assertSize ("But removing it returns us back to original size", Collections.singleton (l), 120, ignore);
52.138 +
52.139 +
52.140 + assertEquals ("Current for pairs are in", res.allItems ().size (), 4); // also activates the listener
52.141 + assertSize ("and making the listener to work", Collections.singleton (l), 120, ignore);
52.142 +
52.143 + c.removePair ((EmptyPair)ignore[0]);
52.144 + assertEquals ("A changes has been delivered", 1, listener.cnt);
52.145 + }
52.146 +
52.147 + /** Simple pair with no data */
52.148 + private static class EmptyPair extends AbstractLookup.Pair {
52.149 + protected boolean creatorOf(Object obj) { return false; }
52.150 + public String getDisplayName() { return ""; }
52.151 + public String getId() { return ""; }
52.152 + public Object getInstance() { return null; }
52.153 + public Class getType() { return Object.class; }
52.154 + protected boolean instanceOf(Class c) { return c == getType (); }
52.155 + } // end of EmptyPair
52.156 +
52.157 + /** Pair with one item (like InstanceContent.Pair) */
52.158 + private static class OneItemPair extends EmptyPair {
52.159 + private Object pointer;
52.160 + }
52.161 +}
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/AbstractLookupTest.java Mon Dec 14 20:58:39 2009 +0100
53.3 @@ -0,0 +1,353 @@
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 +import java.util.concurrent.ExecutionException;
53.48 +
53.49 +import java.lang.ref.WeakReference;
53.50 +import java.util.*;
53.51 +import java.util.concurrent.Executors;
53.52 +import java.util.concurrent.TimeUnit;
53.53 +import junit.framework.Test;
53.54 +import org.netbeans.junit.*;
53.55 +import org.openide.util.Lookup;
53.56 +import org.openide.util.lookup.AbstractLookup.Pair;
53.57 +
53.58 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
53.59 +public class AbstractLookupTest extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
53.60 + public AbstractLookupTest(java.lang.String testName) {
53.61 + super(testName, null);
53.62 + }
53.63 +
53.64 + //
53.65 + // Impl of AbstractLookupBaseHid.Impl
53.66 + //
53.67 +
53.68 + /** Creates the initial abstract lookup.
53.69 + */
53.70 + public Lookup createInstancesLookup (InstanceContent ic) {
53.71 + return new AbstractLookup (ic, new InheritanceTree ());
53.72 + }
53.73 +
53.74 + /** Creates an lookup for given lookup. This class just returns
53.75 + * the object passed in, but subclasses can be different.
53.76 + * @param lookup in lookup
53.77 + * @return a lookup to use
53.78 + */
53.79 + public Lookup createLookup (Lookup lookup) {
53.80 + return lookup;
53.81 + }
53.82 +
53.83 + public void clearCaches () {
53.84 + }
53.85 +
53.86 + static class LkpResultCanBeGargageCollectedAndClearsTheResult extends AbstractLookup {
53.87 + public int cleared;
53.88 + public int dirty;
53.89 +
53.90 + synchronized @Override boolean cleanUpResult(Template t) {
53.91 + boolean res = super.cleanUpResult (t);
53.92 + if (res) {
53.93 + cleared++;
53.94 + } else {
53.95 + dirty++;
53.96 + }
53.97 +
53.98 + notifyAll ();
53.99 +
53.100 + return res;
53.101 + }
53.102 + }
53.103 + public void testResultCanBeGargageCollectedAndClearsTheResult () throws Exception {
53.104 + LkpResultCanBeGargageCollectedAndClearsTheResult lkp = new LkpResultCanBeGargageCollectedAndClearsTheResult ();
53.105 + assertSize ("24 for AbstractLookup, 8 for two ints", 32, lkp);
53.106 + synchronized (lkp) {
53.107 + Lookup.Result res = lkp.lookup (new Lookup.Template (getClass ()));
53.108 + res.allItems();
53.109 +
53.110 + WeakReference ref = new WeakReference (res);
53.111 + res = null;
53.112 + assertGC ("Reference can get cleared", ref);
53.113 +
53.114 + // wait till we
53.115 + while (lkp.cleared == 0 && lkp.dirty == 0) {
53.116 + lkp.wait ();
53.117 + }
53.118 +
53.119 + assertEquals ("No dirty cleanups", 0, lkp.dirty);
53.120 + assertEquals ("One final cleanup", 1, lkp.cleared);
53.121 + }
53.122 + //assertSize ("Everything has been cleaned to original size", 32, lkp);
53.123 +
53.124 + }
53.125 +
53.126 + public void testPairCannotBeUsedInMoreThanOneLookupAtOnce () throws Exception {
53.127 + /** Simple pair with no data */
53.128 + class EmptyPair extends AbstractLookup.Pair {
53.129 + protected boolean creatorOf(Object obj) { return false; }
53.130 + public String getDisplayName() { return "Empty"; }
53.131 + public String getId() { return "empty"; }
53.132 + public Object getInstance() { return null; }
53.133 + public Class getType() { return Object.class; }
53.134 + protected boolean instanceOf(Class c) { return c == getType (); }
53.135 + } // end of EmptyPair
53.136 +
53.137 + AbstractLookup.Content c1 = new AbstractLookup.Content ();
53.138 + AbstractLookup.Content c2 = new AbstractLookup.Content ();
53.139 + AbstractLookup l1 = new AbstractLookup (c1);
53.140 + AbstractLookup l2 = new AbstractLookup (c2);
53.141 +
53.142 + EmptyPair empty = new EmptyPair ();
53.143 + c1.addPair (empty);
53.144 + Lookup.Result res = l1.lookup (new Lookup.Template (Object.class));
53.145 + assertEquals (
53.146 + "Pair is really found", empty,
53.147 + res.allItems ().iterator().next ()
53.148 + );
53.149 + try {
53.150 + c2.addPair (empty);
53.151 + fail ("It should not be possible to add pair to two lookups");
53.152 + } catch (IllegalStateException ex) {
53.153 + // ok, exception is fine
53.154 + }
53.155 + assertEquals (
53.156 + "L2 is still empty", Collections.EMPTY_LIST,
53.157 + new ArrayList (l2.lookup (new Lookup.Template (Object.class)).allItems ())
53.158 + );
53.159 + }
53.160 +
53.161 + public void testInitializationCanBeDoneFromAnotherThread () {
53.162 + class MyLkp extends AbstractLookup implements Runnable {
53.163 + private InstanceContent ic;
53.164 + private boolean direct;
53.165 +
53.166 + public MyLkp (boolean direct) {
53.167 + this (direct, new InstanceContent ());
53.168 + }
53.169 +
53.170 + private MyLkp (boolean direct, InstanceContent ic) {
53.171 + super (ic);
53.172 + this.direct = direct;
53.173 + this.ic = ic;
53.174 + }
53.175 +
53.176 + protected @Override void initialize() {
53.177 + if (direct) {
53.178 + run ();
53.179 + } else {
53.180 + try {
53.181 + Executors.newSingleThreadScheduledExecutor().schedule(this, 0, TimeUnit.MICROSECONDS).get();
53.182 + } catch (InterruptedException ex) {
53.183 + ex.printStackTrace();
53.184 + } catch (ExecutionException ex) {
53.185 + ex.printStackTrace();
53.186 + }
53.187 + }
53.188 + }
53.189 +
53.190 + public void run () {
53.191 + ic.add (this);
53.192 + ic.remove (this);
53.193 + ic.set (Collections.nCopies(10, this), null);
53.194 + ic.set (Collections.EMPTY_LIST, null);
53.195 + ic.add (AbstractLookupTest.this);
53.196 + }
53.197 + }
53.198 +
53.199 + assertEquals ("The test should be there", this, new MyLkp (true).lookup (Object.class));
53.200 + assertEquals ("and in async mode as well", this, new MyLkp (false).lookup (Object.class));
53.201 + }
53.202 +
53.203 + public void testBeforeLookupIsCalled () {
53.204 + class BeforeL extends AbstractLookup {
53.205 + public ArrayList list = new ArrayList ();
53.206 + public String toAdd;
53.207 + public InstanceContent ic;
53.208 +
53.209 + public BeforeL () {
53.210 + this (new InstanceContent ());
53.211 + }
53.212 +
53.213 + private BeforeL (InstanceContent c) {
53.214 + super (c);
53.215 + this.ic = c;
53.216 + }
53.217 +
53.218 + protected @Override void beforeLookup(Template t) {
53.219 + if (toAdd != null) {
53.220 + list.add (0, new SerialPair (toAdd));
53.221 + setPairs (list);
53.222 + } else {
53.223 + ic.add (new Integer (1));
53.224 + }
53.225 + }
53.226 + }
53.227 +
53.228 + BeforeL lookup = new BeforeL ();
53.229 +
53.230 + lookup.toAdd = "First";
53.231 + assertEquals ("First if found", "First", lookup.lookup (String.class));
53.232 +
53.233 + lookup.toAdd = "2";
53.234 + assertEquals ("2 is not first", "2", lookup.lookup (String.class));
53.235 +
53.236 + Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
53.237 + for (int i = 3; i < 20; i++) {
53.238 + lookup.toAdd = String.valueOf (i);
53.239 + assertEquals (i + " items are now there", i, res.allInstances ().size ());
53.240 + }
53.241 + for (int i = 20; i < 35; i++) {
53.242 + lookup.toAdd = String.valueOf (i);
53.243 + assertEquals (i + " items are now there", i, res.allItems ().size ());
53.244 + }
53.245 +
53.246 + assertEquals ("Just strings are there now", 1, res.allClasses ().size ());
53.247 + lookup.toAdd = null; // this will add integer
53.248 + assertEquals ("Two classes now", 2, res.allClasses ().size ());
53.249 + }
53.250 +
53.251 + public void testInconsistentAfterDeserIssue71744() throws Exception {
53.252 + InheritanceTree inhTree = new InheritanceTree();
53.253 +
53.254 + AbstractLookup al = new AbstractLookup(new AbstractLookup.Content(), inhTree);
53.255 + {
53.256 +
53.257 + Collection r = al.lookup(new Lookup.Template(Integer.class)).allInstances();
53.258 + assertEquals("None", 0, r.size());
53.259 + }
53.260 +
53.261 + ICP item = new ICP(new Integer(10));
53.262 + al.addPair(item);
53.263 + al.removePair(item);
53.264 +
53.265 + AbstractLookup newLookup = (AbstractLookup)reserialize(al);
53.266 +
53.267 + newLookup.lookup(Number.class);
53.268 +
53.269 +
53.270 + newLookup.addPair(new ICP(new Long(20)));
53.271 +
53.272 + {
53.273 +
53.274 + Collection r = newLookup.lookup(new Lookup.Template(Number.class)).allInstances();
53.275 + assertEquals("one", 1, r.size());
53.276 +/*
53.277 + Iterator it = r.iterator();
53.278 + assertEquals(new Integer(10), it.next());
53.279 + assertEquals(new Long(20), it.next());*/
53.280 + }
53.281 + }
53.282 +
53.283 + public void testMatchesIssue130673() {
53.284 + class BrokenPairReturningNullID extends Pair<Object> {
53.285 + @Override
53.286 + protected boolean instanceOf(Class<?> c) {
53.287 + return false;
53.288 + }
53.289 +
53.290 + @Override
53.291 + protected boolean creatorOf(Object obj) {
53.292 + return false;
53.293 + }
53.294 +
53.295 + @Override
53.296 + public Object getInstance() {
53.297 + return null;
53.298 + }
53.299 +
53.300 + @Override
53.301 + public Class<? extends Object> getType() {
53.302 + return null;
53.303 + }
53.304 +
53.305 + @Override
53.306 + public String getId() {
53.307 + return null;
53.308 + }
53.309 +
53.310 + @Override
53.311 + public String getDisplayName() {
53.312 + return null;
53.313 + }
53.314 + }
53.315 + BrokenPairReturningNullID broken = new BrokenPairReturningNullID();
53.316 +
53.317 +
53.318 + Lookup.Template<String> t = new Lookup.Template<String>(String.class, "ID", null);
53.319 + boolean not = AbstractLookup.matches(t, broken, true);
53.320 + assertFalse("Does not match the template, but throws no exception", not);
53.321 + }
53.322 +
53.323 + private static final class ICP extends AbstractLookup.Pair {
53.324 + private Number s;
53.325 +
53.326 + public ICP (Number s) {
53.327 + this.s = s;
53.328 + }
53.329 +
53.330 +
53.331 + protected boolean instanceOf(Class c) {
53.332 + return c.isInstance(s);
53.333 + }
53.334 +
53.335 + protected boolean creatorOf(Object obj) {
53.336 + return s == obj;
53.337 + }
53.338 +
53.339 + public Object getInstance() {
53.340 + return s;
53.341 + }
53.342 +
53.343 + public Class getType() {
53.344 + return s.getClass();
53.345 + }
53.346 +
53.347 + public String getId() {
53.348 + return s.toString();
53.349 + }
53.350 +
53.351 + public String getDisplayName() {
53.352 + return getId();
53.353 + }
53.354 +
53.355 + }
53.356 +}
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/ExcludingLookupTest.java Mon Dec 14 20:58:39 2009 +0100
54.3 @@ -0,0 +1,228 @@
54.4 +/*
54.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
54.6 + *
54.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
54.8 + *
54.9 + * The contents of this file are subject to the terms of either the GNU
54.10 + * General Public License Version 2 only ("GPL") or the Common
54.11 + * Development and Distribution License("CDDL") (collectively, the
54.12 + * "License"). You may not use this file except in compliance with the
54.13 + * License. You can obtain a copy of the License at
54.14 + * http://www.netbeans.org/cddl-gplv2.html
54.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
54.16 + * specific language governing permissions and limitations under the
54.17 + * License. When distributing the software, include this License Header
54.18 + * Notice in each file and include the License file at
54.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
54.20 + * particular file as subject to the "Classpath" exception as provided
54.21 + * by Sun in the GPL Version 2 section of the License file that
54.22 + * accompanied this code. If applicable, add the following below the
54.23 + * License Header, with the fields enclosed by brackets [] replaced by
54.24 + * your own identifying information:
54.25 + * "Portions Copyrighted [year] [name of copyright owner]"
54.26 + *
54.27 + * Contributor(s):
54.28 + *
54.29 + * The Original Software is NetBeans. The Initial Developer of the Original
54.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
54.31 + * Microsystems, Inc. All Rights Reserved.
54.32 + *
54.33 + * If you wish your version of this file to be governed by only the CDDL
54.34 + * or only the GPL Version 2, indicate your decision by adding
54.35 + * "[Contributor] elects to include this software in this distribution
54.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
54.37 + * single choice of license, a recipient has the option to distribute
54.38 + * your version of this file under either the CDDL, the GPL Version 2 or
54.39 + * to extend the choice of license to its licensees as provided above.
54.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
54.41 + * Version 2 license, then the option applies only if the new code is
54.42 + * made subject to such option by the copyright holder.
54.43 + */
54.44 +
54.45 +package org.openide.util.lookup;
54.46 +
54.47 +import java.util.*;
54.48 +import org.openide.util.Lookup;
54.49 +
54.50 +/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
54.51 + */
54.52 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
54.53 +public class ExcludingLookupTest extends AbstractLookupBaseHid
54.54 +implements AbstractLookupBaseHid.Impl {
54.55 + public ExcludingLookupTest(java.lang.String testName) {
54.56 + super(testName, null);
54.57 + }
54.58 +
54.59 + public Lookup createLookup (final Lookup lookup) {
54.60 + return Lookups.exclude (lookup, new Class[0]);
54.61 + }
54.62 +
54.63 + public Lookup createInstancesLookup (InstanceContent ic) {
54.64 + return new AbstractLookup (ic);
54.65 + }
54.66 +
54.67 + public void clearCaches () {
54.68 + }
54.69 +
54.70 + public void testWeCanRemoveInteger () throws Exception {
54.71 + doBasicFilteringTest (Integer.class, Integer.class, 0);
54.72 + }
54.73 +
54.74 + public void testWeCanRemoveIntegersEvenByAskingForRemoveOfAllNumbers () throws Exception {
54.75 + doBasicFilteringTest (Number.class, Integer.class, 0);
54.76 + }
54.77 + public void testFunWithInterfaces () throws Exception {
54.78 + doBasicFilteringTest (java.io.Serializable.class, Integer.class, 0);
54.79 + }
54.80 +
54.81 + public void testWeCanGetInstanceOfSerializableEvenItIsExcludedIfWeAskForClassNotExtendingIt () throws Exception {
54.82 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { java.io.Serializable.class });
54.83 + Lookup.Template t = new Lookup.Template (Object.class);
54.84 + Lookup.Result res = lookup.lookup (t);
54.85 +
54.86 + LL ll = new LL ();
54.87 + res.addLookupListener (ll);
54.88 + assertEquals ("Nothing is there", 0, res.allItems ().size ());
54.89 +
54.90 + Object inst = new Integer (3);
54.91 + ic.add (inst);
54.92 +
54.93 + assertEquals ("Not Filtered out", inst, lookup.lookup (Object.class));
54.94 + assertEquals ("Not Filtered out2", inst, lookup.lookupItem (t).getInstance ());
54.95 + assertEquals ("One is there - 2", 1, res.allItems ().size ());
54.96 + assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
54.97 + assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
54.98 + assertEquals ("Right # of events", 1, ll.getCount ());
54.99 +
54.100 + ic.remove (inst);
54.101 + assertEquals ("Filtered out3", null, lookup.lookupItem (t));
54.102 + assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
54.103 + assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
54.104 + assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
54.105 + assertEquals ("Of course it is not there", null, lookup.lookup (Object.class));
54.106 + assertEquals ("Right # of events", 1, ll.getCount ());
54.107 + }
54.108 +
54.109 + public void testIntegersQueriedThruObject () throws Exception {
54.110 + doBasicFilteringTest (Number.class, Object.class, 1);
54.111 + }
54.112 +
54.113 + private void doBasicFilteringTest (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
54.114 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
54.115 + Lookup.Template t = new Lookup.Template (theQuery);
54.116 + Lookup.Result res = lookup.lookup (t);
54.117 +
54.118 + LL ll = new LL ();
54.119 + res.addLookupListener (ll);
54.120 + assertEquals ("Nothing is there", 0, res.allItems ().size ());
54.121 +
54.122 + Object inst = new Integer (3);
54.123 + ic.add (inst);
54.124 +
54.125 + assertEquals ("Filtered out", null, lookup.lookup (theQuery));
54.126 + assertEquals ("Filtered out2", null, lookup.lookupItem (t));
54.127 + assertEquals ("Nothing is there - 2", 0, res.allItems ().size ());
54.128 + assertEquals ("Nothing is there - 2a", 0, res.allInstances ().size ());
54.129 + assertEquals ("Nothing is there - 2b", 0, res.allClasses ().size ());
54.130 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
54.131 +
54.132 + ic.remove (inst);
54.133 + assertEquals ("Filtered out3", null, lookup.lookupItem (t));
54.134 + assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
54.135 + assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
54.136 + assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
54.137 + assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
54.138 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
54.139 +
54.140 + }
54.141 +
54.142 + public void testSizeOfTheLookup () throws Exception {
54.143 + Class exclude = String.class;
54.144 +
54.145 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { exclude });
54.146 +
54.147 + assertSize ("Should be pretty lightweight", Collections.singleton (lookup), 16,
54.148 + new Object[] { this.instanceLookup, exclude });
54.149 + }
54.150 + public void testSizeOfTheLookupForMultipleFiltersIsHigher () throws Exception {
54.151 + Class exclude = String.class;
54.152 + Class exclude2 = Integer.class;
54.153 + Class[] arr = new Class[] { exclude, exclude2 };
54.154 +
54.155 + Lookup lookup = Lookups.exclude (this.instanceLookup, arr);
54.156 +
54.157 + assertSize ("Is fatter", Collections.singleton (lookup), 40,
54.158 + new Object[] { this.instanceLookup, exclude, exclude2 });
54.159 + assertSize ("But only due to the array", Collections.singleton (lookup), 16,
54.160 + new Object[] { this.instanceLookup, exclude, exclude2, arr });
54.161 + }
54.162 +
54.163 + public void testFilteringOfSomething () throws Exception {
54.164 + doFilteringOfSomething (Runnable.class, java.io.Serializable.class, 1);
54.165 + }
54.166 +
54.167 + private void doFilteringOfSomething (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
54.168 + Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
54.169 + Lookup.Template t = new Lookup.Template (theQuery);
54.170 + Lookup.Result res = lookup.lookup (t);
54.171 +
54.172 + LL ll = new LL ();
54.173 + res.addLookupListener (ll);
54.174 + assertEquals ("Nothing is there", 0, res.allItems ().size ());
54.175 +
54.176 + Object inst = new Integer (3);
54.177 + ic.add (inst);
54.178 +
54.179 + assertEquals ("Accepted", inst, lookup.lookup (theQuery));
54.180 + assertNotNull ("Accepted too", lookup.lookupItem (t));
54.181 + assertEquals ("One is there - 2", 1, res.allItems ().size ());
54.182 + assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
54.183 + assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
54.184 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
54.185 +
54.186 + Object inst2 = new Thread (); // implements Runnable
54.187 + ic.add (inst2);
54.188 + assertEquals ("Accepted - 2", inst, lookup.lookup (theQuery));
54.189 + assertNotNull ("Accepted too -2", lookup.lookupItem (t));
54.190 + assertEquals ("One is there - 3", 1, res.allItems ().size ());
54.191 + assertEquals ("One is there - 3a", 1, res.allInstances ().size ());
54.192 + assertEquals ("One is there - 3b", 1, res.allClasses ().size ());
54.193 + assertEquals ("Right # of events", 0, ll.getCount ());
54.194 +
54.195 +
54.196 + ic.remove (inst);
54.197 + assertEquals ("Filtered out3", null, lookup.lookupItem (t));
54.198 + assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
54.199 + assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
54.200 + assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
54.201 + assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
54.202 + assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
54.203 + }
54.204 +
54.205 + public void testTheBehaviourAsRequestedByDavidAndDescribedByJesse () throws Exception {
54.206 + class C implements Runnable, java.io.Serializable {
54.207 + public void run () {}
54.208 + }
54.209 + Object c = new C();
54.210 + Lookup l1 = Lookups.singleton(c);
54.211 + Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
54.212 + assertNull(l2.lookup(Runnable.class));
54.213 + assertEquals(c, l2.lookup(java.io.Serializable.class));
54.214 + }
54.215 +
54.216 + public void testTheBehaviourAsRequestedByDavidAndDescribedByJesseWithUsageOfResult () throws Exception {
54.217 + class C implements Runnable, java.io.Serializable {
54.218 + public void run () {}
54.219 + }
54.220 + Object c = new C();
54.221 + Lookup l1 = Lookups.singleton(c);
54.222 + Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
54.223 +
54.224 + Lookup.Result run = l2.lookup (new Lookup.Template (Runnable.class));
54.225 + Lookup.Result ser = l2.lookup (new Lookup.Template (java.io.Serializable.class));
54.226 +
54.227 + assertEquals ("Runnables filtered out", 0, run.allItems ().size ());
54.228 + assertEquals ("One serialiazble", 1, ser.allItems ().size ());
54.229 + assertEquals ("And it is c", c, ser.allInstances ().iterator ().next ());
54.230 + }
54.231 +}
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/InheritanceTreeTest.java Mon Dec 14 20:58:39 2009 +0100
55.3 @@ -0,0 +1,77 @@
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 +package org.openide.util.lookup;
55.45 +
55.46 +import junit.framework.TestCase;
55.47 +import junit.framework.*;
55.48 +import org.openide.util.Lookup;
55.49 +import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
55.50 +import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
55.51 +import java.io.*;
55.52 +import java.lang.ref.WeakReference;
55.53 +import java.util.*;
55.54 +
55.55 +/**
55.56 + *
55.57 + * @author Jaroslav Tulach
55.58 + */
55.59 +public class InheritanceTreeTest extends TestCase {
55.60 +
55.61 + public InheritanceTreeTest(String testName) {
55.62 + super(testName);
55.63 + }
55.64 +
55.65 + protected void setUp() throws Exception {
55.66 + }
55.67 +
55.68 + protected void tearDown() throws Exception {
55.69 + }
55.70 +
55.71 + public void testDeserOfNode() {
55.72 + InheritanceTree inh = new InheritanceTree();
55.73 + InheritanceTree.Node n = new InheritanceTree.Node(String.class);
55.74 + n.markDeserialized();
55.75 + n.markDeserialized();
55.76 +
55.77 + n.assignItem(inh, new InstanceContent.SimpleItem("Ahoj"));
55.78 + }
55.79 +
55.80 +}
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/InitializationBug44134Test.java Mon Dec 14 20:58:39 2009 +0100
56.3 @@ -0,0 +1,126 @@
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.*;
56.48 +import org.netbeans.junit.*;
56.49 +import org.openide.util.Lookup;
56.50 +
56.51 +public class InitializationBug44134Test extends NbTestCase {
56.52 + public InitializationBug44134Test (java.lang.String testName) {
56.53 + super(testName);
56.54 + }
56.55 +
56.56 + public static void main(java.lang.String[] args) {
56.57 + junit.textui.TestRunner.run(new NbTestSuite(InitializationBug44134Test.class));
56.58 + }
56.59 +
56.60 + public void testThereShouldBe18Integers () throws Exception {
56.61 + FooManifestLookup foo = new FooManifestLookup ();
56.62 +
56.63 + Collection items = foo.lookup (new Lookup.Template (Integer.class)).allItems ();
56.64 +
56.65 + assertEquals ("18 of them", 18, items.size ());
56.66 +
56.67 + Iterator it = items.iterator ();
56.68 + while (it.hasNext()) {
56.69 + Lookup.Item t = (Lookup.Item)it.next ();
56.70 + assertEquals ("Is Integer", Integer.class, t.getInstance ().getClass ());
56.71 + }
56.72 + }
56.73 +
56.74 +
56.75 + public class FooManifestLookup extends AbstractLookup {
56.76 + public FooManifestLookup() {
56.77 + super();
56.78 + }
56.79 +
56.80 + @Override
56.81 + protected void initialize() {
56.82 + for (int i=0; i<18; i++) {
56.83 + try {
56.84 + String id= "__" + i;
56.85 +
56.86 + addPair(new FooLookupItem(new Integer(i),id));
56.87 + }
56.88 + catch (Exception e) {
56.89 + }
56.90 + }
56.91 + }
56.92 +
56.93 + public class FooLookupItem extends AbstractLookup.Pair {
56.94 + public FooLookupItem(Integer data, String id) {
56.95 + super();
56.96 + this.data=data;
56.97 + this.id=id;
56.98 + }
56.99 +
56.100 + protected boolean creatorOf(Object obj) {
56.101 + return obj == data;
56.102 + }
56.103 +
56.104 + public String getDisplayName() {
56.105 + return data.toString();
56.106 + }
56.107 +
56.108 + public Class getType () {
56.109 + return Integer.class;
56.110 + }
56.111 +
56.112 + protected boolean instanceOf (Class c) {
56.113 + return c.isInstance(data);
56.114 + }
56.115 +
56.116 + public Object getInstance() {
56.117 + return data;
56.118 + }
56.119 +
56.120 + public String getId() {
56.121 + return id;
56.122 + }
56.123 +
56.124 + private Integer data;
56.125 + private String id;
56.126 + }
56.127 + }
56.128 +
56.129 +}
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/KomrskaLookupTest.java Mon Dec 14 20:58:39 2009 +0100
57.3 @@ -0,0 +1,177 @@
57.4 +/*
57.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
57.6 + *
57.7 + * Copyright 2008 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 + * If you wish your version of this file to be governed by only the CDDL
57.28 + * or only the GPL Version 2, indicate your decision by adding
57.29 + * "[Contributor] elects to include this software in this distribution
57.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
57.31 + * single choice of license, a recipient has the option to distribute
57.32 + * your version of this file under either the CDDL, the GPL Version 2 or
57.33 + * to extend the choice of license to its licensees as provided above.
57.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
57.35 + * Version 2 license, then the option applies only if the new code is
57.36 + * made subject to such option by the copyright holder.
57.37 + *
57.38 + * Contributor(s):
57.39 + *
57.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
57.41 + */
57.42 +package org.openide.util.lookup;
57.43 +
57.44 +import org.junit.After;
57.45 +import org.junit.Before;
57.46 +import org.junit.Test;
57.47 +import org.openide.util.Lookup;
57.48 +import org.openide.util.LookupEvent;
57.49 +import org.openide.util.LookupListener;
57.50 +import static org.junit.Assert.*;
57.51 +
57.52 +/**
57.53 + * Test donated by Mr. Komrska. Seems to pass with 6.5.
57.54 + * @author komrska
57.55 + */
57.56 +public final class KomrskaLookupTest {
57.57 + private TestLookupManager lookupManager=null;
57.58 + private StringBuffer result=null;
57.59 +
57.60 + //
57.61 +
57.62 + private void addToLookup(final TestLookupItemA object) {
57.63 + result.append('A');
57.64 + lookupManager.add(object);
57.65 + }
57.66 + private void removeFromLookup(final TestLookupItemA object) {
57.67 + result.append('A');
57.68 + lookupManager.remove(object);
57.69 + }
57.70 +
57.71 + private void addToLookup(final TestLookupItemB object) {
57.72 + result.append('B');
57.73 + lookupManager.add(object);
57.74 + }
57.75 + private void removeFromLookup(final TestLookupItemB object) {
57.76 + result.append('B');
57.77 + lookupManager.remove(object);
57.78 + }
57.79 +
57.80 + public String getResult() {
57.81 + return result.toString();
57.82 + }
57.83 +
57.84 + //
57.85 +
57.86 + @Before
57.87 + public void setUp() {
57.88 + lookupManager=new TestLookupManager();
57.89 + result=new StringBuffer();
57.90 + }
57.91 +
57.92 + @After
57.93 + public void tearDown() {
57.94 + lookupManager=null;
57.95 + result=null;
57.96 + }
57.97 +
57.98 + @Test
57.99 + public void testLookupBug() {
57.100 + TestLookupItemA itemA1=new TestLookupItemA();
57.101 + TestLookupItemB itemB1=new TestLookupItemB();
57.102 + //
57.103 + addToLookup(itemA1);
57.104 + addToLookup(itemB1);
57.105 + removeFromLookup(itemA1);
57.106 + removeFromLookup(itemB1);
57.107 + addToLookup(itemB1);
57.108 + removeFromLookup(itemB1);
57.109 + //
57.110 + addToLookup(itemA1);
57.111 + addToLookup(itemB1);
57.112 + removeFromLookup(itemA1);
57.113 + removeFromLookup(itemB1);
57.114 + addToLookup(itemB1);
57.115 + removeFromLookup(itemB1);
57.116 + //
57.117 + addToLookup(itemA1);
57.118 + addToLookup(itemB1);
57.119 + removeFromLookup(itemA1);
57.120 + removeFromLookup(itemB1);
57.121 + addToLookup(itemB1);
57.122 + removeFromLookup(itemB1);
57.123 + //
57.124 + assertEquals(getResult(),lookupManager.getResult());
57.125 + }
57.126 +
57.127 + public static final class TestLookupItemA {}
57.128 + public static final class TestLookupItemB {}
57.129 + public static final class TestLookupManager {
57.130 + private InstanceContent instanceContent=new InstanceContent();
57.131 + private AbstractLookup abstractLookup=new AbstractLookup(instanceContent);
57.132 +
57.133 + private Lookup.Result<TestLookupItemA> resultA=null;
57.134 + private Lookup.Result<TestLookupItemB> resultB=null;
57.135 +
57.136 + private LookupListener listenerA=new LookupListener() {
57.137 + public void resultChanged(LookupEvent event) {
57.138 + result.append('A');
57.139 + }
57.140 + };
57.141 + private LookupListener listenerB=new LookupListener() {
57.142 + public void resultChanged(LookupEvent event) {
57.143 + result.append('B');
57.144 + }
57.145 + };
57.146 +
57.147 + private StringBuffer result=new StringBuffer();
57.148 +
57.149 + //
57.150 +
57.151 + public TestLookupManager() {
57.152 + Lookup.Template<TestLookupItemA> templateA=
57.153 + new Lookup.Template<TestLookupItemA>(TestLookupItemA.class);
57.154 + resultA=abstractLookup.lookup(templateA);
57.155 + resultA.addLookupListener(listenerA);
57.156 + resultA.allInstances().size();
57.157 + //
57.158 + Lookup.Template<TestLookupItemB> templateB=
57.159 + new Lookup.Template<TestLookupItemB>(TestLookupItemB.class);
57.160 + resultB=abstractLookup.lookup(templateB);
57.161 + resultB.addLookupListener(listenerB);
57.162 + resultB.allInstances().size();
57.163 + // WORKAROUND
57.164 + // instanceContent.add(Boolean.TRUE);
57.165 + }
57.166 +
57.167 + //
57.168 +
57.169 + public void add(Object item) {
57.170 + instanceContent.add(item);
57.171 + }
57.172 + public void remove(Object item) {
57.173 + instanceContent.remove(item);
57.174 + }
57.175 + public String getResult() {
57.176 + return result.toString();
57.177 + }
57.178 + }
57.179 +
57.180 +}
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/LookupBugTest.java Mon Dec 14 20:58:39 2009 +0100
58.3 @@ -0,0 +1,79 @@
58.4 +package org.openide.util.lookup;
58.5 +
58.6 +import java.util.logging.Logger;
58.7 +import org.junit.Before;
58.8 +import org.junit.Test;
58.9 +import org.openide.util.Lookup;
58.10 +import org.openide.util.LookupEvent;
58.11 +import org.openide.util.LookupListener;
58.12 +import static org.junit.Assert.*;
58.13 +
58.14 +/**
58.15 + * Test of a Lookup bug seen in NetBeans platforms 6.0-6.5M1.
58.16 + * @author rlee
58.17 + */
58.18 +public class LookupBugTest implements LookupListener
58.19 +{
58.20 + private static final int MAX_LOOPS = 1000;
58.21 +
58.22 + private AbstractLookup lookup;
58.23 + private InstanceContent content;
58.24 + private Lookup.Result<String> wordResult;
58.25 + private Lookup.Result<Integer> numberResult;
58.26 + private String word;
58.27 + private Integer number;
58.28 + private Logger LOG;
58.29 +
58.30 + private boolean fired;
58.31 + private int i;
58.32 +
58.33 + @Before
58.34 + public void setUp()
58.35 + {
58.36 + LOG = Logger.getLogger("test.LookupBugTest");
58.37 + content = new InstanceContent();
58.38 + lookup = new AbstractLookup(content);
58.39 + wordResult = lookup.lookupResult(java.lang.String.class);
58.40 + wordResult.addLookupListener(this);
58.41 + numberResult = lookup.lookupResult(java.lang.Integer.class);
58.42 + numberResult.addLookupListener(this);
58.43 +
58.44 + fired = false;
58.45 + }
58.46 +
58.47 + @Test
58.48 + public void lookupTest()
58.49 + {
58.50 + for(i = 0; i < MAX_LOOPS; i++ )
58.51 + {
58.52 + word = String.valueOf(i);
58.53 + number = new Integer(i);
58.54 + content.add(word);
58.55 + assertTrue( "word on loop " + i, checkLookupEventFired() );
58.56 + content.add(number);
58.57 + assertTrue( "number on loop " + i, checkLookupEventFired() );
58.58 + content.remove(word);
58.59 + assertTrue( "remove word on loop " + i, checkLookupEventFired() );
58.60 + content.remove(number);
58.61 + assertTrue( "remove number on loop " + i, checkLookupEventFired() );
58.62 +
58.63 + assertTrue("The lookup still needs to stay simple", AbstractLookup.isSimple(lookup));
58.64 + }
58.65 + }
58.66 +
58.67 + public void resultChanged(LookupEvent ev)
58.68 + {
58.69 + fired = true;
58.70 + }
58.71 +
58.72 + public boolean checkLookupEventFired()
58.73 + {
58.74 + LOG.fine(" round: " + i + " word = " + word + " number = " + number);
58.75 + if( fired )
58.76 + {
58.77 + fired = false;
58.78 + return true;
58.79 + }
58.80 + else return false;
58.81 + }
58.82 +}
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/LookupsProxyTest.java Mon Dec 14 20:58:39 2009 +0100
59.3 @@ -0,0 +1,282 @@
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.util.*;
59.50 +import org.netbeans.junit.*;
59.51 +import org.openide.util.Lookup;
59.52 +import org.openide.util.LookupEvent;
59.53 +import org.openide.util.LookupListener;
59.54 +
59.55 +/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
59.56 + */
59.57 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
59.58 +public class LookupsProxyTest extends AbstractLookupBaseHid
59.59 +implements AbstractLookupBaseHid.Impl {
59.60 + public LookupsProxyTest(java.lang.String testName) {
59.61 + super(testName, null);
59.62 + }
59.63 +
59.64 + public static void main(java.lang.String[] args) {
59.65 + junit.textui.TestRunner.run(new NbTestSuite (LookupsProxyTest.class));
59.66 + }
59.67 +
59.68 + /** Creates an lookup for given lookup. This class just returns
59.69 + * the object passed in, but subclasses can be different.
59.70 + * @param lookup in lookup
59.71 + * @return a lookup to use
59.72 + */
59.73 + public Lookup createLookup (final Lookup lookup) {
59.74 + return org.openide.util.lookup.Lookups.proxy (
59.75 + new Lookup.Provider () {
59.76 + public Lookup getLookup () {
59.77 + return lookup;
59.78 + }
59.79 + }
59.80 + );
59.81 + }
59.82 +
59.83 + public Lookup createInstancesLookup (InstanceContent ic) {
59.84 + return new AbstractLookup (ic);
59.85 + }
59.86 +
59.87 + public void clearCaches () {
59.88 + }
59.89 +
59.90 +
59.91 +
59.92 + /** Check whether setLookups method does not fire when there is no
59.93 + * change in the lookups.
59.94 + */
59.95 + public void testProxyListener () {
59.96 + Changer ch = new Changer (Lookup.EMPTY);
59.97 +
59.98 + Lookup lookup = Lookups.proxy(ch);
59.99 + Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
59.100 +
59.101 + LL ll = new LL ();
59.102 + res.addLookupListener (ll);
59.103 + Collection allRes = res.allInstances ();
59.104 +
59.105 + ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
59.106 + lookup.lookup (Object.class); // does the refresh
59.107 +
59.108 + assertEquals("Replacing an empty by empty does not generate an event", 0, ll.getCount());
59.109 +
59.110 + InstanceContent content = new InstanceContent ();
59.111 + AbstractLookup del = new AbstractLookup (content);
59.112 + content.add (this);
59.113 + ch.setLookup (del);
59.114 + lookup.lookup (Object.class);
59.115 +
59.116 + if (ll.getCount () != 1) {
59.117 + fail ("Changing lookups with different content generates an event");
59.118 + }
59.119 +
59.120 + ch.setLookup (del);
59.121 + lookup.lookup (Object.class);
59.122 +
59.123 + if (ll.getCount () != 0) {
59.124 + fail ("Not changing the lookups does not generate any event");
59.125 + }
59.126 + }
59.127 +
59.128 +
59.129 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
59.130 + doListeningAndQueryingByTwoListenersSetLookups(0, 1, false);
59.131 + }
59.132 + public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
59.133 + doListeningAndQueryingByTwoListenersSetLookups(1, 1, false);
59.134 + }
59.135 + public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
59.136 + doListeningAndQueryingByTwoListenersSetLookups(2, 1, false);
59.137 + }
59.138 +
59.139 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
59.140 + doListeningAndQueryingByTwoListenersSetLookups(0, 2, false);
59.141 + }
59.142 + public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
59.143 + doListeningAndQueryingByTwoListenersSetLookups(1, 2, false);
59.144 + }
59.145 + public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
59.146 + doListeningAndQueryingByTwoListenersSetLookups(2, 2, false);
59.147 + }
59.148 +
59.149 + public void testListeningAndQueryingByTwoListenersInstancesSetLookupsWithProxy() {
59.150 + doListeningAndQueryingByTwoListenersSetLookups(0, 1, true);
59.151 + }
59.152 + public void testListeningAndQueryingByTwoListenersClassesSetLookupsWithProxy() {
59.153 + doListeningAndQueryingByTwoListenersSetLookups(1, 1, true);
59.154 + }
59.155 + public void testListeningAndQueryingByTwoListenersItemsSetLookupsWithProxy() {
59.156 + doListeningAndQueryingByTwoListenersSetLookups(2, 1, true);
59.157 + }
59.158 +
59.159 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups2WithProxy() {
59.160 + doListeningAndQueryingByTwoListenersSetLookups(0, 2, true);
59.161 + }
59.162 + public void testListeningAndQueryingByTwoListenersClassesSetLookups2WithProxy() {
59.163 + doListeningAndQueryingByTwoListenersSetLookups(1, 2, true);
59.164 + }
59.165 + public void testListeningAndQueryingByTwoListenersItemsSetLookups2WithProxy() {
59.166 + doListeningAndQueryingByTwoListenersSetLookups(2, 2, true);
59.167 + }
59.168 +
59.169 + /* XXX: these are pretty slow, seems there is a performance problem 2^22
59.170 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
59.171 + doListeningAndQueryingByTwoListenersSetLookups(0, 22);
59.172 + }
59.173 + public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
59.174 + doListeningAndQueryingByTwoListenersSetLookups(1, 22);
59.175 + }
59.176 + public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
59.177 + doListeningAndQueryingByTwoListenersSetLookups(2, 22);
59.178 + }
59.179 + */
59.180 +
59.181 + private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth, boolean cacheOnTop) {
59.182 + Changer orig = new Changer(Lookup.EMPTY);
59.183 + Lookup on = Lookups.proxy(orig);
59.184 + Lookup first = on;
59.185 +
59.186 + while (--depth > 0) {
59.187 + Changer next = new Changer(on);
59.188 + on = Lookups.proxy(next);
59.189 + }
59.190 +
59.191 +
59.192 + final Lookup lookup = cacheOnTop ? new ProxyLookup(new Lookup[] { on }) : on;
59.193 +
59.194 + class L implements LookupListener {
59.195 + Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
59.196 + Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
59.197 + Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
59.198 +
59.199 + {
59.200 + integer.addLookupListener(this);
59.201 + number.addLookupListener(this);
59.202 + serial.addLookupListener(this);
59.203 + }
59.204 +
59.205 + int round;
59.206 +
59.207 + public void resultChanged(LookupEvent ev) {
59.208 + Collection c1 = get(type, integer);
59.209 + Collection c2 = get(type, number);
59.210 + Collection c3 = get(type, serial);
59.211 +
59.212 + assertEquals("round " + round + " c1 vs. c2", c1, c2);
59.213 + assertEquals("round " + round + " c1 vs. c3", c1, c3);
59.214 + assertEquals("round " + round + " c2 vs. c3", c2, c3);
59.215 +
59.216 + round++;
59.217 + }
59.218 +
59.219 + private Collection get(int type, Lookup.Result res) {
59.220 + Collection c;
59.221 + switch(type) {
59.222 + case 0: c = res.allInstances(); break;
59.223 + case 1: c = res.allClasses(); break;
59.224 + case 2: c = res.allItems(); break;
59.225 + default: c = null; fail("Type: " + type); break;
59.226 + }
59.227 +
59.228 + assertNotNull(c);
59.229 + return new ArrayList(c);
59.230 + }
59.231 + }
59.232 +
59.233 + L listener = new L();
59.234 + listener.resultChanged(null);
59.235 + ArrayList arr = new ArrayList();
59.236 + for(int i = 0; i < 100; i++) {
59.237 + arr.add(new Integer(i));
59.238 +
59.239 + orig.lookup = Lookups.fixed(arr.toArray());
59.240 + // do the refresh
59.241 + first.lookup((Class)null);
59.242 + }
59.243 +
59.244 + assertEquals("3x100+1 checks", 301, listener.round);
59.245 + }
59.246 +
59.247 +
59.248 + public void testRefreshWithoutAllInstances103300 () {
59.249 + Changer ch = new Changer (Lookup.EMPTY);
59.250 +
59.251 + Lookup lookup = Lookups.proxy(ch);
59.252 +
59.253 + ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
59.254 + assertNull("Nothing there", lookup.lookup (Object.class)); // does the refresh
59.255 +
59.256 + InstanceContent content = new InstanceContent ();
59.257 + AbstractLookup del = new AbstractLookup (content);
59.258 + content.add (this);
59.259 + ch.setLookup (del);
59.260 + assertEquals("Can see me", this, lookup.lookup (Object.class));
59.261 +
59.262 + ch.setLookup (del);
59.263 + assertEquals("Still can see me", this, lookup.lookup (Object.class));
59.264 +
59.265 + assertEquals("I am visible", this, lookup.lookup(LookupsProxyTest.class));
59.266 + }
59.267 +
59.268 +
59.269 + private static final class Changer implements Lookup.Provider {
59.270 + private Lookup lookup;
59.271 +
59.272 + public Changer (Lookup lookup) {
59.273 + setLookup (lookup);
59.274 + }
59.275 +
59.276 + public void setLookup (Lookup lookup) {
59.277 + this.lookup = lookup;
59.278 + }
59.279 +
59.280 + public Lookup getLookup() {
59.281 + return lookup;
59.282 + }
59.283 + }
59.284 +
59.285 +}
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/MetaInfServicesLookupTest.java Mon Dec 14 20:58:39 2009 +0100
60.3 @@ -0,0 +1,552 @@
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-2006 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.io.ByteArrayInputStream;
60.48 +import java.io.File;
60.49 +import java.io.FileOutputStream;
60.50 +import java.io.IOException;
60.51 +import java.io.InputStream;
60.52 +import java.io.InputStreamReader;
60.53 +import java.lang.ref.Reference;
60.54 +import java.lang.ref.WeakReference;
60.55 +import java.net.URL;
60.56 +import java.net.URLClassLoader;
60.57 +import java.net.URLConnection;
60.58 +import java.net.URLStreamHandler;
60.59 +import java.util.ArrayList;
60.60 +import java.util.Collection;
60.61 +import java.util.Collections;
60.62 +import java.util.Comparator;
60.63 +import java.util.Enumeration;
60.64 +import java.util.HashSet;
60.65 +import java.util.Iterator;
60.66 +import java.util.List;
60.67 +import java.util.Map;
60.68 +import java.util.Set;
60.69 +import java.util.TreeSet;
60.70 +import java.util.WeakHashMap;
60.71 +import java.util.concurrent.atomic.AtomicBoolean;
60.72 +import java.util.jar.JarEntry;
60.73 +import java.util.jar.JarOutputStream;
60.74 +import java.util.logging.Level;
60.75 +import java.util.logging.Logger;
60.76 +import java.util.regex.Matcher;
60.77 +import java.util.regex.Pattern;
60.78 +import org.bar.Comparator2;
60.79 +import org.netbeans.junit.MockServices;
60.80 +import org.netbeans.junit.NbTestCase;
60.81 +import org.openide.util.Lookup;
60.82 +import org.openide.util.LookupEvent;
60.83 +import org.openide.util.LookupListener;
60.84 +import org.openide.util.test.MockLookup;
60.85 +
60.86 +/** Test finding services from manifest.
60.87 + * @author Jesse Glick
60.88 + */
60.89 +public class MetaInfServicesLookupTest extends NbTestCase {
60.90 + private Logger LOG;
60.91 + private Map<ClassLoader,Lookup> lookups = new WeakHashMap<ClassLoader,Lookup>();
60.92 +
60.93 + public MetaInfServicesLookupTest(String name) {
60.94 + super(name);
60.95 + LOG = Logger.getLogger("Test." + name);
60.96 + }
60.97 +
60.98 + protected String prefix() {
60.99 + return "META-INF/services/";
60.100 + }
60.101 +
60.102 + protected Lookup createLookup(ClassLoader c) {
60.103 + return Lookups.metaInfServices(c);
60.104 + }
60.105 +
60.106 + @Override
60.107 + protected Level logLevel() {
60.108 + return Level.INFO;
60.109 + }
60.110 +
60.111 + private Lookup getTestedLookup(ClassLoader c) {
60.112 + MockServices.setServices();
60.113 + Lookup l = lookups.get(c);
60.114 + if (l == null) {
60.115 + l = createLookup(c);
60.116 + lookups.put(c, l);
60.117 + }
60.118 + return l;
60.119 + }
60.120 +
60.121 + private URL findJar(String n) throws IOException {
60.122 + LOG.info("Looking for " + n);
60.123 + File jarDir = new File(getWorkDir(), "jars");
60.124 + jarDir.mkdirs();
60.125 + File jar = new File(jarDir, n);
60.126 + if (jar.exists()) {
60.127 + return jar.toURI().toURL();
60.128 + }
60.129 +
60.130 + LOG.info("generating " + jar);
60.131 +
60.132 + URL data = MetaInfServicesLookupTest.class.getResource(n.replaceAll("\\.jar", "\\.txt"));
60.133 + assertNotNull("Data found", data);
60.134 + StringBuffer sb = new StringBuffer();
60.135 + InputStreamReader r = new InputStreamReader(data.openStream());
60.136 + for(;;) {
60.137 + int ch = r.read();
60.138 + if (ch == -1) {
60.139 + break;
60.140 + }
60.141 + sb.append((char)ch);
60.142 + }
60.143 +
60.144 + JarOutputStream os = new JarOutputStream(new FileOutputStream(jar));
60.145 +
60.146 + Pattern p = Pattern.compile(":([^:]+):([^:]*)", Pattern.MULTILINE | Pattern.DOTALL);
60.147 + Matcher m = p.matcher(sb);
60.148 + Pattern foobar = Pattern.compile("^(org\\.(foo|bar)\\..*)$", Pattern.MULTILINE);
60.149 + Set<String> names = new TreeSet<String>();
60.150 + while (m.find()) {
60.151 + assert m.groupCount() == 2;
60.152 + String entryName = prefix() + m.group(1);
60.153 + LOG.info("putting there entry: " + entryName);
60.154 + os.putNextEntry(new JarEntry(entryName));
60.155 + os.write(m.group(2).getBytes());
60.156 + os.closeEntry();
60.157 +
60.158 + Matcher fb = foobar.matcher(m.group(2));
60.159 + while (fb.find()) {
60.160 + String clazz = fb.group(1).replace('.', '/') + ".class";
60.161 + LOG.info("will copy " + clazz);
60.162 + names.add(clazz);
60.163 + }
60.164 + }
60.165 +
60.166 + for (String copy : names) {
60.167 + os.putNextEntry(new JarEntry(copy));
60.168 + LOG.info("copying " + copy);
60.169 + InputStream from = MetaInfServicesLookupTest.class.getResourceAsStream("/" + copy);
60.170 + assertNotNull(copy, from);
60.171 + for (;;) {
60.172 + int ch = from.read();
60.173 + if (ch == -1) {
60.174 + break;
60.175 + }
60.176 + os.write(ch);
60.177 + }
60.178 + from.close();
60.179 + os.closeEntry();
60.180 + }
60.181 + os.close();
60.182 + LOG.info("done " + jar);
60.183 + return jar.toURI().toURL();
60.184 + }
60.185 +
60.186 + ClassLoader c1, c2, c2a, c3, c4;
60.187 +
60.188 + @Override
60.189 + protected void setUp() throws Exception {
60.190 + clearWorkDir();
60.191 + ClassLoader app = getClass().getClassLoader().getParent();
60.192 + ClassLoader c0 = app;
60.193 +
60.194 + c1 = new URLClassLoader(new URL[] {
60.195 + findJar("services-jar-1.jar"),
60.196 + }, c0);
60.197 + c2 = new URLClassLoader(new URL[] {
60.198 + findJar("services-jar-2.jar"),
60.199 + }, c1);
60.200 + c2a = new URLClassLoader(new URL[] {
60.201 + findJar("services-jar-2.jar"),
60.202 + }, c1);
60.203 + c3 = new URLClassLoader(new URL[] { findJar("services-jar-2.jar") },
60.204 + c0
60.205 + );
60.206 + c4 = new URLClassLoader(new URL[] {
60.207 + findJar("services-jar-1.jar"),
60.208 + findJar("services-jar-2.jar"),
60.209 + }, c0);
60.210 + }
60.211 +
60.212 + @Override
60.213 + protected void tearDown() throws Exception {
60.214 + Set<Reference<Lookup>> weak = new HashSet<Reference<Lookup>>();
60.215 + for (Lookup l : lookups.values()) {
60.216 + weak.add(new WeakReference<Lookup>(l));
60.217 + }
60.218 +
60.219 + lookups = null;
60.220 +
60.221 + for(Reference<Lookup> ref : weak) {
60.222 + assertGC("Lookup can disappear", ref);
60.223 + }
60.224 + }
60.225 +
60.226 + public void testBasicUsage() throws Exception {
60.227 + Lookup l = getTestedLookup(c2);
60.228 + Class<?> xface = c1.loadClass("org.foo.Interface");
60.229 + List<?> results = new ArrayList<Object>(l.lookupAll(xface));
60.230 + assertEquals("Two items in result: " + results, 2, results.size());
60.231 + // Note that they have to be in order:
60.232 + assertEquals("org.foo.impl.Implementation1", results.get(0).getClass().getName());
60.233 + assertEquals("org.bar.Implementation2", results.get(1).getClass().getName());
60.234 + // Make sure it does not gratuitously replace items:
60.235 + List<?> results2 = new ArrayList<Object>(l.lookupAll(xface));
60.236 + assertEquals(results, results2);
60.237 + }
60.238 +
60.239 + public void testLoaderSkew() throws Exception {
60.240 + Class<?> xface1 = c1.loadClass("org.foo.Interface");
60.241 + Lookup l3 = getTestedLookup(c3);
60.242 + // If we cannot load Interface, there should be no impls of course... quietly!
60.243 + assertEquals(Collections.emptyList(),
60.244 + new ArrayList<Object>(l3.lookupAll(xface1)));
60.245 + Lookup l4 = getTestedLookup(c4);
60.246 + // If we can load Interface but it is the wrong one, ignore it.
60.247 + assertEquals(Collections.emptyList(),
60.248 + new ArrayList<Object>(l4.lookupAll(xface1)));
60.249 + // Make sure l4 is really OK - it can load from its own JARs.
60.250 + Class<?> xface4 = c4.loadClass("org.foo.Interface");
60.251 + assertEquals(2, l4.lookupAll(xface4).size());
60.252 + }
60.253 +
60.254 + public void testStability() throws Exception {
60.255 + Lookup l = getTestedLookup(c2);
60.256 + Class<?> xface = c1.loadClass("org.foo.Interface");
60.257 + Object first = l.lookup(xface);
60.258 + assertEquals(first, l.lookupAll(xface).iterator().next());
60.259 + l = getTestedLookup(c2a);
60.260 + Object second = l.lookup(xface);
60.261 + assertEquals(first, second);
60.262 + }
60.263 +
60.264 + public void testMaskingOfResources() throws Exception {
60.265 + Lookup l1 = getTestedLookup(c1);
60.266 + Lookup l2 = getTestedLookup(c2);
60.267 + Lookup l4 = getTestedLookup(c4);
60.268 +
60.269 + assertNotNull("services1.jar defines a class that implements runnable", l1.lookup(Runnable.class));
60.270 + assertNull("services2.jar does not defines a class that implements runnable", l2.lookup(Runnable.class));
60.271 + assertNull("services1.jar defines Runnable, but services2.jar masks it out", l4.lookup(Runnable.class));
60.272 + }
60.273 +
60.274 + public void testOrdering() throws Exception {
60.275 + Lookup l = getTestedLookup(c1);
60.276 + Class<?> xface = c1.loadClass("java.util.Comparator");
60.277 + List<?> results = new ArrayList<Object>(l.lookupAll(xface));
60.278 + assertEquals(1, results.size());
60.279 +
60.280 + l = getTestedLookup(c2);
60.281 + xface = c2.loadClass("java.util.Comparator");
60.282 + results = new ArrayList<Object>(l.lookupAll(xface));
60.283 + assertEquals(2, results.size());
60.284 + // Test order:
60.285 + assertEquals("org.bar.Comparator2", results.get(0).getClass().getName());
60.286 + assertEquals("org.foo.impl.Comparator1", results.get(1).getClass().getName());
60.287 +
60.288 + // test that items without position are always at the end
60.289 + l = getTestedLookup(c2);
60.290 + xface = c2.loadClass("java.util.Iterator");
60.291 + results = new ArrayList<Object>(l.lookupAll(xface));
60.292 + assertEquals(2, results.size());
60.293 + // Test order:
60.294 + assertEquals("org.bar.Iterator2", results.get(0).getClass().getName());
60.295 + assertEquals("org.foo.impl.Iterator1", results.get(1).getClass().getName());
60.296 + }
60.297 +
60.298 + public void testNoCallToGetResourceForObjectIssue65124() throws Exception {
60.299 + class Loader extends ClassLoader {
60.300 + private int counter;
60.301 +
60.302 + @Override
60.303 + protected URL findResource(String name) {
60.304 + if (name.equals(prefix() + "java.lang.Object")) {
60.305 + counter++;
60.306 + }
60.307 +
60.308 + URL retValue;
60.309 +
60.310 + retValue = super.findResource(name);
60.311 + return retValue;
60.312 + }
60.313 +
60.314 + @Override
60.315 + protected Enumeration<URL> findResources(String name) throws IOException {
60.316 + if (name.equals(prefix() + "java.lang.Object")) {
60.317 + counter++;
60.318 + }
60.319 + return super.findResources(name);
60.320 + }
60.321 + }
60.322 + Loader loader = new Loader();
60.323 + Lookup l = getTestedLookup(loader);
60.324 +
60.325 + Object no = l.lookup(String.class);
60.326 + assertNull("Not found of course", no);
60.327 + assertEquals("No lookup of Object", 0, loader.counter);
60.328 + }
60.329 +
60.330 + public void testCanGarbageCollectClasses() throws Exception {
60.331 + class Loader extends ClassLoader {
60.332 + public Loader() {
60.333 + super(Loader.class.getClassLoader().getParent());
60.334 + }
60.335 +
60.336 + @Override
60.337 + protected URL findResource(String name) {
60.338 + if (name.equals(prefix() + "java.lang.Runnable")) {
60.339 + return Loader.class.getResource("MetaInfServicesLookupTestRunnable.txt");
60.340 + }
60.341 +
60.342 + URL retValue;
60.343 +
60.344 + retValue = super.findResource(name);
60.345 + return retValue;
60.346 + }
60.347 +
60.348 + @Override
60.349 + protected Class<?> findClass(String name) throws ClassNotFoundException {
60.350 + if (name.equals("org.openide.util.lookup.MetaInfServicesLookupTestRunnable")) {
60.351 + try {
60.352 + InputStream is = getClass().getResourceAsStream("MetaInfServicesLookupTestRunnable.class");
60.353 + byte[] arr = new byte[is.available()];
60.354 + int read = is.read(arr);
60.355 + assertEquals("Fully read", arr.length, read);
60.356 + return defineClass(name, arr, 0, arr.length);
60.357 + } catch (IOException ex) {
60.358 + throw new ClassNotFoundException("Cannot load", ex);
60.359 + }
60.360 + }
60.361 + throw new ClassNotFoundException();
60.362 + }
60.363 +
60.364 +
60.365 +
60.366 + @Override
60.367 + protected Enumeration<URL> findResources(String name) throws IOException {
60.368 + if (name.equals(prefix() + "java.lang.Runnable")) {
60.369 + return Collections.enumeration(Collections.singleton(findResource(name)));
60.370 + }
60.371 + return super.findResources(name);
60.372 + }
60.373 + }
60.374 + Loader loader = new Loader();
60.375 + Lookup l = getTestedLookup(loader);
60.376 +
60.377 +
60.378 + Object no = l.lookup(Runnable.class);
60.379 + assertNotNull("Found of course", no);
60.380 + assertEquals("The right name", "MetaInfServicesLookupTestRunnable", no.getClass().getSimpleName());
60.381 + if (no.getClass().getClassLoader() != loader) {
60.382 + fail("Wrong classloader: " + no.getClass().getClassLoader());
60.383 + }
60.384 +
60.385 + WeakReference<Object> ref = new WeakReference<Object>(no.getClass());
60.386 + loader = null;
60.387 + no = null;
60.388 + l = null;
60.389 + lookups.clear();
60.390 + MockLookup.setInstances();
60.391 + Thread.currentThread().setContextClassLoader(null);
60.392 + assertGC("Class can be garbage collected", ref);
60.393 + }
60.394 +
60.395 + public void testSuperTypes() throws Exception {
60.396 + doTestSuperTypes(createLookup(c2));
60.397 + doTestSuperTypes(new ProxyLookup(createLookup(c2)));
60.398 + }
60.399 + private void doTestSuperTypes(Lookup l) throws Exception {
60.400 + final Class<?> xface = c1.loadClass("org.foo.Interface");
60.401 + final Lookup.Result<Object> res = l.lookupResult(Object.class);
60.402 + assertEquals("Nothing yet", 0, res.allInstances().size());
60.403 + final AtomicBoolean event = new AtomicBoolean();
60.404 + final Thread here = Thread.currentThread();
60.405 + res.addLookupListener(new LookupListener() {
60.406 + public void resultChanged(LookupEvent ev) {
60.407 + if (Thread.currentThread() == here) {
60.408 + event.set(true);
60.409 + }
60.410 + }
60.411 + });
60.412 + assertNotNull("Interface found", l.lookup(xface));
60.413 + assertFalse(event.get());
60.414 + class W implements Runnable {
60.415 + boolean ok;
60.416 + public synchronized void run() {
60.417 + ok = true;
60.418 + notifyAll();
60.419 + }
60.420 +
60.421 + public synchronized void await() throws Exception {
60.422 + while (!ok) {
60.423 + wait();
60.424 + }
60.425 + }
60.426 + }
60.427 + W w = new W();
60.428 + MetaInfServicesLookup.RP.execute(w);
60.429 + w.await();
60.430 + assertEquals("Now two", 2, res.allInstances().size());
60.431 + }
60.432 +
60.433 + public void testWrongOrderAsInIssue100320() throws Exception {
60.434 + ClassLoader app = getClass().getClassLoader().getParent();
60.435 + ClassLoader c0 = app;
60.436 + ClassLoader ctmp = new URLClassLoader(new URL[] {
60.437 + findJar("problem100320.jar"),
60.438 + }, c0);
60.439 + Lookup lookup = Lookups.metaInfServices(ctmp, prefix());
60.440 +
60.441 + Collection<?> colAWT = lookup.lookupAll(IOException.class);
60.442 + assertEquals("There is enough objects to switch to InheritanceTree", 12, colAWT.size());
60.443 +
60.444 +
60.445 + List<?> col1 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
60.446 + assertEquals("Two", 2, col1.size());
60.447 + Collection<?> col2 = lookup.lookupAll(ctmp.loadClass(Comparator2.class.getName()));
60.448 + assertEquals("One", 1, col2.size());
60.449 + List<?> col3 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
60.450 + assertEquals("Two2", 2, col3.size());
60.451 +
60.452 + Iterator<?> it1 = col1.iterator();
60.453 + Iterator<?> it3 = col3.iterator();
60.454 + if (
60.455 + it1.next() != it3.next() ||
60.456 + it1.next() != it3.next()
60.457 + ) {
60.458 + fail("Collections are different:\nFirst: " + col1 + "\nLast: " + col3);
60.459 + }
60.460 + }
60.461 +
60.462 + public void testContentionWhenLoadingMetainfServices() throws Exception {
60.463 + class My extends ClassLoader implements Runnable {
60.464 + Lookup query;
60.465 + Integer value;
60.466 +
60.467 + public void run() {
60.468 + value = query.lookup(Integer.class);
60.469 + }
60.470 +
60.471 +
60.472 + @Override
60.473 + protected URL findResource(String name) {
60.474 + waitForTask(name);
60.475 + return super.findResource(name);
60.476 + }
60.477 +
60.478 + @Override
60.479 + protected Enumeration<URL> findResources(String name) throws IOException {
60.480 + waitForTask(name);
60.481 + return super.findResources(name);
60.482 + }
60.483 +
60.484 + private synchronized void waitForTask(String name) {
60.485 + if (name.startsWith(prefix()) && Thread.currentThread().getName().contains("block")) {
60.486 + try {
60.487 + wait();
60.488 + } catch (InterruptedException ex) {
60.489 + Logger.getLogger("global").log(Level.WARNING, "", ex);
60.490 + }
60.491 + }
60.492 + }
60.493 + }
60.494 +
60.495 + My loader = new My();
60.496 + loader.query = createLookup(loader);
60.497 + Thread t = new Thread(loader, "block when querying");
60.498 + t.start();
60.499 + t.join(1000);
60.500 +
60.501 + // this blocks waiting for the waitForTask to finish
60.502 + // right now
60.503 + Float f = loader.query.lookup(Float.class);
60.504 + assertNull("Nothing found", f);
60.505 +
60.506 + synchronized (loader) {
60.507 + loader.notifyAll();
60.508 + }
60.509 + t.join();
60.510 +
60.511 + assertNull("Nothing found", loader.value);
60.512 + }
60.513 +
60.514 + public void testInitializerRobustness() throws Exception { // #174055
60.515 + check(Broken1.class.getName());
60.516 + check(Broken2.class.getName());
60.517 + }
60.518 + private void check(final String n) {
60.519 + assertNull(Lookups.metaInfServices(new ClassLoader() {
60.520 + protected @Override Enumeration<URL> findResources(String name) throws IOException {
60.521 + if (name.equals("META-INF/services/java.lang.Object")) {
60.522 + return singleton(new URL(null, "dummy:stuff", new URLStreamHandler() {
60.523 + protected URLConnection openConnection(URL u) throws IOException {
60.524 + return new URLConnection(u) {
60.525 + public void connect() throws IOException {}
60.526 + public @Override InputStream getInputStream() throws IOException {
60.527 + return new ByteArrayInputStream(n.getBytes("UTF-8"));
60.528 + }
60.529 + };
60.530 + }
60.531 + }));
60.532 + } else {
60.533 + return Collections.enumeration(Collections.<URL>emptyList());
60.534 + }
60.535 + }
60.536 +
60.537 + }).lookup(Object.class));
60.538 + }
60.539 + public static class Broken1 {
60.540 + public Broken1() {
60.541 + throw new NullPointerException("broken1");
60.542 + }
60.543 + }
60.544 + public static class Broken2 {
60.545 + static {
60.546 + if (true) { // otherwise javac complains
60.547 + throw new NullPointerException("broken2");
60.548 + }
60.549 + }
60.550 + }
60.551 +
60.552 + static <T> Enumeration<T> singleton(T t) {
60.553 + return Collections.enumeration(Collections.singleton(t));
60.554 + }
60.555 +}
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/MetaInfServicesLookupTestRunnable.java Mon Dec 14 20:58:39 2009 +0100
61.3 @@ -0,0 +1,50 @@
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 +
61.48 +/**
61.49 + */
61.50 +public final class MetaInfServicesLookupTestRunnable implements Runnable {
61.51 + public void run() {
61.52 + }
61.53 +}
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/MetaInfServicesLookupTestRunnable.txt Mon Dec 14 20:58:39 2009 +0100
62.3 @@ -0,0 +1,1 @@
62.4 +org.openide.util.lookup.MetaInfServicesLookupTestRunnable
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/NamedServicesLookupTest.java Mon Dec 14 20:58:39 2009 +0100
63.3 @@ -0,0 +1,85 @@
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 org.openide.util.Lookup;
63.48 +import org.openide.util.test.MockLookup;
63.49 +
63.50 +
63.51 +/** Test finding services from manifest.
63.52 + * @author Jaroslav Tulach
63.53 + */
63.54 +public class NamedServicesLookupTest extends MetaInfServicesLookupTest {
63.55 + static {
63.56 + MockLookup.init();
63.57 + }
63.58 + public NamedServicesLookupTest(String name) {
63.59 + super(name);
63.60 + }
63.61 +
63.62 + @Override
63.63 + protected String prefix() {
63.64 + return "META-INF/namedservices/sub/path/";
63.65 + }
63.66 +
63.67 + @Override
63.68 + protected Lookup createLookup(ClassLoader c) {
63.69 + MockLookup.setInstances(c);
63.70 + Thread.currentThread().setContextClassLoader(c);
63.71 + Lookup l = Lookups.forPath("sub/path");
63.72 + return l;
63.73 + }
63.74 +
63.75 + //
63.76 + // this is not much inheriting test, as we mask most of the tested methods
63.77 + // anyway, but the infrastructure to generate the JAR files is useful
63.78 + //
63.79 +
63.80 + public @Override void testLoaderSkew() {}
63.81 + public @Override void testStability() throws Exception {}
63.82 + public @Override void testMaskingOfResources() throws Exception {}
63.83 + public @Override void testOrdering() throws Exception {}
63.84 + public @Override void testNoCallToGetResourceForObjectIssue65124() throws Exception {}
63.85 + public @Override void testSuperTypes() throws Exception {}
63.86 + public @Override void testWrongOrderAsInIssue100320() throws Exception {}
63.87 +
63.88 +}
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/PathInLookupTest.java Mon Dec 14 20:58:39 2009 +0100
64.3 @@ -0,0 +1,112 @@
64.4 +/*
64.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
64.6 + *
64.7 + * Copyright 1997-2009 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 + * Contributor(s):
64.28 + *
64.29 + * The Original Software is NetBeans. The Initial Developer of the Original
64.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
64.31 + * Microsystems, Inc. All Rights Reserved.
64.32 + *
64.33 + * If you wish your version of this file to be governed by only the CDDL
64.34 + * or only the GPL Version 2, indicate your decision by adding
64.35 + * "[Contributor] elects to include this software in this distribution
64.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
64.37 + * single choice of license, a recipient has the option to distribute
64.38 + * your version of this file under either the CDDL, the GPL Version 2 or
64.39 + * to extend the choice of license to its licensees as provided above.
64.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
64.41 + * Version 2 license, then the option applies only if the new code is
64.42 + * made subject to such option by the copyright holder.
64.43 + */
64.44 +
64.45 +package org.openide.util.lookup;
64.46 +
64.47 +import java.util.logging.Level;
64.48 +import org.netbeans.junit.MockServices;
64.49 +import org.netbeans.junit.NbTestCase;
64.50 +import org.netbeans.modules.openide.util.NamedServicesProvider;
64.51 +import org.openide.util.Lookup;
64.52 +
64.53 +/**
64.54 + * @author Jaroslav Tulach
64.55 + */
64.56 +public class PathInLookupTest extends NbTestCase {
64.57 + static {
64.58 + System.setProperty("org.openide.util.Lookup.paths", "MyServices:YourServices");
64.59 + MockServices.setServices(P.class);
64.60 + Lookup.getDefault();
64.61 + }
64.62 +
64.63 + public PathInLookupTest(String name) {
64.64 + super(name);
64.65 + }
64.66 +
64.67 + @Override
64.68 + protected Level logLevel() {
64.69 + return Level.FINE;
64.70 + }
64.71 +
64.72 + public void testInterfaceFoundInMyServices() throws Exception {
64.73 + assertNull("not found", Lookup.getDefault().lookup(Shared.class));
64.74 + Shared v = new Shared();
64.75 + P.ic1.add(v);
64.76 + assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
64.77 + P.ic1.remove(v);
64.78 + assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
64.79 + }
64.80 + public void testInterfaceFoundInMyServices2() throws Exception {
64.81 + assertNull("not found", Lookup.getDefault().lookup(Shared.class));
64.82 + Shared v = new Shared();
64.83 + P.ic2.add(v);
64.84 + assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
64.85 + P.ic2.remove(v);
64.86 + assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
64.87 + }
64.88 +
64.89 + static final class Shared extends Object {}
64.90 +
64.91 + public static final class P extends NamedServicesProvider {
64.92 + static InstanceContent ic1 = new InstanceContent();
64.93 + static InstanceContent ic2 = new InstanceContent();
64.94 + static AbstractLookup[] arr = {
64.95 + new AbstractLookup(ic1), new AbstractLookup(ic2)
64.96 + };
64.97 +
64.98 +
64.99 + @Override
64.100 + public Lookup create(String path) {
64.101 + int indx = -1;
64.102 + if (path.equals("MyServices/")) {
64.103 + indx = 0;
64.104 + }
64.105 + if (path.equals("YourServices/")) {
64.106 + indx = 1;
64.107 + }
64.108 + if (indx == -1) {
64.109 + fail("Unexpected lookup query: " + path);
64.110 + }
64.111 + return arr[indx];
64.112 + }
64.113 + }
64.114 +
64.115 +}
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/PrefixServicesLookupTest.java Mon Dec 14 20:58:39 2009 +0100
65.3 @@ -0,0 +1,63 @@
65.4 +/*
65.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
65.6 + *
65.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
65.8 + *
65.9 + * The contents of this file are subject to the terms of either the GNU
65.10 + * General Public License Version 2 only ("GPL") or the Common
65.11 + * Development and Distribution License("CDDL") (collectively, the
65.12 + * "License"). You may not use this file except in compliance with the
65.13 + * License. You can obtain a copy of the License at
65.14 + * http://www.netbeans.org/cddl-gplv2.html
65.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
65.16 + * specific language governing permissions and limitations under the
65.17 + * License. When distributing the software, include this License Header
65.18 + * Notice in each file and include the License file at
65.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
65.20 + * particular file as subject to the "Classpath" exception as provided
65.21 + * by Sun in the GPL Version 2 section of the License file that
65.22 + * accompanied this code. If applicable, add the following below the
65.23 + * License Header, with the fields enclosed by brackets [] replaced by
65.24 + * your own identifying information:
65.25 + * "Portions Copyrighted [year] [name of copyright owner]"
65.26 + *
65.27 + * Contributor(s):
65.28 + *
65.29 + * The Original Software is NetBeans. The Initial Developer of the Original
65.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
65.31 + * Microsystems, Inc. All Rights Reserved.
65.32 + *
65.33 + * If you wish your version of this file to be governed by only the CDDL
65.34 + * or only the GPL Version 2, indicate your decision by adding
65.35 + * "[Contributor] elects to include this software in this distribution
65.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
65.37 + * single choice of license, a recipient has the option to distribute
65.38 + * your version of this file under either the CDDL, the GPL Version 2 or
65.39 + * to extend the choice of license to its licensees as provided above.
65.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
65.41 + * Version 2 license, then the option applies only if the new code is
65.42 + * made subject to such option by the copyright holder.
65.43 + */
65.44 +
65.45 +package org.openide.util.lookup;
65.46 +
65.47 +import org.openide.util.Lookup;
65.48 +
65.49 +
65.50 +/** Test finding services from manifest.
65.51 + * @author Jaroslav Tulach
65.52 + */
65.53 +public class PrefixServicesLookupTest extends MetaInfServicesLookupTest {
65.54 + public PrefixServicesLookupTest(String name) {
65.55 + super(name);
65.56 + }
65.57 +
65.58 + protected String prefix() {
65.59 + return "META-INF/netbeans/prefix/services/test/";
65.60 + }
65.61 +
65.62 + protected Lookup createLookup(ClassLoader c) {
65.63 + return Lookups.metaInfServices(c, prefix());
65.64 + }
65.65 +
65.66 +}
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/ProxyLookup173975Test.java Mon Dec 14 20:58:39 2009 +0100
66.3 @@ -0,0 +1,108 @@
66.4 +/*
66.5 + * To change this template, choose Tools | Templates
66.6 + * and open the template in the editor.
66.7 + */
66.8 +package org.openide.util.lookup;
66.9 +
66.10 +import java.util.Collection;
66.11 +import java.util.Collections;
66.12 +import org.junit.Assert;
66.13 +import org.junit.Test;
66.14 +import org.openide.util.Lookup;
66.15 +import org.openide.util.LookupEvent;
66.16 +import org.openide.util.LookupListener;
66.17 +import org.openide.util.lookup.AbstractLookup.Storage;
66.18 +
66.19 +public class ProxyLookup173975Test {
66.20 +
66.21 + public ProxyLookup173975Test() {
66.22 + }
66.23 +
66.24 + boolean called = false;
66.25 +
66.26 + @Test
66.27 + public void testAbstractLookupWithoutAllInstances() {
66.28 + registerLookupListenerAndAddSomething(false, false, false);
66.29 + }
66.30 +
66.31 + @Test
66.32 + public void testAbstractLookupWithAllInstances() {
66.33 + registerLookupListenerAndAddSomething(false, true, false);
66.34 + }
66.35 +
66.36 + @Test
66.37 + public void testAbstractLookupInheritanceTreeWithoutAllInstances() {
66.38 + registerLookupListenerAndAddSomething(false, false, true);
66.39 + }
66.40 +
66.41 + @Test
66.42 + public void testAbstractLookupInheritanceTreeWithAllInstances() {
66.43 + registerLookupListenerAndAddSomething(false, true, true);
66.44 + }
66.45 +
66.46 + @Test
66.47 + public void testProxyLookupWithoutAllInstances() {
66.48 + registerLookupListenerAndAddSomething(true, false, false);
66.49 + }
66.50 +
66.51 + @Test
66.52 + public void testProxyLookupWithAllInstances() {
66.53 + registerLookupListenerAndAddSomething(true, true, false);
66.54 + }
66.55 +
66.56 + @Test
66.57 + public void testProxyLookupInheritanceTreeWithoutAllInstances() {
66.58 + registerLookupListenerAndAddSomething(true, false, true);
66.59 + }
66.60 +
66.61 + @Test
66.62 + public void testProxyLookupInheritanceTreeWithAllInstances() {
66.63 + registerLookupListenerAndAddSomething(true, true, true);
66.64 + }
66.65 +
66.66 + private void registerLookupListenerAndAddSomething(boolean useProxy, boolean callAllInstances, boolean inheritanceTree) {
66.67 + called = false;
66.68 + InstanceContent aInstanceContent = new InstanceContent();
66.69 + Storage<?> s = inheritanceTree ? new InheritanceTree() : new ArrayStorage();
66.70 + Lookup aLookup = new AbstractLookup(aInstanceContent, s);
66.71 + if (useProxy) {
66.72 + aLookup = new ProxyLookup(aLookup);
66.73 + }
66.74 + Lookup.Result<ObjectInLookup> result = aLookup.lookupResult(ObjectInLookup.class);
66.75 + if (callAllInstances) {
66.76 + result.allInstances(); // TO GET SUCCESS
66.77 + }
66.78 + result.addLookupListener(new LookupListener() {
66.79 +
66.80 + public void resultChanged(LookupEvent ev) {
66.81 + Lookup.Result aResult = (Lookup.Result) ev.getSource();
66.82 + Collection c = aResult.allInstances();
66.83 + if (!c.isEmpty()) {
66.84 + called = true;
66.85 + }
66.86 + }
66.87 + });
66.88 +
66.89 + aInstanceContent.set(Collections.singleton(
66.90 + new ObjectInLookup("Set Object in Lookup)")), null);
66.91 + Assert.assertTrue("Listener was notified", called);
66.92 + }
66.93 +
66.94 + public class ObjectInLookup {
66.95 +
66.96 + private final String name;
66.97 +
66.98 + public ObjectInLookup(String name) {
66.99 + this.name = name;
66.100 + }
66.101 +
66.102 + public String getName() {
66.103 + return this.name;
66.104 + }
66.105 +
66.106 + @Override
66.107 + public String toString() {
66.108 + return "objectinlookup:" + getName();
66.109 + }
66.110 + }
66.111 +}
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/ProxyLookupEventIssue136866Test.java Mon Dec 14 20:58:39 2009 +0100
67.3 @@ -0,0 +1,56 @@
67.4 +package org.openide.util.lookup;
67.5 +
67.6 +import junit.framework.TestCase;
67.7 +import org.openide.util.Lookup;
67.8 +import org.openide.util.LookupEvent;
67.9 +import org.openide.util.LookupListener;
67.10 +
67.11 +/**
67.12 + * Test case which demonstrates that ProxyLookup does not fire
67.13 + * an event when it should.
67.14 + */
67.15 +public class ProxyLookupEventIssue136866Test extends TestCase {
67.16 +
67.17 + public ProxyLookupEventIssue136866Test(String testName) {
67.18 + super(testName);
67.19 + }
67.20 +
67.21 + public void testAbstractLookupFiresEventWhenContentChanged() {
67.22 + InstanceContent ic = new InstanceContent();
67.23 + AbstractLookup al = new AbstractLookup(ic);
67.24 +
67.25 + final int[] counts = {0}; // Number of items observed upon a LookupEvent
67.26 + final Lookup.Result<String> result = al.lookupResult(String.class);
67.27 +
67.28 + result.addLookupListener(new LookupListener() {
67.29 + public void resultChanged(LookupEvent ev) {
67.30 + // this gets called as expected
67.31 + assertSame(result, ev.getSource());
67.32 + counts[0] = result.allInstances().size();
67.33 + }
67.34 + });
67.35 +
67.36 + ic.add("hello1");
67.37 + assertEquals(1, counts[0]);
67.38 + }
67.39 +
67.40 + public void testProxyLookupFailsToFireEventWhenProxiedLookupChanged() {
67.41 + InstanceContent ic = new InstanceContent();
67.42 +// AbstractLookup al = new AbstractLookup(ic);
67.43 + Lookup proxy = new AbstractLookup(ic);
67.44 +
67.45 + final int[] counts = {0}; // Number of items observed upon a LookupEvent
67.46 + final Lookup.Result<String> result = proxy.lookupResult(String.class);
67.47 +
67.48 + result.addLookupListener(new LookupListener() {
67.49 + public void resultChanged(LookupEvent ev) {
67.50 + // this should be called but never is
67.51 + assertSame(result, ev.getSource());
67.52 + counts[0] = result.allInstances().size();
67.53 + }
67.54 + });
67.55 +
67.56 + ic.add("hello1");
67.57 + assertEquals(1, counts[0]);
67.58 + }
67.59 +}
68.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
68.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java Mon Dec 14 20:58:39 2009 +0100
68.3 @@ -0,0 +1,655 @@
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-2006 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.lookup;
68.46 +
68.47 +import java.io.Serializable;
68.48 +
68.49 +import java.lang.ref.Reference;
68.50 +import java.lang.ref.WeakReference;
68.51 +import java.util.*;
68.52 +import java.util.concurrent.Executor;
68.53 +import junit.framework.*;
68.54 +import org.netbeans.junit.*;
68.55 +import org.netbeans.modules.openide.util.ActiveQueue;
68.56 +import org.openide.util.Lookup;
68.57 +import org.openide.util.Lookup.Result;
68.58 +import org.openide.util.LookupEvent;
68.59 +import org.openide.util.LookupListener;
68.60 +
68.61 +/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
68.62 + */
68.63 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
68.64 +public class ProxyLookupTest extends AbstractLookupBaseHid
68.65 +implements AbstractLookupBaseHid.Impl {
68.66 + public ProxyLookupTest(java.lang.String testName) {
68.67 + super(testName, null);
68.68 + }
68.69 +
68.70 + public static Test suite() {
68.71 + return new NbTestSuite (ProxyLookupTest.class);
68.72 +// return new ProxyLookupTest("testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679");
68.73 + }
68.74 +
68.75 + /** Creates an lookup for given lookup. This class just returns
68.76 + * the object passed in, but subclasses can be different.
68.77 + * @param lookup in lookup
68.78 + * @return a lookup to use
68.79 + */
68.80 + public Lookup createLookup (Lookup lookup) {
68.81 + return new ProxyLookup (new Lookup[] { lookup });
68.82 + }
68.83 +
68.84 + public Lookup createInstancesLookup (InstanceContent ic) {
68.85 + return new AbstractLookup (ic);
68.86 + }
68.87 +
68.88 +
68.89 + public void clearCaches () {
68.90 + }
68.91 +
68.92 +
68.93 + /** Check whether setLookups method does not fire when there is no
68.94 + * change in the lookups.
68.95 + */
68.96 + public void testProxyListener () {
68.97 + ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
68.98 +
68.99 + final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
68.100 + final Object[] IGNORE = {
68.101 + ProxyLookup.ImmutableInternalData.EMPTY,
68.102 + ProxyLookup.ImmutableInternalData.EMPTY_ARR,
68.103 + ActiveQueue.queue(),
68.104 + Collections.emptyMap(),
68.105 + Collections.emptyList(),
68.106 + Collections.emptySet()
68.107 + };
68.108 +
68.109 + assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
68.110 +
68.111 + Lookup.Result<Object> res = lookup.lookup (template);
68.112 +
68.113 + assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
68.114 +
68.115 + LL ll = new LL ();
68.116 + res.addLookupListener (ll);
68.117 + Collection allRes = res.allInstances ();
68.118 +
68.119 + lookup.setLookups (new Lookup[0]);
68.120 +
68.121 + if (ll.getCount () != 0) {
68.122 + fail ("Calling setLookups (emptyarray) fired a change");
68.123 + }
68.124 +
68.125 + InstanceContent t = new InstanceContent();
68.126 + Lookup del = new AbstractLookup (t);
68.127 + t.add("Ahoj");
68.128 + lookup.setLookups (new Lookup[] { del });
68.129 +
68.130 + if (ll.getCount () != 1) {
68.131 + fail ("Changing lookups did not generate an event");
68.132 + }
68.133 +
68.134 + lookup.setLookups (new Lookup[] { del });
68.135 +
68.136 + if (ll.getCount () != 0) {
68.137 + fail ("Calling setLookups (thesamearray) fired a change");
68.138 + }
68.139 + }
68.140 +
68.141 + public void testNoListenersProxyListener () {
68.142 + ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
68.143 + class E implements Executor {
68.144 + Runnable r;
68.145 + public void execute(Runnable command) {
68.146 + assertNull("NO previous", r);
68.147 + r = command;
68.148 + }
68.149 + public void perform() {
68.150 + assertNotNull("We shall have a runnable", r);
68.151 + r.run();
68.152 + r = null;
68.153 + }
68.154 + }
68.155 + E executor = new E();
68.156 +
68.157 +
68.158 + final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
68.159 + final Object[] IGNORE = {
68.160 + ProxyLookup.ImmutableInternalData.EMPTY,
68.161 + ProxyLookup.ImmutableInternalData.EMPTY_ARR,
68.162 + ActiveQueue.queue(),
68.163 + Collections.emptyMap(),
68.164 + Collections.emptyList(),
68.165 + Collections.emptySet()
68.166 + };
68.167 +
68.168 + assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
68.169 +
68.170 + Lookup.Result<Object> res = lookup.lookup (template);
68.171 +
68.172 + assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
68.173 +
68.174 + LL ll = new LL ();
68.175 + res.addLookupListener (ll);
68.176 + Collection allRes = res.allInstances ();
68.177 +
68.178 + lookup.setLookups (executor, new Lookup[0]);
68.179 + if (ll.getCount () != 0) {
68.180 + fail ("Calling setLookups (emptyarray) fired a change");
68.181 + }
68.182 +
68.183 + InstanceContent t = new InstanceContent();
68.184 + Lookup del = new AbstractLookup (t);
68.185 + t.add("Ahoj");
68.186 + lookup.setLookups (executor, new Lookup[] { del });
68.187 + assertEquals("No change yet", 0, ll.getCount());
68.188 + executor.perform();
68.189 + if (ll.getCount () != 1) {
68.190 + fail ("Changing lookups did not generate an event");
68.191 + }
68.192 +
68.193 + lookup.setLookups (executor, new Lookup[] { del });
68.194 + if (ll.getCount () != 0) {
68.195 + fail ("Calling setLookups (thesamearray) fired a change");
68.196 + }
68.197 + }
68.198 +
68.199 + public void testSetLookups () throws Exception {
68.200 + AbstractLookup a1 = new AbstractLookup (new InstanceContent ());
68.201 + AbstractLookup a2 = new AbstractLookup (new InstanceContent ());
68.202 +
68.203 + InstanceContent i3 = new InstanceContent ();
68.204 + i3.add (i3);
68.205 + AbstractLookup a3 = new AbstractLookup (i3);
68.206 +
68.207 + final ProxyLookup p = new ProxyLookup (new Lookup[] { a1, a2 });
68.208 + final Lookup.Result res1 = p.lookup (new Lookup.Template (Object.class));
68.209 + Collection c1 = res1.allInstances();
68.210 +
68.211 + Lookup.Result res2 = p.lookup (new Lookup.Template (String.class));
68.212 + Collection c2 = res2.allInstances ();
68.213 +
68.214 +
68.215 + assertTrue ("We need two results", res1 != res2);
68.216 +
68.217 + final Object blocked = new Object ();
68.218 +
68.219 + class L extends Object implements LookupListener {
68.220 + public void resultChanged (LookupEvent ev) {
68.221 + try {
68.222 + res1.removeLookupListener(this);
68.223 +
68.224 + // waiting for second thread to start #111#
68.225 + blocked.wait ();
68.226 +
68.227 + } catch (Exception ex) {
68.228 + ex.printStackTrace();
68.229 + fail ("An exception occured ");
68.230 + }
68.231 + }
68.232 + }
68.233 +
68.234 + final L listener1 = new L ();
68.235 + res1.addLookupListener (listener1);
68.236 +
68.237 +
68.238 + Runnable newLookupSetter = new Runnable() {
68.239 + public void run () {
68.240 + synchronized (blocked) {
68.241 + try {
68.242 + p.setLookups (new Lookup[0]);
68.243 + } catch (Exception ex) {
68.244 + ex.printStackTrace();
68.245 + fail ("setLookups failed.");
68.246 + } finally {
68.247 + // starts the main thread #111#
68.248 + blocked.notify ();
68.249 + }
68.250 + }
68.251 + }
68.252 + };
68.253 +
68.254 + synchronized (blocked) {
68.255 + new Thread (newLookupSetter).start ();
68.256 +
68.257 + p.setLookups (new Lookup[] { a1, a2, a3 });
68.258 + }
68.259 + }
68.260 +
68.261 + public void testProxyLookupTemplateCaching(){
68.262 + Lookup lookups[] = new Lookup[1];
68.263 + doProxyLookupTemplateCaching(lookups, false);
68.264 + }
68.265 +
68.266 + public void testProxyLookupTemplateCachingOnSizeTwoArray() {
68.267 + Lookup lookups[] = new Lookup[2];
68.268 + lookups[1] = Lookup.EMPTY;
68.269 + doProxyLookupTemplateCaching(lookups, false);
68.270 + }
68.271 + public void testProxyLookupShallNotAllowModificationOfGetLookups(){
68.272 + Lookup lookups[] = new Lookup[1];
68.273 + doProxyLookupTemplateCaching(lookups, true);
68.274 + }
68.275 +
68.276 + public void testProxyLookupShallNotAllowModificationOfGetLookupsOnSizeTwoArray() {
68.277 + Lookup lookups[] = new Lookup[2];
68.278 + lookups[1] = Lookup.EMPTY;
68.279 + doProxyLookupTemplateCaching(lookups, true);
68.280 + }
68.281 +
68.282 + /** Index 0 of lookups will be modified, the rest is up to the
68.283 + * setup code.
68.284 + */
68.285 + private void doProxyLookupTemplateCaching(Lookup[] lookups, boolean reget) {
68.286 + // Create MyProxyLookup with one lookup containing the String object
68.287 + InstanceContent inst = new InstanceContent();
68.288 + inst.add(new String("Hello World")); //NOI18N
68.289 + lookups[0] = new AbstractLookup(inst);
68.290 + ProxyLookup proxy = new ProxyLookup(lookups);
68.291 + if (reget) {
68.292 + lookups = proxy.getLookups();
68.293 + }
68.294 +
68.295 + // Performing template lookup for String object
68.296 + Lookup.Result result = proxy.lookup(new Lookup.Template(String.class, null, null));
68.297 + int stringTemplateResultSize = result.allInstances().size();
68.298 + assertEquals ("Ensure, there is only one instance of String.class in proxyLookup:", //NOI18N
68.299 + 1, stringTemplateResultSize);
68.300 +
68.301 + // Changing lookup in proxy lookup, now it will contain
68.302 + // StringBuffer Object instead of String
68.303 + InstanceContent ic2 = new InstanceContent();
68.304 + ic2.add(new Integer(1234567890));
68.305 + lookups[0] = new AbstractLookup(ic2);
68.306 + proxy.setLookups(lookups);
68.307 +
68.308 + assertEquals ("the old result is updated", 0, result.allInstances().size());
68.309 +
68.310 + // Instance of String.class should not appear in proxyLookup
68.311 + Lookup.Result r2 = proxy.lookup(new Lookup.Template(String.class, null, null));
68.312 + assertEquals ("Instance of String.class should not appear in proxyLookup:", //NOI18N
68.313 + 0, r2.allInstances().size());
68.314 +
68.315 + Lookup.Result r3 = proxy.lookup(new Lookup.Template(Integer.class, null, null));
68.316 + assertEquals ("There is only one instance of Integer.class in proxyLookup:", //NOI18N
68.317 + 1, r3.allInstances().size());
68.318 + }
68.319 +
68.320 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
68.321 + doListeningAndQueryingByTwoListenersSetLookups(0, 1);
68.322 + }
68.323 + public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
68.324 + doListeningAndQueryingByTwoListenersSetLookups(1, 1);
68.325 + }
68.326 + public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
68.327 + doListeningAndQueryingByTwoListenersSetLookups(2, 1);
68.328 + }
68.329 +
68.330 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
68.331 + doListeningAndQueryingByTwoListenersSetLookups(0, 2);
68.332 + }
68.333 + public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
68.334 + doListeningAndQueryingByTwoListenersSetLookups(1, 2);
68.335 + }
68.336 + public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
68.337 + doListeningAndQueryingByTwoListenersSetLookups(2, 2);
68.338 + }
68.339 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
68.340 + doListeningAndQueryingByTwoListenersSetLookups(0, 22);
68.341 + }
68.342 + public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
68.343 + doListeningAndQueryingByTwoListenersSetLookups(1, 22);
68.344 + }
68.345 + public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
68.346 + doListeningAndQueryingByTwoListenersSetLookups(2, 22);
68.347 + }
68.348 +
68.349 + private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth) {
68.350 + ProxyLookup orig = new ProxyLookup();
68.351 + ProxyLookup on = orig;
68.352 +
68.353 + while (--depth > 0) {
68.354 + on = new ProxyLookup(new Lookup[] { on });
68.355 + }
68.356 +
68.357 +
68.358 + final ProxyLookup lookup = on;
68.359 +
68.360 + class L implements LookupListener {
68.361 + Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
68.362 + Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
68.363 + Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
68.364 +
68.365 + {
68.366 + integer.addLookupListener(this);
68.367 + number.addLookupListener(this);
68.368 + serial.addLookupListener(this);
68.369 + }
68.370 +
68.371 + int round;
68.372 +
68.373 + public void resultChanged(LookupEvent ev) {
68.374 + Collection c1 = get(type, integer);
68.375 + Collection c2 = get(type, number);
68.376 + Collection c3 = get(type, serial);
68.377 +
68.378 + assertEquals("round " + round + " c1 vs. c2", c1, c2);
68.379 + assertEquals("round " + round + " c1 vs. c3", c1, c3);
68.380 + assertEquals("round " + round + " c2 vs. c3", c2, c3);
68.381 +
68.382 + round++;
68.383 + }
68.384 +
68.385 + private Collection get(int type, Lookup.Result res) {
68.386 + Collection c;
68.387 + switch(type) {
68.388 + case 0: c = res.allInstances(); break;
68.389 + case 1: c = res.allClasses(); break;
68.390 + case 2: c = res.allItems(); break;
68.391 + default: c = null; fail("Type: " + type); break;
68.392 + }
68.393 +
68.394 + assertNotNull(c);
68.395 + return new ArrayList(c);
68.396 + }
68.397 + }
68.398 +
68.399 + L listener = new L();
68.400 + listener.resultChanged(null);
68.401 + ArrayList arr = new ArrayList();
68.402 + for(int i = 0; i < 100; i++) {
68.403 + arr.add(new Integer(i));
68.404 +
68.405 + orig.setLookups(new Lookup[] { Lookups.fixed(arr.toArray()) });
68.406 + }
68.407 +
68.408 + assertEquals("3x100+1 checks", 301, listener.round);
68.409 + }
68.410 +
68.411 + static Object holder;
68.412 +
68.413 + public void testProxyWithLiveResultCanBeCollected() {
68.414 + Lookup layer0 = Lookups.singleton("Hello");
68.415 + Lookup layer1 = new ProxyLookup(new Lookup[] { layer0 });
68.416 + Lookup layer2 = new ProxyLookup(new Lookup[] { layer1 });
68.417 + Lookup.Result result1 = layer1.lookup(new Lookup.Template(String.class));
68.418 +
68.419 + assertEquals("One instance", 1, result1.allInstances().size());
68.420 +
68.421 + // this will create ProxyLookup$R which listens on origResult
68.422 + Lookup.Result result2 = layer2.lookup(new Lookup.Template(String.class));
68.423 +
68.424 + // this line is necessary. W/o actually querying the result,
68.425 + // it will nether compute it nor attach the listener.
68.426 + assertEquals("One instance", 1, result2.allInstances().size());
68.427 +
68.428 + result2.addLookupListener(new LookupListener() {
68.429 + public void resultChanged(LookupEvent ev) {}
68.430 + });
68.431 +
68.432 + Reference ref = new WeakReference(layer2);
68.433 + layer2 = null;
68.434 + result2 = null;
68.435 + try {
68.436 + holder = result1;
68.437 + assertGC ("The proxy lookup not been garbage collected!", ref);
68.438 + } finally {
68.439 + holder = null;
68.440 + }
68.441 + }
68.442 +
68.443 + public void testArrayIndexAsInIssue119292() throws Exception {
68.444 + final ProxyLookup pl = new ProxyLookup();
68.445 + final int[] cnt = { 0 };
68.446 +
68.447 + class L extends Lookup {
68.448 + L[] set;
68.449 + Lookup l;
68.450 +
68.451 + public L(String s) {
68.452 + l = Lookups.singleton(s);
68.453 + }
68.454 +
68.455 + @Override
68.456 + public <T> T lookup(Class<T> clazz) {
68.457 + return l.lookup(clazz);
68.458 + }
68.459 +
68.460 + @Override
68.461 + public <T> Result<T> lookup(Template<T> template) {
68.462 + return l.lookup(template);
68.463 + }
68.464 +
68.465 + @Override
68.466 + @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
68.467 + public boolean equals(Object obj) {
68.468 + if (set != null) {
68.469 + cnt[0]++;
68.470 + pl.setLookups(set);
68.471 + }
68.472 + return super.equals(obj);
68.473 + }
68.474 +
68.475 + @Override
68.476 + public int hashCode() {
68.477 + int hash = 3;
68.478 + return hash;
68.479 + }
68.480 + }
68.481 +
68.482 + Result<String> res = pl.lookupResult(String.class);
68.483 + assertEquals(Collections.EMPTY_LIST, res.allItems());
68.484 +
68.485 + L[] old = { new L("A"), new L("B") };
68.486 + L[] now = { new L("C") };
68.487 +
68.488 + pl.setLookups(old);
68.489 + cnt[0] = 0;
68.490 +
68.491 + old[0].set = new L[0];
68.492 + pl.setLookups(now);
68.493 +
68.494 + assertEquals("No call to equals", 0, cnt[0]);
68.495 +
68.496 + assertEquals("Still assigned to C", Collections.singletonList("C"), res.allInstances());
68.497 + }
68.498 +
68.499 + public void testArrayIndexWithAddRemoveListenerAsInIssue119292() throws Exception {
68.500 + final ProxyLookup pl = new ProxyLookup();
68.501 + final int[] cnt = { 0 };
68.502 +
68.503 + class L extends Lookup {
68.504 + L[] set;
68.505 + Lookup l;
68.506 +
68.507 + public L(String s) {
68.508 + l = Lookups.singleton(s);
68.509 + }
68.510 +
68.511 + @Override
68.512 + public <T> T lookup(Class<T> clazz) {
68.513 + return l.lookup(clazz);
68.514 + }
68.515 +
68.516 + @Override
68.517 + public <T> Result<T> lookup(Template<T> template) {
68.518 + Result<T> r = l.lookup(template);
68.519 + return new R<T>(r);
68.520 + }
68.521 +
68.522 + final class R<T> extends Result<T> {
68.523 + private Result<T> delegate;
68.524 +
68.525 + public R(Result<T> delegate) {
68.526 + this.delegate = delegate;
68.527 + }
68.528 +
68.529 + @Override
68.530 + public void addLookupListener(LookupListener l) {
68.531 + cnt[0]++;
68.532 + if (set != null) {
68.533 + pl.setLookups(set);
68.534 + }
68.535 + delegate.addLookupListener(l);
68.536 + }
68.537 +
68.538 + @Override
68.539 + public void removeLookupListener(LookupListener l) {
68.540 + cnt[0]++;
68.541 + if (set != null) {
68.542 + pl.setLookups(set);
68.543 + }
68.544 + delegate.removeLookupListener(l);
68.545 + }
68.546 +
68.547 + @Override
68.548 + public Collection<? extends T> allInstances() {
68.549 + return delegate.allInstances();
68.550 + }
68.551 + }
68.552 + }
68.553 +
68.554 + Result<String> res = pl.lookupResult(String.class);
68.555 + assertEquals(Collections.EMPTY_LIST, res.allItems());
68.556 +
68.557 + L[] old = { new L("A"), new L("B") };
68.558 + L[] now = { new L("C") };
68.559 +
68.560 + pl.setLookups(old);
68.561 + cnt[0] = 0;
68.562 +
68.563 + old[0].set = new L[0];
68.564 + pl.setLookups(now);
68.565 +
68.566 + if (cnt[0] == 0) {
68.567 + fail("There should be calls to listeners");
68.568 + }
68.569 +
68.570 + assertEquals("C is overriden from removeLookupListener", Collections.emptyList(), res.allInstances());
68.571 + }
68.572 +
68.573 +
68.574 + public void testArrayIndexWithSetLookupAsInIssue123679() throws Exception {
68.575 + final ProxyLookup pl = new ProxyLookup();
68.576 + final int[] cnt = { 0 };
68.577 +
68.578 + class L extends Lookup {
68.579 + L[] set;
68.580 + Lookup l;
68.581 + Collection<? extends Serializable> res;
68.582 +
68.583 + public L(String s) {
68.584 + l = Lookups.singleton(s);
68.585 + }
68.586 +
68.587 + @Override
68.588 + public <T> T lookup(Class<T> clazz) {
68.589 + return l.lookup(clazz);
68.590 + }
68.591 +
68.592 + @Override
68.593 + public <T> Result<T> lookup(Template<T> template) {
68.594 + cnt[0]++;
68.595 + if (set != null) {
68.596 + pl.setLookups(set);
68.597 + res = pl.lookupAll(Serializable.class);
68.598 + }
68.599 + Result<T> r = l.lookup(template);
68.600 + return r;
68.601 + }
68.602 + }
68.603 +
68.604 + L[] now = { new L("A"), new L("B") };
68.605 + L[] old = { new L("C") };
68.606 + pl.setLookups(old);
68.607 + old[0].set = now;
68.608 +
68.609 + Result<String> res = pl.lookupResult(String.class);
68.610 + assertEquals("New items visible", 2, res.allItems().size());
68.611 +
68.612 +
68.613 + pl.setLookups(new L("X"), new L("Y"), new L("Z"));
68.614 + }
68.615 +
68.616 + public void testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679() throws Exception {
68.617 + final ProxyLookup pl = new ProxyLookup();
68.618 + final int[] cnt = { 0 };
68.619 +
68.620 + class L extends Lookup {
68.621 + L[] set;
68.622 + Lookup l;
68.623 + Collection<? extends Serializable> res;
68.624 +
68.625 + public L(String s) {
68.626 + l = Lookups.singleton(s);
68.627 + }
68.628 +
68.629 + @Override
68.630 + public <T> T lookup(Class<T> clazz) {
68.631 + return l.lookup(clazz);
68.632 + }
68.633 +
68.634 + @Override
68.635 + public <T> Result<T> lookup(Template<T> template) {
68.636 + cnt[0]++;
68.637 + if (set != null) {
68.638 + pl.setLookups(set);
68.639 + res = pl.lookupAll(Serializable.class);
68.640 + }
68.641 + Result<T> r = l.lookup(template);
68.642 + return r;
68.643 + }
68.644 + }
68.645 +
68.646 + L dupl = new L("A");
68.647 + L[] now = { dupl };
68.648 + L[] old = { new L("C") };
68.649 + pl.setLookups(old);
68.650 + old[0].set = now;
68.651 +
68.652 + Result<String> res = pl.lookupResult(String.class);
68.653 + assertEquals("New items visible", 1, res.allItems().size());
68.654 +
68.655 +
68.656 + pl.setLookups(old);
68.657 + }
68.658 +}
69.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
69.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleLookupTest.java Mon Dec 14 20:58:39 2009 +0100
69.3 @@ -0,0 +1,351 @@
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-2009 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.lookup;
69.46 +
69.47 +import java.util.ArrayList;
69.48 +import java.util.Arrays;
69.49 +import java.util.Collection;
69.50 +import java.util.List;
69.51 +import java.util.Set;
69.52 +import org.netbeans.junit.NbTestCase;
69.53 +import org.openide.util.Lookup;
69.54 +
69.55 +/**
69.56 + * Tests for class SimpleLookup.
69.57 + * @author David Strupl
69.58 + */
69.59 +public class SimpleLookupTest extends NbTestCase {
69.60 +
69.61 + public SimpleLookupTest(String testName) {
69.62 + super(testName);
69.63 + }
69.64 +
69.65 + public void testEmptyLookup() {
69.66 + assertSize("Lookup.EMPTY should be small", 8, Lookup.EMPTY);
69.67 + }
69.68 +
69.69 + /**
69.70 + * Simple tests testing singleton lookup.
69.71 + */
69.72 + public void testSingleton() {
69.73 + //
69.74 + Object orig = new Object();
69.75 + Lookup p1 = Lookups.singleton(orig);
69.76 + Object obj = p1.lookup(Object.class);
69.77 + assertTrue(obj == orig);
69.78 + assertNull(p1.lookup(String.class));
69.79 + assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
69.80 + //
69.81 + Lookup p2 = Lookups.singleton("test");
69.82 + assertNotNull(p2.lookup(Object.class));
69.83 + assertNotNull(p2.lookup(String.class));
69.84 + assertNotNull(p2.lookup(java.io.Serializable.class));
69.85 + }
69.86 +
69.87 + public void testEmptyFixed() {
69.88 + Lookup l = Lookups.fixed();
69.89 + assertSize("Lookups.fixed() for empty list of items should be small", 8, l);
69.90 + assertSame(Lookup.EMPTY, l);
69.91 + }
69.92 +
69.93 + public void testSingleItemFixed() {
69.94 + Object o = new Object();
69.95 + Lookup l = Lookups.fixed(o);
69.96 + assertSize("Lookups.fixed(o) for a single item should be small", 24, l);
69.97 + }
69.98 +
69.99 + /**
69.100 + * Simple tests testing fixed lookup.
69.101 + */
69.102 + public void testFixed() {
69.103 + //
69.104 + Object[] orig = new Object[] { new Object(), new Object() };
69.105 + Lookup p1 = Lookups.fixed(orig);
69.106 + Object obj = p1.lookup(Object.class);
69.107 + assertTrue(obj == orig[0] || obj == orig[1]);
69.108 + assertNull(p1.lookup(String.class));
69.109 + //
69.110 + String[] s = new String[] { "test1", "test2" };
69.111 + Lookup p2 = Lookups.fixed((Object[]) s);
69.112 + Object obj2 = p2.lookup(Object.class);
69.113 + assertNotNull(obj2);
69.114 + if (obj2 != s[0] && obj2 != s[1]) {
69.115 + fail("Returned objects are not the originals");
69.116 + }
69.117 + assertNotNull(p2.lookup(String.class));
69.118 + assertNotNull(p2.lookup(java.io.Serializable.class));
69.119 + Lookup.Template<String> t = new Lookup.Template<String>(String.class);
69.120 + Lookup.Result<String> r = p2.lookup(t);
69.121 + Collection<? extends String> all = r.allInstances();
69.122 + assertTrue(all.size() == 2);
69.123 + for (String o : all) {
69.124 + assertTrue("allInstances contains wrong objects", o.equals(s[0]) || o.equals(s[1]));
69.125 + }
69.126 +
69.127 + try {
69.128 + Lookups.fixed(new Object[] {null});
69.129 + fail("No nulls are allowed");
69.130 + } catch (NullPointerException ex) {
69.131 + // ok, NPE is what we want
69.132 + }
69.133 + }
69.134 +
69.135 + public void testFixedSubtypes() {
69.136 + class A {}
69.137 + class B extends A {}
69.138 + Lookup l = Lookups.fixed(new A(), new B());
69.139 + assertEquals(1, l.lookupAll(B.class).size());
69.140 + assertEquals(2, l.lookupAll(A.class).size());
69.141 + }
69.142 +
69.143 + /**
69.144 + * Simple tests testing converting lookup.
69.145 + */
69.146 + public void testConverting() {
69.147 + //
69.148 + String[] orig = new String[] { TestConvertor.TEST1, TestConvertor.TEST2 };
69.149 + TestConvertor convertor = new TestConvertor();
69.150 + Lookup p1 = Lookups.fixed(orig, convertor);
69.151 + assertNull("Converting from String to Integer - it should not find String in result", p1.lookup(String.class));
69.152 + assertNotNull(p1.lookup(Integer.class));
69.153 + assertNotNull(p1.lookup(Integer.class));
69.154 + assertTrue("Convertor should be called only once.", convertor.getNumberOfConvertCalls() == 1);
69.155 + Lookup.Template<Integer> t = new Lookup.Template<Integer>(Integer.class);
69.156 + Lookup.Result<Integer> r = p1.lookup(t);
69.157 + Collection<? extends Integer> all = r.allInstances();
69.158 + assertTrue(all.size() == 2);
69.159 + for (int i : all) {
69.160 + assertTrue("allInstances contains wrong objects", i == TestConvertor.t1 || i == TestConvertor.t2);
69.161 + }
69.162 + }
69.163 +
69.164 + private static class TestConvertor implements InstanceContent.Convertor<String,Integer> {
69.165 + static final String TEST1 = "test1";
69.166 + static final int t1 = 1;
69.167 + static final String TEST2 = "test2";
69.168 + static final int t2 = 2;
69.169 +
69.170 + private int numberOfConvertCalls = 0;
69.171 +
69.172 + public Integer convert(String obj) {
69.173 + numberOfConvertCalls++;
69.174 + if (obj.equals(TEST1)) {
69.175 + return t1;
69.176 + }
69.177 + if (obj.equals(TEST2)) {
69.178 + return t2;
69.179 + }
69.180 + throw new IllegalArgumentException();
69.181 + }
69.182 +
69.183 + public String displayName(String obj) {
69.184 + return obj;
69.185 + }
69.186 +
69.187 + public String id(String obj) {
69.188 + if (obj.equals(TEST1)) {
69.189 + return TEST1;
69.190 + }
69.191 + if (obj.equals(TEST2)) {
69.192 + return TEST2;
69.193 + }
69.194 + return null;
69.195 + }
69.196 +
69.197 + public Class<? extends Integer> type(String obj) {
69.198 + return Integer.class;
69.199 + }
69.200 +
69.201 + int getNumberOfConvertCalls() {
69.202 + return numberOfConvertCalls;
69.203 + }
69.204 + }
69.205 +
69.206 + public void testLookupItem() {
69.207 + SomeInst inst = new SomeInst();
69.208 + Lookup.Item item = Lookups.lookupItem(inst, "XYZ");
69.209 +
69.210 + assertTrue("Wrong instance", item.getInstance() == inst);
69.211 + assertTrue("Wrong instance class", item.getType() == inst.getClass());
69.212 + assertEquals("Wrong id", "XYZ", item.getId());
69.213 +
69.214 + item = Lookups.lookupItem(inst, null);
69.215 + assertNotNull("Id must never be null", item.getId());
69.216 + }
69.217 +
69.218 + public void testLookupItemEquals() {
69.219 + SomeInst instA = new SomeInst();
69.220 + SomeInst instB = new SomeInst();
69.221 + Lookup.Item itemA = Lookups.lookupItem(instA, null);
69.222 + Lookup.Item itemB = Lookups.lookupItem(instB, null);
69.223 +
69.224 + assertTrue("Lookup items shouldn't be equal", !itemA.equals(itemB) && !itemB.equals(itemA));
69.225 +
69.226 + itemA = Lookups.lookupItem(instA, null);
69.227 + itemB = Lookups.lookupItem(instA, null); // same instance
69.228 +
69.229 + assertTrue("Lookup items should be equal", itemA.equals(itemB) && itemB.equals(itemA));
69.230 + assertTrue("Lookup items hashcode should be same", itemA.hashCode() == itemB.hashCode());
69.231 +
69.232 + itemA = Lookups.lookupItem(new String("VOKURKA"), null);
69.233 + itemB = Lookups.lookupItem(new String("VOKURKA"), null);
69.234 +
69.235 + assertTrue("Lookup items shouldn't be equal (2)", !itemA.equals(itemB) && !itemB.equals(itemA));
69.236 + }
69.237 +
69.238 + public void testAllClassesIssue42399 () throws Exception {
69.239 + Object[] arr = { "Ahoj", new Object () };
69.240 +
69.241 + Lookup l = Lookups.fixed (arr);
69.242 +
69.243 + Set<Class<? extends Object>> s = l.lookup(new Lookup.Template<Object>(Object.class)).allClasses();
69.244 +
69.245 + assertEquals ("Two there", 2, s.size ());
69.246 + assertTrue ("Contains Object.class", s.contains (Object.class));
69.247 + assertTrue ("Contains string", s.contains (String.class));
69.248 +
69.249 + }
69.250 +
69.251 + public void testLookupItemEarlyInitializationProblem() {
69.252 + InstanceContent ic = new InstanceContent();
69.253 + AbstractLookup al = new AbstractLookup(ic);
69.254 + LI item = new LI();
69.255 + List<AbstractLookup.Pair> pairs1 = new ArrayList<AbstractLookup.Pair>();
69.256 + List<AbstractLookup.Pair> pairs2 = new ArrayList<AbstractLookup.Pair>();
69.257 +
69.258 + assertEquals("Item's instance shouldn't be requested", 0, item.cnt);
69.259 +
69.260 + pairs1.add(new ItemPair<Object>(Lookups.<Object>lookupItem(new SomeInst(), null)));
69.261 + pairs1.add(new ItemPair<Object>(item));
69.262 + pairs1.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
69.263 +
69.264 + pairs2.add(new ItemPair<Object>(item));
69.265 + pairs2.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
69.266 +
69.267 + ic.setPairs(pairs1);
69.268 + ic.setPairs(pairs2);
69.269 +
69.270 + assertEquals("Item's instance shouldn't be requested when added to lookup", 0, item.cnt);
69.271 +
69.272 + LI item2 = al.lookup(LI.class);
69.273 + assertEquals("Item's instance should be requested", 1, item.cnt);
69.274 + }
69.275 +
69.276 + public void testConvenienceMethods() throws Exception {
69.277 + // Just check signatures and basic behavior of #73848.
69.278 + Lookup l = Lookups.fixed(new Object[] {1, "hello", 2, "goodbye"});
69.279 + Collection<? extends Integer> ints = l.lookupAll(Integer.class);
69.280 + assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
69.281 + Lookup.Result<Integer> r = l.lookupResult(Integer.class);
69.282 + ints = r.allInstances();
69.283 + assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
69.284 + }
69.285 +
69.286 + private static class SomeInst { }
69.287 +
69.288 + private static class LI extends Lookup.Item<Object> {
69.289 +
69.290 + public long cnt = 0;
69.291 +
69.292 + public String getDisplayName() {
69.293 + return getId();
69.294 + }
69.295 +
69.296 + public String getId() {
69.297 + return getClass() + "@" + hashCode();
69.298 + }
69.299 +
69.300 + public Object getInstance() {
69.301 + cnt++;
69.302 + return this;
69.303 + }
69.304 +
69.305 + public Class<? extends Object> getType() {
69.306 + return getClass();
69.307 + }
69.308 + } // End of LI class
69.309 +
69.310 + private static class ItemPair<T> extends AbstractLookup.Pair<T> {
69.311 +
69.312 + private AbstractLookup.Item<T> item;
69.313 +
69.314 + public ItemPair(Lookup.Item<T> i) {
69.315 + this.item = i;
69.316 + }
69.317 +
69.318 + protected boolean creatorOf(Object obj) {
69.319 + return item.getInstance() == obj;
69.320 + }
69.321 +
69.322 + public String getDisplayName() {
69.323 + return item.getDisplayName ();
69.324 + }
69.325 +
69.326 + public String getId() {
69.327 + return item.getId ();
69.328 + }
69.329 +
69.330 + public T getInstance() {
69.331 + return item.getInstance ();
69.332 + }
69.333 +
69.334 + public Class<? extends T> getType() {
69.335 + return item.getType ();
69.336 + }
69.337 +
69.338 + protected boolean instanceOf(Class<?> c) {
69.339 + return c.isAssignableFrom(getType());
69.340 + }
69.341 +
69.342 + public @Override boolean equals(Object o) {
69.343 + if (o instanceof ItemPair) {
69.344 + ItemPair p = (ItemPair)o;
69.345 + return item.equals (p.item);
69.346 + }
69.347 + return false;
69.348 + }
69.349 +
69.350 + public @Override int hashCode() {
69.351 + return item.hashCode ();
69.352 + }
69.353 + } // end of ItemPair
69.354 +}
70.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
70.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleProxyLookupIssue42244Test.java Mon Dec 14 20:58:39 2009 +0100
70.3 @@ -0,0 +1,120 @@
70.4 +/*
70.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
70.6 + *
70.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
70.8 + *
70.9 + * The contents of this file are subject to the terms of either the GNU
70.10 + * General Public License Version 2 only ("GPL") or the Common
70.11 + * Development and Distribution License("CDDL") (collectively, the
70.12 + * "License"). You may not use this file except in compliance with the
70.13 + * License. You can obtain a copy of the License at
70.14 + * http://www.netbeans.org/cddl-gplv2.html
70.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
70.16 + * specific language governing permissions and limitations under the
70.17 + * License. When distributing the software, include this License Header
70.18 + * Notice in each file and include the License file at
70.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
70.20 + * particular file as subject to the "Classpath" exception as provided
70.21 + * by Sun in the GPL Version 2 section of the License file that
70.22 + * accompanied this code. If applicable, add the following below the
70.23 + * License Header, with the fields enclosed by brackets [] replaced by
70.24 + * your own identifying information:
70.25 + * "Portions Copyrighted [year] [name of copyright owner]"
70.26 + *
70.27 + * Contributor(s):
70.28 + *
70.29 + * The Original Software is NetBeans. The Initial Developer of the Original
70.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
70.31 + * Microsystems, Inc. All Rights Reserved.
70.32 + *
70.33 + * If you wish your version of this file to be governed by only the CDDL
70.34 + * or only the GPL Version 2, indicate your decision by adding
70.35 + * "[Contributor] elects to include this software in this distribution
70.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
70.37 + * single choice of license, a recipient has the option to distribute
70.38 + * your version of this file under either the CDDL, the GPL Version 2 or
70.39 + * to extend the choice of license to its licensees as provided above.
70.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
70.41 + * Version 2 license, then the option applies only if the new code is
70.42 + * made subject to such option by the copyright holder.
70.43 + */
70.44 +
70.45 +package org.openide.util.lookup;
70.46 +
70.47 +import java.lang.ref.WeakReference;
70.48 +import java.util.*;
70.49 +import junit.framework.*;
70.50 +import org.netbeans.junit.*;
70.51 +import org.openide.util.Lookup;
70.52 +
70.53 +/** To simulate issue 42244.
70.54 + */
70.55 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
70.56 +public class SimpleProxyLookupIssue42244Test extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
70.57 + public SimpleProxyLookupIssue42244Test (java.lang.String testName) {
70.58 + super(testName, null);
70.59 + }
70.60 +
70.61 + public static Test suite() {
70.62 + // return new SimpleProxyLookupIssue42244Test("testGarbageCollect");
70.63 + return new NbTestSuite(SimpleProxyLookupIssue42244Test.class);
70.64 + }
70.65 +
70.66 + /** Creates an lookup for given lookup. This class just returns
70.67 + * the object passed in, but subclasses can be different.
70.68 + * @param lookup in lookup
70.69 + * @return a lookup to use
70.70 + */
70.71 + public Lookup createLookup (final Lookup lookup) {
70.72 + class C implements Lookup.Provider {
70.73 + public Lookup getLookup () {
70.74 + return lookup;
70.75 + }
70.76 + }
70.77 + return Lookups.proxy (new C ());
70.78 + }
70.79 +
70.80 + public Lookup createInstancesLookup (InstanceContent ic) {
70.81 + return new KeepResultsProxyLookup (new AbstractLookup (ic));
70.82 + }
70.83 +
70.84 + public void clearCaches () {
70.85 + KeepResultsProxyLookup k = (KeepResultsProxyLookup)this.instanceLookup;
70.86 +
70.87 + ArrayList toGC = new ArrayList ();
70.88 + Iterator it = k.allQueries.iterator ();
70.89 + while (it.hasNext ()) {
70.90 + Lookup.Result r = (Lookup.Result)it.next ();
70.91 + toGC.add (new WeakReference (r));
70.92 + }
70.93 +
70.94 + k.allQueries = null;
70.95 +
70.96 + it = toGC.iterator ();
70.97 + while (it.hasNext ()) {
70.98 + WeakReference r = (WeakReference)it.next ();
70.99 + assertGC ("Trying to release all results from memory", r);
70.100 + }
70.101 + }
70.102 +
70.103 + class KeepResultsProxyLookup extends ProxyLookup {
70.104 + private ArrayList allQueries = new ArrayList ();
70.105 + private ThreadLocal in = new ThreadLocal ();
70.106 +
70.107 + public KeepResultsProxyLookup (Lookup delegate) {
70.108 + super (new Lookup[] { delegate });
70.109 + }
70.110 +
70.111 + @Override
70.112 + protected void beforeLookup (org.openide.util.Lookup.Template template) {
70.113 + super.beforeLookup (template);
70.114 + if (allQueries != null && in.get () == null) {
70.115 + in.set (this);
70.116 + Lookup.Result res = lookup (template);
70.117 + allQueries.add (res);
70.118 + in.set (null);
70.119 + }
70.120 + }
70.121 +
70.122 + }
70.123 +}
71.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
71.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleProxyLookupSpeedIssue42244Test.java Mon Dec 14 20:58:39 2009 +0100
71.3 @@ -0,0 +1,118 @@
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. Portions Copyright 1997-2006 Sun
71.31 + * Microsystems, Inc. All Rights Reserved.
71.32 + *
71.33 + * If you wish your version of this file to be governed by only the CDDL
71.34 + * or only the GPL Version 2, indicate your decision by adding
71.35 + * "[Contributor] elects to include this software in this distribution
71.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
71.37 + * single choice of license, a recipient has the option to distribute
71.38 + * your version of this file under either the CDDL, the GPL Version 2 or
71.39 + * to extend the choice of license to its licensees as provided above.
71.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
71.41 + * Version 2 license, then the option applies only if the new code is
71.42 + * made subject to such option by the copyright holder.
71.43 + */
71.44 +
71.45 +package org.openide.util.lookup;
71.46 +
71.47 +import java.util.HashSet;
71.48 +import java.util.Set;
71.49 +import org.netbeans.junit.NbTestCase;
71.50 +
71.51 +import org.netbeans.junit.RandomlyFails;
71.52 +import org.openide.util.Lookup;
71.53 +
71.54 +/**
71.55 + * @author Petr Nejedly, adapted to test by Jaroslav Tulach
71.56 + */
71.57 +@RandomlyFails // NB-Core-Build #1847
71.58 +public class SimpleProxyLookupSpeedIssue42244Test extends NbTestCase {
71.59 +
71.60 + public SimpleProxyLookupSpeedIssue42244Test (String name) {
71.61 + super (name);
71.62 + }
71.63 +
71.64 + public void testCompareTheSpeed () {
71.65 + String content1 = "String1";
71.66 + String content2 = "String2";
71.67 +
71.68 + Lookup fixed1 = Lookups.singleton(content1);
71.69 + Lookup fixed2 = Lookups.singleton(content2);
71.70 +
71.71 + MyProvider provider = new MyProvider();
71.72 + provider.setLookup(fixed1);
71.73 +
71.74 + Lookup top = Lookups.proxy(provider);
71.75 +
71.76 + Lookup.Result<String> r0 = top.lookupResult(String.class);
71.77 + r0.allInstances();
71.78 +
71.79 + long time = System.currentTimeMillis();
71.80 + top.lookupAll(String.class);
71.81 + long withOneResult = System.currentTimeMillis() - time;
71.82 +
71.83 +
71.84 + Set<Object> results = new HashSet<Object>();
71.85 + for (int i=0; i<10000; i++) {
71.86 + Lookup.Result<String> res = top.lookupResult(String.class);
71.87 + results.add (res);
71.88 + res.allInstances();
71.89 + }
71.90 +
71.91 + provider.setLookup(fixed2);
71.92 +
71.93 + time = System.currentTimeMillis();
71.94 + top.lookupAll(String.class);
71.95 + long withManyResults = System.currentTimeMillis() - time;
71.96 +
71.97 + // if the measurement takes less then 10ms, pretend 10ms
71.98 + if (withManyResults < 10) {
71.99 + withManyResults = 10;
71.100 + }
71.101 + if (withOneResult < 10) {
71.102 + withOneResult = 10;
71.103 + }
71.104 +
71.105 + if (withManyResults >= 10 * withOneResult) {
71.106 + fail ("With many results the test runs too long.\n With many: " + withManyResults + "\n With one : " + withOneResult);
71.107 + }
71.108 + }
71.109 +
71.110 + private static class MyProvider implements Lookup.Provider {
71.111 + private Lookup lookup;
71.112 + public Lookup getLookup() {
71.113 + return lookup;
71.114 + }
71.115 +
71.116 + void setLookup(Lookup lookup) {
71.117 + this.lookup = lookup;
71.118 + }
71.119 + }
71.120 +
71.121 +}
72.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
72.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SimpleProxyLookupTest.java Mon Dec 14 20:58:39 2009 +0100
72.3 @@ -0,0 +1,73 @@
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.lookup;
72.46 +
72.47 +import java.lang.ref.WeakReference;
72.48 +import org.netbeans.junit.NbTestCase;
72.49 +import org.openide.util.Lookup;
72.50 +import org.openide.util.Lookup.Provider;
72.51 +
72.52 +/**
72.53 + *
72.54 + * @author Jan Lahoda
72.55 + */
72.56 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
72.57 +public class SimpleProxyLookupTest extends NbTestCase {
72.58 +
72.59 + public SimpleProxyLookupTest(String testName) {
72.60 + super(testName);
72.61 + }
72.62 +
72.63 + public void test69810() throws Exception {
72.64 + Lookup.Template t = new Lookup.Template(String.class);
72.65 + SimpleProxyLookup spl = new SimpleProxyLookup(new Provider() {
72.66 + public Lookup getLookup() {
72.67 + return Lookups.fixed(new Object[] {"test1", "test2"});
72.68 + }
72.69 + });
72.70 +
72.71 + assertGC("", new WeakReference(spl.lookup(t)));
72.72 +
72.73 + spl.lookup(new Lookup.Template(Object.class)).allInstances();
72.74 + }
72.75 +
72.76 +}
73.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
73.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/SingletonLookupTest.java Mon Dec 14 20:58:39 2009 +0100
73.3 @@ -0,0 +1,113 @@
73.4 +/*
73.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
73.6 + *
73.7 + * Copyright 2008 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 + * If you wish your version of this file to be governed by only the CDDL
73.28 + * or only the GPL Version 2, indicate your decision by adding
73.29 + * "[Contributor] elects to include this software in this distribution
73.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
73.31 + * single choice of license, a recipient has the option to distribute
73.32 + * your version of this file under either the CDDL, the GPL Version 2 or
73.33 + * to extend the choice of license to its licensees as provided above.
73.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
73.35 + * Version 2 license, then the option applies only if the new code is
73.36 + * made subject to such option by the copyright holder.
73.37 + *
73.38 + * Contributor(s):
73.39 + *
73.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
73.41 + */
73.42 +
73.43 +package org.openide.util.lookup;
73.44 +
73.45 +import java.util.Collection;
73.46 +import org.netbeans.junit.NbTestCase;
73.47 +import org.openide.util.Lookup;
73.48 +
73.49 +/**
73.50 + * Contains tests of class {@code SingletonLookup}.
73.51 + *
73.52 + * @author Marian Petras
73.53 + */
73.54 +public class SingletonLookupTest extends NbTestCase {
73.55 +
73.56 + public SingletonLookupTest(String testName) {
73.57 + super(testName);
73.58 + }
73.59 +
73.60 + public void testBasics() {
73.61 + Object orig = new Object();
73.62 + Lookup p1 = new SingletonLookup(orig);
73.63 + Object obj = p1.lookup(Object.class);
73.64 + assertTrue(obj == orig);
73.65 + assertNull(p1.lookup(String.class));
73.66 + assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
73.67 + //
73.68 + Lookup p2 = new SingletonLookup("test");
73.69 + assertNotNull(p2.lookup(Object.class));
73.70 + assertNotNull(p2.lookup(String.class));
73.71 + assertNotNull(p2.lookup(java.io.Serializable.class));
73.72 + }
73.73 +
73.74 + public void testId() {
73.75 + Object orig = new Object();
73.76 + Collection allInstances;
73.77 +
73.78 + Lookup l = new SingletonLookup(orig, "id");
73.79 +
73.80 + allInstances = l.lookup(new Lookup.Template<Object>(Object.class, null, null)).allInstances();
73.81 + assertNotNull(allInstances);
73.82 + assertFalse(allInstances.isEmpty());
73.83 + assertEquals(1, allInstances.size());
73.84 + assertTrue(allInstances.iterator().next() == orig);
73.85 +
73.86 + allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "id", null)).allInstances();
73.87 + assertNotNull(allInstances);
73.88 + assertFalse(allInstances.isEmpty());
73.89 + assertEquals(1, allInstances.size());
73.90 + assertTrue(allInstances.iterator().next() == orig);
73.91 +
73.92 + allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "not", null)).allInstances();
73.93 + assertNotNull(allInstances);
73.94 + assertTrue(allInstances.isEmpty());
73.95 +
73.96 + allInstances = l.lookup(new Lookup.Template<String>(String.class, null, null)).allInstances();
73.97 + assertNotNull(allInstances);
73.98 + assertTrue(allInstances.isEmpty());
73.99 +
73.100 + allInstances = l.lookup(new Lookup.Template<String>(String.class, "id", null)).allInstances();
73.101 + assertNotNull(allInstances);
73.102 + assertTrue(allInstances.isEmpty());
73.103 +
73.104 + allInstances = l.lookup(new Lookup.Template<String>(String.class, "not", null)).allInstances();
73.105 + assertNotNull(allInstances);
73.106 + assertTrue(allInstances.isEmpty());
73.107 + }
73.108 +
73.109 + public void testSize() {
73.110 + final Object obj = new Object();
73.111 + assertSize("The singleton lookup instance should be small",
73.112 + 24,
73.113 + new SingletonLookup(obj));
73.114 + }
73.115 +
73.116 +}
74.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
74.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/problem100320.txt Mon Dec 14 20:58:39 2009 +0100
74.3 @@ -0,0 +1,17 @@
74.4 +:java.io.IOException:
74.5 +java.nio.charset.CharacterCodingException
74.6 +java.io.EOFException
74.7 +java.io.FileNotFoundException
74.8 +java.io.InterruptedIOException
74.9 +java.net.MalformedURLException
74.10 +java.io.IOException
74.11 +java.io.UnsupportedEncodingException
74.12 +java.io.NotActiveException
74.13 +java.io.StreamCorruptedException
74.14 +java.io.UTFDataFormatException
74.15 +java.util.zip.ZipException
74.16 +java.util.jar.JarException
74.17 +:java.util.Comparator:
74.18 +org.bar.Comparator3
74.19 +org.bar.Comparator2
74.20 +#position=5
75.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
75.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/services-jar-1.txt Mon Dec 14 20:58:39 2009 +0100
75.3 @@ -0,0 +1,17 @@
75.4 +:somedummyfile:
75.5 +org.foo.Interface
75.6 +:java.lang.Runnable:
75.7 +org.foo.impl.Runnable1
75.8 +:java.util.Comparator:
75.9 +#some comment
75.10 +org.foo.impl.Comparator1
75.11 +#position=10
75.12 +#som comment2
75.13 +:java.util.Iterator:
75.14 +org.foo.impl.Iterator1
75.15 +:org.foo.Interface:
75.16 +# Some header info, maybe.
75.17 +
75.18 +# Our first impl here
75.19 +org.foo.impl.Implementation1
75.20 +
76.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
76.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/services-jar-2.txt Mon Dec 14 20:58:39 2009 +0100
76.3 @@ -0,0 +1,10 @@
76.4 +:java.lang.Runnable:
76.5 +#-org.foo.impl.Runnable1
76.6 +:java.util.Comparator:
76.7 +org.bar.Comparator2
76.8 +#position=5
76.9 +:java.util.Iterator:
76.10 +org.bar.Iterator2
76.11 +#position=100
76.12 +:org.foo.Interface:
76.13 +org.bar.Implementation2
77.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
77.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java Mon Dec 14 20:58:39 2009 +0100
77.3 @@ -0,0 +1,139 @@
77.4 +/*
77.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
77.6 + *
77.7 + * Copyright 2008 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 + * If you wish your version of this file to be governed by only the CDDL
77.28 + * or only the GPL Version 2, indicate your decision by adding
77.29 + * "[Contributor] elects to include this software in this distribution
77.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
77.31 + * single choice of license, a recipient has the option to distribute
77.32 + * your version of this file under either the CDDL, the GPL Version 2 or
77.33 + * to extend the choice of license to its licensees as provided above.
77.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
77.35 + * Version 2 license, then the option applies only if the new code is
77.36 + * made subject to such option by the copyright holder.
77.37 + *
77.38 + * Contributor(s):
77.39 + *
77.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
77.41 + */
77.42 +
77.43 +package org.openide.util.test;
77.44 +
77.45 +import java.io.File;
77.46 +import java.io.FileWriter;
77.47 +import java.io.IOException;
77.48 +import java.io.OutputStream;
77.49 +import java.io.PrintWriter;
77.50 +import java.io.Writer;
77.51 +import java.util.ArrayList;
77.52 +import java.util.List;
77.53 +import java.util.regex.Pattern;
77.54 +import javax.tools.JavaCompiler;
77.55 +import javax.tools.ToolProvider;
77.56 +import junit.framework.Assert;
77.57 +
77.58 +/**
77.59 + * Utilities useful to those testing JSR 269 annotation processors.
77.60 + * <p>If you just want to test that the output of the processor is correct,
77.61 + * you do not need to do anything special:
77.62 + * just use the annotation on some sample classes nested inside your unit test.
77.63 + * They will be processed, and you check that your SPI loads them correctly.
77.64 + * These utilities are useful mainly in case you want to check that the processor
77.65 + * rejects erroneous sources, and that any messages it prints are reasonable;
77.66 + * that it behaves correctly on incremental compilations; etc.
77.67 + */
77.68 +public class AnnotationProcessorTestUtils {
77.69 +
77.70 + private AnnotationProcessorTestUtils() {}
77.71 +
77.72 + /**
77.73 + * Create a source file.
77.74 + * @param dir source root
77.75 + * @param clazz a fully-qualified class name
77.76 + * @param content lines of text (skip package decl)
77.77 + */
77.78 + public static void makeSource(File dir, String clazz, String... content) throws IOException {
77.79 + File f = new File(dir, clazz.replace('.', File.separatorChar) + ".java");
77.80 + f.getParentFile().mkdirs();
77.81 + Writer w = new FileWriter(f);
77.82 + try {
77.83 + PrintWriter pw = new PrintWriter(w);
77.84 + String pkg = clazz.replaceFirst("\\.[^.]+$", "");
77.85 + if (!pkg.equals(clazz)) {
77.86 + pw.println("package " + pkg + ";");
77.87 + }
77.88 + for (String line : content) {
77.89 + pw.println(line);
77.90 + }
77.91 + pw.flush();
77.92 + } finally {
77.93 + w.close();
77.94 + }
77.95 + }
77.96 +
77.97 + /**
77.98 + * Run the Java compiler.
77.99 + * (A JSR 199 implementation must be available.)
77.100 + * @param src a source root (runs javac on all *.java it finds matching {@code srcIncludes})
77.101 + * @param srcIncludes a pattern of source files names without path to compile (useful for testing incremental compiles), or null for all
77.102 + * @param dest a dest dir to compile classes to
77.103 + * @param cp classpath entries; if null, use Java classpath of test
77.104 + * @param stderr output stream to print messages to, or null for test console (i.e. do not capture)
77.105 + * @return true if compilation succeeded, false if it failed
77.106 + */
77.107 + public static boolean runJavac(File src, String srcIncludes, File dest, File[] cp, OutputStream stderr) {
77.108 + List<String> args = new ArrayList<String>();
77.109 + args.add("-classpath");
77.110 + if (cp != null) {
77.111 + StringBuffer b = new StringBuffer();
77.112 + for (File entry : cp) {
77.113 + b.append(File.pathSeparatorChar);
77.114 + b.append(entry.getAbsolutePath());
77.115 + }
77.116 + args.add(b.toString());
77.117 + } else {
77.118 + args.add(System.getProperty("java.class.path"));
77.119 + }
77.120 + args.add("-d");
77.121 + args.add(dest.getAbsolutePath());
77.122 + args.add("-sourcepath");
77.123 + args.add(src.getAbsolutePath());
77.124 + dest.mkdirs();
77.125 + scan(args, src, srcIncludes);
77.126 + JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
77.127 + Assert.assertNotNull("no JSR 199 compiler impl found; try e.g.: " +
77.128 + "test.unit.run.cp.extra=${nb_all}/apisupport.harness/external/openjdk-javac-6-b12.jar", compiler);
77.129 + //System.err.println("running javac with args: " + args);
77.130 + return compiler.run(null, null, stderr, args.toArray(new String[args.size()])) == 0;
77.131 + }
77.132 + private static void scan(List<String> names, File f, String includes) {
77.133 + if (f.isDirectory()) {
77.134 + for (File kid : f.listFiles()) {
77.135 + scan(names, kid, includes);
77.136 + }
77.137 + } else if (f.getName().endsWith(".java") && (includes == null || Pattern.compile(includes).matcher(f.getName()).find())) {
77.138 + names.add(f.getAbsolutePath());
77.139 + }
77.140 + }
77.141 +
77.142 +}
78.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
78.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/test/MockLookup.java Mon Dec 14 20:58:39 2009 +0100
78.3 @@ -0,0 +1,135 @@
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-2007 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 +
78.45 +package org.openide.util.test;
78.46 +
78.47 +import java.lang.reflect.Field;
78.48 +import java.util.Collection;
78.49 +import static junit.framework.Assert.*;
78.50 +import org.openide.util.Lookup;
78.51 +import org.openide.util.lookup.Lookups;
78.52 +import org.openide.util.lookup.ProxyLookup;
78.53 +
78.54 +/**
78.55 + * Mock implementation of system default lookup suitable for use in unit tests.
78.56 + * The initial value just contains classpath services.
78.57 + */
78.58 +public class MockLookup extends ProxyLookup {
78.59 +
78.60 + private static MockLookup DEFAULT;
78.61 + private static boolean making = false;
78.62 + private static volatile boolean ready;
78.63 +
78.64 + static {
78.65 + making = true;
78.66 + try {
78.67 + System.setProperty("org.openide.util.Lookup", MockLookup.class.getName());
78.68 + if (Lookup.getDefault().getClass() != MockLookup.class) {
78.69 + // Someone else initialized lookup first. Try to force our way.
78.70 + Field defaultLookup = Lookup.class.getDeclaredField("defaultLookup");
78.71 + defaultLookup.setAccessible(true);
78.72 + defaultLookup.set(null, null);
78.73 + }
78.74 + assertEquals(MockLookup.class, Lookup.getDefault().getClass());
78.75 + } catch (Exception x) {
78.76 + throw new ExceptionInInitializerError(x);
78.77 + } finally {
78.78 + making = false;
78.79 + }
78.80 + }
78.81 +
78.82 + /** Do not call this directly! */
78.83 + public MockLookup() {
78.84 + assertTrue(making);
78.85 + assertNull(DEFAULT);
78.86 + DEFAULT = this;
78.87 + }
78.88 +
78.89 + /**
78.90 + * Just ensures that this lookup is default lookup, but does not actually change its content.
78.91 + * Useful mainly if you have some test utility method which calls foreign code which might use default lookup,
78.92 + * and you want to ensure that any users of mock lookup will see the correct default lookup right away,
78.93 + * even if they have not yet called {@link #setLookup} or {@link #setInstances}.
78.94 + */
78.95 + public static void init() {
78.96 + if (!ready) {
78.97 + setInstances();
78.98 + }
78.99 + }
78.100 +
78.101 + /**
78.102 + * Sets the global default lookup with zero or more delegate lookups.
78.103 + * Caution: if you don't include Lookups.metaInfServices, you may have trouble,
78.104 + * e.g. {@link #makeScratchDir} will not work.
78.105 + * Most of the time you should use {@link #setInstances} instead.
78.106 + */
78.107 + public static void setLookup(Lookup... lookups) {
78.108 + ready = true;
78.109 + DEFAULT.setLookups(lookups);
78.110 + }
78.111 +
78.112 + /**
78.113 + * Sets the global default lookup with some fixed instances.
78.114 + * Will also include (at a lower priority) a {@link ClassLoader},
78.115 + * and services found from <code>META-INF/services/*</code> in the classpath.
78.116 + */
78.117 + public static void setInstances(Object... instances) {
78.118 + ClassLoader l = MockLookup.class.getClassLoader();
78.119 + setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
78.120 + }
78.121 + /**
78.122 + * Sets the global default lookup with some fixed instances and
78.123 + * content read from Services folder from system file system.
78.124 + * Will also include (at a lower priority) a {@link ClassLoader},
78.125 + * and services found from <code>META-INF/services/*</code> in the classpath.
78.126 + */
78.127 + public static void setLayersAndInstances(Object... instances) {
78.128 + ClassLoader l = MockLookup.class.getClassLoader();
78.129 + if (l != Lookup.getDefault().lookup(ClassLoader.class)) {
78.130 + setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
78.131 + }
78.132 + Lookup projects = Lookups.forPath("Services");
78.133 + Collection<?> initialize = projects.lookupAll(Object.class);
78.134 + //System.err.println("all: " + initialize);
78.135 + setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l), projects);
78.136 + }
78.137 +
78.138 +}
79.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
79.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/test/MockLookupTest.java Mon Dec 14 20:58:39 2009 +0100
79.3 @@ -0,0 +1,66 @@
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-2007 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 +
79.45 +package org.openide.util.test;
79.46 +
79.47 +import junit.framework.TestCase;
79.48 +import org.openide.util.Lookup;
79.49 +
79.50 +public class MockLookupTest extends TestCase {
79.51 +
79.52 + // XXX test:
79.53 + // setLookup with one or more lookup args does not use M-I/s
79.54 + // still works if another Lookup.getDefault was set before
79.55 +
79.56 + public MockLookupTest(String n) {
79.57 + super(n);
79.58 + }
79.59 +
79.60 + public void testSetLookup() throws Exception {
79.61 + MockLookup.setInstances("hello");
79.62 + assertEquals("initial lookup works", "hello", Lookup.getDefault().lookup(String.class));
79.63 + MockLookup.setInstances("goodbye");
79.64 + assertEquals("modified lookup works", "goodbye", Lookup.getDefault().lookup(String.class));
79.65 + MockLookup.setInstances();
79.66 + assertEquals("cleared lookup works", null, Lookup.getDefault().lookup(String.class));
79.67 + }
79.68 +
79.69 +}
80.1 --- a/openide.util/apichanges.xml Thu Dec 10 19:23:25 2009 -0500
80.2 +++ b/openide.util/apichanges.xml Mon Dec 14 20:58:39 2009 +0100
80.3 @@ -43,7 +43,6 @@
80.4 <!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../nbbuild/javadoctools/apichanges.dtd">
80.5 <apichanges>
80.6 <apidefs>
80.7 - <apidef name="lookup">Lookup API</apidef>
80.8 <apidef name="util">Utilities API</apidef>
80.9 <apidef name="xml">XML API</apidef>
80.10 <apidef name="actions">Actions API</apidef>
80.11 @@ -136,23 +135,6 @@
80.12 <class package="org.openide" name="LifecycleManager"/>
80.13 <issue number="168257"/>
80.14 </change>
80.15 - <change id="org.openide.util.Lookup.paths">
80.16 - <api name="lookup"/>
80.17 - <summary>Added
80.18 - <code>org.openide.util.Lookup.paths</code> property
80.19 - </summary>
80.20 - <version major="7" minor="24"/>
80.21 - <date day="19" month="6" year="2009"/>
80.22 - <author login="jtulach"/>
80.23 - <compatibility addition="yes"/>
80.24 - <description>
80.25 - <p>
80.26 - Better way to integrate Lookup.getDefault() and system filesystem.
80.27 - </p>
80.28 - </description>
80.29 - <class package="org.openide.util" name="Lookup"/>
80.30 - <issue number="166782"/>
80.31 - </change>
80.32 <change id="enableStackTraces">
80.33 <api name="util"/>
80.34 <summary>Added constructor <code>RequestProcessor(String name, int throughput, boolean interruptThread, boolean enableStackTraces)</code></summary>
80.35 @@ -200,28 +182,6 @@
80.36 <class package="org.openide.util" name="Utilities"/>
80.37 <issue number="110492"/>
80.38 </change>
80.39 - <change id="ServiceProvider">
80.40 - <api name="lookup"/>
80.41 - <summary>Added <code>ServiceProvider</code> annotation</summary>
80.42 - <version major="7" minor="20"/>
80.43 - <date day="1" month="11" year="2008"/>
80.44 - <author login="jglick"/>
80.45 - <compatibility addition="yes">
80.46 - <p>
80.47 - Modules registering services using <code>META-INF/services</code>
80.48 - files in the source tree are encouraged to switch to the annotation.
80.49 - </p>
80.50 - </compatibility>
80.51 - <description>
80.52 - <p>
80.53 - Added annotations <code>ServiceProvider</code> and <code>ServiceProviders</code>
80.54 - to simplify registration of global singleton services.
80.55 - </p>
80.56 - </description>
80.57 - <class package="org.openide.util.lookup" name="ServiceProvider"/>
80.58 - <class package="org.openide.util.lookup" name="ServiceProviders"/>
80.59 - <issue number="150447"/>
80.60 - </change>
80.61 <change id="Utilities.OS_OPENBSD">
80.62 <api name="util"/>
80.63 <summary>Added <code>OS_OPENBSD</code> and <code>OS_UNIX_OTHER</code> fields</summary>
80.64 @@ -269,29 +229,6 @@
80.65 <class package="org.openide.xml" name="XMLUtil"/>
80.66 <issue number="42686"/>
80.67 </change>
80.68 - <change id="Lookup.asynchronous">
80.69 - <api name="lookup"/>
80.70 - <summary>AbstractLookup and ProxyLookup fire changes asynchronously</summary>
80.71 - <version major="7" minor="16"/>
80.72 - <date day="27" month="6" year="2008"/>
80.73 - <author login="jtulach"/>
80.74 - <compatibility addition="yes" binary="compatible" semantic="compatible"/>
80.75 - <description>
80.76 - <p>
80.77 - All modification methods in <code>AbstractLookup</code> and <code>ProxyLookup</code>
80.78 - were extended to accept an
80.79 - <a href="@JDK@/java/util/concurrent/Executor.html">Executor</a>.
80.80 - If not null, it is used to dispatch events to listeners sometime
80.81 - "later". Also the <code>AbstractLookup.Content</code>
80.82 - and <code>InstanceContent</code> constructors
80.83 - have been extended to accept such <code>Executor</code>s.
80.84 - </p>
80.85 - </description>
80.86 - <class package="org.openide.util.lookup" name="AbstractLookup"/>
80.87 - <class package="org.openide.util.lookup" name="ProxyLookup"/>
80.88 - <class package="org.openide.util.lookup" name="InstanceContent"/>
80.89 - <issue number="134297"/>
80.90 - </change>
80.91 <change id="RequestProcessor.Executor">
80.92 <api name="util"/>
80.93 <summary>RequestProcessor implements Executor interface</summary>
80.94 @@ -386,25 +323,6 @@
80.95 <issue number="119069"/>
80.96 </change>
80.97
80.98 - <change id="Lookups.forPath">
80.99 - <api name="util"/>
80.100 - <summary>Added simplified support for named lookups <code>Lookups.forPath</code></summary>
80.101 - <version major="7" minor="9"/>
80.102 - <date day="17" month="4" year="2007"/>
80.103 - <author login="jtulach"/>
80.104 - <compatibility addition="yes"/>
80.105 - <description>
80.106 - <p>
80.107 - New method <a href="@TOP@/org/openide/util/lookup/Lookups.html#forPath(java.lang.String)">Lookups.forPath(String)</a>
80.108 - has been added to replace now deprecated <a href="@org-openide-loaders@/org/openide/loaders/FolderLookup.html">FolderLookup</a>
80.109 - and allow modules who wants to read settings from layers
80.110 - to do so with a simpler code, without dependency on DataSystems API.
80.111 - </p>
80.112 - </description>
80.113 - <class package="org.openide.util.lookup" name="Lookups"/>
80.114 - <issue number="98426"/>
80.115 - </change>
80.116 -
80.117 <change id="ChangeSupport">
80.118 <api name="util"/>
80.119 <summary>Added <code>ChangeSupport</code></summary>
80.120 @@ -557,30 +475,6 @@
80.121 <issue number="73637"/>
80.122 </change>
80.123
80.124 - <change id="lookupAll-lookupResult">
80.125 - <api name="lookup"/>
80.126 - <summary>Convenience methods added to <code>Lookup</code></summary>
80.127 - <version major="6" minor="10"/>
80.128 - <date day="3" month="4" year="2006"/>
80.129 - <author login="jglick"/>
80.130 - <compatibility addition="yes" binary="compatible" source="incompatible">
80.131 - <p>
80.132 - Could conceivably conflict with existing subclass method with same signature
80.133 - with different semantics or return type.
80.134 - </p>
80.135 - </compatibility>
80.136 - <description>
80.137 - <p>
80.138 - Two methods, <code>lookupResult</code> and <code>lookupAll</code>, were
80.139 - added to <code>Lookup</code> to encapsulate the most common usage patterns
80.140 - with less typing, and more importantly avoiding the need to explicitly
80.141 - make a <code>Lookup.Template</code> object.
80.142 - </p>
80.143 - </description>
80.144 - <class package="org.openide.util" name="Lookup"/>
80.145 - <issue number="73848"/>
80.146 - </change>
80.147 -
80.148 <change id="use-logging" >
80.149 <api name="util"/>
80.150 <summary>Do not use ErrorManager for logging</summary>
80.151 @@ -646,32 +540,6 @@
80.152 <class package="org.openide.util" name="RequestProcessor"/>
80.153 <issue number="68031"/>
80.154 </change>
80.155 - <change id="less-events-from-proxylookup" >
80.156 - <api name="lookup"/>
80.157 - <summary>Less change notifications from ProxyLookup</summary>
80.158 - <version major="6" minor="7"/>
80.159 - <date day="11" month="11" year="2005"/>
80.160 - <author login="jtulach"/>
80.161 - <compatibility addition="no" modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no"/>
80.162 - <description>
80.163 - <a href="@TOP@/org/openide/util/lookup/ProxyLookup.html">ProxyLookup.setLookups</a>
80.164 - used to fire <a href="@TOP@/org/openide/util/LookupEvent.html">LookupEvent</a> every
80.165 - time it was called. Now it always checks whether there was a change to the
80.166 - previous state. This will reduce the number of events delivered when a small
80.167 - change is made. Also results from both
80.168 - <a href="@TOP@/org/openide/util/lookup/ProxyLookup.html">ProxyLookup</a>
80.169 - and <a href="@TOP@/org/openide/util/lookup/AbstractLookup.html">AbstractLookup</a>
80.170 - were modified to return immutable <code>Collection</code>s.
80.171 - So do not try to modify them. It was always documented that the
80.172 - results, are immutable and also it was never said that a change is
80.173 - delivered when there is no change in the result, so this is considered
80.174 - compatible change, even it is know that at least one piece of code
80.175 - in NetBeans relied on this behaviour.
80.176 - </description>
80.177 - <class package="org.openide.util.lookup" name="ProxyLookup"/>
80.178 - <class package="org.openide.util.lookup" name="AbstractLookup"/>
80.179 - <issue number="68031"/>
80.180 - </change>
80.181
80.182 <change>
80.183 <api name="util"/>
80.184 @@ -803,23 +671,6 @@
80.185 <issue number="27868"/>
80.186 </change>
80.187
80.188 - <change id="excluding-lookup">
80.189 - <api name="lookup"/>
80.190 - <summary>
80.191 -<code>Lookups.exclude</code> added to simplify writing of lookups that filter content of other lookups</summary>
80.192 - <version major="5" minor="4"/>
80.193 - <date day="14" month="1" year="2005"/>
80.194 - <author login="jtulach"/>
80.195 - <compatibility binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no" modification="no"/>
80.196 - <description>
80.197 - <p>New method that takes lookup and set of classes and return new lookup
80.198 - which contains everything from the original one except instances of
80.199 - the specified classes has been added.
80.200 - </p>
80.201 - </description>
80.202 - <class package="org.openide.util.lookup" name="Lookups"/>
80.203 - <issue number="53058"/>
80.204 - </change>
80.205 <change id="Task-waitFinished-timeout">
80.206 <api name="util"/>
80.207 <summary>New method <code>task.waitFinished(timeout)</code> added</summary>
80.208 @@ -910,22 +761,6 @@
80.209 <issue number="41166"/>
80.210 </change>
80.211 <change>
80.212 - <api name="lookup"/>
80.213 - <summary>Added ability to order items in META-INF/services/ lookup</summary>
80.214 - <version major="4" minor="34"/>
80.215 - <date day="9" month="5" year="2004"/>
80.216 - <author login="dkonecny"/>
80.217 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.218 - <description>
80.219 - Items in META-INF/services/ lookup can be followed by advisory
80.220 - "position" attribute. The resulting lookup will list first items with lower
80.221 - position value. Items without position attribute will be listed
80.222 - last. See documentation for more details on format.
80.223 - </description>
80.224 - <class package="org.openide.util.lookup" name="Lookups"/>
80.225 - <issue number="41606"/>
80.226 - </change>
80.227 -<change>
80.228 <api name="util"/>
80.229 <summary>Support for complicated listeners</summary>
80.230 <version major="4" minor="12"/>
80.231 @@ -983,20 +818,6 @@
80.232 <class package="org.openide.util" name="WeakListeners"/>
80.233 <issue number="34758"/>
80.234 </change>
80.235 -<change>
80.236 - <api name="lookup"/>
80.237 - <summary>New <code>lookupItem()</code> method in Lookups</summary>
80.238 - <version major="4" minor="8"/>
80.239 - <date day="9" month="7" year="2003"/>
80.240 - <author login="vstejskal"/>
80.241 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.242 - <description>
80.243 - New method that returns Lookup.Item implementation for given instance and key identifying
80.244 - that instance in the lookup. This method is useful when writing Looks which need to
80.245 - return some cookies (Collection of Lookup.Items).
80.246 - </description>
80.247 - <class package="org.openide.util.lookup" name="Lookups"/>
80.248 - </change>
80.249 <change id="HelpCtx.findHelp">
80.250 <api name="util"/>
80.251 <summary>New method to find HelpCtx</summary>
80.252 @@ -1049,22 +870,6 @@
80.253 <issue number="30604"/>
80.254 </change>
80.255 <change>
80.256 - <api name="lookup"/>
80.257 - <summary>New method Lookups.metaInfServices</summary>
80.258 - <version major="3" minor="35"/>
80.259 - <date day="5" month="2" year="2003"/>
80.260 - <author login="dstrupl"/>
80.261 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.262 - <description>
80.263 - A lookup that implements the JDK1.3 JAR services mechanism and delegates
80.264 - to META-INF/services/name.of.class files. This lookup was (is) used by core
80.265 - and the core had to use reflection to create an instance. Moreover can
80.266 - be usefull for module authors and in standalone library.
80.267 - </description>
80.268 - <class package="org.openide.util.lookup" name="Lookups"/>
80.269 - <issue number="29126"/>
80.270 - </change>
80.271 -<change>
80.272 <api name="util"/>
80.273 <summary>org.openide.util.Utilities.createProgressCursor added</summary>
80.274 <version major="3" minor="23"/>
80.275 @@ -1118,23 +923,6 @@
80.276 <issue number="22156"/>
80.277 </change>
80.278 <change>
80.279 - <api name="lookup"/>
80.280 - <summary>New method Lookups.proxy</summary>
80.281 - <version major="3" minor="9"/>
80.282 - <date day="20" month="9" year="2002"/>
80.283 - <author login="dstrupl"/>
80.284 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.285 - <description>
80.286 - Creates a lookup that delegates to another one but that one can change
80.287 - from time to time. The returned lookup checks every time somebody calls
80.288 - lookup or lookupItem method whether the provider still returns
80.289 - the same lookup. If not, it updates state of all Lookup.Results
80.290 - that it created (and that still exists).
80.291 - </description>
80.292 - <class package="org.openide.util.lookup" name="Lookups"/>
80.293 - <issue number="27425"/>
80.294 - </change>
80.295 -<change>
80.296 <api name="util"/>
80.297 <summary>Utilities.activeReferenceQueue()</summary>
80.298 <version major="3" minor="11"/>
80.299 @@ -1151,22 +939,6 @@
80.300 </change>
80.301 <change>
80.302 <api name="util"/>
80.303 - <summary>New interface Lookup.Provider</summary>
80.304 - <version major="3" minor="6"/>
80.305 - <date day="19" month="8" year="2002"/>
80.306 - <author login="dstrupl"/>
80.307 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.308 - <description>
80.309 - An object can have method getLookup if there is a need to provide
80.310 - local loookup instance. To recognize objects with such a facility
80.311 - we are introducing interface Lookup.Provider with only one method:
80.312 - getLookup.
80.313 - </description>
80.314 - <class package="org.openide.util" name="Lookup"/>
80.315 - <issue number="26275"/>
80.316 - </change>
80.317 -<change>
80.318 - <api name="util"/>
80.319 <summary>Deprecation of parts of MouseUtils.PopupMenuAdapter</summary>
80.320 <version major="3" minor="4"/>
80.321 <date day="6" month="8" year="2002"/>
80.322 @@ -1179,46 +951,6 @@
80.323 should be constructed via default constructor.
80.324 </description>
80.325 </change>
80.326 -<change id="meta-inf-services">
80.327 - <api name="lookup"/>
80.328 - <summary>Modules can specify the content of Lookup.getDefault
80.329 - in META-INF/services</summary>
80.330 - <version major="3" minor="3"/>
80.331 - <date day="22" month="7" year="2002"/>
80.332 - <author login="jtulach"/>
80.333 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.334 - <description>
80.335 - The content of <code>Lookup.getDefault()</code> can be specified
80.336 - by a standard JDK registration mechanism, using JARs'
80.337 - <a href="http://java.sun.com/j2se/1.4/docs/guide/jar/jar.html#Service%20Provider" shape="rect">
80.338 - META-INF/services
80.339 - </a>
80.340 - directory. This is suitable for services that do not change,
80.341 - do not require user modification and that need to be ready
80.342 - soon during initialization of the system.
80.343 - </description>
80.344 - </change>
80.345 - <change>
80.346 - <api name="lookup"/>
80.347 - <summary>
80.348 -<code>ErrorManager.isNotifiable</code> added</summary>
80.349 - <version major="3" minor="18"/>
80.350 - <date day="3" month="11" year="2002"/>
80.351 - <author login="jglick"/>
80.352 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no">
80.353 - Existing code which assumes (incorrectly) that <code>isLoggable</code>
80.354 - can be used for this purpose, or which calls <code>notify</code> at a low
80.355 - level such as <code>INFORMATIONAL</code> without first checking
80.356 - <code>isNotifiable</code> for efficiency, should be revised.
80.357 - </compatibility>
80.358 - <description>
80.359 - The method <code>ErrorManager.isNotifiable</code> was added to capture
80.360 - the fact that an error manager implementation might be more aggressive
80.361 - about displaying stack traces than log messages.
80.362 - </description>
80.363 - <class package="org.openide" name="ErrorManager"/>
80.364 - <issue number="24056"/>
80.365 - </change>
80.366 <change>
80.367 <api name="util"/>
80.368 <summary>
80.369 @@ -1246,26 +978,6 @@
80.370 <issue number="29711"/>
80.371 </change>
80.372 <change>
80.373 - <api name="lookup"/>
80.374 - <summary>Added org.openide.util.lookup.Lookups</summary>
80.375 - <version major="2" minor="21"/>
80.376 - <date day="28" month="5" year="2002"/>
80.377 - <author login="dstrupl"/>
80.378 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.379 - <description>New utility class added. The class cannot be instantiated
80.380 - and contains following static methods:
80.381 - <pre xml:space="preserve">
80.382 -<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Lookup</span> <span class="function-name">singleton</span>(<span class="type">Object</span> <span class="variable-name">objectToLookup</span>);
80.383 -<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Lookup</span> <span class="function-name">fixed</span>(<span class="type">Object</span>[] <span class="variable-name">objectsToLookup</span>);
80.384 -<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Lookup</span> <span class="function-name">fixed</span>(<span class="type">Object</span>[] <span class="variable-name">keys</span>, <span class="type">InstanceContent.Convertor</span> <span class="variable-name">convertor</span>);
80.385 -</pre>
80.386 - The methods return an instance of simple lookup implementation
80.387 - that holds the objects passed a parameter.
80.388 - </description>
80.389 - <class package="org.openide.util.lookup" name="Lookups"/>
80.390 - <issue number="20550"/>
80.391 - </change>
80.392 -<change>
80.393 <api name="util"/>
80.394 <summary>Added RequestProcessor.getDefault(), deprecated static methods in RequestProcessor</summary>
80.395 <version major="2" minor="12"/>
80.396 @@ -1325,49 +1037,6 @@
80.397 <class package="org.openide" name="ErrorManager"/>
80.398 <issue number="16854"/>
80.399 </change>
80.400 -<change id="AbstractLookup.Content-ProxyLookup.beforeLookup">
80.401 - <api name="lookup"/>
80.402 - <summary>Enhanced usage of ProxyLookup & AbstractLookup.Content</summary>
80.403 - <version major="1" minor="31"/>
80.404 - <date day="18" month="8" year="2001"/>
80.405 - <author login="jtulach"/>
80.406 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.407 - <description>
80.408 - <code>AbstractLookup.Content</code> made public to allow its usage
80.409 - for objects that do not subclass AbstractLookup. <code>ProxyLookup.beforeLookup</code>
80.410 - added so subclasses can update themselves (call setLookups (...)) before the actual lookup is
80.411 - performed.
80.412 - </description>
80.413 - <class package="org.openide.util.lookup" name="AbstractLookup"/>
80.414 - <class package="org.openide.util.lookup" name="ProxyLookup"/>
80.415 - </change>
80.416 -<change>
80.417 - <api name="lookup"/>
80.418 - <summary>Instance content simplifies creation of lookups</summary>
80.419 - <version major="1" minor="25"/>
80.420 - <!-- XXX date unknown -->
80.421 - <author login="jtulach"/>
80.422 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.423 - <description>
80.424 - Added <code>AbstractLookup.Content</code> which can be passed to an
80.425 - abstract lookup in its constructor and used to control the contents
80.426 - easily. Also <code>InstanceLookup</code> provides the common easy
80.427 - implementation.
80.428 - </description>
80.429 - <class package="org.openide.util.lookup" name="AbstractLookup"/>
80.430 - <class package="org.openide.util.lookup" name="InstanceContent"/>
80.431 - </change>
80.432 - <change id="clone-service-type" >
80.433 - <api name="lookup"/>
80.434 - <summary>
80.435 -<code>ServiceType.createClone</code> added</summary>
80.436 - <date day="30" month="11" year="2000"/>
80.437 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no">Subclasses are encouraged to implement <code>Cloneable</code>.</compatibility>
80.438 - <description>
80.439 - <code>public final ServiceType createClone()</code> added.
80.440 - </description>
80.441 - <class package="org.openide" name="ServiceType"/>
80.442 - </change>
80.443 <change id="logging-added-to-error-manager" >
80.444 <api name="util"/>
80.445 <summary>
80.446 @@ -1392,27 +1061,6 @@
80.447 <class package="org.openide" name="ErrorManager"/>
80.448 </change>
80.449 <change>
80.450 - <api name="lookup"/>
80.451 - <summary>Folder lookup may be serialized</summary>
80.452 - <version major="3" minor="27"/>
80.453 - <date day="7" month="1" year="2003"/>
80.454 - <author login="jglick"/>
80.455 - <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no">
80.456 - Modules which rely on a data object under <samp>Services/</samp> gaining
80.457 - or losing <code>InstanceCookie</code> between sessions may not work
80.458 - correctly with the cache. This is probably very rare.
80.459 - </compatibility>
80.460 - <description>
80.461 - To implement lookup caching, some lookup implementations are now
80.462 - serializable: <code>AbstractLookup</code> as well as
80.463 - <code>FolderLookup</code>'s lookup. <code>ProxyLookup</code> has a
80.464 - protected subclass constructor permitting subclasses to be serializable.
80.465 - </description>
80.466 - <class package="org.openide.util.lookup" name="AbstractLookup"/>
80.467 - <class package="org.openide.util.lookup" name="ProxyLookup"/>
80.468 - <issue number="20190"/>
80.469 - </change>
80.470 - <change>
80.471 <api name="xml"/>
80.472 <summary>Can register entity resolvers</summary>
80.473 <date day="20" month="12" year="2000"/>
80.474 @@ -1534,39 +1182,6 @@
80.475 </description>
80.476 <class package="org.openide.util" name="Mutex"/>
80.477 </change>
80.478 - <change>
80.479 - <api name="lookup"/>
80.480 - <summary>Changes in access protection of proxy lookup</summary>
80.481 - <version major="1" minor="19"/>
80.482 - <date day="8" month="7" year="2001"/>
80.483 - <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no">
80.484 - Changes to newly added feature.
80.485 - </compatibility>
80.486 - <description>
80.487 - <code>ProxyLookup.setLookups</code> made protected instead of public so
80.488 - nobody can misuse the method except the creator of the object and
80.489 - <code>ProxyLookup.getLookups</code> added. <code>ProxyLookup</code> made
80.490 - non final.
80.491 - </description>
80.492 - <class package="org.openide.util.lookup" name="ProxyLookup"/>
80.493 - </change>
80.494 -<change>
80.495 - <api name="lookup"/>
80.496 - <summary>Lookup service providers package created</summary>
80.497 - <version major="1" minor="9"/>
80.498 - <date day="1" month="6" year="2001"/>
80.499 - <author login="jtulach"/>
80.500 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.501 - <description>
80.502 - Package <code>org.openide.util.lookup</code> created, should hold SPI
80.503 - interfaces for lookup. Initially filled with <code>AbstractLookup</code>
80.504 - which introduces <code>AbstractLookup.Pair</code> and with
80.505 - <code>ProxyLookup</code>.
80.506 - </description>
80.507 - <class package="org.openide.util.lookup" name="AbstractLookup"/>
80.508 - <class package="org.openide.util.lookup" name="ProxyLookup"/>
80.509 - <package name="org.openide.util.lookup"/>
80.510 - </change>
80.511 <change id="Task.notifyRunning">
80.512 <api name="util"/>
80.513 <summary>More flexibility in controlling running of tasks</summary>
80.514 @@ -1580,34 +1195,37 @@
80.515 </description>
80.516 <class package="org.openide.util" name="Task"/>
80.517 </change>
80.518 -<change>
80.519 - <api name="lookup"/>
80.520 - <summary>Added lookup items and support APIs</summary>
80.521 - <version major="1" minor="8"/>
80.522 - <date day="25" month="5" year="2001"/>
80.523 - <author login="jtulach"/>
80.524 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.525 + <change>
80.526 + <api name="util"/>
80.527 + <summary>
80.528 + <code>ErrorManager.isNotifiable</code> added</summary>
80.529 + <version major="3" minor="18"/>
80.530 + <date day="3" month="11" year="2002"/>
80.531 + <author login="jglick"/>
80.532 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no">
80.533 + Existing code which assumes (incorrectly) that <code>isLoggable</code>
80.534 + can be used for this purpose, or which calls <code>notify</code> at a low
80.535 + level such as <code>INFORMATIONAL</code> without first checking
80.536 + <code>isNotifiable</code> for efficiency, should be revised.
80.537 + </compatibility>
80.538 <description>
80.539 - <code>Lookup</code> enhanced. Interface <code>Lookup.Item</code> and
80.540 - additional methods to access it also added.
80.541 + The method <code>ErrorManager.isNotifiable</code> was added to capture
80.542 + the fact that an error manager implementation might be more aggressive
80.543 + about displaying stack traces than log messages.
80.544 </description>
80.545 - <class package="org.openide.util" name="Lookup"/>
80.546 + <class package="org.openide" name="ErrorManager"/>
80.547 + <issue number="24056"/>
80.548 </change>
80.549 -<change>
80.550 - <api name="lookup"/>
80.551 - <summary>Lookup system introduced</summary>
80.552 - <date day="1" month="3" year="2001"/>
80.553 - <author login="jtulach"/>
80.554 - <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
80.555 + <change id="clone-service-type" >
80.556 + <api name="util"/>
80.557 + <summary>
80.558 + <code>ServiceType.createClone</code> added</summary>
80.559 + <date day="30" month="11" year="2000"/>
80.560 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no">Subclasses are encouraged to implement <code>Cloneable</code>.</compatibility>
80.561 <description>
80.562 - Better version of <code>Lookup</code> introduced. There is a
80.563 - <code>org.openide.util.Lookup</code> with bunch of inner classes and
80.564 - <code>org.openide.util.LookupListener</code> and
80.565 - <code>org.openide.util.LookupEvent</code>.
80.566 + <code>public final ServiceType createClone()</code> added.
80.567 </description>
80.568 - <class package="org.openide.util" name="Lookup"/>
80.569 - <class package="org.openide.util" name="LookupEvent"/>
80.570 - <class package="org.openide.util" name="LookupListener"/>
80.571 + <class package="org.openide" name="ServiceType"/>
80.572 </change>
80.573 <change>
80.574 <api name="util"/>
81.1 --- a/openide.util/arch.xml Thu Dec 10 19:23:25 2009 -0500
81.2 +++ b/openide.util/arch.xml Mon Dec 14 20:58:39 2009 +0100
81.3 @@ -58,32 +58,20 @@
81.4 <api group="java" name="UtilitiesAPI" category="official" type="export" url="@TOP@/org/openide/util/doc-files/api.html" />
81.5 classes.
81.6 </p>
81.7 -
81.8 - <p>
81.9 - Also this module defines the <a href="@TOP@/org/openide/util/Lookup.html">
81.10 - Lookup</a> which the NetBeans way for dynamic registration
81.11 - and lookup of
81.12 - components in our modularized component system. It allows lookup and discovery
81.13 - of features by description of their interfaces. The classes are devided
81.14 - into two parts. The
81.15 - <api group="java" name="LookupAPI" type="export" category="official" url="@TOP@/org/openide/util/lookup/doc-files/lookup-api.html">
81.16 - allows the discovery</api> and the
81.17 - <api group="java" name="LookupSPI" type="export" category="official" url="@TOP@/org/openide/util/lookup/doc-files/lookup-spi.html">
81.18 - simplifies creation and registration of own lookup objects</api>.
81.19 - </p>
81.20 </answer>
81.21
81.22
81.23 <answer id="arch-quality">
81.24 <p>
81.25 There is a lot of unit tests in
81.26 - <a href="http://www.netbeans.org/source/browse/openide/util/test/unit/src/">CVS</a>.
81.27 + <a href="http://hg.netbeans.org/main-golden/openide.util/test/unit/src/">version control</a>
81.28 + system.
81.29 </p>
81.30 </answer>
81.31
81.32 <answer id="arch-time">
81.33 <p>
81.34 - The module has been around since 1997 and is stilly improved
81.35 + The module has been around since 1997 and is still improved
81.36 from time to time.
81.37 </p>
81.38 </answer>
81.39 @@ -91,130 +79,6 @@
81.40
81.41
81.42 <answer id="arch-usecases">
81.43 -
81.44 - There is a great introduction to Lookup and its usage in its
81.45 - <a href="@TOP@/org/openide/util/Lookup.html">javadoc</a>. Here is just
81.46 - a list of frequently asked or interesting questions slowly expanding as
81.47 - people ask them:
81.48 -
81.49 - <h3>Lookup faq:</h3>
81.50 -
81.51 - <usecase id="lookup-on-certain-platform" name="How to specify that a service in Lookup should be available only on Windows?" >
81.52 -<em><b>Q:</b>
81.53 -Most of the time I specify interfaces that I want to add to the Lookup class in the layer.xml file.
81.54 -But, let's say I have a platform-specific interface (something on Windows only, for instance).</em>
81.55 -<p>
81.56 -<em>
81.57 -How can I specify (in the xml, or programmatically) that this service should only be added to the Lookup if the platform is Windows?
81.58 -</em>>
81.59 -</p>
81.60 -In general there are three ways to achieve this.
81.61 -<ul>
81.62 - <li><p>It is possible to write a specific module and enable it only on windows.
81.63 - See <a href="@org-openide-modules@/org/openide/modules/doc-files/api.html#how-os-specific">os specific modules</a> documentation.
81.64 - Then you can put a registration of your instance into your module's
81.65 - <a href="@TOP@/org/openide/util/doc-files/api.html#service-lookup">META-INF/services</a> directory and it
81.66 - will be available only on Windows.</p>
81.67 - </li>
81.68 -
81.69 - <li><p>Another possibility that does not require new module, but which executes
81.70 - a code on startup (which may have performance implications) is to use <code>methodvalue</code>
81.71 - attribute. Register your instance in layer using <code>your-Object.instance</code> file
81.72 - as described at
81.73 - <a href="@TOP@/org/openide/util/doc-files/api.html#ido-methodvalue">services
81.74 - </a> documentation and in your factory method either return the instance
81.75 - your want or <code>null</code> depending on result of <a href="@TOP@/org/openide/util/Utilities.html#isWindows()">
81.76 - Utilities.isWindows()</a> call.</p>
81.77 - </li>
81.78 - <li>
81.79 - <p>
81.80 - In some cases, the interface for which you will register an implementation permits a
81.81 - no-operation semantics. For example, <code>InstalledFileLocator.locate(...)</code> can
81.82 - return a valid <code>File</code>, or null. You could always register an
81.83 - <code>InstalledFileLocator</code> instance yet disable it on non-Windows platforms
81.84 - (always returning null).
81.85 - </p>
81.86 - </li>
81.87 -</ul>
81.88 -
81.89 - </usecase>
81.90 -
81.91 - <usecase id="lookup-extension-point" name="How shall I write an extension point for my module?" >
81.92 - <p>
81.93 - <em><b>Q:</b>
81.94 - I have more modules one of them providing the core functionality and
81.95 - few more that wish to extend it. What is the right way to do it?
81.96 - How does the Netbeans platform declare such extension point?
81.97 - </em>
81.98 - </p>
81.99 -
81.100 - <p>
81.101 -
81.102 - Start with declaring an extension interface in your
81.103 - core module and put it into the module's <em>public packages</em>. Imagine
81.104 - for example that the core module is in JAR file <code>org-my-netbeans-coremodule.jar</code>
81.105 - and already contains in manifests line like
81.106 - <code>OpenIDE-Module: org.my.netbeans.coremodule/1</code> and wants
81.107 - to display various tips of the day provided by other modules and thus defines:
81.108 - </p><pre>
81.109 -<span class="java-keywords">package</span> <span class="java-identifier">org</span><span class="java-operators">.</span><span class="java-identifier">my</span><span class="java-operators">.</span><span class="java-identifier">netbeans</span><span class="java-operators">.</span><span class="java-identifier">coremodule</span><span class="java-operators">;</span>
81.110 -
81.111 -<span class="java-keywords">public</span> <span class="java-keywords">interface</span> <span class="java-identifier">TipsOfTheDayProvider</span> <span class="java-operators">{</span>
81.112 - <span class="java-keywords">public</span> <span class="java-identifier">String</span> <span class="java-layer-method">provideTipOfTheDay</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">;</span>
81.113 -<span class="java-operators">}</span>
81.114 -</pre><p>
81.115 - And in its manifest adds line
81.116 - <code>OpenIDE-Module-Public-Packages: org.my.netbeans.coremodule.*</code>
81.117 - to specify that this package contains exported API and shall be
81.118 - accessible to other modules.
81.119 - </p>
81.120 - <p>
81.121 - When the core module is about to display the tip of the day it can ask
81.122 - the system for all registered instances of the <code>TipsOfTheDayProvider</code>,
81.123 - randomly select one of them:
81.124 - </p><pre>
81.125 -<span class="java-keywords">import</span> <span class="java-identifier">java</span><span class="java-operators">.</span><span class="java-identifier">util</span><span class="java-operators">.</span><span class="java-identifier">Collection</span><span class="java-operators">;</span>
81.126 -<span class="java-keywords">import</span> <span class="java-identifier">java</span><span class="java-operators">.</span><span class="java-identifier">util</span><span class="java-operators">.</span><span class="java-identifier">Collections</span><span class="java-operators">;</span>
81.127 -<span class="java-keywords">import</span> <span class="java-identifier">org</span><span class="java-operators">.</span><span class="java-identifier">openide</span><span class="java-operators">.</span><span class="java-identifier">util</span><span class="java-operators">.</span><span class="java-identifier">Lookup</span><span class="java-operators">;</span>
81.128 -
81.129 -<a href="@TOP@org/openide/util/Lookup.Result.html"><span class="java-identifier">Lookup</span><span class="java-operators">.</span><span class="java-identifier">Result</span></a> <span class="java-identifier">result</span> <span class="java-operators">=</span> <a href="@TOP@org/openide/util/Lookup.html"><span class="java-identifier">Lookup</span></a><span class="java-operators">.</span><span class="java-layer-method">getDefault</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">.</span><span class="java-layer-method">lookup</span> <span class="java-operators">(</span><span class="java-keywords">new</span> <a href="@TOP@org/openide/util/Lookup.Template.html"><span class="java-identifier">Lookup</span><span class="java-operators">.</span><span class="java-layer-method">Template</span></a> <span class="java-operators">(</span><span class="java-identifier">TipsOfTheDayProvider</span><span class="java-operators">.</span><span class="java-keywords">class</span><span class="java-operators">)</span><span class="java-operators">)</span><span class="java-operators">;</span>
81.130 -<span class="java-identifier">Collection</span> <span class="java-identifier">c</span> <span class="java-operators">=</span> <span class="java-identifier">result</span><span class="java-operators">.</span><a href="@TOP@org/openide/util/Lookup.Result.html#allInstances()"><span class="java-layer-method">allInstances</span></a> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">;</span>
81.131 -<span class="java-identifier">Collections</span><span class="java-operators">.</span><span class="java-layer-method">shuffle</span> <span class="java-operators">(</span><span class="java-identifier">c</span><span class="java-operators">)</span><span class="java-operators">;</span>
81.132 -<span class="java-identifier">TipsOfTheDayProvider</span> <span class="java-identifier">selected</span> <span class="java-operators">=</span> <span class="java-operators">(</span><span class="java-identifier">TipsOfTheDayProvider</span><span class="java-operators">)</span><span class="java-identifier">c</span><span class="java-operators">.</span><span class="java-layer-method">iterator</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">.</span><span class="java-layer-method">next</span> <span class="java-operators">(</span><span class="java-operators">)</span><span class="java-operators">;</span>
81.133 -</pre><p>
81.134 - and then display the tip. Simple, trivial, just by the usage of
81.135 - <a href="@TOP@org/openide/util/Lookup.html">Lookup</a> interface once
81.136 - creates a registry that other modules can enhance. But such enhancing
81.137 - of course requires work on the other side. Each module that would like
81.138 - to register its <code>TipsOfTheDayProvider</code> needs to depend on the
81.139 - core module - add
81.140 - <code>OpenIDE-Module-Module-Dependencies: org.my.netbeans.coremodule/1</code>
81.141 - into its manifest and write a class with its own implementation of the
81.142 - provider:</p><pre>
81.143 -<span class="java-keywords">package</span> <span class="java-identifier">org</span><span class="java-operators">.</span><span class="java-identifier">my</span><span class="java-operators">.</span><span class="java-identifier">netbeans</span><span class="java-operators">.</span><span class="java-identifier">extramodule</span><span class="java-operators">;</span>
81.144 -
81.145 -<span class="java-keywords">class</span> <span class="java-identifier">ExtraTip</span> <span class="java-keywords">implements</span> <span class="java-identifier">TipsOfTheDayProvider</span> <span class="java-operators">{</span>
81.146 - <span class="java-keywords">public</span> <span class="java-identifier">String</span> <span class="java-layer-method">provideTipOfTheDay</span> <span class="java-operators">(</span><span class="java-operators">)</span> <span class="java-operators">{</span>
81.147 - <span class="java-keywords">return</span> <span class="java-string-literal">"Do you know that in order to write extension point you should use Lookup?"</span><span class="java-operators">;</span>
81.148 - <span class="java-operators">}</span>
81.149 -<span class="java-operators">}</span>
81.150 -</pre><p>
81.151 - Then, the only necessary thing is to register such class by using the
81.152 - J2SE standard <api name="ProviderRegistrationMechanism"
81.153 - type="import"
81.154 - category="standard"
81.155 - group="java" /> into plain text file
81.156 - <code>META-INF/services/org.my.netbeans.coremodule.TipsOfTheDayProvider</code>
81.157 - in the module JAR containing just one line: </p><pre>
81.158 -org.my.netbeans.extramodule.ExtraTip
81.159 -</pre><p>
81.160 - and your modules are now ready to communicate
81.161 - using your own <em>extension point</em>.
81.162 - </p>
81.163 -
81.164 - </usecase>
81.165 -
81.166 -
81.167 <usecase id="logging" name="How shall I do or influence logging in NetBeans?">
81.168 <p>
81.169 If you are interested in logging from inside your module, or in writing
81.170 @@ -222,8 +86,6 @@
81.171 to start is the <a href="@TOP@/org/openide/util/doc-files/logging.html">NetBeans logging guide</a>.
81.172 </p>
81.173 </usecase>
81.174 -
81.175 -
81.176 </answer>
81.177
81.178
81.179 @@ -249,28 +111,6 @@
81.180 </p>
81.181 </answer>
81.182
81.183 -
81.184 -
81.185 - <answer id="compat-standards">
81.186 - <p>
81.187 - The default lookup registration follows the JDK's
81.188 - <api name="ProviderRegistrationMechanism"
81.189 - type="import"
81.190 - category="standard"
81.191 - url="http://java.sun.com/j2se/1.3/docs/guide/jar/jar.html#Provider%20Configuration%20File"
81.192 - group="java"
81.193 - />
81.194 - but enhances it to also support the
81.195 - <api
81.196 - name="ProviderRegistrationRemoval"
81.197 - type="export"
81.198 - category="devel"
81.199 - url="@TOP@/org/openide/util/doc-files/api.html#service-lookup"
81.200 - group="java"
81.201 - />.
81.202 - </p>
81.203 - </answer>
81.204 -
81.205 <answer id="compat-version">
81.206 <p>
81.207 This module has no settings.
81.208 @@ -301,7 +141,7 @@
81.209 indirectly communicates with <a href="@org-openide-awt@/overview-summary.html">UI Utilities</a>
81.210 module using <api name="AWTBridge" category="private" group="java" type="export"
81.211 url="http://www.netbeans.org/source/browse/openide/util/src/org/netbeans/modules/openide/util/AWTBridge.java">
81.212 - a class that is looked up in <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.213 + a class that is looked up in <a href="@org-openide-util-lookup@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.214 and if registered can provide better UI elements for <a href="@JDK@/javax/swing/Action.html">Action</a>s.
81.215 </api>
81.216
81.217 @@ -486,50 +326,6 @@
81.218 used on few places
81.219 </api>.
81.220 </li>
81.221 -
81.222 - <li>
81.223 - <api type="export" group="property" name="org.openide.util.Lookup" category="devel">
81.224 - checked by the initialization of the
81.225 - <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.226 - and can
81.227 - contain name of a class that extends <code>org.openide.util.Lookup</code> and
81.228 - has public constructor, that should be instantiated and returned from
81.229 - <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.230 - the class will be loaded by
81.231 - <a href="@JDK@/java/lang/Thread.html#getContextClassLoader()">
81.232 - Thread.currentThread().getContextClassLoader()</a>
81.233 - classloader the first time <code>Lookup.getDefault</code> is invoked.
81.234 - <p/>
81.235 - The property can also contain value <code>"-"</code> which means to completely
81.236 - disable the lookup instantiation and return <a href="@TOP@/org/openide/util/Lookup.html#EMPTY">Lookup.EMPTY</a>
81.237 - from <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>.
81.238 - <p/>
81.239 - If the property is unspecified, the default <code>MetaInfServicesLookup</code>
81.240 - is constructed for <code>Thread.currentThread().getContextclassLoader()</code>
81.241 - that implements the <a href="architecture-summary.html#answer-compat-standards">JDK's standard</a>. If, by
81.242 - a chance an instance of
81.243 - <a href="@TOP@/org/openide/util/Lookup.Provider.html">Lookup.Provider</a>
81.244 - is found
81.245 - in there, its lookup is returned as result. Otherwise the <code>MetaInfServicesLookup</code>
81.246 - is the result of <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>.
81.247 - </api>
81.248 - </li>
81.249 -
81.250 - <li>
81.251 - <api type="export" group="property" name="org.openide.util.Lookup.paths" category="devel">
81.252 - Sometimes it may be useful for the Lookup to contains objects from
81.253 - some system file system folder. This can be done with
81.254 - <code>org.openide.util.Lookup.paths=Folder1:Folder2:Folder3</code>.
81.255 - If this property is set prior to first call to
81.256 - <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>,
81.257 - it is split into pieces (separator is <code>':'</code>) and individual
81.258 - parts are then used to construct <code>Lookups.forPath("Folder1")</code>,
81.259 - etc. All these lookups then become part of the
81.260 - <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.261 - one. This property works since version 7.24
81.262 - </api>
81.263 - </li>
81.264 -
81.265 </ul>
81.266 </answer>
81.267
81.268 @@ -553,20 +349,11 @@
81.269 <api category="devel" group="java" name="WeakListener.setAccessible" type="export" url="@TOP@/org/openide/util/WeakListeners.html">
81.270 used to call the remove method using reflection
81.271 </api>.
81.272 - <api category="devel" group="java" name="Lookups.metaInfServices" type="export" url="@TOP@/org/openide/util/lookup/Lookups.html#metaInfServices(java.lang.ClassLoader)">
81.273 - calls constructor of registered classes using reflection
81.274 - </api>.
81.275 <api category="private" group="lookup" name="ActionManagerInvocation" type="export" >
81.276 because of the API separation, <a href="@TOP@/org/openide/util/actions/CallableSystemAction.html">CallableSystemAction</a> uses lookup for <code>ActionsBridge</code>
81.277 provided by <code>org-openide-actions</code> module
81.278 when looking for <a href="@org-openide-actions@/org/openide/actions/ActionManager.html">org.openide.actions.ActionManager</a> implementation.
81.279 </api>.
81.280 - <api category="friend" group="java" name="Lookup.resetDefaultLookup" type="export">
81.281 - There is a static private method <code>Lookup.resetDefaultLookup</code> that
81.282 - is called by NbJUnit's <code>MockServices</code> to properly reset default
81.283 - lookup and fire changes to all registred listeners.
81.284 - </api>.
81.285 -
81.286 </p>
81.287 </answer>
81.288
81.289 @@ -631,12 +418,6 @@
81.290
81.291 <answer id="lookup-lookup">
81.292 <ul>
81.293 - <li><api name="LookupInitializationLookup" category="devel" group="lookup" type="export" url="#property-org.openide.util.Lookup">
81.294 - during
81.295 - initialization of the <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.296 - the <a href="@TOP@/org/openide/util/Lookup.Provider.html">Lookup.Provider</a>
81.297 - is being searched</api>.
81.298 - </li>
81.299
81.300 <li><api name="LookupSharedClassObject" category="devel" group="lookup" type="export">
81.301 singleton subclasses of <a href="@TOP@/org/openide/util/SharedClassObject.html">SharedClassObject</a>
81.302 @@ -646,7 +427,7 @@
81.303 <li><api name="LookupContextGlobalProvider" category="stable" group="lookup" type="export">
81.304 <a href="@TOP@/org/openide/util/Utilities.html#actionsGlobalContext()">actionsGlobalContext</a>
81.305 searches for <a href="@TOP@/org/openide/util/ContextGlobalProvider.html">ContextGlobalProvider</a> in
81.306 - <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>.
81.307 + <a href="@org-openide-util-lookup@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>.
81.308 The provider is usually provided by <a href="@org-openide-windows@/overview-summary.html">window
81.309 system implementation</a>.
81.310 </api>.</li>
81.311 @@ -666,7 +447,7 @@
81.312 <li><api name="LookupClassLoader" category="devel" group="lookup" type="export">
81.313 Nearly all resource looking functions and reflective code
81.314 uses <a href="@JDK@/java/lang/ClassLoader.html">ClassLoader</a>
81.315 - obtained from <a href="@TOP@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.316 + obtained from <a href="@org-openide-util-lookup@/org/openide/util/Lookup.html#getDefault()">Lookup.getDefault()</a>
81.317 for loading system wide resources.
81.318 </api>.</li>
81.319
81.320 @@ -744,11 +525,6 @@
81.321 -->
81.322 <answer id="perf-limit">
81.323 <p>
81.324 - The default implementation of the <code>MetaInfServicesLookup</code> just
81.325 - keeps hashmap between queried classes and their implementations. The amount
81.326 - of memory is linear to amount of registered classes, but of course we
81.327 - are not counting the memory occupied by the instances which the lookup
81.328 - creates, that can be arbitrary.
81.329 </p>
81.330 </answer>
81.331
81.332 @@ -762,9 +538,7 @@
81.333 -->
81.334 <answer id="perf-mem">
81.335 <p>
81.336 - There are no big data structures. The amount of memory occupied by
81.337 - instances of <a href="@TOP@/org/openide/util/lookup/AbstractLookup.html">AbstractLookup</a>
81.338 - is measured by unit tests.
81.339 + There are no big data structures.
81.340 </p>
81.341 </answer>
81.342
82.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
82.2 +++ b/openide.util/module-auto-deps.xml Mon Dec 14 20:58:39 2009 +0100
82.3 @@ -0,0 +1,61 @@
82.4 +<?xml version="1.0" encoding="UTF-8"?>
82.5 +<!--
82.6 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
82.7 +
82.8 +Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
82.9 +
82.10 +
82.11 +The contents of this file are subject to the terms of either the GNU
82.12 +General Public License Version 2 only ("GPL") or the Common
82.13 +Development and Distribution License("CDDL") (collectively, the
82.14 +"License"). You may not use this file except in compliance with the
82.15 +License. You can obtain a copy of the License at
82.16 +http://www.netbeans.org/cddl-gplv2.html
82.17 +or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
82.18 +specific language governing permissions and limitations under the
82.19 +License. When distributing the software, include this License Header
82.20 +Notice in each file and include the License file at
82.21 +nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
82.22 +particular file as subject to the "Classpath" exception as provided
82.23 +by Sun in the GPL Version 2 section of the License file that
82.24 +accompanied this code. If applicable, add the following below the
82.25 +License Header, with the fields enclosed by brackets [] replaced by
82.26 +your own identifying information:
82.27 +"Portions Copyrighted [year] [name of copyright owner]"
82.28 +
82.29 +Contributor(s):
82.30 +
82.31 +The Original Software is NetBeans. The Initial Developer of the Original
82.32 +Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
82.33 +Microsystems, Inc. All Rights Reserved.
82.34 +
82.35 +If you wish your version of this file to be governed by only the CDDL
82.36 +or only the GPL Version 2, indicate your decision by adding
82.37 +"[Contributor] elects to include this software in this distribution
82.38 +under the [CDDL or GPL Version 2] license." If you do not indicate a
82.39 +single choice of license, a recipient has the option to distribute
82.40 +your version of this file under either the CDDL, the GPL Version 2 or
82.41 +to extend the choice of license to its licensees as provided above.
82.42 +However, if you add GPL Version 2 code and therefore, elected the GPL
82.43 +Version 2 license, then the option applies only if the new code is
82.44 +made subject to such option by the copyright holder.
82.45 +-->
82.46 +
82.47 +<!DOCTYPE transformations PUBLIC "-//NetBeans//DTD Module Automatic Dependencies 1.0//EN" "http://www.netbeans.org/dtds/module-auto-deps-1_0.dtd">
82.48 +
82.49 +<transformations version="1.0">
82.50 + <transformationgroup>
82.51 + <description>#170056] Separate module for Lookup API</description>
82.52 + <transformation>
82.53 + <trigger-dependency type="older">
82.54 + <module-dependency codenamebase="org.openide.util" spec="8.0"/>
82.55 + </trigger-dependency>
82.56 + <implies>
82.57 + <result>
82.58 + <module-dependency codenamebase="org.openide.util.lookup" spec="8.0"/>
82.59 + </result>
82.60 + </implies>
82.61 + </transformation>
82.62 + </transformationgroup>
82.63 +
82.64 +</transformations>
83.1 --- a/openide.util/nbproject/project.properties Thu Dec 10 19:23:25 2009 -0500
83.2 +++ b/openide.util/nbproject/project.properties Mon Dec 14 20:58:39 2009 +0100
83.3 @@ -42,7 +42,7 @@
83.4 module.jar.dir=lib
83.5 cp.extra=${nb_all}/apisupport.harness/external/openjdk-javac-6-b12.jar
83.6
83.7 -spec.version.base=7.32.0
83.8 +spec.version.base=8.0
83.9
83.10 # For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4:
83.11
84.1 --- a/openide.util/nbproject/project.xml Thu Dec 10 19:23:25 2009 -0500
84.2 +++ b/openide.util/nbproject/project.xml Mon Dec 14 20:58:39 2009 +0100
84.3 @@ -45,7 +45,16 @@
84.4 <configuration>
84.5 <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
84.6 <code-name-base>org.openide.util</code-name-base>
84.7 - <module-dependencies/>
84.8 + <module-dependencies>
84.9 + <dependency>
84.10 + <code-name-base>org.openide.util.lookup</code-name-base>
84.11 + <build-prerequisite/>
84.12 + <compile-dependency/>
84.13 + <run-dependency>
84.14 + <implementation-version/>
84.15 + </run-dependency>
84.16 + </dependency>
84.17 + </module-dependencies>
84.18 <test-dependencies>
84.19 <test-type>
84.20 <name>unit</name>
84.21 @@ -58,6 +67,11 @@
84.22 <recursive/>
84.23 <compile-dependency/>
84.24 </test-dependency>
84.25 + <test-dependency>
84.26 + <code-name-base>org.openide.util.lookup</code-name-base>
84.27 + <compile-dependency/>
84.28 + <test/>
84.29 + </test-dependency>
84.30 </test-type>
84.31 </test-dependencies>
84.32 <public-packages>
85.1 --- a/openide.util/src/META-INF/services/javax.annotation.processing.Processor Thu Dec 10 19:23:25 2009 -0500
85.2 +++ b/openide.util/src/META-INF/services/javax.annotation.processing.Processor Mon Dec 14 20:58:39 2009 +0100
85.3 @@ -1,2 +1,1 @@
85.4 -org.netbeans.modules.openide.util.ServiceProviderProcessor
85.5 org.netbeans.modules.openide.util.URLStreamHandlerRegistrationProcessor
86.1 --- a/openide.util/src/org/netbeans/modules/openide/util/AbstractServiceProviderProcessor.java Thu Dec 10 19:23:25 2009 -0500
86.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
86.3 @@ -1,289 +0,0 @@
86.4 -/*
86.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
86.6 - *
86.7 - * Copyright 2009 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 2009 Sun Microsystems, Inc.
86.41 - */
86.42 -
86.43 -package org.netbeans.modules.openide.util;
86.44 -
86.45 -import java.io.BufferedReader;
86.46 -import java.io.FileNotFoundException;
86.47 -import java.io.IOException;
86.48 -import java.io.InputStream;
86.49 -import java.io.InputStreamReader;
86.50 -import java.io.OutputStream;
86.51 -import java.io.OutputStreamWriter;
86.52 -import java.io.PrintWriter;
86.53 -import java.lang.annotation.Annotation;
86.54 -import java.util.ArrayList;
86.55 -import java.util.HashMap;
86.56 -import java.util.List;
86.57 -import java.util.Map;
86.58 -import java.util.Set;
86.59 -import java.util.WeakHashMap;
86.60 -import javax.annotation.processing.AbstractProcessor;
86.61 -import javax.annotation.processing.ProcessingEnvironment;
86.62 -import javax.annotation.processing.RoundEnvironment;
86.63 -import javax.lang.model.element.AnnotationMirror;
86.64 -import javax.lang.model.element.AnnotationValue;
86.65 -import javax.lang.model.element.Element;
86.66 -import javax.lang.model.element.ExecutableElement;
86.67 -import javax.lang.model.element.Modifier;
86.68 -import javax.lang.model.element.TypeElement;
86.69 -import javax.lang.model.type.TypeMirror;
86.70 -import javax.lang.model.util.ElementFilter;
86.71 -import javax.tools.Diagnostic.Kind;
86.72 -import javax.tools.FileObject;
86.73 -import javax.tools.StandardLocation;
86.74 -
86.75 -/**
86.76 - * Infrastructure for generating {@code META-INF/services/*} and
86.77 - * {@code META-INF/namedservices/*} registrations from annotations.
86.78 - */
86.79 -public abstract class AbstractServiceProviderProcessor extends AbstractProcessor {
86.80 -
86.81 - private final Map<ProcessingEnvironment,Map<String,List<String>>> outputFilesByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<String>>>();
86.82 - private final Map<ProcessingEnvironment,Map<String,List<Element>>> originatingElementsByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<Element>>>();
86.83 - private final Map<TypeElement,Boolean> verifiedClasses = new WeakHashMap<TypeElement,Boolean>();
86.84 -
86.85 - /** For access by subclasses. */
86.86 - protected AbstractServiceProviderProcessor() {}
86.87 -
86.88 - public @Override final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
86.89 - if (roundEnv.errorRaised()) {
86.90 - return false;
86.91 - }
86.92 - if (roundEnv.processingOver()) {
86.93 - writeServices();
86.94 - outputFilesByProcessor.clear();
86.95 - originatingElementsByProcessor.clear();
86.96 - return true;
86.97 - } else {
86.98 - return handleProcess(annotations, roundEnv);
86.99 - }
86.100 - }
86.101 -
86.102 - /**
86.103 - * The regular body of {@link #process}.
86.104 - * Called during regular rounds if there are no outstanding errors.
86.105 - * In the last round, one of the processors will write out generated registrations.
86.106 - * @param annotations as in {@link #process}
86.107 - * @param roundEnv as in {@link #process}
86.108 - * @return as in {@link #process}
86.109 - */
86.110 - protected abstract boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);
86.111 -
86.112 - /**
86.113 - * Register a service.
86.114 - * If the class does not have an appropriate signature, an error will be printed and the registration skipped.
86.115 - * @param clazz the service implementation type
86.116 - * @param annotation the (top-level) annotation registering the service, for diagnostic purposes
86.117 - * @param type the type to which the implementation must be assignable
86.118 - * @param path a path under which to register, or "" if inapplicable
86.119 - * @param position a position at which to register, or {@link Integer#MAX_VALUE} to skip
86.120 - * @param supersedes possibly empty list of implementation to supersede
86.121 - */
86.122 - protected final void register(TypeElement clazz, Class<? extends Annotation> annotation,
86.123 - TypeMirror type, String path, int position, String[] supersedes) {
86.124 - Boolean verify = verifiedClasses.get(clazz);
86.125 - if (verify == null) {
86.126 - verify = verifyServiceProviderSignature(clazz, annotation);
86.127 - verifiedClasses.put(clazz, verify);
86.128 - }
86.129 - if (!verify) {
86.130 - return;
86.131 - }
86.132 - String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
86.133 - String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
86.134 - if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
86.135 - AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
86.136 - processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
86.137 - clazz, ann, findAnnotationValue(ann, "service"));
86.138 - return;
86.139 - }
86.140 - processingEnv.getMessager().printMessage(Kind.NOTE,
86.141 - impl + " to be registered as a " + xface + (path.length() > 0 ? " under " + path : ""));
86.142 - String rsrc = (path.length() > 0 ? "META-INF/namedservices/" + path + "/" : "META-INF/services/") + xface;
86.143 - {
86.144 - Map<String,List<Element>> originatingElements = originatingElementsByProcessor.get(processingEnv);
86.145 - if (originatingElements == null) {
86.146 - originatingElements = new HashMap<String,List<Element>>();
86.147 - originatingElementsByProcessor.put(processingEnv, originatingElements);
86.148 - }
86.149 - List<Element> origEls = originatingElements.get(rsrc);
86.150 - if (origEls == null) {
86.151 - origEls = new ArrayList<Element>();
86.152 - originatingElements.put(rsrc, origEls);
86.153 - }
86.154 - origEls.add(clazz);
86.155 - }
86.156 - Map<String,List<String>> outputFiles = outputFilesByProcessor.get(processingEnv);
86.157 - if (outputFiles == null) {
86.158 - outputFiles = new HashMap<String,List<String>>();
86.159 - outputFilesByProcessor.put(processingEnv, outputFiles);
86.160 - }
86.161 - List<String> lines = outputFiles.get(rsrc);
86.162 - if (lines == null) {
86.163 - lines = new ArrayList<String>();
86.164 - try {
86.165 - try {
86.166 - FileObject in = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", rsrc);
86.167 - in.openInputStream().close();
86.168 - processingEnv.getMessager().printMessage(Kind.ERROR,
86.169 - "Cannot generate " + rsrc + " because it already exists in sources: " + in.toUri());
86.170 - return;
86.171 - } catch (FileNotFoundException x) {
86.172 - // Good.
86.173 - }
86.174 - try {
86.175 - FileObject in = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", rsrc);
86.176 - InputStream is = in.openInputStream();
86.177 - try {
86.178 - BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
86.179 - String line;
86.180 - while ((line = r.readLine()) != null) {
86.181 - lines.add(line);
86.182 - }
86.183 - } finally {
86.184 - is.close();
86.185 - }
86.186 - } catch (FileNotFoundException x) {
86.187 - // OK, created for the first time
86.188 - }
86.189 - } catch (IOException x) {
86.190 - processingEnv.getMessager().printMessage(Kind.ERROR, x.toString());
86.191 - return;
86.192 - }
86.193 - outputFiles.put(rsrc, lines);
86.194 - }
86.195 - int idx = lines.indexOf(impl);
86.196 - if (idx != -1) {
86.197 - lines.remove(idx);
86.198 - while (lines.size() > idx && lines.get(idx).matches("#position=.+|#-.+")) {
86.199 - lines.remove(idx);
86.200 - }
86.201 - }
86.202 - lines.add(impl);
86.203 - if (position != Integer.MAX_VALUE) {
86.204 - lines.add("#position=" + position);
86.205 - }
86.206 - for (String exclude : supersedes) {
86.207 - lines.add("#-" + exclude);
86.208 - }
86.209 - }
86.210 -
86.211 - /**
86.212 - * @param element a source element
86.213 - * @param annotation a type of annotation
86.214 - * @return the instance of that annotation on the element, or null if not found
86.215 - */
86.216 - private AnnotationMirror findAnnotationMirror(Element element, Class<? extends Annotation> annotation) {
86.217 - for (AnnotationMirror ann : element.getAnnotationMirrors()) {
86.218 - if (processingEnv.getElementUtils().getBinaryName((TypeElement) ann.getAnnotationType().asElement()).
86.219 - contentEquals(annotation.getName())) {
86.220 - return ann;
86.221 - }
86.222 - }
86.223 - return null;
86.224 - }
86.225 -
86.226 - /**
86.227 - * @param annotation an annotation instance (null permitted)
86.228 - * @param name the name of an attribute of that annotation
86.229 - * @return the corresponding value if found
86.230 - */
86.231 - private AnnotationValue findAnnotationValue(AnnotationMirror annotation, String name) {
86.232 - if (annotation != null) {
86.233 - for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()) {
86.234 - if (entry.getKey().getSimpleName().contentEquals(name)) {
86.235 - return entry.getValue();
86.236 - }
86.237 - }
86.238 - }
86.239 - return null;
86.240 - }
86.241 -
86.242 - private final boolean verifyServiceProviderSignature(TypeElement clazz, Class<? extends Annotation> annotation) {
86.243 - AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
86.244 - if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
86.245 - processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must be public", clazz, ann);
86.246 - return false;
86.247 - }
86.248 - if (clazz.getModifiers().contains(Modifier.ABSTRACT)) {
86.249 - processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must not be abstract", clazz, ann);
86.250 - return false;
86.251 - }
86.252 - {
86.253 - boolean hasDefaultCtor = false;
86.254 - for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
86.255 - if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) {
86.256 - hasDefaultCtor = true;
86.257 - break;
86.258 - }
86.259 - }
86.260 - if (!hasDefaultCtor) {
86.261 - processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must have a public no-argument constructor", clazz, ann);
86.262 - return false;
86.263 - }
86.264 - }
86.265 - return true;
86.266 - }
86.267 -
86.268 - private void writeServices() {
86.269 - for (Map.Entry<ProcessingEnvironment,Map<String,List<String>>> outputFiles : outputFilesByProcessor.entrySet()) {
86.270 - for (Map.Entry<String, List<String>> entry : outputFiles.getValue().entrySet()) {
86.271 - try {
86.272 - FileObject out = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", entry.getKey(),
86.273 - originatingElementsByProcessor.get(outputFiles.getKey()).get(entry.getKey()).toArray(new Element[0]));
86.274 - OutputStream os = out.openOutputStream();
86.275 - try {
86.276 - PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
86.277 - for (String line : entry.getValue()) {
86.278 - w.println(line);
86.279 - }
86.280 - w.flush();
86.281 - w.close();
86.282 - } finally {
86.283 - os.close();
86.284 - }
86.285 - } catch (IOException x) {
86.286 - processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
86.287 - }
86.288 - }
86.289 - }
86.290 - }
86.291 -
86.292 -}
87.1 --- a/openide.util/src/org/netbeans/modules/openide/util/ActiveQueue.java Thu Dec 10 19:23:25 2009 -0500
87.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
87.3 @@ -1,108 +0,0 @@
87.4 -package org.netbeans.modules.openide.util;
87.5 -
87.6 -import java.lang.ref.Reference;
87.7 -import java.lang.ref.ReferenceQueue;
87.8 -import java.util.logging.Level;
87.9 -import java.util.logging.Logger;
87.10 -
87.11 -/**
87.12 - * Implementation of the active reference queue.
87.13 - */
87.14 -public final class ActiveQueue extends ReferenceQueue<Object> implements Runnable {
87.15 -
87.16 - private static final Logger LOGGER = Logger.getLogger(ActiveQueue.class.getName().replace('$', '.'));
87.17 - private static ActiveQueue activeReferenceQueue;
87.18 -
87.19 - /** number of known outstanding references */
87.20 - private int count;
87.21 - private boolean deprecated;
87.22 -
87.23 - ActiveQueue(boolean deprecated) {
87.24 - super();
87.25 - this.deprecated = deprecated;
87.26 - }
87.27 -
87.28 - public static synchronized ReferenceQueue<Object> queue() {
87.29 - if (activeReferenceQueue == null) {
87.30 - activeReferenceQueue = new ActiveQueue(false);
87.31 - }
87.32 -
87.33 - activeReferenceQueue.ping();
87.34 -
87.35 - return activeReferenceQueue;
87.36 - }
87.37 -
87.38 - @Override
87.39 - public Reference<Object> poll() {
87.40 - throw new UnsupportedOperationException();
87.41 - }
87.42 -
87.43 - @Override
87.44 - public Reference<Object> remove(long timeout) throws IllegalArgumentException, InterruptedException {
87.45 - throw new InterruptedException();
87.46 - }
87.47 -
87.48 - @Override
87.49 - public Reference<Object> remove() throws InterruptedException {
87.50 - throw new InterruptedException();
87.51 - }
87.52 -
87.53 - public void run() {
87.54 - while (true) {
87.55 - try {
87.56 - Reference<?> ref = super.remove(0);
87.57 - LOGGER.finer("dequeued reference");
87.58 - if (!(ref instanceof Runnable)) {
87.59 - LOGGER.warning("A reference not implementing runnable has been added to the Utilities.activeReferenceQueue(): " + ref.getClass());
87.60 - continue;
87.61 - }
87.62 - if (deprecated) {
87.63 - LOGGER.warning("Utilities.ACTIVE_REFERENCE_QUEUE has been deprecated for " + ref.getClass() + " use Utilities.activeReferenceQueue");
87.64 - }
87.65 - // do the cleanup
87.66 - try {
87.67 - ((Runnable) ref).run();
87.68 - } catch (ThreadDeath td) {
87.69 - throw td;
87.70 - } catch (Throwable t) {
87.71 - // Should not happen.
87.72 - // If it happens, it is a bug in client code, notify!
87.73 - LOGGER.log(Level.WARNING, null, t);
87.74 - } finally {
87.75 - // to allow GC
87.76 - ref = null;
87.77 - }
87.78 - } catch (InterruptedException ex) {
87.79 - // Can happen during VM shutdown, it seems. Ignore.
87.80 - continue;
87.81 - }
87.82 - synchronized (this) {
87.83 - assert count > 0;
87.84 - count--;
87.85 - if (count == 0) {
87.86 - // We have processed all we have to process (for now at least).
87.87 - // Could be restarted later if ping() called again.
87.88 - // This could also happen in case someone called queue() once and tried
87.89 - // to use it for several references; in that case run() might never be called on
87.90 - // the later ones to be collected. Can't really protect against that situation.
87.91 - // See issue #86625 for details.
87.92 - LOGGER.fine("stopping thread");
87.93 - break;
87.94 - }
87.95 - }
87.96 - }
87.97 - }
87.98 -
87.99 - synchronized void ping() {
87.100 - if (count == 0) {
87.101 - Thread t = new Thread(this, "Active Reference Queue Daemon");
87.102 - t.setPriority(Thread.MIN_PRIORITY);
87.103 - t.setDaemon(true);
87.104 - t.start();
87.105 - LOGGER.fine("starting thread");
87.106 - } else {
87.107 - LOGGER.finer("enqueuing reference");
87.108 - }
87.109 - count++;
87.110 - }
87.111 -}
88.1 --- a/openide.util/src/org/netbeans/modules/openide/util/NamedServicesProvider.java Thu Dec 10 19:23:25 2009 -0500
88.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
88.3 @@ -1,81 +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.
88.31 - *
88.32 - * Portions Copyrighted 2006 Sun Microsystems, Inc.
88.33 - */
88.34 -
88.35 -package org.netbeans.modules.openide.util;
88.36 -
88.37 -import java.lang.ref.Reference;
88.38 -import java.lang.ref.WeakReference;
88.39 -import java.util.Collections;
88.40 -import java.util.HashMap;
88.41 -import java.util.Map;
88.42 -import org.openide.util.Lookup;
88.43 -import org.openide.util.lookup.Lookups;
88.44 -
88.45 -/** Interface for core/startup and core/settings
88.46 - * to provide lookup over system filesystem.
88.47 - *
88.48 - * @author Jaroslav Tulach
88.49 - */
88.50 -public abstract class NamedServicesProvider {
88.51 -
88.52 - private static final Map<String,Reference<Lookup>> map = Collections.synchronizedMap(new HashMap<String,Reference<Lookup>>());
88.53 -
88.54 - public abstract Lookup create(String path);
88.55 -
88.56 - public static Lookup find(String path) {
88.57 - if (!path.endsWith("/")) {
88.58 - path = path + "/";
88.59 - }
88.60 -
88.61 - Reference<Lookup> ref = map.get(path);
88.62 - Lookup lkp = ref == null ? null : ref.get();
88.63 - if (lkp != null) {
88.64 - return lkp;
88.65 - }
88.66 - NamedServicesProvider prov = Lookup.getDefault().lookup(NamedServicesProvider.class);
88.67 - if (prov != null && /* avoid stack overflow during initialization */ !path.startsWith(URLStreamHandlerRegistrationProcessor.REGISTRATION_PREFIX)) {
88.68 - lkp = prov.create(path);
88.69 - } else {
88.70 - ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
88.71 - if (l == null) {
88.72 - l = Thread.currentThread().getContextClassLoader();
88.73 - if (l == null) {
88.74 - l = NamedServicesProvider.class.getClassLoader();
88.75 - }
88.76 - }
88.77 - lkp = Lookups.metaInfServices(l, "META-INF/namedservices/" + path);
88.78 - }
88.79 -
88.80 - map.put(path, new WeakReference<Lookup>(lkp));
88.81 - return lkp;
88.82 - }
88.83 -
88.84 -}
89.1 --- a/openide.util/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java Thu Dec 10 19:23:25 2009 -0500
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.netbeans.modules.openide.util;
89.44 -
89.45 -import java.lang.annotation.Annotation;
89.46 -import java.util.Arrays;
89.47 -import java.util.Collection;
89.48 -import java.util.Collections;
89.49 -import java.util.HashSet;
89.50 -import java.util.LinkedList;
89.51 -import java.util.List;
89.52 -import java.util.Set;
89.53 -import javax.annotation.processing.Completion;
89.54 -import javax.annotation.processing.RoundEnvironment;
89.55 -import javax.annotation.processing.SupportedSourceVersion;
89.56 -import javax.lang.model.SourceVersion;
89.57 -import javax.lang.model.element.AnnotationMirror;
89.58 -import javax.lang.model.element.Element;
89.59 -import javax.lang.model.element.ExecutableElement;
89.60 -import javax.lang.model.element.TypeElement;
89.61 -import javax.lang.model.type.MirroredTypeException;
89.62 -import javax.lang.model.type.TypeKind;
89.63 -import javax.lang.model.type.TypeMirror;
89.64 -import org.openide.util.lookup.ServiceProvider;
89.65 -import org.openide.util.lookup.ServiceProviders;
89.66 -
89.67 -@SupportedSourceVersion(SourceVersion.RELEASE_6)
89.68 -public class ServiceProviderProcessor extends AbstractServiceProviderProcessor {
89.69 -
89.70 - public @Override Set<String> getSupportedAnnotationTypes() {
89.71 - return new HashSet<String>(Arrays.asList(
89.72 - ServiceProvider.class.getCanonicalName(),
89.73 - ServiceProviders.class.getCanonicalName()
89.74 - ));
89.75 - }
89.76 -
89.77 - /** public for ServiceLoader */
89.78 - public ServiceProviderProcessor() {}
89.79 -
89.80 - protected boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
89.81 - for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
89.82 - TypeElement clazz = (TypeElement) el;
89.83 - ServiceProvider sp = clazz.getAnnotation(ServiceProvider.class);
89.84 - register(clazz, ServiceProvider.class, sp);
89.85 - }
89.86 - for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProviders.class)) {
89.87 - TypeElement clazz = (TypeElement) el;
89.88 - ServiceProviders spp = clazz.getAnnotation(ServiceProviders.class);
89.89 - for (ServiceProvider sp : spp.value()) {
89.90 - register(clazz, ServiceProviders.class, sp);
89.91 - }
89.92 - }
89.93 - return true;
89.94 - }
89.95 -
89.96 - private void register(TypeElement clazz, Class<? extends Annotation> annotation, ServiceProvider svc) {
89.97 - try {
89.98 - svc.service();
89.99 - assert false;
89.100 - return;
89.101 - } catch (MirroredTypeException e) {
89.102 - register(clazz, annotation, e.getTypeMirror(), svc.path(), svc.position(), svc.supersedes());
89.103 - }
89.104 - }
89.105 -
89.106 - @Override
89.107 - public Iterable<? extends Completion> getCompletions(Element annotated, AnnotationMirror annotation, ExecutableElement attr, String userText) {
89.108 - if (processingEnv == null || annotated == null || !annotated.getKind().isClass()) {
89.109 - return Collections.emptyList();
89.110 - }
89.111 -
89.112 - if ( annotation == null
89.113 - || !"org.openide.util.lookup.ServiceProvider".contentEquals(((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName())) {
89.114 - return Collections.emptyList();
89.115 - }
89.116 -
89.117 - if (!"service".contentEquals(attr.getSimpleName())) {
89.118 - return Collections.emptyList();
89.119 - }
89.120 -
89.121 - TypeElement jlObject = processingEnv.getElementUtils().getTypeElement("java.lang.Object");
89.122 -
89.123 - if (jlObject == null) {
89.124 - return Collections.emptyList();
89.125 - }
89.126 -
89.127 - Collection<Completion> result = new LinkedList<Completion>();
89.128 - List<TypeElement> toProcess = new LinkedList<TypeElement>();
89.129 -
89.130 - toProcess.add((TypeElement) annotated);
89.131 -
89.132 - while (!toProcess.isEmpty()) {
89.133 - TypeElement c = toProcess.remove(0);
89.134 -
89.135 - result.add(new TypeCompletion(c.getQualifiedName().toString() + ".class"));
89.136 -
89.137 - List<TypeMirror> parents = new LinkedList<TypeMirror>();
89.138 -
89.139 - parents.add(c.getSuperclass());
89.140 - parents.addAll(c.getInterfaces());
89.141 -
89.142 - for (TypeMirror tm : parents) {
89.143 - if (tm == null || tm.getKind() != TypeKind.DECLARED) {
89.144 - continue;
89.145 - }
89.146 -
89.147 - TypeElement type = (TypeElement) processingEnv.getTypeUtils().asElement(tm);
89.148 -
89.149 - if (!jlObject.equals(type)) {
89.150 - toProcess.add(type);
89.151 - }
89.152 - }
89.153 - }
89.154 -
89.155 - return result;
89.156 - }
89.157 -
89.158 - private static final class TypeCompletion implements Completion {
89.159 -
89.160 - private final String type;
89.161 -
89.162 - public TypeCompletion(String type) {
89.163 - this.type = type;
89.164 - }
89.165 -
89.166 - public String getValue() {
89.167 - return type;
89.168 - }
89.169 -
89.170 - public String getMessage() {
89.171 - return null;
89.172 - }
89.173 -
89.174 - }
89.175 -
89.176 -}
90.1 --- a/openide.util/src/org/openide/util/Lookup.java Thu Dec 10 19:23:25 2009 -0500
90.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
90.3 @@ -1,544 +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 -
90.45 -package org.openide.util;
90.46 -
90.47 -import java.util.ArrayList;
90.48 -import java.util.Collection;
90.49 -import java.util.Collections;
90.50 -import java.util.Iterator;
90.51 -import java.util.List;
90.52 -import java.util.Set;
90.53 -import org.openide.util.lookup.Lookups;
90.54 -import org.openide.util.lookup.ProxyLookup;
90.55 -import org.openide.util.lookup.ServiceProvider;
90.56 -
90.57 -/**
90.58 - * A general registry permitting clients to find instances of services
90.59 - * (implementation of a given interface).
90.60 - * This class is inspired by the
90.61 - * <a href="http://www.jini.org/">Jini</a>
90.62 - * registration and lookup mechanism. The difference is that the methods do
90.63 - * not throw checked exceptions (as they usually work only locally and not over the network)
90.64 - * and that the Lookup API concentrates on the lookup, not on the registration
90.65 - * (although {@link Lookup#getDefault} is strongly encouraged to support
90.66 - * {@link Lookups#metaInfServices} for registration in addition to whatever
90.67 - * else it decides to support).
90.68 - * <p>
90.69 - * For a general talk about the idea behind the lookup pattern please see
90.70 - * <UL>
90.71 - * <LI><a href="lookup/doc-files/index.html">The Solution to Communication Between Components</a>
90.72 - * page
90.73 - * <LI>the introduction to the <a href="lookup/doc-files/lookup-api.html">lookup API via
90.74 - * use cases</a>
90.75 - * <LI>the examples of <a href="lookup/doc-files/lookup-spi.html">how to write your own lookup</a>
90.76 - * </UL>
90.77 - *
90.78 - * @see org.openide.util.lookup.AbstractLookup
90.79 - * @see Lookups
90.80 - * @see LookupListener
90.81 - * @see LookupEvent
90.82 - * @author Jaroslav Tulach
90.83 - */
90.84 -public abstract class Lookup {
90.85 - /** A dummy lookup that never returns any results.
90.86 - */
90.87 - public static final Lookup EMPTY = new Empty();
90.88 -
90.89 - /** default instance */
90.90 - private static Lookup defaultLookup;
90.91 -
90.92 - /** Empty constructor for use by subclasses. */
90.93 - public Lookup() {
90.94 - }
90.95 -
90.96 - /** Static method to obtain the global lookup in the whole system.
90.97 - * The actual returned implementation can be different in different
90.98 - * systems, but the default one is based on
90.99 - * {@link org.openide.util.lookup.Lookups#metaInfServices}
90.100 - * with the context classloader of the first caller. Each system is
90.101 - * adviced to honor this and include some form of <code>metaInfServices</code>
90.102 - * implementation in the returned lookup as usage of <code>META-INF/services</code>
90.103 - * is a JDK standard.
90.104 - *
90.105 - * @return the global lookup in the system
90.106 - * @see ServiceProvider
90.107 - */
90.108 - public static synchronized Lookup getDefault() {
90.109 - if (defaultLookup != null) {
90.110 - return defaultLookup;
90.111 - }
90.112 -
90.113 - // You can specify a Lookup impl using a system property if you like.
90.114 - String className = System.getProperty("org.openide.util.Lookup" // NOI18N
90.115 - );
90.116 -
90.117 - if ("-".equals(className)) { // NOI18N
90.118 -
90.119 - // Suppress even MetaInfServicesLookup.
90.120 - return EMPTY;
90.121 - }
90.122 -
90.123 - ClassLoader l = Thread.currentThread().getContextClassLoader();
90.124 -
90.125 - try {
90.126 - if (className != null) {
90.127 - defaultLookup = (Lookup) Class.forName(className, true, l).newInstance();
90.128 -
90.129 - return defaultLookup;
90.130 - }
90.131 - } catch (Exception e) {
90.132 - // do not use ErrorManager because we are in the startup code
90.133 - // and ErrorManager might not be ready
90.134 - e.printStackTrace();
90.135 - }
90.136 -
90.137 - // OK, none specified (successfully) in a system property.
90.138 - // Try MetaInfServicesLookup as a default, which may also
90.139 - // have a org.openide.util.Lookup line specifying the lookup.
90.140 - Lookup misl = Lookups.metaInfServices(l);
90.141 - defaultLookup = misl.lookup(Lookup.class);
90.142 -
90.143 - if (defaultLookup != null) {
90.144 - return defaultLookup;
90.145 - }
90.146 -
90.147 - // You may also specify a Lookup.Provider.
90.148 - Lookup.Provider prov = misl.lookup(Lookup.Provider.class);
90.149 -
90.150 - if (prov != null) {
90.151 - defaultLookup = Lookups.proxy(prov);
90.152 -
90.153 - return defaultLookup;
90.154 - }
90.155 -
90.156 - DefLookup def = new DefLookup();
90.157 - def.init(l, misl, false);
90.158 - defaultLookup = def;
90.159 - def.init(l, misl, true);
90.160 - return defaultLookup;
90.161 - }
90.162 -
90.163 - private static final class DefLookup extends ProxyLookup {
90.164 - public DefLookup() {
90.165 - super(new Lookup[0]);
90.166 - }
90.167 -
90.168 - public void init(ClassLoader loader, Lookup metaInfLookup, boolean addPath) {
90.169 - // Had no such line, use simple impl.
90.170 - // It does however need to have ClassLoader available or many things will break.
90.171 - // Use the thread context classloader in effect now.
90.172 - Lookup clLookup = Lookups.singleton(loader);
90.173 - List<Lookup> arr = new ArrayList<Lookup>();
90.174 - arr.add(metaInfLookup);
90.175 - arr.add(clLookup);
90.176 - String paths = System.getProperty("org.openide.util.Lookup.paths"); // NOI18N
90.177 - if (addPath && paths != null) {
90.178 - for (String p : paths.split(":")) { // NOI18N
90.179 - arr.add(Lookups.forPath(p));
90.180 - }
90.181 - }
90.182 - setLookups(arr.toArray(new Lookup[0]));
90.183 - }
90.184 - }
90.185 -
90.186 - /** Called from MockServices to reset default lookup in case services change
90.187 - */
90.188 - private static void resetDefaultLookup() {
90.189 - if (defaultLookup instanceof DefLookup) {
90.190 - DefLookup def = (DefLookup)defaultLookup;
90.191 - ClassLoader l = Thread.currentThread().getContextClassLoader();
90.192 - def.init(l, Lookups.metaInfServices(l), true);
90.193 - }
90.194 - }
90.195 -
90.196 - /** Look up an object matching a given interface.
90.197 - * This is the simplest method to use.
90.198 - * If more than one object matches, the first will be returned.
90.199 - * The template class may be a class or interface; the instance is
90.200 - * guaranteed to be assignable to it.
90.201 - *
90.202 - * @param clazz class of the object we are searching for
90.203 - * @return an object implementing the given class or <code>null</code> if no such
90.204 - * implementation is found
90.205 - */
90.206 - public abstract <T> T lookup(Class<T> clazz);
90.207 -
90.208 - /** The general lookup method. Callers can get list of all instances and classes
90.209 - * that match the given <code>template</code>, request more info about
90.210 - * them in form of {@link Lookup.Item} and attach a listener to
90.211 - * this be notified about changes. The general interface does not
90.212 - * specify whether subsequent calls with the same template produce new
90.213 - * instance of the {@link Lookup.Result} or return shared instance. The
90.214 - * prefered behaviour however is to return shared one.
90.215 - *
90.216 - * @param template a template describing the services to look for
90.217 - * @return an object containing the results
90.218 - */
90.219 - public abstract <T> Result<T> lookup(Template<T> template);
90.220 -
90.221 - /** Look up the first item matching a given template.
90.222 - * Includes not only the instance but other associated information.
90.223 - * @param template the template to check
90.224 - * @return a matching item or <code>null</code>
90.225 - *
90.226 - * @since 1.8
90.227 - */
90.228 - public <T> Item<T> lookupItem(Template<T> template) {
90.229 - Result<T> res = lookup(template);
90.230 - Iterator<? extends Item<T>> it = res.allItems().iterator();
90.231 - return it.hasNext() ? it.next() : null;
90.232 - }
90.233 -
90.234 - /**
90.235 - * Find a result corresponding to a given class.
90.236 - * Equivalent to calling {@link #lookup(Lookup.Template)} but slightly more convenient.
90.237 - * Subclasses may override this method to produce the same semantics more efficiently.
90.238 - * @param clazz the supertype of the result
90.239 - * @return a live object representing instances of that type
90.240 - * @since org.openide.util 6.10
90.241 - */
90.242 - public <T> Lookup.Result<T> lookupResult(Class<T> clazz) {
90.243 - return lookup(new Lookup.Template<T>(clazz));
90.244 - }
90.245 -
90.246 - /**
90.247 - * Find all instances corresponding to a given class.
90.248 - * Equivalent to calling {@link #lookupResult} and asking for {@link Lookup.Result#allInstances} but slightly more convenient.
90.249 - * Subclasses may override this method to produce the same semantics more efficiently.
90.250 - * <div class="nonnormative">
90.251 - * <p>Example usage:</p>
90.252 - * <pre>
90.253 - * for (MyService svc : Lookup.getDefault().lookupAll(MyService.class)) {
90.254 - * svc.useMe();
90.255 - * }
90.256 - * </pre>
90.257 - * </div>
90.258 - * @param clazz the supertype of the result
90.259 - * @return all currently available instances of that type
90.260 - * @since org.openide.util 6.10
90.261 - */
90.262 - public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
90.263 - return lookupResult(clazz).allInstances();
90.264 - }
90.265 -
90.266 - /**
90.267 - * Objects implementing interface Lookup.Provider are capable of
90.268 - * and willing to provide a lookup (usually bound to the object).
90.269 - * @since 3.6
90.270 - */
90.271 - public interface Provider {
90.272 - /**
90.273 - * Returns lookup associated with the object.
90.274 - * @return fully initialized lookup instance provided by this object
90.275 - */
90.276 - Lookup getLookup();
90.277 - }
90.278 -
90.279 - /*
90.280 - * I expect this class to grow in the future, but for now, it is
90.281 - * enough to start with something simple.
90.282 - */
90.283 -
90.284 - /** Template defining a pattern to filter instances by.
90.285 - */
90.286 - public static final class Template<T> extends Object {
90.287 - /** cached hash code */
90.288 - private int hashCode;
90.289 -
90.290 - /** type of the service */
90.291 - private Class<T> type;
90.292 -
90.293 - /** identity to search for */
90.294 - private String id;
90.295 -
90.296 - /** instance to search for */
90.297 - private T instance;
90.298 -
90.299 - /** General template to find all possible instances.
90.300 - * @deprecated Use <code>new Template (Object.class)</code> which
90.301 - * is going to be better typed with JDK1.5 templates and should produce
90.302 - * the same result.
90.303 - */
90.304 - @Deprecated
90.305 - public Template() {
90.306 - this(null);
90.307 - }
90.308 -
90.309 - /** Create a simple template matching by class.
90.310 - * @param type the class of service we are looking for (subclasses will match)
90.311 - */
90.312 - public Template(Class<T> type) {
90.313 - this(type, null, null);
90.314 - }
90.315 -
90.316 - /** Constructor to create new template.
90.317 - * @param type the class of service we are looking for or <code>null</code> to leave unspecified
90.318 - * @param id the ID of the item/service we are looking for or <code>null</code> to leave unspecified
90.319 - * @param instance a specific known instance to look for or <code>null</code> to leave unspecified
90.320 - */
90.321 - public Template(Class<T> type, String id, T instance) {
90.322 - this.type = extractType(type);
90.323 - this.id = id;
90.324 - this.instance = instance;
90.325 - }
90.326 -
90.327 - @SuppressWarnings("unchecked")
90.328 - private Class<T> extractType(Class<T> type) {
90.329 - return (type == null) ? (Class<T>)Object.class : type;
90.330 - }
90.331 -
90.332 - /** Get the class (or superclass or interface) to search for.
90.333 - * If it was not specified in the constructor, <code>Object</code> is used as
90.334 - * this will match any instance.
90.335 - * @return the class to search for
90.336 - */
90.337 - public Class<T> getType() {
90.338 - return type;
90.339 - }
90.340 -
90.341 - /** Get the persistent identifier being searched for, if any.
90.342 - * @return the ID or <code>null</code>
90.343 - * @see Lookup.Item#getId
90.344 - *
90.345 - * @since 1.8
90.346 - */
90.347 - public String getId() {
90.348 - return id;
90.349 - }
90.350 -
90.351 - /** Get the specific instance being searched for, if any.
90.352 - * Most useful for finding an <code>Item</code> when the instance
90.353 - * is already known.
90.354 - *
90.355 - * @return the object to find or <code>null</code>
90.356 - *
90.357 - * @since 1.8
90.358 - */
90.359 - public T getInstance() {
90.360 - return instance;
90.361 - }
90.362 -
90.363 - /* Computes hashcode for this template. The hashcode is cached.
90.364 - * @return hashcode
90.365 - */
90.366 - @Override
90.367 - public int hashCode() {
90.368 - if (hashCode != 0) {
90.369 - return hashCode;
90.370 - }
90.371 -
90.372 - hashCode = ((type == null) ? 1 : type.hashCode()) + ((id == null) ? 2 : id.hashCode()) +
90.373 - ((instance == null) ? 3 : 0);
90.374 -
90.375 - return hashCode;
90.376 - }
90.377 -
90.378 - /* Checks whether two templates represent the same query.
90.379 - * @param obj another template to check
90.380 - * @return true if so, false otherwise
90.381 - */
90.382 - @Override
90.383 - public boolean equals(Object obj) {
90.384 - if (!(obj instanceof Template)) {
90.385 - return false;
90.386 - }
90.387 -
90.388 - Template t = (Template) obj;
90.389 -
90.390 - if (hashCode() != t.hashCode()) {
90.391 - // this is an optimalization - the hashCodes should have been
90.392 - // precomputed
90.393 - return false;
90.394 - }
90.395 -
90.396 - if (type != t.type) {
90.397 - return false;
90.398 - }
90.399 -
90.400 - if (id == null) {
90.401 - if (t.id != null) {
90.402 - return false;
90.403 - }
90.404 - } else {
90.405 - if (!id.equals(t.id)) {
90.406 - return false;
90.407 - }
90.408 - }
90.409 -
90.410 - if (instance == null) {
90.411 - return (t.instance == null);
90.412 - } else {
90.413 - return instance.equals(t.instance);
90.414 - }
90.415 - }
90.416 -
90.417 - /* for debugging */
90.418 - @Override
90.419 - public String toString() {
90.420 - return "Lookup.Template[type=" + type + ",id=" + id + ",instance=" + instance + "]"; // NOI18N
90.421 - }
90.422 - }
90.423 -
90.424 - /** Result of a lookup request.
90.425 - * Allows access to all matching instances at once.
90.426 - * Also permits listening to changes in the result.
90.427 - * Result can contain duplicate items.
90.428 - */
90.429 - public static abstract class Result<T> extends Object {
90.430 - /** Registers a listener that is invoked when there is a possible
90.431 - * change in this result.
90.432 - *
90.433 - * @param l the listener to add
90.434 - */
90.435 - public abstract void addLookupListener(LookupListener l);
90.436 -
90.437 - /** Unregisters a listener previously added.
90.438 - * @param l the listener to remove
90.439 - */
90.440 - public abstract void removeLookupListener(LookupListener l);
90.441 -
90.442 - /** Get all instances in the result. The return value type
90.443 - * should be List instead of Collection, but it is too late to change it.
90.444 - * @return unmodifiable collection of all instances that will never change its content
90.445 - */
90.446 - public abstract Collection<? extends T> allInstances();
90.447 -
90.448 - /** Get all classes represented in the result.
90.449 - * That is, the set of concrete classes
90.450 - * used by instances present in the result.
90.451 - * All duplicate classes will be omitted.
90.452 - * @return unmodifiable set of <code>Class</code> objects that will never change its content
90.453 - *
90.454 - * @since 1.8
90.455 - */
90.456 - public Set<Class<? extends T>> allClasses() {
90.457 - return Collections.emptySet();
90.458 - }
90.459 -
90.460 - /** Get all registered items.
90.461 - * This should include all pairs of instances together
90.462 - * with their classes, IDs, and so on. The return value type
90.463 - * should be List instead of Collection, but it is too late to change it.
90.464 - * @return unmodifiable collection of {@link Lookup.Item} that will never change its content
90.465 - *
90.466 - * @since 1.8
90.467 - */
90.468 - public Collection<? extends Item<T>> allItems() {
90.469 - return Collections.emptyList();
90.470 - }
90.471 - }
90.472 -
90.473 - /** A single item in a lookup result.
90.474 - * This wrapper provides unified access to not just the instance,
90.475 - * but its class, a possible persistent identifier, and so on.
90.476 - *
90.477 - * @since 1.25
90.478 - */
90.479 - public static abstract class Item<T> extends Object {
90.480 - /** Get the instance itself.
90.481 - * @return the instance or null if the instance cannot be created
90.482 - */
90.483 - public abstract T getInstance();
90.484 -
90.485 - /** Get the implementing class of the instance.
90.486 - * @return the class of the item
90.487 - */
90.488 - public abstract Class<? extends T> getType();
90.489 -
90.490 - // XXX can it be null??
90.491 -
90.492 - /** Get a persistent indentifier for the item.
90.493 - * This identifier should uniquely represent the item
90.494 - * within its containing lookup (and if possible within the
90.495 - * global lookup as a whole). For example, it might represent
90.496 - * the source of the instance as a file name. The ID may be
90.497 - * persisted and in a later session used to find the same instance
90.498 - * as was encountered earlier, by means of passing it into a
90.499 - * lookup template.
90.500 - *
90.501 - * @return a string ID of the item
90.502 - */
90.503 - public abstract String getId();
90.504 -
90.505 - /** Get a human presentable name for the item.
90.506 - * This might be used when summarizing all the items found in a
90.507 - * lookup result in some part of a GUI.
90.508 - * @return the string suitable for presenting the object to a user
90.509 - */
90.510 - public abstract String getDisplayName();
90.511 -
90.512 - /* show ID for debugging */
90.513 - @Override
90.514 - public String toString() {
90.515 - return getId();
90.516 - }
90.517 - }
90.518 -
90.519 - //
90.520 - // Implementation of the default lookup
90.521 - //
90.522 - private static final class Empty extends Lookup {
90.523 - private static final Result NO_RESULT = new Result() {
90.524 - public void addLookupListener(LookupListener l) {
90.525 - }
90.526 -
90.527 - public void removeLookupListener(LookupListener l) {
90.528 - }
90.529 -
90.530 - public Collection allInstances() {
90.531 - return Collections.EMPTY_SET;
90.532 - }
90.533 - };
90.534 -
90.535 - Empty() {
90.536 - }
90.537 -
90.538 - public <T> T lookup(Class<T> clazz) {
90.539 - return null;
90.540 - }
90.541 -
90.542 - @SuppressWarnings("unchecked")
90.543 - public <T> Result<T> lookup(Template<T> template) {
90.544 - return NO_RESULT;
90.545 - }
90.546 - }
90.547 -}
91.1 --- a/openide.util/src/org/openide/util/LookupEvent.java Thu Dec 10 19:23:25 2009 -0500
91.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
91.3 @@ -1,57 +0,0 @@
91.4 -/*
91.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
91.6 - *
91.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
91.8 - *
91.9 - * The contents of this file are subject to the terms of either the GNU
91.10 - * General Public License Version 2 only ("GPL") or the Common
91.11 - * Development and Distribution License("CDDL") (collectively, the
91.12 - * "License"). You may not use this file except in compliance with the
91.13 - * License. You can obtain a copy of the License at
91.14 - * http://www.netbeans.org/cddl-gplv2.html
91.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
91.16 - * specific language governing permissions and limitations under the
91.17 - * License. When distributing the software, include this License Header
91.18 - * Notice in each file and include the License file at
91.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
91.20 - * particular file as subject to the "Classpath" exception as provided
91.21 - * by Sun in the GPL Version 2 section of the License file that
91.22 - * accompanied this code. If applicable, add the following below the
91.23 - * License Header, with the fields enclosed by brackets [] replaced by
91.24 - * your own identifying information:
91.25 - * "Portions Copyrighted [year] [name of copyright owner]"
91.26 - *
91.27 - * Contributor(s):
91.28 - *
91.29 - * The Original Software is NetBeans. The Initial Developer of the Original
91.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
91.31 - * Microsystems, Inc. All Rights Reserved.
91.32 - *
91.33 - * If you wish your version of this file to be governed by only the CDDL
91.34 - * or only the GPL Version 2, indicate your decision by adding
91.35 - * "[Contributor] elects to include this software in this distribution
91.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
91.37 - * single choice of license, a recipient has the option to distribute
91.38 - * your version of this file under either the CDDL, the GPL Version 2 or
91.39 - * to extend the choice of license to its licensees as provided above.
91.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
91.41 - * Version 2 license, then the option applies only if the new code is
91.42 - * made subject to such option by the copyright holder.
91.43 - */
91.44 -package org.openide.util;
91.45 -
91.46 -import java.util.*;
91.47 -
91.48 -
91.49 -/** An event describing the change in the lookup's result.
91.50 - *
91.51 - * @author Jaroslav Tulach
91.52 - */
91.53 -public final class LookupEvent extends EventObject {
91.54 - /** Create a new lookup event.
91.55 - * @param source the lookup result which has changed
91.56 - */
91.57 - public LookupEvent(Lookup.Result source) {
91.58 - super(source);
91.59 - }
91.60 -}
92.1 --- a/openide.util/src/org/openide/util/LookupListener.java Thu Dec 10 19:23:25 2009 -0500
92.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
92.3 @@ -1,59 +0,0 @@
92.4 -/*
92.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
92.6 - *
92.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
92.8 - *
92.9 - * The contents of this file are subject to the terms of either the GNU
92.10 - * General Public License Version 2 only ("GPL") or the Common
92.11 - * Development and Distribution License("CDDL") (collectively, the
92.12 - * "License"). You may not use this file except in compliance with the
92.13 - * License. You can obtain a copy of the License at
92.14 - * http://www.netbeans.org/cddl-gplv2.html
92.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
92.16 - * specific language governing permissions and limitations under the
92.17 - * License. When distributing the software, include this License Header
92.18 - * Notice in each file and include the License file at
92.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
92.20 - * particular file as subject to the "Classpath" exception as provided
92.21 - * by Sun in the GPL Version 2 section of the License file that
92.22 - * accompanied this code. If applicable, add the following below the
92.23 - * License Header, with the fields enclosed by brackets [] replaced by
92.24 - * your own identifying information:
92.25 - * "Portions Copyrighted [year] [name of copyright owner]"
92.26 - *
92.27 - * Contributor(s):
92.28 - *
92.29 - * The Original Software is NetBeans. The Initial Developer of the Original
92.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
92.31 - * Microsystems, Inc. All Rights Reserved.
92.32 - *
92.33 - * If you wish your version of this file to be governed by only the CDDL
92.34 - * or only the GPL Version 2, indicate your decision by adding
92.35 - * "[Contributor] elects to include this software in this distribution
92.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
92.37 - * single choice of license, a recipient has the option to distribute
92.38 - * your version of this file under either the CDDL, the GPL Version 2 or
92.39 - * to extend the choice of license to its licensees as provided above.
92.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
92.41 - * Version 2 license, then the option applies only if the new code is
92.42 - * made subject to such option by the copyright holder.
92.43 - */
92.44 -package org.openide.util;
92.45 -
92.46 -import java.util.*;
92.47 -
92.48 -
92.49 -/** General listener for changes in lookup.
92.50 - *
92.51 - * @author Jaroslav Tulach
92.52 - */
92.53 -public interface LookupListener extends EventListener {
92.54 - /** A change in lookup occured. Please note that this method
92.55 - * should never block since it might be called from lookup implementation
92.56 - * internal threads. If you block here you are in risk that the thread
92.57 - * you wait for might in turn to wait for the lookup internal thread to
92.58 - * finish its work.
92.59 - * @param ev event describing the change
92.60 - */
92.61 - public void resultChanged(LookupEvent ev);
92.62 -}
93.1 --- a/openide.util/src/org/openide/util/doc-files/api.html Thu Dec 10 19:23:25 2009 -0500
93.2 +++ b/openide.util/src/org/openide/util/doc-files/api.html Mon Dec 14 20:58:39 2009 +0100
93.3 @@ -58,8 +58,8 @@
93.4 <h2>Package <a href="../package-summary.html"><code>org.openide.util</code></a></h2>
93.5
93.6 <ol>
93.7 - <li><a href="../Lookup.html">Lookup</a> and its associated
93.8 - <a href="../lookup/package-summary.html">support package</a> as that
93.9 + <li><a href="@org-openide-util-lookup@/org/openide/util/Lookup.html">Lookup</a> and its associated
93.10 + <a href="@org-openide-util-lookup@/org/openide/util/lookup/package-summary.html">support package</a> as that
93.11 is the <em>adaptable</em> interface that objects can provide if
93.12 they wish to offer dynamic capabilities.
93.13 </li>
93.14 @@ -114,11 +114,11 @@
93.15
93.16 <p>For lookup, this centers around
93.17
93.18 -<a href="../Lookup.html"><code>Lookup</code></a>
93.19 +<a href="@org-openide-util-lookup@/org/openide/util/Lookup.html"><code>Lookup</code></a>
93.20
93.21 and helper implementations in
93.22
93.23 -<a href="../lookup/package-summary.html"><code>org.openide.util.lookup</code></a>.
93.24 +<a href="@org-openide-util-lookup@/org/openide/util/lookup/package-summary.html"><code>org.openide.util.lookup</code></a>.
93.25
93.26
93.27
93.28 @@ -447,7 +447,7 @@
93.29
93.30 The client side of the lookup system centers around one class,
93.31
93.32 -<a href="../Lookup.html"><code>Lookup</code></a>.
93.33 +<a href="@org-openide-util-lookup@/org/openide/util/Lookup.html"><code>Lookup</code></a>.
93.34
93.35 In the simplest usage, all that is needed is to get some single
93.36 instance of a given class (or subclass). For example, if some kind of
93.37 @@ -456,7 +456,7 @@
93.38 may simply use:
93.39
93.40 <pre>
93.41 -<font class="type">MyService</font> <font class="variable-name">impl</font> = (<font class="type">MyService</font>)Lookup.getDefault().<a href="../Lookup.html#lookup(java.lang.Class)">lookup</a>(MyService.<font class="keyword">class</font>);
93.42 +<font class="type">MyService</font> <font class="variable-name">impl</font> = (<font class="type">MyService</font>)Lookup.getDefault().<a href="@org-openide-util-lookup@/org/openide/util/Lookup.html#lookup(java.lang.Class)">lookup</a>(MyService.<font class="keyword">class</font>);
93.43 <font class="keyword">if</font> (impl == <font class="constant">null</font>) <font class="comment">/* nothing registered */</font> ...
93.44 impl.useIt();
93.45 </pre>
93.46 @@ -558,12 +558,12 @@
93.47 general method:
93.48
93.49 <pre>
93.50 -<font class="type"><a href="../Lookup.Template.html">Lookup.Template</a></font> <font class="variable-name">templ</font> = <font class="keyword">new</font> <font class="type">Lookup.Template</font>(MyService.<font class="keyword">class</font>);
93.51 -<font class="keyword">final</font> <font class="type"><a href="../Lookup.Result.html">Lookup.Result</a></font> <font class="variable-name">result</font> = Lookup.getDefault().lookup(templ);
93.52 +<font class="type"><a href="@org-openide-util-lookup@/org/openide/util/Lookup.Template.html">Lookup.Template</a></font> <font class="variable-name">templ</font> = <font class="keyword">new</font> <font class="type">Lookup.Template</font>(MyService.<font class="keyword">class</font>);
93.53 +<font class="keyword">final</font> <font class="type"><a href="@org-openide-util-lookup@/org/openide/util/Lookup.Result.html">Lookup.Result</a></font> <font class="variable-name">result</font> = Lookup.getDefault().lookup(templ);
93.54 <font class="type">Collection</font> <font class="variable-name">impls</font> = result.allInstances(); <font class="comment">// Collection<MyService>
93.55 // use Java Collections API to get iterator, ...
93.56 // Pay attention to subsequent changes in the result.
93.57 -</font>result.addLookupListener(<font class="keyword">new</font> <font class="type"><a href="../LookupListener.html">LookupListener</a></font>() {
93.58 +</font>result.addLookupListener(<font class="keyword">new</font> <font class="type"><a href="@org-openide-util-lookup@/org/openide/util/LookupListener.html">LookupListener</a></font>() {
93.59 <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">ev</font>) {
93.60 <font class="comment">// Now it is different.
93.61 </font> <font class="type">Collection</font> <font class="variable-name">impls2</font> = result.allInstances();
93.62 @@ -611,7 +611,7 @@
93.63 <font class="type">Lookup.Result</font> <font class="variable-name">result</font> = Lookup.getDefault().lookup(templ);
93.64 <font class="type">Iterator</font> <font class="variable-name">it</font> = result.allItems().iterator();
93.65 <font class="keyword">while</font> (it.hasNext()) {
93.66 - <font class="type"><a href="../Lookup.Item.html">Lookup.Item</a></font> <font class="variable-name">item</font> = (<font class="type">Lookup.Item</font>)it.next();
93.67 + <font class="type"><a href="@org-openide-util-lookup@/org/openide/util/Lookup.Item.html">Lookup.Item</a></font> <font class="variable-name">item</font> = (<font class="type">Lookup.Item</font>)it.next();
93.68 <font class="type">String</font> <font class="variable-name">displayName</font> = item.getDisplayName();
93.69 <font class="keyword">if</font> (<font class="comment">/* user accepts displayName as the right one */</font>) {
93.70 <font class="type">MyService</font> <font class="variable-name">instance</font> = (<font class="type">MyService</font>)item.getInstance();
93.71 @@ -623,7 +623,7 @@
93.72 }
93.73 <font class="comment">// later...
93.74 </font><font class="type">String</font> <font class="variable-name">storedID</font> = someSettings.getChosenService();
93.75 -<font class="type">Lookup.Template</font> <font class="variable-name">templ</font> = <font class="keyword">new</font> <font class="type"><a href="../Lookup.Template.html#Lookup.Template(java.lang.Class,java.lang.String,java.lang.Object)">Lookup.Template</a></font>(MyService.<font class="keyword">class</font>, storedID, <font class="constant">null</font>);
93.76 +<font class="type">Lookup.Template</font> <font class="variable-name">templ</font> = <font class="keyword">new</font> <font class="type"><a href="@org-openide-util-lookup@/org/openide/util/Lookup.Template.html#Lookup.Template(java.lang.Class,java.lang.String,java.lang.Object)">Lookup.Template</a></font>(MyService.<font class="keyword">class</font>, storedID, <font class="constant">null</font>);
93.77 <font class="type">Iterator</font> <font class="variable-name">it</font> = Lookup.getDefault().lookup(templ).allInstances().iterator();
93.78 <font class="keyword">if</font> (! it.hasNext()) <font class="comment">/* failed to find it... */</font>
93.79 <font class="type">MyService</font> <font class="variable-name">instance</font> = (<font class="type">MyService</font>)it.next();
93.80 @@ -661,7 +661,7 @@
93.81 <p>The simplest way to create a fresh lookup is to base it on other
93.82 existing ones.
93.83
93.84 -<a href="../lookup/ProxyLookup.html"><code>ProxyLookup</code></a>
93.85 +<a href="@org-openide-util-lookup@/org/openide/util/lookup/ProxyLookup.html"><code>ProxyLookup</code></a>
93.86
93.87 accepts a list of other lookup implementations (in the constructor and
93.88 also changeable later). The results it provides are constructed by
93.89 @@ -673,7 +673,7 @@
93.90 If you want to use the common mechanism of finding instances in
93.91 folders (or subfolders) and serving these as the results,
93.92
93.93 -<a href="../lookup/Lookups.html#forPath(java.lang.String)">Lookups.forPath(String)</a>
93.94 +<a href="@org-openide-util-lookup@/org/openide/util/lookup/Lookups.html#forPath(java.lang.String)">Lookups.forPath(String)</a>
93.95
93.96 makes this possible: you need only provide a name of a folder to look in, and
93.97 use
93.98 @@ -723,7 +723,7 @@
93.99 <p>The most powerful way to provide a lookup is to directly define
93.100 what instances and items it should provide, by subclassing. For this,
93.101
93.102 -<a href="../lookup/AbstractLookup.html"><code>AbstractLookup</code></a>
93.103 +<a href="@org-openide-util-lookup@/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 @@ -731,18 +731,18 @@
93.108 public constructor (in which case you need not subclass it). Here you
93.109 provide an
93.110
93.111 -<a href="../lookup/AbstractLookup.Content.html"><code>AbstractLookup.Content</code></a>
93.112 +<a href="@org-openide-util-lookup@/org/openide/util/lookup/AbstractLookup.Content.html"><code>AbstractLookup.Content</code></a>
93.113
93.114 object which you have created and hold on to privately, and which
93.115 keeps track of instances and permits them to be registered and
93.116 deregistered. Often
93.117
93.118 -<a href="../lookup/InstanceContent.html"><code>InstanceContent</code></a>
93.119 +<a href="@org-openide-util-lookup@/org/openide/util/lookup/InstanceContent.html"><code>InstanceContent</code></a>
93.120
93.121 is used as the content implementation. To add something to the lookup,
93.122 simply use
93.123
93.124 -<a href="../lookup/InstanceContent.html#add(java.lang.Object)"><code>add(Object)</code></a>
93.125 +<a href="@org-openide-util-lookup@/org/openide/util/lookup/InstanceContent.html#add(java.lang.Object)"><code>add(Object)</code></a>
93.126
93.127 (and <code>remove(Object)</code> for the reverse). These may be called
93.128 at any time and will update the set of registered instances (firing
93.129 @@ -752,7 +752,7 @@
93.130 lookup, but there is some cheap "key" which can easily generate it,
93.131 you may instead register the key by passing in an
93.132
93.133 -<a href="../lookup/InstanceContent.Convertor.html"><code>InstanceContent.Convertor</code></a>.
93.134 +<a href="@org-openide-util-lookup@/org/openide/util/lookup/InstanceContent.Convertor.html"><code>InstanceContent.Convertor</code></a>.
93.135
93.136 This convertor translates the key to the real instance that the lookup
93.137 client sees, if and when needed. For example, if you have a long list
94.1 --- a/openide.util/src/org/openide/util/lookup/ALPairComparator.java Thu Dec 10 19:23:25 2009 -0500
94.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
94.3 @@ -1,88 +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 - * The contents of this file are subject to the terms of either the GNU
94.10 - * General Public License Version 2 only ("GPL") or the Common
94.11 - * Development and Distribution License("CDDL") (collectively, the
94.12 - * "License"). You may not use this file except in compliance with the
94.13 - * License. You can obtain a copy of the License at
94.14 - * http://www.netbeans.org/cddl-gplv2.html
94.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
94.16 - * specific language governing permissions and limitations under the
94.17 - * License. When distributing the software, include this License Header
94.18 - * Notice in each file and include the License file at
94.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
94.20 - * particular file as subject to the "Classpath" exception as provided
94.21 - * by Sun in the GPL Version 2 section of the License file that
94.22 - * accompanied this code. If applicable, add the following below the
94.23 - * License Header, with the fields enclosed by brackets [] replaced by
94.24 - * your own identifying information:
94.25 - * "Portions Copyrighted [year] [name of copyright owner]"
94.26 - *
94.27 - * Contributor(s):
94.28 - *
94.29 - * The Original Software is NetBeans. The Initial Developer of the Original
94.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
94.31 - * Microsystems, Inc. All Rights Reserved.
94.32 - *
94.33 - * If you wish your version of this file to be governed by only the CDDL
94.34 - * or only the GPL Version 2, indicate your decision by adding
94.35 - * "[Contributor] elects to include this software in this distribution
94.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
94.37 - * single choice of license, a recipient has the option to distribute
94.38 - * your version of this file under either the CDDL, the GPL Version 2 or
94.39 - * to extend the choice of license to its licensees as provided above.
94.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
94.41 - * Version 2 license, then the option applies only if the new code is
94.42 - * made subject to such option by the copyright holder.
94.43 - */
94.44 -package org.openide.util.lookup;
94.45 -
94.46 -import java.util.Comparator;
94.47 -import org.openide.util.lookup.AbstractLookup.Pair;
94.48 -
94.49 -
94.50 -/** Implementation of comparator for AbstractLookup.Pair
94.51 - *
94.52 - * @author Jaroslav Tulach
94.53 - */
94.54 -final class ALPairComparator implements Comparator<Pair<?>> {
94.55 - public static final Comparator<Pair<?>> DEFAULT = new ALPairComparator();
94.56 -
94.57 - /** Creates a new instance of ALPairComparator */
94.58 - private ALPairComparator() {
94.59 - }
94.60 -
94.61 - /** Compares two items.
94.62 - */
94.63 - public int compare(Pair<?> i1, Pair<?> i2) {
94.64 - int result = i1.getIndex() - i2.getIndex();
94.65 -
94.66 - if (result == 0) {
94.67 - if (i1 != i2) {
94.68 - java.io.ByteArrayOutputStream bs = new java.io.ByteArrayOutputStream();
94.69 - java.io.PrintStream ps = new java.io.PrintStream(bs);
94.70 -
94.71 - ps.println(
94.72 - "Duplicate pair in tree" + // NOI18N
94.73 - "Pair1: " + i1 + " pair2: " + i2 + " index1: " + i1.getIndex() + " index2: " +
94.74 - i2.getIndex() // NOI18N
94.75 - +" item1: " + i1.getInstance() + " item2: " + i2.getInstance() // NOI18N
94.76 - +" id1: " + Integer.toHexString(System.identityHashCode(i1)) // NOI18N
94.77 - +" id2: " + Integer.toHexString(System.identityHashCode(i2)) // NOI18N
94.78 - );
94.79 -
94.80 - // print (ps, false);
94.81 - ps.close();
94.82 -
94.83 - throw new IllegalStateException(bs.toString());
94.84 - }
94.85 -
94.86 - return 0;
94.87 - }
94.88 -
94.89 - return result;
94.90 - }
94.91 -}
95.1 --- a/openide.util/src/org/openide/util/lookup/AbstractLookup.java Thu Dec 10 19:23:25 2009 -0500
95.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
95.3 @@ -1,1467 +0,0 @@
95.4 -/*
95.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
95.6 - *
95.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
95.8 - *
95.9 - * The contents of this file are subject to the terms of either the GNU
95.10 - * General Public License Version 2 only ("GPL") or the Common
95.11 - * Development and Distribution License("CDDL") (collectively, the
95.12 - * "License"). You may not use this file except in compliance with the
95.13 - * License. You can obtain a copy of the License at
95.14 - * http://www.netbeans.org/cddl-gplv2.html
95.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
95.16 - * specific language governing permissions and limitations under the
95.17 - * License. When distributing the software, include this License Header
95.18 - * Notice in each file and include the License file at
95.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
95.20 - * particular file as subject to the "Classpath" exception as provided
95.21 - * by Sun in the GPL Version 2 section of the License file that
95.22 - * accompanied this code. If applicable, add the following below the
95.23 - * License Header, with the fields enclosed by brackets [] replaced by
95.24 - * your own identifying information:
95.25 - * "Portions Copyrighted [year] [name of copyright owner]"
95.26 - *
95.27 - * Contributor(s):
95.28 - *
95.29 - * The Original Software is NetBeans. The Initial Developer of the Original
95.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
95.31 - * Microsystems, Inc. All Rights Reserved.
95.32 - *
95.33 - * If you wish your version of this file to be governed by only the CDDL
95.34 - * or only the GPL Version 2, indicate your decision by adding
95.35 - * "[Contributor] elects to include this software in this distribution
95.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
95.37 - * single choice of license, a recipient has the option to distribute
95.38 - * your version of this file under either the CDDL, the GPL Version 2 or
95.39 - * to extend the choice of license to its licensees as provided above.
95.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
95.41 - * Version 2 license, then the option applies only if the new code is
95.42 - * made subject to such option by the copyright holder.
95.43 - */
95.44 -package org.openide.util.lookup;
95.45 -
95.46 -import java.io.PrintStream;
95.47 -import org.openide.util.Lookup;
95.48 -import org.openide.util.LookupEvent;
95.49 -import org.openide.util.LookupListener;
95.50 -
95.51 -import java.io.IOException;
95.52 -import java.io.ObjectOutputStream;
95.53 -import java.io.Serializable;
95.54 -
95.55 -import java.lang.ref.ReferenceQueue;
95.56 -import java.lang.ref.WeakReference;
95.57 -import java.util.ArrayList;
95.58 -import java.util.Arrays;
95.59 -import java.util.Collection;
95.60 -import java.util.Collections;
95.61 -import java.util.Enumeration;
95.62 -import java.util.HashMap;
95.63 -import java.util.HashSet;
95.64 -import java.util.Iterator;
95.65 -import java.util.LinkedHashSet;
95.66 -import java.util.Map;
95.67 -import java.util.Set;
95.68 -import java.util.TreeSet;
95.69 -
95.70 -import java.util.concurrent.Executor;
95.71 -import org.netbeans.modules.openide.util.ActiveQueue;
95.72 -
95.73 -
95.74 -/** Implementation of the lookup from OpenAPIs that is based on the
95.75 - * introduction of Item. This class should provide the default way
95.76 - * of how to store (Class, Object) pairs in the lookups. It offers
95.77 - * protected methods for subclasses to register the pairs.
95.78 - * <p>Serializable since 3.27.
95.79 - * @author Jaroslav Tulach
95.80 - * @since 1.9
95.81 - */
95.82 -public class AbstractLookup extends Lookup implements Serializable {
95.83 - static final long serialVersionUID = 5L;
95.84 -
95.85 - /** lock for initialization of the maps of lookups */
95.86 - private static final Object treeLock = new Object();
95.87 -
95.88 - /** the tree that registers all items (or Integer as a treshold size) */
95.89 - private Object tree;
95.90 -
95.91 - /** count of items in to lookup */
95.92 - private int count;
95.93 -
95.94 - /** Constructor to create this lookup and associate it with given
95.95 - * Content. The content than allows the creator to invoke protected
95.96 - * methods which are not accessible for any other user of the lookup.
95.97 - *
95.98 - * @param content the content to assciate with
95.99 - *
95.100 - * @since 1.25
95.101 - */
95.102 - public AbstractLookup(Content content) {
95.103 - content.attach(this);
95.104 - }
95.105 -
95.106 - /** Constructor for testing purposes that allows specification of storage
95.107 - * as mechanism as well.
95.108 - */
95.109 - AbstractLookup(Content content, Storage<?> storage) {
95.110 - this(content);
95.111 - this.tree = storage;
95.112 - initialize();
95.113 - }
95.114 -
95.115 - /** Constructor for testing purposes that allows specification of storage
95.116 - * as mechanism as well.
95.117 - * @param trashhold number of Pair to "remain small"
95.118 - */
95.119 - AbstractLookup(Content content, Integer trashhold) {
95.120 - this(content);
95.121 - this.tree = trashhold;
95.122 - }
95.123 -
95.124 - /** Default constructor for subclasses that do not need to provide a content
95.125 - */
95.126 - protected AbstractLookup() {
95.127 - }
95.128 -
95.129 - @Override
95.130 - public String toString() {
95.131 - if (tree instanceof Storage) {
95.132 - return "AbstractLookup" + lookup(new Lookup.Template<Object>(Object.class)).allItems(); // NOI18N
95.133 - } else {
95.134 - return super.toString();
95.135 - }
95.136 - }
95.137 -
95.138 - /** Entres the storage management system.
95.139 - */
95.140 - @SuppressWarnings("unchecked")
95.141 - private <T> AbstractLookup.Storage<T> enterStorage() {
95.142 - for (;;) {
95.143 - synchronized (treeLock) {
95.144 - if (tree instanceof AbstractLookup.Storage) {
95.145 - if (tree instanceof DelegatingStorage) {
95.146 - // somebody is using the lookup right now
95.147 - DelegatingStorage del = (DelegatingStorage) tree;
95.148 -
95.149 - // check whether there is not access from the same
95.150 - // thread (can throw exception)
95.151 - del.checkForTreeModification();
95.152 -
95.153 - try {
95.154 - treeLock.wait();
95.155 - } catch (InterruptedException ex) {
95.156 - // ignore and go on
95.157 - }
95.158 -
95.159 - continue;
95.160 - } else {
95.161 - // ok, tree is initialized and nobody is using it yet
95.162 - tree = new DelegatingStorage((Storage<T>) tree);
95.163 -
95.164 - return (Storage<T>) tree;
95.165 - }
95.166 - }
95.167 -
95.168 - // first time initialization of the tree
95.169 - if (tree instanceof Integer) {
95.170 - tree = new ArrayStorage((Integer) tree);
95.171 - } else {
95.172 - tree = new ArrayStorage();
95.173 - }
95.174 - }
95.175 -
95.176 - // the tree has not yet been initilized, initialize and go on again
95.177 - initialize();
95.178 - }
95.179 - }
95.180 -
95.181 - /** Exists tree ownership.
95.182 - */
95.183 - private AbstractLookup.Storage exitStorage() {
95.184 - synchronized (treeLock) {
95.185 - AbstractLookup.Storage stor = ((DelegatingStorage) tree).exitDelegate();
95.186 - tree = stor;
95.187 - treeLock.notifyAll();
95.188 -
95.189 - return stor;
95.190 - }
95.191 - }
95.192 -
95.193 - /** Method for subclasses to initialize them selves.
95.194 - */
95.195 - protected void initialize() {
95.196 - }
95.197 -
95.198 - /** Notifies subclasses that a query is about to be processed.
95.199 - * @param template the template
95.200 - */
95.201 - protected void beforeLookup(Template<?> template) {
95.202 - }
95.203 -
95.204 - /** The method to add instance to the lookup with.
95.205 - * @param pair class/instance pair
95.206 - */
95.207 - protected final void addPair(Pair<?> pair) {
95.208 - addPairImpl(pair, null);
95.209 - }
95.210 -
95.211 - /** The method to add instance to the lookup with.
95.212 - * @param pair class/instance pair
95.213 - * @param notifyIn the executor that will handle the notification of events
95.214 - * @since 7.16
95.215 - */
95.216 - protected final void addPair(Pair<?> pair, Executor notifyIn) {
95.217 - addPairImpl(pair, notifyIn);
95.218 - }
95.219 -
95.220 - private final <Transaction> void addPairImpl(Pair<?> pair, Executor notifyIn) {
95.221 - HashSet<R> toNotify = new HashSet<R>();
95.222 -
95.223 - AbstractLookup.Storage<Transaction> t = enterStorage();
95.224 - Transaction transaction = null;
95.225 -
95.226 - try {
95.227 - transaction = t.beginTransaction(-2);
95.228 -
95.229 - if (t.add(pair, transaction)) {
95.230 - try {
95.231 - pair.setIndex(t, count++);
95.232 - } catch (IllegalStateException ex) {
95.233 - // remove the pair
95.234 - t.remove(pair, transaction);
95.235 -
95.236 - // rethrow the exception
95.237 - throw ex;
95.238 - }
95.239 -
95.240 - // if the pair is newly added and was not there before
95.241 - t.endTransaction(transaction, toNotify);
95.242 - } else {
95.243 - // just finish the process by calling endTransaction
95.244 - t.endTransaction(transaction, new HashSet<R>());
95.245 - }
95.246 - } finally {
95.247 - exitStorage();
95.248 - }
95.249 -
95.250 - notifyIn(notifyIn, toNotify);
95.251 - }
95.252 -
95.253 - /** Remove instance.
95.254 - * @param pair class/instance pair
95.255 - */
95.256 - protected final void removePair(Pair<?> pair) {
95.257 - removePairImpl(pair, null);
95.258 - }
95.259 - /** Remove instance.
95.260 - * @param pair class/instance pair
95.261 - * @param notifyIn the executor that will handle the notification of events
95.262 - * @since 7.16
95.263 - */
95.264 - protected final void removePair(Pair<?> pair, Executor notifyIn) {
95.265 - removePairImpl(pair, notifyIn);
95.266 - }
95.267 -
95.268 - private <Transaction> void removePairImpl(Pair<?> pair, Executor notifyIn) {
95.269 - HashSet<R> toNotify = new HashSet<R>();
95.270 -
95.271 - AbstractLookup.Storage<Transaction> t = enterStorage();
95.272 - Transaction transaction = null;
95.273 -
95.274 - try {
95.275 - transaction = t.beginTransaction(-1);
95.276 - t.remove(pair, transaction);
95.277 - t.endTransaction(transaction, toNotify);
95.278 - } finally {
95.279 - exitStorage();
95.280 - }
95.281 -
95.282 - notifyIn(notifyIn, toNotify);
95.283 - }
95.284 -
95.285 - /** Changes all pairs in the lookup to new values.
95.286 - * @param collection the collection of (Pair) objects
95.287 - */
95.288 - protected final void setPairs(Collection<? extends Pair> collection) {
95.289 - setPairs(collection, null);
95.290 - }
95.291 -
95.292 - /** Changes all pairs in the lookup to new values, notifies listeners
95.293 - * using provided executor.
95.294 - *
95.295 - * @param collection the collection of (Pair) objects
95.296 - * @param notifyIn the executor that will handle the notification of events
95.297 - * @since 7.16
95.298 - */
95.299 - protected final void setPairs(Collection<? extends Pair> collection, Executor notifyIn) {
95.300 - HashSet<R> listeners = setPairsAndCollectListeners(collection);
95.301 - notifyIn(notifyIn, listeners);
95.302 - }
95.303 -
95.304 - private final void notifyIn(Executor notifyIn, final HashSet<R> listeners) {
95.305 - NotifyListeners notify = new NotifyListeners(listeners);
95.306 - if (notify.shallRun()) {
95.307 - if (notifyIn == null) {
95.308 - notify.run();
95.309 - } else {
95.310 - notifyIn.execute(notify);
95.311 - }
95.312 - }
95.313 - }
95.314 -
95.315 - /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
95.316 - * @return a LinkedHashSet that can be modified
95.317 - */
95.318 - final LinkedHashSet<Pair<?>> getPairsAsLHS() {
95.319 - AbstractLookup.Storage<?> t = enterStorage();
95.320 -
95.321 - try {
95.322 - Enumeration<Pair<Object>> en = t.lookup(Object.class);
95.323 - TreeSet<Pair<?>> arr = new TreeSet<Pair<?>>(ALPairComparator.DEFAULT);
95.324 - while (en.hasMoreElements()) {
95.325 - Pair<Object> item = en.nextElement();
95.326 - arr.add(item);
95.327 - }
95.328 - return new LinkedHashSet<Pair<?>>(arr);
95.329 - } finally {
95.330 - exitStorage();
95.331 - }
95.332 - }
95.333 -
95.334 - /** Collects listeners without notification. Needed in MetaInfServicesLookup
95.335 - * right now, but maybe will become an API later.
95.336 - */
95.337 - final <Transaction> HashSet<R> setPairsAndCollectListeners(Collection<? extends Pair> collection) {
95.338 - HashSet<R> toNotify = new HashSet<R>(27);
95.339 -
95.340 - AbstractLookup.Storage<Transaction> t = enterStorage();
95.341 - Transaction transaction = null;
95.342 -
95.343 - try {
95.344 - // map between the Items and their indexes (Integer)
95.345 - HashMap<Item<?>,Info> shouldBeThere = new HashMap<Item<?>,Info>(collection.size() * 2);
95.346 -
95.347 - count = 0;
95.348 -
95.349 - Iterator it = collection.iterator();
95.350 - transaction = t.beginTransaction(collection.size());
95.351 -
95.352 - while (it.hasNext()) {
95.353 - Pair item = (Pair) it.next();
95.354 -
95.355 - if (t.add(item, transaction)) {
95.356 - // the item has not been there yet
95.357 - //t.endTransaction(transaction, toNotify);
95.358 - }
95.359 -
95.360 - // remeber the item, because it should not be removed
95.361 - shouldBeThere.put(item, new Info(count++, transaction));
95.362 -
95.363 - // arr.clear ();
95.364 - }
95.365 -
95.366 - // Object transaction = t.beginTransaction ();
95.367 - // deletes all objects that should not be there and
95.368 - t.retainAll(shouldBeThere, transaction);
95.369 -
95.370 - // collect listeners
95.371 - t.endTransaction(transaction, toNotify);
95.372 -
95.373 - /*
95.374 - // check consistency
95.375 - Enumeration en = t.lookup (java.lang.Object.class);
95.376 - boolean[] max = new boolean[count];
95.377 - int mistake = -1;
95.378 - while (en.hasMoreElements ()) {
95.379 - Pair item = (Pair)en.nextElement ();
95.380 -
95.381 - if (max[item.index]) {
95.382 - mistake = item.index;
95.383 - }
95.384 - max[item.index] = true;
95.385 - }
95.386 -
95.387 - if (mistake != -1) {
95.388 - System.err.println ("Mistake at: " + mistake);
95.389 - tree.print (System.err, true);
95.390 - }
95.391 - */
95.392 - } finally {
95.393 - exitStorage();
95.394 - }
95.395 -
95.396 - return toNotify;
95.397 - }
95.398 -
95.399 - private final void writeObject(ObjectOutputStream oos)
95.400 - throws IOException {
95.401 - AbstractLookup.Storage s = enterStorage();
95.402 -
95.403 - try {
95.404 - // #36830: Serializing only InheritanceTree no ArrayStorage
95.405 - s.beginTransaction(Integer.MAX_VALUE);
95.406 -
95.407 - // #32040: don't write half-made changes
95.408 - oos.defaultWriteObject();
95.409 - } finally {
95.410 - exitStorage();
95.411 - }
95.412 - }
95.413 -
95.414 - public final <T> T lookup(Class<T> clazz) {
95.415 - Lookup.Item<T> item = lookupItem(new Lookup.Template<T>(clazz));
95.416 - return (item == null) ? null : item.getInstance();
95.417 - }
95.418 -
95.419 - @Override
95.420 - public final <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
95.421 - AbstractLookup.this.beforeLookup(template);
95.422 -
95.423 - ArrayList<Pair<T>> list = null;
95.424 - AbstractLookup.Storage<?> t = enterStorage();
95.425 -
95.426 - try {
95.427 - Enumeration<Pair<T>> en;
95.428 -
95.429 - try {
95.430 - en = t.lookup(template.getType());
95.431 -
95.432 - return findSmallest(en, template, false);
95.433 - } catch (AbstractLookup.ISE ex) {
95.434 - // not possible to enumerate the exception, ok, copy it
95.435 - // to create new
95.436 - list = new ArrayList<Pair<T>>();
95.437 - en = t.lookup(null); // this should get all the items without any checks
95.438 -
95.439 - // the checks will be done out side of the storage
95.440 - while (en.hasMoreElements()) {
95.441 - list.add(en.nextElement());
95.442 - }
95.443 - }
95.444 - } finally {
95.445 - exitStorage();
95.446 - }
95.447 -
95.448 - return findSmallest(Collections.enumeration(list), template, true);
95.449 - }
95.450 -
95.451 - private static <T> Pair<T> findSmallest(Enumeration<Pair<T>> en, Lookup.Template<T> template, boolean deepCheck) {
95.452 - int smallest = InheritanceTree.unsorted(en) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
95.453 - Pair<T> res = null;
95.454 -
95.455 - while (en.hasMoreElements()) {
95.456 - Pair<T> item = en.nextElement();
95.457 -
95.458 - if (matches(template, item, deepCheck)) {
95.459 - if (smallest == Integer.MIN_VALUE) {
95.460 - // ok, sorted enumeration the first that matches is fine
95.461 - return item;
95.462 - } else {
95.463 - // check for the smallest item
95.464 - if (smallest > item.getIndex()) {
95.465 - smallest = item.getIndex();
95.466 - res = item;
95.467 - }
95.468 - }
95.469 - }
95.470 - }
95.471 -
95.472 - return res;
95.473 - }
95.474 -
95.475 - public final <T> Lookup.Result<T> lookup(Lookup.Template<T> template) {
95.476 - for (;;) {
95.477 - AbstractLookup.ISE toRun = null;
95.478 -
95.479 - AbstractLookup.Storage<?> t = enterStorage();
95.480 -
95.481 - try {
95.482 - R<T> r = new R<T>();
95.483 - ReferenceToResult<T> newRef = new ReferenceToResult<T>(r, this, template);
95.484 - newRef.next = t.registerReferenceToResult(newRef);
95.485 -
95.486 - return r;
95.487 - } catch (AbstractLookup.ISE ex) {
95.488 - toRun = ex;
95.489 - } finally {
95.490 - exitStorage();
95.491 - }
95.492 -
95.493 - toRun.recover(this);
95.494 -
95.495 - // and try again
95.496 - }
95.497 - }
95.498 -
95.499 - /** Notifies listeners.
95.500 - * @param allAffectedResults set of R
95.501 - */
95.502 - static final class NotifyListeners implements Runnable {
95.503 - private final ArrayList<Object> evAndListeners;
95.504 -
95.505 - public NotifyListeners(Set<R> allAffectedResults) {
95.506 - if (allAffectedResults.isEmpty()) {
95.507 - evAndListeners = null;
95.508 - return;
95.509 - }
95.510 -
95.511 - evAndListeners = new ArrayList<Object>();
95.512 - {
95.513 - for (R<?> result : allAffectedResults) {
95.514 - result.collectFires(evAndListeners);
95.515 - }
95.516 - }
95.517 - }
95.518 -
95.519 - public boolean shallRun() {
95.520 - return evAndListeners != null && !evAndListeners.isEmpty();
95.521 - }
95.522 -
95.523 - public void run() {
95.524 - Iterator it = evAndListeners.iterator();
95.525 - while (it.hasNext()) {
95.526 - LookupEvent ev = (LookupEvent)it.next();
95.527 - LookupListener l = (LookupListener)it.next();
95.528 - l.resultChanged(ev);
95.529 - }
95.530 - }
95.531 - }
95.532 -
95.533 - /**
95.534 - * Call resultChanged on all listeners.
95.535 - * @param listeners array of listeners in the format used by
95.536 - * javax.swing.EventListenerList. It means that there are Class
95.537 - * objects on even positions and the listeners on odd positions
95.538 - * @param ev the event to fire
95.539 - */
95.540 - static void notifyListeners(Object[] listeners, LookupEvent ev, Collection<Object> evAndListeners) {
95.541 - for (int i = listeners.length - 1; i >= 0; i--) {
95.542 - if (! (listeners[i] instanceof LookupListener)) {
95.543 - continue;
95.544 - }
95.545 - LookupListener ll = (LookupListener)listeners[i];
95.546 -
95.547 - try {
95.548 - if (evAndListeners != null) {
95.549 - if (ll instanceof WaitableResult) {
95.550 - WaitableResult<?> wr = (WaitableResult<?>)ll;
95.551 - wr.collectFires(evAndListeners);
95.552 - } else {
95.553 - evAndListeners.add(ev);
95.554 - evAndListeners.add(ll);
95.555 - }
95.556 - } else {
95.557 - ll.resultChanged(ev);
95.558 - }
95.559 - } catch (StackOverflowError err) {
95.560 - throw new CycleError(evAndListeners); // NOI18N
95.561 - } catch (RuntimeException e) {
95.562 - // Such as e.g. occurred in #32040. Do not halt other things.
95.563 - e.printStackTrace();
95.564 - }
95.565 - }
95.566 - }
95.567 -
95.568 - private static class CycleError extends StackOverflowError {
95.569 - private final Collection<Object> print;
95.570 - public CycleError(Collection<Object> evAndListeners) {
95.571 - this.print = evAndListeners;
95.572 - }
95.573 -
95.574 - @Override
95.575 - public String getMessage() {
95.576 - StringBuilder sb = new StringBuilder();
95.577 - sb.append("StackOverflowError, here are the listeners:\n"); // NOI18N
95.578 - for (Object o : print) {
95.579 - sb.append('\n').append(o);
95.580 - if (sb.length() > 10000) {
95.581 - break;
95.582 - }
95.583 - }
95.584 - return sb.toString();
95.585 - }
95.586 - } // end of CycleError
95.587 -
95.588 - /** A method that defines matching between Item and Template.
95.589 - * @param t template providing the criteria
95.590 - * @param item the item to match
95.591 - * @param deepCheck true if type of the pair should be tested, false if it is already has been tested
95.592 - * @return true if item matches the template requirements, false if not
95.593 - */
95.594 - static boolean matches(Template<?> t, Pair<?> item, boolean deepCheck) {
95.595 - String id = t.getId();
95.596 -
95.597 - if (id != null && !id.equals(item.getId())) {
95.598 - return false;
95.599 - }
95.600 -
95.601 - Object instance = t.getInstance();
95.602 -
95.603 - if ((instance != null) && !item.creatorOf(instance)) {
95.604 - return false;
95.605 - }
95.606 -
95.607 - if (deepCheck) {
95.608 - return item.instanceOf(t.getType());
95.609 - } else {
95.610 - return true;
95.611 - }
95.612 - }
95.613 -
95.614 - /**
95.615 - * Compares the array elements for equality.
95.616 - * @return true if all elements in the arrays are equal
95.617 - * (by calling equals(Object x) method)
95.618 - */
95.619 - private static boolean compareArrays(Object[] a, Object[] b) {
95.620 - // handle null values
95.621 - if (a == null) {
95.622 - return (b == null);
95.623 - } else {
95.624 - if (b == null) {
95.625 - return false;
95.626 - }
95.627 - }
95.628 -
95.629 - if (a.length != b.length) {
95.630 - return false;
95.631 - }
95.632 -
95.633 - for (int i = 0; i < a.length; i++) {
95.634 - // handle null values for individual elements
95.635 - if (a[i] == null) {
95.636 - if (b[i] != null) {
95.637 - return false;
95.638 - }
95.639 -
95.640 - // both are null --> ok, take next
95.641 - continue;
95.642 - } else {
95.643 - if (b[i] == null) {
95.644 - return false;
95.645 - }
95.646 - }
95.647 -
95.648 - // perform the comparison
95.649 - if (!a[i].equals(b[i])) {
95.650 - return false;
95.651 - }
95.652 - }
95.653 -
95.654 - return true;
95.655 - }
95.656 -
95.657 - /** Method to be called when a result is cleared to signal that the list
95.658 - * of all result should be checked for clearing.
95.659 - * @param template the template the result was for
95.660 - * @return true if the hash map with all items has been cleared
95.661 - */
95.662 - <T> boolean cleanUpResult(Lookup.Template<T> template) {
95.663 - AbstractLookup.Storage<?> t = enterStorage();
95.664 -
95.665 - try {
95.666 - return t.cleanUpResult(template) == null;
95.667 - } finally {
95.668 - exitStorage();
95.669 - }
95.670 - }
95.671 -
95.672 - /** Storage check for tests. */
95.673 - static boolean isSimple(AbstractLookup l) {
95.674 - return DelegatingStorage.isSimple((Storage)l.tree);
95.675 - }
95.676 -
95.677 - /** Generic support for listeners, so it can be used in other results
95.678 - * as well.
95.679 - * @param add true to add it, false to modify
95.680 - * @param l listener to modify
95.681 - * @param ref the value of the reference to listener or listener list
95.682 - * @return new value to the reference to listener or list
95.683 - */
95.684 - @SuppressWarnings("unchecked")
95.685 - static Object modifyListenerList(boolean add, LookupListener l, Object ref) {
95.686 - if (add) {
95.687 - if (ref == null) {
95.688 - return l;
95.689 - }
95.690 -
95.691 - if (ref instanceof LookupListener) {
95.692 - ArrayList arr = new ArrayList();
95.693 - arr.add(ref);
95.694 - ref = arr;
95.695 - }
95.696 -
95.697 - ((ArrayList) ref).add(l);
95.698 -
95.699 - return ref;
95.700 - } else {
95.701 - // remove
95.702 - if (ref == null) {
95.703 - return null;
95.704 - }
95.705 -
95.706 - if (ref == l) {
95.707 - return null;
95.708 - }
95.709 -
95.710 - ArrayList arr = (ArrayList) ref;
95.711 - arr.remove(l);
95.712 -
95.713 - if (arr.size() == 1) {
95.714 - return arr.iterator().next();
95.715 - } else {
95.716 - return arr;
95.717 - }
95.718 - }
95.719 - }
95.720 -
95.721 - private static ReferenceQueue<Object> activeQueue() {
95.722 - return ActiveQueue.queue();
95.723 - }
95.724 -
95.725 - /** Storage to keep the internal structure of Pairs and to answer
95.726 - * different queries.
95.727 - */
95.728 - interface Storage<Transaction> {
95.729 - /** Initializes a modification operation by creating an object
95.730 - * that will be passsed to all add, remove, retainAll methods
95.731 - * and should collect enough information about the change to
95.732 - * notify listeners about the transaction later
95.733 - *
95.734 - * @param ensure the amount of items that will appear in the storage
95.735 - * after the modifications (-1 == remove one, -2 == add one, >= 0
95.736 - * the amount of objects at the end
95.737 - * @return a token to identify the transaction
95.738 - */
95.739 - public Transaction beginTransaction(int ensure);
95.740 -
95.741 - /** Collects all affected results R that were modified in the
95.742 - * given transaction.
95.743 - *
95.744 - * @param modified place to add results R to
95.745 - * @param transaction the transaction indentification
95.746 - */
95.747 - public void endTransaction(Transaction transaction, Set<R> modifiedResults);
95.748 -
95.749 - /** Adds an item into the storage.
95.750 - * @param item to add
95.751 - * @param transaction transaction token
95.752 - * @return true if the Item has been added for the first time or false if some other
95.753 - * item equal to this one already existed in the lookup
95.754 - */
95.755 - public boolean add(AbstractLookup.Pair<?> item, Transaction transaction);
95.756 -
95.757 - /** Removes an item.
95.758 - */
95.759 - public void remove(AbstractLookup.Pair item, Transaction transaction);
95.760 -
95.761 - /** Removes all items that are not present in the provided collection.
95.762 - * @param retain collection of Pairs to keep them in
95.763 - * @param transaction the transaction context
95.764 - */
95.765 - public void retainAll(Map retain, Transaction transaction);
95.766 -
95.767 - /** Queries for instances of given class.
95.768 - * @param clazz the class to check
95.769 - * @return enumeration of Item
95.770 - * @see #unsorted
95.771 - */
95.772 - public <T> Enumeration<Pair<T>> lookup(Class<T> clazz);
95.773 -
95.774 - /** Registers another reference to a result with the storage. This method
95.775 - * has also a special meaning.
95.776 - *
95.777 - * @param newRef the new reference to remember
95.778 - * @return the previous reference that was kept (null if newRef is the first one)
95.779 - * the applications is expected to link from newRef to this returned
95.780 - * value to form a linked list
95.781 - */
95.782 - public ReferenceToResult<?> registerReferenceToResult(ReferenceToResult<?> newRef);
95.783 -
95.784 - /** Given the provided template, Do cleanup the results.
95.785 - * @param templ template of a result(s) that should be checked
95.786 - * @return null if all references for this template were cleared or one of them
95.787 - */
95.788 - public ReferenceToResult<?> cleanUpResult(Lookup.Template<?> templ);
95.789 - }
95.790 -
95.791 - /** Extension to the default lookup item that offers additional information
95.792 - * for the data structures use in AbstractLookup
95.793 - */
95.794 - public static abstract class Pair<T> extends Lookup.Item<T> implements Serializable {
95.795 - private static final long serialVersionUID = 1L;
95.796 -
95.797 - /** possition of this item in the lookup, manipulated in addPair, removePair, setPairs methods */
95.798 - private int index = -1;
95.799 -
95.800 - /** For use by subclasses. */
95.801 - protected Pair() {
95.802 - }
95.803 -
95.804 - final int getIndex() {
95.805 - return index;
95.806 - }
95.807 -
95.808 - final void setIndex(AbstractLookup.Storage<?> tree, int x) {
95.809 - if (tree == null) {
95.810 - this.index = x;
95.811 -
95.812 - return;
95.813 - }
95.814 -
95.815 - if (this.index == -1) {
95.816 - this.index = x;
95.817 - } else {
95.818 - throw new IllegalStateException("You cannot use " + this + " in more than one AbstractLookup. Prev: " + this.index + " new: " + x); // NOI18N
95.819 - }
95.820 - }
95.821 -
95.822 - /** Tests whether this item can produce object
95.823 - * of class c.
95.824 - */
95.825 - protected abstract boolean instanceOf(Class<?> c);
95.826 -
95.827 - /** Method that can test whether an instance of a class has been created
95.828 - * by this item.
95.829 - *
95.830 - * @param obj the instance
95.831 - * @return if the item has already create an instance and it is the same
95.832 - * as obj.
95.833 - */
95.834 - protected abstract boolean creatorOf(Object obj);
95.835 - }
95.836 -
95.837 - /** Result based on one instance returned.
95.838 - */
95.839 - static final class R<T> extends WaitableResult<T> {
95.840 - /** reference our result is attached to (do not modify) */
95.841 - public ReferenceToResult<T> reference;
95.842 -
95.843 - /** listeners on the results or pointer to one listener */
95.844 - private Object listeners;
95.845 -
95.846 - public R() {
95.847 - }
95.848 -
95.849 - /** Checks whether we have simple behaviour of complex.
95.850 - */
95.851 - private boolean isSimple() {
95.852 - Storage s = (Storage) reference.lookup.tree;
95.853 -
95.854 - return DelegatingStorage.isSimple(s);
95.855 - }
95.856 -
95.857 - //
95.858 - // Handling cache management for both cases, no caches
95.859 - // for simple (but mark that we needed them, so refresh can
95.860 - // be done in cloneList) and complex when all 3 types
95.861 - // of result are cached
95.862 - //
95.863 - private Object getFromCache(int indx) {
95.864 - if (isSimple()) {
95.865 - return null;
95.866 - }
95.867 -
95.868 - Object maybeArray = reference.caches;
95.869 -
95.870 - if (maybeArray instanceof Object[]) {
95.871 - return ((Object[]) maybeArray)[indx];
95.872 - }
95.873 -
95.874 - return null;
95.875 - }
95.876 -
95.877 - @SuppressWarnings("unchecked")
95.878 - private Set<Class<? extends T>> getClassesCache() {
95.879 - return (Set<Class<? extends T>>) getFromCache(0);
95.880 - }
95.881 -
95.882 - private void setClassesCache(Set s) {
95.883 - if (isSimple()) {
95.884 - // mark it as being used
95.885 - reference.caches = reference;
95.886 -
95.887 - return;
95.888 - }
95.889 -
95.890 - if (!(reference.caches instanceof Object[])) {
95.891 - reference.caches = new Object[3];
95.892 - }
95.893 -
95.894 - ((Object[]) reference.caches)[0] = s;
95.895 - }
95.896 -
95.897 - @SuppressWarnings("unchecked")
95.898 - private Collection<T> getInstancesCache() {
95.899 - return (Collection<T>) getFromCache(1);
95.900 - }
95.901 -
95.902 - private void setInstancesCache(Collection c) {
95.903 - if (isSimple()) {
95.904 - // mark it as being used
95.905 - reference.caches = reference;
95.906 -
95.907 - return;
95.908 - }
95.909 -
95.910 - if (!(reference.caches instanceof Object[])) {
95.911 - reference.caches = new Object[3];
95.912 - }
95.913 -
95.914 - ((Object[]) reference.caches)[1] = c;
95.915 - }
95.916 -
95.917 - @SuppressWarnings("unchecked")
95.918 - private Pair<T>[] getItemsCache() {
95.919 - return (Pair<T>[]) getFromCache(2);
95.920 - }
95.921 -
95.922 - private void setItemsCache(Collection<?> c) {
95.923 - if (isSimple()) {
95.924 - // mark it as being used
95.925 - reference.caches = reference;
95.926 -
95.927 - return;
95.928 - }
95.929 -
95.930 - if (!(reference.caches instanceof Object[])) {
95.931 - reference.caches = new Object[3];
95.932 - }
95.933 -
95.934 - ((Object[]) reference.caches)[2] = c.toArray(new Pair[0]);
95.935 - }
95.936 -
95.937 - private void clearCaches() {
95.938 - if (reference.caches instanceof Object[]) {
95.939 - reference.caches = new Object[3];
95.940 - }
95.941 - }
95.942 -
95.943 - /** Ok, register listeners to all classes and super classes.
95.944 - */
95.945 - public synchronized void addLookupListener(LookupListener l) {
95.946 - listeners = modifyListenerList(true, l, listeners);
95.947 - }
95.948 -
95.949 - /** Ok, register listeners to all classes and super classes.
95.950 - */
95.951 - public synchronized void removeLookupListener(LookupListener l) {
95.952 - listeners = modifyListenerList(false, l, listeners);
95.953 - }
95.954 -
95.955 - /** Delete all cached values, the template changed.
95.956 - */
95.957 - protected void collectFires(Collection<Object> evAndListeners) {
95.958 - Object[] previousItems = getItemsCache();
95.959 - clearCaches();
95.960 -
95.961 - if (previousItems != null) {
95.962 - Object[] newArray = allItemsWithoutBeforeLookup().toArray();
95.963 -
95.964 - if (compareArrays(previousItems, newArray)) {
95.965 - // do not fire any change if nothing has been changed
95.966 - return;
95.967 - }
95.968 - }
95.969 -
95.970 - LookupListener[] arr;
95.971 -
95.972 - synchronized (this) {
95.973 - if (listeners == null) {
95.974 - return;
95.975 - }
95.976 -
95.977 - if (listeners instanceof LookupListener) {
95.978 - arr = new LookupListener[] { (LookupListener) listeners };
95.979 - } else {
95.980 - ArrayList<?> l = (ArrayList<?>) listeners;
95.981 - arr = l.toArray(new LookupListener[l.size()]);
95.982 - }
95.983 - }
95.984 -
95.985 - final LookupListener[] ll = arr;
95.986 - final LookupEvent ev = new LookupEvent(this);
95.987 - notifyListeners(ll, ev, evAndListeners);
95.988 - }
95.989 -
95.990 - public Collection<T> allInstances() {
95.991 - reference.lookup.beforeLookup(reference.template);
95.992 -
95.993 - Collection<T> s = getInstancesCache();
95.994 -
95.995 - if (s != null) {
95.996 - return s;
95.997 - }
95.998 -
95.999 - Collection<Pair<T>> items = allItemsWithoutBeforeLookup();
95.1000 - ArrayList<T> list = new ArrayList<T>(items.size());
95.1001 -
95.1002 - Iterator<Pair<T>> it = items.iterator();
95.1003 -
95.1004 - while (it.hasNext()) {
95.1005 - Pair<T> item = it.next();
95.1006 - T obj = item.getInstance();
95.1007 -
95.1008 - if (reference.template.getType().isInstance(obj)) {
95.1009 - list.add(obj);
95.1010 - }
95.1011 - }
95.1012 -
95.1013 - s = Collections.unmodifiableList(list);
95.1014 - setInstancesCache(s);
95.1015 -
95.1016 - return s;
95.1017 - }
95.1018 -
95.1019 - /** Set of all classes.
95.1020 - *
95.1021 - */
95.1022 - @Override
95.1023 - public Set<Class<? extends T>> allClasses() {
95.1024 - reference.lookup.beforeLookup(reference.template);
95.1025 -
95.1026 - Set<Class<? extends T>> s = getClassesCache();
95.1027 -
95.1028 - if (s != null) {
95.1029 - return s;
95.1030 - }
95.1031 -
95.1032 - s = new HashSet<Class<? extends T>>();
95.1033 -
95.1034 - for (Pair<T> item : allItemsWithoutBeforeLookup()) {
95.1035 - Class<? extends T> clazz = item.getType();
95.1036 -
95.1037 - if (clazz != null) {
95.1038 - s.add(clazz);
95.1039 - }
95.1040 - }
95.1041 -
95.1042 - s = Collections.unmodifiableSet(s);
95.1043 - setClassesCache(s);
95.1044 -
95.1045 - return s;
95.1046 - }
95.1047 -
95.1048 - /** Items are stored directly in the allItems.
95.1049 - */
95.1050 - @Override
95.1051 - public Collection<? extends Item<T>> allItems() {
95.1052 - reference.lookup.beforeLookup(reference.template);
95.1053 -
95.1054 - return allItemsWithoutBeforeLookup();
95.1055 - }
95.1056 -
95.1057 - /** Implements the search for allItems, but without asking for before lookup */
95.1058 - private Collection<Pair<T>> allItemsWithoutBeforeLookup() {
95.1059 - Pair<T>[] c = getItemsCache();
95.1060 -
95.1061 - if (c != null) {
95.1062 - return Collections.unmodifiableList(Arrays.asList(c));
95.1063 - }
95.1064 -
95.1065 - ArrayList<Pair<Object>> saferCheck = null;
95.1066 - AbstractLookup.Storage<?> t = reference.lookup.enterStorage();
95.1067 -
95.1068 - try {
95.1069 - try {
95.1070 - return Collections.unmodifiableCollection(initItems(t));
95.1071 - } catch (AbstractLookup.ISE ex) {
95.1072 - // do less effective evaluation of items outside of the
95.1073 - // locked storage
95.1074 - saferCheck = new ArrayList<Pair<Object>>();
95.1075 -
95.1076 - Enumeration<Pair<Object>> en = t.lookup(null); // get all Pairs
95.1077 -
95.1078 - while (en.hasMoreElements()) {
95.1079 - Pair<Object> i = en.nextElement();
95.1080 - saferCheck.add(i);
95.1081 - }
95.1082 - }
95.1083 - } finally {
95.1084 - reference.lookup.exitStorage();
95.1085 - }
95.1086 - return extractPairs(saferCheck);
95.1087 - }
95.1088 -
95.1089 - @SuppressWarnings("unchecked")
95.1090 - private Collection<Pair<T>> extractPairs(final ArrayList<Pair<Object>> saferCheck) {
95.1091 - TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
95.1092 - for (Pair<Object> i : saferCheck) {
95.1093 - if (matches(reference.template, i, false)) {
95.1094 - items.add((Pair<T>)i);
95.1095 - }
95.1096 - }
95.1097 - return Collections.unmodifiableCollection(items);
95.1098 - }
95.1099 -
95.1100 - /** Initializes items.
95.1101 - */
95.1102 - private Collection<Pair<T>> initItems(Storage<?> t) {
95.1103 - // manipulation with the tree must be synchronized
95.1104 - Enumeration<Pair<T>> en = t.lookup(reference.template.getType());
95.1105 -
95.1106 - // InheritanceTree is comparator for AbstractLookup.Pairs
95.1107 - TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
95.1108 -
95.1109 - while (en.hasMoreElements()) {
95.1110 - Pair<T> i = en.nextElement();
95.1111 -
95.1112 - if (matches(reference.template, i, false)) {
95.1113 - items.add(i);
95.1114 - }
95.1115 - }
95.1116 -
95.1117 - // create a correctly sorted copy using the tree as the comparator
95.1118 - setItemsCache(items);
95.1119 -
95.1120 - return items;
95.1121 - }
95.1122 -
95.1123 - /** Used by proxy results to synchronize before lookup.
95.1124 - */
95.1125 - protected void beforeLookup(Lookup.Template t) {
95.1126 - if (t.getType() == reference.template.getType()) {
95.1127 - reference.lookup.beforeLookup(t);
95.1128 - }
95.1129 - }
95.1130 -
95.1131 - /* Do not need to implement it, the default way is ok.
95.1132 - public boolean equals(java.lang.Object obj) {
95.1133 - return obj == this;
95.1134 - }
95.1135 - */
95.1136 - @Override
95.1137 - public String toString() {
95.1138 - return super.toString() + " for " + reference.template;
95.1139 - }
95.1140 - }
95.1141 - // end of R
95.1142 -
95.1143 - /** A class that can be used by the creator of the AbstractLookup to
95.1144 - * control its content. It can be passed to AbstractLookup constructor
95.1145 - * and used to add and remove pairs.
95.1146 - *
95.1147 - * @since 1.25
95.1148 - */
95.1149 - public static class Content extends Object implements Serializable {
95.1150 - private static final long serialVersionUID = 1L;
95.1151 -
95.1152 - // one of them is always null (except attach stage)
95.1153 -
95.1154 - /** abstract lookup we are connected to */
95.1155 - private AbstractLookup al;
95.1156 - private transient Object notifyIn;
95.1157 -
95.1158 - /** Default constructor.
95.1159 - */
95.1160 - public Content() {
95.1161 - this(null);
95.1162 - }
95.1163 -
95.1164 - /** Creates a content associated with an executor to handle dispatch
95.1165 - * of changes.
95.1166 - * @param notifyIn the executor to notify changes in
95.1167 - * @since 7.16
95.1168 - */
95.1169 - public Content(Executor notifyIn) {
95.1170 - this.notifyIn = notifyIn;
95.1171 - }
95.1172 -
95.1173 - /** for testing purposes */
95.1174 - final void attachExecutor(Executor notifyIn) {
95.1175 - this.notifyIn = notifyIn;
95.1176 - }
95.1177 -
95.1178 - /** A lookup attaches to this object.
95.1179 - */
95.1180 - final synchronized void attach(AbstractLookup al) {
95.1181 - if (this.al == null) {
95.1182 - this.al = al;
95.1183 -
95.1184 - ArrayList<Pair> ep = getEarlyPairs();
95.1185 - if (ep != null) {
95.1186 - notifyIn = null;
95.1187 - setPairs(ep);
95.1188 - }
95.1189 - } else {
95.1190 - throw new IllegalStateException(
95.1191 - "Trying to use content for " + al + " but it is already used for " + this.al
95.1192 - ); // NOI18N
95.1193 - }
95.1194 - }
95.1195 -
95.1196 - /** The method to add instance to the lookup with.
95.1197 - * @param pair class/instance pair
95.1198 - */
95.1199 - public final void addPair(Pair<?> pair) {
95.1200 - AbstractLookup a = al;
95.1201 - Executor e = getExecutor();
95.1202 -
95.1203 - if (a != null || e != null) {
95.1204 - a.addPair(pair, e);
95.1205 - } else {
95.1206 - if (notifyIn == null) {
95.1207 - notifyIn = new ArrayList<Pair>(3);
95.1208 - }
95.1209 -
95.1210 - getEarlyPairs().add(pair);
95.1211 - }
95.1212 - }
95.1213 -
95.1214 - /** Remove instance.
95.1215 - * @param pair class/instance pair
95.1216 - */
95.1217 - public final void removePair(Pair<?> pair) {
95.1218 - AbstractLookup a = al;
95.1219 - Executor e = getExecutor();
95.1220 -
95.1221 - if (a != null || e != null) {
95.1222 - a.removePair(pair, e);
95.1223 - } else {
95.1224 - if (notifyIn == null) {
95.1225 - notifyIn = new ArrayList<Pair>(3);
95.1226 - }
95.1227 -
95.1228 - getEarlyPairs().remove(pair);
95.1229 - }
95.1230 - }
95.1231 -
95.1232 - /** Changes all pairs in the lookup to new values.
95.1233 - * @param c the collection of (Pair) objects
95.1234 - */
95.1235 - public final void setPairs(Collection<? extends Pair> c) {
95.1236 - AbstractLookup a = al;
95.1237 - Executor e = getExecutor();
95.1238 -
95.1239 - if (a != null || e != null) {
95.1240 - a.setPairs(c, e);
95.1241 - } else {
95.1242 - notifyIn = new ArrayList<Pair>(c);
95.1243 - }
95.1244 - }
95.1245 -
95.1246 - @SuppressWarnings("unchecked")
95.1247 - private ArrayList<Pair> getEarlyPairs() {
95.1248 - Object o = notifyIn;
95.1249 - return o instanceof ArrayList ? (ArrayList<Pair>)o : null;
95.1250 - }
95.1251 -
95.1252 - private Executor getExecutor() {
95.1253 - Object o = notifyIn;
95.1254 - return o instanceof Executor ? (Executor)o : null;
95.1255 - }
95.1256 - }
95.1257 - // end of Content
95.1258 -
95.1259 - /** Just a holder for index & modified values.
95.1260 - */
95.1261 - final static class Info extends Object {
95.1262 - public int index;
95.1263 - public Object transaction;
95.1264 -
95.1265 - public Info(int i, Object t) {
95.1266 - index = i;
95.1267 - transaction = t;
95.1268 - }
95.1269 - }
95.1270 -
95.1271 - /** Reference to a result R
95.1272 - */
95.1273 - static final class ReferenceToResult<T> extends WeakReference<R<T>> implements Runnable {
95.1274 - /** next refernece in chain, modified only from AbstractLookup or this */
95.1275 - private ReferenceToResult<?> next;
95.1276 -
95.1277 - /** the template for the result */
95.1278 - public final Template<T> template;
95.1279 -
95.1280 - /** the lookup we are attached to */
95.1281 - public final AbstractLookup lookup;
95.1282 -
95.1283 - /** caches for results */
95.1284 - public Object caches;
95.1285 -
95.1286 - /** Creates a weak refernece to a new result R in context of lookup
95.1287 - * for given template
95.1288 - */
95.1289 - private ReferenceToResult(R<T> result, AbstractLookup lookup, Template<T> template) {
95.1290 - super(result, activeQueue());
95.1291 - this.template = template;
95.1292 - this.lookup = lookup;
95.1293 - getResult().reference = this;
95.1294 - }
95.1295 -
95.1296 - /** Returns the result or null
95.1297 - */
95.1298 - R<T> getResult() {
95.1299 - return get();
95.1300 - }
95.1301 -
95.1302 - /** Cleans the reference. Implements Runnable interface, do not call
95.1303 - * directly.
95.1304 - */
95.1305 - public void run() {
95.1306 - lookup.cleanUpResult(this.template);
95.1307 - }
95.1308 -
95.1309 - /** Clones the reference list to given Storage.
95.1310 - * @param storage storage to clone to
95.1311 - */
95.1312 - public void cloneList(AbstractLookup.Storage<?> storage) {
95.1313 - ReferenceIterator it = new ReferenceIterator(this);
95.1314 -
95.1315 - while (it.next()) {
95.1316 - ReferenceToResult<?> current = it.current();
95.1317 - ReferenceToResult<?> newRef = current.cloneRef();
95.1318 - newRef.next = storage.registerReferenceToResult(newRef);
95.1319 - newRef.caches = current.caches;
95.1320 -
95.1321 - if (current.caches == current) {
95.1322 - current.getResult().initItems(storage);
95.1323 - }
95.1324 - }
95.1325 - }
95.1326 -
95.1327 - private ReferenceToResult<T> cloneRef() {
95.1328 - return new ReferenceToResult<T>(getResult(), lookup, template);
95.1329 - }
95.1330 - }
95.1331 - // end of ReferenceToResult
95.1332 -
95.1333 - /** Supporting class to iterate over linked list of ReferenceToResult
95.1334 - * Use:
95.1335 - * <PRE>
95.1336 - * ReferenceIterator it = new ReferenceIterator (this.ref);
95.1337 - * while (it.next ()) {
95.1338 - * it.current (): // do some work
95.1339 - * }
95.1340 - * this.ref = it.first (); // remember the first one
95.1341 - */
95.1342 - static final class ReferenceIterator extends Object {
95.1343 - private ReferenceToResult<?> first;
95.1344 - private ReferenceToResult<?> current;
95.1345 -
95.1346 - /** hard reference to current result, so it is not GCed meanwhile */
95.1347 - private R<?> currentResult;
95.1348 -
95.1349 - /** Initializes the iterator with first reference.
95.1350 - */
95.1351 - public ReferenceIterator(ReferenceToResult<?> first) {
95.1352 - this.first = first;
95.1353 - }
95.1354 -
95.1355 - /** Moves the current to next possition */
95.1356 - public boolean next() {
95.1357 - ReferenceToResult<?> prev;
95.1358 - ReferenceToResult<?> ref;
95.1359 -
95.1360 - if (current == null) {
95.1361 - ref = first;
95.1362 - prev = null;
95.1363 - } else {
95.1364 - prev = current;
95.1365 - ref = current.next;
95.1366 - }
95.1367 -
95.1368 - while (ref != null) {
95.1369 - R<?> result = ref.get();
95.1370 -
95.1371 - if (result == null) {
95.1372 - if (prev == null) {
95.1373 - // move the head
95.1374 - first = ref.next;
95.1375 - } else {
95.1376 - // skip over this reference
95.1377 - prev.next = ref.next;
95.1378 - }
95.1379 -
95.1380 - prev = ref;
95.1381 - ref = ref.next;
95.1382 - } else {
95.1383 - // we have found next item
95.1384 - currentResult = result;
95.1385 - current = ref;
95.1386 -
95.1387 - return true;
95.1388 - }
95.1389 - }
95.1390 -
95.1391 - currentResult = null;
95.1392 - current = null;
95.1393 -
95.1394 - return false;
95.1395 - }
95.1396 -
95.1397 - /** Access to current reference.
95.1398 - */
95.1399 - public ReferenceToResult<?> current() {
95.1400 - return current;
95.1401 - }
95.1402 -
95.1403 - /** Access to reference that is supposed to be the first one.
95.1404 - */
95.1405 - public ReferenceToResult<?> first() {
95.1406 - return first;
95.1407 - }
95.1408 - }
95.1409 -
95.1410 - /** Signals that a lookup is being modified from a lookup query.
95.1411 - *
95.1412 - * @author Jaroslav Tulach
95.1413 - */
95.1414 - static final class ISE extends IllegalStateException {
95.1415 - static final long serialVersionUID = 100L;
95.1416 -
95.1417 - /** list of jobs to execute. */
95.1418 - private java.util.List<Job> jobs;
95.1419 -
95.1420 - /** @param msg message
95.1421 - */
95.1422 - public ISE(String msg) {
95.1423 - super(msg);
95.1424 - }
95.1425 -
95.1426 - /** Registers a job to be executed partially out and partially in
95.1427 - * the lock over storage.
95.1428 - */
95.1429 - public void registerJob(Job job) {
95.1430 - if (jobs == null) {
95.1431 - jobs = new java.util.ArrayList<Job>();
95.1432 - }
95.1433 -
95.1434 - jobs.add(job);
95.1435 - }
95.1436 -
95.1437 - /** Executes the jobs outside, and then inside a locked session.
95.1438 - */
95.1439 - public void recover(AbstractLookup lookup) {
95.1440 - if (jobs == null) {
95.1441 - // no recovery plan, throw itself
95.1442 - throw this;
95.1443 - }
95.1444 -
95.1445 - for (Job j : jobs) {
95.1446 - j.before();
95.1447 - }
95.1448 -
95.1449 - AbstractLookup.Storage s = lookup.enterStorage();
95.1450 -
95.1451 - try {
95.1452 - for (Job j : jobs) {
95.1453 - j.inside();
95.1454 - }
95.1455 - } finally {
95.1456 - lookup.exitStorage();
95.1457 - }
95.1458 - }
95.1459 -
95.1460 - /** A job to be executed partially outside and partially inside
95.1461 - * the storage lock.
95.1462 - */
95.1463 - static interface Job {
95.1464 - public void before();
95.1465 -
95.1466 - public void inside();
95.1467 - }
95.1468 - }
95.1469 - // end of ISE
95.1470 -}
96.1 --- a/openide.util/src/org/openide/util/lookup/ArrayStorage.java Thu Dec 10 19:23:25 2009 -0500
96.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
96.3 @@ -1,477 +0,0 @@
96.4 -/*
96.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
96.6 - *
96.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
96.8 - *
96.9 - * The contents of this file are subject to the terms of either the GNU
96.10 - * General Public License Version 2 only ("GPL") or the Common
96.11 - * Development and Distribution License("CDDL") (collectively, the
96.12 - * "License"). You may not use this file except in compliance with the
96.13 - * License. You can obtain a copy of the License at
96.14 - * http://www.netbeans.org/cddl-gplv2.html
96.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
96.16 - * specific language governing permissions and limitations under the
96.17 - * License. When distributing the software, include this License Header
96.18 - * Notice in each file and include the License file at
96.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
96.20 - * particular file as subject to the "Classpath" exception as provided
96.21 - * by Sun in the GPL Version 2 section of the License file that
96.22 - * accompanied this code. If applicable, add the following below the
96.23 - * License Header, with the fields enclosed by brackets [] replaced by
96.24 - * your own identifying information:
96.25 - * "Portions Copyrighted [year] [name of copyright owner]"
96.26 - *
96.27 - * Contributor(s):
96.28 - *
96.29 - * The Original Software is NetBeans. The Initial Developer of the Original
96.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
96.31 - * Microsystems, Inc. All Rights Reserved.
96.32 - *
96.33 - * If you wish your version of this file to be governed by only the CDDL
96.34 - * or only the GPL Version 2, indicate your decision by adding
96.35 - * "[Contributor] elects to include this software in this distribution
96.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
96.37 - * single choice of license, a recipient has the option to distribute
96.38 - * your version of this file under either the CDDL, the GPL Version 2 or
96.39 - * to extend the choice of license to its licensees as provided above.
96.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
96.41 - * Version 2 license, then the option applies only if the new code is
96.42 - * made subject to such option by the copyright holder.
96.43 - */
96.44 -package org.openide.util.lookup;
96.45 -
96.46 -import org.openide.util.Lookup;
96.47 -
96.48 -
96.49 -
96.50 -import java.util.*;
96.51 -import org.openide.util.lookup.AbstractLookup.Pair;
96.52 -
96.53 -
96.54 -/** ArrayStorage of Pairs from AbstractLookup.
96.55 - * @author Jaroslav Tulach
96.56 - */
96.57 -final class ArrayStorage extends Object
96.58 -implements AbstractLookup.Storage<ArrayStorage.Transaction> {
96.59 - /** default trashold */
96.60 - static final Integer DEFAULT_TRASH = new Integer(11);
96.61 -
96.62 - /** list of items */
96.63 - private Object content;
96.64 -
96.65 - /** linked list of refernces to results */
96.66 - private transient AbstractLookup.ReferenceToResult<?> results;
96.67 -
96.68 - /** Constructor
96.69 - */
96.70 - public ArrayStorage() {
96.71 - this(DEFAULT_TRASH);
96.72 - }
96.73 -
96.74 - /** Constructs new ArrayStorage */
96.75 - public ArrayStorage(Integer treshhold) {
96.76 - this.content = treshhold;
96.77 - }
96.78 -
96.79 - /** Adds an item into the tree.
96.80 - * @param item to add
96.81 - * @return true if the Item has been added for the first time or false if some other
96.82 - * item equal to this one already existed in the lookup
96.83 - */
96.84 - public boolean add(AbstractLookup.Pair<?> item, Transaction changed) {
96.85 - Object[] arr = changed.current;
96.86 -
96.87 - if (changed.arr == null) {
96.88 - // just simple add of one item
96.89 - for (int i = 0; i < arr.length; i++) {
96.90 - if (arr[i] == null) {
96.91 - arr[i] = item;
96.92 - changed.add(item);
96.93 -
96.94 - return true;
96.95 - }
96.96 -
96.97 - if (arr[i].equals(item)) {
96.98 - // reassign the item number
96.99 - item.setIndex(null, ((AbstractLookup.Pair) arr[i]).getIndex());
96.100 -
96.101 - // already there, but update it
96.102 - arr[i] = item;
96.103 -
96.104 - return false;
96.105 - }
96.106 - }
96.107 -
96.108 - // cannot happen as the beginTransaction ensured we can finish
96.109 - // correctly
96.110 - throw new IllegalStateException();
96.111 - } else {
96.112 - // doing remainAll after that, let Transaction hold the new array
96.113 - int newIndex = changed.addPair(item);
96.114 -
96.115 - for (int i = 0; i < arr.length; i++) {
96.116 - if (arr[i] == null) {
96.117 - changed.add(item);
96.118 -
96.119 - return true;
96.120 - }
96.121 -
96.122 - if (arr[i].equals(item)) {
96.123 - // already there
96.124 - if (i != newIndex) {
96.125 - // change in index
96.126 - changed.add(item);
96.127 -
96.128 - return false;
96.129 - } else {
96.130 - // no change
96.131 - return false;
96.132 - }
96.133 - }
96.134 - }
96.135 -
96.136 - // if not found in the original array
96.137 - changed.add(item);
96.138 -
96.139 - return true;
96.140 - }
96.141 - }
96.142 -
96.143 - /** Removes an item.
96.144 - */
96.145 - public void remove(AbstractLookup.Pair item, Transaction changed) {
96.146 - Object[] arr = changed.current;
96.147 - if (arr == null) {
96.148 - return;
96.149 - }
96.150 -
96.151 - int found = -1;
96.152 -
96.153 - for (int i = 0; i < arr.length;) {
96.154 - if (arr[i] == null) {
96.155 - // end of task
96.156 - return;
96.157 - }
96.158 -
96.159 - if ((found == -1) && arr[i].equals(item)) {
96.160 - // already there
96.161 - Pair<?> p = (Pair<?>)arr[i];
96.162 - p.setIndex(null, -1);
96.163 - changed.add(p);
96.164 - found = i;
96.165 - }
96.166 -
96.167 - i++;
96.168 -
96.169 - if (found != -1) {
96.170 - if (i < arr.length && !(arr[i] instanceof Integer)) {
96.171 - // moving the array
96.172 - arr[i - 1] = arr[i];
96.173 - } else {
96.174 - arr[i - 1] = null;
96.175 - }
96.176 - }
96.177 - }
96.178 - }
96.179 -
96.180 - /** Removes all items that are not present in the provided collection.
96.181 - * @param retain Pair -> AbstractLookup.Info map
96.182 - * @param notify set of Classes that has possibly changed
96.183 - */
96.184 - public void retainAll(Map retain, Transaction changed) {
96.185 - Object[] arr = changed.current;
96.186 -
96.187 - for (int from = 0; from < arr.length; from++) {
96.188 - if (!(arr[from] instanceof AbstractLookup.Pair)) {
96.189 - // end of content
96.190 - break;
96.191 - }
96.192 -
96.193 - AbstractLookup.Pair p = (AbstractLookup.Pair) arr[from];
96.194 -
96.195 - AbstractLookup.Info info = (AbstractLookup.Info) retain.get(p);
96.196 -
96.197 - if (info == null) {
96.198 - // was removed
96.199 -
96.200 - /*
96.201 - if (info != null) {
96.202 - if (info.index < arr.length) {
96.203 - newArr[info.index] = p;
96.204 - }
96.205 -
96.206 - if (p.getIndex() != info.index) {
96.207 - p.setIndex (null, info.index);
96.208 - changed.add (p);
96.209 - }
96.210 - } else {
96.211 - // removed
96.212 - */
96.213 - changed.add(p);
96.214 - }
96.215 - }
96.216 - }
96.217 -
96.218 - /** Queries for instances of given class.
96.219 - * @param clazz the class to check
96.220 - * @return enumeration of Item
96.221 - * @see #unsorted
96.222 - */
96.223 - public <T> Enumeration<Pair<T>> lookup(final Class<T> clazz) {
96.224 - if (content instanceof Object[]) {
96.225 - final Enumeration<Object> all = InheritanceTree.arrayEn((Object[]) content);
96.226 - class JustPairs implements Enumeration<Pair<T>> {
96.227 - private Pair<T> next;
96.228 -
96.229 - @SuppressWarnings("unchecked")
96.230 - private Pair<T> findNext() {
96.231 - for (;;) {
96.232 - if (next != null) {
96.233 - return next;
96.234 - }
96.235 - if (!all.hasMoreElements()) {
96.236 - return null;
96.237 - }
96.238 - Object o = all.nextElement();
96.239 - boolean ok;
96.240 - if (o instanceof AbstractLookup.Pair) {
96.241 - ok = (clazz == null) || ((AbstractLookup.Pair<?>) o).instanceOf(clazz);
96.242 - } else {
96.243 - ok = false;
96.244 - }
96.245 -
96.246 - next = ok ? (Pair<T>) o : null;
96.247 - }
96.248 - }
96.249 -
96.250 - public boolean hasMoreElements() {
96.251 - return findNext() != null;
96.252 - }
96.253 -
96.254 - public Pair<T> nextElement() {
96.255 - Pair<T> r = findNext();
96.256 - if (r == null) {
96.257 - throw new NoSuchElementException();
96.258 - }
96.259 - next = null;
96.260 - return r;
96.261 - }
96.262 - } // end of JustPairs
96.263 - return new JustPairs();
96.264 - } else {
96.265 - return InheritanceTree.emptyEn();
96.266 - }
96.267 - }
96.268 -
96.269 - /** Associates another result with this storage.
96.270 - */
96.271 - public AbstractLookup.ReferenceToResult registerReferenceToResult(AbstractLookup.ReferenceToResult<?> newRef) {
96.272 - AbstractLookup.ReferenceToResult prev = this.results;
96.273 - this.results = newRef;
96.274 -
96.275 - return prev;
96.276 - }
96.277 -
96.278 - /** Cleanup the references
96.279 - */
96.280 - public AbstractLookup.ReferenceToResult cleanUpResult(Lookup.Template<?> templ) {
96.281 - AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
96.282 -
96.283 - while (it.next()) {
96.284 - // empty
96.285 - }
96.286 -
96.287 - return this.results = it.first();
96.288 - }
96.289 -
96.290 - /** We use a hash set of all modified Pair to handle the transaction */
96.291 - public Transaction beginTransaction(int ensure) {
96.292 - return new Transaction(ensure, content);
96.293 - }
96.294 -
96.295 - /** Extract all results.
96.296 - */
96.297 - public void endTransaction(Transaction changed, Set<AbstractLookup.R> modified) {
96.298 - AbstractLookup.ReferenceIterator it = new AbstractLookup.ReferenceIterator(this.results);
96.299 -
96.300 - if (changed.arr == null) {
96.301 - // either add or remove, only check the content of check HashSet
96.302 - while (it.next()) {
96.303 - AbstractLookup.ReferenceToResult ref = it.current();
96.304 - Iterator<Pair<?>> pairs = changed.iterator();
96.305 -
96.306 - while (pairs.hasNext()) {
96.307 - AbstractLookup.Pair p = (AbstractLookup.Pair) pairs.next();
96.308 -
96.309 - if (AbstractLookup.matches(ref.template, p, true)) {
96.310 - modified.add(ref.getResult());
96.311 - }
96.312 - }
96.313 - }
96.314 - } else {
96.315 - // do full check of changes
96.316 - while (it.next()) {
96.317 - AbstractLookup.ReferenceToResult ref = it.current();
96.318 -
96.319 - int oldIndex = -1;
96.320 - int newIndex = -1;
96.321 -
96.322 - for (;;) {
96.323 - oldIndex = findMatching(ref.template, changed.current, oldIndex);
96.324 - newIndex = findMatching(ref.template, changed.arr, newIndex);
96.325 -
96.326 - if ((oldIndex == -1) && (newIndex == -1)) {
96.327 - break;
96.328 - }
96.329 -
96.330 - if (
96.331 - (oldIndex == -1) || (newIndex == -1) ||
96.332 - !changed.current[oldIndex].equals(changed.arr[newIndex])
96.333 - ) {
96.334 - modified.add(ref.getResult());
96.335 -
96.336 - break;
96.337 - }
96.338 - }
96.339 - }
96.340 - }
96.341 -
96.342 - this.results = it.first();
96.343 - this.content = changed.newContent(this.content);
96.344 - }
96.345 -
96.346 - private static int findMatching(Lookup.Template t, Object[] arr, int from) {
96.347 - while (++from < arr.length) {
96.348 - if (arr[from] instanceof AbstractLookup.Pair) {
96.349 - if (AbstractLookup.matches(t, (AbstractLookup.Pair) arr[from], true)) {
96.350 - return from;
96.351 - }
96.352 - }
96.353 - }
96.354 -
96.355 - return -1;
96.356 - }
96.357 -
96.358 - /** HashSet with additional field for new array which is callocated
96.359 - * in case we are doing replace to hold all new items.
96.360 - */
96.361 - static final class Transaction extends HashSet<Pair<?>> {
96.362 - /** array with current objects */
96.363 - public final Object[] current;
96.364 -
96.365 - /** array with new objects */
96.366 - public final Object[] arr;
96.367 -
96.368 - /** number of objects in the array */
96.369 - private int cnt;
96.370 -
96.371 - public Transaction(int ensure, Object currentContent) {
96.372 - Integer trashold;
96.373 - Object[] _arr;
96.374 -
96.375 - if (currentContent instanceof Integer) {
96.376 - trashold = (Integer) currentContent;
96.377 - _arr = null;
96.378 - } else {
96.379 - _arr = (Object[]) currentContent;
96.380 -
96.381 - if (_arr[_arr.length - 1] instanceof Integer) {
96.382 - trashold = (Integer) _arr[_arr.length - 1];
96.383 - } else {
96.384 - // nowhere to grow we have reached the limit
96.385 - trashold = null;
96.386 - }
96.387 - }
96.388 -
96.389 - int maxSize = (trashold == null) ? _arr.length : trashold.intValue();
96.390 -
96.391 - if (ensure > maxSize) {
96.392 - throw new UnsupportedOperationException();
96.393 - }
96.394 -
96.395 - if (ensure == -1) {
96.396 - // remove => it is ok
96.397 - this.current = currentContent instanceof Integer ? null : (Object[]) currentContent;
96.398 - this.arr = null;
96.399 -
96.400 - return;
96.401 - }
96.402 -
96.403 - if (ensure == -2) {
96.404 - // adding one
96.405 - if (_arr == null) {
96.406 - // first time add, let's allocate the array
96.407 - _arr = new Object[2];
96.408 - _arr[1] = trashold;
96.409 - } else {
96.410 - if (_arr[_arr.length - 1] instanceof AbstractLookup.Pair) {
96.411 - // we are full
96.412 - throw new UnsupportedOperationException();
96.413 - } else {
96.414 - // ensure we have allocated enough space
96.415 - if (_arr.length < 2 || _arr[_arr.length - 2] != null) {
96.416 - // double the array
96.417 - int newSize = (_arr.length - 1) * 2;
96.418 -
96.419 - if (newSize <= 1) {
96.420 - newSize = 2;
96.421 - }
96.422 -
96.423 - if (newSize > maxSize) {
96.424 - newSize = maxSize;
96.425 -
96.426 - if (newSize <= _arr.length) {
96.427 - // no space to get in
96.428 - throw new UnsupportedOperationException();
96.429 - }
96.430 -
96.431 - _arr = new Object[newSize];
96.432 - } else {
96.433 - // still a lot of space
96.434 - _arr = new Object[newSize + 1];
96.435 - _arr[newSize] = trashold;
96.436 - }
96.437 -
96.438 - // copy content of original array without the last Integer into
96.439 - // the new one
96.440 - System.arraycopy(currentContent, 0, _arr, 0, ((Object[]) currentContent).length - 1);
96.441 - }
96.442 - }
96.443 - }
96.444 -
96.445 - this.current = _arr;
96.446 - this.arr = null;
96.447 - } else {
96.448 - // allocate array for complete replacement
96.449 - if (ensure == maxSize) {
96.450 - this.arr = new Object[ensure];
96.451 - } else {
96.452 - this.arr = new Object[ensure + 1];
96.453 - this.arr[ensure] = trashold;
96.454 - }
96.455 -
96.456 - this.current = (currentContent instanceof Object[]) ? (Object[]) currentContent : new Object[0];
96.457 - }
96.458 - }
96.459 -
96.460 - public int addPair(AbstractLookup.Pair<?> p) {
96.461 - p.setIndex(null, cnt);
96.462 - arr[cnt++] = p;
96.463 -
96.464 - return p.getIndex();
96.465 - }
96.466 -
96.467 - public Object newContent(Object prev) {
96.468 - if (arr == null) {
96.469 - if (current == null) {
96.470 - return prev;
96.471 - } else {
96.472 - return current;
96.473 - }
96.474 - } else {
96.475 - return arr;
96.476 - }
96.477 - }
96.478 - }
96.479 - // end of Transaction
96.480 -}
97.1 --- a/openide.util/src/org/openide/util/lookup/DelegatingStorage.java Thu Dec 10 19:23:25 2009 -0500
97.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
97.3 @@ -1,180 +0,0 @@
97.4 -/*
97.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
97.6 - *
97.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
97.8 - *
97.9 - * The contents of this file are subject to the terms of either the GNU
97.10 - * General Public License Version 2 only ("GPL") or the Common
97.11 - * Development and Distribution License("CDDL") (collectively, the
97.12 - * "License"). You may not use this file except in compliance with the
97.13 - * License. You can obtain a copy of the License at
97.14 - * http://www.netbeans.org/cddl-gplv2.html
97.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
97.16 - * specific language governing permissions and limitations under the
97.17 - * License. When distributing the software, include this License Header
97.18 - * Notice in each file and include the License file at
97.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
97.20 - * particular file as subject to the "Classpath" exception as provided
97.21 - * by Sun in the GPL Version 2 section of the License file that
97.22 - * accompanied this code. If applicable, add the following below the
97.23 - * License Header, with the fields enclosed by brackets [] replaced by
97.24 - * your own identifying information:
97.25 - * "Portions Copyrighted [year] [name of copyright owner]"
97.26 - *
97.27 - * Contributor(s):
97.28 - *
97.29 - * The Original Software is NetBeans. The Initial Developer of the Original
97.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
97.31 - * Microsystems, Inc. All Rights Reserved.
97.32 - *
97.33 - * If you wish your version of this file to be governed by only the CDDL
97.34 - * or only the GPL Version 2, indicate your decision by adding
97.35 - * "[Contributor] elects to include this software in this distribution
97.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
97.37 - * single choice of license, a recipient has the option to distribute
97.38 - * your version of this file under either the CDDL, the GPL Version 2 or
97.39 - * to extend the choice of license to its licensees as provided above.
97.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
97.41 - * Version 2 license, then the option applies only if the new code is
97.42 - * made subject to such option by the copyright holder.
97.43 - */
97.44 -package org.openide.util.lookup;
97.45 -
97.46 -import org.openide.util.Lookup;
97.47 -
97.48 -import java.io.*;
97.49 -
97.50 -import java.lang.ref.WeakReference;
97.51 -
97.52 -import java.util.*;
97.53 -import org.openide.util.lookup.AbstractLookup.Pair;
97.54 -
97.55 -
97.56 -/** Storages that can switch between another storages.
97.57 - * @author Jaroslav Tulach
97.58 - */
97.59 -final class DelegatingStorage<Transaction> extends Object
97.60 -implements Serializable, AbstractLookup.Storage<Transaction> {
97.61 - /** object to delegate to */
97.62 - private AbstractLookup.Storage<Transaction> delegate;
97.63 -
97.64 - /** thread just accessing the storage */
97.65 - private Thread owner;
97.66 -
97.67 - public DelegatingStorage(AbstractLookup.Storage<Transaction> d) {
97.68 - this.delegate = d;
97.69 - this.owner = Thread.currentThread();
97.70 - }
97.71 -
97.72 - /** Never serialize yourself, always put there the delegate */
97.73 - public Object writeReplace() {
97.74 - return this.delegate;
97.75 - }
97.76 -
97.77 - /** Method to check whether there is not multiple access from the same thread.
97.78 - */
97.79 - public void checkForTreeModification() {
97.80 - if (Thread.currentThread() == owner) {
97.81 - throw new AbstractLookup.ISE("You are trying to modify lookup from lookup query!"); // NOI18N
97.82 - }
97.83 - }
97.84 -
97.85 - /** Checks whether we have simple behaviour or complex.
97.86 - */
97.87 - public static boolean isSimple(AbstractLookup.Storage s) {
97.88 - if (s instanceof DelegatingStorage) {
97.89 - return ((DelegatingStorage) s).delegate instanceof ArrayStorage;
97.90 - } else {
97.91 - return s instanceof ArrayStorage;
97.92 - }
97.93 - }
97.94 -
97.95 - /** Exits from the owners ship of the storage.
97.96 - */
97.97 - public AbstractLookup.Storage<Transaction> exitDelegate() {
97.98 - if (Thread.currentThread() != owner) {
97.99 - throw new IllegalStateException("Onwer: " + owner + " caller: " + Thread.currentThread()); // NOI18N
97.100 - }
97.101 -
97.102 - AbstractLookup.Storage<Transaction> d = delegate;
97.103 - delegate = null;
97.104 -
97.105 - return d;
97.106 - }
97.107 -
97.108 - public boolean add(AbstractLookup.Pair<?> item, Transaction transaction) {
97.109 - return delegate.add(item, transaction);
97.110 - }
97.111 -
97.112 - public void remove(org.openide.util.lookup.AbstractLookup.Pair item, Transaction transaction) {
97.113 - delegate.remove(item, transaction);
97.114 - }
97.115 -
97.116 - public void retainAll(Map retain, Transaction transaction) {
97.117 - delegate.retainAll(retain, transaction);
97.118 - }
97.119 -
97.120 - /** A special method to change the backing storage.
97.121 - * In fact it is not much typesafe as it changes the
97.122 - * type of Transaction but we know that nobody is currently
97.123 - * holding a transaction object, so there cannot be inconsitencies.
97.124 - */
97.125 - @SuppressWarnings("unchecked")
97.126 - private void changeDelegate(InheritanceTree st) {
97.127 - delegate = (AbstractLookup.Storage<Transaction>)st;
97.128 - }
97.129 -
97.130 - public Transaction beginTransaction(int ensure) {
97.131 - try {
97.132 - return delegate.beginTransaction(ensure);
97.133 - } catch (UnsupportedOperationException ex) {
97.134 - // let's convert to InheritanceTree
97.135 - ArrayStorage arr = (ArrayStorage) delegate;
97.136 - InheritanceTree inh = new InheritanceTree();
97.137 - changeDelegate(inh);
97.138 -
97.139 - //
97.140 - // Copy content
97.141 - //
97.142 - Enumeration<Pair<Object>> en = arr.lookup(Object.class);
97.143 -
97.144 - while (en.hasMoreElements()) {
97.145 - if (!inh.add(en.nextElement(), new ArrayList<Class>())) {
97.146 - throw new IllegalStateException("All objects have to be accepted"); // NOI18N
97.147 - }
97.148 - }
97.149 -
97.150 - //
97.151 - // Copy listeners
97.152 - //
97.153 - AbstractLookup.ReferenceToResult<?> ref = arr.cleanUpResult(null);
97.154 -
97.155 - if (ref != null) {
97.156 - ref.cloneList(inh);
97.157 - }
97.158 -
97.159 - // we have added the current content and now we can start transaction
97.160 - return delegate.beginTransaction(ensure);
97.161 - }
97.162 - }
97.163 -
97.164 - public org.openide.util.lookup.AbstractLookup.ReferenceToResult cleanUpResult(
97.165 - org.openide.util.Lookup.Template templ
97.166 - ) {
97.167 - return delegate.cleanUpResult(templ);
97.168 - }
97.169 -
97.170 - public void endTransaction(Transaction transaction, Set<AbstractLookup.R> modified) {
97.171 - delegate.endTransaction(transaction, modified);
97.172 - }
97.173 -
97.174 - public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
97.175 - return delegate.lookup(clazz);
97.176 - }
97.177 -
97.178 - public org.openide.util.lookup.AbstractLookup.ReferenceToResult registerReferenceToResult(
97.179 - org.openide.util.lookup.AbstractLookup.ReferenceToResult newRef
97.180 - ) {
97.181 - return delegate.registerReferenceToResult(newRef);
97.182 - }
97.183 -}
98.1 --- a/openide.util/src/org/openide/util/lookup/ExcludingLookup.java Thu Dec 10 19:23:25 2009 -0500
98.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
98.3 @@ -1,428 +0,0 @@
98.4 -/*
98.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
98.6 - *
98.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
98.8 - *
98.9 - * The contents of this file are subject to the terms of either the GNU
98.10 - * General Public License Version 2 only ("GPL") or the Common
98.11 - * Development and Distribution License("CDDL") (collectively, the
98.12 - * "License"). You may not use this file except in compliance with the
98.13 - * License. You can obtain a copy of the License at
98.14 - * http://www.netbeans.org/cddl-gplv2.html
98.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
98.16 - * specific language governing permissions and limitations under the
98.17 - * License. When distributing the software, include this License Header
98.18 - * Notice in each file and include the License file at
98.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
98.20 - * particular file as subject to the "Classpath" exception as provided
98.21 - * by Sun in the GPL Version 2 section of the License file that
98.22 - * accompanied this code. If applicable, add the following below the
98.23 - * License Header, with the fields enclosed by brackets [] replaced by
98.24 - * your own identifying information:
98.25 - * "Portions Copyrighted [year] [name of copyright owner]"
98.26 - *
98.27 - * Contributor(s):
98.28 - *
98.29 - * The Original Software is NetBeans. The Initial Developer of the Original
98.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
98.31 - * Microsystems, Inc. All Rights Reserved.
98.32 - *
98.33 - * If you wish your version of this file to be governed by only the CDDL
98.34 - * or only the GPL Version 2, indicate your decision by adding
98.35 - * "[Contributor] elects to include this software in this distribution
98.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
98.37 - * single choice of license, a recipient has the option to distribute
98.38 - * your version of this file under either the CDDL, the GPL Version 2 or
98.39 - * to extend the choice of license to its licensees as provided above.
98.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
98.41 - * Version 2 license, then the option applies only if the new code is
98.42 - * made subject to such option by the copyright holder.
98.43 - */
98.44 -package org.openide.util.lookup;
98.45 -
98.46 -import java.lang.ref.Reference;
98.47 -import java.lang.ref.WeakReference;
98.48 -import org.openide.util.Lookup;
98.49 -import org.openide.util.LookupListener;
98.50 -
98.51 -import java.util.*;
98.52 -import org.openide.util.LookupEvent;
98.53 -
98.54 -
98.55 -/** Allows exclusion of certain instances from lookup.
98.56 - *
98.57 - * @author Jaroslav Tulach
98.58 - */
98.59 -final class ExcludingLookup extends org.openide.util.Lookup {
98.60 - /** the other lookup that we delegate to */
98.61 - private Lookup delegate;
98.62 -
98.63 - /** classes to exclude (Class[]) or just one class (Class) */
98.64 - private Object classes;
98.65 -
98.66 - /**
98.67 - * Creates new Result object with supplied instances parameter.
98.68 - * @param instances to be used to return from the lookup
98.69 - */
98.70 - ExcludingLookup(Lookup delegate, Class[] classes) {
98.71 - this.delegate = delegate;
98.72 -
98.73 - for (Class c : classes) {
98.74 - if (c == null) {
98.75 - throw new NullPointerException();
98.76 - }
98.77 - }
98.78 - if (classes.length == 1) {
98.79 - this.classes = classes[0];
98.80 - } else {
98.81 - this.classes = classes;
98.82 - }
98.83 - }
98.84 -
98.85 - @Override
98.86 - public String toString() {
98.87 - return "ExcludingLookup: " + delegate + " excludes: " + Arrays.asList(classes()); // NOI18N
98.88 - }
98.89 -
98.90 - public <T> Result<T> lookup(Template<T> template) {
98.91 - if (template == null) {
98.92 - throw new NullPointerException();
98.93 - }
98.94 -
98.95 - if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
98.96 - // empty result
98.97 - return Lookup.EMPTY.lookup(template);
98.98 - }
98.99 -
98.100 - return new R<T>(template.getType(), delegate.lookup(template));
98.101 - }
98.102 -
98.103 - public <T> T lookup(Class<T> clazz) {
98.104 - if (areSubclassesOfThisClassAlwaysExcluded(clazz)) {
98.105 - return null;
98.106 - }
98.107 -
98.108 - T res = delegate.lookup(clazz);
98.109 -
98.110 - if (isObjectAccessible(clazz, res, 0)) {
98.111 - return res;
98.112 - } else {
98.113 - return null;
98.114 - }
98.115 - }
98.116 -
98.117 - @Override
98.118 - public <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
98.119 - if (areSubclassesOfThisClassAlwaysExcluded(template.getType())) {
98.120 - return null;
98.121 - }
98.122 -
98.123 - Lookup.Item<T> retValue = delegate.lookupItem(template);
98.124 -
98.125 - if (isObjectAccessible(template.getType(), retValue, 2)) {
98.126 - return retValue;
98.127 - } else {
98.128 - return null;
98.129 - }
98.130 - }
98.131 -
98.132 - /** @return true if the instance of class c shall never be returned from this lookup
98.133 - */
98.134 - private boolean areSubclassesOfThisClassAlwaysExcluded(Class<?> c) {
98.135 - Class<?>[] arr = classes();
98.136 -
98.137 - for (int i = 0; i < arr.length; i++) {
98.138 - if (arr[i].isAssignableFrom(c)) {
98.139 - return true;
98.140 - }
98.141 - }
98.142 -
98.143 - return false;
98.144 - }
98.145 -
98.146 - /** Returns the array of classes this lookup filters.
98.147 - */
98.148 - final Class<?>[] classes() {
98.149 - if (classes instanceof Class[]) {
98.150 - return (Class[]) classes;
98.151 - } else {
98.152 - return new Class[] { (Class) classes };
98.153 - }
98.154 - }
98.155 -
98.156 - /** Does a check whether two classes are accessible (in the super/sub class)
98.157 - * releation ship without walking thru any of the classes mentioned in the
98.158 - * barrier.
98.159 - */
98.160 - private static boolean isAccessible(Class<?>[] barriers, Class<?> from, Class<?> to) {
98.161 - if ((to == null) || !from.isAssignableFrom(to)) {
98.162 - // no way to reach each other by walking up
98.163 - return false;
98.164 - }
98.165 -
98.166 - for (int i = 0; i < barriers.length; i++) {
98.167 - if (to == barriers[i]) {
98.168 - return false;
98.169 - }
98.170 - }
98.171 -
98.172 - if (from == to) {
98.173 - return true;
98.174 - }
98.175 -
98.176 - //
98.177 - // depth first search
98.178 - //
98.179 - if (isAccessible(barriers, from, to.getSuperclass())) {
98.180 - return true;
98.181 - }
98.182 -
98.183 - Class[] interfaces = to.getInterfaces();
98.184 -
98.185 - for (int i = 0; i < interfaces.length; i++) {
98.186 - if (isAccessible(barriers, from, interfaces[i])) {
98.187 - return true;
98.188 - }
98.189 - }
98.190 -
98.191 - return false;
98.192 - }
98.193 -
98.194 - /** based on type decides whether the class accepts or not anObject
98.195 - * @param from the base type of the query
98.196 - * @param to depending on value of type either Object, Class or Item
98.197 - * @param type 0,1,2 for Object, Class or Item
98.198 - * @return true if we can access the to from from by walking around the bariers
98.199 - */
98.200 - private final boolean isObjectAccessible(Class from, Object to, int type) {
98.201 - if (to == null) {
98.202 - return false;
98.203 - }
98.204 -
98.205 - return isObjectAccessible(classes(), from, to, type);
98.206 - }
98.207 -
98.208 - /** based on type decides whether the class accepts or not anObject
98.209 - * @param barriers classes to avoid when testing reachability
98.210 - * @param from the base type of the query
98.211 - * @param to depending on value of type either Object, Class or Item
98.212 - * @param type 0,1,2 for Object, Class or Item
98.213 - * @return true if we can access the to from from by walking around the bariers
98.214 - */
98.215 - static final boolean isObjectAccessible(Class[] barriers, Class from, Object to, int type) {
98.216 - if (to == null) {
98.217 - return false;
98.218 - }
98.219 -
98.220 - switch (type) {
98.221 - case 0:
98.222 - return isAccessible(barriers, from, to.getClass());
98.223 -
98.224 - case 1:
98.225 - return isAccessible(barriers, from, (Class) to);
98.226 -
98.227 - case 2: {
98.228 - Item item = (Item) to;
98.229 -
98.230 - return isAccessible(barriers, from, item.getType());
98.231 - }
98.232 -
98.233 - default:
98.234 - throw new IllegalStateException("Type: " + type);
98.235 - }
98.236 - }
98.237 -
98.238 - /** Filters collection accroding to set of given filters.
98.239 - */
98.240 - final <E, T extends Collection<E>> T filter(
98.241 - Class<?>[] arr, Class<?> from, T c, int type, T prototype
98.242 - ) {
98.243 - T ret = null;
98.244 -
98.245 -
98.246 -// optimistic strategy expecting we will not need to filter
98.247 -TWICE:
98.248 - for (;;) {
98.249 - Iterator<E> it = c.iterator();
98.250 -BIG:
98.251 - while (it.hasNext()) {
98.252 - E res = it.next();
98.253 -
98.254 - if (!isObjectAccessible(arr, from, res, type)) {
98.255 - if (ret == null) {
98.256 - // we need to restart the scanning again
98.257 - // as there is an active filter
98.258 - ret = prototype;
98.259 - continue TWICE;
98.260 - }
98.261 -
98.262 - continue BIG;
98.263 - }
98.264 -
98.265 - if (ret != null) {
98.266 - // if we are running the second round from TWICE
98.267 - ret.add(res);
98.268 - }
98.269 - }
98.270 -
98.271 - // ok, processed
98.272 - break TWICE;
98.273 - }
98.274 -
98.275 - return (ret != null) ? ret : c;
98.276 - }
98.277 -
98.278 - /** Delegating result that filters unwanted items and instances.
98.279 - */
98.280 - private final class R<T> extends WaitableResult<T> implements LookupListener {
98.281 - private Result<T> result;
98.282 - private WeakResult<T> weak;
98.283 - private Object listeners;
98.284 - private Class<?> from;
98.285 -
98.286 - R(Class<?> from, Result<T> delegate) {
98.287 - this.from = from;
98.288 - this.result = delegate;
98.289 - this.weak = new WeakResult<T>(this, delegate);
98.290 - }
98.291 -
98.292 - protected void beforeLookup(Template t) {
98.293 - if (result instanceof WaitableResult) {
98.294 - ((WaitableResult) result).beforeLookup(t);
98.295 - }
98.296 - }
98.297 -
98.298 - public void addLookupListener(LookupListener l) {
98.299 - boolean add;
98.300 -
98.301 - synchronized (this) {
98.302 - listeners = AbstractLookup.modifyListenerList(true, l, listeners);
98.303 - add = listeners != null;
98.304 - }
98.305 -
98.306 - if (add) {
98.307 - result.addLookupListener(weak);
98.308 - }
98.309 - }
98.310 -
98.311 - public void removeLookupListener(LookupListener l) {
98.312 - boolean remove;
98.313 -
98.314 - synchronized (this) {
98.315 - listeners = AbstractLookup.modifyListenerList(false, l, listeners);
98.316 - remove = listeners == null;
98.317 - }
98.318 -
98.319 - if (remove) {
98.320 - result.removeLookupListener(weak);
98.321 - }
98.322 - }
98.323 -
98.324 - public Collection<? extends T> allInstances() {
98.325 - return openCol(result.allInstances(), 0);
98.326 - }
98.327 -
98.328 - private <S> Collection<S> openCol(Collection<S> c, int type) {
98.329 - return filter(classes(), from, c, type, new ArrayList<S>(c.size()));
98.330 - }
98.331 -
98.332 - @Override
98.333 - public Set<Class<? extends T>> allClasses() {
98.334 - return filter(classes(), from, result.allClasses(), 1, new HashSet<Class<? extends T>>());
98.335 - }
98.336 -
98.337 - @Override
98.338 - public Collection<? extends Item<T>> allItems() {
98.339 - return openCol(result.allItems(), 2);
98.340 - }
98.341 -
98.342 - public void resultChanged(org.openide.util.LookupEvent ev) {
98.343 - if (ev.getSource() == result) {
98.344 - collectFires(null);
98.345 - }
98.346 - }
98.347 -
98.348 - protected void collectFires(Collection<Object> evAndListeners) {
98.349 - LookupListener[] arr;
98.350 -
98.351 - synchronized (this) {
98.352 - if (listeners == null) {
98.353 - return;
98.354 - }
98.355 -
98.356 - if (listeners instanceof LookupListener) {
98.357 - arr = new LookupListener[] { (LookupListener) listeners };
98.358 - } else {
98.359 - ArrayList<?> l = (ArrayList<?>) listeners;
98.360 - arr = l.toArray(new LookupListener[l.size()]);
98.361 - }
98.362 - }
98.363 -
98.364 - final LookupListener[] ll = arr;
98.365 - final org.openide.util.LookupEvent newev = new org.openide.util.LookupEvent(this);
98.366 - AbstractLookup.notifyListeners(ll, newev, evAndListeners);
98.367 - }
98.368 - } // end of R
98.369 -
98.370 - private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
98.371 - private Lookup.Result source;
98.372 - private Reference<R<T>> result;
98.373 -
98.374 - public WeakResult(R<T> r, Lookup.Result<T> s) {
98.375 - this.result = new WeakReference<R<T>>(r);
98.376 - this.source = s;
98.377 - }
98.378 -
98.379 - protected void beforeLookup(Lookup.Template t) {
98.380 - R r = (R)result.get();
98.381 - if (r != null) {
98.382 - r.beforeLookup(t);
98.383 - } else {
98.384 - source.removeLookupListener(this);
98.385 - }
98.386 - }
98.387 -
98.388 - protected void collectFires(Collection<Object> evAndListeners) {
98.389 - R<T> r = result.get();
98.390 - if (r != null) {
98.391 - r.collectFires(evAndListeners);
98.392 - } else {
98.393 - source.removeLookupListener(this);
98.394 - }
98.395 - }
98.396 -
98.397 - public void addLookupListener(LookupListener l) {
98.398 - assert false;
98.399 - }
98.400 -
98.401 - public void removeLookupListener(LookupListener l) {
98.402 - assert false;
98.403 - }
98.404 -
98.405 - public Collection<T> allInstances() {
98.406 - assert false;
98.407 - return null;
98.408 - }
98.409 -
98.410 - public void resultChanged(LookupEvent ev) {
98.411 - R r = (R)result.get();
98.412 - if (r != null) {
98.413 - r.resultChanged(ev);
98.414 - } else {
98.415 - source.removeLookupListener(this);
98.416 - }
98.417 - }
98.418 -
98.419 - @Override
98.420 - public Collection<? extends Item<T>> allItems() {
98.421 - assert false;
98.422 - return null;
98.423 - }
98.424 -
98.425 - @Override
98.426 - public Set<Class<? extends T>> allClasses() {
98.427 - assert false;
98.428 - return null;
98.429 - }
98.430 - } // end of WeakResult
98.431 -}
99.1 --- a/openide.util/src/org/openide/util/lookup/InheritanceTree.java Thu Dec 10 19:23:25 2009 -0500
99.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
99.3 @@ -1,1276 +0,0 @@
99.4 -/*
99.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
99.6 - *
99.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
99.8 - *
99.9 - * The contents of this file are subject to the terms of either the GNU
99.10 - * General Public License Version 2 only ("GPL") or the Common
99.11 - * Development and Distribution License("CDDL") (collectively, the
99.12 - * "License"). You may not use this file except in compliance with the
99.13 - * License. You can obtain a copy of the License at
99.14 - * http://www.netbeans.org/cddl-gplv2.html
99.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
99.16 - * specific language governing permissions and limitations under the
99.17 - * License. When distributing the software, include this License Header
99.18 - * Notice in each file and include the License file at
99.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
99.20 - * particular file as subject to the "Classpath" exception as provided
99.21 - * by Sun in the GPL Version 2 section of the License file that
99.22 - * accompanied this code. If applicable, add the following below the
99.23 - * License Header, with the fields enclosed by brackets [] replaced by
99.24 - * your own identifying information:
99.25 - * "Portions Copyrighted [year] [name of copyright owner]"
99.26 - *
99.27 - * Contributor(s):
99.28 - *
99.29 - * The Original Software is NetBeans. The Initial Developer of the Original
99.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
99.31 - * Microsystems, Inc. All Rights Reserved.
99.32 - *
99.33 - * If you wish your version of this file to be governed by only the CDDL
99.34 - * or only the GPL Version 2, indicate your decision by adding
99.35 - * "[Contributor] elects to include this software in this distribution
99.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
99.37 - * single choice of license, a recipient has the option to distribute
99.38 - * your version of this file under either the CDDL, the GPL Version 2 or
99.39 - * to extend the choice of license to its licensees as provided above.
99.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
99.41 - * Version 2 license, then the option applies only if the new code is
99.42 - * made subject to such option by the copyright holder.
99.43 - */
99.44 -package org.openide.util.lookup;
99.45 -
99.46 -import org.openide.util.Lookup;
99.47 -import org.openide.util.lookup.AbstractLookup.Pair;
99.48 -import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
99.49 -import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
99.50 -
99.51 -import java.io.*;
99.52 -
99.53 -import java.lang.ref.WeakReference;
99.54 -
99.55 -import java.util.*;
99.56 -
99.57 -
99.58 -/** A tree to represent classes with inheritance. Description of the
99.59 - * data structure by Petr Nejedly:
99.60 - * <P>
99.61 - * So pretend I'm Lookup implementation. I've got a bunch of Items (e.g.
99.62 - * setPairs() method),
99.63 - * didn't do anything on them yet (no startup penalty) so I know nothing
99.64 - * about them.
99.65 - * Then I'll be asked for all instances implementing given interface or a
99.66 - * class. I surely need
99.67 - * to check all the Items now, as I don't know anything abou them. I surely
99.68 - * don't want to call
99.69 - * Item.getClass() as it will dismiss the whole effort. So all I have is
99.70 - * Item.instanceOf()
99.71 - * and I'll call it on every Item. I'll cache results, so the next time
99.72 - * you'll ask me for
99.73 - * the same interface/class, I'll answer immediatelly. But what if you ask
99.74 - * me for another
99.75 - * interface/class? I'll have to scan all Items for it again, unless I can
99.76 - * be sure some
99.77 - * of them can't implement it. The only source of this knowledge are the
99.78 - * previous questions
99.79 - * and my rulings on them. Here the algorithm have to be split into two
99.80 - * paths. If you
99.81 - * previously asked me for interfaces only, I'll have no hint for
99.82 - * subsequent queries,
99.83 - * but if you asked me for a class in history, and then for another class
99.84 - * and these classes
99.85 - * are not in inheritance relation (I can check hierarchy of lookup
99.86 - * arguments, because
99.87 - * they are already resolved/loaded) I can tell that those returned in
99.88 - * previous query can't
99.89 - * implement the newly asked class (they are in different hierarchy branch)
99.90 - * and I need to
99.91 - * ask less Items.
99.92 - * <P>
99.93 - * So if we use mostly classes for asking for services (and it is a trend
99.94 - * to use
99.95 - * abstract classes for this purpose in IDE anyway), this could be usable.
99.96 - * <P>
99.97 - * The data structure for separating the Items based on previous queries is
99.98 - * simple
99.99 - * tree, with every node tagged with one class. The tree's root is,
99.100 - * naturally,
99.101 - * java.lang.Object, is marked invited and initially contains all the
99.102 - * Items.
99.103 - * For every class query, the missing part of class hierarchy tree is
99.104 - * created,
99.105 - * the node of the class looked up is marked as invited and all Items from
99.106 - * nearest
99.107 - * invited parent (sperclass) are dragged to this node. The result are then
99.108 - * all
99.109 - * Items from this node and all the nodes deeper in hierarchy. Because it
99.110 - * may
99.111 - * be too complicated to walk through the children nodes, the results could
99.112 - * be
99.113 - * cached in the map.
99.114 - * For interface lookup, there is a little hint in reality (interfaces
99.115 - * and superinterfaces), but it would be harder to exploit it, so we could
99.116 - * fall-back
99.117 - * to walking through all the Items and cache results.
99.118 - *
99.119 - *
99.120 - * @author Jaroslav Tulach
99.121 - */
99.122 -final class InheritanceTree extends Object
99.123 -implements Serializable, AbstractLookup.Storage<ArrayList<Class>> {
99.124 - private static final long serialVersionUID = 1L;
99.125 -
99.126 - /** the root item (represents Object) */
99.127 - private transient Node object;
99.128 -
99.129 - /** Map of queried interfaces.
99.130 - * <p>Type: <code>Map<Class, (Collection<AbstractLookup.Pair> | AbstractLookup.Pair)></code>
99.131 - */
99.132 - private transient Map<Class,Object> interfaces;
99.133 -
99.134 - /** Map (Class, ReferenceToResult) of all listeners that are waiting in
99.135 - * changes in class Class
99.136 - */
99.137 - private transient Map<Class,ReferenceToResult> reg;
99.138 -
99.139 - /** Constructor
99.140 - */
99.141 - public InheritanceTree() {
99.142 - object = new Node(java.lang.Object.class);
99.143 - }
99.144 -
99.145 - private void writeObject(ObjectOutputStream oos) throws IOException {
99.146 - oos.writeObject(object);
99.147 -
99.148 - if (interfaces != null) {
99.149 - Iterator it = interfaces.entrySet().iterator();
99.150 -
99.151 - while (it.hasNext()) {
99.152 - Map.Entry e = (Map.Entry) it.next();
99.153 - Class c = (Class) e.getKey();
99.154 - oos.writeObject(c.getName());
99.155 -
99.156 - Object o = e.getValue();
99.157 -
99.158 - if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
99.159 - throw new ClassCastException(String.valueOf(o));
99.160 - }
99.161 -
99.162 - oos.writeObject(o);
99.163 - }
99.164 - }
99.165 -
99.166 - oos.writeObject(null);
99.167 - }
99.168 -
99.169 - private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
99.170 - object = (Node) ois.readObject();
99.171 - interfaces = new WeakHashMap<Class,Object>();
99.172 -
99.173 - String clazz;
99.174 - ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
99.175 -
99.176 - while ((clazz = (String) ois.readObject()) != null) {
99.177 - Object o = ois.readObject();
99.178 -
99.179 - if (!(o instanceof Collection) && !(o instanceof AbstractLookup.Pair)) {
99.180 - throw new ClassCastException(String.valueOf(o));
99.181 - }
99.182 -
99.183 - Class c = Class.forName(clazz, false, l);
99.184 - interfaces.put(c, o);
99.185 - }
99.186 - }
99.187 -
99.188 - /** Adds an item into the tree.
99.189 - * @param item to add
99.190 - * @return true if the Item has been added for the first time or false if some other
99.191 - * item equal to this one already existed in the lookup
99.192 - */
99.193 - public boolean add(AbstractLookup.Pair<?> item, ArrayList<Class> affected) {
99.194 - Node node = registerClass(object, item);
99.195 -
99.196 - affected.add(node.getType());
99.197 -
99.198 - if (node.assignItem(this, item)) {
99.199 - // this is the first item added to n.items
99.200 - // ok, we have to test interfaces too
99.201 - } else {
99.202 - // equal item is already there => stop processing
99.203 - return false;
99.204 - }
99.205 -
99.206 - boolean registeredAsInterface = registerInterface(item, affected);
99.207 -
99.208 - return registeredAsInterface;
99.209 - }
99.210 -
99.211 - /** Removes an item.
99.212 - */
99.213 - public void remove(AbstractLookup.Pair item, ArrayList<Class> affected) {
99.214 - Node n = removeClass(object, item);
99.215 -
99.216 - if (n != null) {
99.217 - affected.add(n.getType());
99.218 - }
99.219 -
99.220 - removeInterface(item, affected);
99.221 - }
99.222 -
99.223 - /** Removes all items that are not present in the provided collection.
99.224 - * @param retain collection of Pairs to keep them in
99.225 - * @param notify set of Classes that has possibly changed
99.226 - */
99.227 - public void retainAll(Map retain, ArrayList<Class> notify) {
99.228 - retainAllInterface(retain, notify);
99.229 - retainAllClasses(object, retain, notify);
99.230 - }
99.231 -
99.232 - /** Queries for instances of given class.
99.233 - * @param clazz the class to check
99.234 - * @return enumeration of Item
99.235 - * @see #unsorted
99.236 - */
99.237 - @SuppressWarnings("unchecked")
99.238 - public <T> Enumeration<Pair<T>> lookup(Class<T> clazz) {
99.239 - if ((clazz != null) && clazz.isInterface()) {
99.240 - return (Enumeration)searchInterface(clazz);
99.241 - } else {
99.242 - return (Enumeration)searchClass(object, clazz);
99.243 - }
99.244 - }
99.245 -
99.246 - /** A method to check whether the enumeration returned from
99.247 - * lookup method is sorted or is not
99.248 - * @param en enumeration to check
99.249 - * @return true if it is unsorted and needs to be sorted to find
99.250 - * pair with smallest index
99.251 - */
99.252 - public static boolean unsorted(Enumeration en) {
99.253 - return en instanceof NeedsSortEnum;
99.254 - }
99.255 -
99.256 - /** Prints debug messages.
99.257 - * @param out stream to output to
99.258 - * @param instances print also instances of the
99.259 - */
99.260 - public void print(java.io.PrintStream out, boolean instances) {
99.261 - printNode(object, "", out, instances); // NOI18N
99.262 - }
99.263 -
99.264 - //
99.265 - // methods to work on classes which are not interfaces
99.266 - //
99.267 -
99.268 - /** Searches the subtree and register the item where necessary.
99.269 - * @return the node that should contain the item
99.270 - */
99.271 - private static Node registerClass(Node n, AbstractLookup.Pair item) {
99.272 - if (!n.accepts(item)) {
99.273 - return null;
99.274 - }
99.275 -
99.276 - if (n.children != null) {
99.277 - Iterator it = n.children.iterator();
99.278 -
99.279 - for (;;) {
99.280 - Node ch = extractNode(it);
99.281 -
99.282 - if (ch == null) {
99.283 - break;
99.284 - }
99.285 -
99.286 - Node result = registerClass(ch, item);
99.287 -
99.288 - if (result != null) {
99.289 - // it is in subclass, in case of classes, it cannot
99.290 - // be any other class
99.291 - return result;
99.292 - }
99.293 - }
99.294 - }
99.295 -
99.296 - // ok, nobody of our subclasses wants the class, I'll take it
99.297 - return n;
99.298 - }
99.299 -
99.300 - /** Removes the item from the tree of objects.
99.301 - * @return most narrow class that this item was removed from
99.302 - */
99.303 - private static Node removeClass(Node n, AbstractLookup.Pair item) {
99.304 - if (!n.accepts(item)) {
99.305 - return null;
99.306 - }
99.307 -
99.308 - if ((n.items != null) && n.items.remove(item)) {
99.309 - // this node really contains the item
99.310 - return n;
99.311 - }
99.312 -
99.313 - if (n.children != null) {
99.314 - Iterator it = n.children.iterator();
99.315 -
99.316 - for (;;) {
99.317 - Node ch = extractNode(it);
99.318 -
99.319 - if (ch == null) {
99.320 - break;
99.321 - }
99.322 -
99.323 - Node result = removeClass(ch, item);
99.324 -
99.325 - // If the children node was emptied, remove it if possible.
99.326 - if (((ch.items == null) || ch.items.isEmpty()) && ((ch.children == null) || ch.children.isEmpty())) {
99.327 - it.remove();
99.328 - }
99.329 -
99.330 - if (result != null) {
99.331 - // it is in subclass, in case of classes, it cannot
99.332 - // be any other class
99.333 - return result;
99.334 - }
99.335 - }
99.336 - }
99.337 -
99.338 - // nobody found
99.339 - return null;
99.340 - }
99.341 -
99.342 - /** Finds a node that represents a class.
99.343 - * @param n node to search from
99.344 - * @param clazz the clazz to find
99.345 - * @return node that represents clazz in the tree or null if the clazz is not
99.346 - * represented under the node n
99.347 - */
99.348 - private Node classToNode(final Node n, final Class<?> clazz) {
99.349 - if (!n.accepts(clazz)) {
99.350 - // nothing from us
99.351 - return null;
99.352 - }
99.353 -
99.354 - if (n.getType() == clazz) {
99.355 - // we have found what we need
99.356 - return n;
99.357 - }
99.358 -
99.359 - if (n.children != null) {
99.360 - // have to proceed to children
99.361 - Iterator it = n.children.iterator();
99.362 -
99.363 - for (;;) {
99.364 - final Node ch = extractNode(it);
99.365 -
99.366 - if (ch == null) {
99.367 - break;
99.368 - }
99.369 -
99.370 - Node found = classToNode(ch, clazz);
99.371 -
99.372 - if ((found != null) && ch.deserialized()) {
99.373 - class VerifyJob implements AbstractLookup.ISE.Job {
99.374 - private AbstractLookup.Pair<?>[] pairs;
99.375 - private boolean[] answers;
99.376 -
99.377 - public VerifyJob(Collection<Pair> items) {
99.378 - if (items != null) {
99.379 - pairs = items.toArray(new AbstractLookup.Pair[0]);
99.380 - }
99.381 - }
99.382 -
99.383 - public void before() {
99.384 - // make sure the node is converted into deserialized state
99.385 - ch.deserialized();
99.386 -
99.387 - if (pairs != null) {
99.388 - answers = new boolean[pairs.length];
99.389 -
99.390 - for (int i = 0; i < pairs.length; i++) {
99.391 - answers[i] = pairs[i].instanceOf(clazz);
99.392 - }
99.393 - }
99.394 - }
99.395 -
99.396 - public void inside() {
99.397 - if (pairs != null) {
99.398 - for (int i = 0; i < pairs.length; i++) {
99.399 - if (answers[i]) {
99.400 - ch.assignItem(InheritanceTree.this, pairs[i]);
99.401 - n.items.remove(pairs[i]);
99.402 - }
99.403 - }
99.404 - }
99.405 -
99.406 - if (n.children != null) {
99.407 - // consolidate all nodes that represent the same class
99.408 - HashMap<Class,Node> nodes = new HashMap<Class,Node>(n.children.size() * 3);
99.409 -
99.410 - Iterator child = n.children.iterator();
99.411 -
99.412 - while (child.hasNext()) {
99.413 - Node node = extractNode(child);
99.414 - if (node == null) {
99.415 - continue;
99.416 - }
99.417 - Node prev = nodes.put(node.getType(), node);
99.418 -
99.419 - if (prev != null) {
99.420 - child.remove();
99.421 - nodes.put(node.getType(), prev);
99.422 -
99.423 - // mark as being deserialized
99.424 - prev.markDeserialized();
99.425 -
99.426 - if (prev.children == null) {
99.427 - prev.children = node.children;
99.428 - } else {
99.429 - if (node.children != null) {
99.430 - prev.children.addAll(node.children);
99.431 - }
99.432 - }
99.433 -
99.434 - if (node.items != null) {
99.435 - Iterator items = node.items.iterator();
99.436 -
99.437 - while (items.hasNext()) {
99.438 - AbstractLookup.Pair item = (AbstractLookup.Pair) items.next();
99.439 - prev.assignItem(InheritanceTree.this, item);
99.440 - }
99.441 - }
99.442 - }
99.443 - }
99.444 - }
99.445 - }
99.446 - }
99.447 -
99.448 - VerifyJob verify = new VerifyJob(n.items);
99.449 -
99.450 - try {
99.451 - verify.before();
99.452 - } catch (AbstractLookup.ISE ex) {
99.453 - // mark deserialized again
99.454 - ch.markDeserialized();
99.455 - ex.registerJob(verify);
99.456 - throw ex;
99.457 - }
99.458 -
99.459 - verify.inside();
99.460 -
99.461 - found = classToNode(ch, clazz);
99.462 - }
99.463 -
99.464 - if (found != null) {
99.465 - // class found in one of subnodes
99.466 - return found;
99.467 - }
99.468 - }
99.469 - }
99.470 -
99.471 - class TwoJobs implements AbstractLookup.ISE.Job {
99.472 - private AbstractLookup.Pair[] pairs;
99.473 - private boolean[] answers;
99.474 - private Node newNode;
99.475 -
99.476 - public void before() {
99.477 - // have to create new subnode and possibly reparent one of my own
99.478 - // but all changes can be done only if we will not be interrupted from
99.479 - // outside - e.g. instanceOf methods will not throw exception
99.480 - // first of all let's compute the answers to method instanceOf
99.481 - AbstractLookup.Pair[] arr = null;
99.482 - boolean[] boolArr = null;
99.483 -
99.484 - if (n.items != null) {
99.485 - arr = new AbstractLookup.Pair[n.items.size()];
99.486 - boolArr = new boolean[n.items.size()];
99.487 -
99.488 - int i = 0;
99.489 - Iterator<Pair> it = n.items.iterator();
99.490 -
99.491 - while (it.hasNext()) {
99.492 - AbstractLookup.Pair<?> item = it.next();
99.493 - arr[i] = item;
99.494 - boolArr[i] = item.instanceOf(clazz);
99.495 - i++;
99.496 - }
99.497 - }
99.498 -
99.499 - pairs = arr;
99.500 - answers = boolArr;
99.501 - }
99.502 -
99.503 - public void inside() {
99.504 - // test if the query has not chagned since
99.505 - if (pairs != null) {
99.506 - if (!Arrays.equals(n.items.toArray(), pairs)) {
99.507 - // ok, let try once more
99.508 - return;
99.509 - }
99.510 - }
99.511 -
99.512 - internal();
99.513 - }
99.514 -
99.515 - public void internal() {
99.516 - ArrayList<Node> reparent = null;
99.517 -
99.518 - if (n.children == null) {
99.519 - n.children = new ArrayList<Node>();
99.520 - } else {
99.521 - // scan thru all my nodes if some of them are not a subclass
99.522 - // of clazz => then they would need to become child of newNode
99.523 - Iterator it = n.children.iterator();
99.524 -
99.525 - for (;;) {
99.526 - Node r = extractNode(it);
99.527 -
99.528 - if (r == null) {
99.529 - break;
99.530 - }
99.531 -
99.532 - if (clazz.isAssignableFrom(r.getType())) {
99.533 - if (reparent == null) {
99.534 - reparent = new ArrayList<Node>();
99.535 - }
99.536 -
99.537 - reparent.add(r);
99.538 - it.remove();
99.539 - }
99.540 - }
99.541 - }
99.542 -
99.543 - newNode = new Node(clazz);
99.544 - n.children.add(newNode);
99.545 -
99.546 - if (reparent != null) {
99.547 - // reassing reparent node as a child of newNode
99.548 - newNode.children = reparent;
99.549 - }
99.550 -
99.551 - // now take all my items that are instances of that class and
99.552 - // reasign them
99.553 - if (n.items != null) {
99.554 - Iterator it = n.items.iterator();
99.555 - int i = 0;
99.556 -
99.557 - while (it.hasNext()) {
99.558 - AbstractLookup.Pair item = (AbstractLookup.Pair) it.next();
99.559 -
99.560 - if (answers[i]) { // answers[i] is precomputed value of item.instanceOf (clazz))
99.561 - it.remove();
99.562 - newNode.assignItem(InheritanceTree.this, pairs[i]);
99.563 - }
99.564 -
99.565 - i++;
99.566 - }
99.567 - }
99.568 - }
99.569 - }
99.570 -
99.571 - TwoJobs j = new TwoJobs();
99.572 -
99.573 - try {
99.574 - j.before();
99.575 - } catch (AbstractLookup.ISE ex) {
99.576 - // ok, it is not possible to call instanceOf now, let's
99.577 - // schedule it for later
99.578 - // so register recovery job
99.579 - ex.registerJob(j);
99.580 - throw ex;
99.581 - }
99.582 -
99.583 - j.internal();
99.584 -
99.585 - // newNode represents my clazz
99.586 - return j.newNode;
99.587 - }
99.588 -
99.589 - /** Search for a requested class.
99.590 - * @return enumeration of Pair
99.591 - */
99.592 - private Enumeration<Pair> searchClass(Node n, Class<?> clazz) {
99.593 - if (clazz != null) {
99.594 - n = classToNode(n, clazz);
99.595 - }
99.596 -
99.597 - if (n == null) {
99.598 - // not for us
99.599 - return emptyEn();
99.600 - } else {
99.601 - return nodeToEnum(n);
99.602 - }
99.603 - }
99.604 -
99.605 - /** Retains all classes. Removes nodes which items and children are emptied, works
99.606 - * recursivelly from specified root node.
99.607 - * @param node root node from which to start to process the tree
99.608 - * @param retain a map from (Item, AbstractLookup.Info) that describes which items to retain
99.609 - * and witch integer to assign them
99.610 - * @param notify collection of classes will be changed
99.611 - * @return <code>true<code> if some items were changed and node items and children are emptied,
99.612 - * those nodes, excluding root, will be removed from tree */
99.613 - private boolean retainAllClasses(Node node, Map retain, Collection<Class> notify) {
99.614 - boolean retained = false;
99.615 -
99.616 - if ((node.items != null) && (retain != null)) {
99.617 - Iterator<Pair> it = node.items.iterator();
99.618 -
99.619 - while (it.hasNext()) {
99.620 - AbstractLookup.Pair<?> item = it.next();
99.621 - AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(item);
99.622 -
99.623 - if (n == null) {
99.624 - // remove this item, it should not be there
99.625 - it.remove();
99.626 - retained = true;
99.627 - } else {
99.628 - // change the index
99.629 - if (item.getIndex() != n.index) {
99.630 - item.setIndex(null, n.index);
99.631 -
99.632 - // notify.addAll ((ArrayList)n.transaction);
99.633 - }
99.634 - }
99.635 - }
99.636 -
99.637 - if (retained && (notify != null)) {
99.638 - // type of this node has been changed
99.639 - notify.add(node.getType());
99.640 - }
99.641 - }
99.642 -
99.643 - if (node.children != null) {
99.644 - for (Iterator it = node.children.iterator();;) {
99.645 - Node ch = extractNode(it);
99.646 -
99.647 - if (ch == null) {
99.648 - break;
99.649 - }
99.650 -
99.651 - boolean result = retainAllClasses(ch, retain, notify);
99.652 -
99.653 - if (result) {
99.654 - // The children node was emptied and has no children -> remove it.
99.655 - it.remove();
99.656 - }
99.657 - }
99.658 - }
99.659 -
99.660 - return retained && node.items.isEmpty() && ((node.children == null) || node.children.isEmpty());
99.661 - }
99.662 -
99.663 - /** A method that creates enumeration of all items under given node.
99.664 - *
99.665 - * @param n node to create enumeration for
99.666 - * @return enumeration of Pairs
99.667 - */
99.668 - private static Enumeration<Pair> nodeToEnum(Node n) {
99.669 - if (n.children == null) {
99.670 - // create a simple enumeration because we do not have children
99.671 - Enumeration<Pair> e;
99.672 - if (n.items == null) {
99.673 - e = emptyEn();
99.674 - } else {
99.675 - e = Collections.enumeration(n.items);
99.676 - }
99.677 - return e;
99.678 - }
99.679 -
99.680 - // create enumeration of Items
99.681 - return new NeedsSortEnum(n);
99.682 - }
99.683 -
99.684 - //
99.685 - // Methods to work on interfaces
99.686 - //
99.687 -
99.688 - /** Registers an item with interfaces.
99.689 - * @param item item to register
99.690 - * @param affected list of classes that were affected
99.691 - * @return false if similar item has already been registered
99.692 - */
99.693 - @SuppressWarnings("unchecked")
99.694 - private boolean registerInterface(AbstractLookup.Pair<?> item, Collection<Class> affected) {
99.695 - if (interfaces == null) {
99.696 - return true;
99.697 - }
99.698 -
99.699 - Iterator<Map.Entry<Class,Object>> it = interfaces.entrySet().iterator();
99.700 -
99.701 - while (it.hasNext()) {
99.702 - Map.Entry<Class,Object> entry = it.next();
99.703 - Class<?> iface = entry.getKey();
99.704 -
99.705 - if (item.instanceOf(iface)) {
99.706 - Object value = entry.getValue();
99.707 -
99.708 - if (value instanceof Collection) {
99.709 - Collection<Object> set = (Collection<Object>) value;
99.710 -
99.711 - if (!set.add(item)) {
99.712 - // item is already there, probably (if everything is correct) is registered in
99.713 - // all other ifaces too, so stop additional testing
99.714 - return false;
99.715 - }
99.716 - } else {
99.717 - // there is just one pair right now
99.718 - if (value.equals(item)) {
99.719 - // item is there => stop processing (same as above)
99.720 - return false;
99.721 - }
99.722 -
99.723 - // otherwise replace the single item with ArrayList
99.724 - ArrayList<Object> ll = new ArrayList<Object>(3);
99.725 - ll.add(value);
99.726 - ll.add(item);
99.727 - entry.setValue(ll);
99.728 - }
99.729 -
99.730 - affected.add(iface);
99.731 - }
99.732 - }
99.733 -
99.734 - return true;
99.735 - }
99.736 -
99.737 - /** Removes interface.
99.738 - * @param item item to register
99.739 - * @param affected list of classes that were affected
99.740 - */
99.741 - @SuppressWarnings("unchecked")
99.742 - private void removeInterface(AbstractLookup.Pair item, Collection affected) {
99.743 - if (interfaces == null) {
99.744 - return;
99.745 - }
99.746 -
99.747 - Iterator it = interfaces.entrySet().iterator();
99.748 -
99.749 - while (it.hasNext()) {
99.750 - Map.Entry entry = (Map.Entry) it.next();
99.751 - Object value = entry.getValue();
99.752 -
99.753 - if (value instanceof Collection) {
99.754 - Collection set = (Collection) value;
99.755 -
99.756 - if (set.remove(item)) {
99.757 - if (set.size() == 1) {
99.758 - // if there is just one item remaining change to single item mode
99.759 - entry.setValue(set.iterator().next());
99.760 - }
99.761 -
99.762 - // adds the Class the item was register to into affected
99.763 - affected.add(entry.getKey());
99.764 - }
99.765 - } else {
99.766 - // single item value
99.767 - if (value.equals(item)) {
99.768 - // Emptied -> remove.
99.769 - it.remove();
99.770 -
99.771 - affected.add(entry.getKey());
99.772 - }
99.773 - }
99.774 - }
99.775 - }
99.776 -
99.777 - /** Retains some items.
99.778 - * @param retainItems items to retain and their mapping to index numbers
99.779 - * (AbstractLookup.Pair -> AbstractLookup.Info)
99.780 - * @param affected list of classes that were affected
99.781 - */
99.782 - @SuppressWarnings("unchecked")
99.783 - private void retainAllInterface(Map retainItems, Collection affected) {
99.784 - if (interfaces == null) {
99.785 - return;
99.786 - }
99.787 -
99.788 - Iterator it = interfaces.entrySet().iterator();
99.789 -
99.790 - while (it.hasNext()) {
99.791 - Map.Entry entry = (Map.Entry) it.next();
99.792 - Object value = entry.getValue();
99.793 -
99.794 - HashMap<?,?> retain = new HashMap(retainItems);
99.795 -
99.796 - Iterator elems;
99.797 - boolean multi = value instanceof Collection;
99.798 -
99.799 - if (multi) {
99.800 - // collection mode
99.801 - elems = ((Collection) value).iterator();
99.802 - } else {
99.803 - // single item mode
99.804 - elems = Collections.singleton(value).iterator();
99.805 - }
99.806 -
99.807 - boolean changed = false;
99.808 - boolean reordered = false;
99.809 -
99.810 - while (elems.hasNext()) {
99.811 - AbstractLookup.Pair p = (AbstractLookup.Pair) elems.next();
99.812 -
99.813 - AbstractLookup.Info n = (AbstractLookup.Info) retain.remove(p);
99.814 -
99.815 - if (n == null) {
99.816 - if (multi) {
99.817 - // remove it
99.818 - elems.remove();
99.819 - }
99.820 -
99.821 - changed = true;
99.822 - } else {
99.823 - if (p.getIndex() != n.index) {
99.824 - // improve the index
99.825 - p.setIndex(null, n.index);
99.826 -
99.827 - // affected.addAll ((ArrayList)n.transaction);
99.828 - reordered = true;
99.829 - }
99.830 - }
99.831 - }
99.832 -
99.833 - if (reordered && value instanceof List) {
99.834 - // if reordered, than update the order in the collection
99.835 - List l = (List) value;
99.836 - Collections.sort(l, ALPairComparator.DEFAULT);
99.837 - }
99.838 -
99.839 - if (changed) {
99.840 - if (multi) {
99.841 - Collection c = (Collection) value;
99.842 -
99.843 - if (c.size() == 1) {
99.844 - // back to single item mode
99.845 - entry.setValue(c.iterator().next());
99.846 - }
99.847 - } else {
99.848 - // remove in single mode => remove completely
99.849 - it.remove();
99.850 - }
99.851 -
99.852 - // adds the Class the item was register to into affected
99.853 - affected.add(entry.getKey());
99.854 - }
99.855 - }
99.856 - }
99.857 -
99.858 - /** Searches for a clazz between interfaces.
99.859 - * @param clazz class to search for
99.860 - * @return enumeration of Items
99.861 - */
99.862 - @SuppressWarnings("unchecked")
99.863 - private Enumeration<Pair> searchInterface(final Class<?> clazz) {
99.864 - if (interfaces == null) {
99.865 - // first call for interface, only initialize
99.866 - interfaces = new WeakHashMap();
99.867 - }
99.868 -
99.869 - Object obj = interfaces.get(clazz);
99.870 -
99.871 - if (obj == null) {
99.872 - // set of items
99.873 - AbstractLookup.Pair one = null;
99.874 - ArrayList items = null;
99.875 -
99.876 - Enumeration en = lookup(Object.class);
99.877 -
99.878 - while (en.hasMoreElements()) {
99.879 - AbstractLookup.Pair it = (AbstractLookup.Pair) en.nextElement();
99.880 -
99.881 - if (it.instanceOf(clazz)) {
99.882 - // ok, this item implements given clazz
99.883 - if (one == null) {
99.884 - one = it;
99.885 - } else {
99.886 - if (items == null) {
99.887 - items = new ArrayList(3);
99.888 - items.add(one);
99.889 - }
99.890 -
99.891 - items.add(it);
99.892 - }
99.893 - }
99.894 - }
99.895 -
99.896 - if ((items == null) && (one != null)) {
99.897 - // single item mode
99.898 - interfaces.put(clazz, one);
99.899 -
99.900 - return singletonEn(one);
99.901 - } else {
99.902 - if (items == null) {
99.903 - items = new ArrayList(2);
99.904 - }
99.905 -
99.906 - interfaces.put(clazz, items);
99.907 -
99.908 - return Collections.enumeration(items);
99.909 - }
99.910 - } else {
99.911 - if (obj instanceof Collection) {
99.912 - return Collections.enumeration((Collection) obj);
99.913 - } else {
99.914 - // single item mode
99.915 - return singletonEn((Pair)obj);
99.916 - }
99.917 - }
99.918 - }
99.919 -
99.920 - /** Extracts a node from an iterator, returning null if no next element found
99.921 - */
99.922 - private static Node extractNode(Iterator it) {
99.923 - while (it.hasNext()) {
99.924 - Node n = (Node) it.next();
99.925 -
99.926 - if (n.get() == null) {
99.927 - it.remove();
99.928 - } else {
99.929 - return n;
99.930 - }
99.931 - }
99.932 -
99.933 - return null;
99.934 - }
99.935 -
99.936 - /** Prints debug info about the node.
99.937 - * @param n node to print
99.938 - * @param sp spaces to add
99.939 - * @param out where
99.940 - * @param instances print also instances
99.941 - */
99.942 - private static void printNode(Node n, String sp, java.io.PrintStream out, boolean instances) {
99.943 - int i;
99.944 - Iterator it;
99.945 -
99.946 - Class type = n.getType();
99.947 -
99.948 - out.print(sp);
99.949 - out.println("Node for: " + type + "\t" + ((type == null) ? null : type.getClassLoader())); // NOI18N
99.950 -
99.951 - if (n.items != null) {
99.952 - i = 0;
99.953 - it = new ArrayList<Pair>(n.items).iterator();
99.954 -
99.955 - while (it.hasNext()) {
99.956 - AbstractLookup.Pair p = (AbstractLookup.Pair) it.next();
99.957 - out.print(sp);
99.958 - out.print(" item (" + i++ + "): ");
99.959 - out.print(p); // NOI18N
99.960 - out.print(" id: " + Integer.toHexString(System.identityHashCode(p))); // NOI18N
99.961 - out.print(" index: "); // NOI18N
99.962 - out.print(p.getIndex());
99.963 -
99.964 - if (instances) {
99.965 - out.print(" I: " + p.getInstance());
99.966 - }
99.967 -
99.968 - out.println();
99.969 - }
99.970 - }
99.971 -
99.972 - if (n.children != null) {
99.973 - i = 0;
99.974 - it = n.children.iterator();
99.975 -
99.976 - while (it.hasNext()) {
99.977 - Node ch = (Node) it.next();
99.978 - printNode(ch, sp + " ", out, instances); // NOI18N
99.979 - }
99.980 - }
99.981 - }
99.982 -
99.983 - public ReferenceToResult registerReferenceToResult(ReferenceToResult<?> newRef) {
99.984 - if (reg == null) {
99.985 - reg = new HashMap<Class,ReferenceToResult>();
99.986 - }
99.987 -
99.988 - Class<? extends Object> clazz = newRef.template.getType();
99.989 -
99.990 - // initialize the data structures if not yet
99.991 - lookup(clazz);
99.992 -
99.993 - // newRef will be the new head of the list
99.994 - return reg.put(clazz, newRef);
99.995 - }
99.996 -
99.997 - public ReferenceToResult cleanUpResult(Lookup.Template templ) {
99.998 - collectListeners(null, templ.getType());
99.999 -
99.1000 - return (reg == null) ? null : reg.get(templ.getType());
99.1001 - }
99.1002 -
99.1003 - public ArrayList<Class> beginTransaction(int ensure) {
99.1004 - return new ArrayList<Class>();
99.1005 - }
99.1006 -
99.1007 - public void endTransaction(ArrayList<Class> list, Set<AbstractLookup.R> allAffectedResults) {
99.1008 - if (list.size() == 1) {
99.1009 - // probably the most common case
99.1010 - collectListeners(allAffectedResults, list.get(0));
99.1011 - } else {
99.1012 - Iterator it = list.iterator();
99.1013 -
99.1014 - while (it.hasNext()) {
99.1015 - collectListeners(allAffectedResults, (Class) it.next());
99.1016 - }
99.1017 - }
99.1018 - }
99.1019 -
99.1020 - /** Notifies all listeners that are interested in changes in this class.
99.1021 - * Should be called from synchronized places.
99.1022 - * @param allAffectedResults adds Results into this set
99.1023 - * @param c the class that has changed
99.1024 - */
99.1025 - private void collectListeners(Set<AbstractLookup.R> allAffectedResults, Class c) {
99.1026 - if (reg == null) {
99.1027 - return;
99.1028 - }
99.1029 -
99.1030 - while (c != null) {
99.1031 - ReferenceToResult first = reg.get(c);
99.1032 - ReferenceIterator it = new ReferenceIterator(first);
99.1033 -
99.1034 - while (it.next()) {
99.1035 - AbstractLookup.R result = it.current().getResult();
99.1036 -
99.1037 - if (allAffectedResults != null) {
99.1038 - // add result
99.1039 - allAffectedResults.add(result);
99.1040 - }
99.1041 - }
99.1042 -
99.1043 - if (first != it.first()) {
99.1044 - if (it.first() == null) {
99.1045 - // we do not need have more results on this object
99.1046 - reg.remove(c);
99.1047 - } else {
99.1048 - // move the head of the list
99.1049 - reg.put(c, it.first());
99.1050 - }
99.1051 - }
99.1052 -
99.1053 - c = c.getSuperclass();
99.1054 - }
99.1055 -
99.1056 - if (reg.isEmpty()) {
99.1057 - // clean up the list of all results if we do not need them anymore
99.1058 - reg = null;
99.1059 - }
99.1060 - }
99.1061 -
99.1062 - /** Node in the tree.
99.1063 - */
99.1064 - static final class Node extends WeakReference<Class> implements Serializable {
99.1065 - static final long serialVersionUID = 3L;
99.1066 -
99.1067 - /** children nodes */
99.1068 - public ArrayList<Node> children;
99.1069 -
99.1070 - /** list of items assigned to this node (suspect to be subclasses) */
99.1071 - public Collection<Pair> items;
99.1072 -
99.1073 - /** Constructor.
99.1074 - */
99.1075 - public Node(Class clazz) {
99.1076 - super(clazz);
99.1077 - }
99.1078 -
99.1079 - /** Returns true if the object was deserialized also clears the serialized flag.
99.1080 - * @return true if so.
99.1081 - */
99.1082 - public boolean deserialized() {
99.1083 - if ((items == null) || items instanceof LinkedHashSet) {
99.1084 - return false;
99.1085 - }
99.1086 -
99.1087 - if (items.isEmpty()) {
99.1088 - items = null;
99.1089 - } else {
99.1090 - items = new LinkedHashSet<Pair>(items);
99.1091 - }
99.1092 -
99.1093 - return true;
99.1094 - }
99.1095 -
99.1096 - /** Marks this item as being deserialized.
99.1097 - */
99.1098 - public void markDeserialized() {
99.1099 - if (items == null || items == Collections.EMPTY_LIST) {
99.1100 - items = Collections.emptyList();
99.1101 - } else {
99.1102 - items = Collections.synchronizedCollection(items);
99.1103 - }
99.1104 - }
99.1105 -
99.1106 - /** Getter for the type associated with this node.
99.1107 - */
99.1108 - public Class<?> getType() {
99.1109 - Class<?> c = get();
99.1110 -
99.1111 - // if garbage collected, then return a garbage
99.1112 - return (c == null) ? Void.TYPE : c;
99.1113 - }
99.1114 -
99.1115 - /** Checks whether a node can represent an class.
99.1116 - */
99.1117 - public boolean accepts(Class<?> clazz) {
99.1118 - if (getType() == Object.class) {
99.1119 - return true;
99.1120 - }
99.1121 -
99.1122 - return getType().isAssignableFrom(clazz);
99.1123 - }
99.1124 -
99.1125 - /** Checks whether item is instance of this node.
99.1126 - */
99.1127 - public boolean accepts(AbstractLookup.Pair<?> item) {
99.1128 - if (getType() == Object.class) {
99.1129 - // Object.class
99.1130 - return true;
99.1131 - }
99.1132 -
99.1133 - return item.instanceOf(getType());
99.1134 - }
99.1135 -
99.1136 - /** Assings an item to this node.
99.1137 - * @param item the item
99.1138 - * @return true if item has been added as new
99.1139 - */
99.1140 - public boolean assignItem(InheritanceTree tree, AbstractLookup.Pair<?> item) {
99.1141 - if ((items == null) || (items == Collections.EMPTY_LIST)) {
99.1142 - items = new LinkedHashSet<Pair>();
99.1143 - items.add(item);
99.1144 -
99.1145 - return true;
99.1146 - }
99.1147 -
99.1148 - if (items.contains(item)) {
99.1149 - Iterator<Pair> it = items.iterator();
99.1150 - Pair old;
99.1151 - for (;;) {
99.1152 - old = it.next();
99.1153 - if (item.equals(old)) {
99.1154 - break;
99.1155 - }
99.1156 - }
99.1157 -
99.1158 - if (old != item) {
99.1159 - // replace the items there
99.1160 - item.setIndex(tree, old.getIndex());
99.1161 - }
99.1162 -
99.1163 - it.remove();
99.1164 - items.add(item);
99.1165 -
99.1166 - return false;
99.1167 - }
99.1168 -
99.1169 - items.add(item);
99.1170 -
99.1171 - return true;
99.1172 - }
99.1173 -
99.1174 - private Object writeReplace() {
99.1175 - return new R(this);
99.1176 - }
99.1177 -
99.1178 - @Override
99.1179 - public String toString() {
99.1180 - return "Node for " + get();
99.1181 - }
99.1182 - }
99.1183 - // End of class Node.
99.1184 -
99.1185 - private static final class R implements Serializable {
99.1186 - static final long serialVersionUID = 1L;
99.1187 - private static ClassLoader l;
99.1188 - private String clazzName;
99.1189 - private transient Class<?> clazz;
99.1190 - private ArrayList<Node> children;
99.1191 - private Collection<Pair> items;
99.1192 -
99.1193 - public R(Node n) {
99.1194 - this.clazzName = n.getType().getName();
99.1195 - this.children = n.children;
99.1196 -
99.1197 - if (n.items instanceof LinkedHashSet || (n.items == null)) {
99.1198 - this.items = n.items;
99.1199 - } else {
99.1200 - this.items = new LinkedHashSet<Pair>(n.items);
99.1201 - }
99.1202 - }
99.1203 -
99.1204 - private void readObject(ObjectInputStream ois)
99.1205 - throws IOException, ClassNotFoundException {
99.1206 - ois.defaultReadObject();
99.1207 -
99.1208 - if (l == null) {
99.1209 - l = Lookup.getDefault().lookup(ClassLoader.class);
99.1210 - }
99.1211 -
99.1212 - clazz = Class.forName(clazzName, false, l);
99.1213 - }
99.1214 -
99.1215 - private Object readResolve() throws ObjectStreamException {
99.1216 - Node n = new Node(clazz);
99.1217 - n.children = children;
99.1218 - n.items = items;
99.1219 - n.markDeserialized();
99.1220 -
99.1221 - return n;
99.1222 - }
99.1223 - }
99.1224 - // end of R
99.1225 -
99.1226 - static Enumeration<Object> arrayEn(Object[] object) {
99.1227 - return Collections.enumeration(Arrays.asList(object));
99.1228 - }
99.1229 - static <T> Enumeration<T> singletonEn(T object) {
99.1230 - return Collections.enumeration(Collections.singleton(object));
99.1231 - }
99.1232 - static <T> Enumeration<T> emptyEn() {
99.1233 - return Collections.enumeration(Collections.<T>emptyList());
99.1234 - }
99.1235 -
99.1236 - /** Just a marker class to be able to do instanceof and find out
99.1237 - * that this enumeration is not sorted
99.1238 - */
99.1239 - private static final class NeedsSortEnum extends LinkedList<Node>
99.1240 - implements Enumeration<Pair> {
99.1241 - private Enumeration<Pair> en;
99.1242 -
99.1243 - public NeedsSortEnum(Node n) {
99.1244 - add(n);
99.1245 - }
99.1246 -
99.1247 - private boolean ensureNext() {
99.1248 - for (;;) {
99.1249 - if (en != null && en.hasMoreElements()) {
99.1250 - return true;
99.1251 - }
99.1252 - if (isEmpty()) {
99.1253 - return false;
99.1254 - }
99.1255 -
99.1256 - Node n2 = poll();
99.1257 - if (n2.children != null) {
99.1258 - addAll(n2.children);
99.1259 - }
99.1260 -
99.1261 - if (n2.items != null && !n2.items.isEmpty()) {
99.1262 - en = Collections.enumeration(n2.items);
99.1263 - }
99.1264 - }
99.1265 - }
99.1266 -
99.1267 - public boolean hasMoreElements() {
99.1268 - return ensureNext();
99.1269 - }
99.1270 -
99.1271 - public Pair nextElement() {
99.1272 - if (!ensureNext()) {
99.1273 - throw new NoSuchElementException();
99.1274 - }
99.1275 - return en.nextElement();
99.1276 - }
99.1277 - }
99.1278 - // end of NeedsSortEnum
99.1279 -}
100.1 --- a/openide.util/src/org/openide/util/lookup/InstanceContent.java Thu Dec 10 19:23:25 2009 -0500
100.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
100.3 @@ -1,378 +0,0 @@
100.4 -/*
100.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
100.6 - *
100.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
100.8 - *
100.9 - * The contents of this file are subject to the terms of either the GNU
100.10 - * General Public License Version 2 only ("GPL") or the Common
100.11 - * Development and Distribution License("CDDL") (collectively, the
100.12 - * "License"). You may not use this file except in compliance with the
100.13 - * License. You can obtain a copy of the License at
100.14 - * http://www.netbeans.org/cddl-gplv2.html
100.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
100.16 - * specific language governing permissions and limitations under the
100.17 - * License. When distributing the software, include this License Header
100.18 - * Notice in each file and include the License file at
100.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
100.20 - * particular file as subject to the "Classpath" exception as provided
100.21 - * by Sun in the GPL Version 2 section of the License file that
100.22 - * accompanied this code. If applicable, add the following below the
100.23 - * License Header, with the fields enclosed by brackets [] replaced by
100.24 - * your own identifying information:
100.25 - * "Portions Copyrighted [year] [name of copyright owner]"
100.26 - *
100.27 - * Contributor(s):
100.28 - *
100.29 - * The Original Software is NetBeans. The Initial Developer of the Original
100.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
100.31 - * Microsystems, Inc. All Rights Reserved.
100.32 - *
100.33 - * If you wish your version of this file to be governed by only the CDDL
100.34 - * or only the GPL Version 2, indicate your decision by adding
100.35 - * "[Contributor] elects to include this software in this distribution
100.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
100.37 - * single choice of license, a recipient has the option to distribute
100.38 - * your version of this file under either the CDDL, the GPL Version 2 or
100.39 - * to extend the choice of license to its licensees as provided above.
100.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
100.41 - * Version 2 license, then the option applies only if the new code is
100.42 - * made subject to such option by the copyright holder.
100.43 - */
100.44 -package org.openide.util.lookup;
100.45 -
100.46 -import org.openide.util.lookup.AbstractLookup.Pair;
100.47 -
100.48 -import java.lang.ref.WeakReference;
100.49 -
100.50 -import java.util.*;
100.51 -import java.util.concurrent.Executor;
100.52 -import org.openide.util.Lookup.Item;
100.53 -
100.54 -
100.55 -/** A special content implementation that can be passed to AbstractLookup
100.56 - * and provides methods for registration of instances and lazy instances.
100.57 - * <PRE>
100.58 - * InstanceContent ic = new InstanceContent ();
100.59 - * AbstractLookup al = new AbstractLookup (ic);
100.60 - *
100.61 - * ic.add (new Object ());
100.62 - * ic.add (new Dimension (...));
100.63 - *
100.64 - * Dimension theDim = (Dimension)al.lookup (Dimension.class);
100.65 - * </PRE>
100.66 - *
100.67 - * @author Jaroslav Tulach
100.68 - *
100.69 - * @since 1.25
100.70 - */
100.71 -public final class InstanceContent extends AbstractLookup.Content {
100.72 - /**
100.73 - * Create a new, empty content.
100.74 - */
100.75 - public InstanceContent() {
100.76 - }
100.77 -
100.78 - /** Creates a content associated with an executor to handle dispatch
100.79 - * of changes.
100.80 - * @param notifyIn the executor to notify changes in
100.81 - * @since 7.16
100.82 - */
100.83 - public InstanceContent(Executor notifyIn) {
100.84 - super(notifyIn);
100.85 - }
100.86 - /** The method to add instance to the lookup with.
100.87 - * @param inst instance
100.88 - */
100.89 - public final void add(Object inst) {
100.90 - addPair(new SimpleItem<Object>(inst));
100.91 - }
100.92 -
100.93 - /** Adds a convertible instance into the lookup. The <code>inst</code>
100.94 - * argument is just a key, not the actual value to appear in the lookup.
100.95 - * The value will be created on demand, later when it is really needed
100.96 - * by calling <code>convertor</code> methods.
100.97 - * <p>
100.98 - * This method is useful to delay creation of heavy weight objects.
100.99 - * Instead just register lightweight key and a convertor.
100.100 - * <p>
100.101 - * To remove registered object from lookup use {@link #remove(java.lang.Object, org.openide.util.lookup.InstanceContent.Convertor)}
100.102 - * with the same arguments.
100.103 - *
100.104 - * @param inst instance
100.105 - * @param conv convertor which postponing an instantiation,
100.106 - * if <code>conv==null</code> then the instance is registered directly.
100.107 - */
100.108 - public final <T,R> void add(T inst, Convertor<T,R> conv) {
100.109 - addPair(new ConvertingItem<T,R>(inst, conv));
100.110 - }
100.111 -
100.112 - /** Remove instance.
100.113 - * @param inst instance
100.114 - */
100.115 - public final void remove(Object inst) {
100.116 - removePair(new SimpleItem<Object>(inst));
100.117 - }
100.118 -
100.119 - /** Remove instance added with a convertor.
100.120 - * @param inst instance
100.121 - * @param conv convertor, if <code>conv==null</code> it is same like
100.122 - * remove(Object)
100.123 - */
100.124 - public final <T,R> void remove(T inst, Convertor<T,R> conv) {
100.125 - removePair(new ConvertingItem<T,R>(inst, conv));
100.126 - }
100.127 -
100.128 - /** Changes all pairs in the lookup to new values. Converts collection of
100.129 - * instances to collection of pairs.
100.130 - * @param col the collection of (Item) objects
100.131 - * @param conv the convertor to use or null
100.132 - */
100.133 - public final <T,R> void set(Collection<T> col, Convertor<T,R> conv) {
100.134 - ArrayList<Pair<?>> l = new ArrayList<Pair<?>>(col.size());
100.135 - Iterator<T> it = col.iterator();
100.136 -
100.137 - if (conv == null) {
100.138 - while (it.hasNext()) {
100.139 - l.add(new SimpleItem<T>(it.next()));
100.140 - }
100.141 - } else {
100.142 - while (it.hasNext()) {
100.143 - l.add(new ConvertingItem<T,R>(it.next(), conv));
100.144 - }
100.145 - }
100.146 -
100.147 - setPairs(l);
100.148 - }
100.149 -
100.150 - /** Convertor postpones an instantiation of an object.
100.151 - * @since 1.25
100.152 - */
100.153 - public static interface Convertor<T,R> {
100.154 - /** Convert obj to other object. There is no need to implement
100.155 - * cache mechanism. It is provided by
100.156 - * {@link Item#getInstance()} method itself. However the
100.157 - * method can be called more than once because instance is held
100.158 - * just by weak reference.
100.159 - *
100.160 - * @param obj the registered object
100.161 - * @return the object converted from this object
100.162 - */
100.163 - public R convert(T obj);
100.164 -
100.165 - /** Return type of converted object. Accessible via
100.166 - * {@link Item#getType()}
100.167 - * @param obj the registered object
100.168 - * @return the class that will be produced from this object (class or
100.169 - * superclass of convert (obj))
100.170 - */
100.171 - public Class<? extends R> type(T obj);
100.172 -
100.173 - /** Computes the ID of the resulted object. Accessible via
100.174 - * {@link Item#getId()}.
100.175 - * @param obj the registered object
100.176 - * @return the ID for the object
100.177 - */
100.178 - public String id(T obj);
100.179 -
100.180 - /** The human presentable name for the object. Accessible via
100.181 - * {@link Item#getDisplayName()}.
100.182 - * @param obj the registered object
100.183 - * @return the name representing the object for the user
100.184 - */
100.185 - public String displayName(T obj);
100.186 - }
100.187 -
100.188 - /** Instance of one item representing an object.
100.189 - */
100.190 - final static class SimpleItem<T> extends Pair<T> {
100.191 - private T obj;
100.192 -
100.193 - /** Create an item.
100.194 - * @obj object to register
100.195 - */
100.196 - public SimpleItem(T obj) {
100.197 - if (obj == null) {
100.198 - throw new NullPointerException();
100.199 - }
100.200 - this.obj = obj;
100.201 - }
100.202 -
100.203 - /** Tests whether this item can produce object
100.204 - * of class c.
100.205 - */
100.206 - public boolean instanceOf(Class<?> c) {
100.207 - return c.isInstance(obj);
100.208 - }
100.209 -
100.210 - /** Get instance of registered object. If convertor is specified then
100.211 - * method InstanceLookup.Convertor.convertor is used and weak reference
100.212 - * to converted object is saved.
100.213 - * @return the instance of the object.
100.214 - */
100.215 - public T getInstance() {
100.216 - return obj;
100.217 - }
100.218 -
100.219 - @Override
100.220 - public boolean equals(Object o) {
100.221 - if (o instanceof SimpleItem) {
100.222 - return obj.equals(((SimpleItem) o).obj);
100.223 - } else {
100.224 - return false;
100.225 - }
100.226 - }
100.227 -
100.228 - @Override
100.229 - public int hashCode() {
100.230 - return obj.hashCode();
100.231 - }
100.232 -
100.233 - /** An identity of the item.
100.234 - * @return string representing the item, that can be used for
100.235 - * persistance purposes to locate the same item next time
100.236 - */
100.237 - public String getId() {
100.238 - return "IL[" + obj.toString(); // NOI18N
100.239 - }
100.240 -
100.241 - /** Getter for display name of the item.
100.242 - */
100.243 - public String getDisplayName() {
100.244 - return obj.toString();
100.245 - }
100.246 -
100.247 - /** Method that can test whether an instance of a class has been created
100.248 - * by this item.
100.249 - *
100.250 - * @param obj the instance
100.251 - * @return if the item has already create an instance and it is the same
100.252 - * as obj.
100.253 - */
100.254 - protected boolean creatorOf(Object obj) {
100.255 - return obj == this.obj;
100.256 - }
100.257 -
100.258 - /** The class of this item.
100.259 - * @return the correct class
100.260 - */
100.261 - @SuppressWarnings("unchecked")
100.262 - public Class<? extends T> getType() {
100.263 - return (Class<? extends T>)obj.getClass();
100.264 - }
100.265 - }
100.266 - // end of SimpleItem
100.267 -
100.268 - /** Instance of one item registered in the map.
100.269 - */
100.270 - final static class ConvertingItem<T,R> extends Pair<R> {
100.271 - /** registered object */
100.272 - private T obj;
100.273 -
100.274 - /** Reference to converted object. */
100.275 - private WeakReference<R> ref;
100.276 -
100.277 - /** convertor to use */
100.278 - private Convertor<? super T,R> conv;
100.279 -
100.280 - /** Create an item.
100.281 - * @obj object to register
100.282 - * @conv a convertor, can be <code>null</code>.
100.283 - */
100.284 - public ConvertingItem(T obj, Convertor<? super T,R> conv) {
100.285 - this.obj = obj;
100.286 - this.conv = conv;
100.287 - }
100.288 -
100.289 - /** Tests whether this item can produce object
100.290 - * of class c.
100.291 - */
100.292 - public boolean instanceOf(Class<?> c) {
100.293 - return c.isAssignableFrom(getType());
100.294 - }
100.295 -
100.296 - /** Returns converted object or null if obj has not been converted yet
100.297 - * or reference was cleared by garbage collector.
100.298 - */
100.299 - private R getConverted() {
100.300 - if (ref == null) {
100.301 - return null;
100.302 - }
100.303 -
100.304 - return ref.get();
100.305 - }
100.306 -
100.307 - /** Get instance of registered object. If convertor is specified then
100.308 - * method InstanceLookup.Convertor.convertor is used and weak reference
100.309 - * to converted object is saved.
100.310 - * @return the instance of the object.
100.311 - */
100.312 - public synchronized R getInstance() {
100.313 - R converted = getConverted();
100.314 -
100.315 - if (converted == null) {
100.316 - converted = conv.convert(obj);
100.317 - ref = new WeakReference<R>(converted);
100.318 - }
100.319 -
100.320 - return converted;
100.321 - }
100.322 -
100.323 - @Override
100.324 - public boolean equals(Object o) {
100.325 - if (o instanceof ConvertingItem) {
100.326 - return obj.equals(((ConvertingItem) o).obj);
100.327 - } else {
100.328 - return false;
100.329 - }
100.330 - }
100.331 -
100.332 - @Override
100.333 - public int hashCode() {
100.334 - return obj.hashCode();
100.335 - }
100.336 -
100.337 - /** An identity of the item.
100.338 - * @return string representing the item, that can be used for
100.339 - * persistance purposes to locate the same item next time
100.340 - */
100.341 - public String getId() {
100.342 - return conv.id(obj);
100.343 - }
100.344 -
100.345 - /** Getter for display name of the item.
100.346 - */
100.347 - public String getDisplayName() {
100.348 - return conv.displayName(obj);
100.349 - }
100.350 -
100.351 - /** Method that can test whether an instance of a class has been created
100.352 - * by this item.
100.353 - *
100.354 - * @param obj the instance
100.355 - * @return if the item has already create an instance and it is the same
100.356 - * as obj.
100.357 - */
100.358 - protected boolean creatorOf(Object obj) {
100.359 - if (conv == null) {
100.360 - return obj == this.obj;
100.361 - } else {
100.362 - return obj == getConverted();
100.363 - }
100.364 - }
100.365 -
100.366 - /** The class of this item.
100.367 - * @return the correct class
100.368 - */
100.369 - @SuppressWarnings("unchecked")
100.370 - public Class<? extends R> getType() {
100.371 - R converted = getConverted();
100.372 -
100.373 - if (converted == null) {
100.374 - return conv.type(obj);
100.375 - }
100.376 -
100.377 - return (Class<? extends R>)converted.getClass();
100.378 - }
100.379 - }
100.380 - // end of ConvertingItem
100.381 -}
101.1 --- a/openide.util/src/org/openide/util/lookup/Lookups.java Thu Dec 10 19:23:25 2009 -0500
101.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
101.3 @@ -1,317 +0,0 @@
101.4 -/*
101.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
101.6 - *
101.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
101.8 - *
101.9 - * The contents of this file are subject to the terms of either the GNU
101.10 - * General Public License Version 2 only ("GPL") or the Common
101.11 - * Development and Distribution License("CDDL") (collectively, the
101.12 - * "License"). You may not use this file except in compliance with the
101.13 - * License. You can obtain a copy of the License at
101.14 - * http://www.netbeans.org/cddl-gplv2.html
101.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
101.16 - * specific language governing permissions and limitations under the
101.17 - * License. When distributing the software, include this License Header
101.18 - * Notice in each file and include the License file at
101.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
101.20 - * particular file as subject to the "Classpath" exception as provided
101.21 - * by Sun in the GPL Version 2 section of the License file that
101.22 - * accompanied this code. If applicable, add the following below the
101.23 - * License Header, with the fields enclosed by brackets [] replaced by
101.24 - * your own identifying information:
101.25 - * "Portions Copyrighted [year] [name of copyright owner]"
101.26 - *
101.27 - * Contributor(s):
101.28 - *
101.29 - * The Original Software is NetBeans. The Initial Developer of the Original
101.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
101.31 - * Microsystems, Inc. All Rights Reserved.
101.32 - *
101.33 - * If you wish your version of this file to be governed by only the CDDL
101.34 - * or only the GPL Version 2, indicate your decision by adding
101.35 - * "[Contributor] elects to include this software in this distribution
101.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
101.37 - * single choice of license, a recipient has the option to distribute
101.38 - * your version of this file under either the CDDL, the GPL Version 2 or
101.39 - * to extend the choice of license to its licensees as provided above.
101.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
101.41 - * Version 2 license, then the option applies only if the new code is
101.42 - * made subject to such option by the copyright holder.
101.43 - */
101.44 -
101.45 -package org.openide.util.lookup;
101.46 -
101.47 -import java.util.Arrays;
101.48 -import org.netbeans.modules.openide.util.NamedServicesProvider;
101.49 -import org.openide.util.Lookup;
101.50 -
101.51 -/**
101.52 - * Static factory methods for creating common lookup implementations.
101.53 - *
101.54 - * @author David Strupl
101.55 - * @since 2.21
101.56 - */
101.57 -public class Lookups {
101.58 -
101.59 - /** static methods only */
101.60 - private Lookups() {}
101.61 -
101.62 - /**
101.63 - * Creates a singleton lookup. It means lookup that contains only
101.64 - * one object specified via the supplied parameter. The lookup will
101.65 - * either return the object or null if the supplied template does
101.66 - * not match the class. If the specified argument is null the method
101.67 - * will end with NullPointerException.
101.68 - * @return Fully initialized lookup object ready to use
101.69 - * @throws NullPointerException if the supplied argument is null
101.70 - * @since 2.21
101.71 - */
101.72 - public static Lookup singleton(Object objectToLookup) {
101.73 - if (objectToLookup == null) {
101.74 - throw new NullPointerException();
101.75 - }
101.76 -
101.77 - return new SingletonLookup(objectToLookup);
101.78 - }
101.79 -
101.80 - /**
101.81 - * Creates a lookup that contains an array of objects specified via the
101.82 - * parameter. The resulting lookup is fixed in the following sense: it
101.83 - * contains only fixed set of objects passed in by the array parameter.
101.84 - * Its contents never changes so registering listeners on such lookup
101.85 - * does not have any observable effect (the listeners are never called).
101.86 - *
101.87 - * @param objectsToLookup list of objects to include
101.88 - * @return Fully initialized lookup object ready to use
101.89 - * @throws NullPointerException if the supplied argument is null
101.90 - * @since 2.21
101.91 - *
101.92 - */
101.93 - public static Lookup fixed(Object... objectsToLookup) {
101.94 - if (objectsToLookup == null) {
101.95 - throw new NullPointerException();
101.96 - }
101.97 -
101.98 - if (objectsToLookup.length == 0) {
101.99 - return Lookup.EMPTY;
101.100 - }
101.101 -
101.102 - if (objectsToLookup.length == 1) {
101.103 - return singleton(objectsToLookup[0]);
101.104 - }
101.105 -
101.106 - return new SimpleLookup(Arrays.asList(objectsToLookup));
101.107 - }
101.108 -
101.109 - /**
101.110 - * Creates a lookup that contains an array of objects specified via the
101.111 - * parameter. The resulting lookup is fixed in the following sense: it
101.112 - * contains only fixed set of objects passed in by the array parameter.
101.113 - * The objects returned from this lookup are converted to real objects
101.114 - * before they are returned by the lookup.
101.115 - * Its contents never changes so registering listeners on such lookup
101.116 - * does not have any observable effect (the listeners are never called).
101.117 - *
101.118 - * @return Fully initialized lookup object ready to use
101.119 - * @throws NullPointerException if the any of the arguments is null
101.120 - * @since 2.21
101.121 - *
101.122 - */
101.123 - public static <T,R> Lookup fixed(T[] keys, InstanceContent.Convertor<? super T,R> convertor) {
101.124 - if (keys == null) {
101.125 - throw new NullPointerException();
101.126 - }
101.127 -
101.128 - if (convertor == null) {
101.129 - throw new NullPointerException();
101.130 - }
101.131 -
101.132 - return new SimpleLookup(Arrays.asList(keys), convertor);
101.133 - }
101.134 -
101.135 - /** Creates a lookup that delegates to another one but that one can change
101.136 - * from time to time. The returned lookup checks every time somebody calls
101.137 - * <code>lookup</code> or <code>lookupItem</code> method whether the
101.138 - * provider still returns the same lookup. If not, it updates state of
101.139 - * all {@link org.openide.util.Lookup.Result}s
101.140 - * that it created (and that still exists).
101.141 - * <P>
101.142 - * The user of this method has to implement its provider's <code>getLookup</code>
101.143 - * method (must be thread safe and fast, will be called often and from any thread)
101.144 - * pass it to this method and use the returned lookup. Whenever the user
101.145 - * changes the return value from the <code>getLookup</code> method and wants
101.146 - * to notify listeners on the lookup about that it should trigger the event
101.147 - * firing, for example by calling <code>lookup.lookup (Object.class)</code>
101.148 - * directly on the lookup returned by this method
101.149 - * that forces a check of the return value of {@link org.openide.util.Lookup.Provider#getLookup}</code>.
101.150 - *
101.151 - * @param provider the provider that returns a lookup to delegate to
101.152 - * @return lookup delegating to the lookup returned by the provider
101.153 - * @since 3.9
101.154 - */
101.155 - public static Lookup proxy(Lookup.Provider provider) {
101.156 - return new SimpleProxyLookup(provider);
101.157 - }
101.158 -
101.159 - /** Returns a lookup that implements the JDK1.3 JAR services mechanism and delegates
101.160 - * to META-INF/services/name.of.class files.
101.161 - * <p>Some extensions to the JAR services specification are implemented:
101.162 - * <ol>
101.163 - * <li>An entry may be followed by a line of the form <code>#position=<i>integer</i></code>
101.164 - * to specify ordering. (Smaller numbers first, entries with unspecified position last.)
101.165 - * <li>A line of the form <code>#-<i>classname</i></code> suppresses an entry registered
101.166 - * in another file, so can be used to supersede one implementation with another.
101.167 - * </ol>
101.168 - * <p>Note: It is not dynamic - so if you need to change the classloader or JARs,
101.169 - * wrap it in a {@link ProxyLookup} and change the delegate when necessary.
101.170 - * Existing instances will be kept if the implementation classes are unchanged,
101.171 - * so there is "stability" in doing this provided some parent loaders are the same
101.172 - * as the previous ones.
101.173 - * @since 3.35
101.174 - * @see ServiceProvider
101.175 - */
101.176 - public static Lookup metaInfServices(ClassLoader classLoader) {
101.177 - return new MetaInfServicesLookup(classLoader, "META-INF/services/"); // NOI18N
101.178 - }
101.179 -
101.180 - /** Returns a lookup that behaves exactly like {@link #metaInfServices(ClassLoader)}
101.181 - * except that it does not read data from <code>META-INF/services/</code>, but instead
101.182 - * from the specified prefix.
101.183 - * @param classLoader class loader to use for loading
101.184 - * @param prefix prefix to prepend to the class name when searching
101.185 - * @since 7.9
101.186 - */
101.187 - public static Lookup metaInfServices(ClassLoader classLoader, String prefix) {
101.188 - return new MetaInfServicesLookup(classLoader, prefix);
101.189 - }
101.190 -
101.191 - /** Creates a <q>named</q> lookup.
101.192 - * It is a lookup identified by a given path.
101.193 - * Two lookups with the same path should have the same content.
101.194 - * <p>It is expected that each <q>named</q> lookup
101.195 - * will contain a superset of what would be created by:
101.196 - * <code>{@linkplain #metaInfServices(ClassLoader,String) metaInfServices}(theRightLoader, "META-INF/namedservices/" + path + "/")</code>
101.197 - *
101.198 - * <p class="nonnormative">Various environments can add their own
101.199 - * extensions to its content. As such
101.200 - * {@link Lookups#forPath(java.lang.String)} can combine lookups
101.201 - * from several sources. In current NetBeans Runtime Container, two lookups are used:
101.202 - * </p>
101.203 - * <ul class="nonnormative">
101.204 - * <li><code>Lookups.metaInfServices("META-INF/namedservices/" + path)</code></li>
101.205 - * <li><code>org.openide.loaders.FolderLookup(path)</code></li>
101.206 - * </ul>
101.207 - * <p class="nonnormative">
101.208 - * Please note that these lookups differ in the way they inspect sub-folders.
101.209 - * The first lookup just returns instances from the given path, ignoring
101.210 - * sub-folders, the second one retrieves instances from the whole sub-tree.
101.211 - * </p>
101.212 - * <p>
101.213 - * Read more about the <a href="../doc-files/api.html#folderlookup">usage of this method</a>.
101.214 - *
101.215 - * @param path the path identifying the lookup, e.g. <code>Projects/Actions</code>
101.216 - * @return lookup associated with this path
101.217 - * @since 7.9
101.218 - */
101.219 - public static Lookup forPath(String path) {
101.220 - return NamedServicesProvider.find(path);
101.221 - }
101.222 -
101.223 - /** Creates a lookup that wraps another one and filters out instances
101.224 - * of specified classes. If you have a lookup and
101.225 - * you want to remove all instances of ActionMap you can use:
101.226 - * <pre>
101.227 - * l = Lookups.exclude(lookup, ActionMap.class);
101.228 - * </pre>
101.229 - * Then anybody who asks for <code>l.lookup(ActionMap.class)</code> or
101.230 - * subclass will get <code>null</code>. Even if the original lookup contains the
101.231 - * value.
101.232 - * To create empty lookup (well, just an example, otherwise use {@link Lookup#EMPTY}) one could use:
101.233 - * <pre>
101.234 - * Lookup.exclude(anyLookup, Object.class);
101.235 - * </pre>
101.236 - * as any instance in any lookup is of type Object and thus would be excluded.
101.237 - * <p>
101.238 - * The complete behavior can be described as <code>classes</code> being
101.239 - * a barrier. For an object not to be excluded, there has to be an inheritance
101.240 - * path between the queried class and the actual class of the instance,
101.241 - * that is not blocked by any of the excluded classes:
101.242 - * <pre>
101.243 - * interface A {}
101.244 - * interface B {}
101.245 - * class C implements A, B {}
101.246 - * Object c = new C();
101.247 - * Lookup l1 = Lookups.singleton(c);
101.248 - * Lookup l2 = Lookups.exclude(l1, A.class);
101.249 - * assertNull("A is directly excluded", l2.lookup(A.class));
101.250 - * assertEquals("Returns C as A.class is not between B and C", c, l2.lookup(B.class));
101.251 - * </pre>
101.252 - * For more info check the
101.253 - * <a href="http://hg.netbeans.org/main-golden/annotate/4883eaeda744/openide.util/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java">
101.254 - * excluding lookup tests</a> and the discussion in issue
101.255 - * <a href="http://openide.netbeans.org/issues/show_bug.cgi?id=53058">53058</a>.
101.256 - *
101.257 - * @param lookup the original lookup that should be filtered
101.258 - * @param classes array of classes those instances should be excluded
101.259 - * @since 5.4
101.260 - */
101.261 - public static Lookup exclude(Lookup lookup, Class... classes) {
101.262 - return new ExcludingLookup(lookup, classes);
101.263 - }
101.264 -
101.265 - /** Creates <code>Lookup.Item</code> representing the instance passed in.
101.266 - *
101.267 - * @param instance the object for which Lookup.Item should be creted
101.268 - * @param id unique identification of the object, for details see {@link org.openide.util.Lookup.Item#getId},
101.269 - * can be <code>null</code>
101.270 - * @return lookup item representing instance
101.271 - * @since 4.8
101.272 - */
101.273 - public static <T> Lookup.Item<T> lookupItem(T instance, String id) {
101.274 - return new LookupItem<T>(instance, id);
101.275 - }
101.276 -
101.277 - private static class LookupItem<T> extends Lookup.Item<T> {
101.278 - private String id;
101.279 - private T instance;
101.280 -
101.281 - public LookupItem(T instance) {
101.282 - this(instance, null);
101.283 - }
101.284 -
101.285 - public LookupItem(T instance, String id) {
101.286 - this.id = id;
101.287 - this.instance = instance;
101.288 - }
101.289 -
101.290 - public String getDisplayName() {
101.291 - return getId();
101.292 - }
101.293 -
101.294 - public String getId() {
101.295 - return (id == null) ? instance.toString() : id;
101.296 - }
101.297 -
101.298 - public T getInstance() {
101.299 - return instance;
101.300 - }
101.301 -
101.302 - @SuppressWarnings("unchecked")
101.303 - public Class<? extends T> getType() {
101.304 - return (Class<? extends T>)instance.getClass();
101.305 - }
101.306 -
101.307 - public @Override boolean equals(Object object) {
101.308 - if (object instanceof LookupItem) {
101.309 - return instance == ((LookupItem) object).getInstance();
101.310 - }
101.311 -
101.312 - return false;
101.313 - }
101.314 -
101.315 - public @Override int hashCode() {
101.316 - return instance.hashCode();
101.317 - }
101.318 - }
101.319 - // End of LookupItem class
101.320 -}
102.1 --- a/openide.util/src/org/openide/util/lookup/MetaInfServicesLookup.java Thu Dec 10 19:23:25 2009 -0500
102.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
102.3 @@ -1,559 +0,0 @@
102.4 -/*
102.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
102.6 - *
102.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
102.8 - *
102.9 - * The contents of this file are subject to the terms of either the GNU
102.10 - * General Public License Version 2 only ("GPL") or the Common
102.11 - * Development and Distribution License("CDDL") (collectively, the
102.12 - * "License"). You may not use this file except in compliance with the
102.13 - * License. You can obtain a copy of the License at
102.14 - * http://www.netbeans.org/cddl-gplv2.html
102.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
102.16 - * specific language governing permissions and limitations under the
102.17 - * License. When distributing the software, include this License Header
102.18 - * Notice in each file and include the License file at
102.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
102.20 - * particular file as subject to the "Classpath" exception as provided
102.21 - * by Sun in the GPL Version 2 section of the License file that
102.22 - * accompanied this code. If applicable, add the following below the
102.23 - * License Header, with the fields enclosed by brackets [] replaced by
102.24 - * your own identifying information:
102.25 - * "Portions Copyrighted [year] [name of copyright owner]"
102.26 - *
102.27 - * Contributor(s):
102.28 - *
102.29 - * The Original Software is NetBeans. The Initial Developer of the Original
102.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
102.31 - * Microsystems, Inc. All Rights Reserved.
102.32 - *
102.33 - * If you wish your version of this file to be governed by only the CDDL
102.34 - * or only the GPL Version 2, indicate your decision by adding
102.35 - * "[Contributor] elects to include this software in this distribution
102.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
102.37 - * single choice of license, a recipient has the option to distribute
102.38 - * your version of this file under either the CDDL, the GPL Version 2 or
102.39 - * to extend the choice of license to its licensees as provided above.
102.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
102.41 - * Version 2 license, then the option applies only if the new code is
102.42 - * made subject to such option by the copyright holder.
102.43 - */
102.44 -
102.45 -package org.openide.util.lookup;
102.46 -
102.47 -import java.io.BufferedReader;
102.48 -import java.io.IOException;
102.49 -import java.io.InputStream;
102.50 -import java.io.InputStreamReader;
102.51 -import java.lang.ref.Reference;
102.52 -import java.lang.ref.WeakReference;
102.53 -import java.lang.reflect.Method;
102.54 -import java.net.URL;
102.55 -import java.util.ArrayList;
102.56 -import java.util.Collection;
102.57 -import java.util.Enumeration;
102.58 -import java.util.HashSet;
102.59 -import java.util.LinkedHashSet;
102.60 -import java.util.List;
102.61 -import java.util.Map;
102.62 -import java.util.WeakHashMap;
102.63 -import java.util.logging.Level;
102.64 -import java.util.logging.Logger;
102.65 -import org.openide.util.Lookup;
102.66 -import org.openide.util.RequestProcessor;
102.67 -
102.68 -/**
102.69 - * @author Jaroslav Tulach, Jesse Glick
102.70 - * @see Lookups#metaInfServices(ClassLoader,String)
102.71 - * @see "#14722"
102.72 - */
102.73 -final class MetaInfServicesLookup extends AbstractLookup {
102.74 -
102.75 - private static final Logger LOGGER = Logger.getLogger(MetaInfServicesLookup.class.getName());
102.76 - static final RequestProcessor RP = new RequestProcessor(MetaInfServicesLookup.class.getName(), 1);
102.77 - private static int knownInstancesCount;
102.78 - private static final List<Reference<Object>> knownInstances;
102.79 - static {
102.80 - knownInstances = new ArrayList<Reference<Object>>();
102.81 - for (int i = 0; i < 512; i++) {
102.82 - knownInstances.add(null);
102.83 - }
102.84 - }
102.85 -
102.86 - /** A set of all requested classes.
102.87 - * Note that classes that we actually succeeded on can never be removed
102.88 - * from here because we hold a strong reference to the loader.
102.89 - * However we also hold classes which are definitely not loadable by
102.90 - * our loader.
102.91 - */
102.92 - private final Map<Class,Object> classes = new WeakHashMap<Class,Object>();
102.93 -
102.94 - /** class loader to use */
102.95 - private final ClassLoader loader;
102.96 - /** prefix to prepend */
102.97 - private final String prefix;
102.98 -
102.99 - /** Create a lookup reading from a specified classloader.
102.100 - */
102.101 - public MetaInfServicesLookup(ClassLoader loader, String prefix) {
102.102 - this.loader = loader;
102.103 - this.prefix = prefix;
102.104 -
102.105 - LOGGER.log(Level.FINE, "Created: {0}", this);
102.106 - }
102.107 -
102.108 - @Override
102.109 - public String toString() {
102.110 - return "MetaInfServicesLookup[" + loader + "]"; // NOI18N
102.111 - }
102.112 -
102.113 - /* Tries to load appropriate resources from manifest files.
102.114 - */
102.115 - @Override
102.116 - protected final void beforeLookup(Lookup.Template t) {
102.117 - Class c = t.getType();
102.118 -
102.119 - Collection<AbstractLookup.Pair<?>> toAdd = null;
102.120 - synchronized (this) {
102.121 - if (classes.get(c) == null) { // NOI18N
102.122 - toAdd = new ArrayList<Pair<?>>();
102.123 - } else {
102.124 - // ok, nothing needs to be done
102.125 - return;
102.126 - }
102.127 - }
102.128 - if (toAdd != null) {
102.129 - search(c, toAdd);
102.130 - }
102.131 - synchronized (this) {
102.132 - if (classes.put(c, "") == null) { // NOI18N
102.133 - // Added new class, search for it.
102.134 - LinkedHashSet<AbstractLookup.Pair<?>> arr = getPairsAsLHS();
102.135 - arr.addAll(toAdd);
102.136 - setPairs(arr, RP);
102.137 - }
102.138 - }
102.139 - }
102.140 -
102.141 - /** Finds all pairs and adds them to the collection.
102.142 - *
102.143 - * @param clazz class to find
102.144 - * @param result collection to add Pair to
102.145 - */
102.146 - private void search(Class<?> clazz, Collection<AbstractLookup.Pair<?>> result) {
102.147 - if (LOGGER.isLoggable(Level.FINER)) {
102.148 - LOGGER.log(Level.FINER, "Searching for " + clazz.getName() + " in " + clazz.getClassLoader() + " from " + this);
102.149 - }
102.150 -
102.151 - String res = prefix + clazz.getName(); // NOI18N
102.152 - Enumeration<URL> en;
102.153 -
102.154 - try {
102.155 - en = loader.getResources(res);
102.156 - } catch (IOException ioe) {
102.157 - // do not use ErrorManager because we are in the startup code
102.158 - // and ErrorManager might not be ready
102.159 - ioe.printStackTrace();
102.160 -
102.161 - return;
102.162 - }
102.163 -
102.164 - // Do not create multiple instances in case more than one JAR
102.165 - // has the same entry in it (and they load to the same class).
102.166 - // Probably would not happen, assuming JARs only list classes
102.167 - // they own, but just in case...
102.168 - List<Item> foundClasses = new ArrayList<Item>();
102.169 - Collection<Class> removeClasses = new ArrayList<Class>();
102.170 -
102.171 - boolean foundOne = false;
102.172 -
102.173 - while (en.hasMoreElements()) {
102.174 - if (!foundOne) {
102.175 - foundOne = true;
102.176 -
102.177 - // Double-check that in fact we can load the *interface* class.
102.178 - // For example, say class I is defined in two JARs, J1 and J2.
102.179 - // There is also an implementation M1 defined in J1, and another
102.180 - // implementation M2 defined in J2.
102.181 - // Classloaders C1 and C2 are made from J1 and J2.
102.182 - // A MetaInfServicesLookup is made from C1. Then the user asks to
102.183 - // lookup I as loaded from C2. J1 has the services line and lists
102.184 - // M1, and we can in fact make it. However it is not of the desired
102.185 - // type to be looked up. Don't do this check, which could be expensive,
102.186 - // unless we expect to be getting some results, however.
102.187 - Class realMcCoy = null;
102.188 -
102.189 - try {
102.190 - realMcCoy = loader.loadClass(clazz.getName());
102.191 - } catch (ClassNotFoundException cnfe) {
102.192 - // our loader does not know about it, OK
102.193 - }
102.194 -
102.195 - if (realMcCoy != clazz) {
102.196 - // Either the interface class is not available at all in our loader,
102.197 - // or it is not the same version as we expected. Don't provide results.
102.198 - if (LOGGER.isLoggable(Level.WARNING)) {
102.199 - if (realMcCoy != null) {
102.200 - LOGGER.log(Level.WARNING,
102.201 - clazz.getName() + " is not the real McCoy! Actually found it in " +
102.202 - realMcCoy.getClassLoader()
102.203 - ); // NOI18N
102.204 - } else {
102.205 - LOGGER.log(Level.WARNING, clazz.getName() + " could not be found in " + loader); // NOI18N
102.206 - }
102.207 - }
102.208 -
102.209 - return;
102.210 - }
102.211 - }
102.212 -
102.213 - URL url = en.nextElement();
102.214 - Item currentItem = null;
102.215 -
102.216 - try {
102.217 - InputStream is = url.openStream();
102.218 -
102.219 - try {
102.220 - BufferedReader reader = new BufferedReader(new InputStreamReader(is, "UTF-8")); // NOI18N
102.221 -
102.222 - while (true) {
102.223 - String line = reader.readLine();
102.224 -
102.225 - if (line == null) {
102.226 - break;
102.227 - }
102.228 -
102.229 - line = line.trim();
102.230 -
102.231 - // is it position attribute?
102.232 - if (line.startsWith("#position=")) {
102.233 - if (currentItem == null) {
102.234 - LOGGER.log(Level.WARNING, "Found line '{0}' in {1} but there is no item to associate it with", new Object[] {line, url});
102.235 - continue;
102.236 - }
102.237 -
102.238 - try {
102.239 - currentItem.position = Integer.parseInt(line.substring(10));
102.240 - } catch (NumberFormatException e) {
102.241 - // do not use ErrorManager because we are in the startup code
102.242 - // and ErrorManager might not be ready
102.243 - e.printStackTrace();
102.244 - }
102.245 - }
102.246 -
102.247 - if (currentItem != null) {
102.248 - insertItem(currentItem, foundClasses);
102.249 - currentItem = null;
102.250 - }
102.251 -
102.252 - // Ignore blank lines and comments.
102.253 - if (line.length() == 0) {
102.254 - continue;
102.255 - }
102.256 -
102.257 - boolean remove = false;
102.258 -
102.259 - if (line.charAt(0) == '#') {
102.260 - if ((line.length() == 1) || (line.charAt(1) != '-')) {
102.261 - continue;
102.262 - }
102.263 -
102.264 - // line starting with #- is a sign to remove that class from lookup
102.265 - remove = true;
102.266 - line = line.substring(2);
102.267 - }
102.268 -
102.269 - Class inst = null;
102.270 -
102.271 - try {
102.272 - // Most lines are fully-qualified class names.
102.273 - inst = Class.forName(line, false, loader);
102.274 - } catch (ClassNotFoundException cnfe) {
102.275 - if (remove) {
102.276 - // if we are removing somthing and the something
102.277 - // cannot be found it is ok to do nothing
102.278 - continue;
102.279 - } else {
102.280 - // but if we are not removing just rethrow
102.281 - throw cnfe;
102.282 - }
102.283 - }
102.284 -
102.285 - if (!clazz.isAssignableFrom(inst)) {
102.286 - throw new ClassNotFoundException(clazzToString(inst) + " not a subclass of " + clazzToString(clazz)); // NOI18N
102.287 - }
102.288 -
102.289 - if (remove) {
102.290 - removeClasses.add(inst);
102.291 - } else {
102.292 - // create new item here, but do not put it into
102.293 - // foundClasses array yet because following line
102.294 - // might specify its position
102.295 - currentItem = new Item();
102.296 - currentItem.clazz = inst;
102.297 - }
102.298 - }
102.299 -
102.300 - if (currentItem != null) {
102.301 - insertItem(currentItem, foundClasses);
102.302 - currentItem = null;
102.303 - }
102.304 - } finally {
102.305 - is.close();
102.306 - }
102.307 - } catch (ClassNotFoundException ex) {
102.308 - LOGGER.log(Level.WARNING, null, ex);
102.309 - } catch (IOException ex) {
102.310 - LOGGER.log(Level.WARNING, null, ex);
102.311 - }
102.312 - }
102.313 -
102.314 - LOGGER.log(Level.FINER, "Found impls of {0}: {1} and removed: {2} from: {3}", new Object[] {clazz.getName(), foundClasses, removeClasses, this});
102.315 -
102.316 - foundClasses.removeAll(removeClasses);
102.317 -
102.318 - for (Item item : foundClasses) {
102.319 - if (removeClasses.contains(item.clazz)) {
102.320 - continue;
102.321 - }
102.322 -
102.323 - result.add(new P(item.clazz));
102.324 - }
102.325 - }
102.326 - private static String clazzToString(Class clazz) {
102.327 - return clazz.getName() + "@" + clazz.getClassLoader() + ":" + clazz.getProtectionDomain().getCodeSource().getLocation(); // NOI18N
102.328 - }
102.329 -
102.330 - /**
102.331 - * Insert item to the list according to item.position value.
102.332 - */
102.333 - private void insertItem(Item item, List<Item> list) {
102.334 - // no position? -> add it to the end
102.335 - if (item.position == -1) {
102.336 - list.add(item);
102.337 -
102.338 - return;
102.339 - }
102.340 -
102.341 - int index = -1;
102.342 - for (Item i : list) {
102.343 - index++;
102.344 -
102.345 - if (i.position == -1) {
102.346 - list.add(index, item);
102.347 -
102.348 - return;
102.349 - } else {
102.350 - if (i.position > item.position) {
102.351 - list.add(index, item);
102.352 -
102.353 - return;
102.354 - }
102.355 - }
102.356 - }
102.357 -
102.358 - list.add(item);
102.359 - }
102.360 -
102.361 - private static class Item {
102.362 - private Class clazz;
102.363 - private int position = -1;
102.364 - @Override
102.365 - public String toString() {
102.366 - return "MetaInfServicesLookup.Item[" + clazz.getName() + "]"; // NOI18N
102.367 - }
102.368 - }
102.369 -
102.370 - /** Pair that holds name of a class and maybe the instance.
102.371 - */
102.372 - private static final class P extends AbstractLookup.Pair<Object> {
102.373 - /** May be one of three things:
102.374 - * 1. The implementation class which was named in the services file.
102.375 - * 2. An instance of it.
102.376 - * 3. Null, if creation of the instance resulted in an error.
102.377 - */
102.378 - private Object object;
102.379 -
102.380 - public P(Class<?> clazz) {
102.381 - this.object = clazz;
102.382 - }
102.383 -
102.384 - /** Finds the class.
102.385 - */
102.386 - private Class<? extends Object> clazz() {
102.387 - Object o = object;
102.388 -
102.389 - if (o instanceof Class) {
102.390 - return (Class<? extends Object>) o;
102.391 - } else if (o != null) {
102.392 - return o.getClass();
102.393 - } else {
102.394 - // Broken.
102.395 - return Object.class;
102.396 - }
102.397 - }
102.398 -
102.399 - @Override
102.400 - public boolean equals(Object o) {
102.401 - if (o instanceof P) {
102.402 - return ((P) o).clazz().equals(clazz());
102.403 - }
102.404 -
102.405 - return false;
102.406 - }
102.407 -
102.408 - @Override
102.409 - public int hashCode() {
102.410 - return clazz().hashCode();
102.411 - }
102.412 -
102.413 - protected boolean instanceOf(Class<?> c) {
102.414 - return c.isAssignableFrom(clazz());
102.415 - }
102.416 -
102.417 - public Class<?> getType() {
102.418 - return clazz();
102.419 - }
102.420 -
102.421 - public Object getInstance() {
102.422 - Object o = object; // keeping local copy to avoid another
102.423 -
102.424 - // thread to modify it under my hands
102.425 - if (o instanceof Class) {
102.426 - synchronized (o) { // o is Class and we will not create
102.427 - // 2 instances of the same class
102.428 -
102.429 - try {
102.430 - Class<?> c = ((Class) o);
102.431 - o = null;
102.432 -
102.433 - synchronized (knownInstances) { // guards only the static cache
102.434 - int size = knownInstances.size();
102.435 - int index = c.hashCode() % size;
102.436 - for (int i = 0; i < size; i++) {
102.437 - Reference<Object> ref = knownInstances.get(index);
102.438 - Object obj = ref == null ? null : ref.get();
102.439 - if (obj == null) {
102.440 - break;
102.441 - }
102.442 - if (c == obj.getClass()) {
102.443 - o = obj;
102.444 - break;
102.445 - }
102.446 - if (++index == size) {
102.447 - index = 0;
102.448 - }
102.449 - }
102.450 - }
102.451 -
102.452 - if (o == null) {
102.453 - o = createInstance(c);
102.454 -
102.455 - synchronized (knownInstances) { // guards only the static cache
102.456 - hashPut(o);
102.457 -
102.458 - int size = knownInstances.size();
102.459 - if (knownInstancesCount > size * 2 / 3) {
102.460 - LOGGER.log(Level.CONFIG, "Cache of size {0} is 2/3 full. Rehashing.", size);
102.461 - HashSet<Reference<Object>> all = new HashSet<Reference<Object>>();
102.462 - all.addAll(knownInstances);
102.463 - for (int i = 0; i < size; i++) {
102.464 - knownInstances.set(i, null);
102.465 - }
102.466 - for (int i = 0; i < size; i++) {
102.467 - knownInstances.add(null);
102.468 - }
102.469 - knownInstancesCount = 0;
102.470 - for (Reference<Object> r : all) {
102.471 - if (r == null) {
102.472 - continue;
102.473 - }
102.474 - Object instance = r.get();
102.475 - if (instance == null) {
102.476 - continue;
102.477 - }
102.478 - hashPut(instance);
102.479 - }
102.480 - }
102.481 -
102.482 - }
102.483 - }
102.484 -
102.485 - // Do not assign to instance var unless there is a complete synch
102.486 - // block between the newInstance and this line. Otherwise we could
102.487 - // be assigning a half-constructed instance that another thread
102.488 - // could see and return immediately.
102.489 - object = o;
102.490 - } catch (Exception ex) {
102.491 - LOGGER.log(Level.WARNING, "Cannot create " + object, ex);
102.492 - object = null;
102.493 - } catch (ExceptionInInitializerError x) { // #174055
102.494 - LOGGER.log(Level.WARNING, "Cannot create " + object, x);
102.495 - object = null;
102.496 - }
102.497 - }
102.498 - }
102.499 -
102.500 - return object;
102.501 - }
102.502 -
102.503 - public String getDisplayName() {
102.504 - return clazz().getName();
102.505 - }
102.506 -
102.507 - public String getId() {
102.508 - return clazz().getName();
102.509 - }
102.510 -
102.511 - protected boolean creatorOf(Object obj) {
102.512 - return obj == object;
102.513 - }
102.514 -
102.515 - private static void hashPut(Object o) {
102.516 - Class<?> c = o.getClass();
102.517 - int size = knownInstances.size();
102.518 - int index = c.hashCode() % size;
102.519 - for (int i = 0; i < size; i++) {
102.520 - Reference<Object> ref = knownInstances.get(index);
102.521 - Object obj = ref == null ? null : ref.get();
102.522 - if (obj == null) {
102.523 - knownInstances.set(index, new WeakReference<Object>(o));
102.524 - knownInstancesCount++;
102.525 - break;
102.526 - }
102.527 - if (++index == size) {
102.528 - index = 0;
102.529 - }
102.530 - }
102.531 - }
102.532 -
102.533 - private static boolean findSharedClassObjectSkip;
102.534 - private static Method findSharedClassObject;
102.535 - /** Basically does c.newInstance(), however the method is complicated
102.536 - * with a special behaviour for old and almost obsoleted NetBeans
102.537 - * class: SharedClassObject.
102.538 - */
102.539 - private static Object createInstance(Class<?> c) throws InstantiationException, IllegalAccessException {
102.540 - if (!findSharedClassObjectSkip) {
102.541 - try {
102.542 - if (findSharedClassObject == null) {
102.543 - Class<?> sco;
102.544 - try {
102.545 - sco = Class.forName("org.openide.util.SharedClassObject"); // NOI18N
102.546 - } catch (ClassNotFoundException ex) {
102.547 - findSharedClassObjectSkip = true;
102.548 - return c.newInstance();
102.549 - }
102.550 - findSharedClassObject = sco.getMethod("findObject", Class.class, boolean.class);
102.551 - }
102.552 - if (findSharedClassObject.getReturnType().isAssignableFrom(c)) {
102.553 - return findSharedClassObject.invoke(null, c, true);
102.554 - }
102.555 - } catch (Exception problem) {
102.556 - throw (InstantiationException)new InstantiationException(problem.getMessage()).initCause(problem);
102.557 - }
102.558 - }
102.559 - return c.newInstance();
102.560 - }
102.561 - }
102.562 -}
103.1 --- a/openide.util/src/org/openide/util/lookup/ProxyLookup.java Thu Dec 10 19:23:25 2009 -0500
103.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
103.3 @@ -1,980 +0,0 @@
103.4 -/*
103.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
103.6 - *
103.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
103.8 - *
103.9 - * The contents of this file are subject to the terms of either the GNU
103.10 - * General Public License Version 2 only ("GPL") or the Common
103.11 - * Development and Distribution License("CDDL") (collectively, the
103.12 - * "License"). You may not use this file except in compliance with the
103.13 - * License. You can obtain a copy of the License at
103.14 - * http://www.netbeans.org/cddl-gplv2.html
103.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
103.16 - * specific language governing permissions and limitations under the
103.17 - * License. When distributing the software, include this License Header
103.18 - * Notice in each file and include the License file at
103.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
103.20 - * particular file as subject to the "Classpath" exception as provided
103.21 - * by Sun in the GPL Version 2 section of the License file that
103.22 - * accompanied this code. If applicable, add the following below the
103.23 - * License Header, with the fields enclosed by brackets [] replaced by
103.24 - * your own identifying information:
103.25 - * "Portions Copyrighted [year] [name of copyright owner]"
103.26 - *
103.27 - * Contributor(s):
103.28 - *
103.29 - * The Original Software is NetBeans. The Initial Developer of the Original
103.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
103.31 - * Microsystems, Inc. All Rights Reserved.
103.32 - *
103.33 - * If you wish your version of this file to be governed by only the CDDL
103.34 - * or only the GPL Version 2, indicate your decision by adding
103.35 - * "[Contributor] elects to include this software in this distribution
103.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
103.37 - * single choice of license, a recipient has the option to distribute
103.38 - * your version of this file under either the CDDL, the GPL Version 2 or
103.39 - * to extend the choice of license to its licensees as provided above.
103.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
103.41 - * Version 2 license, then the option applies only if the new code is
103.42 - * made subject to such option by the copyright holder.
103.43 - */
103.44 -
103.45 -package org.openide.util.lookup;
103.46 -
103.47 -import java.lang.ref.Reference;
103.48 -import java.lang.ref.WeakReference;
103.49 -import java.util.ArrayList;
103.50 -import java.util.Arrays;
103.51 -import java.util.Collection;
103.52 -import java.util.Collections;
103.53 -import java.util.HashMap;
103.54 -import java.util.HashSet;
103.55 -import java.util.IdentityHashMap;
103.56 -import java.util.Iterator;
103.57 -import java.util.List;
103.58 -import java.util.Map;
103.59 -import java.util.Map.Entry;
103.60 -import java.util.Set;
103.61 -import java.util.concurrent.Executor;
103.62 -import javax.swing.event.EventListenerList;
103.63 -import org.openide.util.Lookup;
103.64 -import org.openide.util.LookupEvent;
103.65 -import org.openide.util.LookupListener;
103.66 -
103.67 -/** Implementation of lookup that can delegate to others.
103.68 - *
103.69 - * @author Jaroslav Tulach
103.70 - * @since 1.9
103.71 - */
103.72 -public class ProxyLookup extends Lookup {
103.73 - /** data representing the state of the lookup */
103.74 - private ImmutableInternalData data;
103.75 -
103.76 - /** Create a proxy to some other lookups.
103.77 - * @param lookups the initial delegates
103.78 - */
103.79 - public ProxyLookup(Lookup... lookups) {
103.80 - data = ImmutableInternalData.EMPTY.setLookupsNoFire(lookups, true);
103.81 - }
103.82 -
103.83 - /**
103.84 - * Create a lookup initially proxying to no others.
103.85 - * Permits serializable subclasses.
103.86 - * @since 3.27
103.87 - */
103.88 - protected ProxyLookup() {
103.89 - data = ImmutableInternalData.EMPTY;
103.90 - }
103.91 -
103.92 - @Override
103.93 - public synchronized String toString() {
103.94 - return "ProxyLookup(class=" + getClass() + ")->" + Arrays.asList(getData().getLookups(false)); // NOI18N
103.95 - }
103.96 -
103.97 - /** Getter for the delegates.
103.98 - * @return the array of lookups we delegate to
103.99 - * @since 1.19
103.100 - */
103.101 - protected final Lookup[] getLookups() {
103.102 - synchronized (ProxyLookup.this) {
103.103 - return getData().getLookups(true);
103.104 - }
103.105 - }
103.106 -
103.107 - private Set<Lookup> identityHashSet(Collection<Lookup> current) {
103.108 - Map<Lookup,Void> map = new IdentityHashMap<Lookup, Void>();
103.109 - for (Lookup lookup : current) {
103.110 - map.put(lookup, null);
103.111 - }
103.112 - return map.keySet();
103.113 - }
103.114 -
103.115 - /**
103.116 - * Changes the delegates.
103.117 - *
103.118 - * @param lookups the new lookups to delegate to
103.119 - * @since 1.19 protected
103.120 - */
103.121 - protected final void setLookups(Lookup... lookups) {
103.122 - setLookups(null, lookups);
103.123 - }
103.124 -
103.125 - /**
103.126 - * Changes the delegates immediatelly, notifies the listeners in provided
103.127 - * executor, potentially later.
103.128 - *
103.129 - * @param lookups the new lookups to delegate to
103.130 - * @param notifyIn executor to deliver the notification to listeners or null
103.131 - * @since 7.16
103.132 - */
103.133 - protected final void setLookups(Executor notifyIn, Lookup... lookups) {
103.134 - Collection<Reference<R>> arr;
103.135 - Set<Lookup> newL;
103.136 - Set<Lookup> current;
103.137 - Lookup[] old;
103.138 -
103.139 - Map<Result,LookupListener> toRemove = new IdentityHashMap<Lookup.Result, LookupListener>();
103.140 - Map<Result,LookupListener> toAdd = new IdentityHashMap<Lookup.Result, LookupListener>();
103.141 -
103.142 - ImmutableInternalData orig;
103.143 - synchronized (ProxyLookup.this) {
103.144 - orig = getData();
103.145 - ImmutableInternalData newData = getData().setLookupsNoFire(lookups, false);
103.146 - if (newData == getData()) {
103.147 - return;
103.148 - }
103.149 - arr = setData(newData, lookups, toAdd, toRemove);
103.150 - }
103.151 -
103.152 - // better to do this later than in synchronized block
103.153 - for (Map.Entry<Result, LookupListener> e : toRemove.entrySet()) {
103.154 - e.getKey().removeLookupListener(e.getValue());
103.155 - }
103.156 - for (Map.Entry<Result, LookupListener> e : toAdd.entrySet()) {
103.157 - e.getKey().addLookupListener(e.getValue());
103.158 - }
103.159 -
103.160 -
103.161 - // this cannot be done from the synchronized block
103.162 - final ArrayList<Object> evAndListeners = new ArrayList<Object>();
103.163 - for (Reference<R> ref : arr) {
103.164 - R<?> r = ref.get();
103.165 - if (r != null) {
103.166 - r.collectFires(evAndListeners);
103.167 - }
103.168 - }
103.169 -
103.170 - class Notify implements Runnable {
103.171 - public void run() {
103.172 - Iterator it = evAndListeners.iterator();
103.173 - while (it.hasNext()) {
103.174 - LookupEvent ev = (LookupEvent)it.next();
103.175 - LookupListener l = (LookupListener)it.next();
103.176 - l.resultChanged(ev);
103.177 - }
103.178 - }
103.179 - }
103.180 - Notify n = new Notify();
103.181 - if (notifyIn == null) {
103.182 - n.run();
103.183 - } else {
103.184 - notifyIn.execute(n);
103.185 - }
103.186 - }
103.187 -
103.188 - /** Notifies subclasses that a query is about to be processed.
103.189 - * Subclasses can update its state before the actual processing
103.190 - * begins. It is allowed to call <code>setLookups</code> method
103.191 - * to change/update the set of objects the proxy delegates to.
103.192 - *
103.193 - * @param template the template of the query
103.194 - * @since 1.31
103.195 - */
103.196 - protected void beforeLookup(Template<?> template) {
103.197 - }
103.198 -
103.199 - public final <T> T lookup(Class<T> clazz) {
103.200 - beforeLookup(new Template<T>(clazz));
103.201 -
103.202 - Lookup[] tmpLkps;
103.203 - synchronized (ProxyLookup.this) {
103.204 - tmpLkps = getData().getLookups(false);
103.205 - }
103.206 -
103.207 - for (int i = 0; i < tmpLkps.length; i++) {
103.208 - T o = tmpLkps[i].lookup(clazz);
103.209 -
103.210 - if (o != null) {
103.211 - return o;
103.212 - }
103.213 - }
103.214 -
103.215 - return null;
103.216 - }
103.217 -
103.218 - @Override
103.219 - public final <T> Item<T> lookupItem(Template<T> template) {
103.220 - beforeLookup(template);
103.221 -
103.222 - Lookup[] tmpLkps;
103.223 - synchronized (ProxyLookup.this) {
103.224 - tmpLkps = getData().getLookups(false);
103.225 - }
103.226 -
103.227 - for (int i = 0; i < tmpLkps.length; i++) {
103.228 - Item<T> o = tmpLkps[i].lookupItem(template);
103.229 -
103.230 - if (o != null) {
103.231 - return o;
103.232 - }
103.233 - }
103.234 -
103.235 - return null;
103.236 - }
103.237 -
103.238 - @SuppressWarnings("unchecked")
103.239 - private static <T> R<T> convertResult(R r) {
103.240 - return (R<T>)r;
103.241 - }
103.242 -
103.243 - public final <T> Result<T> lookup(Lookup.Template<T> template) {
103.244 - synchronized (ProxyLookup.this) {
103.245 - ImmutableInternalData[] res = { null };
103.246 - R<T> newR = getData().findResult(this, res, template);
103.247 - setData(res[0], getData().getLookups(false), null, null);
103.248 - return newR;
103.249 - }
103.250 - }
103.251 -
103.252 - /** Unregisters a template from the has map.
103.253 - */
103.254 - private final void unregisterTemplate(Template<?> template) {
103.255 - synchronized (ProxyLookup.this) {
103.256 - ImmutableInternalData id = getData();
103.257 - if (id == null) {
103.258 - return;
103.259 - }
103.260 - setData(id.removeTemplate(this, template), getData().getLookups(false), null, null);
103.261 - }
103.262 - }
103.263 -
103.264 - private ImmutableInternalData getData() {
103.265 - assert Thread.holdsLock(this);
103.266 - return data;
103.267 - }
103.268 -
103.269 - private Collection<Reference<R>> setData(
103.270 - ImmutableInternalData newData, Lookup[] current,
103.271 - Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
103.272 - ) {
103.273 - assert Thread.holdsLock(ProxyLookup.this);
103.274 - assert newData != null;
103.275 -
103.276 - ImmutableInternalData previous = this.getData();
103.277 -
103.278 - if (previous == newData) {
103.279 - return Collections.emptyList();
103.280 - }
103.281 -
103.282 - if (newData.isEmpty()) {
103.283 - this.setData(newData);
103.284 - // no affected results => exit
103.285 - return Collections.emptyList();
103.286 - }
103.287 -
103.288 - Collection<Reference<R>> arr = newData.references();
103.289 -
103.290 - Set<Lookup> removed = identityHashSet(previous.getLookupsList());
103.291 - Set<Lookup> currentSet = identityHashSet(Arrays.asList(current));
103.292 - Set<Lookup> newL = identityHashSet(currentSet);
103.293 - removed.removeAll(currentSet); // current contains just those lookups that have disappeared
103.294 - newL.removeAll(previous.getLookupsList()); // really new lookups
103.295 -
103.296 - for (Reference<R> ref : arr) {
103.297 - R<?> r = ref.get();
103.298 - if (r != null) {
103.299 - r.lookupChange(newData, current, previous, newL, removed, toAdd, toRemove);
103.300 - if (this.getData() != previous) {
103.301 - // the data were changed by an re-entrant call
103.302 - // skip any other change processing, as it is not needed
103.303 - // anymore
103.304 - }
103.305 - }
103.306 - }
103.307 - for (Reference<R> ref : arr) {
103.308 - R<?> r = ref.get();
103.309 - if (r != null) {
103.310 - r.data = newData;
103.311 - }
103.312 - }
103.313 - this.setData(newData);
103.314 - return arr;
103.315 - }
103.316 -
103.317 - private void setData(ImmutableInternalData data) {
103.318 - this.data = data;
103.319 - }
103.320 -
103.321 - /** Result of a lookup request. Allows access to single object
103.322 - * that was found (not too useful) and also to all objects found
103.323 - * (more useful).
103.324 - */
103.325 - private static final class R<T> extends WaitableResult<T> {
103.326 - /** weak listener & result */
103.327 - private final WeakResult<T> weakL;
103.328 -
103.329 - /** list of listeners added */
103.330 - private javax.swing.event.EventListenerList listeners;
103.331 -
103.332 - /** collection of Objects */
103.333 - private Collection[] cache;
103.334 -
103.335 -
103.336 - /** associated lookup */
103.337 - private ImmutableInternalData data;
103.338 -
103.339 - /** Constructor.
103.340 - */
103.341 - public R(ProxyLookup proxy, Lookup.Template<T> t) {
103.342 - this.weakL = new WeakResult<T>(proxy, this, t);
103.343 - }
103.344 -
103.345 - private ProxyLookup proxy() {
103.346 - return weakL.result.proxy;
103.347 - }
103.348 -
103.349 - @SuppressWarnings("unchecked")
103.350 - private Result<T>[] newResults(int len) {
103.351 - return new Result[len];
103.352 - }
103.353 -
103.354 - @Override
103.355 - protected void finalize() {
103.356 - weakL.result.run();
103.357 - }
103.358 -
103.359 - /** initializes the results
103.360 - */
103.361 - private Result<T>[] initResults() {
103.362 - BIG_LOOP: for (;;) {
103.363 - Lookup[] myLkps;
103.364 - ImmutableInternalData current;
103.365 - synchronized (proxy()) {
103.366 - if (weakL.getResults() != null) {
103.367 - return weakL.getResults();
103.368 - }
103.369 - myLkps = data.getLookups(false);
103.370 - current = data;
103.371 - }
103.372 -
103.373 - Result<T>[] arr = newResults(myLkps.length);
103.374 -
103.375 - for (int i = 0; i < arr.length; i++) {
103.376 - arr[i] = myLkps[i].lookup(weakL.result.template);
103.377 - }
103.378 -
103.379 - synchronized (proxy()) {
103.380 - if (current != data) {
103.381 - continue;
103.382 - }
103.383 -
103.384 - Lookup[] currentLkps = data.getLookups(false);
103.385 - if (currentLkps.length != myLkps.length) {
103.386 - continue BIG_LOOP;
103.387 - }
103.388 - for (int i = 0; i < currentLkps.length; i++) {
103.389 - if (currentLkps[i] != myLkps[i]) {
103.390 - continue BIG_LOOP;
103.391 - }
103.392 - }
103.393 -
103.394 - // some other thread might compute the result mean while.
103.395 - // if not finish the computation yourself
103.396 - if (weakL.getResults() != null) {
103.397 - return weakL.getResults();
103.398 - }
103.399 -
103.400 - weakL.setResults(arr);
103.401 - }
103.402 - for (int i = 0; i < arr.length; i++) {
103.403 - arr[i].addLookupListener(weakL);
103.404 - }
103.405 - return arr;
103.406 - }
103.407 - }
103.408 -
103.409 - /** Called when there is a change in the list of proxied lookups.
103.410 - * @param added set of added lookups
103.411 - * @param remove set of removed lookups
103.412 - * @param current array of current lookups
103.413 - */
103.414 - final void lookupChange(
103.415 - ImmutableInternalData newData, Lookup[] current, ImmutableInternalData oldData,
103.416 - Set<Lookup> added, Set<Lookup> removed,
103.417 - Map<Result,LookupListener> toAdd, Map<Result,LookupListener> toRemove
103.418 - ) {
103.419 - if (weakL.getResults() == null) {
103.420 - // not computed yet, do not need to do anything
103.421 - return;
103.422 - }
103.423 -
103.424 - Lookup[] old = oldData.getLookups(false);
103.425 -
103.426 - // map (Lookup, Lookup.Result)
103.427 - Map<Lookup,Result<T>> map = new IdentityHashMap<Lookup,Result<T>>(old.length * 2);
103.428 -
103.429 - for (int i = 0; i < old.length; i++) {
103.430 - if (removed.contains(old[i])) {
103.431 - // removed lookup
103.432 - if (toRemove != null) {
103.433 - toRemove.put(weakL.getResults()[i], weakL);
103.434 - }
103.435 - } else {
103.436 - // remember the association
103.437 - map.put(old[i], weakL.getResults()[i]);
103.438 - }
103.439 - }
103.440 -
103.441 - Lookup.Result<T>[] arr = newResults(current.length);
103.442 -
103.443 - for (int i = 0; i < current.length; i++) {
103.444 - if (added.contains(current[i])) {
103.445 - // new lookup
103.446 - arr[i] = current[i].lookup(weakL.result.template);
103.447 - if (toAdd != null) {
103.448 - toAdd.put(arr[i], weakL);
103.449 - }
103.450 - } else {
103.451 - // old lookup
103.452 - arr[i] = map.get(current[i]);
103.453 -
103.454 - if (arr[i] == null) {
103.455 - // assert
103.456 - throw new IllegalStateException();
103.457 - }
103.458 - }
103.459 - }
103.460 -
103.461 - // remember the new results
103.462 - weakL.setResults(arr);
103.463 - }
103.464 -
103.465 - /** Just delegates.
103.466 - */
103.467 - public void addLookupListener(LookupListener l) {
103.468 - synchronized (proxy()) {
103.469 - if (listeners == null) {
103.470 - listeners = new EventListenerList();
103.471 - }
103.472 - }
103.473 -
103.474 - listeners.add(LookupListener.class, l);
103.475 - initResults();
103.476 - }
103.477 -
103.478 - /** Just delegates.
103.479 - */
103.480 - public void removeLookupListener(LookupListener l) {
103.481 - if (listeners != null) {
103.482 - listeners.remove(LookupListener.class, l);
103.483 - }
103.484 - }
103.485 -
103.486 - /** Access to all instances in the result.
103.487 - * @return collection of all instances
103.488 - */
103.489 - @SuppressWarnings("unchecked")
103.490 - public java.util.Collection<T> allInstances() {
103.491 - return computeResult(0);
103.492 - }
103.493 -
103.494 - /** Classes of all results. Set of the most concreate classes
103.495 - * that are registered in the system.
103.496 - * @return set of Class objects
103.497 - */
103.498 - @SuppressWarnings("unchecked")
103.499 - @Override
103.500 - public java.util.Set<Class<? extends T>> allClasses() {
103.501 - return (java.util.Set<Class<? extends T>>) computeResult(1);
103.502 - }
103.503 -
103.504 - /** All registered items. The collection of all pairs of
103.505 - * ii and their classes.
103.506 - * @return collection of Lookup.Item
103.507 - */
103.508 - @SuppressWarnings("unchecked")
103.509 - @Override
103.510 - public java.util.Collection<? extends Item<T>> allItems() {
103.511 - return computeResult(2);
103.512 - }
103.513 -
103.514 - /** Computes results from proxied lookups.
103.515 - * @param indexToCache 0 = allInstances, 1 = allClasses, 2 = allItems
103.516 - * @return the collection or set of the objects
103.517 - */
103.518 - private java.util.Collection computeResult(int indexToCache) {
103.519 - // results to use
103.520 - Lookup.Result<T>[] arr = myBeforeLookup();
103.521 -
103.522 - // if the call to beforeLookup resulted in deletion of caches
103.523 - synchronized (proxy()) {
103.524 - Collection[] cc = getCache();
103.525 - if (cc != null && cc != NO_CACHE) {
103.526 - Collection result = cc[indexToCache];
103.527 - if (result != null) {
103.528 - return result;
103.529 - }
103.530 - }
103.531 - }
103.532 -
103.533 - // initialize the collection to hold result
103.534 - Collection<Object> compute;
103.535 - Collection<Object> ret;
103.536 -
103.537 - if (indexToCache == 1) {
103.538 - HashSet<Object> s = new HashSet<Object>();
103.539 - compute = s;
103.540 - ret = Collections.unmodifiableSet(s);
103.541 - } else {
103.542 - List<Object> l = new ArrayList<Object>(arr.length * 2);
103.543 - compute = l;
103.544 - ret = Collections.unmodifiableList(l);
103.545 - }
103.546 -
103.547 - // fill the collection
103.548 - for (int i = 0; i < arr.length; i++) {
103.549 - switch (indexToCache) {
103.550 - case 0:
103.551 - compute.addAll(arr[i].allInstances());
103.552 - break;
103.553 - case 1:
103.554 - compute.addAll(arr[i].allClasses());
103.555 - break;
103.556 - case 2:
103.557 - compute.addAll(arr[i].allItems());
103.558 - break;
103.559 - default:
103.560 - assert false : "Wrong index: " + indexToCache;
103.561 - }
103.562 - }
103.563 -
103.564 -
103.565 -
103.566 - synchronized (proxy()) {
103.567 - Collection[] cc = getCache();
103.568 - if (cc == null || cc == NO_CACHE) {
103.569 - // initialize the cache to indicate this result is in use
103.570 - setCache(cc = new Collection[3]);
103.571 - }
103.572 -
103.573 - if (arr == weakL.getResults()) {
103.574 - // updates the results, if the results have not been
103.575 - // changed during the computation of allInstances
103.576 - cc[indexToCache] = ret;
103.577 - }
103.578 - }
103.579 -
103.580 - return ret;
103.581 - }
103.582 -
103.583 - /** When the result changes, fire the event.
103.584 - */
103.585 - public void resultChanged(LookupEvent ev) {
103.586 - collectFires(null);
103.587 - }
103.588 -
103.589 - protected void collectFires(Collection<Object> evAndListeners) {
103.590 - boolean modified = true;
103.591 -
103.592 - try {
103.593 - // clear cached instances
103.594 - Collection oldItems;
103.595 - Collection oldInstances;
103.596 - synchronized (proxy()) {
103.597 - final Collection[] cc = getCache();
103.598 - if (cc == NO_CACHE) {
103.599 - return;
103.600 - }
103.601 -
103.602 - oldInstances = cc == null ? null : cc[0];
103.603 - oldItems = cc == null ? null : cc[2];
103.604 -
103.605 -
103.606 - if (listeners == null || listeners.getListenerCount() == 0) {
103.607 - // clear the cache
103.608 - setCache(new Collection[3]);
103.609 - return;
103.610 - }
103.611 -
103.612 - // ignore events if they arrive as a result of call to allItems
103.613 - // or allInstances, bellow...
103.614 - setCache(NO_CACHE);
103.615 - }
103.616 -
103.617 - if (oldItems != null) {
103.618 - Collection newItems = allItems();
103.619 - if (oldItems.equals(newItems)) {
103.620 - modified = false;
103.621 - }
103.622 - } else {
103.623 - if (oldInstances != null) {
103.624 - Collection newInstances = allInstances();
103.625 - if (oldInstances.equals(newInstances)) {
103.626 - modified = false;
103.627 - }
103.628 - } else {
103.629 - synchronized (proxy()) {
103.630 - if (getCache() == NO_CACHE) {
103.631 - // we have to initialize the cache
103.632 - // to show that the result has been initialized
103.633 - setCache(new Collection[3]);
103.634 - }
103.635 - }
103.636 - }
103.637 - }
103.638 - } finally {
103.639 - synchronized (proxy()) {
103.640 - if (getCache() == NO_CACHE) {
103.641 - setCache(null);
103.642 - }
103.643 - }
103.644 - }
103.645 -
103.646 - if (modified) {
103.647 - LookupEvent ev = new LookupEvent(this);
103.648 - AbstractLookup.notifyListeners(listeners.getListenerList(), ev, evAndListeners);
103.649 - }
103.650 - }
103.651 -
103.652 - /** Implementation of my before lookup.
103.653 - * @return results to work on.
103.654 - */
103.655 - private Lookup.Result<T>[] myBeforeLookup() {
103.656 - Template<T> template = weakL.result.template;
103.657 -
103.658 - proxy().beforeLookup(template);
103.659 -
103.660 - Lookup.Result<T>[] arr = initResults();
103.661 -
103.662 - // invoke update on the results
103.663 - for (int i = 0; i < arr.length; i++) {
103.664 - if (arr[i] instanceof WaitableResult) {
103.665 - WaitableResult w = (WaitableResult) arr[i];
103.666 - w.beforeLookup(template);
103.667 - }
103.668 - }
103.669 -
103.670 - return arr;
103.671 - }
103.672 -
103.673 - /** Used by proxy results to synchronize before lookup.
103.674 - */
103.675 - protected void beforeLookup(Lookup.Template t) {
103.676 - if (t.getType() == weakL.result.template.getType()) {
103.677 - myBeforeLookup();
103.678 - }
103.679 - }
103.680 -
103.681 - private Collection[] getCache() {
103.682 - return cache;
103.683 - }
103.684 -
103.685 - private void setCache(Collection[] cache) {
103.686 - assert Thread.holdsLock(proxy());
103.687 - this.cache = cache;
103.688 - }
103.689 - private static final Collection[] NO_CACHE = new Collection[0];
103.690 - }
103.691 - private static final class WeakRef<T> extends WeakReference<R> implements Runnable {
103.692 - final WeakResult<T> result;
103.693 - final ProxyLookup proxy;
103.694 - final Template<T> template;
103.695 -
103.696 - public WeakRef(R r, WeakResult<T> result, ProxyLookup proxy, Template<T> template) {
103.697 - super(r);
103.698 - this.result = result;
103.699 - this.template = template;
103.700 - this.proxy = proxy;
103.701 - }
103.702 -
103.703 - public void run() {
103.704 - result.removeListeners();
103.705 - proxy.unregisterTemplate(template);
103.706 - }
103.707 - }
103.708 -
103.709 -
103.710 - private static final class WeakResult<T> extends WaitableResult<T> implements LookupListener, Runnable {
103.711 - /** all results */
103.712 - private Lookup.Result<T>[] results;
103.713 - private final WeakRef<T> result;
103.714 -
103.715 - public WeakResult(ProxyLookup proxy, R r, Template<T> t) {
103.716 - this.result = new WeakRef<T>(r, this, proxy, t);
103.717 - }
103.718 -
103.719 - final void removeListeners() {
103.720 - Lookup.Result<T>[] arr = this.getResults();
103.721 - if (arr == null) {
103.722 - return;
103.723 - }
103.724 -
103.725 - for(int i = 0; i < arr.length; i++) {
103.726 - arr[i].removeLookupListener(this);
103.727 - }
103.728 - }
103.729 -
103.730 - protected void beforeLookup(Lookup.Template t) {
103.731 - R r = result.get();
103.732 - if (r != null) {
103.733 - r.beforeLookup(t);
103.734 - } else {
103.735 - removeListeners();
103.736 - }
103.737 - }
103.738 -
103.739 - protected void collectFires(Collection<Object> evAndListeners) {
103.740 - R<?> r = result.get();
103.741 - if (r != null) {
103.742 - r.collectFires(evAndListeners);
103.743 - } else {
103.744 - removeListeners();
103.745 - }
103.746 - }
103.747 -
103.748 - public void addLookupListener(LookupListener l) {
103.749 - assert false;
103.750 - }
103.751 -
103.752 - public void removeLookupListener(LookupListener l) {
103.753 - assert false;
103.754 - }
103.755 -
103.756 - public Collection<T> allInstances() {
103.757 - assert false;
103.758 - return null;
103.759 - }
103.760 -
103.761 - public void resultChanged(LookupEvent ev) {
103.762 - R r = result.get();
103.763 - if (r != null) {
103.764 - r.resultChanged(ev);
103.765 - } else {
103.766 - removeListeners();
103.767 - }
103.768 - }
103.769 -
103.770 - @Override
103.771 - public Collection<? extends Item<T>> allItems() {
103.772 - assert false;
103.773 - return null;
103.774 - }
103.775 -
103.776 - @Override
103.777 - public Set<Class<? extends T>> allClasses() {
103.778 - assert false;
103.779 - return null;
103.780 - }
103.781 -
103.782 - public void run() {
103.783 - removeListeners();
103.784 - }
103.785 -
103.786 - private Lookup.Result<T>[] getResults() {
103.787 - return results;
103.788 - }
103.789 -
103.790 - private void setResults(Lookup.Result<T>[] results) {
103.791 - this.results = results;
103.792 - }
103.793 - } // end of WeakResult
103.794 -
103.795 - static abstract class ImmutableInternalData extends Object {
103.796 - static final ImmutableInternalData EMPTY = new EmptyInternalData();
103.797 - static final Lookup[] EMPTY_ARR = new Lookup[0];
103.798 -
103.799 -
103.800 - protected ImmutableInternalData() {
103.801 - }
103.802 -
103.803 - public static ImmutableInternalData create(Object lkp, Map<Template, Reference<R>> results) {
103.804 - if (results.size() == 0 && lkp == EMPTY_ARR) {
103.805 - return EMPTY;
103.806 - }
103.807 - if (results.size() == 1) {
103.808 - Entry<Template,Reference<R>> e = results.entrySet().iterator().next();
103.809 - return new SingleInternalData(lkp, e.getKey(), e.getValue());
103.810 - }
103.811 -
103.812 - return new RealInternalData(lkp, results);
103.813 - }
103.814 -
103.815 - protected abstract boolean isEmpty();
103.816 - protected abstract Map<Template, Reference<R>> getResults();
103.817 - protected abstract Object getRawLookups();
103.818 -
103.819 - final Collection<Reference<R>> references() {
103.820 - return getResults().values();
103.821 - }
103.822 -
103.823 - final <T> ImmutableInternalData removeTemplate(ProxyLookup proxy, Template<T> template) {
103.824 - if (getResults().containsKey(template)) {
103.825 - HashMap<Template,Reference<R>> c = new HashMap<Template, Reference<ProxyLookup.R>>(getResults());
103.826 - Reference<R> ref = c.remove(template);
103.827 - if (ref != null && ref.get() != null) {
103.828 - // seems like there is a reference to a result for this template
103.829 - // thta is still alive
103.830 - return this;
103.831 - }
103.832 - return create(getRawLookups(), c);
103.833 - } else {
103.834 - return this;
103.835 - }
103.836 - }
103.837 -
103.838 - <T> R<T> findResult(ProxyLookup proxy, ImmutableInternalData[] newData, Template<T> template) {
103.839 - assert Thread.holdsLock(proxy);
103.840 -
103.841 - Map<Template,Reference<R>> map = getResults();
103.842 -
103.843 - Reference<R> ref = map.get(template);
103.844 - R r = (ref == null) ? null : ref.get();
103.845 -
103.846 - if (r != null) {
103.847 - newData[0] = this;
103.848 - return convertResult(r);
103.849 - }
103.850 -
103.851 - HashMap<Template, Reference<R>> res = new HashMap<Template, Reference<R>>(map);
103.852 - R<T> newR = new R<T>(proxy, template);
103.853 - res.put(template, new java.lang.ref.SoftReference<R>(newR));
103.854 - newR.data = newData[0] = create(getRawLookups(), res);
103.855 - return newR;
103.856 - }
103.857 - final ImmutableInternalData setLookupsNoFire(Lookup[] lookups, boolean skipCheck) {
103.858 - Object l;
103.859 -
103.860 - if (!skipCheck) {
103.861 - Lookup[] previous = getLookups(false);
103.862 - if (previous == lookups) {
103.863 - return this;
103.864 - }
103.865 -
103.866 - if (previous.length == lookups.length) {
103.867 - int same = 0;
103.868 - for (int i = 0; i < previous.length; i++) {
103.869 - if (lookups[i] != previous[i]) {
103.870 - break;
103.871 - }
103.872 - same++;
103.873 - }
103.874 - if (same == previous.length) {
103.875 - return this;
103.876 - }
103.877 - }
103.878 - }
103.879 -
103.880 - if (lookups.length == 1) {
103.881 - l = lookups[0];
103.882 - assert l != null : "Cannot assign null delegate";
103.883 - } else {
103.884 - if (lookups.length == 0) {
103.885 - l = EMPTY_ARR;
103.886 - } else {
103.887 - l = lookups.clone();
103.888 - }
103.889 - }
103.890 -
103.891 - if (isEmpty() && l == EMPTY_ARR) {
103.892 - return this;
103.893 - }
103.894 -
103.895 - return create(l, getResults());
103.896 - }
103.897 - final Lookup[] getLookups(boolean clone) {
103.898 - Object l = this.getRawLookups();
103.899 - if (l instanceof Lookup) {
103.900 - return new Lookup[] { (Lookup)l };
103.901 - } else {
103.902 - Lookup[] arr = (Lookup[])l;
103.903 - if (clone) {
103.904 - arr = arr.clone();
103.905 - }
103.906 - return arr;
103.907 - }
103.908 - }
103.909 - final List<Lookup> getLookupsList() {
103.910 - return Arrays.asList(getLookups(false));
103.911 - }
103.912 -
103.913 - } // end of ImmutableInternalData
103.914 -
103.915 - private static final class SingleInternalData extends ImmutableInternalData {
103.916 - /** lookups to delegate to (either Lookup or array of Lookups) */
103.917 - private final Object lookups;
103.918 - private final Template template;
103.919 - private final Reference<ProxyLookup.R> result;
103.920 -
103.921 - public SingleInternalData(Object lookups, Template<?> template, Reference<ProxyLookup.R> result) {
103.922 - this.lookups = lookups;
103.923 - this.template = template;
103.924 - this.result = result;
103.925 - }
103.926 -
103.927 - protected final boolean isEmpty() {
103.928 - return false;
103.929 - }
103.930 -
103.931 - protected Map<Template, Reference<R>> getResults() {
103.932 - return Collections.singletonMap(template, result);
103.933 - }
103.934 -
103.935 - protected Object getRawLookups() {
103.936 - return lookups;
103.937 - }
103.938 - }
103.939 - private static final class RealInternalData extends ImmutableInternalData {
103.940 - /** lookups to delegate to (either Lookup or array of Lookups) */
103.941 - private final Object lookups;
103.942 -
103.943 - /** map of templates to currently active results */
103.944 - private final Map<Template,Reference<R>> results;
103.945 -
103.946 - public RealInternalData(Object lookups, Map<Template, Reference<ProxyLookup.R>> results) {
103.947 - this.results = results;
103.948 - this.lookups = lookups;
103.949 - }
103.950 -
103.951 - protected final boolean isEmpty() {
103.952 - return false;
103.953 - }
103.954 -
103.955 - protected Map<Template, Reference<R>> getResults() {
103.956 - boolean strict = false;
103.957 - assert strict = true;
103.958 - return strict ? Collections.unmodifiableMap(results) : results;
103.959 - }
103.960 -
103.961 - protected Object getRawLookups() {
103.962 - return lookups;
103.963 - }
103.964 - }
103.965 -
103.966 - private static final class EmptyInternalData extends ImmutableInternalData {
103.967 - EmptyInternalData() {
103.968 - }
103.969 -
103.970 - protected final boolean isEmpty() {
103.971 - return true;
103.972 - }
103.973 -
103.974 - protected Map<Template, Reference<R>> getResults() {
103.975 - return Collections.emptyMap();
103.976 - }
103.977 -
103.978 - @Override
103.979 - protected Object getRawLookups() {
103.980 - return EMPTY_ARR;
103.981 - }
103.982 - } // end of EmptyInternalData
103.983 -}
104.1 --- a/openide.util/src/org/openide/util/lookup/ServiceProvider.java Thu Dec 10 19:23:25 2009 -0500
104.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
104.3 @@ -1,102 +0,0 @@
104.4 -/*
104.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
104.6 - *
104.7 - * Copyright 2008 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 - * If you wish your version of this file to be governed by only the CDDL
104.28 - * or only the GPL Version 2, indicate your decision by adding
104.29 - * "[Contributor] elects to include this software in this distribution
104.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
104.31 - * single choice of license, a recipient has the option to distribute
104.32 - * your version of this file under either the CDDL, the GPL Version 2 or
104.33 - * to extend the choice of license to its licensees as provided above.
104.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
104.35 - * Version 2 license, then the option applies only if the new code is
104.36 - * made subject to such option by the copyright holder.
104.37 - *
104.38 - * Contributor(s):
104.39 - *
104.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
104.41 - */
104.42 -
104.43 -package org.openide.util.lookup;
104.44 -
104.45 -import java.lang.annotation.ElementType;
104.46 -import java.lang.annotation.Retention;
104.47 -import java.lang.annotation.RetentionPolicy;
104.48 -import java.lang.annotation.Target;
104.49 -import org.openide.util.Lookup;
104.50 -
104.51 -/**
104.52 - * Declarative registration of a singleton service provider.
104.53 - * By marking an implementation class with this annotation,
104.54 - * you automatically register that implementation, normally in {@link Lookup#getDefault}.
104.55 - * The class must be public and have a public no-argument constructor.
104.56 - * <p>Example of usage:
104.57 - * <pre>
104.58 - * package my.module;
104.59 - * import org.netbeans.spi.whatever.Thing;
104.60 - * import org.openide.util.lookup.ServiceProvider;
104.61 - * @ServiceProvider(service=Thing.class)
104.62 - * public class MyThing implements Thing {...}
104.63 - * </pre>
104.64 - * <p>would result in a resource file <code>META-INF/services/org.netbeans.spi.whatever.Thing</code>
104.65 - * containing the single line of text: <code>my.module.MyThing</code>
104.66 - * @see Lookups#metaInfServices(ClassLoader)
104.67 - * @since org.openide.util 7.20
104.68 - */
104.69 -@Retention(RetentionPolicy.SOURCE)
104.70 -@Target(ElementType.TYPE)
104.71 -public @interface ServiceProvider {
104.72 -
104.73 - /**
104.74 - * The interface (or abstract class) to register this implementation under.
104.75 - * It is an error if the implementation class is not in fact assignable to the interface.
104.76 - * <p>If you need to register one class under multiple interfaces, use {@link ServiceProviders}.
104.77 - * <p>Requests to look up the specified interface should result in this implementation.
104.78 - * Requests for any other types may or may not result in this implementation even if the
104.79 - * implementation is assignable to those types.
104.80 - */
104.81 - Class<?> service();
104.82 -
104.83 - /**
104.84 - * An optional position in which to register this service relative to others.
104.85 - * Lower-numbered services are returned in the lookup result first.
104.86 - * Services with no specified position are returned last.
104.87 - */
104.88 - int position() default Integer.MAX_VALUE;
104.89 -
104.90 - /**
104.91 - * An optional list of implementations (given as fully-qualified class names) which this implementation supersedes.
104.92 - * If specified, those implementations will not be loaded even if they were registered.
104.93 - * Useful on occasion to cancel a generic implementation and replace it with a more advanced one.
104.94 - */
104.95 - String[] supersedes() default {};
104.96 -
104.97 - /**
104.98 - * An optional path to register this implementation in.
104.99 - * For example, <code>Projects/sometype/Nodes</code> could be used.
104.100 - * This style of registration would be recognized by {@link Lookups#forPath}
104.101 - * rather than {@link Lookup#getDefault}.
104.102 - */
104.103 - String path() default "";
104.104 -
104.105 -}
105.1 --- a/openide.util/src/org/openide/util/lookup/ServiceProviders.java Thu Dec 10 19:23:25 2009 -0500
105.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
105.3 @@ -1,60 +0,0 @@
105.4 -/*
105.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
105.6 - *
105.7 - * Copyright 2008 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 - * If you wish your version of this file to be governed by only the CDDL
105.28 - * or only the GPL Version 2, indicate your decision by adding
105.29 - * "[Contributor] elects to include this software in this distribution
105.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
105.31 - * single choice of license, a recipient has the option to distribute
105.32 - * your version of this file under either the CDDL, the GPL Version 2 or
105.33 - * to extend the choice of license to its licensees as provided above.
105.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
105.35 - * Version 2 license, then the option applies only if the new code is
105.36 - * made subject to such option by the copyright holder.
105.37 - *
105.38 - * Contributor(s):
105.39 - *
105.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
105.41 - */
105.42 -
105.43 -package org.openide.util.lookup;
105.44 -
105.45 -import java.lang.annotation.ElementType;
105.46 -import java.lang.annotation.Retention;
105.47 -import java.lang.annotation.RetentionPolicy;
105.48 -import java.lang.annotation.Target;
105.49 -
105.50 -/**
105.51 - * Similar to {@link ServiceProvider} but permits multiple registrations of one class.
105.52 - * @since org.openide.util 7.20
105.53 - */
105.54 -@Retention(RetentionPolicy.SOURCE)
105.55 -@Target(ElementType.TYPE)
105.56 -public @interface ServiceProviders {
105.57 -
105.58 - /**
105.59 - * List of service provider registrations.
105.60 - */
105.61 - ServiceProvider[] value();
105.62 -
105.63 -}
106.1 --- a/openide.util/src/org/openide/util/lookup/SimpleLookup.java Thu Dec 10 19:23:25 2009 -0500
106.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
106.3 @@ -1,250 +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 -package org.openide.util.lookup;
106.45 -
106.46 -import org.openide.util.Lookup;
106.47 -import org.openide.util.LookupListener;
106.48 -
106.49 -import java.util.*;
106.50 -
106.51 -
106.52 -/**
106.53 - * Simple lookup implementation. It can be used to create temporary lookups
106.54 - * that do not change over time. The result stores references to all objects
106.55 - * passed in the constructor. Those objecst are the only ones returned as
106.56 - * result.
106.57 - * @author David Strupl
106.58 - */
106.59 -class SimpleLookup extends org.openide.util.Lookup {
106.60 - /** This variable is initialized in constructor and thus null
106.61 - * value is not allowed as its value. */
106.62 - private Collection<Item<?>> allItems;
106.63 -
106.64 - /**
106.65 - * Creates new Result object with supplied instances parameter.
106.66 - * @param instances to be used to return from the lookup
106.67 - */
106.68 - SimpleLookup(Collection<Object> instances) {
106.69 - allItems = new ArrayList<Item<?>>(instances.size());
106.70 -
106.71 - for (Iterator i = instances.iterator(); i.hasNext();) {
106.72 - allItems.add(new InstanceContent.SimpleItem<Object>(i.next()));
106.73 - }
106.74 - }
106.75 -
106.76 - <T,R> SimpleLookup(Collection<T> keys, InstanceContent.Convertor<? super T,R> conv) {
106.77 - allItems = new ArrayList<Item<?>>(keys.size());
106.78 -
106.79 - for (T item : keys) {
106.80 - allItems.add(new InstanceContent.ConvertingItem<T,R>(item, conv));
106.81 - }
106.82 - }
106.83 -
106.84 - public String toString() {
106.85 - return "SimpleLookup" + lookup(new Template<Object>(Object.class)).allInstances();
106.86 - }
106.87 -
106.88 - public <T> Result<T> lookup(Template<T> template) {
106.89 - if (template == null) {
106.90 - throw new NullPointerException();
106.91 - }
106.92 -
106.93 - return new SimpleResult<T>(template);
106.94 - }
106.95 -
106.96 - public <T> T lookup(Class<T> clazz) {
106.97 - for (Iterator i = allItems.iterator(); i.hasNext();) {
106.98 - Object o = i.next();
106.99 -
106.100 - if (o instanceof AbstractLookup.Pair) {
106.101 - AbstractLookup.Pair<?> p = (AbstractLookup.Pair<?>)o;
106.102 - if (p.instanceOf(clazz)) {
106.103 - Object ret = p.getInstance();
106.104 - if (clazz.isInstance(ret)) {
106.105 - return clazz.cast(ret);
106.106 - }
106.107 - }
106.108 - }
106.109 - }
106.110 - return null;
106.111 - }
106.112 -
106.113 - /** A method that defines matching between Item and Template.
106.114 - * @param item the item to match
106.115 - * @return true if item matches the template requirements, false if not
106.116 - */
106.117 - private static boolean matches(Template<?> t, AbstractLookup.Pair<?> item) {
106.118 - if (!AbstractLookup.matches(t, item, true)) {
106.119 - return false;
106.120 - }
106.121 -
106.122 - Class<?> type = t.getType();
106.123 -
106.124 - if ((type != null) && !type.isAssignableFrom(item.getType())) {
106.125 - return false;
106.126 - }
106.127 -
106.128 - return true;
106.129 - }
106.130 -
106.131 - /**
106.132 - * Result used in SimpleLookup. It holds a reference to the collection
106.133 - * passed in constructor. As the contents of this lookup result never
106.134 - * changes the addLookupListener and removeLookupListener are empty.
106.135 - */
106.136 - private class SimpleResult<T> extends Lookup.Result<T> {
106.137 - /** can be null and is initialized lazily */
106.138 - private Set<Class<? extends T>> classes;
106.139 -
106.140 - /** can be null and is initialized lazily */
106.141 - private Collection<? extends Item<T>> items;
106.142 -
106.143 - /** Template used for this result. It is never null.*/
106.144 - private Template<T> template;
106.145 -
106.146 - /** can be null and is initialized lazily */
106.147 - private Collection<T> results;
106.148 -
106.149 - /** Just remembers the supplied argument in variable template.*/
106.150 - SimpleResult(Template<T> template) {
106.151 - this.template = template;
106.152 - }
106.153 -
106.154 - /**
106.155 - * Intentionally does nothing because the lookup does not change
106.156 - * and no notification is needed.
106.157 - */
106.158 - public void addLookupListener(LookupListener l) {
106.159 - }
106.160 -
106.161 - /**
106.162 - * Intentionally does nothing because the lookup does not change
106.163 - * and no notification is needed.
106.164 - */
106.165 - public void removeLookupListener(LookupListener l) {
106.166 - }
106.167 -
106.168 - /**
106.169 - * Lazy initializes the results collection. Uses a call to allItems
106.170 - * to obtain the instances.
106.171 - */
106.172 - public java.util.Collection<? extends T> allInstances() {
106.173 - synchronized (this) {
106.174 - if (results != null) {
106.175 - return results;
106.176 - }
106.177 - }
106.178 -
106.179 -
106.180 - Collection<T> res = new ArrayList<T>(allItems.size());
106.181 -
106.182 - for (Item<T> item : allItems()) {
106.183 - res.add(item.getInstance());
106.184 - }
106.185 -
106.186 - synchronized (this) {
106.187 - results = Collections.unmodifiableCollection(res);
106.188 - }
106.189 -
106.190 - return results;
106.191 - }
106.192 -
106.193 - /**
106.194 - * Lazy initializes variable classes. Uses a call to allItems to
106.195 - * compute the result.
106.196 - */
106.197 - public Set<Class<? extends T>> allClasses() {
106.198 - synchronized (this) {
106.199 - if (classes != null) {
106.200 - return classes;
106.201 - }
106.202 - }
106.203 -
106.204 - Set<Class<? extends T>> res = new HashSet<Class<? extends T>>();
106.205 -
106.206 - for (Item<T> item : allItems()) {
106.207 - res.add(item.getType());
106.208 - }
106.209 -
106.210 - synchronized (this) {
106.211 - classes = Collections.unmodifiableSet(res);
106.212 - }
106.213 -
106.214 - return classes;
106.215 - }
106.216 -
106.217 - /**
106.218 - * Lazy initializes variable items. Creates an item for each
106.219 - * element in the instances collection. It puts either SimpleItem
106.220 - * or ConvertingItem to the collection.
106.221 - */
106.222 - public Collection<? extends Item<T>> allItems() {
106.223 - synchronized (this) {
106.224 - if (items != null) {
106.225 - return items;
106.226 - }
106.227 - }
106.228 -
106.229 - Collection<Item<T>> res = new ArrayList<Item<T>>(allItems.size());
106.230 -
106.231 - for (Iterator<Item<?>> i = allItems.iterator(); i.hasNext();) {
106.232 - Item<?> o = i.next();
106.233 -
106.234 - if (o instanceof AbstractLookup.Pair) {
106.235 - if (matches(template, (AbstractLookup.Pair) o)) {
106.236 - res.add(cast(o));
106.237 - }
106.238 - }
106.239 - }
106.240 -
106.241 - synchronized (this) {
106.242 - items = Collections.unmodifiableCollection(res);
106.243 - }
106.244 -
106.245 - return items;
106.246 - }
106.247 -
106.248 - @SuppressWarnings("unchecked")
106.249 - private Item<T> cast(Item<?> i) {
106.250 - return (Item<T>)i;
106.251 - }
106.252 - }
106.253 -}
107.1 --- a/openide.util/src/org/openide/util/lookup/SimpleProxyLookup.java Thu Dec 10 19:23:25 2009 -0500
107.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
107.3 @@ -1,359 +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 -package org.openide.util.lookup;
107.45 -
107.46 -import java.lang.ref.Reference;
107.47 -import java.lang.ref.WeakReference;
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 -import java.util.*;
107.53 -
107.54 -
107.55 -/**
107.56 - * Simple proxy lookup. Keeps reference to a lookup it delegates to and
107.57 - * forwards all requests.
107.58 - *
107.59 - * @author Jaroslav Tulach
107.60 - */
107.61 -final class SimpleProxyLookup extends org.openide.util.Lookup {
107.62 - /** the provider to check for the status */
107.63 - private Provider provider;
107.64 -
107.65 - /** the lookup we currently delegate to */
107.66 - private Lookup delegate;
107.67 -
107.68 - /** map of all templates to Reference (results) associated to this lookup */
107.69 - private WeakHashMap<Template<?>,Reference<ProxyResult<?>>> results;
107.70 -
107.71 - /**
107.72 - * @param provider provider to delegate to
107.73 - */
107.74 - SimpleProxyLookup(Provider provider) {
107.75 - this.provider = provider;
107.76 - }
107.77 -
107.78 - /** Checks whether we still delegate to the same lookup */
107.79 - private Lookup checkLookup() {
107.80 - Lookup l = provider.getLookup();
107.81 -
107.82 - // iterator over Reference (ProxyResult)
107.83 - Iterator<Reference<ProxyResult<?>>> toCheck = null;
107.84 -
107.85 - synchronized (this) {
107.86 - if (l != delegate) {
107.87 - this.delegate = l;
107.88 -
107.89 - if (results != null) {
107.90 - toCheck = new ArrayList<Reference<ProxyResult<?>>>(results.values()).iterator();
107.91 - }
107.92 - }
107.93 - }
107.94 -
107.95 - if (toCheck != null) {
107.96 - // update
107.97 - ArrayList<Object> evAndListeners = new ArrayList<Object>();
107.98 - for (Iterator<Reference<ProxyResult<?>>> it = toCheck; it.hasNext(); ) {
107.99 - java.lang.ref.Reference<ProxyResult<?>> ref = it.next();
107.100 - if (ref == null) {
107.101 - continue;
107.102 - }
107.103 -
107.104 - ProxyResult<?> p = ref.get();
107.105 -
107.106 - if (p != null && p.updateLookup(l)) {
107.107 - p.collectFires(evAndListeners);
107.108 - }
107.109 - }
107.110 -
107.111 - for (Iterator it = evAndListeners.iterator(); it.hasNext(); ) {
107.112 - LookupEvent ev = (LookupEvent)it.next();
107.113 - LookupListener ll = (LookupListener)it.next();
107.114 - ll.resultChanged(ev);
107.115 - }
107.116 - }
107.117 -
107.118 - return delegate;
107.119 - }
107.120 -
107.121 - @SuppressWarnings("unchecked")
107.122 - private static <T> ProxyResult<T> cast(ProxyResult<?> p) {
107.123 - return (ProxyResult<T>)p;
107.124 - }
107.125 -
107.126 - public <T> Result<T> lookup(Template<T> template) {
107.127 - synchronized (this) {
107.128 - if (results == null) {
107.129 - results = new WeakHashMap<Template<?>,Reference<ProxyResult<?>>>();
107.130 - } else {
107.131 - Reference<ProxyResult<?>> ref = results.get(template);
107.132 -
107.133 - if (ref != null) {
107.134 - ProxyResult<?> p = ref.get();
107.135 -
107.136 - if (p != null) {
107.137 - return cast(p);
107.138 - }
107.139 - }
107.140 - }
107.141 -
107.142 - ProxyResult<T> p = new ProxyResult<T>(template);
107.143 - Reference<ProxyResult<?>> ref = new WeakReference<ProxyResult<?>>(p);
107.144 - results.put(template, ref);
107.145 -
107.146 - return p;
107.147 - }
107.148 - }
107.149 -
107.150 - public <T> T lookup(Class<T> clazz) {
107.151 - if (clazz == null) {
107.152 - checkLookup();
107.153 - return null;
107.154 - }
107.155 - return checkLookup().lookup(clazz);
107.156 - }
107.157 -
107.158 - public <T> Item<T> lookupItem(Template<T> template) {
107.159 - return checkLookup().lookupItem(template);
107.160 - }
107.161 -
107.162 - /**
107.163 - * Result used in SimpleLookup. It holds a reference to the collection
107.164 - * passed in constructor. As the contents of this lookup result never
107.165 - * changes the addLookupListener and removeLookupListener are empty.
107.166 - */
107.167 - private final class ProxyResult<T> extends WaitableResult<T> implements LookupListener {
107.168 - /** Template used for this result. It is never null.*/
107.169 - private Template<T> template;
107.170 -
107.171 - /** result to delegate to */
107.172 - private Lookup.Result<T> delegate;
107.173 -
107.174 - /** listeners set */
107.175 - private javax.swing.event.EventListenerList listeners;
107.176 - private LookupListener lastListener;
107.177 -
107.178 - /** Just remembers the supplied argument in variable template.*/
107.179 - ProxyResult(Template<T> template) {
107.180 - this.template = template;
107.181 - }
107.182 -
107.183 - /** Checks state of the result
107.184 - */
107.185 - private Result<T> checkResult() {
107.186 - updateLookup(checkLookup());
107.187 -
107.188 - return this.delegate;
107.189 - }
107.190 -
107.191 - /** Updates the state of the lookup.
107.192 - * @return true if the lookup really changed
107.193 - */
107.194 - public boolean updateLookup(Lookup l) {
107.195 - Collection<? extends Item<T>> oldPairs = (delegate != null) ? delegate.allItems() : null;
107.196 -
107.197 - LookupListener removedListener;
107.198 -
107.199 - synchronized (this) {
107.200 - if ((delegate != null) && (lastListener != null)) {
107.201 - removedListener = lastListener;
107.202 - delegate.removeLookupListener(lastListener);
107.203 - } else {
107.204 - removedListener = null;
107.205 - }
107.206 - }
107.207 -
107.208 - // cannot call to foreign code
107.209 - Lookup.Result<T> res = l.lookup(template);
107.210 -
107.211 - synchronized (this) {
107.212 - if (removedListener == lastListener) {
107.213 - delegate = res;
107.214 - lastListener = new WeakResult<T>(this, delegate);
107.215 - delegate.addLookupListener(lastListener);
107.216 - }
107.217 - }
107.218 -
107.219 - if (oldPairs == null) {
107.220 - // nobody knows about a change
107.221 - return false;
107.222 - }
107.223 -
107.224 - Collection<? extends Item<T>> newPairs = delegate.allItems();
107.225 -
107.226 - // See #34961 for explanation.
107.227 - if (!(oldPairs instanceof List)) {
107.228 - if (oldPairs == Collections.EMPTY_SET) {
107.229 - // avoid allocation
107.230 - oldPairs = Collections.emptyList();
107.231 - } else {
107.232 - oldPairs = new ArrayList<Item<T>>(oldPairs);
107.233 - }
107.234 - }
107.235 -
107.236 - if (!(newPairs instanceof List)) {
107.237 - newPairs = new ArrayList<Item<T>>(newPairs);
107.238 - }
107.239 -
107.240 - return !oldPairs.equals(newPairs);
107.241 - }
107.242 -
107.243 - public synchronized void addLookupListener(LookupListener l) {
107.244 - if (listeners == null) {
107.245 - listeners = new javax.swing.event.EventListenerList();
107.246 - }
107.247 -
107.248 - listeners.add(LookupListener.class, l);
107.249 - }
107.250 -
107.251 - public synchronized void removeLookupListener(LookupListener l) {
107.252 - if (listeners != null) {
107.253 - listeners.remove(LookupListener.class, l);
107.254 - }
107.255 - }
107.256 -
107.257 - public java.util.Collection<? extends T> allInstances() {
107.258 - return checkResult().allInstances();
107.259 - }
107.260 -
107.261 - public Set<Class<? extends T>> allClasses() {
107.262 - return checkResult().allClasses();
107.263 - }
107.264 -
107.265 - public Collection<? extends Item<T>> allItems() {
107.266 - return checkResult().allItems();
107.267 - }
107.268 -
107.269 - protected void beforeLookup(Lookup.Template t) {
107.270 - Lookup.Result r = checkResult();
107.271 -
107.272 - if (r instanceof WaitableResult) {
107.273 - ((WaitableResult) r).beforeLookup(t);
107.274 - }
107.275 - }
107.276 -
107.277 - /** A change in lookup occured.
107.278 - * @param ev event describing the change
107.279 - *
107.280 - */
107.281 - public void resultChanged(LookupEvent anEvent) {
107.282 - collectFires(null);
107.283 - }
107.284 -
107.285 - protected void collectFires(Collection<Object> evAndListeners) {
107.286 - javax.swing.event.EventListenerList l = this.listeners;
107.287 -
107.288 - if (l == null) {
107.289 - return;
107.290 - }
107.291 -
107.292 - Object[] listeners = l.getListenerList();
107.293 -
107.294 - if (listeners.length == 0) {
107.295 - return;
107.296 - }
107.297 -
107.298 - LookupEvent ev = new LookupEvent(this);
107.299 - AbstractLookup.notifyListeners(listeners, ev, evAndListeners);
107.300 - }
107.301 - }
107.302 - // end of ProxyResult
107.303 - private final class WeakResult<T> extends WaitableResult<T> implements LookupListener {
107.304 - private Lookup.Result source;
107.305 - private Reference<ProxyResult<T>> result;
107.306 -
107.307 - public WeakResult(ProxyResult<T> r, Lookup.Result<T> s) {
107.308 - this.result = new WeakReference<ProxyResult<T>>(r);
107.309 - this.source = s;
107.310 - }
107.311 -
107.312 - protected void beforeLookup(Lookup.Template t) {
107.313 - ProxyResult r = (ProxyResult)result.get();
107.314 - if (r != null) {
107.315 - r.beforeLookup(t);
107.316 - } else {
107.317 - source.removeLookupListener(this);
107.318 - }
107.319 - }
107.320 -
107.321 - protected void collectFires(Collection<Object> evAndListeners) {
107.322 - ProxyResult<T> r = result.get();
107.323 - if (r != null) {
107.324 - r.collectFires(evAndListeners);
107.325 - } else {
107.326 - source.removeLookupListener(this);
107.327 - }
107.328 - }
107.329 -
107.330 - public void addLookupListener(LookupListener l) {
107.331 - assert false;
107.332 - }
107.333 -
107.334 - public void removeLookupListener(LookupListener l) {
107.335 - assert false;
107.336 - }
107.337 -
107.338 - public Collection<T> allInstances() {
107.339 - assert false;
107.340 - return null;
107.341 - }
107.342 -
107.343 - public void resultChanged(LookupEvent ev) {
107.344 - ProxyResult r = (ProxyResult)result.get();
107.345 - if (r != null) {
107.346 - r.resultChanged(ev);
107.347 - } else {
107.348 - source.removeLookupListener(this);
107.349 - }
107.350 - }
107.351 -
107.352 - public Collection<? extends Item<T>> allItems() {
107.353 - assert false;
107.354 - return null;
107.355 - }
107.356 -
107.357 - public Set<Class<? extends T>> allClasses() {
107.358 - assert false;
107.359 - return null;
107.360 - }
107.361 - } // end of WeakResult
107.362 -}
108.1 --- a/openide.util/src/org/openide/util/lookup/SingletonLookup.java Thu Dec 10 19:23:25 2009 -0500
108.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
108.3 @@ -1,173 +0,0 @@
108.4 -/*
108.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
108.6 - *
108.7 - * Copyright 2008 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 - * If you wish your version of this file to be governed by only the CDDL
108.28 - * or only the GPL Version 2, indicate your decision by adding
108.29 - * "[Contributor] elects to include this software in this distribution
108.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
108.31 - * single choice of license, a recipient has the option to distribute
108.32 - * your version of this file under either the CDDL, the GPL Version 2 or
108.33 - * to extend the choice of license to its licensees as provided above.
108.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
108.35 - * Version 2 license, then the option applies only if the new code is
108.36 - * made subject to such option by the copyright holder.
108.37 - *
108.38 - * Contributor(s):
108.39 - *
108.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
108.41 - */
108.42 -
108.43 -package org.openide.util.lookup;
108.44 -
108.45 -import java.util.Collection;
108.46 -import java.util.Collections;
108.47 -import java.util.Set;
108.48 -import org.openide.util.Lookup;
108.49 -import org.openide.util.LookupListener;
108.50 -
108.51 -/**
108.52 - * Unmodifiable lookup that contains just one fixed object.
108.53 - *
108.54 - * @author Marian Petras
108.55 - */
108.56 -class SingletonLookup extends Lookup {
108.57 -
108.58 - private final Object objectToLookup;
108.59 - private final String id;
108.60 -
108.61 - SingletonLookup(Object objectToLookup) {
108.62 - this(objectToLookup, null);
108.63 - }
108.64 -
108.65 - SingletonLookup(Object objectToLookup, String id) {
108.66 - if (objectToLookup == null) {
108.67 - throw new IllegalArgumentException("null"); //NOI18N
108.68 - }
108.69 -
108.70 - this.objectToLookup = objectToLookup;
108.71 - this.id = id;
108.72 - }
108.73 -
108.74 - @Override
108.75 - public <T> T lookup(Class<T> clazz) {
108.76 - if (clazz == null) {
108.77 - throw new IllegalArgumentException("null"); //NOI18N
108.78 - }
108.79 -
108.80 - return (clazz.isInstance(objectToLookup))
108.81 - ? clazz.cast(objectToLookup)
108.82 - : null;
108.83 - }
108.84 -
108.85 - @Override
108.86 - public <T> Result<T> lookup(Template<T> template) {
108.87 - if (template == null) {
108.88 - throw new IllegalArgumentException("null"); //NOI18N
108.89 - }
108.90 -
108.91 - Lookup.Item<T> item = lookupItem(template);
108.92 - if (item != null) {
108.93 - return new SingletonResult<T>(item);
108.94 - } else {
108.95 - return Lookup.EMPTY.lookup(template);
108.96 - }
108.97 - }
108.98 -
108.99 - @Override
108.100 - public <T> Collection<? extends T> lookupAll(Class<T> clazz) {
108.101 - if (clazz == null) {
108.102 - throw new IllegalArgumentException("null"); //NOI18N
108.103 - }
108.104 -
108.105 - return (clazz.isInstance(objectToLookup))
108.106 - ? Collections.singletonList(clazz.cast(objectToLookup))
108.107 - : Collections.<T>emptyList();
108.108 - }
108.109 -
108.110 - @Override
108.111 - @SuppressWarnings("unchecked")
108.112 - public <T> Item<T> lookupItem(Template<T> template) {
108.113 - if (template == null) {
108.114 - throw new IllegalArgumentException("null"); //NOI18N
108.115 - }
108.116 -
108.117 - String templateId = template.getId();
108.118 - if ((templateId != null) && !templateId.equals(id)) {
108.119 - return null;
108.120 - }
108.121 -
108.122 - Object templateInst = template.getInstance();
108.123 - if ((templateInst != null) && (objectToLookup != templateInst)) {
108.124 - return null;
108.125 - }
108.126 -
108.127 - Class<T> clazz = template.getType();
108.128 - if ((clazz != null) && !clazz.isInstance(objectToLookup)) {
108.129 - return null;
108.130 - }
108.131 -
108.132 - Lookup.Item<T> item;
108.133 - if (clazz != null) {
108.134 - item = Lookups.lookupItem(clazz.cast(objectToLookup), id);
108.135 - } else {
108.136 - item = Lookups.lookupItem((T) objectToLookup, id);
108.137 - }
108.138 - return item;
108.139 - }
108.140 -
108.141 - static class SingletonResult<T> extends Lookup.Result<T> {
108.142 -
108.143 - private final Lookup.Item<T> item;
108.144 -
108.145 - SingletonResult(Lookup.Item<T> item) {
108.146 - this.item = item;
108.147 - }
108.148 -
108.149 - @Override
108.150 - public void addLookupListener(LookupListener l) {
108.151 - // this result never changes - no need to register a listener
108.152 - }
108.153 -
108.154 - @Override
108.155 - public void removeLookupListener(LookupListener l) {
108.156 - // this result never changes - no need to register a listener
108.157 - }
108.158 -
108.159 - @Override
108.160 - public Set<Class<? extends T>> allClasses() {
108.161 - return Collections.<Class<? extends T>>singleton(item.getType());
108.162 - }
108.163 -
108.164 - @Override
108.165 - public Collection<? extends Item<T>> allItems() {
108.166 - return Collections.singletonList(item);
108.167 - }
108.168 -
108.169 - @Override
108.170 - public Collection<? extends T> allInstances() {
108.171 - return Collections.singletonList(item.getInstance());
108.172 - }
108.173 -
108.174 - }
108.175 -
108.176 -}
109.1 --- a/openide.util/src/org/openide/util/lookup/WaitableResult.java Thu Dec 10 19:23:25 2009 -0500
109.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
109.3 @@ -1,62 +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 -package org.openide.util.lookup;
109.45 -
109.46 -import java.util.Collection;
109.47 -import org.openide.util.Lookup;
109.48 -
109.49 -
109.50 -/** A special subclass of lookup that is able to wait before queries.
109.51 - *
109.52 - * @author Jaroslav Tulach
109.53 - */
109.54 -abstract class WaitableResult<T> extends Lookup.Result<T> {
109.55 - /** Used by proxy results to synchronize before lookup.
109.56 - */
109.57 - protected abstract void beforeLookup(Lookup.Template t);
109.58 -
109.59 - /** Needed to group notification of outside the package listeners
109.60 - * after all AbstractLookup and ProxyLookups have been updated.
109.61 - * @param evAndListeners LookupEvent, LookupListener, LookupEvent, LookupListener, etc.
109.62 - */
109.63 - protected abstract void collectFires(Collection<Object> evAndListeners);
109.64 -
109.65 -}
110.1 --- a/openide.util/src/org/openide/util/lookup/doc-files/index.html Thu Dec 10 19:23:25 2009 -0500
110.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
110.3 @@ -1,208 +0,0 @@
110.4 -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
110.5 -<!--
110.6 - - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
110.7 - -
110.8 - - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
110.9 - -
110.10 - - The contents of this file are subject to the terms of either the GNU
110.11 - - General Public License Version 2 only ("GPL") or the Common
110.12 - - Development and Distribution License("CDDL") (collectively, the
110.13 - - "License"). You may not use this file except in compliance with the
110.14 - - License. You can obtain a copy of the License at
110.15 - - http://www.netbeans.org/cddl-gplv2.html
110.16 - - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
110.17 - - specific language governing permissions and limitations under the
110.18 - - License. When distributing the software, include this License Header
110.19 - - Notice in each file and include the License file at
110.20 - - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
110.21 - - particular file as subject to the "Classpath" exception as provided
110.22 - - by Sun in the GPL Version 2 section of the License file that
110.23 - - accompanied this code. If applicable, add the following below the
110.24 - - License Header, with the fields enclosed by brackets [] replaced by
110.25 - - your own identifying information:
110.26 - - "Portions Copyrighted [year] [name of copyright owner]"
110.27 - -
110.28 - - Contributor(s):
110.29 - -
110.30 - - The Original Software is NetBeans. The Initial Developer of the Original
110.31 - - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
110.32 - - Microsystems, Inc. All Rights Reserved.
110.33 - -
110.34 - - If you wish your version of this file to be governed by only the CDDL
110.35 - - or only the GPL Version 2, indicate your decision by adding
110.36 - - "[Contributor] elects to include this software in this distribution
110.37 - - under the [CDDL or GPL Version 2] license." If you do not indicate a
110.38 - - single choice of license, a recipient has the option to distribute
110.39 - - your version of this file under either the CDDL, the GPL Version 2 or
110.40 - - to extend the choice of license to its licensees as provided above.
110.41 - - However, if you add GPL Version 2 code and therefore, elected the GPL
110.42 - - Version 2 license, then the option applies only if the new code is
110.43 - - made subject to such option by the copyright holder.
110.44 - -->
110.45 -<HTML>
110.46 -<HEAD>
110.47 -<TITLE>Lookup Library</TITLE>
110.48 -<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
110.49 -</HEAD>
110.50 -<BODY>
110.51 -
110.52 -<P>
110.53 -
110.54 -This is the home page of the <em>lookup library</em> implementation, which
110.55 -is intended to solve a general problem that every <cite>component-based system</CITE>
110.56 -has had to face: how different components <b>register</b> to the system
110.57 -and how other parts of the system can <b>look</b> them <b>up</B>.
110.58 -<P>
110.59 -There already are libraries trying to solve this problem, usually by querying for
110.60 -an interface and finding its appropriate implementaion. The most famous is
110.61 -<A href="http://www.jini.org/">Jini</A>, the platform for development of
110.62 -distributed network services. Our library does something similar, but tries
110.63 -to stay small and easy
110.64 -to use. The NetBeans <em>Lookup
110.65 -Library</EM>'s main focus is a modular application consisting of independent modules
110.66 -that want to communicate with each other. It does not try to solve networking or
110.67 -legacy application integration. It is simple but powerful.
110.68 -
110.69 -<H2>Why would you want to use it?</H2>
110.70 -
110.71 -A well-written modular program separates <em>development</EM>
110.72 -and <em>deployment</EM>.
110.73 -There are many situations where a component needs some functionality but
110.74 -does not actually care about the implementation. It is up to the <em>system
110.75 -adminstrator</em> that deploys (installs) the application to decide which
110.76 -implementation to use.
110.77 -<P>
110.78 -The most simple and most often used method for allowing other implementations
110.79 -to be plugged in is the <em>system property</em> pattern:
110.80 -
110.81 -<pre>
110.82 - <font class="keyword">public</font> <font class="type">Toolkit</font> <font class="function-name">getDefaultToolkit</font> () {
110.83 - java.awt.<font class="type">Toolkit</font> <font class="variable-name">t</font> = <font class="constant">null</font>;
110.84 - <font class="type">String</font> <font class="variable-name">classname</font> = System.getProperty (<font class="string">"java.awt.Toolkit"</font>);
110.85 - <font class="keyword">if</font> (classname != <font class="constant">null</font>) {
110.86 - <font class="keyword">try</font> {
110.87 - <font class="type">Class</font> <font class="variable-name">c</font> = Class.forName (classname);
110.88 - t = (java.awt.<font class="type">Toolkit</font>)c.newInstance ();
110.89 - } <font class="keyword">catch</font> (<font class="type">Exception</font> <font class="variable-name">ex</font>) {
110.90 - System.out.println (<font class="string">"Cannot initialize toolkit: "</font> + classname);
110.91 - ex.printStackTrace ();
110.92 - }
110.93 - }
110.94 - <font class="comment">// fallback </font>
110.95 - <font class="keyword">if</font> (t == <font class="constant">null</font>) {
110.96 - t = <font class="keyword">new</font> <font class="type">GenericAWTToolkit</font> ();
110.97 - }
110.98 - }
110.99 -</pre>
110.100 -
110.101 -
110.102 -The idea is simple. The <em>deployer</em> can start the Java VM with the flag
110.103 -<code>-Djava.awt.Toolkit=org.myorg.MyToolkit</code> where the <code>MyToolkit</code>
110.104 -is his class with default constructor and the code in the <code>getDefaultToolkit</CODE>
110.105 -method will instantiate the class and use it.
110.106 -<P>
110.107 -In principle this is general enough of a solution and works well, except that writing the
110.108 -code above is error prone and it also requires passing the arguments to the virtual machine.
110.109 -It would be much nicer if the registation could be done just by putting a JAR file with the <code>MyToolkit</code> class
110.110 -into the application classpath.
110.111 -<P>
110.112 -Actually this has been realized also by the JDK development team and addressed in
110.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>.
110.114 -The <code>MyToolkit</code> could be registered by adding a file
110.115 -<code>/META-INF/services/java.awt.Toolkit</code> with one line
110.116 -<code>org.myorg.MyToolkit</code> into the JAR file that contains the
110.117 -<code>MyToolkit</CODE> implementation. The code in <code>getDefaultToolkit</CODE>
110.118 -will scan all JAR files in classpath and search for that file,
110.119 -create an instance of <code>MyToolkit</code> and use it.
110.120 -The deployer can influence which toolkit will be created by
110.121 -adding the right JAR files into the classpath.
110.122 -<P>
110.123 -Of course the code to access the <code>META-INF/services/</code> files is even
110.124 -more error prone than the <em>property pattern</EM>. And this is exactly the
110.125 -place where the <em>lookup library</em> can help. It provides an implementation of
110.126 -the search algorithm with an easy interface. Just write:
110.127 -<pre>
110.128 - <font class="keyword">import</font> <font class="type">java.awt.Toolkit</font>;
110.129 - <font class="keyword">import</font> <font class="type">org.openide.util.Lookup;</font>;
110.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>);
110.131 -</PRE>
110.132 -and if the JAR with <code>MyToolkit</CODE> is in the class path, the simple call
110.133 -above will do the rest.
110.134 -<P>
110.135 -So whenever one writes an application divided into several independent modules (jar files)
110.136 -that are being developed and deployed independently, there is a need for registering
110.137 -and discovering components. First of all, a set of interfaces can be defined to enable
110.138 -inter-module communication (like the abstract class <code>java.awt.Toolkit</CODE>).
110.139 -After that a set of modules providing implementation can written (<code>MyToolkit</code> and other concurent implementations)
110.140 -and after that, whenever a module trying to utilitize the functionality wants to access
110.141 -the <code>Toolkit</code> via lookup, the real implementation is returned.
110.142 -<P>
110.143 -It is the responsibility of lookup to find a suitable implementation of the
110.144 -requested service and return an object implementing the service. This is the
110.145 -the basic functionality and while the library provides you with a little bit
110.146 -more, even this simple usage might be extremaly useful: the client code knows
110.147 -nothing about the implementation and the implementation can be switched in
110.148 -deployment time by simply replacing one implementation jar with other. There
110.149 -is no code change required.
110.150 -
110.151 -<H2> Local lookup usage </H2>
110.152 -The example in previous paragraph demostrated the usage of lookup as a global
110.153 -registry (by using the <CODE>Lookup.getDefault()</CODE> call). One can also
110.154 -consider another scenario where the lookup can help.
110.155 -<P>
110.156 -Let's switch hats to be an API designer for a while. The goal is to introduce a
110.157 -new object into the system. But you either are not sure yet what all the roles
110.158 -of the new object will be or you (more importantly) want to be able to add (or
110.159 -change) roles of the object dynamically. So why not to introduce following
110.160 -method to the object's interface:
110.161 -<pre>
110.162 -<font class="keyword">public class </FONT> <font class="type">MorphingObject</FONT> {
110.163 - <font class="keyword">public</FONT> <font class="type"><a href="@TOP@org/openide/util/Lookup.html">Lookup</A></FONT> getLookup() {
110.164 - <font class="keyword">return</FONT> <font class="variable-name">myLookup;</FONT>
110.165 - }
110.166 - ...
110.167 -}
110.168 -</pre>
110.169 -By exposing the method getLookup you can attach different functionality to the
110.170 -MorphingObject at runtime and whoever gets a reference to your object can ask it
110.171 -whether the object supports a given interface like this:
110.172 -<pre>
110.173 -<font class="type">MorphingObject</FONT> <font class="variable-name">morph</FONT> = ...
110.174 -<font class="type">AnInterface</font> <font class="variable-name">impl</font> = (<font
110.175 -class="type">AnInterface</font>)morph.getLookup().<a
110.176 -href="@TOP@org/openide/util/Lookup.html#lookup(java.lang.Class)">lookup</a>(AnInterface.<font class="keyword">class</font>);
110.177 -<font class="keyword">if</font> (impl == <font class="constant">null</font>) {
110.178 - <font class="keyword">return;</font><font class="comment">/* AnInterface not supported now! */</font>
110.179 -}
110.180 -impl.useIt();
110.181 -</PRE>
110.182 -
110.183 -<H2>Additional functionality</H2>
110.184 -The NetBeans lookup library also provides:
110.185 -<UL>
110.186 -<LI>Support for dynamically changing the lookup content.</LI>
110.187 -<LI>The ability to return multiple results.</LI>
110.188 -<LI>Notification of changes. After retrieving the result, the client can attach a
110.189 -listener and be notified when the result of the lookup is changed.</LI>
110.190 -<LI>Lazy initialization of the implementation. The implementation objects are
110.191 -initialized only after someone asks for them. Even the implementation classes
110.192 -are not loaded if they are not going to be used! </LI>
110.193 -</UL>
110.194 -
110.195 -<H2>Further information</H2>
110.196 -<UL>
110.197 - <LI><A HREF="lookup-api.html">Lookup Library APIs</A> for those writing the client code.
110.198 -Specifying the query, getting the result and listenning on changes.</LI>
110.199 - <LI><A HREF="lookup-spi.html">Lookup Library SPIs</A> for those writing the
110.200 -implementaion code and registering it with lookup. Includes also writing own
110.201 -lookup implementation.</LI>
110.202 - <LI>Download <A HREF="http://www.netbeans.org/">NetBeans platform</A> which
110.203 -contains <code>org-openide-util.jar</code></LI>
110.204 - <A HREF="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/lookup/">
110.205 - implementation package (org.openide.util.lookup) </A>
110.206 - + classes Lookup, LookupEvent, LookupListener in
110.207 - <A href="http://hg.netbeans.org/main-golden/file/tip/openide.util/src/org/openide/util/">util package</A></LI>
110.208 - <li><a href="http://www.martinfowler.com/articles/injection.html">Inversion of Control Containers and the Dependency Injection pattern</a> (Martin Fowler)</li>
110.209 -</UL>
110.210 -</BODY>
110.211 -</HTML>
111.1 --- a/openide.util/src/org/openide/util/lookup/doc-files/lookup-api.html Thu Dec 10 19:23:25 2009 -0500
111.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
111.3 @@ -1,188 +0,0 @@
111.4 -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
111.5 -<!--
111.6 - - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
111.7 - -
111.8 - - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
111.9 - -
111.10 - - The contents of this file are subject to the terms of either the GNU
111.11 - - General Public License Version 2 only ("GPL") or the Common
111.12 - - Development and Distribution License("CDDL") (collectively, the
111.13 - - "License"). You may not use this file except in compliance with the
111.14 - - License. You can obtain a copy of the License at
111.15 - - http://www.netbeans.org/cddl-gplv2.html
111.16 - - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
111.17 - - specific language governing permissions and limitations under the
111.18 - - License. When distributing the software, include this License Header
111.19 - - Notice in each file and include the License file at
111.20 - - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
111.21 - - particular file as subject to the "Classpath" exception as provided
111.22 - - by Sun in the GPL Version 2 section of the License file that
111.23 - - accompanied this code. If applicable, add the following below the
111.24 - - License Header, with the fields enclosed by brackets [] replaced by
111.25 - - your own identifying information:
111.26 - - "Portions Copyrighted [year] [name of copyright owner]"
111.27 - -
111.28 - - Contributor(s):
111.29 - -
111.30 - - The Original Software is NetBeans. The Initial Developer of the Original
111.31 - - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
111.32 - - Microsystems, Inc. All Rights Reserved.
111.33 - -
111.34 - - If you wish your version of this file to be governed by only the CDDL
111.35 - - or only the GPL Version 2, indicate your decision by adding
111.36 - - "[Contributor] elects to include this software in this distribution
111.37 - - under the [CDDL or GPL Version 2] license." If you do not indicate a
111.38 - - single choice of license, a recipient has the option to distribute
111.39 - - your version of this file under either the CDDL, the GPL Version 2 or
111.40 - - to extend the choice of license to its licensees as provided above.
111.41 - - However, if you add GPL Version 2 code and therefore, elected the GPL
111.42 - - Version 2 license, then the option applies only if the new code is
111.43 - - made subject to such option by the copyright holder.
111.44 - -->
111.45 -<HTML>
111.46 -<HEAD>
111.47 -<TITLE>Lookup Library API</TITLE>
111.48 -<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
111.49 -</HEAD>
111.50 -<BODY>
111.51 -<H1>Lookup library API</H1>
111.52 -<p>
111.53 -This document describes usage of the API provided by the Lookup Library. In this
111.54 -document we assume that someone has already provided us with a lookup
111.55 -implementation (for those seeking how to write a lookup implementation please
111.56 -check <A href="lookup-spi.html">the SPI document</A>).
111.57 -
111.58 -<H2> Getting the lookup </H2>
111.59 -
111.60 -The first question you might ask is this: how can I get hold of a
111.61 -lookup instance? There are basically two ways how you can get it.
111.62 -
111.63 -<H3> Global lookup </H3>
111.64 -As you can see in the
111.65 -
111.66 -<a href="@TOP@org/openide/util/Lookup.html">Lookup</a>
111.67 -
111.68 -Javadoc there is a static method
111.69 -
111.70 -<pre><a href="@TOP@org/openide/util/Lookup.html#getDefault()">public static Lookup getDefault()</a></pre>
111.71 -
111.72 -The object returned from this method is
111.73 -a global lookup that can serve as a central place for registering services.
111.74 -The default implementation is a lookup that implements
111.75 -<a href="http://java.sun.com/j2se/1.5.0/docs/guide/jar/jar.html#Service%20Provider">
111.76 -the JDK JAR services</A>
111.77 -mechanism and delegates to <samp>META-INF/services/name.of.Class</samp> files.
111.78 -<P>
111.79 -If you want to add your class to this lookup just create a file in your
111.80 -jar file under the <code>META-INF</code> directory (e.g. <samp>META-INF/services/com.my.APIClass</samp>)
111.81 -and let the file contain only one line of text
111.82 -
111.83 -<pre>com.foo.impl.ImplOfTheAPI</pre>
111.84 -
111.85 -<p>(This is more easily done using the <code>@ServiceProvider</code> annotation.)</p>
111.86 -
111.87 -The following code will return you a newly created instance of
111.88 -<code>com.foo.impl.ImplOfTheAPI</code>:
111.89 -
111.90 -<PRE>
111.91 - <font class="keyword">import</FONT> org.openide.util.Lookup;
111.92 - return Lookup.getDefault().lookup(com.my.APIClass.class);
111.93 -</PRE>
111.94 -
111.95 -<H3> Local lookup </H3>
111.96 -
111.97 -This is just a reminder that whenever you find a method called getLookup
111.98 -or similar returning a lookup instance, the provided lookup is <EM>not</EM> the
111.99 -general lookup described in the previous paragraph. Rather, it is a private lookup
111.100 -implementation that is usually bound to the object you invoked the method on.
111.101 -
111.102 -<H2> Use of Lookup.Template and Lookup.Result </H2>
111.103 -
111.104 -There are more ways how you can ask lookup besides the variant with one class
111.105 -parameter. If you want more functionality, you have to implement the interface
111.106 -Lookup.Template and pass an instance of such object to the lookup call.
111.107 -<p>
111.108 -<EM>Note:</EM> If you use Lookup.Template, the object returned from the lookup is
111.109 -<EM>not</EM> the object you are looking for but rather a result object
111.110 -(Lookup.Result). You can call methods on such a result object to get the actual
111.111 -results.
111.112 -<p>
111.113 -Let's examine following example:
111.114 -
111.115 -<pre>
111.116 - <font class="keyword">import</FONT> org.openide.util.Lookup;
111.117 -
111.118 - <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
111.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>);
111.120 - Lookup.<font class="type">Result</font> <font class="variable-name">result</font> = lookup.lookup(template);
111.121 - <font class="type">Collection</font> <font class="variable-name">c</font> = result.allInstances();
111.122 - <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = c.iterator(); i.hasNext(); ) {
111.123 - <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
111.124 - s.callMyService();
111.125 - }
111.126 -</pre>
111.127 -
111.128 -In this example the call to method lookup(...) returns immediately because the
111.129 -result object can be constructed even without real results. The first time you
111.130 -ask for the result object by calling r.allInstances(), the lookup has to supply you
111.131 -the real results and this method can block until the required data are really
111.132 -available.
111.133 -<p>
111.134 -If you are not interested in all objects as in the previous example, you can use the
111.135 -template to ask for one resulting object (wrapped in special Item instance):
111.136 -<pre>
111.137 - <font class="keyword">import</FONT> org.openide.util.Lookup;
111.138 -
111.139 - <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
111.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>);
111.141 - Lookup.<font class="type">Item</font> <font class="variable-name">item</font> = lookup.lookupItem(template);
111.142 - <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)item.getInstance();
111.143 - s.callMyService();
111.144 -</pre>
111.145 -
111.146 -Again, the Item object can construct the real instance only if you call
111.147 -getInstance. The item can be useful even without calling getInstance - you can get
111.148 -its display name or an unique id. You can use this information, for example, for
111.149 -constructing menu items without the need to instantiate (or even load!)
111.150 -the class implementing the functionality. Only when the real functionality is
111.151 -needed (e.g. the user has selected the menu item) you can call getInstance
111.152 -and call the real meat of the implementation.
111.153 -
111.154 -<H2> Listenning on lookup changes </H2>
111.155 -There is one additional piece of functionality bound to the Lookup.Result object worth
111.156 -mentioning: you can attach a listener to it and be informed about any changes in
111.157 -the lookup. This might be extremly usefull when the lookup dynamically changes
111.158 -(from other threads). The listener can keep state of your object up-to-date even
111.159 -in cases where the lookup changes asynchronously.
111.160 -<p>
111.161 -So here is some sample code using the listenner:
111.162 -
111.163 -<pre>
111.164 - <font class="keyword">import</FONT> org.openide.util.Lookup;
111.165 - <font class="keyword">import</FONT> org.openide.util.LookupListener;
111.166 - <font class="keyword">import</FONT> org.openide.util.LookupEvent;
111.167 -
111.168 - <font class="type">Lookup</font> <font class="variable-name">lookup</font> = ...;
111.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>);
111.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);
111.171 - result.addLookupListener(<font class="keyword">new</font> <font class="type">LookupListener</font>() {
111.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>) {
111.173 - reaction(result);
111.174 - }
111.175 - });
111.176 - reaction(result);
111.177 - }
111.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>) {
111.179 - <font class="keyword">for</font> (<font class="type">Iterator</font> <font class="variable-name">i</font> = r.allInstances().iterator(); i.hasNext(); ) {
111.180 - <font class="type">MyService</font> <font class="variable-name">s</font> = (<font class="type">MyService</font>)i.next();
111.181 - s.callMyService();
111.182 - }
111.183 - }
111.184 -</pre>
111.185 -
111.186 -Please note that we first attach a listener and then call the reaction method.
111.187 -This ensures that we always get the newest possible state. Also you must be
111.188 -careful in the reaction method since it can be called from two different
111.189 -threads simultaneously (your code has to be prepared for this).
111.190 -</BODY>
111.191 -</HTML>
112.1 --- a/openide.util/src/org/openide/util/lookup/doc-files/lookup-spi.html Thu Dec 10 19:23:25 2009 -0500
112.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
112.3 @@ -1,147 +0,0 @@
112.4 -<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
112.5 -<!--
112.6 - - DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
112.7 - -
112.8 - - Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
112.9 - -
112.10 - - The contents of this file are subject to the terms of either the GNU
112.11 - - General Public License Version 2 only ("GPL") or the Common
112.12 - - Development and Distribution License("CDDL") (collectively, the
112.13 - - "License"). You may not use this file except in compliance with the
112.14 - - License. You can obtain a copy of the License at
112.15 - - http://www.netbeans.org/cddl-gplv2.html
112.16 - - or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
112.17 - - specific language governing permissions and limitations under the
112.18 - - License. When distributing the software, include this License Header
112.19 - - Notice in each file and include the License file at
112.20 - - nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
112.21 - - particular file as subject to the "Classpath" exception as provided
112.22 - - by Sun in the GPL Version 2 section of the License file that
112.23 - - accompanied this code. If applicable, add the following below the
112.24 - - License Header, with the fields enclosed by brackets [] replaced by
112.25 - - your own identifying information:
112.26 - - "Portions Copyrighted [year] [name of copyright owner]"
112.27 - -
112.28 - - Contributor(s):
112.29 - -
112.30 - - The Original Software is NetBeans. The Initial Developer of the Original
112.31 - - Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
112.32 - - Microsystems, Inc. All Rights Reserved.
112.33 - -
112.34 - - If you wish your version of this file to be governed by only the CDDL
112.35 - - or only the GPL Version 2, indicate your decision by adding
112.36 - - "[Contributor] elects to include this software in this distribution
112.37 - - under the [CDDL or GPL Version 2] license." If you do not indicate a
112.38 - - single choice of license, a recipient has the option to distribute
112.39 - - your version of this file under either the CDDL, the GPL Version 2 or
112.40 - - to extend the choice of license to its licensees as provided above.
112.41 - - However, if you add GPL Version 2 code and therefore, elected the GPL
112.42 - - Version 2 license, then the option applies only if the new code is
112.43 - - made subject to such option by the copyright holder.
112.44 - -->
112.45 -<HTML>
112.46 -<HEAD>
112.47 -<TITLE>Lookup Library SPI</TITLE>
112.48 -<link rel="Stylesheet" href="@TOP@/prose.css" type="text/css" title="NetBeans Open APIs Style">
112.49 -</HEAD>
112.50 -<BODY>
112.51 -<H1>Lookup library SPI</H1>
112.52 -This document describe usage of the SPI provided by the Lookup Library
112.53 -(for those seeking how to use lookup instance please
112.54 -check <A href="lookup-api.html">the API document</A>).
112.55 -<p>
112.56 -By using the SPI you can create lookups that can be used by the users of the
112.57 -Lookup API. While the Lookup API consists of a couple of classes in the package
112.58 -<em>org.openide.util.*</EM>,
112.59 -the SPI has its own package <em>org.openide.util.lookup.*</EM>.
112.60 -
112.61 -<H2> Simple lookups </H2>
112.62 -Let us start with the simplest case. You have decided that your newly created
112.63 -object will provide an API in the form of a getLookup() method. You have to
112.64 -return a functional lookup from this call. You can use static methods in class
112.65 -<a href="@TOP@org/openide/util/lookup/Lookups.html">
112.66 -<code>Lookups</code></A> to create a lookup for you. If you want only one
112.67 -object to be returned, just call
112.68 -<a href="@TOP@org/openide/util/lookup/Lookups.html#singleton(java.lang.Object)">
112.69 -<code>Lookups.singleton(x)</code></A> where x is the object to be
112.70 -returned by the lookup. Or if you want to supply more objects, use a call to the method
112.71 -<a href="@TOP@org/openide/util/lookup/Lookups.html#fixed(java.lang.Object...)">
112.72 -<code>fixed(Object []x)</CODE></A>.
112.73 -<EM> Note: </EM> The lookups returned from methods <code>singleton(...)</code> and
112.74 -<code>fixed(...)</code> do <EM>
112.75 -not </EM> support dynamic changes and attaching listeners. Their content is
112.76 -fixed from the time you call the creating method.
112.77 -
112.78 -<H2> ProxyLookup </H2>
112.79 -There can be situations where you get a lookup object from someone else and you
112.80 -want your lookup to return exactly the instances from the original lookup plus
112.81 -your own results. Here the class ProxyLookup comes into the play.
112.82 -<p>
112.83 -You simply create a new lookup like this:
112.84 -
112.85 -<pre>
112.86 - <font class="keyword">import</FONT> org.openide.util.Lookup;
112.87 - <font class="keyword">import</FONT> org.openide.util.lookup.*;
112.88 -
112.89 - <font class="type">Lookup</font> <font class="variable-name">lookup1</font> = ...;
112.90 -
112.91 - <font class="type">Lookup</font> <font class="variable-name">lookup2</font> = Lookups.singleton(MyService.<font class="keyword">class</font>);
112.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 });
112.93 -</pre>
112.94 -
112.95 -<H2> AbstractLookup </H2>
112.96 -<!-- This paragraph originally copied from
112.97 -@TOP@org/openide/doc-files/services-api.html#lookup-impl
112.98 --->
112.99 -
112.100 -<p>The most powerful way to provide a lookup is to directly define
112.101 -what instances and items it should provide, by subclassing. For this,
112.102 -
112.103 -<a href="@TOP@org/openide/util/lookup/AbstractLookup.html"><code>AbstractLookup</code></a>
112.104 -
112.105 -is recommended as it is easiest to use.
112.106 -
112.107 -<p>The simplest way to use <code>AbstractLookup</code> is to use its
112.108 -public constructor (in which case you need not subclass it). Here you
112.109 -provide an
112.110 -
112.111 -<a href="@TOP@org/openide/util/lookup/AbstractLookup.Content.html"><code>AbstractLookup.Content</code></a>
112.112 -
112.113 -object which you have created and hold on to privately, and which
112.114 -keeps track of instances and permits them to be registered and
112.115 -deregistered. Often
112.116 -
112.117 -<a href="@TOP@org/openide/util/lookup/InstanceContent.html"><code>InstanceContent</code></a>
112.118 -
112.119 -is used as the content implementation. To add something to the lookup,
112.120 -simply use
112.121 -
112.122 -<a href="@TOP@org/openide/util/lookup/InstanceContent.html#add(java.lang.Object)"><code>add(Object)</code></a>
112.123 -
112.124 -(and <code>remove(Object)</code> for the reverse). These may be called
112.125 -at any time and will update the set of registered instances (firing
112.126 -result changes as needed).
112.127 -
112.128 -<pre>
112.129 - <font class="keyword">import</FONT> org.openide.util.lookup.*;
112.130 - <font class="type">InstanceContent</font> <font class="variable-name">ic</font> = <font class="keyword">new</font> <font class="type">InstanceContent</font> ();
112.131 - ic.add(firstObject);
112.132 - <font class="keyword">return</font> <font class="keyword">new</font> <font class="type">AbstractLookup</font> (ic);
112.133 -</pre>
112.134 -
112.135 -<p>In case it is expensive to actually compute the object in the
112.136 -lookup, but there is some cheap "key" which can easily generate it,
112.137 -you may instead register the key by passing in an
112.138 -
112.139 -<a href="@TOP@org/openide/util/lookup/InstanceContent.Convertor.html"><code>InstanceContent.Convertor</code></a>.
112.140 -
112.141 -This convertor translates the key to the real instance that the lookup
112.142 -client sees, if and when needed. For example, if you have a long list
112.143 -of class names and wish to register default instances of each class,
112.144 -you might actually register the class name as the key, and supply a
112.145 -convertor which really loads the class and instantiates it. This makes
112.146 -it easy to set up the lookup, but nothing is really loaded until
112.147 -someone asks for it.
112.148 -
112.149 -</BODY>
112.150 -</HTML>
113.1 --- a/openide.util/src/org/openide/util/lookup/package.html Thu Dec 10 19:23:25 2009 -0500
113.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
113.3 @@ -1,48 +0,0 @@
113.4 -<!--
113.5 -DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
113.6 -
113.7 -Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
113.8 -
113.9 -
113.10 -The contents of this file are subject to the terms of either the GNU
113.11 -General Public License Version 2 only ("GPL") or the Common
113.12 -Development and Distribution License("CDDL") (collectively, the
113.13 -"License"). You may not use this file except in compliance with the
113.14 -License. You can obtain a copy of the License at
113.15 -http://www.netbeans.org/cddl-gplv2.html
113.16 -or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
113.17 -specific language governing permissions and limitations under the
113.18 -License. When distributing the software, include this License Header
113.19 -Notice in each file and include the License file at
113.20 -nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
113.21 -particular file as subject to the "Classpath" exception as provided
113.22 -by Sun in the GPL Version 2 section of the License file that
113.23 -accompanied this code. If applicable, add the following below the
113.24 -License Header, with the fields enclosed by brackets [] replaced by
113.25 -your own identifying information:
113.26 -"Portions Copyrighted [year] [name of copyright owner]"
113.27 -
113.28 -Contributor(s):
113.29 -
113.30 -The Original Software is NetBeans. The Initial Developer of the Original
113.31 -Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
113.32 -Microsystems, Inc. All Rights Reserved.
113.33 -
113.34 -If you wish your version of this file to be governed by only the CDDL
113.35 -or only the GPL Version 2, indicate your decision by adding
113.36 -"[Contributor] elects to include this software in this distribution
113.37 -under the [CDDL or GPL Version 2] license." If you do not indicate a
113.38 -single choice of license, a recipient has the option to distribute
113.39 -your version of this file under either the CDDL, the GPL Version 2 or
113.40 -to extend the choice of license to its licensees as provided above.
113.41 -However, if you add GPL Version 2 code and therefore, elected the GPL
113.42 -Version 2 license, then the option applies only if the new code is
113.43 -made subject to such option by the copyright holder.
113.44 --->
113.45 -
113.46 -<html>
113.47 -<body>
113.48 -Support classes for the Registration and {@link org.openide.util.Lookup} extension mechanism.
113.49 -Read more: <a href="doc-files/index.html">Lookup Library</a>
113.50 -</body>
113.51 -</html>
114.1 --- a/openide.util/test/unit/src/org/bar/Comparator2.java Thu Dec 10 19:23:25 2009 -0500
114.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
114.3 @@ -1,7 +0,0 @@
114.4 -
114.5 -package org.bar;
114.6 -
114.7 -public class Comparator2 implements java.util.Comparator {
114.8 - public int compare(Object o1, Object o2) {return 0;}
114.9 - public boolean equals(Object obj) {return true;}
114.10 -}
115.1 --- a/openide.util/test/unit/src/org/bar/Comparator3.java Thu Dec 10 19:23:25 2009 -0500
115.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
115.3 @@ -1,7 +0,0 @@
115.4 -
115.5 -package org.bar;
115.6 -
115.7 -public class Comparator3 implements java.util.Comparator {
115.8 - public int compare(Object o1, Object o2) {return 0;}
115.9 - public boolean equals(Object obj) {return true;}
115.10 -}
116.1 --- a/openide.util/test/unit/src/org/bar/Implementation2.java Thu Dec 10 19:23:25 2009 -0500
116.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
116.3 @@ -1,3 +0,0 @@
116.4 -package org.bar;
116.5 -import org.foo.Interface;
116.6 -public class Implementation2 implements Interface {}
117.1 --- a/openide.util/test/unit/src/org/bar/Iterator2.java Thu Dec 10 19:23:25 2009 -0500
117.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
117.3 @@ -1,11 +0,0 @@
117.4 -
117.5 -package org.bar;
117.6 -
117.7 -public class Iterator2 implements java.util.Iterator {
117.8 - public boolean hasNext() {return false;}
117.9 -
117.10 - public Object next() {return null;}
117.11 -
117.12 - public void remove() {}
117.13 -
117.14 -}
118.1 --- a/openide.util/test/unit/src/org/foo/Interface.java Thu Dec 10 19:23:25 2009 -0500
118.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
118.3 @@ -1,2 +0,0 @@
118.4 -package org.foo;
118.5 -public interface Interface {}
119.1 --- a/openide.util/test/unit/src/org/foo/impl/Comparator1.java Thu Dec 10 19:23:25 2009 -0500
119.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
119.3 @@ -1,7 +0,0 @@
119.4 -
119.5 -package org.foo.impl;
119.6 -
119.7 -public class Comparator1 implements java.util.Comparator {
119.8 - public int compare(Object o1, Object o2) {return 0;}
119.9 - public boolean equals(Object obj) {return true;}
119.10 -}
120.1 --- a/openide.util/test/unit/src/org/foo/impl/Implementation1.java Thu Dec 10 19:23:25 2009 -0500
120.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
120.3 @@ -1,3 +0,0 @@
120.4 -package org.foo.impl;
120.5 -import org.foo.Interface;
120.6 -public class Implementation1 implements Interface {}
121.1 --- a/openide.util/test/unit/src/org/foo/impl/Iterator1.java Thu Dec 10 19:23:25 2009 -0500
121.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
121.3 @@ -1,11 +0,0 @@
121.4 -
121.5 -package org.foo.impl;
121.6 -
121.7 -public class Iterator1 implements java.util.Iterator {
121.8 - public boolean hasNext() {return false;}
121.9 -
121.10 - public Object next() {return null;}
121.11 -
121.12 - public void remove() {}
121.13 -
121.14 -}
122.1 --- a/openide.util/test/unit/src/org/foo/impl/Runnable1.java Thu Dec 10 19:23:25 2009 -0500
122.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
122.3 @@ -1,6 +0,0 @@
122.4 -
122.5 -package org.foo.impl;
122.6 -
122.7 -public class Runnable1 implements Runnable {
122.8 - public void run () {}
122.9 -}
123.1 --- a/openide.util/test/unit/src/org/netbeans/modules/openide/util/ServiceProviderProcessorTest.java Thu Dec 10 19:23:25 2009 -0500
123.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
123.3 @@ -1,180 +0,0 @@
123.4 -/*
123.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
123.6 - *
123.7 - * Copyright 2008 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 - * If you wish your version of this file to be governed by only the CDDL
123.28 - * or only the GPL Version 2, indicate your decision by adding
123.29 - * "[Contributor] elects to include this software in this distribution
123.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
123.31 - * single choice of license, a recipient has the option to distribute
123.32 - * your version of this file under either the CDDL, the GPL Version 2 or
123.33 - * to extend the choice of license to its licensees as provided above.
123.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
123.35 - * Version 2 license, then the option applies only if the new code is
123.36 - * made subject to such option by the copyright holder.
123.37 - *
123.38 - * Contributor(s):
123.39 - *
123.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
123.41 - */
123.42 -
123.43 -package org.netbeans.modules.openide.util;
123.44 -
123.45 -import java.io.ByteArrayOutputStream;
123.46 -import java.io.File;
123.47 -import java.util.ArrayList;
123.48 -import java.util.Arrays;
123.49 -import java.util.Collections;
123.50 -import java.util.Comparator;
123.51 -import java.util.List;
123.52 -import org.netbeans.junit.NbTestCase;
123.53 -import org.openide.util.Lookup;
123.54 -import org.openide.util.lookup.Lookups;
123.55 -import org.openide.util.lookup.ServiceProvider;
123.56 -import org.openide.util.lookup.ServiceProviders;
123.57 -import org.openide.util.test.AnnotationProcessorTestUtils;
123.58 -
123.59 -public class ServiceProviderProcessorTest extends NbTestCase {
123.60 -
123.61 - public ServiceProviderProcessorTest(String n) {
123.62 - super(n);
123.63 - }
123.64 -
123.65 - private static List<Class<?>> classesOf(Iterable<?> objects) {
123.66 - List<Class<?>> cs = new ArrayList<Class<?>>();
123.67 - for (Object o : objects) {
123.68 - cs.add(o.getClass());
123.69 - }
123.70 - return cs;
123.71 - }
123.72 -
123.73 - private static List<Class<?>> classesOfLookup(Class<?> xface) {
123.74 - return classesOf(Lookup.getDefault().lookupAll(xface));
123.75 - }
123.76 -
123.77 - private static List<Class<?>> sortClassList(List<Class<?>> classes) {
123.78 - List<Class<?>> sorted = new ArrayList<Class<?>>(classes);
123.79 - Collections.sort(sorted, new Comparator<Class<?>>() {
123.80 - public int compare(Class<?> c1, Class<?> c2) {
123.81 - return c1.getName().compareTo(c2.getName());
123.82 - }
123.83 - });
123.84 - return sorted;
123.85 - }
123.86 -
123.87 - public void testBasicUsage() throws Exception {
123.88 - assertEquals(Collections.singletonList(Implementation.class), classesOfLookup(Interface.class));
123.89 - }
123.90 - public interface Interface {}
123.91 - @ServiceProvider(service=Interface.class)
123.92 - public static class Implementation implements Interface {}
123.93 -
123.94 - public void testPosition() throws Exception {
123.95 - assertEquals(Arrays.<Class<?>>asList(OrderedImpl3.class, OrderedImpl2.class, OrderedImpl1.class), classesOfLookup(OrderedInterface.class));
123.96 - }
123.97 - public interface OrderedInterface {}
123.98 - @ServiceProvider(service=OrderedInterface.class)
123.99 - public static class OrderedImpl1 implements OrderedInterface {}
123.100 - @ServiceProvider(service=OrderedInterface.class, position=200)
123.101 - public static class OrderedImpl2 implements OrderedInterface {}
123.102 - @ServiceProvider(service=OrderedInterface.class, position=100)
123.103 - public static class OrderedImpl3 implements OrderedInterface {}
123.104 -
123.105 - public void testPath() throws Exception {
123.106 - assertEquals(Collections.singletonList(PathImplementation.class), classesOf(Lookups.forPath("some/path").lookupAll(Interface.class)));
123.107 - }
123.108 - @ServiceProvider(service=Interface.class, path="some/path")
123.109 - public static class PathImplementation implements Interface {}
123.110 -
123.111 - public void testSupersedes() throws Exception {
123.112 - assertEquals(Arrays.<Class<?>>asList(Overrider.class, Unrelated.class), sortClassList(classesOfLookup(CancellableInterface.class)));
123.113 - }
123.114 - public interface CancellableInterface {}
123.115 - @ServiceProvider(service=CancellableInterface.class)
123.116 - public static class Overridden implements CancellableInterface {}
123.117 - @ServiceProvider(service=CancellableInterface.class, supersedes="org.netbeans.modules.openide.util.ServiceProviderProcessorTest$Overridden")
123.118 - public static class Overrider implements CancellableInterface {}
123.119 - @ServiceProvider(service=CancellableInterface.class)
123.120 - public static class Unrelated implements CancellableInterface {}
123.121 -
123.122 - public void testMultipleRegistrations() throws Exception {
123.123 - assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface1.class));
123.124 - assertEquals(Collections.singletonList(Multitasking.class), classesOfLookup(Interface2.class));
123.125 - }
123.126 - public interface Interface1 {}
123.127 - public interface Interface2 {}
123.128 - @ServiceProviders({@ServiceProvider(service=Interface1.class), @ServiceProvider(service=Interface2.class)})
123.129 - public static class Multitasking implements Interface1, Interface2 {}
123.130 -
123.131 - public void testErrorReporting() throws Exception {
123.132 - clearWorkDir();
123.133 - File src = new File(getWorkDir(), "src");
123.134 - File dest = new File(getWorkDir(), "classes");
123.135 - String xfaceName = Interface.class.getCanonicalName();
123.136 -
123.137 - AnnotationProcessorTestUtils.makeSource(src, "p.C1",
123.138 - "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
123.139 - "public class C1 implements " + xfaceName + " {}");
123.140 - ByteArrayOutputStream baos = new ByteArrayOutputStream();
123.141 - assertTrue(AnnotationProcessorTestUtils.runJavac(src, "C1", dest, null, baos));
123.142 -
123.143 - AnnotationProcessorTestUtils.makeSource(src, "p.C2",
123.144 - "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
123.145 - "class C2 implements " + xfaceName + " {}");
123.146 - baos = new ByteArrayOutputStream();
123.147 - assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C2", dest, null, baos));
123.148 - assertTrue(baos.toString(), baos.toString().contains("public"));
123.149 -
123.150 - AnnotationProcessorTestUtils.makeSource(src, "p.C3",
123.151 - "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
123.152 - "public class C3 implements " + xfaceName + " {",
123.153 - "public C3(boolean x) {}",
123.154 - "}");
123.155 - baos = new ByteArrayOutputStream();
123.156 - assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C3", dest, null, baos));
123.157 - assertTrue(baos.toString(), baos.toString().contains("constructor"));
123.158 -
123.159 - AnnotationProcessorTestUtils.makeSource(src, "p.C4",
123.160 - "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
123.161 - "public class C4 implements " + xfaceName + " {",
123.162 - "C4() {}",
123.163 - "}");
123.164 - baos = new ByteArrayOutputStream();
123.165 - assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C4", dest, null, baos));
123.166 - assertTrue(baos.toString(), baos.toString().contains("constructor"));
123.167 -
123.168 - AnnotationProcessorTestUtils.makeSource(src, "p.C5",
123.169 - "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
123.170 - "public abstract class C5 implements " + xfaceName + " {}");
123.171 - baos = new ByteArrayOutputStream();
123.172 - assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C5", dest, null, baos));
123.173 - assertTrue(baos.toString(), baos.toString().contains("abstract"));
123.174 -
123.175 - AnnotationProcessorTestUtils.makeSource(src, "p.C6",
123.176 - "@org.openide.util.lookup.ServiceProvider(service=" + xfaceName + ".class)",
123.177 - "public class C6 {}");
123.178 - baos = new ByteArrayOutputStream();
123.179 - assertFalse(AnnotationProcessorTestUtils.runJavac(src, "C6", dest, null, baos));
123.180 - assertTrue(baos.toString(), baos.toString().contains("assignable"));
123.181 - }
123.182 -
123.183 -}
124.1 --- a/openide.util/test/unit/src/org/openide/util/InitJobTest.java Thu Dec 10 19:23:25 2009 -0500
124.2 +++ b/openide.util/test/unit/src/org/openide/util/InitJobTest.java Mon Dec 14 20:58:39 2009 +0100
124.3 @@ -81,6 +81,11 @@
124.4 protected boolean runInEQ() {
124.5 return true;
124.6 }
124.7 +
124.8 + @Override
124.9 + protected int timeOut() {
124.10 + return 15000;
124.11 + }
124.12
124.13 /** Basic testing of Utilities.attachInitJob, if calls to AsyncGUIJob
124.14 * impl conforms to the API behaviour described in javadoc *
125.1 --- a/openide.util/test/unit/src/org/openide/util/UtilitiesActiveQueueTest.java Thu Dec 10 19:23:25 2009 -0500
125.2 +++ b/openide.util/test/unit/src/org/openide/util/UtilitiesActiveQueueTest.java Mon Dec 14 20:58:39 2009 +0100
125.3 @@ -114,48 +114,6 @@
125.4 }
125.5 }
125.6
125.7 - public void testMemoryLeak() throws Exception {
125.8 - final Class<?> u1 = Utilities.class;
125.9 - class L extends URLClassLoader {
125.10 - public L() {
125.11 - super(new URL[] {u1.getProtectionDomain().getCodeSource().getLocation()}, u1.getClassLoader().getParent());
125.12 - }
125.13 - protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
125.14 - if (name.equals(u1.getName()) || name.startsWith(u1.getName() + "$")) {
125.15 - Class c = findLoadedClass(name);
125.16 - if (c == null) {
125.17 - c = findClass(name);
125.18 - }
125.19 - if (resolve) {
125.20 - resolveClass(c);
125.21 - }
125.22 - return c;
125.23 - } else {
125.24 - return super.loadClass(name, resolve);
125.25 - }
125.26 - }
125.27 - }
125.28 - ClassLoader l = new L();
125.29 - Class<?> u2 = l.loadClass(u1.getName());
125.30 - assertEquals(l, u2.getClassLoader());
125.31 - Object obj = new Object();
125.32 - @SuppressWarnings("unchecked")
125.33 - ReferenceQueue<Object> q = (ReferenceQueue<Object>) u2.getMethod("activeReferenceQueue").invoke(null);
125.34 - RunnableRef ref = new RunnableRef(obj, q);
125.35 - synchronized (ref) {
125.36 - obj = null;
125.37 - assertGC("Ref should be GC'ed as usual", ref);
125.38 - ref.wait();
125.39 - assertTrue("Run method has been executed", ref.executed);
125.40 - }
125.41 - Reference<?> r = new WeakReference<Object>(u2);
125.42 - q = null;
125.43 - u2 = null;
125.44 - l = null;
125.45 - assertGC("#86625: Utilities.class can also be collected now", r);
125.46 - }
125.47 -
125.48 -
125.49 private static class RunnableRef extends WeakReference<Object>
125.50 implements Runnable {
125.51 public boolean wait;
126.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupArrayStorageTest.java Thu Dec 10 19:23:25 2009 -0500
126.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
126.3 @@ -1,120 +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 junit.framework.*;
126.48 -import org.netbeans.junit.*;
126.49 -import org.openide.util.Lookup;
126.50 -
126.51 -public class AbstractLookupArrayStorageTest extends AbstractLookupBaseHid {
126.52 - public AbstractLookupArrayStorageTest(java.lang.String testName) {
126.53 - super(testName, null);
126.54 - }
126.55 -
126.56 - public static TestSuite suite () {
126.57 - NbTestSuite suite = new NbTestSuite ();
126.58 - suite.addTest (new PL (2));
126.59 - suite.addTest (new AL (1));
126.60 - suite.addTest (new AL (-1));
126.61 - suite.addTest (new PL (-1));
126.62 - suite.addTest (new AL (5));
126.63 - suite.addTest (new PL (3));
126.64 - suite.addTest (new AL (2000));
126.65 - suite.addTest (new PL (2000));
126.66 - return suite;
126.67 - }
126.68 -
126.69 - static final class AL extends ArrayTestSuite {
126.70 - public AL (int trash) {
126.71 - super (trash);
126.72 - }
126.73 -
126.74 - public Lookup createLookup (Lookup lookup) {
126.75 - return lookup;
126.76 - }
126.77 -
126.78 - public void clearCaches () {
126.79 - }
126.80 -
126.81 - }
126.82 -
126.83 - static final class PL extends ArrayTestSuite {
126.84 - public PL (int trash) {
126.85 - super (trash);
126.86 - }
126.87 -
126.88 - public Lookup createLookup (Lookup lookup) {
126.89 - return new ProxyLookup (new Lookup[] { lookup });
126.90 - }
126.91 -
126.92 - public void clearCaches () {
126.93 - }
126.94 -
126.95 - }
126.96 -
126.97 - private static abstract class ArrayTestSuite extends NbTestSuite
126.98 - implements AbstractLookupBaseHid.Impl {
126.99 - private int trash;
126.100 -
126.101 - public ArrayTestSuite (int trash) {
126.102 - super (AbstractLookupArrayStorageTest.class);
126.103 - this.trash = trash;
126.104 -
126.105 - int cnt = this.countTestCases();
126.106 - for (int i = 0; i < cnt; i++) {
126.107 - Object o = this.testAt (i);
126.108 - AbstractLookupBaseHid t = (AbstractLookupBaseHid)o;
126.109 - t.impl = this;
126.110 - }
126.111 - }
126.112 -
126.113 - public Lookup createInstancesLookup (InstanceContent ic) {
126.114 - if (trash == -1) {
126.115 - return new AbstractLookup (ic, new ArrayStorage ());
126.116 - } else {
126.117 - return new AbstractLookup (ic, new ArrayStorage (new Integer (trash)));
126.118 - }
126.119 - }
126.120 -
126.121 -
126.122 - }
126.123 -}
127.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupAsynchExecutorTest.java Thu Dec 10 19:23:25 2009 -0500
127.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
127.3 @@ -1,108 +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.util.ArrayList;
127.48 -import java.util.List;
127.49 -import java.util.concurrent.Executor;
127.50 -import org.netbeans.junit.NbTestCase;
127.51 -import org.openide.util.Lookup;
127.52 -import org.openide.util.LookupEvent;
127.53 -import org.openide.util.LookupListener;
127.54 -
127.55 -public class AbstractLookupAsynchExecutorTest extends NbTestCase implements Executor {
127.56 - private List<Runnable> toRun = new ArrayList<Runnable>();
127.57 -
127.58 -
127.59 - public AbstractLookupAsynchExecutorTest(java.lang.String testName) {
127.60 - super(testName);
127.61 - }
127.62 -
127.63 - public void testCanProxyLookupHaveWrongResults() {
127.64 - final InstanceContent ic = new InstanceContent(this);
127.65 - final AbstractLookup lookup = new AbstractLookup(ic);
127.66 -
127.67 - class L implements LookupListener {
127.68 - ProxyLookup pl;
127.69 - Lookup.Result<String> original;
127.70 - Lookup.Result<String> wrapped;
127.71 - boolean ok;
127.72 -
127.73 - public void test() {
127.74 - pl = new ProxyLookup(lookup);
127.75 - original = lookup.lookupResult(String.class);
127.76 -
127.77 - original.addLookupListener(this);
127.78 -
127.79 - wrapped = pl.lookupResult(String.class);
127.80 -
127.81 - assertEquals("Original empty", 0, original.allInstances().size());
127.82 - assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
127.83 -
127.84 - ic.add("Hello!");
127.85 - }
127.86 -
127.87 - public void resultChanged(LookupEvent ev) {
127.88 - ok = true;
127.89 - assertContainsHello();
127.90 - }
127.91 -
127.92 - public void assertContainsHello() {
127.93 - assertEquals("Original has hello", 1, original.allInstances().size());
127.94 - assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
127.95 - }
127.96 -
127.97 - }
127.98 - L listener = new L();
127.99 - listener.test();
127.100 - listener.assertContainsHello();
127.101 - for (Runnable r : toRun) {
127.102 - r.run();
127.103 - }
127.104 - assertTrue("Listener called", listener.ok);
127.105 - }
127.106 -
127.107 - public void execute(Runnable command) {
127.108 - toRun.add(command);
127.109 - }
127.110 -
127.111 -}
128.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupBaseHid.java Thu Dec 10 19:23:25 2009 -0500
128.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
128.3 @@ -1,2088 +0,0 @@
128.4 -/*
128.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
128.6 - *
128.7 - * Copyright 1997-2009 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 - * Contributor(s):
128.28 - *
128.29 - * The Original Software is NetBeans. The Initial Developer of the Original
128.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
128.31 - * Microsystems, Inc. All Rights Reserved.
128.32 - *
128.33 - * If you wish your version of this file to be governed by only the CDDL
128.34 - * or only the GPL Version 2, indicate your decision by adding
128.35 - * "[Contributor] elects to include this software in this distribution
128.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
128.37 - * single choice of license, a recipient has the option to distribute
128.38 - * your version of this file under either the CDDL, the GPL Version 2 or
128.39 - * to extend the choice of license to its licensees as provided above.
128.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
128.41 - * Version 2 license, then the option applies only if the new code is
128.42 - * made subject to such option by the copyright holder.
128.43 - */
128.44 -
128.45 -package org.openide.util.lookup;
128.46 -
128.47 -import java.io.ByteArrayInputStream;
128.48 -import java.io.ByteArrayOutputStream;
128.49 -import java.io.ObjectInputStream;
128.50 -import java.io.ObjectOutputStream;
128.51 -import java.io.Serializable;
128.52 -import java.lang.ref.WeakReference;
128.53 -import java.lang.ref.Reference;
128.54 -import java.util.ArrayList;
128.55 -import java.util.Arrays;
128.56 -import java.util.Collection;
128.57 -import java.util.Collections;
128.58 -import java.util.Iterator;
128.59 -import java.util.LinkedList;
128.60 -import java.util.List;
128.61 -import java.util.concurrent.Executors;
128.62 -import java.util.concurrent.TimeUnit;
128.63 -import javax.swing.ActionMap;
128.64 -import javax.swing.InputMap;
128.65 -import org.netbeans.junit.NbTestCase;
128.66 -import org.openide.util.Lookup;
128.67 -import org.openide.util.Lookup.Template;
128.68 -import org.openide.util.LookupEvent;
128.69 -import org.openide.util.LookupListener;
128.70 -
128.71 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
128.72 -public class AbstractLookupBaseHid extends NbTestCase {
128.73 - private static AbstractLookupBaseHid running;
128.74 -
128.75 - /** instance content to work with */
128.76 - InstanceContent ic;
128.77 - /** the lookup to work on */
128.78 - protected Lookup instanceLookup;
128.79 - /** the lookup created to work with */
128.80 - private Lookup lookup;
128.81 - /** implementation of methods that can influence the behaviour */
128.82 - Impl impl;
128.83 -
128.84 - protected AbstractLookupBaseHid(String testName, Impl impl) {
128.85 - super(testName);
128.86 - if (impl == null && (this instanceof Impl)) {
128.87 - impl = (Impl)this;
128.88 - }
128.89 - this.impl = impl;
128.90 - }
128.91 -
128.92 - protected @Override void setUp() {
128.93 - this.ic = new InstanceContent ();
128.94 -
128.95 - beforeActualTest(getName());
128.96 -
128.97 - this.instanceLookup = createInstancesLookup (ic);
128.98 - this.lookup = createLookup (instanceLookup);
128.99 - running = this;
128.100 - }
128.101 -
128.102 - protected @Override void tearDown() {
128.103 - running = null;
128.104 - }
128.105 -
128.106 - /** The methods to influence test behaviour */
128.107 - public static interface Impl {
128.108 - /** Creates the initial abstract lookup.
128.109 - */
128.110 - public Lookup createInstancesLookup (InstanceContent ic);
128.111 - /** Creates an lookup for given lookup. This class just returns
128.112 - * the object passed in, but subclasses can be different.
128.113 - * @param lookup in lookup
128.114 - * @return a lookup to use
128.115 - */
128.116 - public Lookup createLookup (Lookup lookup);
128.117 -
128.118 - /** If the impl has any caches that would prevent the system
128.119 - * to not garbage collect correctly, then clear them now.
128.120 - */
128.121 - public void clearCaches ();
128.122 - }
128.123 -
128.124 - private Lookup createInstancesLookup (InstanceContent ic) {
128.125 - return impl.createInstancesLookup (ic);
128.126 - }
128.127 -
128.128 - private Lookup createLookup (Lookup lookup) {
128.129 - return impl.createLookup (lookup);
128.130 - }
128.131 -
128.132 - /** instances that we register */
128.133 - private static Object[] INSTANCES = new Object[] {
128.134 - new Integer (10),
128.135 - new Object ()
128.136 - };
128.137 -
128.138 - /** Test if first is really first.
128.139 - */
128.140 - public void testFirst () {
128.141 - Integer i1 = 1;
128.142 - Integer i2 = 2;
128.143 -
128.144 - ic.add (i1);
128.145 - ic.add (i2);
128.146 -
128.147 - Integer found = lookup.lookup(Integer.class);
128.148 - if (found != i1) {
128.149 - fail ("First object is not first: " + found + " != " + i1);
128.150 - }
128.151 -
128.152 - List<Integer> list = new ArrayList<Integer>();
128.153 - list.add (i2);
128.154 - list.add (i1);
128.155 - ic.set (list, null);
128.156 -
128.157 - found = lookup.lookup (Integer.class);
128.158 - if (found != i2) {
128.159 - fail ("Second object is not first after reorder: " + found + " != " + i2);
128.160 - }
128.161 -
128.162 - }
128.163 -
128.164 - public void testToString() {
128.165 - String txt = lookup.toString();
128.166 - assertNotNull("Something is there", txt);
128.167 - assertTrue("Something2: " + txt, txt.length() > 0);
128.168 - }
128.169 -
128.170 -
128.171 - /** Tests ordering of items in the lookup.
128.172 - */
128.173 - public void testOrder () {
128.174 - addInstances (INSTANCES);
128.175 -
128.176 - if (INSTANCES[0] != lookup.lookup (INSTANCES[0].getClass ())) {
128.177 - fail ("First object in intances not found");
128.178 - }
128.179 -
128.180 - Iterator<?> all = lookup.lookupAll(Object.class).iterator();
128.181 - checkIterator ("Difference between instances added and found", all, Arrays.asList (INSTANCES));
128.182 - }
128.183 -
128.184 - /** Checks the reorder of items in lookup reflects the result.
128.185 - * Testing both classes and interfaces, because they are often treated
128.186 - * especially.
128.187 - */
128.188 - public void testReorder () {
128.189 - String s1 = "s2";
128.190 - String s2 = "s1";
128.191 - Runnable r1 = new Runnable () {
128.192 - public void run () {}
128.193 - };
128.194 - Runnable r2 = new Runnable () {
128.195 - public void run () {}
128.196 - };
128.197 - List<Object> l = new ArrayList<Object>();
128.198 -
128.199 - l.add (s1);
128.200 - l.add (s2);
128.201 - l.add (r1);
128.202 - l.add (r2);
128.203 - ic.set (l, null);
128.204 -
128.205 - assertEquals ("s1 is found", s1, lookup.lookup (String.class));
128.206 - assertEquals ("r1 is found", r1, lookup.lookup (Runnable.class));
128.207 -
128.208 - Collections.reverse (l);
128.209 -
128.210 - ic.set (l, null);
128.211 -
128.212 - assertEquals ("s2 is found", s2, lookup.lookup (String.class));
128.213 - assertEquals ("r2 is found", r2, lookup.lookup (Runnable.class));
128.214 - }
128.215 -
128.216 - /** Tries to set empty collection to the lookup.
128.217 - */
128.218 - public void testSetEmpty () {
128.219 - ic.add ("A serializable string");
128.220 - lookup.lookup (Serializable.class);
128.221 -
128.222 - ic.set (Collections.emptyList(), null);
128.223 - }
128.224 -
128.225 - /** Tests a more complex reorder on nodes.
128.226 - */
128.227 - public void testComplexReorder () {
128.228 - Integer i1 = 1;
128.229 - Long i2 = 2L;
128.230 -
128.231 - List<Object> l = new ArrayList<Object>();
128.232 - l.add (i1);
128.233 - l.add (i2);
128.234 - ic.set (l, null);
128.235 -
128.236 - assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
128.237 - assertEquals ("Find long", i2, lookup.lookup (Long.class));
128.238 - assertEquals ("Find number", i1, lookup.lookup (Number.class));
128.239 -
128.240 - Collections.reverse (l);
128.241 -
128.242 - ic.set (l, null);
128.243 -
128.244 - assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
128.245 - assertEquals ("Find long", i2, lookup.lookup (Long.class));
128.246 - assertEquals ("Find number", i2, lookup.lookup (Number.class));
128.247 - }
128.248 -
128.249 - /** Checks whether setPairs keeps the order.
128.250 - */
128.251 - public void testSetPairs () {
128.252 - // test setPairs method
128.253 - List<Object> li = new ArrayList<Object>();
128.254 - li.addAll (Arrays.asList (INSTANCES));
128.255 - ic.set (li, null);
128.256 -
128.257 - Lookup.Result<Object> res = lookup.lookupResult(Object.class);
128.258 - Iterator<?> all = res.allInstances().iterator();
128.259 - checkIterator ("Original order not kept", all, li);
128.260 -
128.261 - // reverse the order
128.262 - Collections.reverse (li);
128.263 -
128.264 - // change the pairs
128.265 - LL listener = new LL (res);
128.266 - res.addLookupListener (listener);
128.267 - ic.set (li, null);
128.268 - if (listener.getCount () != 1) {
128.269 - fail ("Result has not changed even we set reversed order");
128.270 - }
128.271 -
128.272 - all = res.allInstances ().iterator ();
128.273 - checkIterator ("Reversed order not kept", all, li);
128.274 - }
128.275 -
128.276 - /** Checks whether setPairs fires correct events.
128.277 - */
128.278 - public void testSetPairsFire () {
128.279 - // test setPairs method
128.280 - List<Object> li = new ArrayList<Object>();
128.281 - li.addAll (Arrays.asList (INSTANCES));
128.282 - ic.set (li, null);
128.283 -
128.284 - Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
128.285 - Iterator<?> all = res.allInstances().iterator();
128.286 - checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
128.287 -
128.288 - // change the pairs
128.289 - LL listener = new LL (res);
128.290 - res.addLookupListener (listener);
128.291 -
128.292 - List<Object> l2 = new ArrayList<Object>(li);
128.293 - l2.remove (INSTANCES[0]);
128.294 - ic.set (l2, null);
128.295 -
128.296 - all = lookup.lookupAll(Object.class).iterator();
128.297 - checkIterator ("The removed integer is not noticed", all, l2);
128.298 -
128.299 - if (listener.getCount () != 1) {
128.300 - fail ("Nothing has not been fired");
128.301 - }
128.302 - }
128.303 -
128.304 - /** Checks whether set pairs does not fire when they should not.
128.305 - */
128.306 - public void testSetPairsDoesNotFire () {
128.307 - Object tmp = new Object ();
128.308 -
128.309 - List<Object> li = new ArrayList<Object>();
128.310 - li.add (tmp);
128.311 - li.addAll (Arrays.asList (INSTANCES));
128.312 - ic.set (li, null);
128.313 -
128.314 - Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
128.315 - Iterator<?> all = res.allInstances ().iterator ();
128.316 - checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
128.317 -
128.318 - // change the pairs
128.319 - LL listener = new LL (res);
128.320 - res.addLookupListener (listener);
128.321 -
128.322 - List<Object> l2 = new ArrayList<Object>(li);
128.323 - l2.remove (tmp);
128.324 - ic.set (l2, null);
128.325 -
128.326 - all = lookup.lookupAll(Object.class).iterator();
128.327 - checkIterator ("The removed integer is not noticed", all, l2);
128.328 -
128.329 - if (listener.getCount () != 0) {
128.330 - fail ("Something has been fired");
128.331 - }
128.332 - }
128.333 -
128.334 - /** Test whether after registration it is possible to find registered objects
128.335 - *
128.336 - */
128.337 - public void testLookupAndAdd () throws Exception {
128.338 - addInstances (INSTANCES);
128.339 -
128.340 - for (int i = 0; i < INSTANCES.length; i++) {
128.341 - Object obj = INSTANCES[i];
128.342 - findAll (lookup, obj.getClass (), true);
128.343 - }
128.344 - }
128.345 -
128.346 - /** Tries to find all classes and superclasses in the lookup.
128.347 - */
128.348 - private void findAll(Lookup lookup, Class<?> clazz, boolean shouldBeThere) {
128.349 - if (clazz == null) return;
128.350 -
128.351 - Object found = lookup.lookup (clazz);
128.352 - if (found == null) {
128.353 - if (shouldBeThere) {
128.354 - // should find at either instance or something else, but must
128.355 - // find at least something
128.356 - fail ("Lookup (" + clazz.getName () + ") found nothing");
128.357 - }
128.358 - } else {
128.359 - if (!shouldBeThere) {
128.360 - // should find at either instance or something else, but must
128.361 - // find at least something
128.362 - fail ("Lookup (" + clazz.getName () + ") found " + found);
128.363 - }
128.364 - }
128.365 -
128.366 - Lookup.Result<?> res = lookup.lookupResult(clazz);
128.367 - Collection<?> collection = res.allInstances();
128.368 -
128.369 - for (int i = 0; i < INSTANCES.length; i++) {
128.370 - boolean isSubclass = clazz.isInstance (INSTANCES[i]);
128.371 - boolean isThere = collection.contains (INSTANCES[i]);
128.372 -
128.373 - if (isSubclass != isThere) {
128.374 - // a problem found
128.375 - // should find at either instance or something else, but must
128.376 - // find at least something
128.377 - fail ("Lookup.Result (" + clazz.getName () + ") for " + INSTANCES[i] + " is subclass: " + isSubclass + " isThere: " + isThere);
128.378 - }
128.379 - }
128.380 -
128.381 - // go on for superclasses
128.382 -
128.383 - findAll (lookup, clazz.getSuperclass (), shouldBeThere);
128.384 -
128.385 - Class[] ies = clazz.getInterfaces ();
128.386 - for (int i = 0; i < ies.length; i++) {
128.387 - findAll (lookup, ies[i], shouldBeThere);
128.388 - }
128.389 - }
128.390 -
128.391 - /** Test if it is possible to remove a registered object. */
128.392 - public void testRemoveRegisteredObject() {
128.393 - Integer inst = new Integer(10);
128.394 -
128.395 - ic.add(inst);
128.396 - if (lookup.lookup(inst.getClass()) == null) {
128.397 - // should find an instance
128.398 - fail("Lookup (" + inst.getClass().getName () + ") found nothing");
128.399 - }
128.400 -
128.401 - ic.remove(inst);
128.402 - if (lookup.lookup(inst.getClass()) != null) {
128.403 - // should NOT find an instance
128.404 - fail("Lookup (" + inst.getClass().getName () +
128.405 - ") found an instance after remove operation");
128.406 - }
128.407 - }
128.408 -
128.409 - public void testCanReturnReallyStrangeResults () throws Exception {
128.410 - class QueryingPair extends AbstractLookup.Pair<Object> {
128.411 - private Integer i = 434;
128.412 -
128.413 - //
128.414 - // do the test
128.415 - //
128.416 -
128.417 - public void doTest () throws Exception {
128.418 - ic.add (i);
128.419 - ic.addPair (this);
128.420 -
128.421 - Object found = lookup.lookup (QueryingPair.class);
128.422 - assertEquals ("This object is found", this, found);
128.423 - }
128.424 -
128.425 -
128.426 - //
128.427 - // Implementation of pair
128.428 - //
128.429 -
128.430 - public String getId() {
128.431 - return getType ().toString();
128.432 - }
128.433 -
128.434 - public String getDisplayName() {
128.435 - return getId ();
128.436 - }
128.437 -
128.438 - public Class<?> getType() {
128.439 - return getClass ();
128.440 - }
128.441 -
128.442 - protected boolean creatorOf(Object obj) {
128.443 - return obj == this;
128.444 - }
128.445 -
128.446 - protected boolean instanceOf(Class<?> c) {
128.447 - assertEquals ("Integer found or exception is thrown", i, lookup.lookup (Integer.class));
128.448 - return c.isAssignableFrom(getType ());
128.449 - }
128.450 -
128.451 - public Object getInstance() {
128.452 - return this;
128.453 - }
128.454 -
128.455 -
128.456 - }
128.457 -
128.458 -
128.459 - QueryingPair qp = new QueryingPair ();
128.460 - qp.doTest ();
128.461 - }
128.462 -
128.463 - /** Test of firing events. */
128.464 - public void testLookupListener() {
128.465 - Object inst = 10;
128.466 - Lookup.Result<?> res = lookup.lookupResult(inst.getClass());
128.467 - res.allInstances ();
128.468 -
128.469 - LL listener = new LL(res);
128.470 - res.addLookupListener(listener);
128.471 -
128.472 - ic.add(inst);
128.473 - if (listener.getCount() == 0) {
128.474 - fail("None event fired during NbLookup.addPair()");
128.475 - }
128.476 -
128.477 - ic.remove(inst);
128.478 - if (listener.getCount() == 0) {
128.479 - fail("None event fired during NbLookup.removePair()");
128.480 - }
128.481 -
128.482 - ic.add(inst);
128.483 - if (listener.getCount() == 0) {
128.484 - fail("None event fired during second NbLookup.addPair()");
128.485 - }
128.486 -
128.487 - ic.remove(inst);
128.488 - if (listener.getCount() == 0) {
128.489 - fail("None event fired during second NbLookup.removePair()");
128.490 - }
128.491 - }
128.492 -
128.493 - /** Testing identity of the lookup.
128.494 - */
128.495 - public void testId () {
128.496 - Lookup.Template<?> templ;
128.497 - int cnt;
128.498 -
128.499 - addInstances (INSTANCES);
128.500 -
128.501 - Lookup.Result<?> res = lookup.lookupResult(Object.class);
128.502 - for (AbstractLookup.Item<?> item : res.allItems()) {
128.503 -
128.504 - templ = new Lookup.Template<Object>(null, item.getId(), null);
128.505 - cnt = lookup.lookup (templ).allInstances ().size ();
128.506 - if (cnt != 1) {
128.507 - fail ("Identity lookup failed. Instances = " + cnt);
128.508 - }
128.509 -
128.510 - templ = makeTemplate(item.getType(), item.getId());
128.511 - cnt = lookup.lookup (templ).allInstances ().size ();
128.512 - if (cnt != 1) {
128.513 - fail ("Identity lookup with type failed. Instances = " + cnt);
128.514 - }
128.515 -
128.516 - templ = makeTemplate(this.getClass(), item.getId());
128.517 - cnt = lookup.lookup (templ).allInstances ().size ();
128.518 - if (cnt != 0) {
128.519 - fail ("Identity lookup with wrong type failed. Instances = " + cnt);
128.520 - }
128.521 -
128.522 - templ = new Lookup.Template<Object>(null, null, item.getInstance());
128.523 - cnt = lookup.lookup (templ).allInstances ().size ();
128.524 - if (cnt != 1) {
128.525 - fail ("Instance lookup failed. Instances = " + cnt);
128.526 - }
128.527 -
128.528 - templ = new Lookup.Template<Object>(null, item.getId(), item.getInstance());
128.529 - cnt = lookup.lookup (templ).allInstances ().size ();
128.530 - if (cnt != 1) {
128.531 - fail ("Instance & identity lookup failed. Instances = " + cnt);
128.532 - }
128.533 -
128.534 - }
128.535 - }
128.536 - private static <T> Lookup.Template<T> makeTemplate(Class<T> clazz, String id) { // captures type parameter
128.537 - return new Lookup.Template<T>(clazz, id, null);
128.538 - }
128.539 -
128.540 - /** Tests adding and removing.
128.541 - */
128.542 - public void testAddAndRemove () throws Exception {
128.543 - Object map = new javax.swing.ActionMap ();
128.544 - LL ll = new LL ();
128.545 -
128.546 - Lookup.Result<?> res = lookup.lookupResult(map.getClass());
128.547 - res.allItems();
128.548 - res.addLookupListener (ll);
128.549 - ll.source = res;
128.550 -
128.551 - ic.add (map);
128.552 -
128.553 - assertEquals ("First change when adding", ll.getCount (), 1);
128.554 -
128.555 - ic.remove (map);
128.556 -
128.557 - assertEquals ("Second when removing", ll.getCount (), 1);
128.558 -
128.559 - ic.add (map);
128.560 -
128.561 - assertEquals ("Third when readding", ll.getCount (), 1);
128.562 -
128.563 - ic.remove (map);
128.564 -
128.565 - assertEquals ("Forth when reremoving", ll.getCount (), 1);
128.566 -
128.567 - }
128.568 -
128.569 - /** Will a class garbage collect even it is registered in lookup.
128.570 - */
128.571 - public void testGarbageCollect () throws Exception {
128.572 - ClassLoader l = new CL ();
128.573 - Class<?> c = l.loadClass(Garbage.class.getName());
128.574 - Reference<?> ref = new WeakReference<Object>(c);
128.575 -
128.576 - lookup.lookup (c);
128.577 -
128.578 - // now test garbage collection
128.579 - c = null;
128.580 - l = null;
128.581 - impl.clearCaches ();
128.582 - assertGC ("The classloader has not been garbage collected!", ref);
128.583 - }
128.584 -
128.585 - /** Items are the same as results.
128.586 - */
128.587 - public void testItemsAndIntances () {
128.588 - addInstances (INSTANCES);
128.589 -
128.590 - Lookup.Result<Object> r = lookup.lookupResult(Object.class);
128.591 - Collection<? extends Lookup.Item<?>> items = r.allItems();
128.592 - Collection<?> insts = r.allInstances();
128.593 -
128.594 - if (items.size () != insts.size ()) {
128.595 - fail ("Different size of sets");
128.596 - }
128.597 -
128.598 - for (Lookup.Item<?> item : items) {
128.599 - if (!insts.contains (item.getInstance ())) {
128.600 - fail ("Intance " + item.getInstance () + " is missing in " + insts);
128.601 - }
128.602 - }
128.603 - }
128.604 -
128.605 - /** Checks search for interface.
128.606 - */
128.607 - public void testSearchForInterface () {
128.608 - Lookup.Template<Serializable> t = new Lookup.Template<Serializable>(Serializable.class, null, null);
128.609 -
128.610 - assertNull("Nothing to find", lookup.lookupItem (t));
128.611 -
128.612 - Serializable s = new Serializable () {};
128.613 - ic.add (s);
128.614 -
128.615 - Lookup.Item item = lookup.lookupItem (t);
128.616 - assertNotNull ("Something found", item);
128.617 - }
128.618 -
128.619 - /** Test to add broken item if it incorrectly answers instanceOf questions.
128.620 - */
128.621 - public void testIncorectInstanceOf40364 () {
128.622 - final Long sharedLong = new Long (0);
128.623 -
128.624 - class P extends AbstractLookup.Pair<Object> {
128.625 - public boolean isLong;
128.626 -
128.627 - P (boolean b) {
128.628 - isLong = b;
128.629 - }
128.630 -
128.631 - protected boolean creatorOf (Object obj) {
128.632 - return obj == sharedLong;
128.633 - }
128.634 -
128.635 - public String getDisplayName () {
128.636 - return "";
128.637 - }
128.638 -
128.639 - public String getId () {
128.640 - return "";
128.641 - }
128.642 -
128.643 - public Object getInstance () {
128.644 - return sharedLong;
128.645 - }
128.646 -
128.647 - public Class<?> getType() {
128.648 - return isLong ? Long.class : Number.class;
128.649 - }
128.650 -
128.651 - protected boolean instanceOf(Class<?> c) {
128.652 - return c.isAssignableFrom (getType ());
128.653 - }
128.654 -
128.655 - public @Override int hashCode() {
128.656 - return getClass ().hashCode ();
128.657 - }
128.658 -
128.659 - public @Override boolean equals(Object obj) {
128.660 - return obj != null && getClass ().equals (obj.getClass ());
128.661 - }
128.662 - }
128.663 -
128.664 - // to create the right structure in the lookup
128.665 - lookup.lookup (Object.class);
128.666 - lookup.lookup (Long.class);
128.667 - lookup.lookup (Number.class);
128.668 -
128.669 - P lng1 = new P (true);
128.670 - ic.addPair (lng1);
128.671 -
128.672 - P lng2 = new P (false);
128.673 - ic.setPairs (Collections.singleton (lng2));
128.674 -
128.675 - Collection<? extends Lookup.Item<?>> res = lookup.lookupResult(Object.class).allItems();
128.676 - assertEquals ("Just one pair", 1, res.size ());
128.677 - }
128.678 -
128.679 - public void testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly () throws Exception {
128.680 - class X implements TestInterfaceInheritanceA, TestInterfaceInheritanceB {
128.681 - }
128.682 - final X shared = new X ();
128.683 -
128.684 - class P extends AbstractLookup.Pair<Object> {
128.685 - public int howLong;
128.686 -
128.687 - P (int b) {
128.688 - howLong = b;
128.689 - }
128.690 -
128.691 - protected boolean creatorOf (Object obj) {
128.692 - return obj == shared;
128.693 - }
128.694 -
128.695 - public String getDisplayName () {
128.696 - return "";
128.697 - }
128.698 -
128.699 - public String getId () {
128.700 - return "";
128.701 - }
128.702 -
128.703 - public Object getInstance () {
128.704 - return shared;
128.705 - }
128.706 -
128.707 - public Class<?> getType() {
128.708 - return howLong == 0 ? TestInterfaceInheritanceB.class : TestInterfaceInheritanceA.class;
128.709 - }
128.710 -
128.711 - protected boolean instanceOf(Class<?> c) {
128.712 - return c.isAssignableFrom (getType ());
128.713 - }
128.714 -
128.715 - public @Override int hashCode() {
128.716 - return getClass ().hashCode ();
128.717 - }
128.718 -
128.719 - public @Override boolean equals(Object obj) {
128.720 - if (obj instanceof P) {
128.721 - P p = (P)obj;
128.722 - if (this.howLong > 0) {
128.723 - this.howLong--;
128.724 - return false;
128.725 - }
128.726 - if (p.howLong > 0) {
128.727 - p.howLong--;
128.728 - return false;
128.729 - }
128.730 - return getClass ().equals (p.getClass ());
128.731 - }
128.732 - return false;
128.733 - }
128.734 - }
128.735 -
128.736 - // to create the right structure in the lookup
128.737 - Lookup.Result<?> a = lookup.lookupResult(TestInterfaceInheritanceA.class);
128.738 - Lookup.Result<?> b = lookup.lookupResult(TestInterfaceInheritanceB.class);
128.739 -
128.740 - P lng1 = new P (0);
128.741 - ic.addPair (lng1);
128.742 -
128.743 - assertEquals ("One in a", 1, a.allItems ().size ());
128.744 - assertEquals ("One in b", 1, b.allItems ().size ());
128.745 -
128.746 - P lng2 = new P (1);
128.747 -
128.748 -
128.749 - /* Following call used to generate this exception:
128.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
128.751 - at org.openide.util.lookup.ALPairComparator.compare(ALPairComparator.java:52)
128.752 - at java.util.Arrays.mergeSort(Arrays.java:1284)
128.753 - at java.util.Arrays.sort(Arrays.java:1223)
128.754 - at java.util.Collections.sort(Collections.java:159)
128.755 - at org.openide.util.lookup.InheritanceTree.retainAllInterface(InheritanceTree.java:753)
128.756 - at org.openide.util.lookup.InheritanceTree.retainAll(InheritanceTree.java:183)
128.757 - at org.openide.util.lookup.DelegatingStorage.retainAll(DelegatingStorage.java:83)
128.758 - at org.openide.util.lookup.AbstractLookup.setPairsAndCollectListeners(AbstractLookup.java:238)
128.759 - at org.openide.util.lookup.AbstractLookup.setPairs(AbstractLookup.java:203)
128.760 - at org.openide.util.lookup.AbstractLookup$Content.setPairs(AbstractLookup.java:885)
128.761 - at org.openide.util.lookup.AbstractLookupBaseHid.testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly(AbstractLookupBaseHid.java:696)
128.762 - at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
128.763 - at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
128.764 - at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
128.765 - at org.netbeans.junit.NbTestCase.run(NbTestCase.java:119)
128.766 - */
128.767 - ic.setPairs (Collections.singleton (lng2));
128.768 -
128.769 -
128.770 - }
128.771 -
128.772 - public void testInstancesArePreservedFoundWhenFixing48590 () throws Exception {
128.773 - class X implements Runnable, Serializable {
128.774 - public void run () {
128.775 -
128.776 - }
128.777 -
128.778 - public void assertOnlyMe (String msg, Lookup.Result<?> res) {
128.779 - Collection<?> col = res.allInstances();
128.780 - assertEquals (msg + " just one", 1, col.size ());
128.781 - assertSame (msg + " and it is me", this, col.iterator ().next ());
128.782 - }
128.783 - }
128.784 -
128.785 - Lookup.Result<?> runnable = lookup.lookupResult(Runnable.class);
128.786 - Lookup.Result<?> serial = lookup.lookupResult(Serializable.class);
128.787 -
128.788 -
128.789 - X x = new X ();
128.790 - ic.add (x);
128.791 -
128.792 -
128.793 - x.assertOnlyMe ("x implements it (1)", runnable);
128.794 - x.assertOnlyMe ("x implements it (2)", serial);
128.795 -
128.796 - ic.set (Collections.singleton (x), null);
128.797 -
128.798 - x.assertOnlyMe ("x implements it (3)", runnable);
128.799 - x.assertOnlyMe ("x implements it (4)", serial);
128.800 - }
128.801 -
128.802 - /** Testing lookup of inherited classes. */
128.803 - public void testInheritance() {
128.804 - class A {}
128.805 - class B extends A implements java.rmi.Remote {}
128.806 - class BB extends B {}
128.807 - class C extends A implements java.rmi.Remote {}
128.808 - class D extends A {}
128.809 -
128.810 - A[] types = {new B(), new BB(), new C(), new D()};
128.811 -
128.812 - for (int i = 0; i < types.length; i++) {
128.813 - ic.add(types[i]);
128.814 - if (lookup.lookup(types[i].getClass()) == null) {
128.815 - // should find an instance
128.816 - fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
128.817 - }
128.818 - }
128.819 -
128.820 - int size1, size2;
128.821 -
128.822 - //interface query
128.823 - size1 = lookup.lookupAll(java.rmi.Remote.class).size();
128.824 - size2 = countInstances(types, java.rmi.Remote.class);
128.825 -
128.826 - if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
128.827 -
128.828 - // superclass query
128.829 - size1 = lookup.lookupAll(A.class).size();
128.830 - size2 = countInstances(types, A.class);
128.831 -
128.832 - if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
128.833 - }
128.834 -
128.835 - /** Test interface inheritance.
128.836 - */
128.837 - public void testInterfaceInheritance() {
128.838 - TestInterfaceInheritanceA[] types = {
128.839 - new TestInterfaceInheritanceB() {},
128.840 - new TestInterfaceInheritanceBB() {},
128.841 - new TestInterfaceInheritanceC() {},
128.842 - new TestInterfaceInheritanceD() {}
128.843 - };
128.844 -
128.845 - for (int i = 0; i < types.length; i++) {
128.846 - ic.add(types[i]);
128.847 - if (lookup.lookup(types[i].getClass()) == null) {
128.848 - // should find an instance
128.849 - fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
128.850 - }
128.851 - }
128.852 -
128.853 - int size1, size2;
128.854 -
128.855 - //interface query
128.856 - LL l = new LL ();
128.857 - Lookup.Result<?> res = lookup.lookupResult(java.rmi.Remote.class);
128.858 - l.source = res;
128.859 - size1 = res.allInstances().size();
128.860 - size2 = countInstances(types, java.rmi.Remote.class);
128.861 -
128.862 - if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
128.863 -
128.864 - // superclass query
128.865 - size1 = lookup.lookupAll(TestInterfaceInheritanceA.class).size();
128.866 - size2 = countInstances(types, TestInterfaceInheritanceA.class);
128.867 -
128.868 - if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
128.869 -
128.870 - res.addLookupListener (l);
128.871 - ic.remove (types[0]);
128.872 -
128.873 - if (l.getCount () != 1) {
128.874 - fail ("No notification that a Remote is removed");
128.875 - }
128.876 - }
128.877 -
128.878 - /** Checks whether the AbstractLookup is guarded against modifications
128.879 - * while doing some kind of modification.
128.880 - */
128.881 - public void testModificationArePreventedWhenDoingModifications () throws Exception {
128.882 - BrokenPair broken = new BrokenPair (true, false);
128.883 - ic.addPair (broken);
128.884 -
128.885 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
128.886 - Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
128.887 - assertEquals ("Broken is found", broken, item);
128.888 - }
128.889 -
128.890 - public void testModificationArePreventedWhenDoingModificationsResult () throws Exception {
128.891 - BrokenPair broken = new BrokenPair (false, true);
128.892 - ic.addPair (broken);
128.893 -
128.894 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
128.895 -
128.896 - Collection<? extends BrokenPair> c = lookup.lookup (templ).allInstances();
128.897 - assertEquals ("One item", 1, c.size ());
128.898 - assertEquals ("Broken is found again", broken, c.iterator().next ());
128.899 - }
128.900 -
128.901 - public void testModificationArePreventedWhenDoingModificationsItemAndResult () throws Exception {
128.902 - BrokenPair broken = new BrokenPair (false, true);
128.903 - ic.addPair (broken);
128.904 -
128.905 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
128.906 - Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
128.907 - assertEquals ("Broken is found", broken, item);
128.908 -
128.909 - Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
128.910 - assertEquals ("One item", 1, c.size ());
128.911 - assertEquals ("Broken is found again", broken, c.iterator().next ());
128.912 - }
128.913 -
128.914 - public void testModificationArePreventedWhenDoingModificationsResultAndItem () throws Exception {
128.915 - BrokenPair broken = new BrokenPair (false, true);
128.916 - ic.addPair (broken);
128.917 -
128.918 - Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
128.919 - Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
128.920 - assertEquals ("One item", 1, c.size ());
128.921 - assertEquals ("Broken is found again", broken, c.iterator().next ());
128.922 -
128.923 - Object item = lookup.lookupItem (templ);
128.924 - assertEquals ("Broken is found", broken, item);
128.925 - }
128.926 -
128.927 - public void testAddALotOfPairsIntoTheLookupOneByOne () throws Exception {
128.928 - Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
128.929 - for (int i = 0; i < 1000; i++) {
128.930 - ic.add(i);
128.931 - }
128.932 - assertEquals (
128.933 - "there is the right count",
128.934 - 1000,
128.935 - res.allItems().size ()
128.936 - );
128.937 - }
128.938 -
128.939 - public void testAddALotOfPairsIntoTheLookup () throws Exception {
128.940 - List<Integer> arr = new ArrayList<Integer>();
128.941 - for (int i = 0; i < 1000; i++) {
128.942 - arr.add(i);
128.943 - }
128.944 - ic.set (arr, null);
128.945 -
128.946 - assertEquals (
128.947 - "there is the right count",
128.948 - 1000,
128.949 - lookup.lookupResult(Integer.class).allItems().size()
128.950 - );
128.951 - }
128.952 -
128.953 -
128.954 - public void testDoubleAddIssue35274 () throws Exception {
128.955 - class P extends AbstractLookup.Pair<Object> {
128.956 - protected boolean creatorOf(Object obj) { return false; }
128.957 - public String getDisplayName() { return ""; }
128.958 - public String getId() { return ""; }
128.959 - public Object getInstance() { return null; }
128.960 - public Class<?> getType() { return Object.class; }
128.961 - protected boolean instanceOf(Class<?> c) { return c.isAssignableFrom(getType ()); }
128.962 - public @Override int hashCode() {return getClass().hashCode();}
128.963 - public @Override boolean equals(Object obj) {return getClass() == obj.getClass();}
128.964 - }
128.965 -
128.966 - P p = new P ();
128.967 -
128.968 - ic.addPair (p);
128.969 - ic.addPair (p);
128.970 -
128.971 - Lookup.Result<Object> result = lookup.lookupResult(Object.class);
128.972 - Collection res = result.allItems ();
128.973 - assertEquals ("One item there", 1, res.size ());
128.974 - assertTrue ("It is the p", p == res.iterator ().next ());
128.975 -
128.976 - P p2 = new P ();
128.977 - ic.addPair (p2);
128.978 -
128.979 - Reference<?> ref = new WeakReference<Object>(result);
128.980 - result = null;
128.981 - assertGC ("The result can disappear", ref);
128.982 -
128.983 - impl.clearCaches ();
128.984 -
128.985 - result = lookup.lookupResult(Object.class);
128.986 - res = result.allItems ();
128.987 - assertEquals ("One item is still there", 1, res.size ());
128.988 - assertTrue ("But the p2 replaced p", p2 == res.iterator ().next ());
128.989 -
128.990 - }
128.991 -
128.992 - /** Test for proper serialization.
128.993 - */
128.994 - public void testSerializationSupport () throws Exception {
128.995 - doSerializationSupport (1);
128.996 - }
128.997 - public void testDoubleSerializationSupport () throws Exception {
128.998 - doSerializationSupport (2);
128.999 - }
128.1000 -
128.1001 - private void doSerializationSupport (int count) throws Exception {
128.1002 - if (lookup instanceof Serializable) {
128.1003 - ic.addPair (new SerialPair ("1"));
128.1004 - ic.addPair (new SerialPair ("2"));
128.1005 - ic.addPair (new SerialPair ("3"));
128.1006 -
128.1007 - Lookup l = (Lookup)reserialize(lookup);
128.1008 -
128.1009 - assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
128.1010 -
128.1011 - assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
128.1012 -
128.1013 - while (count-- > 0) {
128.1014 - l = (Lookup)reserialize(l);
128.1015 - }
128.1016 -
128.1017 - assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
128.1018 -
128.1019 - assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
128.1020 - }
128.1021 - }
128.1022 -
128.1023 - /** When a lookup with two different versions of the same class
128.1024 - * get's serialized, the results may be very bad.
128.1025 - */
128.1026 - public void testSerializationOfTwoClassesWithTheSameName () throws Exception {
128.1027 - if (lookup instanceof Serializable) {
128.1028 - doTwoSerializedClasses (false, false);
128.1029 - }
128.1030 - }
128.1031 - public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSave () throws Exception {
128.1032 - if (lookup instanceof Serializable) {
128.1033 - doTwoSerializedClasses (true, false);
128.1034 - }
128.1035 - }
128.1036 - public void testSerializationOfTwoClassesWithTheSameNameWithBroken () throws Exception {
128.1037 - if (lookup instanceof Serializable) {
128.1038 - doTwoSerializedClasses (false, true);
128.1039 - }
128.1040 - }
128.1041 - public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSaveWithBroken () throws Exception {
128.1042 - if (lookup instanceof Serializable) {
128.1043 - doTwoSerializedClasses (true, true);
128.1044 - }
128.1045 - }
128.1046 -
128.1047 - private void doTwoSerializedClasses (boolean queryBeforeSerialization, boolean useBroken) throws Exception {
128.1048 - ClassLoader loader = new CL ();
128.1049 - Class c = loader.loadClass (Garbage.class.getName ());
128.1050 -
128.1051 - // in case of InheritanceTree it creates a slot for class Garbage
128.1052 - lookup.lookup(c);
128.1053 -
128.1054 - // but creates new instance and adds it into the lookup
128.1055 - // without querying for it
128.1056 - loader = new CL ();
128.1057 - c = loader.loadClass (Garbage.class.getName ());
128.1058 -
128.1059 - Object theInstance = c.newInstance ();
128.1060 -
128.1061 - ic.addPair (new SerialPair (theInstance));
128.1062 -
128.1063 - Broken2Pair broken = null;
128.1064 - if (useBroken) {
128.1065 - broken = new Broken2Pair ();
128.1066 - ic.addPair (broken);
128.1067 -
128.1068 - assertNull (
128.1069 - "We need to create the slot for the List as " +
128.1070 - "the Broken2Pair will ask for it after deserialization",
128.1071 - lookup.lookup (java.awt.List.class)
128.1072 - );
128.1073 - }
128.1074 -
128.1075 - if (queryBeforeSerialization) {
128.1076 - assertEquals ("Instance is found", theInstance, lookup.lookup (c));
128.1077 - }
128.1078 -
128.1079 - // replace the old lookup with new one
128.1080 - lookup = (Lookup)reserialize(lookup);
128.1081 -
128.1082 - Lookup.Result result = lookup.lookup (new Lookup.Template (Garbage.class));
128.1083 - assertEquals ("One item is the result", 1, result.allInstances ().size ());
128.1084 - Object r = result.allInstances ().iterator ().next ();
128.1085 - assertNotNull("A value is found", r);
128.1086 - assertEquals ("It is of the right class", Garbage.class, r.getClass());
128.1087 - }
128.1088 -
128.1089 - /** Test of reorder and item change which used to fail on interfaces.
128.1090 - */
128.1091 - public void testReoderingIssue13779 () throws Exception {
128.1092 - LinkedList arr = new LinkedList ();
128.1093 -
128.1094 - class R extends Exception implements Cloneable {
128.1095 - }
128.1096 - Object o1 = new R ();
128.1097 - Object o2 = new R ();
128.1098 - Object o3 = new R ();
128.1099 -
128.1100 - arr.add (o1);
128.1101 - arr.add (o2);
128.1102 -
128.1103 - ic.set (arr, null);
128.1104 -
128.1105 - Lookup.Result objectResult = lookup.lookup (new Lookup.Template (Exception.class));
128.1106 - Lookup.Result interfaceResult = lookup.lookup (new Lookup.Template (Cloneable.class));
128.1107 - objectResult.allItems ();
128.1108 - interfaceResult.allItems ();
128.1109 -
128.1110 - LL l1 = new LL (objectResult);
128.1111 - LL l2 = new LL (interfaceResult);
128.1112 -
128.1113 - objectResult.addLookupListener(l1);
128.1114 - interfaceResult.addLookupListener(l2);
128.1115 -
128.1116 - arr.addFirst (o3);
128.1117 -
128.1118 - ic.set (arr, null);
128.1119 -
128.1120 - assertEquals ("One change on objects", 1, l1.getCount ());
128.1121 - assertEquals ("One change on interfaces", 1, l2.getCount ());
128.1122 -
128.1123 - arr.addFirst (new Cloneable () { });
128.1124 - ic.set (arr, null);
128.1125 -
128.1126 - assertEquals ("No change on objects", 0, l1.getCount ());
128.1127 - assertEquals ("But one change on interfaces", 1, l2.getCount ());
128.1128 -
128.1129 - }
128.1130 -
128.1131 - public void testDeadlockBetweenProxyResultAndLookupIssue47772 () throws Exception {
128.1132 - final String myModule = "My Module";
128.1133 - ic.add (myModule);
128.1134 -
128.1135 - class MyProxy extends ProxyLookup {
128.1136 - public MyProxy () {
128.1137 - super (new Lookup[] { lookup });
128.1138 - }
128.1139 - }
128.1140 - final MyProxy my = new MyProxy ();
128.1141 -
128.1142 - final Lookup.Result allModules = my.lookup (new Lookup.Template (String.class));
128.1143 -
128.1144 - class PairThatNeedsInfoAboutModules extends AbstractLookup.Pair {
128.1145 - public String getDisplayName () {
128.1146 - return "Need a module";
128.1147 - }
128.1148 - public String getId () {
128.1149 - return getDisplayName ();
128.1150 - }
128.1151 - public Class getType () {
128.1152 - return Integer.class;
128.1153 - }
128.1154 - protected boolean instanceOf (Class c) {
128.1155 - if (c == Integer.class) {
128.1156 - synchronized (this) {
128.1157 - notifyAll ();
128.1158 - try {
128.1159 - wait (1000);
128.1160 - } catch (InterruptedException ex) {
128.1161 - fail (ex.getMessage ());
128.1162 - }
128.1163 - }
128.1164 - java.util.Collection coll = allModules.allInstances ();
128.1165 - assertEquals ("Size is 1", 1, coll.size ());
128.1166 - assertEquals ("My module is there", myModule, coll.iterator ().next ());
128.1167 - }
128.1168 - return c.isAssignableFrom (Integer.class);
128.1169 - }
128.1170 -
128.1171 - public Object getInstance () {
128.1172 - return new Integer (10);
128.1173 - }
128.1174 -
128.1175 - protected boolean creatorOf (Object obj) {
128.1176 - return new Integer (10).equals (obj);
128.1177 - }
128.1178 - }
128.1179 -
128.1180 - PairThatNeedsInfoAboutModules pair = new PairThatNeedsInfoAboutModules ();
128.1181 - ic.addPair (pair);
128.1182 -
128.1183 - synchronized (pair) {
128.1184 - class BlockInInstanceOf implements Runnable {
128.1185 - public void run () {
128.1186 - Integer i = my.lookup(Integer.class);
128.1187 - assertEquals (new Integer (10), i);
128.1188 - }
128.1189 - }
128.1190 - BlockInInstanceOf blk = new BlockInInstanceOf ();
128.1191 - Executors.newSingleThreadScheduledExecutor().schedule(blk, 0, TimeUnit.MICROSECONDS);
128.1192 - pair.wait ();
128.1193 - }
128.1194 -
128.1195 - java.util.Collection coll = allModules.allInstances ();
128.1196 - assertEquals ("Size is 1", 1, coll.size ());
128.1197 - assertEquals ("My module is there", myModule, coll.iterator ().next ());
128.1198 - }
128.1199 -
128.1200 - public void testAWayToGenerateProblem13779 () {
128.1201 - ic.add (new Integer (1));
128.1202 - ic.add (new Integer (2));
128.1203 - ic.add (new Integer (1));
128.1204 - ic.add (new Integer (2));
128.1205 -
128.1206 - Collection c = lookup.lookup (new Lookup.Template (Integer.class)).allInstances ();
128.1207 - assertEquals ("There are two objects", 2, c.size ());
128.1208 -
128.1209 - }
128.1210 -
128.1211 - /** Replacing items with different objects.
128.1212 - */
128.1213 - public void testReplacingObjectsDoesNotGenerateException () throws Exception {
128.1214 - LinkedList arr = new LinkedList ();
128.1215 -
128.1216 - class R extends Exception implements Cloneable {
128.1217 - }
128.1218 - arr.add (new R ());
128.1219 - arr.add (new R ());
128.1220 -
128.1221 - ic.set (arr, null);
128.1222 -
128.1223 - arr.clear();
128.1224 -
128.1225 - arr.add (new R ());
128.1226 - arr.add (new R ());
128.1227 -
128.1228 - ic.set (arr, null);
128.1229 - }
128.1230 -
128.1231 - public void testAfterDeserializationNoQueryIsPeformedOnAlreadyQueriedObjects() throws Exception {
128.1232 - if (! (lookup instanceof Serializable)) {
128.1233 - // well this test works only for serializable lookups
128.1234 - return;
128.1235 - }
128.1236 -
128.1237 - SerialPair my = new SerialPair ("no");
128.1238 - ic.addPair (my);
128.1239 -
128.1240 - Lookup.Result res = lookup.lookup (new Lookup.Template (String.class));
128.1241 - assertEquals ("One instance", 1, res.allInstances().size ());
128.1242 - assertEquals ("my.instanceOf called once", 1, my.countInstanceOf);
128.1243 -
128.1244 - Lookup serial = (Lookup)reserialize(lookup);
128.1245 -
128.1246 - Lookup.Result r2 = serial.lookup(new Lookup.Template(String.class));
128.1247 -
128.1248 - assertEquals ("One item", 1, r2.allItems ().size ());
128.1249 - Object one = r2.allItems().iterator().next ();
128.1250 - assertEquals ("The right class", SerialPair.class, one.getClass());
128.1251 - SerialPair p = (SerialPair)one;
128.1252 -
128.1253 - assertEquals ("p.instanceOf has not been queried", 0, p.countInstanceOf);
128.1254 - }
128.1255 -
128.1256 - /** Checks the iterator */
128.1257 - private <T> void checkIterator(String msg, Iterator<? extends T> it1, List<? extends T> list) {
128.1258 - int cnt = 0;
128.1259 - Iterator<? extends T> it2 = list.iterator();
128.1260 - while (it1.hasNext () && it2.hasNext ()) {
128.1261 - T n1 = it1.next();
128.1262 - T n2 = it2.next();
128.1263 -
128.1264 - if (n1 != n2) {
128.1265 - fail (msg + " iterator[" + cnt + "] = " + n1 + " but list[" + cnt + "] = " + n2);
128.1266 - }
128.1267 -
128.1268 - cnt++;
128.1269 - }
128.1270 -
128.1271 - if (it1.hasNext ()) {
128.1272 - fail ("Iterator has more elements than list");
128.1273 - }
128.1274 -
128.1275 - if (it2.hasNext ()) {
128.1276 - fail ("List has more elements than iterator");
128.1277 - }
128.1278 - }
128.1279 -
128.1280 -
128.1281 - public void testResultsAreUnmodifyableOrAtLeastTheyDoNotPropagateToCache() throws Exception {
128.1282 - String s = "Ahoj";
128.1283 -
128.1284 - ic.add(s);
128.1285 -
128.1286 - Lookup.Result res = lookup.lookup(new Template(String.class));
128.1287 -
128.1288 - for (int i = 1; i < 5; i++) {
128.1289 - Collection c1 = res.allInstances();
128.1290 - Collection c2 = res.allClasses();
128.1291 - Collection c3 = res.allItems();
128.1292 -
128.1293 - assertTrue(i + ": c1 has it", c1.contains(s));
128.1294 - assertTrue(i + ": c2 has it", c2.contains(s.getClass()));
128.1295 - assertEquals(i + ": c3 has one", 1, c3.size());
128.1296 - Lookup.Item item = (Lookup.Item) c3.iterator().next();
128.1297 - assertEquals(i + ": c3 has it", s, item.getInstance());
128.1298 -
128.1299 - try {
128.1300 - c1.remove(s);
128.1301 - assertEquals("No elements now", 0, c1.size());
128.1302 - } catch (UnsupportedOperationException ex) {
128.1303 - // ok, this need not be supported
128.1304 - }
128.1305 - try {
128.1306 - c2.remove(s.getClass());
128.1307 - assertEquals("No elements now", 0, c2.size());
128.1308 - } catch (UnsupportedOperationException ex) {
128.1309 - // ok, this need not be supported
128.1310 - }
128.1311 - try {
128.1312 - c3.remove(item);
128.1313 - assertEquals("No elements now", 0, c3.size());
128.1314 - } catch (UnsupportedOperationException ex) {
128.1315 - // ok, this need not be supported
128.1316 - }
128.1317 - }
128.1318 - }
128.1319 -
128.1320 - public void testSomeProblemWithDVBFrameworkSeemsToBeInLookup() {
128.1321 - for (int i = 0; i < 5; i++) {
128.1322 - ic.add(lookup);
128.1323 - assertEquals("Can be found", lookup, lookup.lookup(lookup.getClass()));
128.1324 - ic.set(Collections.EMPTY_LIST, null);
128.1325 - }
128.1326 - }
128.1327 -
128.1328 - public void testListeningAndQueryingByTwoListenersInstances() {
128.1329 - doListeningAndQueryingByTwoListeners(0);
128.1330 - }
128.1331 - public void testListeningAndQueryingByTwoListenersClasses() {
128.1332 - doListeningAndQueryingByTwoListeners(1);
128.1333 - }
128.1334 - public void testListeningAndQueryingByTwoListenersItems() {
128.1335 - doListeningAndQueryingByTwoListeners(2);
128.1336 - }
128.1337 -
128.1338 -
128.1339 - private void doListeningAndQueryingByTwoListeners(final int type) {
128.1340 - class L implements LookupListener {
128.1341 - Lookup.Result integer = lookup.lookup(new Template(Integer.class));
128.1342 - Lookup.Result number = lookup.lookup(new Template(Number.class));
128.1343 - Lookup.Result serial = lookup.lookup(new Template(Serializable.class));
128.1344 -
128.1345 - {
128.1346 - integer.addLookupListener(this);
128.1347 - number.addLookupListener(this);
128.1348 - serial.addLookupListener(this);
128.1349 - }
128.1350 -
128.1351 - int round;
128.1352 -
128.1353 - public void resultChanged(LookupEvent ev) {
128.1354 - Collection c1 = get(type, integer);
128.1355 - Collection c2 = get(type, number);
128.1356 - Collection c3 = get(type, serial);
128.1357 -
128.1358 - assertEquals("round " + round + " c1 vs. c2", c1, c2);
128.1359 - assertEquals("round " + round + " c1 vs. c3", c1, c3);
128.1360 - assertEquals("round " + round + " c2 vs. c3", c2, c3);
128.1361 -
128.1362 - round++;
128.1363 - }
128.1364 -
128.1365 - private Collection get(int type, Lookup.Result res) {
128.1366 - Collection c;
128.1367 - switch(type) {
128.1368 - case 0: c = res.allInstances(); break;
128.1369 - case 1: c = res.allClasses(); break;
128.1370 - case 2: c = res.allItems(); break;
128.1371 - default: c = null; fail("Type: " + type); break;
128.1372 - }
128.1373 -
128.1374 - assertNotNull(c);
128.1375 - return new ArrayList(c);
128.1376 - }
128.1377 - }
128.1378 -
128.1379 - L listener = new L();
128.1380 - listener.resultChanged(null);
128.1381 -
128.1382 - for(int i = 0; i < 100; i++) {
128.1383 - ic.add(new Integer(i));
128.1384 - }
128.1385 -
128.1386 - assertEquals("3x100+1 checks", 301, listener.round);
128.1387 - }
128.1388 -
128.1389 - public void testChangeOfNodeDoesNotFireChangeInActionMap() {
128.1390 - ActionMap am = new ActionMap();
128.1391 - Lookup s = Lookups.singleton(am);
128.1392 - doChangeOfNodeDoesNotFireChangeInActionMap(am, s, false, 0);
128.1393 - }
128.1394 - public void testChangeOfNodeDoesNotFireChangeInActionMapSimple() {
128.1395 - ActionMap am = new ActionMap();
128.1396 - Lookup s = Lookups.singleton(am);
128.1397 - doChangeOfNodeDoesNotFireChangeInActionMap(am, s, true, 0);
128.1398 - }
128.1399 -
128.1400 - public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookupSimple() {
128.1401 - doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(true);
128.1402 - }
128.1403 -
128.1404 - public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup() {
128.1405 - doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(false);
128.1406 - }
128.1407 - private void doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(boolean wrapBySimple) {
128.1408 - final ActionMap am = new ActionMap();
128.1409 -
128.1410 - class Before extends AbstractLookup {
128.1411 - public InstanceContent ic;
128.1412 - public Before() {
128.1413 - this(new InstanceContent());
128.1414 - }
128.1415 -
128.1416 - private Before(InstanceContent ic) {
128.1417 - super(ic);
128.1418 - this.ic = ic;
128.1419 - }
128.1420 -
128.1421 - protected @Override void beforeLookup(Template template) {
128.1422 - if (ic != null) {
128.1423 - ic.add(am);
128.1424 - ic = null;
128.1425 - }
128.1426 - }
128.1427 - }
128.1428 -
128.1429 - Before s = new Before();
128.1430 - doChangeOfNodeDoesNotFireChangeInActionMap(am, s, wrapBySimple, 1);
128.1431 -
128.1432 - assertNull("beforeLookup called once", s.ic);
128.1433 - }
128.1434 -
128.1435 - private void doChangeOfNodeDoesNotFireChangeInActionMap(final ActionMap am, Lookup actionMapLookup, final boolean wrapBySimple, int firstChange) {
128.1436 - Lookup[] lookups = { lookup, actionMapLookup };
128.1437 -
128.1438 - class Provider implements Lookup.Provider {
128.1439 - ProxyLookup delegate;
128.1440 - Lookup query;
128.1441 -
128.1442 - public Provider(Lookup[] arr) {
128.1443 - if (wrapBySimple) {
128.1444 - delegate = new ProxyLookup(arr);
128.1445 - query = Lookups.proxy(this);
128.1446 - } else {
128.1447 - query = delegate = new ProxyLookup(arr);
128.1448 - }
128.1449 - }
128.1450 -
128.1451 - public Lookup getLookup() {
128.1452 - return delegate;
128.1453 - }
128.1454 -
128.1455 - public void setLookups(Lookup... arr) {
128.1456 - if (wrapBySimple) {
128.1457 - delegate = new ProxyLookup(arr);
128.1458 - } else {
128.1459 - delegate.setLookups(arr);
128.1460 - }
128.1461 - }
128.1462 - }
128.1463 -
128.1464 - Provider p = new Provider(lookups);
128.1465 -
128.1466 - Lookup.Result res = p.query.lookup(new Lookup.Template(ActionMap.class));
128.1467 - LL ll = new LL();
128.1468 - res.addLookupListener(ll);
128.1469 -
128.1470 - Collection c = res.allInstances();
128.1471 - assertFalse("Has next", c.isEmpty());
128.1472 -
128.1473 - ActionMap am1 = (ActionMap)c.iterator().next();
128.1474 - assertEquals("Am is there", am, am1);
128.1475 -
128.1476 - assertEquals("Correct # of changes in first get", firstChange, ll.getCount());
128.1477 -
128.1478 - Object m1 = new InputMap();
128.1479 - Object m2 = new InputMap();
128.1480 -
128.1481 - ic.add(m1);
128.1482 - assertEquals("No change in ActionMap 1", 0, ll.getCount());
128.1483 - ic.set(Collections.singletonList(m2), null);
128.1484 - assertEquals("No change in ActionMap 2", 0, ll.getCount());
128.1485 - ic.add(m2);
128.1486 - assertEquals("No change in ActionMap 3", 0, ll.getCount());
128.1487 - p.setLookups(lookup, actionMapLookup, Lookup.EMPTY);
128.1488 - assertEquals("No change in ActionMap 4", 0, ll.getCount());
128.1489 -
128.1490 - ActionMap am2 = p.query.lookup(ActionMap.class);
128.1491 - assertEquals("Still the same action map", am, am2);
128.1492 -
128.1493 -
128.1494 - class Before extends AbstractLookup {
128.1495 - public InstanceContent ic;
128.1496 - public Before() {
128.1497 - this(new InstanceContent());
128.1498 - }
128.1499 -
128.1500 - private Before(InstanceContent ic) {
128.1501 - super(ic);
128.1502 - this.ic = ic;
128.1503 - }
128.1504 -
128.1505 - protected @Override void beforeLookup(Template template) {
128.1506 - if (ic != null) {
128.1507 - ic.add(am);
128.1508 - ic = null;
128.1509 - }
128.1510 - }
128.1511 - }
128.1512 -
128.1513 - Before s = new Before();
128.1514 -
128.1515 - // adding different Before, but returning the same instance
128.1516 - // this happens with metaInfServices lookup often, moreover
128.1517 - // it adds the instance in beforeLookup, which confuses a lot
128.1518 - p.setLookups(new Lookup[]{ lookup, new Before() });
128.1519 - assertEquals("No change in ActionMap 5", 0, ll.getCount());
128.1520 -
128.1521 -
128.1522 - }
128.1523 -
128.1524 - public void testTasklistsCase() throws Exception {
128.1525 - ic.remove(new Object());
128.1526 - }
128.1527 -
128.1528 -
128.1529 -
128.1530 - public void testMultipleListeners() {
128.1531 - Object object = new ImplementationObject();
128.1532 - ic.add(object);
128.1533 -
128.1534 - Listener[] listeners = new Listener[4];
128.1535 - Lookup.Result result = lookup.lookup(new Lookup.Template(LookupObject.class));
128.1536 - for(int i = 0; i < listeners.length; ++i) {
128.1537 - listeners[i] = new Listener();
128.1538 - result.addLookupListener(listeners[i]);
128.1539 - }
128.1540 - // initialize listening
128.1541 - result.allItems();
128.1542 -
128.1543 - ic.remove(object);
128.1544 -
128.1545 - // Apparently, only odd-numbered listeners get called when there are multiple LookupListeners on a result
128.1546 - //for(int i = 0; i < listeners.length; ++i) {
128.1547 - // System.out.println("Listener " + i + ": " + listeners[i].wasCalled());
128.1548 - //}
128.1549 - for(int i = 0; i < listeners.length; ++i) {
128.1550 - assertTrue("Listener " + i + " called", listeners[i].wasCalled());
128.1551 - }
128.1552 - }
128.1553 -
128.1554 - static Object reserialize(Object o) throws Exception {
128.1555 - ByteArrayOutputStream os = new ByteArrayOutputStream();
128.1556 - ObjectOutputStream oos = new ObjectOutputStream(os);
128.1557 - oos.writeObject(o);
128.1558 - oos.close();
128.1559 -
128.1560 - ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
128.1561 - ObjectInputStream ois = new ObjectInputStream(is);
128.1562 - return ois.readObject();
128.1563 - }
128.1564 -
128.1565 - private class Listener implements LookupListener {
128.1566 - private boolean listenerCalled = false;
128.1567 -
128.1568 - public void resultChanged(LookupEvent ev) {
128.1569 - listenerCalled = true;
128.1570 - }
128.1571 -
128.1572 - public boolean wasCalled() {
128.1573 - return listenerCalled;
128.1574 - }
128.1575 -
128.1576 - public void reset() {
128.1577 - listenerCalled = false;
128.1578 - }
128.1579 - }
128.1580 -
128.1581 - private interface LookupObject {}
128.1582 - private class ImplementationObject implements LookupObject {}
128.1583 - private class NullObject implements LookupObject {}
128.1584 -
128.1585 -
128.1586 - public void testReturnSomethingElseThenYouClaimYouWillReturn() {
128.1587 - class Liar extends AbstractLookup.Pair {
128.1588 - public Object obj;
128.1589 -
128.1590 - protected boolean instanceOf(Class c) {
128.1591 - return c.isAssignableFrom(String.class);
128.1592 - }
128.1593 -
128.1594 - protected boolean creatorOf(Object obj) {
128.1595 - return this.obj == obj;
128.1596 - }
128.1597 -
128.1598 - public Object getInstance() {
128.1599 - return this.obj;
128.1600 - }
128.1601 -
128.1602 - public Class getType() {
128.1603 - return String.class;
128.1604 - }
128.1605 -
128.1606 - public String getId() {
128.1607 - return String.class.getName();
128.1608 - }
128.1609 -
128.1610 - public String getDisplayName() {
128.1611 - return getId();
128.1612 - }
128.1613 - }
128.1614 -
128.1615 -
128.1616 - Liar l = new Liar();
128.1617 - l.obj = new Integer(5);
128.1618 -
128.1619 - this.ic.addPair(l);
128.1620 -
128.1621 - Collection c = lookup.lookup(new Lookup.Template(String.class)).allInstances();
128.1622 - assertTrue("It is empty: " + c, c.isEmpty());
128.1623 - }
128.1624 -
128.1625 - public void testCanProxyLookupHaveWrongResults() {
128.1626 - class L implements LookupListener {
128.1627 - ProxyLookup pl;
128.1628 - Lookup.Result<String> original;
128.1629 - Lookup.Result<String> wrapped;
128.1630 - boolean ok;
128.1631 -
128.1632 - public void test() {
128.1633 - pl = new ProxyLookup(lookup);
128.1634 - original = lookup.lookupResult(String.class);
128.1635 -
128.1636 - original.addLookupListener(this);
128.1637 -
128.1638 - wrapped = pl.lookupResult(String.class);
128.1639 -
128.1640 - assertEquals("Original empty", 0, original.allInstances().size());
128.1641 - assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
128.1642 -
128.1643 - ic.add("Hello!");
128.1644 - }
128.1645 -
128.1646 - public void resultChanged(LookupEvent ev) {
128.1647 - ok = true;
128.1648 -
128.1649 - assertEquals("Original has hello", 1, original.allInstances().size());
128.1650 - assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
128.1651 - }
128.1652 -
128.1653 - }
128.1654 - L listener = new L();
128.1655 - listener.test();
128.1656 - assertTrue("Listener called", listener.ok);
128.1657 - }
128.1658 -
128.1659 - public void testObjectFromInstanceContentConverterDisappearsIfNotReferenced() {
128.1660 - Conv converter = new Conv("foo");
128.1661 - ic.add (converter, converter);
128.1662 - Lookup lkp = instanceLookup;
128.1663 - StringBuilder sb = lookup.lookup (StringBuilder.class);
128.1664 - assertNotNull (sb);
128.1665 - int hash = System.identityHashCode(sb);
128.1666 - assertEquals ("foo", sb.toString());
128.1667 - Reference<StringBuilder> r = new WeakReference<StringBuilder>(sb);
128.1668 - sb = null;
128.1669 - assertGC("Lookup held onto object", r);
128.1670 - sb = lookup.lookup (StringBuilder.class);
128.1671 - assertNotSame(hash, System.identityHashCode(sb));
128.1672 - r = new WeakReference<StringBuilder>(sb);
128.1673 - sb = null;
128.1674 - assertGC("Lookup held onto object", r);
128.1675 - ic.remove (converter, converter);
128.1676 - Reference <InstanceContent.Convertor> cref = new WeakReference<InstanceContent.Convertor>(converter);
128.1677 - converter = null;
128.1678 - assertGC("Converter still referenced", cref);
128.1679 -
128.1680 - sb = lkp.lookup(StringBuilder.class);
128.1681 - assertNull ("Converter removed from lookup, but object it " +
128.1682 - "created still present:'" + sb +"'", sb);
128.1683 - converter = new Conv("bar");
128.1684 - ic.add (converter, converter);
128.1685 - assertNotNull (lkp.lookup(StringBuilder.class));
128.1686 - assertEquals ("bar", lkp.lookup(StringBuilder.class).toString());
128.1687 - }
128.1688 -
128.1689 - private static class Conv implements InstanceContent.Convertor<Conv, StringBuilder> {
128.1690 - private final String str;
128.1691 - private Conv (String str) {
128.1692 - this.str = str;
128.1693 - }
128.1694 -
128.1695 - public StringBuilder convert(Conv obj) {
128.1696 - return new StringBuilder (str);
128.1697 - }
128.1698 -
128.1699 - public Class<? extends StringBuilder> type(Conv obj) {
128.1700 - return StringBuilder.class;
128.1701 - }
128.1702 -
128.1703 - public String id(Conv obj) {
128.1704 - return "Foo";
128.1705 - }
128.1706 -
128.1707 - public String displayName(Conv obj) {
128.1708 - return "Foo";
128.1709 - }
128.1710 - } // end of Conv
128.1711 -
128.1712 - public void testCanGCResults() throws Exception {
128.1713 - class L implements LookupListener {
128.1714 - int cnt;
128.1715 -
128.1716 - public void resultChanged(LookupEvent ev) {
128.1717 - cnt++;
128.1718 - }
128.1719 -
128.1720 - }
128.1721 - L listener1 = new L();
128.1722 - L listener2 = new L();
128.1723 -
128.1724 - Lookup.Result<String> res1 = this.instanceLookup.lookupResult(String.class);
128.1725 - Lookup.Result<String> res2 = this.lookup.lookupResult(String.class);
128.1726 -
128.1727 - assertEquals("Empty1", 0, res1.allItems().size());
128.1728 - assertEquals("Empty2", 0, res2.allItems().size());
128.1729 -
128.1730 - res1.addLookupListener(listener1);
128.1731 - res2.addLookupListener(listener2);
128.1732 -
128.1733 - addInstances(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
128.1734 - this.ic.add("Ahoj");
128.1735 -
128.1736 - assertEquals("Change1", 1, listener1.cnt);
128.1737 - assertEquals("Change2", 1, listener2.cnt);
128.1738 -
128.1739 - assertEquals("Full1", 1, res1.allItems().size());
128.1740 - assertEquals("Full2", 1, res2.allItems().size());
128.1741 -
128.1742 -
128.1743 - Reference<Object> ref2 = new WeakReference<Object>(res2);
128.1744 - res2 = null;
128.1745 - assertGC("Result can disappear", ref2);
128.1746 - }
128.1747 -
128.1748 - void beforeActualTest(String n) {
128.1749 - if (n.equals("testEqualsIsNotCalledTooMuch")) {
128.1750 - CntPair.cnt = 0;
128.1751 - CntPair.hashCnt = 0;
128.1752 - CntPair.instances = 0;
128.1753 - int how = 1000;
128.1754 -
128.1755 - for(int i = 0; i < how; i++) {
128.1756 - this.ic.addPair(new CntPair("x" + i));
128.1757 - }
128.1758 -
128.1759 - assertEquals("No equals called", 0, CntPair.cnt);
128.1760 - assertEquals("1000 instances ", how, CntPair.instances);
128.1761 - }
128.1762 - }
128.1763 -
128.1764 - public void testEqualsIsNotCalledTooMuch() throws Exception {
128.1765 - // most of the work done in beforeActualTest
128.1766 -
128.1767 - // desirable: assertEquals("no comparitions", 0, CntPair.cnt);
128.1768 - // works for InheritanceTree, but not for ArrayStorage, but array
128.1769 - // storages are generally small
128.1770 -
128.1771 - if (CntPair.cnt > 12000) {
128.1772 - fail("Too much comparitions " + CntPair.cnt);
128.1773 - }
128.1774 - if (CntPair.hashCnt > 40000) {
128.1775 - fail("Too much hashes: " + CntPair.hashCnt);
128.1776 - }
128.1777 -
128.1778 - assertEquals("instaces is enough", 1000, CntPair.instances);
128.1779 - }
128.1780 -
128.1781 - /** Adds instances to the instance lookup.
128.1782 - */
128.1783 - private void addInstances (Object... instances) {
128.1784 - for (int i = 0; i < instances.length; i++) {
128.1785 - ic.add(instances[i]);
128.1786 - }
128.1787 - }
128.1788 -
128.1789 - /** Count instances of clazz in an array. */
128.1790 - private int countInstances (Object[] objs, Class clazz) {
128.1791 - int count = 0;
128.1792 - for (int i = 0; i < objs.length; i++) {
128.1793 - if (clazz.isInstance(objs[i])) count++;
128.1794 - }
128.1795 - return count;
128.1796 - }
128.1797 -
128.1798 - /** Counting listener */
128.1799 - protected static class LL implements LookupListener {
128.1800 - private int count = 0;
128.1801 - public Object source;
128.1802 - public Thread changesIn;
128.1803 -
128.1804 - public LL () {
128.1805 - this (null);
128.1806 - }
128.1807 -
128.1808 - public LL (Object source) {
128.1809 - this.source = source;
128.1810 - }
128.1811 -
128.1812 - public void resultChanged(LookupEvent ev) {
128.1813 - if (changesIn != null) {
128.1814 - assertEquals("Changes in the same thread", changesIn, Thread.currentThread());
128.1815 - } else {
128.1816 - changesIn = Thread.currentThread();
128.1817 - }
128.1818 - ++count;
128.1819 - if (source != null) {
128.1820 - assertSame ("Source is the same", source, ev.getSource ());
128.1821 -// assertSame ("Result is the same", source, ev.getResult ());
128.1822 - }
128.1823 - }
128.1824 -
128.1825 - public int getCount() {
128.1826 - int i = count;
128.1827 - count = 0;
128.1828 - return i;
128.1829 - }
128.1830 - };
128.1831 -
128.1832 - /** A set of interfaces for testInterfaceInheritance
128.1833 - */
128.1834 - interface TestInterfaceInheritanceA {}
128.1835 - interface TestInterfaceInheritanceB extends TestInterfaceInheritanceA, java.rmi.Remote {}
128.1836 - interface TestInterfaceInheritanceBB extends TestInterfaceInheritanceB {}
128.1837 - interface TestInterfaceInheritanceC extends TestInterfaceInheritanceA, java.rmi.Remote {}
128.1838 - interface TestInterfaceInheritanceD extends TestInterfaceInheritanceA {}
128.1839 -
128.1840 - /** A special class for garbage test */
128.1841 - public static final class Garbage extends Object implements Serializable {
128.1842 - static final long serialVersionUID = 435340912534L;
128.1843 - }
128.1844 -
128.1845 -
128.1846 - /* A classloader that can load one class in a special way */
128.1847 - private static class CL extends ClassLoader {
128.1848 - public CL () {
128.1849 - super (null);
128.1850 - }
128.1851 -
128.1852 - public @Override Class findClass(String name) throws ClassNotFoundException {
128.1853 - if (name.equals (Garbage.class.getName ())) {
128.1854 - String n = name.replace ('.', '/');
128.1855 - java.io.InputStream is = getClass ().getResourceAsStream ("/" + n + ".class");
128.1856 - byte[] arr = new byte[8096];
128.1857 - try {
128.1858 - int cnt = is.read (arr);
128.1859 - if (cnt == arr.length) {
128.1860 - fail ("Buffer to load the class is not big enough");
128.1861 - }
128.1862 -
128.1863 - return defineClass (name, arr, 0, cnt);
128.1864 - } catch (java.io.IOException ex) {
128.1865 - ex.printStackTrace();
128.1866 - fail ("IO Exception");
128.1867 - return null;
128.1868 - }
128.1869 - } else {
128.1870 - return null;
128.1871 - }
128.1872 - }
128.1873 -
128.1874 - /** Convert obj to other object. There is no need to implement
128.1875 - * cache mechanism. It is provided by AbstractLookup.Item.getInstance().
128.1876 - * Method should be called more than once because Lookup holds
128.1877 - * just weak reference.
128.1878 - */
128.1879 - public Object convert(Object obj) {
128.1880 - return null;
128.1881 - }
128.1882 -
128.1883 - /** Return type of converted object. */
128.1884 - public Class type(Object obj) {
128.1885 - try {
128.1886 - return loadClass (Garbage.class.getName ());
128.1887 - } catch (ClassNotFoundException ex) {
128.1888 - fail ("Class not found");
128.1889 - throw new InternalError ();
128.1890 - }
128.1891 - }
128.1892 - }
128.1893 -
128.1894 - private static final class CntPair extends AbstractLookup.Pair {
128.1895 - private static int instances;
128.1896 - private String txt;
128.1897 -
128.1898 - public CntPair(String txt) {
128.1899 - this.txt = txt;
128.1900 - instances++;
128.1901 - }
128.1902 -
128.1903 - public static int hashCnt;
128.1904 - @Override
128.1905 - public int hashCode() {
128.1906 - hashCnt++;
128.1907 - return txt.hashCode() + 3777;
128.1908 - }
128.1909 -
128.1910 - public static int cnt;
128.1911 - @Override
128.1912 - public boolean equals(Object obj) {
128.1913 - cnt++;
128.1914 -
128.1915 - if (obj == null) {
128.1916 - return false;
128.1917 - }
128.1918 - if (getClass() != obj.getClass()) {
128.1919 - return false;
128.1920 - }
128.1921 - final CntPair other = (CntPair) obj;
128.1922 - if (this.txt != other.txt && (this.txt == null || !this.txt.equals(other.txt))) {
128.1923 - return false;
128.1924 - }
128.1925 - return true;
128.1926 - }
128.1927 -
128.1928 - protected boolean instanceOf(Class c) {
128.1929 - return c.isAssignableFrom(String.class);
128.1930 - }
128.1931 -
128.1932 - protected boolean creatorOf(Object obj) {
128.1933 - return obj == txt;
128.1934 - }
128.1935 -
128.1936 - public Object getInstance() {
128.1937 - return txt;
128.1938 - }
128.1939 -
128.1940 - public Class getType() {
128.1941 - return String.class;
128.1942 - }
128.1943 -
128.1944 - public String getId() {
128.1945 - return txt;
128.1946 - }
128.1947 -
128.1948 - public String getDisplayName() {
128.1949 - return txt;
128.1950 - }
128.1951 -
128.1952 - }
128.1953 -
128.1954 - public static final class SerialPair extends AbstractLookup.Pair
128.1955 - implements java.io.Serializable {
128.1956 - static final long serialVersionUID = 54305834L;
128.1957 - private Object value;
128.1958 - public transient int countInstanceOf;
128.1959 -
128.1960 - public SerialPair (Object value) {
128.1961 - this.value = value;
128.1962 - }
128.1963 -
128.1964 - protected boolean creatorOf(Object obj) {
128.1965 - return obj == value;
128.1966 - }
128.1967 -
128.1968 - public String getDisplayName() {
128.1969 - return getId ();
128.1970 - }
128.1971 -
128.1972 - public String getId() {
128.1973 - return value.toString();
128.1974 - }
128.1975 -
128.1976 - public Object getInstance() {
128.1977 - return value;
128.1978 - }
128.1979 -
128.1980 - public Class getType() {
128.1981 - return value.getClass ();
128.1982 - }
128.1983 -
128.1984 - protected boolean instanceOf(Class c) {
128.1985 - countInstanceOf++;
128.1986 - return c.isInstance(value);
128.1987 - }
128.1988 - } // end of SerialPair
128.1989 -
128.1990 - private static class BrokenPair extends AbstractLookup.Pair {
128.1991 - private transient ThreadLocal IN = new ThreadLocal ();
128.1992 - private boolean checkModify;
128.1993 - private boolean checkQuery;
128.1994 -
128.1995 - public BrokenPair (boolean checkModify, boolean checkQuery) {
128.1996 - this.checkModify = checkModify;
128.1997 - this.checkQuery = checkQuery;
128.1998 - }
128.1999 -
128.2000 - protected boolean creatorOf(Object obj) { return this == obj; }
128.2001 - public String getDisplayName() { return "Broken"; }
128.2002 - public String getId() { return "broken"; }
128.2003 - public Object getInstance() { return this; }
128.2004 - public Class getType() { return getClass (); }
128.2005 - protected boolean instanceOf(Class c) {
128.2006 -
128.2007 - if (checkQuery) {
128.2008 - if (IN.get () == null) {
128.2009 - try {
128.2010 - IN.set (this);
128.2011 - // broken behaviour, tries to modify the lookup
128.2012 - // queries have to survive
128.2013 -
128.2014 - running.lookup.lookup (java.awt.List.class);
128.2015 -
128.2016 - //
128.2017 - // creation of new result has to survive as well
128.2018 - Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.Button.class));
128.2019 - Collection all = myQuery.allItems ();
128.2020 - } finally {
128.2021 - IN.set (null);
128.2022 - }
128.2023 - }
128.2024 - }
128.2025 -
128.2026 -
128.2027 - if (checkModify) {
128.2028 - //
128.2029 - // modifications should fail
128.2030 - //
128.2031 -
128.2032 - try {
128.2033 - running.ic.addPair (new SerialPair (""));
128.2034 - fail ("Modification from a query should be prohibited");
128.2035 - } catch (IllegalStateException ex) {
128.2036 - }
128.2037 -
128.2038 - try {
128.2039 - running.ic.removePair (this);
128.2040 - fail ("This has to throw the exception");
128.2041 - } catch (IllegalStateException ex) {
128.2042 - }
128.2043 - try {
128.2044 - running.ic.setPairs (Collections.EMPTY_SET);
128.2045 - fail ("This has to throw the exception as well");
128.2046 - } catch (IllegalStateException ex) {
128.2047 - }
128.2048 - }
128.2049 -
128.2050 - return c.isAssignableFrom(getType ());
128.2051 - }
128.2052 - } // end of BrokenPair
128.2053 -
128.2054 - private static class Broken2Pair extends AbstractLookup.Pair {
128.2055 - static final long serialVersionUID = 4532587018501L;
128.2056 - public transient ThreadLocal IN;
128.2057 -
128.2058 - public Broken2Pair () {
128.2059 - }
128.2060 -
128.2061 - private void writeObject (java.io.ObjectOutputStream oos) throws java.io.IOException {
128.2062 - }
128.2063 -
128.2064 - private void readObject (java.io.ObjectInputStream ois) throws java.io.IOException, ClassNotFoundException {
128.2065 - IN = new ThreadLocal ();
128.2066 - }
128.2067 -
128.2068 - protected boolean creatorOf(Object obj) { return this == obj; }
128.2069 - public String getDisplayName() { return "Broken"; }
128.2070 - public String getId() { return "broken"; }
128.2071 - public Object getInstance() { return this; }
128.2072 - public Class getType() { return getClass (); }
128.2073 - protected boolean instanceOf(Class c) {
128.2074 -
128.2075 - // behaviour gets broken only after deserialization
128.2076 - if (IN != null && IN.get () == null) {
128.2077 - try {
128.2078 - IN.set (this);
128.2079 -
128.2080 - // creation of new result has to survive as well
128.2081 - Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.List.class));
128.2082 - Collection all = myQuery.allItems ();
128.2083 - } finally {
128.2084 - IN.set (null);
128.2085 - }
128.2086 - }
128.2087 -
128.2088 - return c.isAssignableFrom(getType ());
128.2089 - }
128.2090 - } // end of Broken2Pair
128.2091 -}
129.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupExecutorTest.java Thu Dec 10 19:23:25 2009 -0500
129.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
129.3 @@ -1,98 +0,0 @@
129.4 -/*
129.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
129.6 - *
129.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
129.8 - *
129.9 - * The contents of this file are subject to the terms of either the GNU
129.10 - * General Public License Version 2 only ("GPL") or the Common
129.11 - * Development and Distribution License("CDDL") (collectively, the
129.12 - * "License"). You may not use this file except in compliance with the
129.13 - * License. You can obtain a copy of the License at
129.14 - * http://www.netbeans.org/cddl-gplv2.html
129.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
129.16 - * specific language governing permissions and limitations under the
129.17 - * License. When distributing the software, include this License Header
129.18 - * Notice in each file and include the License file at
129.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
129.20 - * particular file as subject to the "Classpath" exception as provided
129.21 - * by Sun in the GPL Version 2 section of the License file that
129.22 - * accompanied this code. If applicable, add the following below the
129.23 - * License Header, with the fields enclosed by brackets [] replaced by
129.24 - * your own identifying information:
129.25 - * "Portions Copyrighted [year] [name of copyright owner]"
129.26 - *
129.27 - * Contributor(s):
129.28 - *
129.29 - * The Original Software is NetBeans. The Initial Developer of the Original
129.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
129.31 - * Microsystems, Inc. All Rights Reserved.
129.32 - *
129.33 - * If you wish your version of this file to be governed by only the CDDL
129.34 - * or only the GPL Version 2, indicate your decision by adding
129.35 - * "[Contributor] elects to include this software in this distribution
129.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
129.37 - * single choice of license, a recipient has the option to distribute
129.38 - * your version of this file under either the CDDL, the GPL Version 2 or
129.39 - * to extend the choice of license to its licensees as provided above.
129.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
129.41 - * Version 2 license, then the option applies only if the new code is
129.42 - * made subject to such option by the copyright holder.
129.43 - */
129.44 -
129.45 -package org.openide.util.lookup;
129.46 -
129.47 -import java.util.concurrent.Executor;
129.48 -import org.openide.util.Lookup;
129.49 -import org.openide.util.LookupEvent;
129.50 -import org.openide.util.LookupListener;
129.51 -
129.52 -public class AbstractLookupExecutorTest extends AbstractLookupBaseHid
129.53 -implements AbstractLookupBaseHid.Impl, Executor, LookupListener {
129.54 - Lookup.Result<?> res;
129.55 -
129.56 -
129.57 - public AbstractLookupExecutorTest(java.lang.String testName) {
129.58 - super(testName, null);
129.59 - }
129.60 -
129.61 - //
129.62 - // Impl of AbstractLookupBaseHid.Impl
129.63 - //
129.64 -
129.65 - /** Creates the initial abstract lookup.
129.66 - */
129.67 - public Lookup createInstancesLookup (InstanceContent ic) {
129.68 - ic.attachExecutor(this);
129.69 - Lookup l = new AbstractLookup (ic, new InheritanceTree ());
129.70 - return l;
129.71 - }
129.72 -
129.73 - /** Creates an lookup for given lookup. This class just returns
129.74 - * the object passed in, but subclasses can be different.
129.75 - * @param lookup in lookup
129.76 - * @return a lookup to use
129.77 - */
129.78 - public Lookup createLookup (Lookup lookup) {
129.79 - res = lookup.lookupResult(Object.class);
129.80 - res.addLookupListener(this);
129.81 - return lookup;
129.82 - }
129.83 -
129.84 - public void clearCaches () {
129.85 - }
129.86 -
129.87 - ThreadLocal<Object> ME = new ThreadLocal<Object>();
129.88 - public void execute(Runnable command) {
129.89 - assertEquals("Not yet set", null, ME.get());
129.90 - ME.set(this);
129.91 - try {
129.92 - command.run();
129.93 - } finally {
129.94 - ME.set(null);
129.95 - }
129.96 - }
129.97 -
129.98 - public void resultChanged(LookupEvent ev) {
129.99 - assertEquals("Changes delivered only from execute method", this, ME.get());
129.100 - }
129.101 -}
130.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupMemoryTest.java Thu Dec 10 19:23:25 2009 -0500
130.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
130.3 @@ -1,158 +0,0 @@
130.4 -/*
130.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
130.6 - *
130.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
130.8 - *
130.9 - * The contents of this file are subject to the terms of either the GNU
130.10 - * General Public License Version 2 only ("GPL") or the Common
130.11 - * Development and Distribution License("CDDL") (collectively, the
130.12 - * "License"). You may not use this file except in compliance with the
130.13 - * License. You can obtain a copy of the License at
130.14 - * http://www.netbeans.org/cddl-gplv2.html
130.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
130.16 - * specific language governing permissions and limitations under the
130.17 - * License. When distributing the software, include this License Header
130.18 - * Notice in each file and include the License file at
130.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
130.20 - * particular file as subject to the "Classpath" exception as provided
130.21 - * by Sun in the GPL Version 2 section of the License file that
130.22 - * accompanied this code. If applicable, add the following below the
130.23 - * License Header, with the fields enclosed by brackets [] replaced by
130.24 - * your own identifying information:
130.25 - * "Portions Copyrighted [year] [name of copyright owner]"
130.26 - *
130.27 - * Contributor(s):
130.28 - *
130.29 - * The Original Software is NetBeans. The Initial Developer of the Original
130.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
130.31 - * Microsystems, Inc. All Rights Reserved.
130.32 - *
130.33 - * If you wish your version of this file to be governed by only the CDDL
130.34 - * or only the GPL Version 2, indicate your decision by adding
130.35 - * "[Contributor] elects to include this software in this distribution
130.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
130.37 - * single choice of license, a recipient has the option to distribute
130.38 - * your version of this file under either the CDDL, the GPL Version 2 or
130.39 - * to extend the choice of license to its licensees as provided above.
130.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
130.41 - * Version 2 license, then the option applies only if the new code is
130.42 - * made subject to such option by the copyright holder.
130.43 - */
130.44 -
130.45 -package org.openide.util.lookup;
130.46 -
130.47 -import java.util.*;
130.48 -import org.netbeans.junit.*;
130.49 -import org.netbeans.modules.openide.util.ActiveQueue;
130.50 -import org.openide.util.Lookup;
130.51 -
130.52 -/** Testing memory consumption of various AbstractLookup aspects.
130.53 - */
130.54 -public class AbstractLookupMemoryTest extends NbTestCase {
130.55 - public AbstractLookupMemoryTest(java.lang.String testName) {
130.56 - super(testName);
130.57 - }
130.58 -
130.59 - public static void main(java.lang.String[] args) {
130.60 - junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupMemoryTest.class));
130.61 - }
130.62 -
130.63 - public void testEmptySize () {
130.64 - AbstractLookup instanceLookup = new AbstractLookup ();
130.65 - assertSize ("Empty lookup should be small", 16, instanceLookup);
130.66 -
130.67 - InstanceContent ic = new InstanceContent ();
130.68 - instanceLookup = new AbstractLookup (ic);
130.69 - assertSize ("Lookup with InstanceContent should be small as well", 16, instanceLookup);
130.70 - }
130.71 -
130.72 - public void testPairSize () {
130.73 - AbstractLookup.Pair pair = new EmptyPair ();
130.74 - assertSize ("Pair occupies only 16 bytes", 16, pair);
130.75 - }
130.76 -
130.77 - public void testPairWithOnePointerSize () {
130.78 - AbstractLookup.Pair pair = new OneItemPair ();
130.79 - assertSize ("Pair occupies only 16 bytes", 16, pair);
130.80 - }
130.81 -
130.82 - public void testLookupWithPairs () {
130.83 - Lookup.Template<Object> t = new Lookup.Template<Object>(Object.class);
130.84 - class L implements org.openide.util.LookupListener {
130.85 - public int cnt;
130.86 - public void resultChanged (org.openide.util.LookupEvent ev) {
130.87 - cnt++;
130.88 - }
130.89 - }
130.90 - L listener = new L ();
130.91 - L listener2 = new L ();
130.92 -
130.93 - EmptyPair[] pairs = {
130.94 - new EmptyPair(),
130.95 - new EmptyPair(),
130.96 - new EmptyPair(),
130.97 - new EmptyPair(),
130.98 - };
130.99 - Object[] ignore = {
130.100 - pairs[0],
130.101 - pairs[1],
130.102 - pairs[2],
130.103 - pairs[3],
130.104 - t,
130.105 - ActiveQueue.queue(),
130.106 - listener,
130.107 - listener2,
130.108 - new Integer (11) // trashhold is shared
130.109 - };
130.110 -
130.111 - AbstractLookup.Content c = new AbstractLookup.Content ();
130.112 - AbstractLookup l = new AbstractLookup (c, (Integer)ignore[ignore.length - 1]);
130.113 -
130.114 - c.addPair ((EmptyPair)ignore[0]);
130.115 - assertSize ("Should be really small (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
130.116 -
130.117 - c.addPair ((EmptyPair)ignore[1]);
130.118 - assertSize ("Is bigger I guess (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
130.119 -
130.120 - c.setPairs(Arrays.asList(pairs).subList(0, 3));
130.121 - assertSize ("Even bigger (not counting the pair sizes)", Collections.singleton (l), 64, ignore);
130.122 -
130.123 - c.setPairs(Arrays.asList(pairs).subList(0, 4));
130.124 - assertSize ("Now not that much(not counting the pair sizes)", Collections.singleton (l), 64, ignore);
130.125 -
130.126 - Lookup.Result res = l.lookup (t);
130.127 -
130.128 - assertSize ("After creating a result", Collections.singleton (l), 120, ignore);
130.129 -
130.130 - res.addLookupListener (listener);
130.131 -
130.132 - assertSize ("And attaching one listener", Collections.singleton (l), 120, ignore);
130.133 -
130.134 - res.addLookupListener (listener2);
130.135 - assertSize ("Second listener makes the situation much worse", Collections.singleton (l), 200, ignore);
130.136 - res.removeLookupListener(listener2);
130.137 - assertSize ("But removing it returns us back to original size", Collections.singleton (l), 120, ignore);
130.138 -
130.139 -
130.140 - assertEquals ("Current for pairs are in", res.allItems ().size (), 4); // also activates the listener
130.141 - assertSize ("and making the listener to work", Collections.singleton (l), 120, ignore);
130.142 -
130.143 - c.removePair ((EmptyPair)ignore[0]);
130.144 - assertEquals ("A changes has been delivered", 1, listener.cnt);
130.145 - }
130.146 -
130.147 - /** Simple pair with no data */
130.148 - private static class EmptyPair extends AbstractLookup.Pair {
130.149 - protected boolean creatorOf(Object obj) { return false; }
130.150 - public String getDisplayName() { return ""; }
130.151 - public String getId() { return ""; }
130.152 - public Object getInstance() { return null; }
130.153 - public Class getType() { return Object.class; }
130.154 - protected boolean instanceOf(Class c) { return c == getType (); }
130.155 - } // end of EmptyPair
130.156 -
130.157 - /** Pair with one item (like InstanceContent.Pair) */
130.158 - private static class OneItemPair extends EmptyPair {
130.159 - private Object pointer;
130.160 - }
130.161 -}
131.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupTest.java Thu Dec 10 19:23:25 2009 -0500
131.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
131.3 @@ -1,353 +0,0 @@
131.4 -/*
131.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
131.6 - *
131.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
131.8 - *
131.9 - * The contents of this file are subject to the terms of either the GNU
131.10 - * General Public License Version 2 only ("GPL") or the Common
131.11 - * Development and Distribution License("CDDL") (collectively, the
131.12 - * "License"). You may not use this file except in compliance with the
131.13 - * License. You can obtain a copy of the License at
131.14 - * http://www.netbeans.org/cddl-gplv2.html
131.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
131.16 - * specific language governing permissions and limitations under the
131.17 - * License. When distributing the software, include this License Header
131.18 - * Notice in each file and include the License file at
131.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
131.20 - * particular file as subject to the "Classpath" exception as provided
131.21 - * by Sun in the GPL Version 2 section of the License file that
131.22 - * accompanied this code. If applicable, add the following below the
131.23 - * License Header, with the fields enclosed by brackets [] replaced by
131.24 - * your own identifying information:
131.25 - * "Portions Copyrighted [year] [name of copyright owner]"
131.26 - *
131.27 - * Contributor(s):
131.28 - *
131.29 - * The Original Software is NetBeans. The Initial Developer of the Original
131.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
131.31 - * Microsystems, Inc. All Rights Reserved.
131.32 - *
131.33 - * If you wish your version of this file to be governed by only the CDDL
131.34 - * or only the GPL Version 2, indicate your decision by adding
131.35 - * "[Contributor] elects to include this software in this distribution
131.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
131.37 - * single choice of license, a recipient has the option to distribute
131.38 - * your version of this file under either the CDDL, the GPL Version 2 or
131.39 - * to extend the choice of license to its licensees as provided above.
131.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
131.41 - * Version 2 license, then the option applies only if the new code is
131.42 - * made subject to such option by the copyright holder.
131.43 - */
131.44 -
131.45 -package org.openide.util.lookup;
131.46 -
131.47 -import java.util.concurrent.ExecutionException;
131.48 -
131.49 -import java.lang.ref.WeakReference;
131.50 -import java.util.*;
131.51 -import java.util.concurrent.Executors;
131.52 -import java.util.concurrent.TimeUnit;
131.53 -import junit.framework.Test;
131.54 -import org.netbeans.junit.*;
131.55 -import org.openide.util.Lookup;
131.56 -import org.openide.util.lookup.AbstractLookup.Pair;
131.57 -
131.58 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
131.59 -public class AbstractLookupTest extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
131.60 - public AbstractLookupTest(java.lang.String testName) {
131.61 - super(testName, null);
131.62 - }
131.63 -
131.64 - //
131.65 - // Impl of AbstractLookupBaseHid.Impl
131.66 - //
131.67 -
131.68 - /** Creates the initial abstract lookup.
131.69 - */
131.70 - public Lookup createInstancesLookup (InstanceContent ic) {
131.71 - return new AbstractLookup (ic, new InheritanceTree ());
131.72 - }
131.73 -
131.74 - /** Creates an lookup for given lookup. This class just returns
131.75 - * the object passed in, but subclasses can be different.
131.76 - * @param lookup in lookup
131.77 - * @return a lookup to use
131.78 - */
131.79 - public Lookup createLookup (Lookup lookup) {
131.80 - return lookup;
131.81 - }
131.82 -
131.83 - public void clearCaches () {
131.84 - }
131.85 -
131.86 - static class LkpResultCanBeGargageCollectedAndClearsTheResult extends AbstractLookup {
131.87 - public int cleared;
131.88 - public int dirty;
131.89 -
131.90 - synchronized @Override boolean cleanUpResult(Template t) {
131.91 - boolean res = super.cleanUpResult (t);
131.92 - if (res) {
131.93 - cleared++;
131.94 - } else {
131.95 - dirty++;
131.96 - }
131.97 -
131.98 - notifyAll ();
131.99 -
131.100 - return res;
131.101 - }
131.102 - }
131.103 - public void testResultCanBeGargageCollectedAndClearsTheResult () throws Exception {
131.104 - LkpResultCanBeGargageCollectedAndClearsTheResult lkp = new LkpResultCanBeGargageCollectedAndClearsTheResult ();
131.105 - assertSize ("24 for AbstractLookup, 8 for two ints", 32, lkp);
131.106 - synchronized (lkp) {
131.107 - Lookup.Result res = lkp.lookup (new Lookup.Template (getClass ()));
131.108 - res.allItems();
131.109 -
131.110 - WeakReference ref = new WeakReference (res);
131.111 - res = null;
131.112 - assertGC ("Reference can get cleared", ref);
131.113 -
131.114 - // wait till we
131.115 - while (lkp.cleared == 0 && lkp.dirty == 0) {
131.116 - lkp.wait ();
131.117 - }
131.118 -
131.119 - assertEquals ("No dirty cleanups", 0, lkp.dirty);
131.120 - assertEquals ("One final cleanup", 1, lkp.cleared);
131.121 - }
131.122 - //assertSize ("Everything has been cleaned to original size", 32, lkp);
131.123 -
131.124 - }
131.125 -
131.126 - public void testPairCannotBeUsedInMoreThanOneLookupAtOnce () throws Exception {
131.127 - /** Simple pair with no data */
131.128 - class EmptyPair extends AbstractLookup.Pair {
131.129 - protected boolean creatorOf(Object obj) { return false; }
131.130 - public String getDisplayName() { return "Empty"; }
131.131 - public String getId() { return "empty"; }
131.132 - public Object getInstance() { return null; }
131.133 - public Class getType() { return Object.class; }
131.134 - protected boolean instanceOf(Class c) { return c == getType (); }
131.135 - } // end of EmptyPair
131.136 -
131.137 - AbstractLookup.Content c1 = new AbstractLookup.Content ();
131.138 - AbstractLookup.Content c2 = new AbstractLookup.Content ();
131.139 - AbstractLookup l1 = new AbstractLookup (c1);
131.140 - AbstractLookup l2 = new AbstractLookup (c2);
131.141 -
131.142 - EmptyPair empty = new EmptyPair ();
131.143 - c1.addPair (empty);
131.144 - Lookup.Result res = l1.lookup (new Lookup.Template (Object.class));
131.145 - assertEquals (
131.146 - "Pair is really found", empty,
131.147 - res.allItems ().iterator().next ()
131.148 - );
131.149 - try {
131.150 - c2.addPair (empty);
131.151 - fail ("It should not be possible to add pair to two lookups");
131.152 - } catch (IllegalStateException ex) {
131.153 - // ok, exception is fine
131.154 - }
131.155 - assertEquals (
131.156 - "L2 is still empty", Collections.EMPTY_LIST,
131.157 - new ArrayList (l2.lookup (new Lookup.Template (Object.class)).allItems ())
131.158 - );
131.159 - }
131.160 -
131.161 - public void testInitializationCanBeDoneFromAnotherThread () {
131.162 - class MyLkp extends AbstractLookup implements Runnable {
131.163 - private InstanceContent ic;
131.164 - private boolean direct;
131.165 -
131.166 - public MyLkp (boolean direct) {
131.167 - this (direct, new InstanceContent ());
131.168 - }
131.169 -
131.170 - private MyLkp (boolean direct, InstanceContent ic) {
131.171 - super (ic);
131.172 - this.direct = direct;
131.173 - this.ic = ic;
131.174 - }
131.175 -
131.176 - protected @Override void initialize() {
131.177 - if (direct) {
131.178 - run ();
131.179 - } else {
131.180 - try {
131.181 - Executors.newSingleThreadScheduledExecutor().schedule(this, 0, TimeUnit.MICROSECONDS).get();
131.182 - } catch (InterruptedException ex) {
131.183 - ex.printStackTrace();
131.184 - } catch (ExecutionException ex) {
131.185 - ex.printStackTrace();
131.186 - }
131.187 - }
131.188 - }
131.189 -
131.190 - public void run () {
131.191 - ic.add (this);
131.192 - ic.remove (this);
131.193 - ic.set (Collections.nCopies(10, this), null);
131.194 - ic.set (Collections.EMPTY_LIST, null);
131.195 - ic.add (AbstractLookupTest.this);
131.196 - }
131.197 - }
131.198 -
131.199 - assertEquals ("The test should be there", this, new MyLkp (true).lookup (Object.class));
131.200 - assertEquals ("and in async mode as well", this, new MyLkp (false).lookup (Object.class));
131.201 - }
131.202 -
131.203 - public void testBeforeLookupIsCalled () {
131.204 - class BeforeL extends AbstractLookup {
131.205 - public ArrayList list = new ArrayList ();
131.206 - public String toAdd;
131.207 - public InstanceContent ic;
131.208 -
131.209 - public BeforeL () {
131.210 - this (new InstanceContent ());
131.211 - }
131.212 -
131.213 - private BeforeL (InstanceContent c) {
131.214 - super (c);
131.215 - this.ic = c;
131.216 - }
131.217 -
131.218 - protected @Override void beforeLookup(Template t) {
131.219 - if (toAdd != null) {
131.220 - list.add (0, new SerialPair (toAdd));
131.221 - setPairs (list);
131.222 - } else {
131.223 - ic.add (new Integer (1));
131.224 - }
131.225 - }
131.226 - }
131.227 -
131.228 - BeforeL lookup = new BeforeL ();
131.229 -
131.230 - lookup.toAdd = "First";
131.231 - assertEquals ("First if found", "First", lookup.lookup (String.class));
131.232 -
131.233 - lookup.toAdd = "2";
131.234 - assertEquals ("2 is not first", "2", lookup.lookup (String.class));
131.235 -
131.236 - Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
131.237 - for (int i = 3; i < 20; i++) {
131.238 - lookup.toAdd = String.valueOf (i);
131.239 - assertEquals (i + " items are now there", i, res.allInstances ().size ());
131.240 - }
131.241 - for (int i = 20; i < 35; i++) {
131.242 - lookup.toAdd = String.valueOf (i);
131.243 - assertEquals (i + " items are now there", i, res.allItems ().size ());
131.244 - }
131.245 -
131.246 - assertEquals ("Just strings are there now", 1, res.allClasses ().size ());
131.247 - lookup.toAdd = null; // this will add integer
131.248 - assertEquals ("Two classes now", 2, res.allClasses ().size ());
131.249 - }
131.250 -
131.251 - public void testInconsistentAfterDeserIssue71744() throws Exception {
131.252 - InheritanceTree inhTree = new InheritanceTree();
131.253 -
131.254 - AbstractLookup al = new AbstractLookup(new AbstractLookup.Content(), inhTree);
131.255 - {
131.256 -
131.257 - Collection r = al.lookup(new Lookup.Template(Integer.class)).allInstances();
131.258 - assertEquals("None", 0, r.size());
131.259 - }
131.260 -
131.261 - ICP item = new ICP(new Integer(10));
131.262 - al.addPair(item);
131.263 - al.removePair(item);
131.264 -
131.265 - AbstractLookup newLookup = (AbstractLookup)reserialize(al);
131.266 -
131.267 - newLookup.lookup(Number.class);
131.268 -
131.269 -
131.270 - newLookup.addPair(new ICP(new Long(20)));
131.271 -
131.272 - {
131.273 -
131.274 - Collection r = newLookup.lookup(new Lookup.Template(Number.class)).allInstances();
131.275 - assertEquals("one", 1, r.size());
131.276 -/*
131.277 - Iterator it = r.iterator();
131.278 - assertEquals(new Integer(10), it.next());
131.279 - assertEquals(new Long(20), it.next());*/
131.280 - }
131.281 - }
131.282 -
131.283 - public void testMatchesIssue130673() {
131.284 - class BrokenPairReturningNullID extends Pair<Object> {
131.285 - @Override
131.286 - protected boolean instanceOf(Class<?> c) {
131.287 - return false;
131.288 - }
131.289 -
131.290 - @Override
131.291 - protected boolean creatorOf(Object obj) {
131.292 - return false;
131.293 - }
131.294 -
131.295 - @Override
131.296 - public Object getInstance() {
131.297 - return null;
131.298 - }
131.299 -
131.300 - @Override
131.301 - public Class<? extends Object> getType() {
131.302 - return null;
131.303 - }
131.304 -
131.305 - @Override
131.306 - public String getId() {
131.307 - return null;
131.308 - }
131.309 -
131.310 - @Override
131.311 - public String getDisplayName() {
131.312 - return null;
131.313 - }
131.314 - }
131.315 - BrokenPairReturningNullID broken = new BrokenPairReturningNullID();
131.316 -
131.317 -
131.318 - Lookup.Template<String> t = new Lookup.Template<String>(String.class, "ID", null);
131.319 - boolean not = AbstractLookup.matches(t, broken, true);
131.320 - assertFalse("Does not match the template, but throws no exception", not);
131.321 - }
131.322 -
131.323 - private static final class ICP extends AbstractLookup.Pair {
131.324 - private Number s;
131.325 -
131.326 - public ICP (Number s) {
131.327 - this.s = s;
131.328 - }
131.329 -
131.330 -
131.331 - protected boolean instanceOf(Class c) {
131.332 - return c.isInstance(s);
131.333 - }
131.334 -
131.335 - protected boolean creatorOf(Object obj) {
131.336 - return s == obj;
131.337 - }
131.338 -
131.339 - public Object getInstance() {
131.340 - return s;
131.341 - }
131.342 -
131.343 - public Class getType() {
131.344 - return s.getClass();
131.345 - }
131.346 -
131.347 - public String getId() {
131.348 - return s.toString();
131.349 - }
131.350 -
131.351 - public String getDisplayName() {
131.352 - return getId();
131.353 - }
131.354 -
131.355 - }
131.356 -}
132.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java Thu Dec 10 19:23:25 2009 -0500
132.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
132.3 @@ -1,228 +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-2006 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.lookup;
132.46 -
132.47 -import java.util.*;
132.48 -import org.openide.util.Lookup;
132.49 -
132.50 -/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
132.51 - */
132.52 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
132.53 -public class ExcludingLookupTest extends AbstractLookupBaseHid
132.54 -implements AbstractLookupBaseHid.Impl {
132.55 - public ExcludingLookupTest(java.lang.String testName) {
132.56 - super(testName, null);
132.57 - }
132.58 -
132.59 - public Lookup createLookup (final Lookup lookup) {
132.60 - return Lookups.exclude (lookup, new Class[0]);
132.61 - }
132.62 -
132.63 - public Lookup createInstancesLookup (InstanceContent ic) {
132.64 - return new AbstractLookup (ic);
132.65 - }
132.66 -
132.67 - public void clearCaches () {
132.68 - }
132.69 -
132.70 - public void testWeCanRemoveInteger () throws Exception {
132.71 - doBasicFilteringTest (Integer.class, Integer.class, 0);
132.72 - }
132.73 -
132.74 - public void testWeCanRemoveIntegersEvenByAskingForRemoveOfAllNumbers () throws Exception {
132.75 - doBasicFilteringTest (Number.class, Integer.class, 0);
132.76 - }
132.77 - public void testFunWithInterfaces () throws Exception {
132.78 - doBasicFilteringTest (java.io.Serializable.class, Integer.class, 0);
132.79 - }
132.80 -
132.81 - public void testWeCanGetInstanceOfSerializableEvenItIsExcludedIfWeAskForClassNotExtendingIt () throws Exception {
132.82 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { java.io.Serializable.class });
132.83 - Lookup.Template t = new Lookup.Template (Object.class);
132.84 - Lookup.Result res = lookup.lookup (t);
132.85 -
132.86 - LL ll = new LL ();
132.87 - res.addLookupListener (ll);
132.88 - assertEquals ("Nothing is there", 0, res.allItems ().size ());
132.89 -
132.90 - Object inst = new Integer (3);
132.91 - ic.add (inst);
132.92 -
132.93 - assertEquals ("Not Filtered out", inst, lookup.lookup (Object.class));
132.94 - assertEquals ("Not Filtered out2", inst, lookup.lookupItem (t).getInstance ());
132.95 - assertEquals ("One is there - 2", 1, res.allItems ().size ());
132.96 - assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
132.97 - assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
132.98 - assertEquals ("Right # of events", 1, ll.getCount ());
132.99 -
132.100 - ic.remove (inst);
132.101 - assertEquals ("Filtered out3", null, lookup.lookupItem (t));
132.102 - assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
132.103 - assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
132.104 - assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
132.105 - assertEquals ("Of course it is not there", null, lookup.lookup (Object.class));
132.106 - assertEquals ("Right # of events", 1, ll.getCount ());
132.107 - }
132.108 -
132.109 - public void testIntegersQueriedThruObject () throws Exception {
132.110 - doBasicFilteringTest (Number.class, Object.class, 1);
132.111 - }
132.112 -
132.113 - private void doBasicFilteringTest (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
132.114 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
132.115 - Lookup.Template t = new Lookup.Template (theQuery);
132.116 - Lookup.Result res = lookup.lookup (t);
132.117 -
132.118 - LL ll = new LL ();
132.119 - res.addLookupListener (ll);
132.120 - assertEquals ("Nothing is there", 0, res.allItems ().size ());
132.121 -
132.122 - Object inst = new Integer (3);
132.123 - ic.add (inst);
132.124 -
132.125 - assertEquals ("Filtered out", null, lookup.lookup (theQuery));
132.126 - assertEquals ("Filtered out2", null, lookup.lookupItem (t));
132.127 - assertEquals ("Nothing is there - 2", 0, res.allItems ().size ());
132.128 - assertEquals ("Nothing is there - 2a", 0, res.allInstances ().size ());
132.129 - assertEquals ("Nothing is there - 2b", 0, res.allClasses ().size ());
132.130 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
132.131 -
132.132 - ic.remove (inst);
132.133 - assertEquals ("Filtered out3", null, lookup.lookupItem (t));
132.134 - assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
132.135 - assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
132.136 - assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
132.137 - assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
132.138 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
132.139 -
132.140 - }
132.141 -
132.142 - public void testSizeOfTheLookup () throws Exception {
132.143 - Class exclude = String.class;
132.144 -
132.145 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { exclude });
132.146 -
132.147 - assertSize ("Should be pretty lightweight", Collections.singleton (lookup), 16,
132.148 - new Object[] { this.instanceLookup, exclude });
132.149 - }
132.150 - public void testSizeOfTheLookupForMultipleFiltersIsHigher () throws Exception {
132.151 - Class exclude = String.class;
132.152 - Class exclude2 = Integer.class;
132.153 - Class[] arr = new Class[] { exclude, exclude2 };
132.154 -
132.155 - Lookup lookup = Lookups.exclude (this.instanceLookup, arr);
132.156 -
132.157 - assertSize ("Is fatter", Collections.singleton (lookup), 40,
132.158 - new Object[] { this.instanceLookup, exclude, exclude2 });
132.159 - assertSize ("But only due to the array", Collections.singleton (lookup), 16,
132.160 - new Object[] { this.instanceLookup, exclude, exclude2, arr });
132.161 - }
132.162 -
132.163 - public void testFilteringOfSomething () throws Exception {
132.164 - doFilteringOfSomething (Runnable.class, java.io.Serializable.class, 1);
132.165 - }
132.166 -
132.167 - private void doFilteringOfSomething (Class theFilter, Class theQuery, int numberOfExcpectedEventsAfterOneChange) throws Exception {
132.168 - Lookup lookup = Lookups.exclude (this.instanceLookup, new Class[] { theFilter });
132.169 - Lookup.Template t = new Lookup.Template (theQuery);
132.170 - Lookup.Result res = lookup.lookup (t);
132.171 -
132.172 - LL ll = new LL ();
132.173 - res.addLookupListener (ll);
132.174 - assertEquals ("Nothing is there", 0, res.allItems ().size ());
132.175 -
132.176 - Object inst = new Integer (3);
132.177 - ic.add (inst);
132.178 -
132.179 - assertEquals ("Accepted", inst, lookup.lookup (theQuery));
132.180 - assertNotNull ("Accepted too", lookup.lookupItem (t));
132.181 - assertEquals ("One is there - 2", 1, res.allItems ().size ());
132.182 - assertEquals ("One is there - 2a", 1, res.allInstances ().size ());
132.183 - assertEquals ("One is there - 2b", 1, res.allClasses ().size ());
132.184 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
132.185 -
132.186 - Object inst2 = new Thread (); // implements Runnable
132.187 - ic.add (inst2);
132.188 - assertEquals ("Accepted - 2", inst, lookup.lookup (theQuery));
132.189 - assertNotNull ("Accepted too -2", lookup.lookupItem (t));
132.190 - assertEquals ("One is there - 3", 1, res.allItems ().size ());
132.191 - assertEquals ("One is there - 3a", 1, res.allInstances ().size ());
132.192 - assertEquals ("One is there - 3b", 1, res.allClasses ().size ());
132.193 - assertEquals ("Right # of events", 0, ll.getCount ());
132.194 -
132.195 -
132.196 - ic.remove (inst);
132.197 - assertEquals ("Filtered out3", null, lookup.lookupItem (t));
132.198 - assertEquals ("Nothing is there - 3", 0, res.allItems ().size ());
132.199 - assertEquals ("Nothing is there - 3a", 0, res.allInstances ().size ());
132.200 - assertEquals ("Nothing is there - 3b", 0, res.allClasses ().size ());
132.201 - assertEquals ("Of course it is not there", null, lookup.lookup (theQuery));
132.202 - assertEquals ("Right # of events", numberOfExcpectedEventsAfterOneChange, ll.getCount ());
132.203 - }
132.204 -
132.205 - public void testTheBehaviourAsRequestedByDavidAndDescribedByJesse () throws Exception {
132.206 - class C implements Runnable, java.io.Serializable {
132.207 - public void run () {}
132.208 - }
132.209 - Object c = new C();
132.210 - Lookup l1 = Lookups.singleton(c);
132.211 - Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
132.212 - assertNull(l2.lookup(Runnable.class));
132.213 - assertEquals(c, l2.lookup(java.io.Serializable.class));
132.214 - }
132.215 -
132.216 - public void testTheBehaviourAsRequestedByDavidAndDescribedByJesseWithUsageOfResult () throws Exception {
132.217 - class C implements Runnable, java.io.Serializable {
132.218 - public void run () {}
132.219 - }
132.220 - Object c = new C();
132.221 - Lookup l1 = Lookups.singleton(c);
132.222 - Lookup l2 = Lookups.exclude(l1, new Class[] {Runnable.class});
132.223 -
132.224 - Lookup.Result run = l2.lookup (new Lookup.Template (Runnable.class));
132.225 - Lookup.Result ser = l2.lookup (new Lookup.Template (java.io.Serializable.class));
132.226 -
132.227 - assertEquals ("Runnables filtered out", 0, run.allItems ().size ());
132.228 - assertEquals ("One serialiazble", 1, ser.allItems ().size ());
132.229 - assertEquals ("And it is c", c, ser.allInstances ().iterator ().next ());
132.230 - }
132.231 -}
133.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/InheritanceTreeTest.java Thu Dec 10 19:23:25 2009 -0500
133.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
133.3 @@ -1,77 +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-2006 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 -package org.openide.util.lookup;
133.45 -
133.46 -import junit.framework.TestCase;
133.47 -import junit.framework.*;
133.48 -import org.openide.util.Lookup;
133.49 -import org.openide.util.lookup.AbstractLookup.ReferenceIterator;
133.50 -import org.openide.util.lookup.AbstractLookup.ReferenceToResult;
133.51 -import java.io.*;
133.52 -import java.lang.ref.WeakReference;
133.53 -import java.util.*;
133.54 -
133.55 -/**
133.56 - *
133.57 - * @author Jaroslav Tulach
133.58 - */
133.59 -public class InheritanceTreeTest extends TestCase {
133.60 -
133.61 - public InheritanceTreeTest(String testName) {
133.62 - super(testName);
133.63 - }
133.64 -
133.65 - protected void setUp() throws Exception {
133.66 - }
133.67 -
133.68 - protected void tearDown() throws Exception {
133.69 - }
133.70 -
133.71 - public void testDeserOfNode() {
133.72 - InheritanceTree inh = new InheritanceTree();
133.73 - InheritanceTree.Node n = new InheritanceTree.Node(String.class);
133.74 - n.markDeserialized();
133.75 - n.markDeserialized();
133.76 -
133.77 - n.assignItem(inh, new InstanceContent.SimpleItem("Ahoj"));
133.78 - }
133.79 -
133.80 -}
134.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/InitializationBug44134Test.java Thu Dec 10 19:23:25 2009 -0500
134.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
134.3 @@ -1,126 +0,0 @@
134.4 -/*
134.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
134.6 - *
134.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
134.8 - *
134.9 - * The contents of this file are subject to the terms of either the GNU
134.10 - * General Public License Version 2 only ("GPL") or the Common
134.11 - * Development and Distribution License("CDDL") (collectively, the
134.12 - * "License"). You may not use this file except in compliance with the
134.13 - * License. You can obtain a copy of the License at
134.14 - * http://www.netbeans.org/cddl-gplv2.html
134.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
134.16 - * specific language governing permissions and limitations under the
134.17 - * License. When distributing the software, include this License Header
134.18 - * Notice in each file and include the License file at
134.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
134.20 - * particular file as subject to the "Classpath" exception as provided
134.21 - * by Sun in the GPL Version 2 section of the License file that
134.22 - * accompanied this code. If applicable, add the following below the
134.23 - * License Header, with the fields enclosed by brackets [] replaced by
134.24 - * your own identifying information:
134.25 - * "Portions Copyrighted [year] [name of copyright owner]"
134.26 - *
134.27 - * Contributor(s):
134.28 - *
134.29 - * The Original Software is NetBeans. The Initial Developer of the Original
134.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
134.31 - * Microsystems, Inc. All Rights Reserved.
134.32 - *
134.33 - * If you wish your version of this file to be governed by only the CDDL
134.34 - * or only the GPL Version 2, indicate your decision by adding
134.35 - * "[Contributor] elects to include this software in this distribution
134.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
134.37 - * single choice of license, a recipient has the option to distribute
134.38 - * your version of this file under either the CDDL, the GPL Version 2 or
134.39 - * to extend the choice of license to its licensees as provided above.
134.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
134.41 - * Version 2 license, then the option applies only if the new code is
134.42 - * made subject to such option by the copyright holder.
134.43 - */
134.44 -
134.45 -package org.openide.util.lookup;
134.46 -
134.47 -import java.util.*;
134.48 -import org.netbeans.junit.*;
134.49 -import org.openide.util.Lookup;
134.50 -
134.51 -public class InitializationBug44134Test extends NbTestCase {
134.52 - public InitializationBug44134Test (java.lang.String testName) {
134.53 - super(testName);
134.54 - }
134.55 -
134.56 - public static void main(java.lang.String[] args) {
134.57 - junit.textui.TestRunner.run(new NbTestSuite(InitializationBug44134Test.class));
134.58 - }
134.59 -
134.60 - public void testThereShouldBe18Integers () throws Exception {
134.61 - FooManifestLookup foo = new FooManifestLookup ();
134.62 -
134.63 - Collection items = foo.lookup (new Lookup.Template (Integer.class)).allItems ();
134.64 -
134.65 - assertEquals ("18 of them", 18, items.size ());
134.66 -
134.67 - Iterator it = items.iterator ();
134.68 - while (it.hasNext()) {
134.69 - Lookup.Item t = (Lookup.Item)it.next ();
134.70 - assertEquals ("Is Integer", Integer.class, t.getInstance ().getClass ());
134.71 - }
134.72 - }
134.73 -
134.74 -
134.75 - public class FooManifestLookup extends AbstractLookup {
134.76 - public FooManifestLookup() {
134.77 - super();
134.78 - }
134.79 -
134.80 - @Override
134.81 - protected void initialize() {
134.82 - for (int i=0; i<18; i++) {
134.83 - try {
134.84 - String id= "__" + i;
134.85 -
134.86 - addPair(new FooLookupItem(new Integer(i),id));
134.87 - }
134.88 - catch (Exception e) {
134.89 - }
134.90 - }
134.91 - }
134.92 -
134.93 - public class FooLookupItem extends AbstractLookup.Pair {
134.94 - public FooLookupItem(Integer data, String id) {
134.95 - super();
134.96 - this.data=data;
134.97 - this.id=id;
134.98 - }
134.99 -
134.100 - protected boolean creatorOf(Object obj) {
134.101 - return obj == data;
134.102 - }
134.103 -
134.104 - public String getDisplayName() {
134.105 - return data.toString();
134.106 - }
134.107 -
134.108 - public Class getType () {
134.109 - return Integer.class;
134.110 - }
134.111 -
134.112 - protected boolean instanceOf (Class c) {
134.113 - return c.isInstance(data);
134.114 - }
134.115 -
134.116 - public Object getInstance() {
134.117 - return data;
134.118 - }
134.119 -
134.120 - public String getId() {
134.121 - return id;
134.122 - }
134.123 -
134.124 - private Integer data;
134.125 - private String id;
134.126 - }
134.127 - }
134.128 -
134.129 -}
135.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/KomrskaLookupTest.java Thu Dec 10 19:23:25 2009 -0500
135.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
135.3 @@ -1,177 +0,0 @@
135.4 -/*
135.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
135.6 - *
135.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
135.8 - *
135.9 - * The contents of this file are subject to the terms of either the GNU
135.10 - * General Public License Version 2 only ("GPL") or the Common
135.11 - * Development and Distribution License("CDDL") (collectively, the
135.12 - * "License"). You may not use this file except in compliance with the
135.13 - * License. You can obtain a copy of the License at
135.14 - * http://www.netbeans.org/cddl-gplv2.html
135.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
135.16 - * specific language governing permissions and limitations under the
135.17 - * License. When distributing the software, include this License Header
135.18 - * Notice in each file and include the License file at
135.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
135.20 - * particular file as subject to the "Classpath" exception as provided
135.21 - * by Sun in the GPL Version 2 section of the License file that
135.22 - * accompanied this code. If applicable, add the following below the
135.23 - * License Header, with the fields enclosed by brackets [] replaced by
135.24 - * your own identifying information:
135.25 - * "Portions Copyrighted [year] [name of copyright owner]"
135.26 - *
135.27 - * If you wish your version of this file to be governed by only the CDDL
135.28 - * or only the GPL Version 2, indicate your decision by adding
135.29 - * "[Contributor] elects to include this software in this distribution
135.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
135.31 - * single choice of license, a recipient has the option to distribute
135.32 - * your version of this file under either the CDDL, the GPL Version 2 or
135.33 - * to extend the choice of license to its licensees as provided above.
135.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
135.35 - * Version 2 license, then the option applies only if the new code is
135.36 - * made subject to such option by the copyright holder.
135.37 - *
135.38 - * Contributor(s):
135.39 - *
135.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
135.41 - */
135.42 -package org.openide.util.lookup;
135.43 -
135.44 -import org.junit.After;
135.45 -import org.junit.Before;
135.46 -import org.junit.Test;
135.47 -import org.openide.util.Lookup;
135.48 -import org.openide.util.LookupEvent;
135.49 -import org.openide.util.LookupListener;
135.50 -import static org.junit.Assert.*;
135.51 -
135.52 -/**
135.53 - * Test donated by Mr. Komrska. Seems to pass with 6.5.
135.54 - * @author komrska
135.55 - */
135.56 -public final class KomrskaLookupTest {
135.57 - private TestLookupManager lookupManager=null;
135.58 - private StringBuffer result=null;
135.59 -
135.60 - //
135.61 -
135.62 - private void addToLookup(final TestLookupItemA object) {
135.63 - result.append('A');
135.64 - lookupManager.add(object);
135.65 - }
135.66 - private void removeFromLookup(final TestLookupItemA object) {
135.67 - result.append('A');
135.68 - lookupManager.remove(object);
135.69 - }
135.70 -
135.71 - private void addToLookup(final TestLookupItemB object) {
135.72 - result.append('B');
135.73 - lookupManager.add(object);
135.74 - }
135.75 - private void removeFromLookup(final TestLookupItemB object) {
135.76 - result.append('B');
135.77 - lookupManager.remove(object);
135.78 - }
135.79 -
135.80 - public String getResult() {
135.81 - return result.toString();
135.82 - }
135.83 -
135.84 - //
135.85 -
135.86 - @Before
135.87 - public void setUp() {
135.88 - lookupManager=new TestLookupManager();
135.89 - result=new StringBuffer();
135.90 - }
135.91 -
135.92 - @After
135.93 - public void tearDown() {
135.94 - lookupManager=null;
135.95 - result=null;
135.96 - }
135.97 -
135.98 - @Test
135.99 - public void testLookupBug() {
135.100 - TestLookupItemA itemA1=new TestLookupItemA();
135.101 - TestLookupItemB itemB1=new TestLookupItemB();
135.102 - //
135.103 - addToLookup(itemA1);
135.104 - addToLookup(itemB1);
135.105 - removeFromLookup(itemA1);
135.106 - removeFromLookup(itemB1);
135.107 - addToLookup(itemB1);
135.108 - removeFromLookup(itemB1);
135.109 - //
135.110 - addToLookup(itemA1);
135.111 - addToLookup(itemB1);
135.112 - removeFromLookup(itemA1);
135.113 - removeFromLookup(itemB1);
135.114 - addToLookup(itemB1);
135.115 - removeFromLookup(itemB1);
135.116 - //
135.117 - addToLookup(itemA1);
135.118 - addToLookup(itemB1);
135.119 - removeFromLookup(itemA1);
135.120 - removeFromLookup(itemB1);
135.121 - addToLookup(itemB1);
135.122 - removeFromLookup(itemB1);
135.123 - //
135.124 - assertEquals(getResult(),lookupManager.getResult());
135.125 - }
135.126 -
135.127 - public static final class TestLookupItemA {}
135.128 - public static final class TestLookupItemB {}
135.129 - public static final class TestLookupManager {
135.130 - private InstanceContent instanceContent=new InstanceContent();
135.131 - private AbstractLookup abstractLookup=new AbstractLookup(instanceContent);
135.132 -
135.133 - private Lookup.Result<TestLookupItemA> resultA=null;
135.134 - private Lookup.Result<TestLookupItemB> resultB=null;
135.135 -
135.136 - private LookupListener listenerA=new LookupListener() {
135.137 - public void resultChanged(LookupEvent event) {
135.138 - result.append('A');
135.139 - }
135.140 - };
135.141 - private LookupListener listenerB=new LookupListener() {
135.142 - public void resultChanged(LookupEvent event) {
135.143 - result.append('B');
135.144 - }
135.145 - };
135.146 -
135.147 - private StringBuffer result=new StringBuffer();
135.148 -
135.149 - //
135.150 -
135.151 - public TestLookupManager() {
135.152 - Lookup.Template<TestLookupItemA> templateA=
135.153 - new Lookup.Template<TestLookupItemA>(TestLookupItemA.class);
135.154 - resultA=abstractLookup.lookup(templateA);
135.155 - resultA.addLookupListener(listenerA);
135.156 - resultA.allInstances().size();
135.157 - //
135.158 - Lookup.Template<TestLookupItemB> templateB=
135.159 - new Lookup.Template<TestLookupItemB>(TestLookupItemB.class);
135.160 - resultB=abstractLookup.lookup(templateB);
135.161 - resultB.addLookupListener(listenerB);
135.162 - resultB.allInstances().size();
135.163 - // WORKAROUND
135.164 - // instanceContent.add(Boolean.TRUE);
135.165 - }
135.166 -
135.167 - //
135.168 -
135.169 - public void add(Object item) {
135.170 - instanceContent.add(item);
135.171 - }
135.172 - public void remove(Object item) {
135.173 - instanceContent.remove(item);
135.174 - }
135.175 - public String getResult() {
135.176 - return result.toString();
135.177 - }
135.178 - }
135.179 -
135.180 -}
136.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/LookupBugTest.java Thu Dec 10 19:23:25 2009 -0500
136.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
136.3 @@ -1,79 +0,0 @@
136.4 -package org.openide.util.lookup;
136.5 -
136.6 -import java.util.logging.Logger;
136.7 -import org.junit.Before;
136.8 -import org.junit.Test;
136.9 -import org.openide.util.Lookup;
136.10 -import org.openide.util.LookupEvent;
136.11 -import org.openide.util.LookupListener;
136.12 -import static org.junit.Assert.*;
136.13 -
136.14 -/**
136.15 - * Test of a Lookup bug seen in NetBeans platforms 6.0-6.5M1.
136.16 - * @author rlee
136.17 - */
136.18 -public class LookupBugTest implements LookupListener
136.19 -{
136.20 - private static final int MAX_LOOPS = 1000;
136.21 -
136.22 - private AbstractLookup lookup;
136.23 - private InstanceContent content;
136.24 - private Lookup.Result<String> wordResult;
136.25 - private Lookup.Result<Integer> numberResult;
136.26 - private String word;
136.27 - private Integer number;
136.28 - private Logger LOG;
136.29 -
136.30 - private boolean fired;
136.31 - private int i;
136.32 -
136.33 - @Before
136.34 - public void setUp()
136.35 - {
136.36 - LOG = Logger.getLogger("test.LookupBugTest");
136.37 - content = new InstanceContent();
136.38 - lookup = new AbstractLookup(content);
136.39 - wordResult = lookup.lookupResult(java.lang.String.class);
136.40 - wordResult.addLookupListener(this);
136.41 - numberResult = lookup.lookupResult(java.lang.Integer.class);
136.42 - numberResult.addLookupListener(this);
136.43 -
136.44 - fired = false;
136.45 - }
136.46 -
136.47 - @Test
136.48 - public void lookupTest()
136.49 - {
136.50 - for(i = 0; i < MAX_LOOPS; i++ )
136.51 - {
136.52 - word = String.valueOf(i);
136.53 - number = new Integer(i);
136.54 - content.add(word);
136.55 - assertTrue( "word on loop " + i, checkLookupEventFired() );
136.56 - content.add(number);
136.57 - assertTrue( "number on loop " + i, checkLookupEventFired() );
136.58 - content.remove(word);
136.59 - assertTrue( "remove word on loop " + i, checkLookupEventFired() );
136.60 - content.remove(number);
136.61 - assertTrue( "remove number on loop " + i, checkLookupEventFired() );
136.62 -
136.63 - assertTrue("The lookup still needs to stay simple", AbstractLookup.isSimple(lookup));
136.64 - }
136.65 - }
136.66 -
136.67 - public void resultChanged(LookupEvent ev)
136.68 - {
136.69 - fired = true;
136.70 - }
136.71 -
136.72 - public boolean checkLookupEventFired()
136.73 - {
136.74 - LOG.fine(" round: " + i + " word = " + word + " number = " + number);
136.75 - if( fired )
136.76 - {
136.77 - fired = false;
136.78 - return true;
136.79 - }
136.80 - else return false;
136.81 - }
136.82 -}
137.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/LookupsProxyTest.java Thu Dec 10 19:23:25 2009 -0500
137.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
137.3 @@ -1,282 +0,0 @@
137.4 -/*
137.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
137.6 - *
137.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
137.8 - *
137.9 - * The contents of this file are subject to the terms of either the GNU
137.10 - * General Public License Version 2 only ("GPL") or the Common
137.11 - * Development and Distribution License("CDDL") (collectively, the
137.12 - * "License"). You may not use this file except in compliance with the
137.13 - * License. You can obtain a copy of the License at
137.14 - * http://www.netbeans.org/cddl-gplv2.html
137.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
137.16 - * specific language governing permissions and limitations under the
137.17 - * License. When distributing the software, include this License Header
137.18 - * Notice in each file and include the License file at
137.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
137.20 - * particular file as subject to the "Classpath" exception as provided
137.21 - * by Sun in the GPL Version 2 section of the License file that
137.22 - * accompanied this code. If applicable, add the following below the
137.23 - * License Header, with the fields enclosed by brackets [] replaced by
137.24 - * your own identifying information:
137.25 - * "Portions Copyrighted [year] [name of copyright owner]"
137.26 - *
137.27 - * Contributor(s):
137.28 - *
137.29 - * The Original Software is NetBeans. The Initial Developer of the Original
137.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
137.31 - * Microsystems, Inc. All Rights Reserved.
137.32 - *
137.33 - * If you wish your version of this file to be governed by only the CDDL
137.34 - * or only the GPL Version 2, indicate your decision by adding
137.35 - * "[Contributor] elects to include this software in this distribution
137.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
137.37 - * single choice of license, a recipient has the option to distribute
137.38 - * your version of this file under either the CDDL, the GPL Version 2 or
137.39 - * to extend the choice of license to its licensees as provided above.
137.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
137.41 - * Version 2 license, then the option applies only if the new code is
137.42 - * made subject to such option by the copyright holder.
137.43 - */
137.44 -
137.45 -package org.openide.util.lookup;
137.46 -
137.47 -import java.io.Serializable;
137.48 -
137.49 -import java.util.*;
137.50 -import org.netbeans.junit.*;
137.51 -import org.openide.util.Lookup;
137.52 -import org.openide.util.LookupEvent;
137.53 -import org.openide.util.LookupListener;
137.54 -
137.55 -/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
137.56 - */
137.57 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
137.58 -public class LookupsProxyTest extends AbstractLookupBaseHid
137.59 -implements AbstractLookupBaseHid.Impl {
137.60 - public LookupsProxyTest(java.lang.String testName) {
137.61 - super(testName, null);
137.62 - }
137.63 -
137.64 - public static void main(java.lang.String[] args) {
137.65 - junit.textui.TestRunner.run(new NbTestSuite (LookupsProxyTest.class));
137.66 - }
137.67 -
137.68 - /** Creates an lookup for given lookup. This class just returns
137.69 - * the object passed in, but subclasses can be different.
137.70 - * @param lookup in lookup
137.71 - * @return a lookup to use
137.72 - */
137.73 - public Lookup createLookup (final Lookup lookup) {
137.74 - return org.openide.util.lookup.Lookups.proxy (
137.75 - new Lookup.Provider () {
137.76 - public Lookup getLookup () {
137.77 - return lookup;
137.78 - }
137.79 - }
137.80 - );
137.81 - }
137.82 -
137.83 - public Lookup createInstancesLookup (InstanceContent ic) {
137.84 - return new AbstractLookup (ic);
137.85 - }
137.86 -
137.87 - public void clearCaches () {
137.88 - }
137.89 -
137.90 -
137.91 -
137.92 - /** Check whether setLookups method does not fire when there is no
137.93 - * change in the lookups.
137.94 - */
137.95 - public void testProxyListener () {
137.96 - Changer ch = new Changer (Lookup.EMPTY);
137.97 -
137.98 - Lookup lookup = Lookups.proxy(ch);
137.99 - Lookup.Result res = lookup.lookup (new Lookup.Template (Object.class));
137.100 -
137.101 - LL ll = new LL ();
137.102 - res.addLookupListener (ll);
137.103 - Collection allRes = res.allInstances ();
137.104 -
137.105 - ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
137.106 - lookup.lookup (Object.class); // does the refresh
137.107 -
137.108 - assertEquals("Replacing an empty by empty does not generate an event", 0, ll.getCount());
137.109 -
137.110 - InstanceContent content = new InstanceContent ();
137.111 - AbstractLookup del = new AbstractLookup (content);
137.112 - content.add (this);
137.113 - ch.setLookup (del);
137.114 - lookup.lookup (Object.class);
137.115 -
137.116 - if (ll.getCount () != 1) {
137.117 - fail ("Changing lookups with different content generates an event");
137.118 - }
137.119 -
137.120 - ch.setLookup (del);
137.121 - lookup.lookup (Object.class);
137.122 -
137.123 - if (ll.getCount () != 0) {
137.124 - fail ("Not changing the lookups does not generate any event");
137.125 - }
137.126 - }
137.127 -
137.128 -
137.129 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
137.130 - doListeningAndQueryingByTwoListenersSetLookups(0, 1, false);
137.131 - }
137.132 - public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
137.133 - doListeningAndQueryingByTwoListenersSetLookups(1, 1, false);
137.134 - }
137.135 - public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
137.136 - doListeningAndQueryingByTwoListenersSetLookups(2, 1, false);
137.137 - }
137.138 -
137.139 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
137.140 - doListeningAndQueryingByTwoListenersSetLookups(0, 2, false);
137.141 - }
137.142 - public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
137.143 - doListeningAndQueryingByTwoListenersSetLookups(1, 2, false);
137.144 - }
137.145 - public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
137.146 - doListeningAndQueryingByTwoListenersSetLookups(2, 2, false);
137.147 - }
137.148 -
137.149 - public void testListeningAndQueryingByTwoListenersInstancesSetLookupsWithProxy() {
137.150 - doListeningAndQueryingByTwoListenersSetLookups(0, 1, true);
137.151 - }
137.152 - public void testListeningAndQueryingByTwoListenersClassesSetLookupsWithProxy() {
137.153 - doListeningAndQueryingByTwoListenersSetLookups(1, 1, true);
137.154 - }
137.155 - public void testListeningAndQueryingByTwoListenersItemsSetLookupsWithProxy() {
137.156 - doListeningAndQueryingByTwoListenersSetLookups(2, 1, true);
137.157 - }
137.158 -
137.159 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups2WithProxy() {
137.160 - doListeningAndQueryingByTwoListenersSetLookups(0, 2, true);
137.161 - }
137.162 - public void testListeningAndQueryingByTwoListenersClassesSetLookups2WithProxy() {
137.163 - doListeningAndQueryingByTwoListenersSetLookups(1, 2, true);
137.164 - }
137.165 - public void testListeningAndQueryingByTwoListenersItemsSetLookups2WithProxy() {
137.166 - doListeningAndQueryingByTwoListenersSetLookups(2, 2, true);
137.167 - }
137.168 -
137.169 - /* XXX: these are pretty slow, seems there is a performance problem 2^22
137.170 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
137.171 - doListeningAndQueryingByTwoListenersSetLookups(0, 22);
137.172 - }
137.173 - public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
137.174 - doListeningAndQueryingByTwoListenersSetLookups(1, 22);
137.175 - }
137.176 - public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
137.177 - doListeningAndQueryingByTwoListenersSetLookups(2, 22);
137.178 - }
137.179 - */
137.180 -
137.181 - private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth, boolean cacheOnTop) {
137.182 - Changer orig = new Changer(Lookup.EMPTY);
137.183 - Lookup on = Lookups.proxy(orig);
137.184 - Lookup first = on;
137.185 -
137.186 - while (--depth > 0) {
137.187 - Changer next = new Changer(on);
137.188 - on = Lookups.proxy(next);
137.189 - }
137.190 -
137.191 -
137.192 - final Lookup lookup = cacheOnTop ? new ProxyLookup(new Lookup[] { on }) : on;
137.193 -
137.194 - class L implements LookupListener {
137.195 - Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
137.196 - Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
137.197 - Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
137.198 -
137.199 - {
137.200 - integer.addLookupListener(this);
137.201 - number.addLookupListener(this);
137.202 - serial.addLookupListener(this);
137.203 - }
137.204 -
137.205 - int round;
137.206 -
137.207 - public void resultChanged(LookupEvent ev) {
137.208 - Collection c1 = get(type, integer);
137.209 - Collection c2 = get(type, number);
137.210 - Collection c3 = get(type, serial);
137.211 -
137.212 - assertEquals("round " + round + " c1 vs. c2", c1, c2);
137.213 - assertEquals("round " + round + " c1 vs. c3", c1, c3);
137.214 - assertEquals("round " + round + " c2 vs. c3", c2, c3);
137.215 -
137.216 - round++;
137.217 - }
137.218 -
137.219 - private Collection get(int type, Lookup.Result res) {
137.220 - Collection c;
137.221 - switch(type) {
137.222 - case 0: c = res.allInstances(); break;
137.223 - case 1: c = res.allClasses(); break;
137.224 - case 2: c = res.allItems(); break;
137.225 - default: c = null; fail("Type: " + type); break;
137.226 - }
137.227 -
137.228 - assertNotNull(c);
137.229 - return new ArrayList(c);
137.230 - }
137.231 - }
137.232 -
137.233 - L listener = new L();
137.234 - listener.resultChanged(null);
137.235 - ArrayList arr = new ArrayList();
137.236 - for(int i = 0; i < 100; i++) {
137.237 - arr.add(new Integer(i));
137.238 -
137.239 - orig.lookup = Lookups.fixed(arr.toArray());
137.240 - // do the refresh
137.241 - first.lookup((Class)null);
137.242 - }
137.243 -
137.244 - assertEquals("3x100+1 checks", 301, listener.round);
137.245 - }
137.246 -
137.247 -
137.248 - public void testRefreshWithoutAllInstances103300 () {
137.249 - Changer ch = new Changer (Lookup.EMPTY);
137.250 -
137.251 - Lookup lookup = Lookups.proxy(ch);
137.252 -
137.253 - ch.setLookup (new AbstractLookup (new InstanceContent ())); // another empty lookup
137.254 - assertNull("Nothing there", lookup.lookup (Object.class)); // does the refresh
137.255 -
137.256 - InstanceContent content = new InstanceContent ();
137.257 - AbstractLookup del = new AbstractLookup (content);
137.258 - content.add (this);
137.259 - ch.setLookup (del);
137.260 - assertEquals("Can see me", this, lookup.lookup (Object.class));
137.261 -
137.262 - ch.setLookup (del);
137.263 - assertEquals("Still can see me", this, lookup.lookup (Object.class));
137.264 -
137.265 - assertEquals("I am visible", this, lookup.lookup(LookupsProxyTest.class));
137.266 - }
137.267 -
137.268 -
137.269 - private static final class Changer implements Lookup.Provider {
137.270 - private Lookup lookup;
137.271 -
137.272 - public Changer (Lookup lookup) {
137.273 - setLookup (lookup);
137.274 - }
137.275 -
137.276 - public void setLookup (Lookup lookup) {
137.277 - this.lookup = lookup;
137.278 - }
137.279 -
137.280 - public Lookup getLookup() {
137.281 - return lookup;
137.282 - }
137.283 - }
137.284 -
137.285 -}
138.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTest.java Thu Dec 10 19:23:25 2009 -0500
138.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
138.3 @@ -1,535 +0,0 @@
138.4 -/*
138.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
138.6 - *
138.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
138.8 - *
138.9 - * The contents of this file are subject to the terms of either the GNU
138.10 - * General Public License Version 2 only ("GPL") or the Common
138.11 - * Development and Distribution License("CDDL") (collectively, the
138.12 - * "License"). You may not use this file except in compliance with the
138.13 - * License. You can obtain a copy of the License at
138.14 - * http://www.netbeans.org/cddl-gplv2.html
138.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
138.16 - * specific language governing permissions and limitations under the
138.17 - * License. When distributing the software, include this License Header
138.18 - * Notice in each file and include the License file at
138.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
138.20 - * particular file as subject to the "Classpath" exception as provided
138.21 - * by Sun in the GPL Version 2 section of the License file that
138.22 - * accompanied this code. If applicable, add the following below the
138.23 - * License Header, with the fields enclosed by brackets [] replaced by
138.24 - * your own identifying information:
138.25 - * "Portions Copyrighted [year] [name of copyright owner]"
138.26 - *
138.27 - * Contributor(s):
138.28 - *
138.29 - * The Original Software is NetBeans. The Initial Developer of the Original
138.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
138.31 - * Microsystems, Inc. All Rights Reserved.
138.32 - *
138.33 - * If you wish your version of this file to be governed by only the CDDL
138.34 - * or only the GPL Version 2, indicate your decision by adding
138.35 - * "[Contributor] elects to include this software in this distribution
138.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
138.37 - * single choice of license, a recipient has the option to distribute
138.38 - * your version of this file under either the CDDL, the GPL Version 2 or
138.39 - * to extend the choice of license to its licensees as provided above.
138.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
138.41 - * Version 2 license, then the option applies only if the new code is
138.42 - * made subject to such option by the copyright holder.
138.43 - */
138.44 -
138.45 -package org.openide.util.lookup;
138.46 -
138.47 -import java.io.ByteArrayInputStream;
138.48 -import java.io.File;
138.49 -import java.io.FileOutputStream;
138.50 -import java.io.IOException;
138.51 -import java.io.InputStream;
138.52 -import java.io.InputStreamReader;
138.53 -import java.lang.ref.Reference;
138.54 -import java.lang.ref.WeakReference;
138.55 -import java.net.URL;
138.56 -import java.net.URLClassLoader;
138.57 -import java.net.URLConnection;
138.58 -import java.net.URLStreamHandler;
138.59 -import java.util.ArrayList;
138.60 -import java.util.Collection;
138.61 -import java.util.Collections;
138.62 -import java.util.Comparator;
138.63 -import java.util.Enumeration;
138.64 -import java.util.HashSet;
138.65 -import java.util.Iterator;
138.66 -import java.util.List;
138.67 -import java.util.Map;
138.68 -import java.util.Set;
138.69 -import java.util.TreeSet;
138.70 -import java.util.WeakHashMap;
138.71 -import java.util.concurrent.atomic.AtomicBoolean;
138.72 -import java.util.jar.JarEntry;
138.73 -import java.util.jar.JarOutputStream;
138.74 -import java.util.logging.Level;
138.75 -import java.util.logging.Logger;
138.76 -import java.util.regex.Matcher;
138.77 -import java.util.regex.Pattern;
138.78 -import org.bar.Comparator2;
138.79 -import org.netbeans.junit.MockServices;
138.80 -import org.netbeans.junit.NbTestCase;
138.81 -import org.openide.util.Enumerations;
138.82 -import org.openide.util.Exceptions;
138.83 -import org.openide.util.Lookup;
138.84 -import org.openide.util.LookupEvent;
138.85 -import org.openide.util.LookupListener;
138.86 -import org.openide.util.test.MockLookup;
138.87 -
138.88 -/** Test finding services from manifest.
138.89 - * @author Jesse Glick
138.90 - */
138.91 -public class MetaInfServicesLookupTest extends NbTestCase {
138.92 - private Logger LOG;
138.93 - private Map<ClassLoader,Lookup> lookups = new WeakHashMap<ClassLoader,Lookup>();
138.94 -
138.95 - public MetaInfServicesLookupTest(String name) {
138.96 - super(name);
138.97 - LOG = Logger.getLogger("Test." + name);
138.98 - }
138.99 -
138.100 - protected String prefix() {
138.101 - return "META-INF/services/";
138.102 - }
138.103 -
138.104 - protected Lookup createLookup(ClassLoader c) {
138.105 - return Lookups.metaInfServices(c);
138.106 - }
138.107 -
138.108 - @Override
138.109 - protected Level logLevel() {
138.110 - return Level.INFO;
138.111 - }
138.112 -
138.113 - private Lookup getTestedLookup(ClassLoader c) {
138.114 - MockServices.setServices();
138.115 - Lookup l = lookups.get(c);
138.116 - if (l == null) {
138.117 - l = createLookup(c);
138.118 - lookups.put(c, l);
138.119 - }
138.120 - return l;
138.121 - }
138.122 -
138.123 - private URL findJar(String n) throws IOException {
138.124 - LOG.info("Looking for " + n);
138.125 - File jarDir = new File(getWorkDir(), "jars");
138.126 - jarDir.mkdirs();
138.127 - File jar = new File(jarDir, n);
138.128 - if (jar.exists()) {
138.129 - return jar.toURI().toURL();
138.130 - }
138.131 -
138.132 - LOG.info("generating " + jar);
138.133 -
138.134 - URL data = MetaInfServicesLookupTest.class.getResource(n.replaceAll("\\.jar", "\\.txt"));
138.135 - assertNotNull("Data found", data);
138.136 - StringBuffer sb = new StringBuffer();
138.137 - InputStreamReader r = new InputStreamReader(data.openStream());
138.138 - for(;;) {
138.139 - int ch = r.read();
138.140 - if (ch == -1) {
138.141 - break;
138.142 - }
138.143 - sb.append((char)ch);
138.144 - }
138.145 -
138.146 - JarOutputStream os = new JarOutputStream(new FileOutputStream(jar));
138.147 -
138.148 - Pattern p = Pattern.compile(":([^:]+):([^:]*)", Pattern.MULTILINE | Pattern.DOTALL);
138.149 - Matcher m = p.matcher(sb);
138.150 - Pattern foobar = Pattern.compile("^(org\\.(foo|bar)\\..*)$", Pattern.MULTILINE);
138.151 - Set<String> names = new TreeSet<String>();
138.152 - while (m.find()) {
138.153 - assert m.groupCount() == 2;
138.154 - String entryName = prefix() + m.group(1);
138.155 - LOG.info("putting there entry: " + entryName);
138.156 - os.putNextEntry(new JarEntry(entryName));
138.157 - os.write(m.group(2).getBytes());
138.158 - os.closeEntry();
138.159 -
138.160 - Matcher fb = foobar.matcher(m.group(2));
138.161 - while (fb.find()) {
138.162 - String clazz = fb.group(1).replace('.', '/') + ".class";
138.163 - LOG.info("will copy " + clazz);
138.164 - names.add(clazz);
138.165 - }
138.166 - }
138.167 -
138.168 - for (String copy : names) {
138.169 - os.putNextEntry(new JarEntry(copy));
138.170 - LOG.info("copying " + copy);
138.171 - InputStream from = MetaInfServicesLookupTest.class.getResourceAsStream("/" + copy);
138.172 - assertNotNull(copy, from);
138.173 - for (;;) {
138.174 - int ch = from.read();
138.175 - if (ch == -1) {
138.176 - break;
138.177 - }
138.178 - os.write(ch);
138.179 - }
138.180 - from.close();
138.181 - os.closeEntry();
138.182 - }
138.183 - os.close();
138.184 - LOG.info("done " + jar);
138.185 - return jar.toURI().toURL();
138.186 - }
138.187 -
138.188 - ClassLoader c1, c2, c2a, c3, c4;
138.189 -
138.190 - @Override
138.191 - protected void setUp() throws Exception {
138.192 - clearWorkDir();
138.193 - ClassLoader app = getClass().getClassLoader().getParent();
138.194 - ClassLoader c0 = app;
138.195 -
138.196 - c1 = new URLClassLoader(new URL[] {
138.197 - findJar("services-jar-1.jar"),
138.198 - }, c0);
138.199 - c2 = new URLClassLoader(new URL[] {
138.200 - findJar("services-jar-2.jar"),
138.201 - }, c1);
138.202 - c2a = new URLClassLoader(new URL[] {
138.203 - findJar("services-jar-2.jar"),
138.204 - }, c1);
138.205 - c3 = new URLClassLoader(new URL[] { findJar("services-jar-2.jar") },
138.206 - c0
138.207 - );
138.208 - c4 = new URLClassLoader(new URL[] {
138.209 - findJar("services-jar-1.jar"),
138.210 - findJar("services-jar-2.jar"),
138.211 - }, c0);
138.212 - }
138.213 -
138.214 - @Override
138.215 - protected void tearDown() throws Exception {
138.216 - Set<Reference<Lookup>> weak = new HashSet<Reference<Lookup>>();
138.217 - for (Lookup l : lookups.values()) {
138.218 - weak.add(new WeakReference<Lookup>(l));
138.219 - }
138.220 -
138.221 - lookups = null;
138.222 -
138.223 - for(Reference<Lookup> ref : weak) {
138.224 - assertGC("Lookup can disappear", ref);
138.225 - }
138.226 - }
138.227 -
138.228 - public void testBasicUsage() throws Exception {
138.229 - Lookup l = getTestedLookup(c2);
138.230 - Class<?> xface = c1.loadClass("org.foo.Interface");
138.231 - List<?> results = new ArrayList<Object>(l.lookupAll(xface));
138.232 - assertEquals("Two items in result: " + results, 2, results.size());
138.233 - // Note that they have to be in order:
138.234 - assertEquals("org.foo.impl.Implementation1", results.get(0).getClass().getName());
138.235 - assertEquals("org.bar.Implementation2", results.get(1).getClass().getName());
138.236 - // Make sure it does not gratuitously replace items:
138.237 - List<?> results2 = new ArrayList<Object>(l.lookupAll(xface));
138.238 - assertEquals(results, results2);
138.239 - }
138.240 -
138.241 - public void testLoaderSkew() throws Exception {
138.242 - Class<?> xface1 = c1.loadClass("org.foo.Interface");
138.243 - Lookup l3 = getTestedLookup(c3);
138.244 - // If we cannot load Interface, there should be no impls of course... quietly!
138.245 - assertEquals(Collections.emptyList(),
138.246 - new ArrayList<Object>(l3.lookupAll(xface1)));
138.247 - Lookup l4 = getTestedLookup(c4);
138.248 - // If we can load Interface but it is the wrong one, ignore it.
138.249 - assertEquals(Collections.emptyList(),
138.250 - new ArrayList<Object>(l4.lookupAll(xface1)));
138.251 - // Make sure l4 is really OK - it can load from its own JARs.
138.252 - Class<?> xface4 = c4.loadClass("org.foo.Interface");
138.253 - assertEquals(2, l4.lookupAll(xface4).size());
138.254 - }
138.255 -
138.256 - public void testStability() throws Exception {
138.257 - Lookup l = getTestedLookup(c2);
138.258 - Class<?> xface = c1.loadClass("org.foo.Interface");
138.259 - Object first = l.lookup(xface);
138.260 - assertEquals(first, l.lookupAll(xface).iterator().next());
138.261 - l = getTestedLookup(c2a);
138.262 - Object second = l.lookup(xface);
138.263 - assertEquals(first, second);
138.264 - }
138.265 -
138.266 - public void testMaskingOfResources() throws Exception {
138.267 - Lookup l1 = getTestedLookup(c1);
138.268 - Lookup l2 = getTestedLookup(c2);
138.269 - Lookup l4 = getTestedLookup(c4);
138.270 -
138.271 - assertNotNull("services1.jar defines a class that implements runnable", l1.lookup(Runnable.class));
138.272 - assertNull("services2.jar does not defines a class that implements runnable", l2.lookup(Runnable.class));
138.273 - assertNull("services1.jar defines Runnable, but services2.jar masks it out", l4.lookup(Runnable.class));
138.274 - }
138.275 -
138.276 - public void testOrdering() throws Exception {
138.277 - Lookup l = getTestedLookup(c1);
138.278 - Class<?> xface = c1.loadClass("java.util.Comparator");
138.279 - List<?> results = new ArrayList<Object>(l.lookupAll(xface));
138.280 - assertEquals(1, results.size());
138.281 -
138.282 - l = getTestedLookup(c2);
138.283 - xface = c2.loadClass("java.util.Comparator");
138.284 - results = new ArrayList<Object>(l.lookupAll(xface));
138.285 - assertEquals(2, results.size());
138.286 - // Test order:
138.287 - assertEquals("org.bar.Comparator2", results.get(0).getClass().getName());
138.288 - assertEquals("org.foo.impl.Comparator1", results.get(1).getClass().getName());
138.289 -
138.290 - // test that items without position are always at the end
138.291 - l = getTestedLookup(c2);
138.292 - xface = c2.loadClass("java.util.Iterator");
138.293 - results = new ArrayList<Object>(l.lookupAll(xface));
138.294 - assertEquals(2, results.size());
138.295 - // Test order:
138.296 - assertEquals("org.bar.Iterator2", results.get(0).getClass().getName());
138.297 - assertEquals("org.foo.impl.Iterator1", results.get(1).getClass().getName());
138.298 - }
138.299 -
138.300 - public void testNoCallToGetResourceForObjectIssue65124() throws Exception {
138.301 - class Loader extends ClassLoader {
138.302 - private int counter;
138.303 -
138.304 - @Override
138.305 - protected URL findResource(String name) {
138.306 - if (name.equals(prefix() + "java.lang.Object")) {
138.307 - counter++;
138.308 - }
138.309 -
138.310 - URL retValue;
138.311 -
138.312 - retValue = super.findResource(name);
138.313 - return retValue;
138.314 - }
138.315 -
138.316 - @Override
138.317 - protected Enumeration<URL> findResources(String name) throws IOException {
138.318 - if (name.equals(prefix() + "java.lang.Object")) {
138.319 - counter++;
138.320 - }
138.321 - return super.findResources(name);
138.322 - }
138.323 - }
138.324 - Loader loader = new Loader();
138.325 - Lookup l = getTestedLookup(loader);
138.326 -
138.327 - Object no = l.lookup(String.class);
138.328 - assertNull("Not found of course", no);
138.329 - assertEquals("No lookup of Object", 0, loader.counter);
138.330 - }
138.331 -
138.332 - public void testCanGarbageCollectClasses() throws Exception {
138.333 - class Loader extends ClassLoader {
138.334 - public Loader() {
138.335 - super(Loader.class.getClassLoader().getParent());
138.336 - }
138.337 -
138.338 - @Override
138.339 - protected URL findResource(String name) {
138.340 - if (name.equals(prefix() + "java.lang.Runnable")) {
138.341 - return Loader.class.getResource("MetaInfServicesLookupTestRunnable.txt");
138.342 - }
138.343 -
138.344 - URL retValue;
138.345 -
138.346 - retValue = super.findResource(name);
138.347 - return retValue;
138.348 - }
138.349 -
138.350 - @Override
138.351 - protected Class<?> findClass(String name) throws ClassNotFoundException {
138.352 - if (name.equals("org.openide.util.lookup.MetaInfServicesLookupTestRunnable")) {
138.353 - try {
138.354 - InputStream is = getClass().getResourceAsStream("MetaInfServicesLookupTestRunnable.class");
138.355 - byte[] arr = new byte[is.available()];
138.356 - int read = is.read(arr);
138.357 - assertEquals("Fully read", arr.length, read);
138.358 - return defineClass(name, arr, 0, arr.length);
138.359 - } catch (IOException ex) {
138.360 - throw new ClassNotFoundException("Cannot load", ex);
138.361 - }
138.362 - }
138.363 - throw new ClassNotFoundException();
138.364 - }
138.365 -
138.366 -
138.367 -
138.368 - @Override
138.369 - protected Enumeration<URL> findResources(String name) throws IOException {
138.370 - if (name.equals(prefix() + "java.lang.Runnable")) {
138.371 - return Collections.enumeration(Collections.singleton(findResource(name)));
138.372 - }
138.373 - return super.findResources(name);
138.374 - }
138.375 - }
138.376 - Loader loader = new Loader();
138.377 - Lookup l = getTestedLookup(loader);
138.378 -
138.379 -
138.380 - Object no = l.lookup(Runnable.class);
138.381 - assertNotNull("Found of course", no);
138.382 - assertEquals("The right name", "MetaInfServicesLookupTestRunnable", no.getClass().getSimpleName());
138.383 - if (no.getClass().getClassLoader() != loader) {
138.384 - fail("Wrong classloader: " + no.getClass().getClassLoader());
138.385 - }
138.386 -
138.387 - WeakReference<Object> ref = new WeakReference<Object>(no.getClass());
138.388 - loader = null;
138.389 - no = null;
138.390 - l = null;
138.391 - lookups.clear();
138.392 - MockLookup.setInstances();
138.393 - Thread.currentThread().setContextClassLoader(null);
138.394 - assertGC("Class can be garbage collected", ref);
138.395 - }
138.396 -
138.397 - public void testSuperTypes() throws Exception {
138.398 - doTestSuperTypes(createLookup(c2));
138.399 - doTestSuperTypes(new ProxyLookup(createLookup(c2)));
138.400 - }
138.401 - private void doTestSuperTypes(Lookup l) throws Exception {
138.402 - final Class<?> xface = c1.loadClass("org.foo.Interface");
138.403 - final Lookup.Result<Object> res = l.lookupResult(Object.class);
138.404 - assertEquals("Nothing yet", 0, res.allInstances().size());
138.405 - final AtomicBoolean event = new AtomicBoolean();
138.406 - final Thread here = Thread.currentThread();
138.407 - res.addLookupListener(new LookupListener() {
138.408 - public void resultChanged(LookupEvent ev) {
138.409 - if (Thread.currentThread() == here) {
138.410 - event.set(true);
138.411 - }
138.412 - }
138.413 - });
138.414 - assertNotNull("Interface found", l.lookup(xface));
138.415 - assertFalse(event.get());
138.416 - MetaInfServicesLookup.RP.post(new Runnable() {public void run() {}}).waitFinished();
138.417 - assertEquals("Now two", 2, res.allInstances().size());
138.418 - }
138.419 -
138.420 - public void testWrongOrderAsInIssue100320() throws Exception {
138.421 - ClassLoader app = getClass().getClassLoader().getParent();
138.422 - ClassLoader c0 = app;
138.423 - ClassLoader ctmp = new URLClassLoader(new URL[] {
138.424 - findJar("problem100320.jar"),
138.425 - }, c0);
138.426 - Lookup lookup = Lookups.metaInfServices(ctmp, prefix());
138.427 -
138.428 - Collection<?> colAWT = lookup.lookupAll(IOException.class);
138.429 - assertEquals("There is enough objects to switch to InheritanceTree", 12, colAWT.size());
138.430 -
138.431 -
138.432 - List<?> col1 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
138.433 - assertEquals("Two", 2, col1.size());
138.434 - Collection<?> col2 = lookup.lookupAll(ctmp.loadClass(Comparator2.class.getName()));
138.435 - assertEquals("One", 1, col2.size());
138.436 - List<?> col3 = new ArrayList<Object>(lookup.lookupAll(Comparator.class));
138.437 - assertEquals("Two2", 2, col3.size());
138.438 -
138.439 - Iterator<?> it1 = col1.iterator();
138.440 - Iterator<?> it3 = col3.iterator();
138.441 - if (
138.442 - it1.next() != it3.next() ||
138.443 - it1.next() != it3.next()
138.444 - ) {
138.445 - fail("Collections are different:\nFirst: " + col1 + "\nLast: " + col3);
138.446 - }
138.447 - }
138.448 -
138.449 - public void testContentionWhenLoadingMetainfServices() throws Exception {
138.450 - class My extends ClassLoader implements Runnable {
138.451 - Lookup query;
138.452 - Integer value;
138.453 -
138.454 - public void run() {
138.455 - value = query.lookup(Integer.class);
138.456 - }
138.457 -
138.458 -
138.459 - @Override
138.460 - protected URL findResource(String name) {
138.461 - waitForTask(name);
138.462 - return super.findResource(name);
138.463 - }
138.464 -
138.465 - @Override
138.466 - protected Enumeration<URL> findResources(String name) throws IOException {
138.467 - waitForTask(name);
138.468 - return super.findResources(name);
138.469 - }
138.470 -
138.471 - private synchronized void waitForTask(String name) {
138.472 - if (name.startsWith(prefix()) && Thread.currentThread().getName().contains("block")) {
138.473 - try {
138.474 - wait();
138.475 - } catch (InterruptedException ex) {
138.476 - Exceptions.printStackTrace(ex);
138.477 - }
138.478 - }
138.479 - }
138.480 - }
138.481 -
138.482 - My loader = new My();
138.483 - loader.query = createLookup(loader);
138.484 - Thread t = new Thread(loader, "block when querying");
138.485 - t.start();
138.486 - t.join(1000);
138.487 -
138.488 - // this blocks waiting for the waitForTask to finish
138.489 - // right now
138.490 - Float f = loader.query.lookup(Float.class);
138.491 - assertNull("Nothing found", f);
138.492 -
138.493 - synchronized (loader) {
138.494 - loader.notifyAll();
138.495 - }
138.496 - t.join();
138.497 -
138.498 - assertNull("Nothing found", loader.value);
138.499 - }
138.500 -
138.501 - public void testInitializerRobustness() throws Exception { // #174055
138.502 - check(Broken1.class.getName());
138.503 - check(Broken2.class.getName());
138.504 - }
138.505 - private void check(final String n) {
138.506 - assertNull(Lookups.metaInfServices(new ClassLoader() {
138.507 - protected @Override Enumeration<URL> findResources(String name) throws IOException {
138.508 - if (name.equals("META-INF/services/java.lang.Object")) {
138.509 - return Enumerations.singleton(new URL(null, "dummy:stuff", new URLStreamHandler() {
138.510 - protected URLConnection openConnection(URL u) throws IOException {
138.511 - return new URLConnection(u) {
138.512 - public void connect() throws IOException {}
138.513 - public @Override InputStream getInputStream() throws IOException {
138.514 - return new ByteArrayInputStream(n.getBytes("UTF-8"));
138.515 - }
138.516 - };
138.517 - }
138.518 - }));
138.519 - } else {
138.520 - return Enumerations.empty();
138.521 - }
138.522 - }
138.523 - }).lookup(Object.class));
138.524 - }
138.525 - public static class Broken1 {
138.526 - public Broken1() {
138.527 - throw new NullPointerException("broken1");
138.528 - }
138.529 - }
138.530 - public static class Broken2 {
138.531 - static {
138.532 - if (true) { // otherwise javac complains
138.533 - throw new NullPointerException("broken2");
138.534 - }
138.535 - }
138.536 - }
138.537 -
138.538 -}
139.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTestRunnable.java Thu Dec 10 19:23:25 2009 -0500
139.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
139.3 @@ -1,50 +0,0 @@
139.4 -/*
139.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
139.6 - *
139.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
139.8 - *
139.9 - * The contents of this file are subject to the terms of either the GNU
139.10 - * General Public License Version 2 only ("GPL") or the Common
139.11 - * Development and Distribution License("CDDL") (collectively, the
139.12 - * "License"). You may not use this file except in compliance with the
139.13 - * License. You can obtain a copy of the License at
139.14 - * http://www.netbeans.org/cddl-gplv2.html
139.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
139.16 - * specific language governing permissions and limitations under the
139.17 - * License. When distributing the software, include this License Header
139.18 - * Notice in each file and include the License file at
139.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
139.20 - * particular file as subject to the "Classpath" exception as provided
139.21 - * by Sun in the GPL Version 2 section of the License file that
139.22 - * accompanied this code. If applicable, add the following below the
139.23 - * License Header, with the fields enclosed by brackets [] replaced by
139.24 - * your own identifying information:
139.25 - * "Portions Copyrighted [year] [name of copyright owner]"
139.26 - *
139.27 - * Contributor(s):
139.28 - *
139.29 - * The Original Software is NetBeans. The Initial Developer of the Original
139.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
139.31 - * Microsystems, Inc. All Rights Reserved.
139.32 - *
139.33 - * If you wish your version of this file to be governed by only the CDDL
139.34 - * or only the GPL Version 2, indicate your decision by adding
139.35 - * "[Contributor] elects to include this software in this distribution
139.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
139.37 - * single choice of license, a recipient has the option to distribute
139.38 - * your version of this file under either the CDDL, the GPL Version 2 or
139.39 - * to extend the choice of license to its licensees as provided above.
139.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
139.41 - * Version 2 license, then the option applies only if the new code is
139.42 - * made subject to such option by the copyright holder.
139.43 - */
139.44 -
139.45 -package org.openide.util.lookup;
139.46 -
139.47 -
139.48 -/**
139.49 - */
139.50 -public final class MetaInfServicesLookupTestRunnable implements Runnable {
139.51 - public void run() {
139.52 - }
139.53 -}
140.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/MetaInfServicesLookupTestRunnable.txt Thu Dec 10 19:23:25 2009 -0500
140.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
140.3 @@ -1,1 +0,0 @@
140.4 -org.openide.util.lookup.MetaInfServicesLookupTestRunnable
141.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/NamedServicesLookupTest.java Thu Dec 10 19:23:25 2009 -0500
141.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
141.3 @@ -1,85 +0,0 @@
141.4 -/*
141.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
141.6 - *
141.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
141.8 - *
141.9 - * The contents of this file are subject to the terms of either the GNU
141.10 - * General Public License Version 2 only ("GPL") or the Common
141.11 - * Development and Distribution License("CDDL") (collectively, the
141.12 - * "License"). You may not use this file except in compliance with the
141.13 - * License. You can obtain a copy of the License at
141.14 - * http://www.netbeans.org/cddl-gplv2.html
141.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
141.16 - * specific language governing permissions and limitations under the
141.17 - * License. When distributing the software, include this License Header
141.18 - * Notice in each file and include the License file at
141.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
141.20 - * particular file as subject to the "Classpath" exception as provided
141.21 - * by Sun in the GPL Version 2 section of the License file that
141.22 - * accompanied this code. If applicable, add the following below the
141.23 - * License Header, with the fields enclosed by brackets [] replaced by
141.24 - * your own identifying information:
141.25 - * "Portions Copyrighted [year] [name of copyright owner]"
141.26 - *
141.27 - * Contributor(s):
141.28 - *
141.29 - * The Original Software is NetBeans. The Initial Developer of the Original
141.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
141.31 - * Microsystems, Inc. All Rights Reserved.
141.32 - *
141.33 - * If you wish your version of this file to be governed by only the CDDL
141.34 - * or only the GPL Version 2, indicate your decision by adding
141.35 - * "[Contributor] elects to include this software in this distribution
141.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
141.37 - * single choice of license, a recipient has the option to distribute
141.38 - * your version of this file under either the CDDL, the GPL Version 2 or
141.39 - * to extend the choice of license to its licensees as provided above.
141.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
141.41 - * Version 2 license, then the option applies only if the new code is
141.42 - * made subject to such option by the copyright holder.
141.43 - */
141.44 -
141.45 -package org.openide.util.lookup;
141.46 -
141.47 -import org.openide.util.Lookup;
141.48 -import org.openide.util.test.MockLookup;
141.49 -
141.50 -
141.51 -/** Test finding services from manifest.
141.52 - * @author Jaroslav Tulach
141.53 - */
141.54 -public class NamedServicesLookupTest extends MetaInfServicesLookupTest {
141.55 - static {
141.56 - MockLookup.init();
141.57 - }
141.58 - public NamedServicesLookupTest(String name) {
141.59 - super(name);
141.60 - }
141.61 -
141.62 - @Override
141.63 - protected String prefix() {
141.64 - return "META-INF/namedservices/sub/path/";
141.65 - }
141.66 -
141.67 - @Override
141.68 - protected Lookup createLookup(ClassLoader c) {
141.69 - MockLookup.setInstances(c);
141.70 - Thread.currentThread().setContextClassLoader(c);
141.71 - Lookup l = Lookups.forPath("sub/path");
141.72 - return l;
141.73 - }
141.74 -
141.75 - //
141.76 - // this is not much inheriting test, as we mask most of the tested methods
141.77 - // anyway, but the infrastructure to generate the JAR files is useful
141.78 - //
141.79 -
141.80 - public @Override void testLoaderSkew() {}
141.81 - public @Override void testStability() throws Exception {}
141.82 - public @Override void testMaskingOfResources() throws Exception {}
141.83 - public @Override void testOrdering() throws Exception {}
141.84 - public @Override void testNoCallToGetResourceForObjectIssue65124() throws Exception {}
141.85 - public @Override void testSuperTypes() throws Exception {}
141.86 - public @Override void testWrongOrderAsInIssue100320() throws Exception {}
141.87 -
141.88 -}
142.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/PathInLookupTest.java Thu Dec 10 19:23:25 2009 -0500
142.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
142.3 @@ -1,112 +0,0 @@
142.4 -/*
142.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
142.6 - *
142.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
142.8 - *
142.9 - * The contents of this file are subject to the terms of either the GNU
142.10 - * General Public License Version 2 only ("GPL") or the Common
142.11 - * Development and Distribution License("CDDL") (collectively, the
142.12 - * "License"). You may not use this file except in compliance with the
142.13 - * License. You can obtain a copy of the License at
142.14 - * http://www.netbeans.org/cddl-gplv2.html
142.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
142.16 - * specific language governing permissions and limitations under the
142.17 - * License. When distributing the software, include this License Header
142.18 - * Notice in each file and include the License file at
142.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
142.20 - * particular file as subject to the "Classpath" exception as provided
142.21 - * by Sun in the GPL Version 2 section of the License file that
142.22 - * accompanied this code. If applicable, add the following below the
142.23 - * License Header, with the fields enclosed by brackets [] replaced by
142.24 - * your own identifying information:
142.25 - * "Portions Copyrighted [year] [name of copyright owner]"
142.26 - *
142.27 - * Contributor(s):
142.28 - *
142.29 - * The Original Software is NetBeans. The Initial Developer of the Original
142.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
142.31 - * Microsystems, Inc. All Rights Reserved.
142.32 - *
142.33 - * If you wish your version of this file to be governed by only the CDDL
142.34 - * or only the GPL Version 2, indicate your decision by adding
142.35 - * "[Contributor] elects to include this software in this distribution
142.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
142.37 - * single choice of license, a recipient has the option to distribute
142.38 - * your version of this file under either the CDDL, the GPL Version 2 or
142.39 - * to extend the choice of license to its licensees as provided above.
142.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
142.41 - * Version 2 license, then the option applies only if the new code is
142.42 - * made subject to such option by the copyright holder.
142.43 - */
142.44 -
142.45 -package org.openide.util.lookup;
142.46 -
142.47 -import java.util.logging.Level;
142.48 -import org.netbeans.junit.MockServices;
142.49 -import org.netbeans.junit.NbTestCase;
142.50 -import org.netbeans.modules.openide.util.NamedServicesProvider;
142.51 -import org.openide.util.Lookup;
142.52 -
142.53 -/**
142.54 - * @author Jaroslav Tulach
142.55 - */
142.56 -public class PathInLookupTest extends NbTestCase {
142.57 - static {
142.58 - System.setProperty("org.openide.util.Lookup.paths", "MyServices:YourServices");
142.59 - MockServices.setServices(P.class);
142.60 - Lookup.getDefault();
142.61 - }
142.62 -
142.63 - public PathInLookupTest(String name) {
142.64 - super(name);
142.65 - }
142.66 -
142.67 - @Override
142.68 - protected Level logLevel() {
142.69 - return Level.FINE;
142.70 - }
142.71 -
142.72 - public void testInterfaceFoundInMyServices() throws Exception {
142.73 - assertNull("not found", Lookup.getDefault().lookup(Shared.class));
142.74 - Shared v = new Shared();
142.75 - P.ic1.add(v);
142.76 - assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
142.77 - P.ic1.remove(v);
142.78 - assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
142.79 - }
142.80 - public void testInterfaceFoundInMyServices2() throws Exception {
142.81 - assertNull("not found", Lookup.getDefault().lookup(Shared.class));
142.82 - Shared v = new Shared();
142.83 - P.ic2.add(v);
142.84 - assertNotNull("found", Lookup.getDefault().lookup(Shared.class));
142.85 - P.ic2.remove(v);
142.86 - assertNull("not found again", Lookup.getDefault().lookup(Shared.class));
142.87 - }
142.88 -
142.89 - static final class Shared extends Object {}
142.90 -
142.91 - public static final class P extends NamedServicesProvider {
142.92 - static InstanceContent ic1 = new InstanceContent();
142.93 - static InstanceContent ic2 = new InstanceContent();
142.94 - static AbstractLookup[] arr = {
142.95 - new AbstractLookup(ic1), new AbstractLookup(ic2)
142.96 - };
142.97 -
142.98 -
142.99 - @Override
142.100 - public Lookup create(String path) {
142.101 - int indx = -1;
142.102 - if (path.equals("MyServices/")) {
142.103 - indx = 0;
142.104 - }
142.105 - if (path.equals("YourServices/")) {
142.106 - indx = 1;
142.107 - }
142.108 - if (indx == -1) {
142.109 - fail("Unexpected lookup query: " + path);
142.110 - }
142.111 - return arr[indx];
142.112 - }
142.113 - }
142.114 -
142.115 -}
143.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/PrefixServicesLookupTest.java Thu Dec 10 19:23:25 2009 -0500
143.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
143.3 @@ -1,63 +0,0 @@
143.4 -/*
143.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
143.6 - *
143.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
143.8 - *
143.9 - * The contents of this file are subject to the terms of either the GNU
143.10 - * General Public License Version 2 only ("GPL") or the Common
143.11 - * Development and Distribution License("CDDL") (collectively, the
143.12 - * "License"). You may not use this file except in compliance with the
143.13 - * License. You can obtain a copy of the License at
143.14 - * http://www.netbeans.org/cddl-gplv2.html
143.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
143.16 - * specific language governing permissions and limitations under the
143.17 - * License. When distributing the software, include this License Header
143.18 - * Notice in each file and include the License file at
143.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
143.20 - * particular file as subject to the "Classpath" exception as provided
143.21 - * by Sun in the GPL Version 2 section of the License file that
143.22 - * accompanied this code. If applicable, add the following below the
143.23 - * License Header, with the fields enclosed by brackets [] replaced by
143.24 - * your own identifying information:
143.25 - * "Portions Copyrighted [year] [name of copyright owner]"
143.26 - *
143.27 - * Contributor(s):
143.28 - *
143.29 - * The Original Software is NetBeans. The Initial Developer of the Original
143.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
143.31 - * Microsystems, Inc. All Rights Reserved.
143.32 - *
143.33 - * If you wish your version of this file to be governed by only the CDDL
143.34 - * or only the GPL Version 2, indicate your decision by adding
143.35 - * "[Contributor] elects to include this software in this distribution
143.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
143.37 - * single choice of license, a recipient has the option to distribute
143.38 - * your version of this file under either the CDDL, the GPL Version 2 or
143.39 - * to extend the choice of license to its licensees as provided above.
143.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
143.41 - * Version 2 license, then the option applies only if the new code is
143.42 - * made subject to such option by the copyright holder.
143.43 - */
143.44 -
143.45 -package org.openide.util.lookup;
143.46 -
143.47 -import org.openide.util.Lookup;
143.48 -
143.49 -
143.50 -/** Test finding services from manifest.
143.51 - * @author Jaroslav Tulach
143.52 - */
143.53 -public class PrefixServicesLookupTest extends MetaInfServicesLookupTest {
143.54 - public PrefixServicesLookupTest(String name) {
143.55 - super(name);
143.56 - }
143.57 -
143.58 - protected String prefix() {
143.59 - return "META-INF/netbeans/prefix/services/test/";
143.60 - }
143.61 -
143.62 - protected Lookup createLookup(ClassLoader c) {
143.63 - return Lookups.metaInfServices(c, prefix());
143.64 - }
143.65 -
143.66 -}
144.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookup173975Test.java Thu Dec 10 19:23:25 2009 -0500
144.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
144.3 @@ -1,108 +0,0 @@
144.4 -/*
144.5 - * To change this template, choose Tools | Templates
144.6 - * and open the template in the editor.
144.7 - */
144.8 -package org.openide.util.lookup;
144.9 -
144.10 -import java.util.Collection;
144.11 -import java.util.Collections;
144.12 -import org.junit.Assert;
144.13 -import org.junit.Test;
144.14 -import org.openide.util.Lookup;
144.15 -import org.openide.util.LookupEvent;
144.16 -import org.openide.util.LookupListener;
144.17 -import org.openide.util.lookup.AbstractLookup.Storage;
144.18 -
144.19 -public class ProxyLookup173975Test {
144.20 -
144.21 - public ProxyLookup173975Test() {
144.22 - }
144.23 -
144.24 - boolean called = false;
144.25 -
144.26 - @Test
144.27 - public void testAbstractLookupWithoutAllInstances() {
144.28 - registerLookupListenerAndAddSomething(false, false, false);
144.29 - }
144.30 -
144.31 - @Test
144.32 - public void testAbstractLookupWithAllInstances() {
144.33 - registerLookupListenerAndAddSomething(false, true, false);
144.34 - }
144.35 -
144.36 - @Test
144.37 - public void testAbstractLookupInheritanceTreeWithoutAllInstances() {
144.38 - registerLookupListenerAndAddSomething(false, false, true);
144.39 - }
144.40 -
144.41 - @Test
144.42 - public void testAbstractLookupInheritanceTreeWithAllInstances() {
144.43 - registerLookupListenerAndAddSomething(false, true, true);
144.44 - }
144.45 -
144.46 - @Test
144.47 - public void testProxyLookupWithoutAllInstances() {
144.48 - registerLookupListenerAndAddSomething(true, false, false);
144.49 - }
144.50 -
144.51 - @Test
144.52 - public void testProxyLookupWithAllInstances() {
144.53 - registerLookupListenerAndAddSomething(true, true, false);
144.54 - }
144.55 -
144.56 - @Test
144.57 - public void testProxyLookupInheritanceTreeWithoutAllInstances() {
144.58 - registerLookupListenerAndAddSomething(true, false, true);
144.59 - }
144.60 -
144.61 - @Test
144.62 - public void testProxyLookupInheritanceTreeWithAllInstances() {
144.63 - registerLookupListenerAndAddSomething(true, true, true);
144.64 - }
144.65 -
144.66 - private void registerLookupListenerAndAddSomething(boolean useProxy, boolean callAllInstances, boolean inheritanceTree) {
144.67 - called = false;
144.68 - InstanceContent aInstanceContent = new InstanceContent();
144.69 - Storage<?> s = inheritanceTree ? new InheritanceTree() : new ArrayStorage();
144.70 - Lookup aLookup = new AbstractLookup(aInstanceContent, s);
144.71 - if (useProxy) {
144.72 - aLookup = new ProxyLookup(aLookup);
144.73 - }
144.74 - Lookup.Result<ObjectInLookup> result = aLookup.lookupResult(ObjectInLookup.class);
144.75 - if (callAllInstances) {
144.76 - result.allInstances(); // TO GET SUCCESS
144.77 - }
144.78 - result.addLookupListener(new LookupListener() {
144.79 -
144.80 - public void resultChanged(LookupEvent ev) {
144.81 - Lookup.Result aResult = (Lookup.Result) ev.getSource();
144.82 - Collection c = aResult.allInstances();
144.83 - if (!c.isEmpty()) {
144.84 - called = true;
144.85 - }
144.86 - }
144.87 - });
144.88 -
144.89 - aInstanceContent.set(Collections.singleton(
144.90 - new ObjectInLookup("Set Object in Lookup)")), null);
144.91 - Assert.assertTrue("Listener was notified", called);
144.92 - }
144.93 -
144.94 - public class ObjectInLookup {
144.95 -
144.96 - private final String name;
144.97 -
144.98 - public ObjectInLookup(String name) {
144.99 - this.name = name;
144.100 - }
144.101 -
144.102 - public String getName() {
144.103 - return this.name;
144.104 - }
144.105 -
144.106 - @Override
144.107 - public String toString() {
144.108 - return "objectinlookup:" + getName();
144.109 - }
144.110 - }
144.111 -}
145.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupEventIssue136866Test.java Thu Dec 10 19:23:25 2009 -0500
145.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
145.3 @@ -1,56 +0,0 @@
145.4 -package org.openide.util.lookup;
145.5 -
145.6 -import junit.framework.TestCase;
145.7 -import org.openide.util.Lookup;
145.8 -import org.openide.util.LookupEvent;
145.9 -import org.openide.util.LookupListener;
145.10 -
145.11 -/**
145.12 - * Test case which demonstrates that ProxyLookup does not fire
145.13 - * an event when it should.
145.14 - */
145.15 -public class ProxyLookupEventIssue136866Test extends TestCase {
145.16 -
145.17 - public ProxyLookupEventIssue136866Test(String testName) {
145.18 - super(testName);
145.19 - }
145.20 -
145.21 - public void testAbstractLookupFiresEventWhenContentChanged() {
145.22 - InstanceContent ic = new InstanceContent();
145.23 - AbstractLookup al = new AbstractLookup(ic);
145.24 -
145.25 - final int[] counts = {0}; // Number of items observed upon a LookupEvent
145.26 - final Lookup.Result<String> result = al.lookupResult(String.class);
145.27 -
145.28 - result.addLookupListener(new LookupListener() {
145.29 - public void resultChanged(LookupEvent ev) {
145.30 - // this gets called as expected
145.31 - assertSame(result, ev.getSource());
145.32 - counts[0] = result.allInstances().size();
145.33 - }
145.34 - });
145.35 -
145.36 - ic.add("hello1");
145.37 - assertEquals(1, counts[0]);
145.38 - }
145.39 -
145.40 - public void testProxyLookupFailsToFireEventWhenProxiedLookupChanged() {
145.41 - InstanceContent ic = new InstanceContent();
145.42 -// AbstractLookup al = new AbstractLookup(ic);
145.43 - Lookup proxy = new AbstractLookup(ic);
145.44 -
145.45 - final int[] counts = {0}; // Number of items observed upon a LookupEvent
145.46 - final Lookup.Result<String> result = proxy.lookupResult(String.class);
145.47 -
145.48 - result.addLookupListener(new LookupListener() {
145.49 - public void resultChanged(LookupEvent ev) {
145.50 - // this should be called but never is
145.51 - assertSame(result, ev.getSource());
145.52 - counts[0] = result.allInstances().size();
145.53 - }
145.54 - });
145.55 -
145.56 - ic.add("hello1");
145.57 - assertEquals(1, counts[0]);
145.58 - }
145.59 -}
146.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java Thu Dec 10 19:23:25 2009 -0500
146.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
146.3 @@ -1,655 +0,0 @@
146.4 -/*
146.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
146.6 - *
146.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
146.8 - *
146.9 - * The contents of this file are subject to the terms of either the GNU
146.10 - * General Public License Version 2 only ("GPL") or the Common
146.11 - * Development and Distribution License("CDDL") (collectively, the
146.12 - * "License"). You may not use this file except in compliance with the
146.13 - * License. You can obtain a copy of the License at
146.14 - * http://www.netbeans.org/cddl-gplv2.html
146.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
146.16 - * specific language governing permissions and limitations under the
146.17 - * License. When distributing the software, include this License Header
146.18 - * Notice in each file and include the License file at
146.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
146.20 - * particular file as subject to the "Classpath" exception as provided
146.21 - * by Sun in the GPL Version 2 section of the License file that
146.22 - * accompanied this code. If applicable, add the following below the
146.23 - * License Header, with the fields enclosed by brackets [] replaced by
146.24 - * your own identifying information:
146.25 - * "Portions Copyrighted [year] [name of copyright owner]"
146.26 - *
146.27 - * Contributor(s):
146.28 - *
146.29 - * The Original Software is NetBeans. The Initial Developer of the Original
146.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
146.31 - * Microsystems, Inc. All Rights Reserved.
146.32 - *
146.33 - * If you wish your version of this file to be governed by only the CDDL
146.34 - * or only the GPL Version 2, indicate your decision by adding
146.35 - * "[Contributor] elects to include this software in this distribution
146.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
146.37 - * single choice of license, a recipient has the option to distribute
146.38 - * your version of this file under either the CDDL, the GPL Version 2 or
146.39 - * to extend the choice of license to its licensees as provided above.
146.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
146.41 - * Version 2 license, then the option applies only if the new code is
146.42 - * made subject to such option by the copyright holder.
146.43 - */
146.44 -
146.45 -package org.openide.util.lookup;
146.46 -
146.47 -import java.io.Serializable;
146.48 -
146.49 -import java.lang.ref.Reference;
146.50 -import java.lang.ref.WeakReference;
146.51 -import java.util.*;
146.52 -import java.util.concurrent.Executor;
146.53 -import junit.framework.*;
146.54 -import org.netbeans.junit.*;
146.55 -import org.netbeans.modules.openide.util.ActiveQueue;
146.56 -import org.openide.util.Lookup;
146.57 -import org.openide.util.Lookup.Result;
146.58 -import org.openide.util.LookupEvent;
146.59 -import org.openide.util.LookupListener;
146.60 -
146.61 -/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
146.62 - */
146.63 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
146.64 -public class ProxyLookupTest extends AbstractLookupBaseHid
146.65 -implements AbstractLookupBaseHid.Impl {
146.66 - public ProxyLookupTest(java.lang.String testName) {
146.67 - super(testName, null);
146.68 - }
146.69 -
146.70 - public static Test suite() {
146.71 - return new NbTestSuite (ProxyLookupTest.class);
146.72 -// return new ProxyLookupTest("testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679");
146.73 - }
146.74 -
146.75 - /** Creates an lookup for given lookup. This class just returns
146.76 - * the object passed in, but subclasses can be different.
146.77 - * @param lookup in lookup
146.78 - * @return a lookup to use
146.79 - */
146.80 - public Lookup createLookup (Lookup lookup) {
146.81 - return new ProxyLookup (new Lookup[] { lookup });
146.82 - }
146.83 -
146.84 - public Lookup createInstancesLookup (InstanceContent ic) {
146.85 - return new AbstractLookup (ic);
146.86 - }
146.87 -
146.88 -
146.89 - public void clearCaches () {
146.90 - }
146.91 -
146.92 -
146.93 - /** Check whether setLookups method does not fire when there is no
146.94 - * change in the lookups.
146.95 - */
146.96 - public void testProxyListener () {
146.97 - ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
146.98 -
146.99 - final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
146.100 - final Object[] IGNORE = {
146.101 - ProxyLookup.ImmutableInternalData.EMPTY,
146.102 - ProxyLookup.ImmutableInternalData.EMPTY_ARR,
146.103 - ActiveQueue.queue(),
146.104 - Collections.emptyMap(),
146.105 - Collections.emptyList(),
146.106 - Collections.emptySet()
146.107 - };
146.108 -
146.109 - assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
146.110 -
146.111 - Lookup.Result<Object> res = lookup.lookup (template);
146.112 -
146.113 - assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
146.114 -
146.115 - LL ll = new LL ();
146.116 - res.addLookupListener (ll);
146.117 - Collection allRes = res.allInstances ();
146.118 -
146.119 - lookup.setLookups (new Lookup[0]);
146.120 -
146.121 - if (ll.getCount () != 0) {
146.122 - fail ("Calling setLookups (emptyarray) fired a change");
146.123 - }
146.124 -
146.125 - InstanceContent t = new InstanceContent();
146.126 - Lookup del = new AbstractLookup (t);
146.127 - t.add("Ahoj");
146.128 - lookup.setLookups (new Lookup[] { del });
146.129 -
146.130 - if (ll.getCount () != 1) {
146.131 - fail ("Changing lookups did not generate an event");
146.132 - }
146.133 -
146.134 - lookup.setLookups (new Lookup[] { del });
146.135 -
146.136 - if (ll.getCount () != 0) {
146.137 - fail ("Calling setLookups (thesamearray) fired a change");
146.138 - }
146.139 - }
146.140 -
146.141 - public void testNoListenersProxyListener () {
146.142 - ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
146.143 - class E implements Executor {
146.144 - Runnable r;
146.145 - public void execute(Runnable command) {
146.146 - assertNull("NO previous", r);
146.147 - r = command;
146.148 - }
146.149 - public void perform() {
146.150 - assertNotNull("We shall have a runnable", r);
146.151 - r.run();
146.152 - r = null;
146.153 - }
146.154 - }
146.155 - E executor = new E();
146.156 -
146.157 -
146.158 - final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
146.159 - final Object[] IGNORE = {
146.160 - ProxyLookup.ImmutableInternalData.EMPTY,
146.161 - ProxyLookup.ImmutableInternalData.EMPTY_ARR,
146.162 - ActiveQueue.queue(),
146.163 - Collections.emptyMap(),
146.164 - Collections.emptyList(),
146.165 - Collections.emptySet()
146.166 - };
146.167 -
146.168 - assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
146.169 -
146.170 - Lookup.Result<Object> res = lookup.lookup (template);
146.171 -
146.172 - assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
146.173 -
146.174 - LL ll = new LL ();
146.175 - res.addLookupListener (ll);
146.176 - Collection allRes = res.allInstances ();
146.177 -
146.178 - lookup.setLookups (executor, new Lookup[0]);
146.179 - if (ll.getCount () != 0) {
146.180 - fail ("Calling setLookups (emptyarray) fired a change");
146.181 - }
146.182 -
146.183 - InstanceContent t = new InstanceContent();
146.184 - Lookup del = new AbstractLookup (t);
146.185 - t.add("Ahoj");
146.186 - lookup.setLookups (executor, new Lookup[] { del });
146.187 - assertEquals("No change yet", 0, ll.getCount());
146.188 - executor.perform();
146.189 - if (ll.getCount () != 1) {
146.190 - fail ("Changing lookups did not generate an event");
146.191 - }
146.192 -
146.193 - lookup.setLookups (executor, new Lookup[] { del });
146.194 - if (ll.getCount () != 0) {
146.195 - fail ("Calling setLookups (thesamearray) fired a change");
146.196 - }
146.197 - }
146.198 -
146.199 - public void testSetLookups () throws Exception {
146.200 - AbstractLookup a1 = new AbstractLookup (new InstanceContent ());
146.201 - AbstractLookup a2 = new AbstractLookup (new InstanceContent ());
146.202 -
146.203 - InstanceContent i3 = new InstanceContent ();
146.204 - i3.add (i3);
146.205 - AbstractLookup a3 = new AbstractLookup (i3);
146.206 -
146.207 - final ProxyLookup p = new ProxyLookup (new Lookup[] { a1, a2 });
146.208 - final Lookup.Result res1 = p.lookup (new Lookup.Template (Object.class));
146.209 - Collection c1 = res1.allInstances();
146.210 -
146.211 - Lookup.Result res2 = p.lookup (new Lookup.Template (String.class));
146.212 - Collection c2 = res2.allInstances ();
146.213 -
146.214 -
146.215 - assertTrue ("We need two results", res1 != res2);
146.216 -
146.217 - final Object blocked = new Object ();
146.218 -
146.219 - class L extends Object implements LookupListener {
146.220 - public void resultChanged (LookupEvent ev) {
146.221 - try {
146.222 - res1.removeLookupListener(this);
146.223 -
146.224 - // waiting for second thread to start #111#
146.225 - blocked.wait ();
146.226 -
146.227 - } catch (Exception ex) {
146.228 - ex.printStackTrace();
146.229 - fail ("An exception occured ");
146.230 - }
146.231 - }
146.232 - }
146.233 -
146.234 - final L listener1 = new L ();
146.235 - res1.addLookupListener (listener1);
146.236 -
146.237 -
146.238 - Runnable newLookupSetter = new Runnable() {
146.239 - public void run () {
146.240 - synchronized (blocked) {
146.241 - try {
146.242 - p.setLookups (new Lookup[0]);
146.243 - } catch (Exception ex) {
146.244 - ex.printStackTrace();
146.245 - fail ("setLookups failed.");
146.246 - } finally {
146.247 - // starts the main thread #111#
146.248 - blocked.notify ();
146.249 - }
146.250 - }
146.251 - }
146.252 - };
146.253 -
146.254 - synchronized (blocked) {
146.255 - new Thread (newLookupSetter).start ();
146.256 -
146.257 - p.setLookups (new Lookup[] { a1, a2, a3 });
146.258 - }
146.259 - }
146.260 -
146.261 - public void testProxyLookupTemplateCaching(){
146.262 - Lookup lookups[] = new Lookup[1];
146.263 - doProxyLookupTemplateCaching(lookups, false);
146.264 - }
146.265 -
146.266 - public void testProxyLookupTemplateCachingOnSizeTwoArray() {
146.267 - Lookup lookups[] = new Lookup[2];
146.268 - lookups[1] = Lookup.EMPTY;
146.269 - doProxyLookupTemplateCaching(lookups, false);
146.270 - }
146.271 - public void testProxyLookupShallNotAllowModificationOfGetLookups(){
146.272 - Lookup lookups[] = new Lookup[1];
146.273 - doProxyLookupTemplateCaching(lookups, true);
146.274 - }
146.275 -
146.276 - public void testProxyLookupShallNotAllowModificationOfGetLookupsOnSizeTwoArray() {
146.277 - Lookup lookups[] = new Lookup[2];
146.278 - lookups[1] = Lookup.EMPTY;
146.279 - doProxyLookupTemplateCaching(lookups, true);
146.280 - }
146.281 -
146.282 - /** Index 0 of lookups will be modified, the rest is up to the
146.283 - * setup code.
146.284 - */
146.285 - private void doProxyLookupTemplateCaching(Lookup[] lookups, boolean reget) {
146.286 - // Create MyProxyLookup with one lookup containing the String object
146.287 - InstanceContent inst = new InstanceContent();
146.288 - inst.add(new String("Hello World")); //NOI18N
146.289 - lookups[0] = new AbstractLookup(inst);
146.290 - ProxyLookup proxy = new ProxyLookup(lookups);
146.291 - if (reget) {
146.292 - lookups = proxy.getLookups();
146.293 - }
146.294 -
146.295 - // Performing template lookup for String object
146.296 - Lookup.Result result = proxy.lookup(new Lookup.Template(String.class, null, null));
146.297 - int stringTemplateResultSize = result.allInstances().size();
146.298 - assertEquals ("Ensure, there is only one instance of String.class in proxyLookup:", //NOI18N
146.299 - 1, stringTemplateResultSize);
146.300 -
146.301 - // Changing lookup in proxy lookup, now it will contain
146.302 - // StringBuffer Object instead of String
146.303 - InstanceContent ic2 = new InstanceContent();
146.304 - ic2.add(new Integer(1234567890));
146.305 - lookups[0] = new AbstractLookup(ic2);
146.306 - proxy.setLookups(lookups);
146.307 -
146.308 - assertEquals ("the old result is updated", 0, result.allInstances().size());
146.309 -
146.310 - // Instance of String.class should not appear in proxyLookup
146.311 - Lookup.Result r2 = proxy.lookup(new Lookup.Template(String.class, null, null));
146.312 - assertEquals ("Instance of String.class should not appear in proxyLookup:", //NOI18N
146.313 - 0, r2.allInstances().size());
146.314 -
146.315 - Lookup.Result r3 = proxy.lookup(new Lookup.Template(Integer.class, null, null));
146.316 - assertEquals ("There is only one instance of Integer.class in proxyLookup:", //NOI18N
146.317 - 1, r3.allInstances().size());
146.318 - }
146.319 -
146.320 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
146.321 - doListeningAndQueryingByTwoListenersSetLookups(0, 1);
146.322 - }
146.323 - public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
146.324 - doListeningAndQueryingByTwoListenersSetLookups(1, 1);
146.325 - }
146.326 - public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
146.327 - doListeningAndQueryingByTwoListenersSetLookups(2, 1);
146.328 - }
146.329 -
146.330 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
146.331 - doListeningAndQueryingByTwoListenersSetLookups(0, 2);
146.332 - }
146.333 - public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
146.334 - doListeningAndQueryingByTwoListenersSetLookups(1, 2);
146.335 - }
146.336 - public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
146.337 - doListeningAndQueryingByTwoListenersSetLookups(2, 2);
146.338 - }
146.339 - public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
146.340 - doListeningAndQueryingByTwoListenersSetLookups(0, 22);
146.341 - }
146.342 - public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
146.343 - doListeningAndQueryingByTwoListenersSetLookups(1, 22);
146.344 - }
146.345 - public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
146.346 - doListeningAndQueryingByTwoListenersSetLookups(2, 22);
146.347 - }
146.348 -
146.349 - private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth) {
146.350 - ProxyLookup orig = new ProxyLookup();
146.351 - ProxyLookup on = orig;
146.352 -
146.353 - while (--depth > 0) {
146.354 - on = new ProxyLookup(new Lookup[] { on });
146.355 - }
146.356 -
146.357 -
146.358 - final ProxyLookup lookup = on;
146.359 -
146.360 - class L implements LookupListener {
146.361 - Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
146.362 - Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
146.363 - Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
146.364 -
146.365 - {
146.366 - integer.addLookupListener(this);
146.367 - number.addLookupListener(this);
146.368 - serial.addLookupListener(this);
146.369 - }
146.370 -
146.371 - int round;
146.372 -
146.373 - public void resultChanged(LookupEvent ev) {
146.374 - Collection c1 = get(type, integer);
146.375 - Collection c2 = get(type, number);
146.376 - Collection c3 = get(type, serial);
146.377 -
146.378 - assertEquals("round " + round + " c1 vs. c2", c1, c2);
146.379 - assertEquals("round " + round + " c1 vs. c3", c1, c3);
146.380 - assertEquals("round " + round + " c2 vs. c3", c2, c3);
146.381 -
146.382 - round++;
146.383 - }
146.384 -
146.385 - private Collection get(int type, Lookup.Result res) {
146.386 - Collection c;
146.387 - switch(type) {
146.388 - case 0: c = res.allInstances(); break;
146.389 - case 1: c = res.allClasses(); break;
146.390 - case 2: c = res.allItems(); break;
146.391 - default: c = null; fail("Type: " + type); break;
146.392 - }
146.393 -
146.394 - assertNotNull(c);
146.395 - return new ArrayList(c);
146.396 - }
146.397 - }
146.398 -
146.399 - L listener = new L();
146.400 - listener.resultChanged(null);
146.401 - ArrayList arr = new ArrayList();
146.402 - for(int i = 0; i < 100; i++) {
146.403 - arr.add(new Integer(i));
146.404 -
146.405 - orig.setLookups(new Lookup[] { Lookups.fixed(arr.toArray()) });
146.406 - }
146.407 -
146.408 - assertEquals("3x100+1 checks", 301, listener.round);
146.409 - }
146.410 -
146.411 - static Object holder;
146.412 -
146.413 - public void testProxyWithLiveResultCanBeCollected() {
146.414 - Lookup layer0 = Lookups.singleton("Hello");
146.415 - Lookup layer1 = new ProxyLookup(new Lookup[] { layer0 });
146.416 - Lookup layer2 = new ProxyLookup(new Lookup[] { layer1 });
146.417 - Lookup.Result result1 = layer1.lookup(new Lookup.Template(String.class));
146.418 -
146.419 - assertEquals("One instance", 1, result1.allInstances().size());
146.420 -
146.421 - // this will create ProxyLookup$R which listens on origResult
146.422 - Lookup.Result result2 = layer2.lookup(new Lookup.Template(String.class));
146.423 -
146.424 - // this line is necessary. W/o actually querying the result,
146.425 - // it will nether compute it nor attach the listener.
146.426 - assertEquals("One instance", 1, result2.allInstances().size());
146.427 -
146.428 - result2.addLookupListener(new LookupListener() {
146.429 - public void resultChanged(LookupEvent ev) {}
146.430 - });
146.431 -
146.432 - Reference ref = new WeakReference(layer2);
146.433 - layer2 = null;
146.434 - result2 = null;
146.435 - try {
146.436 - holder = result1;
146.437 - assertGC ("The proxy lookup not been garbage collected!", ref);
146.438 - } finally {
146.439 - holder = null;
146.440 - }
146.441 - }
146.442 -
146.443 - public void testArrayIndexAsInIssue119292() throws Exception {
146.444 - final ProxyLookup pl = new ProxyLookup();
146.445 - final int[] cnt = { 0 };
146.446 -
146.447 - class L extends Lookup {
146.448 - L[] set;
146.449 - Lookup l;
146.450 -
146.451 - public L(String s) {
146.452 - l = Lookups.singleton(s);
146.453 - }
146.454 -
146.455 - @Override
146.456 - public <T> T lookup(Class<T> clazz) {
146.457 - return l.lookup(clazz);
146.458 - }
146.459 -
146.460 - @Override
146.461 - public <T> Result<T> lookup(Template<T> template) {
146.462 - return l.lookup(template);
146.463 - }
146.464 -
146.465 - @Override
146.466 - @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
146.467 - public boolean equals(Object obj) {
146.468 - if (set != null) {
146.469 - cnt[0]++;
146.470 - pl.setLookups(set);
146.471 - }
146.472 - return super.equals(obj);
146.473 - }
146.474 -
146.475 - @Override
146.476 - public int hashCode() {
146.477 - int hash = 3;
146.478 - return hash;
146.479 - }
146.480 - }
146.481 -
146.482 - Result<String> res = pl.lookupResult(String.class);
146.483 - assertEquals(Collections.EMPTY_LIST, res.allItems());
146.484 -
146.485 - L[] old = { new L("A"), new L("B") };
146.486 - L[] now = { new L("C") };
146.487 -
146.488 - pl.setLookups(old);
146.489 - cnt[0] = 0;
146.490 -
146.491 - old[0].set = new L[0];
146.492 - pl.setLookups(now);
146.493 -
146.494 - assertEquals("No call to equals", 0, cnt[0]);
146.495 -
146.496 - assertEquals("Still assigned to C", Collections.singletonList("C"), res.allInstances());
146.497 - }
146.498 -
146.499 - public void testArrayIndexWithAddRemoveListenerAsInIssue119292() throws Exception {
146.500 - final ProxyLookup pl = new ProxyLookup();
146.501 - final int[] cnt = { 0 };
146.502 -
146.503 - class L extends Lookup {
146.504 - L[] set;
146.505 - Lookup l;
146.506 -
146.507 - public L(String s) {
146.508 - l = Lookups.singleton(s);
146.509 - }
146.510 -
146.511 - @Override
146.512 - public <T> T lookup(Class<T> clazz) {
146.513 - return l.lookup(clazz);
146.514 - }
146.515 -
146.516 - @Override
146.517 - public <T> Result<T> lookup(Template<T> template) {
146.518 - Result<T> r = l.lookup(template);
146.519 - return new R<T>(r);
146.520 - }
146.521 -
146.522 - final class R<T> extends Result<T> {
146.523 - private Result<T> delegate;
146.524 -
146.525 - public R(Result<T> delegate) {
146.526 - this.delegate = delegate;
146.527 - }
146.528 -
146.529 - @Override
146.530 - public void addLookupListener(LookupListener l) {
146.531 - cnt[0]++;
146.532 - if (set != null) {
146.533 - pl.setLookups(set);
146.534 - }
146.535 - delegate.addLookupListener(l);
146.536 - }
146.537 -
146.538 - @Override
146.539 - public void removeLookupListener(LookupListener l) {
146.540 - cnt[0]++;
146.541 - if (set != null) {
146.542 - pl.setLookups(set);
146.543 - }
146.544 - delegate.removeLookupListener(l);
146.545 - }
146.546 -
146.547 - @Override
146.548 - public Collection<? extends T> allInstances() {
146.549 - return delegate.allInstances();
146.550 - }
146.551 - }
146.552 - }
146.553 -
146.554 - Result<String> res = pl.lookupResult(String.class);
146.555 - assertEquals(Collections.EMPTY_LIST, res.allItems());
146.556 -
146.557 - L[] old = { new L("A"), new L("B") };
146.558 - L[] now = { new L("C") };
146.559 -
146.560 - pl.setLookups(old);
146.561 - cnt[0] = 0;
146.562 -
146.563 - old[0].set = new L[0];
146.564 - pl.setLookups(now);
146.565 -
146.566 - if (cnt[0] == 0) {
146.567 - fail("There should be calls to listeners");
146.568 - }
146.569 -
146.570 - assertEquals("C is overriden from removeLookupListener", Collections.emptyList(), res.allInstances());
146.571 - }
146.572 -
146.573 -
146.574 - public void testArrayIndexWithSetLookupAsInIssue123679() throws Exception {
146.575 - final ProxyLookup pl = new ProxyLookup();
146.576 - final int[] cnt = { 0 };
146.577 -
146.578 - class L extends Lookup {
146.579 - L[] set;
146.580 - Lookup l;
146.581 - Collection<? extends Serializable> res;
146.582 -
146.583 - public L(String s) {
146.584 - l = Lookups.singleton(s);
146.585 - }
146.586 -
146.587 - @Override
146.588 - public <T> T lookup(Class<T> clazz) {
146.589 - return l.lookup(clazz);
146.590 - }
146.591 -
146.592 - @Override
146.593 - public <T> Result<T> lookup(Template<T> template) {
146.594 - cnt[0]++;
146.595 - if (set != null) {
146.596 - pl.setLookups(set);
146.597 - res = pl.lookupAll(Serializable.class);
146.598 - }
146.599 - Result<T> r = l.lookup(template);
146.600 - return r;
146.601 - }
146.602 - }
146.603 -
146.604 - L[] now = { new L("A"), new L("B") };
146.605 - L[] old = { new L("C") };
146.606 - pl.setLookups(old);
146.607 - old[0].set = now;
146.608 -
146.609 - Result<String> res = pl.lookupResult(String.class);
146.610 - assertEquals("New items visible", 2, res.allItems().size());
146.611 -
146.612 -
146.613 - pl.setLookups(new L("X"), new L("Y"), new L("Z"));
146.614 - }
146.615 -
146.616 - public void testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679() throws Exception {
146.617 - final ProxyLookup pl = new ProxyLookup();
146.618 - final int[] cnt = { 0 };
146.619 -
146.620 - class L extends Lookup {
146.621 - L[] set;
146.622 - Lookup l;
146.623 - Collection<? extends Serializable> res;
146.624 -
146.625 - public L(String s) {
146.626 - l = Lookups.singleton(s);
146.627 - }
146.628 -
146.629 - @Override
146.630 - public <T> T lookup(Class<T> clazz) {
146.631 - return l.lookup(clazz);
146.632 - }
146.633 -
146.634 - @Override
146.635 - public <T> Result<T> lookup(Template<T> template) {
146.636 - cnt[0]++;
146.637 - if (set != null) {
146.638 - pl.setLookups(set);
146.639 - res = pl.lookupAll(Serializable.class);
146.640 - }
146.641 - Result<T> r = l.lookup(template);
146.642 - return r;
146.643 - }
146.644 - }
146.645 -
146.646 - L dupl = new L("A");
146.647 - L[] now = { dupl };
146.648 - L[] old = { new L("C") };
146.649 - pl.setLookups(old);
146.650 - old[0].set = now;
146.651 -
146.652 - Result<String> res = pl.lookupResult(String.class);
146.653 - assertEquals("New items visible", 1, res.allItems().size());
146.654 -
146.655 -
146.656 - pl.setLookups(old);
146.657 - }
146.658 -}
147.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleLookupTest.java Thu Dec 10 19:23:25 2009 -0500
147.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
147.3 @@ -1,351 +0,0 @@
147.4 -/*
147.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
147.6 - *
147.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
147.8 - *
147.9 - * The contents of this file are subject to the terms of either the GNU
147.10 - * General Public License Version 2 only ("GPL") or the Common
147.11 - * Development and Distribution License("CDDL") (collectively, the
147.12 - * "License"). You may not use this file except in compliance with the
147.13 - * License. You can obtain a copy of the License at
147.14 - * http://www.netbeans.org/cddl-gplv2.html
147.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
147.16 - * specific language governing permissions and limitations under the
147.17 - * License. When distributing the software, include this License Header
147.18 - * Notice in each file and include the License file at
147.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
147.20 - * particular file as subject to the "Classpath" exception as provided
147.21 - * by Sun in the GPL Version 2 section of the License file that
147.22 - * accompanied this code. If applicable, add the following below the
147.23 - * License Header, with the fields enclosed by brackets [] replaced by
147.24 - * your own identifying information:
147.25 - * "Portions Copyrighted [year] [name of copyright owner]"
147.26 - *
147.27 - * Contributor(s):
147.28 - *
147.29 - * The Original Software is NetBeans. The Initial Developer of the Original
147.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
147.31 - * Microsystems, Inc. All Rights Reserved.
147.32 - *
147.33 - * If you wish your version of this file to be governed by only the CDDL
147.34 - * or only the GPL Version 2, indicate your decision by adding
147.35 - * "[Contributor] elects to include this software in this distribution
147.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
147.37 - * single choice of license, a recipient has the option to distribute
147.38 - * your version of this file under either the CDDL, the GPL Version 2 or
147.39 - * to extend the choice of license to its licensees as provided above.
147.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
147.41 - * Version 2 license, then the option applies only if the new code is
147.42 - * made subject to such option by the copyright holder.
147.43 - */
147.44 -
147.45 -package org.openide.util.lookup;
147.46 -
147.47 -import java.util.ArrayList;
147.48 -import java.util.Arrays;
147.49 -import java.util.Collection;
147.50 -import java.util.List;
147.51 -import java.util.Set;
147.52 -import org.netbeans.junit.NbTestCase;
147.53 -import org.openide.util.Lookup;
147.54 -
147.55 -/**
147.56 - * Tests for class SimpleLookup.
147.57 - * @author David Strupl
147.58 - */
147.59 -public class SimpleLookupTest extends NbTestCase {
147.60 -
147.61 - public SimpleLookupTest(String testName) {
147.62 - super(testName);
147.63 - }
147.64 -
147.65 - public void testEmptyLookup() {
147.66 - assertSize("Lookup.EMPTY should be small", 8, Lookup.EMPTY);
147.67 - }
147.68 -
147.69 - /**
147.70 - * Simple tests testing singleton lookup.
147.71 - */
147.72 - public void testSingleton() {
147.73 - //
147.74 - Object orig = new Object();
147.75 - Lookup p1 = Lookups.singleton(orig);
147.76 - Object obj = p1.lookup(Object.class);
147.77 - assertTrue(obj == orig);
147.78 - assertNull(p1.lookup(String.class));
147.79 - assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
147.80 - //
147.81 - Lookup p2 = Lookups.singleton("test");
147.82 - assertNotNull(p2.lookup(Object.class));
147.83 - assertNotNull(p2.lookup(String.class));
147.84 - assertNotNull(p2.lookup(java.io.Serializable.class));
147.85 - }
147.86 -
147.87 - public void testEmptyFixed() {
147.88 - Lookup l = Lookups.fixed();
147.89 - assertSize("Lookups.fixed() for empty list of items should be small", 8, l);
147.90 - assertSame(Lookup.EMPTY, l);
147.91 - }
147.92 -
147.93 - public void testSingleItemFixed() {
147.94 - Object o = new Object();
147.95 - Lookup l = Lookups.fixed(o);
147.96 - assertSize("Lookups.fixed(o) for a single item should be small", 24, l);
147.97 - }
147.98 -
147.99 - /**
147.100 - * Simple tests testing fixed lookup.
147.101 - */
147.102 - public void testFixed() {
147.103 - //
147.104 - Object[] orig = new Object[] { new Object(), new Object() };
147.105 - Lookup p1 = Lookups.fixed(orig);
147.106 - Object obj = p1.lookup(Object.class);
147.107 - assertTrue(obj == orig[0] || obj == orig[1]);
147.108 - assertNull(p1.lookup(String.class));
147.109 - //
147.110 - String[] s = new String[] { "test1", "test2" };
147.111 - Lookup p2 = Lookups.fixed((Object[]) s);
147.112 - Object obj2 = p2.lookup(Object.class);
147.113 - assertNotNull(obj2);
147.114 - if (obj2 != s[0] && obj2 != s[1]) {
147.115 - fail("Returned objects are not the originals");
147.116 - }
147.117 - assertNotNull(p2.lookup(String.class));
147.118 - assertNotNull(p2.lookup(java.io.Serializable.class));
147.119 - Lookup.Template<String> t = new Lookup.Template<String>(String.class);
147.120 - Lookup.Result<String> r = p2.lookup(t);
147.121 - Collection<? extends String> all = r.allInstances();
147.122 - assertTrue(all.size() == 2);
147.123 - for (String o : all) {
147.124 - assertTrue("allInstances contains wrong objects", o.equals(s[0]) || o.equals(s[1]));
147.125 - }
147.126 -
147.127 - try {
147.128 - Lookups.fixed(new Object[] {null});
147.129 - fail("No nulls are allowed");
147.130 - } catch (NullPointerException ex) {
147.131 - // ok, NPE is what we want
147.132 - }
147.133 - }
147.134 -
147.135 - public void testFixedSubtypes() {
147.136 - class A {}
147.137 - class B extends A {}
147.138 - Lookup l = Lookups.fixed(new A(), new B());
147.139 - assertEquals(1, l.lookupAll(B.class).size());
147.140 - assertEquals(2, l.lookupAll(A.class).size());
147.141 - }
147.142 -
147.143 - /**
147.144 - * Simple tests testing converting lookup.
147.145 - */
147.146 - public void testConverting() {
147.147 - //
147.148 - String[] orig = new String[] { TestConvertor.TEST1, TestConvertor.TEST2 };
147.149 - TestConvertor convertor = new TestConvertor();
147.150 - Lookup p1 = Lookups.fixed(orig, convertor);
147.151 - assertNull("Converting from String to Integer - it should not find String in result", p1.lookup(String.class));
147.152 - assertNotNull(p1.lookup(Integer.class));
147.153 - assertNotNull(p1.lookup(Integer.class));
147.154 - assertTrue("Convertor should be called only once.", convertor.getNumberOfConvertCalls() == 1);
147.155 - Lookup.Template<Integer> t = new Lookup.Template<Integer>(Integer.class);
147.156 - Lookup.Result<Integer> r = p1.lookup(t);
147.157 - Collection<? extends Integer> all = r.allInstances();
147.158 - assertTrue(all.size() == 2);
147.159 - for (int i : all) {
147.160 - assertTrue("allInstances contains wrong objects", i == TestConvertor.t1 || i == TestConvertor.t2);
147.161 - }
147.162 - }
147.163 -
147.164 - private static class TestConvertor implements InstanceContent.Convertor<String,Integer> {
147.165 - static final String TEST1 = "test1";
147.166 - static final int t1 = 1;
147.167 - static final String TEST2 = "test2";
147.168 - static final int t2 = 2;
147.169 -
147.170 - private int numberOfConvertCalls = 0;
147.171 -
147.172 - public Integer convert(String obj) {
147.173 - numberOfConvertCalls++;
147.174 - if (obj.equals(TEST1)) {
147.175 - return t1;
147.176 - }
147.177 - if (obj.equals(TEST2)) {
147.178 - return t2;
147.179 - }
147.180 - throw new IllegalArgumentException();
147.181 - }
147.182 -
147.183 - public String displayName(String obj) {
147.184 - return obj;
147.185 - }
147.186 -
147.187 - public String id(String obj) {
147.188 - if (obj.equals(TEST1)) {
147.189 - return TEST1;
147.190 - }
147.191 - if (obj.equals(TEST2)) {
147.192 - return TEST2;
147.193 - }
147.194 - return null;
147.195 - }
147.196 -
147.197 - public Class<? extends Integer> type(String obj) {
147.198 - return Integer.class;
147.199 - }
147.200 -
147.201 - int getNumberOfConvertCalls() {
147.202 - return numberOfConvertCalls;
147.203 - }
147.204 - }
147.205 -
147.206 - public void testLookupItem() {
147.207 - SomeInst inst = new SomeInst();
147.208 - Lookup.Item item = Lookups.lookupItem(inst, "XYZ");
147.209 -
147.210 - assertTrue("Wrong instance", item.getInstance() == inst);
147.211 - assertTrue("Wrong instance class", item.getType() == inst.getClass());
147.212 - assertEquals("Wrong id", "XYZ", item.getId());
147.213 -
147.214 - item = Lookups.lookupItem(inst, null);
147.215 - assertNotNull("Id must never be null", item.getId());
147.216 - }
147.217 -
147.218 - public void testLookupItemEquals() {
147.219 - SomeInst instA = new SomeInst();
147.220 - SomeInst instB = new SomeInst();
147.221 - Lookup.Item itemA = Lookups.lookupItem(instA, null);
147.222 - Lookup.Item itemB = Lookups.lookupItem(instB, null);
147.223 -
147.224 - assertTrue("Lookup items shouldn't be equal", !itemA.equals(itemB) && !itemB.equals(itemA));
147.225 -
147.226 - itemA = Lookups.lookupItem(instA, null);
147.227 - itemB = Lookups.lookupItem(instA, null); // same instance
147.228 -
147.229 - assertTrue("Lookup items should be equal", itemA.equals(itemB) && itemB.equals(itemA));
147.230 - assertTrue("Lookup items hashcode should be same", itemA.hashCode() == itemB.hashCode());
147.231 -
147.232 - itemA = Lookups.lookupItem(new String("VOKURKA"), null);
147.233 - itemB = Lookups.lookupItem(new String("VOKURKA"), null);
147.234 -
147.235 - assertTrue("Lookup items shouldn't be equal (2)", !itemA.equals(itemB) && !itemB.equals(itemA));
147.236 - }
147.237 -
147.238 - public void testAllClassesIssue42399 () throws Exception {
147.239 - Object[] arr = { "Ahoj", new Object () };
147.240 -
147.241 - Lookup l = Lookups.fixed (arr);
147.242 -
147.243 - Set<Class<? extends Object>> s = l.lookup(new Lookup.Template<Object>(Object.class)).allClasses();
147.244 -
147.245 - assertEquals ("Two there", 2, s.size ());
147.246 - assertTrue ("Contains Object.class", s.contains (Object.class));
147.247 - assertTrue ("Contains string", s.contains (String.class));
147.248 -
147.249 - }
147.250 -
147.251 - public void testLookupItemEarlyInitializationProblem() {
147.252 - InstanceContent ic = new InstanceContent();
147.253 - AbstractLookup al = new AbstractLookup(ic);
147.254 - LI item = new LI();
147.255 - List<AbstractLookup.Pair> pairs1 = new ArrayList<AbstractLookup.Pair>();
147.256 - List<AbstractLookup.Pair> pairs2 = new ArrayList<AbstractLookup.Pair>();
147.257 -
147.258 - assertEquals("Item's instance shouldn't be requested", 0, item.cnt);
147.259 -
147.260 - pairs1.add(new ItemPair<Object>(Lookups.<Object>lookupItem(new SomeInst(), null)));
147.261 - pairs1.add(new ItemPair<Object>(item));
147.262 - pairs1.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
147.263 -
147.264 - pairs2.add(new ItemPair<Object>(item));
147.265 - pairs2.add(new ItemPair<Object>(Lookups.lookupItem(new Object(), null)));
147.266 -
147.267 - ic.setPairs(pairs1);
147.268 - ic.setPairs(pairs2);
147.269 -
147.270 - assertEquals("Item's instance shouldn't be requested when added to lookup", 0, item.cnt);
147.271 -
147.272 - LI item2 = al.lookup(LI.class);
147.273 - assertEquals("Item's instance should be requested", 1, item.cnt);
147.274 - }
147.275 -
147.276 - public void testConvenienceMethods() throws Exception {
147.277 - // Just check signatures and basic behavior of #73848.
147.278 - Lookup l = Lookups.fixed(new Object[] {1, "hello", 2, "goodbye"});
147.279 - Collection<? extends Integer> ints = l.lookupAll(Integer.class);
147.280 - assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
147.281 - Lookup.Result<Integer> r = l.lookupResult(Integer.class);
147.282 - ints = r.allInstances();
147.283 - assertEquals(Arrays.asList(new Integer[] {1, 2}), new ArrayList<Integer>(ints));
147.284 - }
147.285 -
147.286 - private static class SomeInst { }
147.287 -
147.288 - private static class LI extends Lookup.Item<Object> {
147.289 -
147.290 - public long cnt = 0;
147.291 -
147.292 - public String getDisplayName() {
147.293 - return getId();
147.294 - }
147.295 -
147.296 - public String getId() {
147.297 - return getClass() + "@" + hashCode();
147.298 - }
147.299 -
147.300 - public Object getInstance() {
147.301 - cnt++;
147.302 - return this;
147.303 - }
147.304 -
147.305 - public Class<? extends Object> getType() {
147.306 - return getClass();
147.307 - }
147.308 - } // End of LI class
147.309 -
147.310 - private static class ItemPair<T> extends AbstractLookup.Pair<T> {
147.311 -
147.312 - private AbstractLookup.Item<T> item;
147.313 -
147.314 - public ItemPair(Lookup.Item<T> i) {
147.315 - this.item = i;
147.316 - }
147.317 -
147.318 - protected boolean creatorOf(Object obj) {
147.319 - return item.getInstance() == obj;
147.320 - }
147.321 -
147.322 - public String getDisplayName() {
147.323 - return item.getDisplayName ();
147.324 - }
147.325 -
147.326 - public String getId() {
147.327 - return item.getId ();
147.328 - }
147.329 -
147.330 - public T getInstance() {
147.331 - return item.getInstance ();
147.332 - }
147.333 -
147.334 - public Class<? extends T> getType() {
147.335 - return item.getType ();
147.336 - }
147.337 -
147.338 - protected boolean instanceOf(Class<?> c) {
147.339 - return c.isAssignableFrom(getType());
147.340 - }
147.341 -
147.342 - public @Override boolean equals(Object o) {
147.343 - if (o instanceof ItemPair) {
147.344 - ItemPair p = (ItemPair)o;
147.345 - return item.equals (p.item);
147.346 - }
147.347 - return false;
147.348 - }
147.349 -
147.350 - public @Override int hashCode() {
147.351 - return item.hashCode ();
147.352 - }
147.353 - } // end of ItemPair
147.354 -}
148.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleProxyLookupIssue42244Test.java Thu Dec 10 19:23:25 2009 -0500
148.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
148.3 @@ -1,120 +0,0 @@
148.4 -/*
148.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
148.6 - *
148.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
148.8 - *
148.9 - * The contents of this file are subject to the terms of either the GNU
148.10 - * General Public License Version 2 only ("GPL") or the Common
148.11 - * Development and Distribution License("CDDL") (collectively, the
148.12 - * "License"). You may not use this file except in compliance with the
148.13 - * License. You can obtain a copy of the License at
148.14 - * http://www.netbeans.org/cddl-gplv2.html
148.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
148.16 - * specific language governing permissions and limitations under the
148.17 - * License. When distributing the software, include this License Header
148.18 - * Notice in each file and include the License file at
148.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
148.20 - * particular file as subject to the "Classpath" exception as provided
148.21 - * by Sun in the GPL Version 2 section of the License file that
148.22 - * accompanied this code. If applicable, add the following below the
148.23 - * License Header, with the fields enclosed by brackets [] replaced by
148.24 - * your own identifying information:
148.25 - * "Portions Copyrighted [year] [name of copyright owner]"
148.26 - *
148.27 - * Contributor(s):
148.28 - *
148.29 - * The Original Software is NetBeans. The Initial Developer of the Original
148.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
148.31 - * Microsystems, Inc. All Rights Reserved.
148.32 - *
148.33 - * If you wish your version of this file to be governed by only the CDDL
148.34 - * or only the GPL Version 2, indicate your decision by adding
148.35 - * "[Contributor] elects to include this software in this distribution
148.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
148.37 - * single choice of license, a recipient has the option to distribute
148.38 - * your version of this file under either the CDDL, the GPL Version 2 or
148.39 - * to extend the choice of license to its licensees as provided above.
148.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
148.41 - * Version 2 license, then the option applies only if the new code is
148.42 - * made subject to such option by the copyright holder.
148.43 - */
148.44 -
148.45 -package org.openide.util.lookup;
148.46 -
148.47 -import java.lang.ref.WeakReference;
148.48 -import java.util.*;
148.49 -import junit.framework.*;
148.50 -import org.netbeans.junit.*;
148.51 -import org.openide.util.Lookup;
148.52 -
148.53 -/** To simulate issue 42244.
148.54 - */
148.55 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
148.56 -public class SimpleProxyLookupIssue42244Test extends AbstractLookupBaseHid implements AbstractLookupBaseHid.Impl {
148.57 - public SimpleProxyLookupIssue42244Test (java.lang.String testName) {
148.58 - super(testName, null);
148.59 - }
148.60 -
148.61 - public static Test suite() {
148.62 - // return new SimpleProxyLookupIssue42244Test("testGarbageCollect");
148.63 - return new NbTestSuite(SimpleProxyLookupIssue42244Test.class);
148.64 - }
148.65 -
148.66 - /** Creates an lookup for given lookup. This class just returns
148.67 - * the object passed in, but subclasses can be different.
148.68 - * @param lookup in lookup
148.69 - * @return a lookup to use
148.70 - */
148.71 - public Lookup createLookup (final Lookup lookup) {
148.72 - class C implements Lookup.Provider {
148.73 - public Lookup getLookup () {
148.74 - return lookup;
148.75 - }
148.76 - }
148.77 - return Lookups.proxy (new C ());
148.78 - }
148.79 -
148.80 - public Lookup createInstancesLookup (InstanceContent ic) {
148.81 - return new KeepResultsProxyLookup (new AbstractLookup (ic));
148.82 - }
148.83 -
148.84 - public void clearCaches () {
148.85 - KeepResultsProxyLookup k = (KeepResultsProxyLookup)this.instanceLookup;
148.86 -
148.87 - ArrayList toGC = new ArrayList ();
148.88 - Iterator it = k.allQueries.iterator ();
148.89 - while (it.hasNext ()) {
148.90 - Lookup.Result r = (Lookup.Result)it.next ();
148.91 - toGC.add (new WeakReference (r));
148.92 - }
148.93 -
148.94 - k.allQueries = null;
148.95 -
148.96 - it = toGC.iterator ();
148.97 - while (it.hasNext ()) {
148.98 - WeakReference r = (WeakReference)it.next ();
148.99 - assertGC ("Trying to release all results from memory", r);
148.100 - }
148.101 - }
148.102 -
148.103 - class KeepResultsProxyLookup extends ProxyLookup {
148.104 - private ArrayList allQueries = new ArrayList ();
148.105 - private ThreadLocal in = new ThreadLocal ();
148.106 -
148.107 - public KeepResultsProxyLookup (Lookup delegate) {
148.108 - super (new Lookup[] { delegate });
148.109 - }
148.110 -
148.111 - @Override
148.112 - protected void beforeLookup (org.openide.util.Lookup.Template template) {
148.113 - super.beforeLookup (template);
148.114 - if (allQueries != null && in.get () == null) {
148.115 - in.set (this);
148.116 - Lookup.Result res = lookup (template);
148.117 - allQueries.add (res);
148.118 - in.set (null);
148.119 - }
148.120 - }
148.121 -
148.122 - }
148.123 -}
149.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleProxyLookupSpeedIssue42244Test.java Thu Dec 10 19:23:25 2009 -0500
149.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
149.3 @@ -1,118 +0,0 @@
149.4 -/*
149.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
149.6 - *
149.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
149.8 - *
149.9 - * The contents of this file are subject to the terms of either the GNU
149.10 - * General Public License Version 2 only ("GPL") or the Common
149.11 - * Development and Distribution License("CDDL") (collectively, the
149.12 - * "License"). You may not use this file except in compliance with the
149.13 - * License. You can obtain a copy of the License at
149.14 - * http://www.netbeans.org/cddl-gplv2.html
149.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
149.16 - * specific language governing permissions and limitations under the
149.17 - * License. When distributing the software, include this License Header
149.18 - * Notice in each file and include the License file at
149.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
149.20 - * particular file as subject to the "Classpath" exception as provided
149.21 - * by Sun in the GPL Version 2 section of the License file that
149.22 - * accompanied this code. If applicable, add the following below the
149.23 - * License Header, with the fields enclosed by brackets [] replaced by
149.24 - * your own identifying information:
149.25 - * "Portions Copyrighted [year] [name of copyright owner]"
149.26 - *
149.27 - * Contributor(s):
149.28 - *
149.29 - * The Original Software is NetBeans. The Initial Developer of the Original
149.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
149.31 - * Microsystems, Inc. All Rights Reserved.
149.32 - *
149.33 - * If you wish your version of this file to be governed by only the CDDL
149.34 - * or only the GPL Version 2, indicate your decision by adding
149.35 - * "[Contributor] elects to include this software in this distribution
149.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
149.37 - * single choice of license, a recipient has the option to distribute
149.38 - * your version of this file under either the CDDL, the GPL Version 2 or
149.39 - * to extend the choice of license to its licensees as provided above.
149.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
149.41 - * Version 2 license, then the option applies only if the new code is
149.42 - * made subject to such option by the copyright holder.
149.43 - */
149.44 -
149.45 -package org.openide.util.lookup;
149.46 -
149.47 -import java.util.HashSet;
149.48 -import java.util.Set;
149.49 -import org.netbeans.junit.NbTestCase;
149.50 -
149.51 -import org.netbeans.junit.RandomlyFails;
149.52 -import org.openide.util.Lookup;
149.53 -
149.54 -/**
149.55 - * @author Petr Nejedly, adapted to test by Jaroslav Tulach
149.56 - */
149.57 -@RandomlyFails // NB-Core-Build #1847
149.58 -public class SimpleProxyLookupSpeedIssue42244Test extends NbTestCase {
149.59 -
149.60 - public SimpleProxyLookupSpeedIssue42244Test (String name) {
149.61 - super (name);
149.62 - }
149.63 -
149.64 - public void testCompareTheSpeed () {
149.65 - String content1 = "String1";
149.66 - String content2 = "String2";
149.67 -
149.68 - Lookup fixed1 = Lookups.singleton(content1);
149.69 - Lookup fixed2 = Lookups.singleton(content2);
149.70 -
149.71 - MyProvider provider = new MyProvider();
149.72 - provider.setLookup(fixed1);
149.73 -
149.74 - Lookup top = Lookups.proxy(provider);
149.75 -
149.76 - Lookup.Result<String> r0 = top.lookupResult(String.class);
149.77 - r0.allInstances();
149.78 -
149.79 - long time = System.currentTimeMillis();
149.80 - top.lookupAll(String.class);
149.81 - long withOneResult = System.currentTimeMillis() - time;
149.82 -
149.83 -
149.84 - Set<Object> results = new HashSet<Object>();
149.85 - for (int i=0; i<10000; i++) {
149.86 - Lookup.Result<String> res = top.lookupResult(String.class);
149.87 - results.add (res);
149.88 - res.allInstances();
149.89 - }
149.90 -
149.91 - provider.setLookup(fixed2);
149.92 -
149.93 - time = System.currentTimeMillis();
149.94 - top.lookupAll(String.class);
149.95 - long withManyResults = System.currentTimeMillis() - time;
149.96 -
149.97 - // if the measurement takes less then 10ms, pretend 10ms
149.98 - if (withManyResults < 10) {
149.99 - withManyResults = 10;
149.100 - }
149.101 - if (withOneResult < 10) {
149.102 - withOneResult = 10;
149.103 - }
149.104 -
149.105 - if (withManyResults >= 10 * withOneResult) {
149.106 - fail ("With many results the test runs too long.\n With many: " + withManyResults + "\n With one : " + withOneResult);
149.107 - }
149.108 - }
149.109 -
149.110 - private static class MyProvider implements Lookup.Provider {
149.111 - private Lookup lookup;
149.112 - public Lookup getLookup() {
149.113 - return lookup;
149.114 - }
149.115 -
149.116 - void setLookup(Lookup lookup) {
149.117 - this.lookup = lookup;
149.118 - }
149.119 - }
149.120 -
149.121 -}
150.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SimpleProxyLookupTest.java Thu Dec 10 19:23:25 2009 -0500
150.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
150.3 @@ -1,73 +0,0 @@
150.4 -/*
150.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
150.6 - *
150.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
150.8 - *
150.9 - * The contents of this file are subject to the terms of either the GNU
150.10 - * General Public License Version 2 only ("GPL") or the Common
150.11 - * Development and Distribution License("CDDL") (collectively, the
150.12 - * "License"). You may not use this file except in compliance with the
150.13 - * License. You can obtain a copy of the License at
150.14 - * http://www.netbeans.org/cddl-gplv2.html
150.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
150.16 - * specific language governing permissions and limitations under the
150.17 - * License. When distributing the software, include this License Header
150.18 - * Notice in each file and include the License file at
150.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
150.20 - * particular file as subject to the "Classpath" exception as provided
150.21 - * by Sun in the GPL Version 2 section of the License file that
150.22 - * accompanied this code. If applicable, add the following below the
150.23 - * License Header, with the fields enclosed by brackets [] replaced by
150.24 - * your own identifying information:
150.25 - * "Portions Copyrighted [year] [name of copyright owner]"
150.26 - *
150.27 - * Contributor(s):
150.28 - *
150.29 - * The Original Software is NetBeans. The Initial Developer of the Original
150.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
150.31 - * Microsystems, Inc. All Rights Reserved.
150.32 - *
150.33 - * If you wish your version of this file to be governed by only the CDDL
150.34 - * or only the GPL Version 2, indicate your decision by adding
150.35 - * "[Contributor] elects to include this software in this distribution
150.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
150.37 - * single choice of license, a recipient has the option to distribute
150.38 - * your version of this file under either the CDDL, the GPL Version 2 or
150.39 - * to extend the choice of license to its licensees as provided above.
150.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
150.41 - * Version 2 license, then the option applies only if the new code is
150.42 - * made subject to such option by the copyright holder.
150.43 - */
150.44 -
150.45 -package org.openide.util.lookup;
150.46 -
150.47 -import java.lang.ref.WeakReference;
150.48 -import org.netbeans.junit.NbTestCase;
150.49 -import org.openide.util.Lookup;
150.50 -import org.openide.util.Lookup.Provider;
150.51 -
150.52 -/**
150.53 - *
150.54 - * @author Jan Lahoda
150.55 - */
150.56 -@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
150.57 -public class SimpleProxyLookupTest extends NbTestCase {
150.58 -
150.59 - public SimpleProxyLookupTest(String testName) {
150.60 - super(testName);
150.61 - }
150.62 -
150.63 - public void test69810() throws Exception {
150.64 - Lookup.Template t = new Lookup.Template(String.class);
150.65 - SimpleProxyLookup spl = new SimpleProxyLookup(new Provider() {
150.66 - public Lookup getLookup() {
150.67 - return Lookups.fixed(new Object[] {"test1", "test2"});
150.68 - }
150.69 - });
150.70 -
150.71 - assertGC("", new WeakReference(spl.lookup(t)));
150.72 -
150.73 - spl.lookup(new Lookup.Template(Object.class)).allInstances();
150.74 - }
150.75 -
150.76 -}
151.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/SingletonLookupTest.java Thu Dec 10 19:23:25 2009 -0500
151.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
151.3 @@ -1,113 +0,0 @@
151.4 -/*
151.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
151.6 - *
151.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
151.8 - *
151.9 - * The contents of this file are subject to the terms of either the GNU
151.10 - * General Public License Version 2 only ("GPL") or the Common
151.11 - * Development and Distribution License("CDDL") (collectively, the
151.12 - * "License"). You may not use this file except in compliance with the
151.13 - * License. You can obtain a copy of the License at
151.14 - * http://www.netbeans.org/cddl-gplv2.html
151.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
151.16 - * specific language governing permissions and limitations under the
151.17 - * License. When distributing the software, include this License Header
151.18 - * Notice in each file and include the License file at
151.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
151.20 - * particular file as subject to the "Classpath" exception as provided
151.21 - * by Sun in the GPL Version 2 section of the License file that
151.22 - * accompanied this code. If applicable, add the following below the
151.23 - * License Header, with the fields enclosed by brackets [] replaced by
151.24 - * your own identifying information:
151.25 - * "Portions Copyrighted [year] [name of copyright owner]"
151.26 - *
151.27 - * If you wish your version of this file to be governed by only the CDDL
151.28 - * or only the GPL Version 2, indicate your decision by adding
151.29 - * "[Contributor] elects to include this software in this distribution
151.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
151.31 - * single choice of license, a recipient has the option to distribute
151.32 - * your version of this file under either the CDDL, the GPL Version 2 or
151.33 - * to extend the choice of license to its licensees as provided above.
151.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
151.35 - * Version 2 license, then the option applies only if the new code is
151.36 - * made subject to such option by the copyright holder.
151.37 - *
151.38 - * Contributor(s):
151.39 - *
151.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
151.41 - */
151.42 -
151.43 -package org.openide.util.lookup;
151.44 -
151.45 -import java.util.Collection;
151.46 -import org.netbeans.junit.NbTestCase;
151.47 -import org.openide.util.Lookup;
151.48 -
151.49 -/**
151.50 - * Contains tests of class {@code SingletonLookup}.
151.51 - *
151.52 - * @author Marian Petras
151.53 - */
151.54 -public class SingletonLookupTest extends NbTestCase {
151.55 -
151.56 - public SingletonLookupTest(String testName) {
151.57 - super(testName);
151.58 - }
151.59 -
151.60 - public void testBasics() {
151.61 - Object orig = new Object();
151.62 - Lookup p1 = new SingletonLookup(orig);
151.63 - Object obj = p1.lookup(Object.class);
151.64 - assertTrue(obj == orig);
151.65 - assertNull(p1.lookup(String.class));
151.66 - assertTrue(orig == p1.lookup(Object.class)); // 2nd time, still the same?
151.67 - //
151.68 - Lookup p2 = new SingletonLookup("test");
151.69 - assertNotNull(p2.lookup(Object.class));
151.70 - assertNotNull(p2.lookup(String.class));
151.71 - assertNotNull(p2.lookup(java.io.Serializable.class));
151.72 - }
151.73 -
151.74 - public void testId() {
151.75 - Object orig = new Object();
151.76 - Collection allInstances;
151.77 -
151.78 - Lookup l = new SingletonLookup(orig, "id");
151.79 -
151.80 - allInstances = l.lookup(new Lookup.Template<Object>(Object.class, null, null)).allInstances();
151.81 - assertNotNull(allInstances);
151.82 - assertFalse(allInstances.isEmpty());
151.83 - assertEquals(1, allInstances.size());
151.84 - assertTrue(allInstances.iterator().next() == orig);
151.85 -
151.86 - allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "id", null)).allInstances();
151.87 - assertNotNull(allInstances);
151.88 - assertFalse(allInstances.isEmpty());
151.89 - assertEquals(1, allInstances.size());
151.90 - assertTrue(allInstances.iterator().next() == orig);
151.91 -
151.92 - allInstances = l.lookup(new Lookup.Template<Object>(Object.class, "not", null)).allInstances();
151.93 - assertNotNull(allInstances);
151.94 - assertTrue(allInstances.isEmpty());
151.95 -
151.96 - allInstances = l.lookup(new Lookup.Template<String>(String.class, null, null)).allInstances();
151.97 - assertNotNull(allInstances);
151.98 - assertTrue(allInstances.isEmpty());
151.99 -
151.100 - allInstances = l.lookup(new Lookup.Template<String>(String.class, "id", null)).allInstances();
151.101 - assertNotNull(allInstances);
151.102 - assertTrue(allInstances.isEmpty());
151.103 -
151.104 - allInstances = l.lookup(new Lookup.Template<String>(String.class, "not", null)).allInstances();
151.105 - assertNotNull(allInstances);
151.106 - assertTrue(allInstances.isEmpty());
151.107 - }
151.108 -
151.109 - public void testSize() {
151.110 - final Object obj = new Object();
151.111 - assertSize("The singleton lookup instance should be small",
151.112 - 24,
151.113 - new SingletonLookup(obj));
151.114 - }
151.115 -
151.116 -}
152.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/problem100320.txt Thu Dec 10 19:23:25 2009 -0500
152.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
152.3 @@ -1,17 +0,0 @@
152.4 -:java.io.IOException:
152.5 -java.nio.charset.CharacterCodingException
152.6 -java.io.EOFException
152.7 -java.io.FileNotFoundException
152.8 -java.io.InterruptedIOException
152.9 -java.net.MalformedURLException
152.10 -java.io.IOException
152.11 -java.io.UnsupportedEncodingException
152.12 -java.io.NotActiveException
152.13 -java.io.StreamCorruptedException
152.14 -java.io.UTFDataFormatException
152.15 -java.util.zip.ZipException
152.16 -java.util.jar.JarException
152.17 -:java.util.Comparator:
152.18 -org.bar.Comparator3
152.19 -org.bar.Comparator2
152.20 -#position=5
153.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/services-jar-1.txt Thu Dec 10 19:23:25 2009 -0500
153.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
153.3 @@ -1,17 +0,0 @@
153.4 -:somedummyfile:
153.5 -org.foo.Interface
153.6 -:java.lang.Runnable:
153.7 -org.foo.impl.Runnable1
153.8 -:java.util.Comparator:
153.9 -#some comment
153.10 -org.foo.impl.Comparator1
153.11 -#position=10
153.12 -#som comment2
153.13 -:java.util.Iterator:
153.14 -org.foo.impl.Iterator1
153.15 -:org.foo.Interface:
153.16 -# Some header info, maybe.
153.17 -
153.18 -# Our first impl here
153.19 -org.foo.impl.Implementation1
153.20 -
154.1 --- a/openide.util/test/unit/src/org/openide/util/lookup/services-jar-2.txt Thu Dec 10 19:23:25 2009 -0500
154.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
154.3 @@ -1,10 +0,0 @@
154.4 -:java.lang.Runnable:
154.5 -#-org.foo.impl.Runnable1
154.6 -:java.util.Comparator:
154.7 -org.bar.Comparator2
154.8 -#position=5
154.9 -:java.util.Iterator:
154.10 -org.bar.Iterator2
154.11 -#position=100
154.12 -:org.foo.Interface:
154.13 -org.bar.Implementation2
155.1 --- a/openide.util/test/unit/src/org/openide/util/test/AnnotationProcessorTestUtils.java Thu Dec 10 19:23:25 2009 -0500
155.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
155.3 @@ -1,139 +0,0 @@
155.4 -/*
155.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
155.6 - *
155.7 - * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
155.8 - *
155.9 - * The contents of this file are subject to the terms of either the GNU
155.10 - * General Public License Version 2 only ("GPL") or the Common
155.11 - * Development and Distribution License("CDDL") (collectively, the
155.12 - * "License"). You may not use this file except in compliance with the
155.13 - * License. You can obtain a copy of the License at
155.14 - * http://www.netbeans.org/cddl-gplv2.html
155.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
155.16 - * specific language governing permissions and limitations under the
155.17 - * License. When distributing the software, include this License Header
155.18 - * Notice in each file and include the License file at
155.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
155.20 - * particular file as subject to the "Classpath" exception as provided
155.21 - * by Sun in the GPL Version 2 section of the License file that
155.22 - * accompanied this code. If applicable, add the following below the
155.23 - * License Header, with the fields enclosed by brackets [] replaced by
155.24 - * your own identifying information:
155.25 - * "Portions Copyrighted [year] [name of copyright owner]"
155.26 - *
155.27 - * If you wish your version of this file to be governed by only the CDDL
155.28 - * or only the GPL Version 2, indicate your decision by adding
155.29 - * "[Contributor] elects to include this software in this distribution
155.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
155.31 - * single choice of license, a recipient has the option to distribute
155.32 - * your version of this file under either the CDDL, the GPL Version 2 or
155.33 - * to extend the choice of license to its licensees as provided above.
155.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
155.35 - * Version 2 license, then the option applies only if the new code is
155.36 - * made subject to such option by the copyright holder.
155.37 - *
155.38 - * Contributor(s):
155.39 - *
155.40 - * Portions Copyrighted 2008 Sun Microsystems, Inc.
155.41 - */
155.42 -
155.43 -package org.openide.util.test;
155.44 -
155.45 -import java.io.File;
155.46 -import java.io.FileWriter;
155.47 -import java.io.IOException;
155.48 -import java.io.OutputStream;
155.49 -import java.io.PrintWriter;
155.50 -import java.io.Writer;
155.51 -import java.util.ArrayList;
155.52 -import java.util.List;
155.53 -import java.util.regex.Pattern;
155.54 -import javax.tools.JavaCompiler;
155.55 -import javax.tools.ToolProvider;
155.56 -import junit.framework.Assert;
155.57 -
155.58 -/**
155.59 - * Utilities useful to those testing JSR 269 annotation processors.
155.60 - * <p>If you just want to test that the output of the processor is correct,
155.61 - * you do not need to do anything special:
155.62 - * just use the annotation on some sample classes nested inside your unit test.
155.63 - * They will be processed, and you check that your SPI loads them correctly.
155.64 - * These utilities are useful mainly in case you want to check that the processor
155.65 - * rejects erroneous sources, and that any messages it prints are reasonable;
155.66 - * that it behaves correctly on incremental compilations; etc.
155.67 - */
155.68 -public class AnnotationProcessorTestUtils {
155.69 -
155.70 - private AnnotationProcessorTestUtils() {}
155.71 -
155.72 - /**
155.73 - * Create a source file.
155.74 - * @param dir source root
155.75 - * @param clazz a fully-qualified class name
155.76 - * @param content lines of text (skip package decl)
155.77 - */
155.78 - public static void makeSource(File dir, String clazz, String... content) throws IOException {
155.79 - File f = new File(dir, clazz.replace('.', File.separatorChar) + ".java");
155.80 - f.getParentFile().mkdirs();
155.81 - Writer w = new FileWriter(f);
155.82 - try {
155.83 - PrintWriter pw = new PrintWriter(w);
155.84 - String pkg = clazz.replaceFirst("\\.[^.]+$", "");
155.85 - if (!pkg.equals(clazz)) {
155.86 - pw.println("package " + pkg + ";");
155.87 - }
155.88 - for (String line : content) {
155.89 - pw.println(line);
155.90 - }
155.91 - pw.flush();
155.92 - } finally {
155.93 - w.close();
155.94 - }
155.95 - }
155.96 -
155.97 - /**
155.98 - * Run the Java compiler.
155.99 - * (A JSR 199 implementation must be available.)
155.100 - * @param src a source root (runs javac on all *.java it finds matching {@code srcIncludes})
155.101 - * @param srcIncludes a pattern of source files names without path to compile (useful for testing incremental compiles), or null for all
155.102 - * @param dest a dest dir to compile classes to
155.103 - * @param cp classpath entries; if null, use Java classpath of test
155.104 - * @param stderr output stream to print messages to, or null for test console (i.e. do not capture)
155.105 - * @return true if compilation succeeded, false if it failed
155.106 - */
155.107 - public static boolean runJavac(File src, String srcIncludes, File dest, File[] cp, OutputStream stderr) {
155.108 - List<String> args = new ArrayList<String>();
155.109 - args.add("-classpath");
155.110 - if (cp != null) {
155.111 - StringBuffer b = new StringBuffer();
155.112 - for (File entry : cp) {
155.113 - b.append(File.pathSeparatorChar);
155.114 - b.append(entry.getAbsolutePath());
155.115 - }
155.116 - args.add(b.toString());
155.117 - } else {
155.118 - args.add(System.getProperty("java.class.path"));
155.119 - }
155.120 - args.add("-d");
155.121 - args.add(dest.getAbsolutePath());
155.122 - args.add("-sourcepath");
155.123 - args.add(src.getAbsolutePath());
155.124 - dest.mkdirs();
155.125 - scan(args, src, srcIncludes);
155.126 - JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
155.127 - Assert.assertNotNull("no JSR 199 compiler impl found; try e.g.: " +
155.128 - "test.unit.run.cp.extra=${nb_all}/apisupport.harness/external/openjdk-javac-6-b12.jar", compiler);
155.129 - //System.err.println("running javac with args: " + args);
155.130 - return compiler.run(null, null, stderr, args.toArray(new String[args.size()])) == 0;
155.131 - }
155.132 - private static void scan(List<String> names, File f, String includes) {
155.133 - if (f.isDirectory()) {
155.134 - for (File kid : f.listFiles()) {
155.135 - scan(names, kid, includes);
155.136 - }
155.137 - } else if (f.getName().endsWith(".java") && (includes == null || Pattern.compile(includes).matcher(f.getName()).find())) {
155.138 - names.add(f.getAbsolutePath());
155.139 - }
155.140 - }
155.141 -
155.142 -}
156.1 --- a/openide.util/test/unit/src/org/openide/util/test/MockLookup.java Thu Dec 10 19:23:25 2009 -0500
156.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
156.3 @@ -1,135 +0,0 @@
156.4 -/*
156.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
156.6 - *
156.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
156.8 - *
156.9 - * The contents of this file are subject to the terms of either the GNU
156.10 - * General Public License Version 2 only ("GPL") or the Common
156.11 - * Development and Distribution License("CDDL") (collectively, the
156.12 - * "License"). You may not use this file except in compliance with the
156.13 - * License. You can obtain a copy of the License at
156.14 - * http://www.netbeans.org/cddl-gplv2.html
156.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
156.16 - * specific language governing permissions and limitations under the
156.17 - * License. When distributing the software, include this License Header
156.18 - * Notice in each file and include the License file at
156.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
156.20 - * particular file as subject to the "Classpath" exception as provided
156.21 - * by Sun in the GPL Version 2 section of the License file that
156.22 - * accompanied this code. If applicable, add the following below the
156.23 - * License Header, with the fields enclosed by brackets [] replaced by
156.24 - * your own identifying information:
156.25 - * "Portions Copyrighted [year] [name of copyright owner]"
156.26 - *
156.27 - * Contributor(s):
156.28 - *
156.29 - * The Original Software is NetBeans. The Initial Developer of the Original
156.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
156.31 - * Microsystems, Inc. All Rights Reserved.
156.32 - *
156.33 - * If you wish your version of this file to be governed by only the CDDL
156.34 - * or only the GPL Version 2, indicate your decision by adding
156.35 - * "[Contributor] elects to include this software in this distribution
156.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
156.37 - * single choice of license, a recipient has the option to distribute
156.38 - * your version of this file under either the CDDL, the GPL Version 2 or
156.39 - * to extend the choice of license to its licensees as provided above.
156.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
156.41 - * Version 2 license, then the option applies only if the new code is
156.42 - * made subject to such option by the copyright holder.
156.43 - */
156.44 -
156.45 -package org.openide.util.test;
156.46 -
156.47 -import java.lang.reflect.Field;
156.48 -import java.util.Collection;
156.49 -import static junit.framework.Assert.*;
156.50 -import org.openide.util.Lookup;
156.51 -import org.openide.util.lookup.Lookups;
156.52 -import org.openide.util.lookup.ProxyLookup;
156.53 -
156.54 -/**
156.55 - * Mock implementation of system default lookup suitable for use in unit tests.
156.56 - * The initial value just contains classpath services.
156.57 - */
156.58 -public class MockLookup extends ProxyLookup {
156.59 -
156.60 - private static MockLookup DEFAULT;
156.61 - private static boolean making = false;
156.62 - private static volatile boolean ready;
156.63 -
156.64 - static {
156.65 - making = true;
156.66 - try {
156.67 - System.setProperty("org.openide.util.Lookup", MockLookup.class.getName());
156.68 - if (Lookup.getDefault().getClass() != MockLookup.class) {
156.69 - // Someone else initialized lookup first. Try to force our way.
156.70 - Field defaultLookup = Lookup.class.getDeclaredField("defaultLookup");
156.71 - defaultLookup.setAccessible(true);
156.72 - defaultLookup.set(null, null);
156.73 - }
156.74 - assertEquals(MockLookup.class, Lookup.getDefault().getClass());
156.75 - } catch (Exception x) {
156.76 - throw new ExceptionInInitializerError(x);
156.77 - } finally {
156.78 - making = false;
156.79 - }
156.80 - }
156.81 -
156.82 - /** Do not call this directly! */
156.83 - public MockLookup() {
156.84 - assertTrue(making);
156.85 - assertNull(DEFAULT);
156.86 - DEFAULT = this;
156.87 - }
156.88 -
156.89 - /**
156.90 - * Just ensures that this lookup is default lookup, but does not actually change its content.
156.91 - * Useful mainly if you have some test utility method which calls foreign code which might use default lookup,
156.92 - * and you want to ensure that any users of mock lookup will see the correct default lookup right away,
156.93 - * even if they have not yet called {@link #setLookup} or {@link #setInstances}.
156.94 - */
156.95 - public static void init() {
156.96 - if (!ready) {
156.97 - setInstances();
156.98 - }
156.99 - }
156.100 -
156.101 - /**
156.102 - * Sets the global default lookup with zero or more delegate lookups.
156.103 - * Caution: if you don't include Lookups.metaInfServices, you may have trouble,
156.104 - * e.g. {@link #makeScratchDir} will not work.
156.105 - * Most of the time you should use {@link #setInstances} instead.
156.106 - */
156.107 - public static void setLookup(Lookup... lookups) {
156.108 - ready = true;
156.109 - DEFAULT.setLookups(lookups);
156.110 - }
156.111 -
156.112 - /**
156.113 - * Sets the global default lookup with some fixed instances.
156.114 - * Will also include (at a lower priority) a {@link ClassLoader},
156.115 - * and services found from <code>META-INF/services/*</code> in the classpath.
156.116 - */
156.117 - public static void setInstances(Object... instances) {
156.118 - ClassLoader l = MockLookup.class.getClassLoader();
156.119 - setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
156.120 - }
156.121 - /**
156.122 - * Sets the global default lookup with some fixed instances and
156.123 - * content read from Services folder from system file system.
156.124 - * Will also include (at a lower priority) a {@link ClassLoader},
156.125 - * and services found from <code>META-INF/services/*</code> in the classpath.
156.126 - */
156.127 - public static void setLayersAndInstances(Object... instances) {
156.128 - ClassLoader l = MockLookup.class.getClassLoader();
156.129 - if (l != Lookup.getDefault().lookup(ClassLoader.class)) {
156.130 - setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l));
156.131 - }
156.132 - Lookup projects = Lookups.forPath("Services");
156.133 - Collection<?> initialize = projects.lookupAll(Object.class);
156.134 - //System.err.println("all: " + initialize);
156.135 - setLookup(Lookups.fixed(instances), Lookups.metaInfServices(l), Lookups.singleton(l), projects);
156.136 - }
156.137 -
156.138 -}
157.1 --- a/openide.util/test/unit/src/org/openide/util/test/MockLookupTest.java Thu Dec 10 19:23:25 2009 -0500
157.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
157.3 @@ -1,66 +0,0 @@
157.4 -/*
157.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
157.6 - *
157.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
157.8 - *
157.9 - * The contents of this file are subject to the terms of either the GNU
157.10 - * General Public License Version 2 only ("GPL") or the Common
157.11 - * Development and Distribution License("CDDL") (collectively, the
157.12 - * "License"). You may not use this file except in compliance with the
157.13 - * License. You can obtain a copy of the License at
157.14 - * http://www.netbeans.org/cddl-gplv2.html
157.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
157.16 - * specific language governing permissions and limitations under the
157.17 - * License. When distributing the software, include this License Header
157.18 - * Notice in each file and include the License file at
157.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
157.20 - * particular file as subject to the "Classpath" exception as provided
157.21 - * by Sun in the GPL Version 2 section of the License file that
157.22 - * accompanied this code. If applicable, add the following below the
157.23 - * License Header, with the fields enclosed by brackets [] replaced by
157.24 - * your own identifying information:
157.25 - * "Portions Copyrighted [year] [name of copyright owner]"
157.26 - *
157.27 - * Contributor(s):
157.28 - *
157.29 - * The Original Software is NetBeans. The Initial Developer of the Original
157.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
157.31 - * Microsystems, Inc. All Rights Reserved.
157.32 - *
157.33 - * If you wish your version of this file to be governed by only the CDDL
157.34 - * or only the GPL Version 2, indicate your decision by adding
157.35 - * "[Contributor] elects to include this software in this distribution
157.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
157.37 - * single choice of license, a recipient has the option to distribute
157.38 - * your version of this file under either the CDDL, the GPL Version 2 or
157.39 - * to extend the choice of license to its licensees as provided above.
157.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
157.41 - * Version 2 license, then the option applies only if the new code is
157.42 - * made subject to such option by the copyright holder.
157.43 - */
157.44 -
157.45 -package org.openide.util.test;
157.46 -
157.47 -import junit.framework.TestCase;
157.48 -import org.openide.util.Lookup;
157.49 -
157.50 -public class MockLookupTest extends TestCase {
157.51 -
157.52 - // XXX test:
157.53 - // setLookup with one or more lookup args does not use M-I/s
157.54 - // still works if another Lookup.getDefault was set before
157.55 -
157.56 - public MockLookupTest(String n) {
157.57 - super(n);
157.58 - }
157.59 -
157.60 - public void testSetLookup() throws Exception {
157.61 - MockLookup.setInstances("hello");
157.62 - assertEquals("initial lookup works", "hello", Lookup.getDefault().lookup(String.class));
157.63 - MockLookup.setInstances("goodbye");
157.64 - assertEquals("modified lookup works", "goodbye", Lookup.getDefault().lookup(String.class));
157.65 - MockLookup.setInstances();
157.66 - assertEquals("cleared lookup works", null, Lookup.getDefault().lookup(String.class));
157.67 - }
157.68 -
157.69 -}