179289: remove impl deps from platform cluster.
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
1.2 +++ b/openide.util.lookup/apichanges.xml Fri Jan 22 10:02:41 2010 -0500
1.3 @@ -0,0 +1,495 @@
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="named.services.provider">
1.53 + <api name="lookup"/>
1.54 + <summary>Introducing semihidden SPI</summary>
1.55 + <version major="8" minor="1"/>
1.56 + <date day="15" month="1" year="2010"/>
1.57 + <author login="jtulach"/>
1.58 + <compatibility
1.59 + addition="yes"
1.60 + binary="compatible" deletion="no" deprecation="no"
1.61 + modification="no" semantic="compatible" source="compatible"
1.62 + />
1.63 + <description>
1.64 + <p>
1.65 + Adding SPI interface package for those who implement
1.66 + the NetBeans platform. This package is not shown in Javadoc
1.67 + as it does not form a generally available public API.
1.68 + </p>
1.69 + </description>
1.70 + <issue number="179289"/>
1.71 + </change>
1.72 + <change id="lookup.is.free">
1.73 + <api name="lookup"/>
1.74 + <summary>Separate module for Lookup API</summary>
1.75 + <version major="8" minor="0"/>
1.76 + <date day="20" month="12" year="2009"/>
1.77 + <author login="jtulach"/>
1.78 + <compatibility modification="yes">
1.79 + <p>
1.80 + Runtime compatibility remains, compile time compatibility is
1.81 + mostly preserved too. It is however recommended to upgrade
1.82 + dependencies of your modules. Try running
1.83 + <code>ant fix-dependencies</code> in your Ant module.
1.84 + </p>
1.85 + </compatibility>
1.86 + <description>
1.87 + <p>
1.88 + <a href="@org-openide-util-lookup@/org/openide/util/Lookup.html">Lookup</a>
1.89 + and its associated interfaces are now available as a
1.90 + <a href="@org-openide-util-lookup@/overview-summary.html">separate module</a>.
1.91 + </p>
1.92 + </description>
1.93 + <class package="org.openide.util" name="Lookup"/>
1.94 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.95 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.96 + <class package="org.openide.util.lookup" name="Lookups"/>
1.97 + <issue number="170056"/>
1.98 + </change>
1.99 + <change id="org.openide.util.Lookup.paths">
1.100 + <api name="lookup"/>
1.101 + <summary>Added
1.102 + <code>org.openide.util.Lookup.paths</code> property
1.103 + </summary>
1.104 + <version major="7" minor="24"/>
1.105 + <date day="19" month="6" year="2009"/>
1.106 + <author login="jtulach"/>
1.107 + <compatibility addition="yes"/>
1.108 + <description>
1.109 + <p>
1.110 + Better way to integrate Lookup.getDefault() and system filesystem.
1.111 + </p>
1.112 + </description>
1.113 + <class package="org.openide.util" name="Lookup"/>
1.114 + <issue number="166782"/>
1.115 + </change>
1.116 + <change id="ServiceProvider">
1.117 + <api name="lookup"/>
1.118 + <summary>Added <code>ServiceProvider</code> annotation</summary>
1.119 + <version major="7" minor="20"/>
1.120 + <date day="1" month="11" year="2008"/>
1.121 + <author login="jglick"/>
1.122 + <compatibility addition="yes">
1.123 + <p>
1.124 + Modules registering services using <code>META-INF/services</code>
1.125 + files in the source tree are encouraged to switch to the annotation.
1.126 + </p>
1.127 + </compatibility>
1.128 + <description>
1.129 + <p>
1.130 + Added annotations <code>ServiceProvider</code> and <code>ServiceProviders</code>
1.131 + to simplify registration of global singleton services.
1.132 + </p>
1.133 + </description>
1.134 + <class package="org.openide.util.lookup" name="ServiceProvider"/>
1.135 + <class package="org.openide.util.lookup" name="ServiceProviders"/>
1.136 + <issue number="150447"/>
1.137 + </change>
1.138 + <change id="Lookup.asynchronous">
1.139 + <api name="lookup"/>
1.140 + <summary>AbstractLookup and ProxyLookup fire changes asynchronously</summary>
1.141 + <version major="7" minor="16"/>
1.142 + <date day="27" month="6" year="2008"/>
1.143 + <author login="jtulach"/>
1.144 + <compatibility addition="yes" binary="compatible" semantic="compatible"/>
1.145 + <description>
1.146 + <p>
1.147 + All modification methods in <code>AbstractLookup</code> and <code>ProxyLookup</code>
1.148 + were extended to accept an
1.149 + <a href="@JDK@/java/util/concurrent/Executor.html">Executor</a>.
1.150 + If not null, it is used to dispatch events to listeners sometime
1.151 + "later". Also the <code>AbstractLookup.Content</code>
1.152 + and <code>InstanceContent</code> constructors
1.153 + have been extended to accept such <code>Executor</code>s.
1.154 + </p>
1.155 + </description>
1.156 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.157 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.158 + <class package="org.openide.util.lookup" name="InstanceContent"/>
1.159 + <issue number="134297"/>
1.160 + </change>
1.161 +
1.162 + <change id="Lookups.forPath">
1.163 + <api name="lookup"/>
1.164 + <summary>Added simplified support for named lookups <code>Lookups.forPath</code></summary>
1.165 + <version major="7" minor="9"/>
1.166 + <date day="17" month="4" year="2007"/>
1.167 + <author login="jtulach"/>
1.168 + <compatibility addition="yes"/>
1.169 + <description>
1.170 + <p>
1.171 + New method <a href="@TOP@/org/openide/util/lookup/Lookups.html#forPath(java.lang.String)">Lookups.forPath(String)</a>
1.172 + has been added to replace now deprecated <a href="@org-openide-loaders@/org/openide/loaders/FolderLookup.html">FolderLookup</a>
1.173 + and allow modules who wants to read settings from layers
1.174 + to do so with a simpler code, without dependency on DataSystems API.
1.175 + </p>
1.176 + </description>
1.177 + <class package="org.openide.util.lookup" name="Lookups"/>
1.178 + <issue number="98426"/>
1.179 + </change>
1.180 +
1.181 + <change id="lookupAll-lookupResult">
1.182 + <api name="lookup"/>
1.183 + <summary>Convenience methods added to <code>Lookup</code></summary>
1.184 + <version major="6" minor="10"/>
1.185 + <date day="3" month="4" year="2006"/>
1.186 + <author login="jglick"/>
1.187 + <compatibility addition="yes" binary="compatible" source="incompatible">
1.188 + <p>
1.189 + Could conceivably conflict with existing subclass method with same signature
1.190 + with different semantics or return type.
1.191 + </p>
1.192 + </compatibility>
1.193 + <description>
1.194 + <p>
1.195 + Two methods, <code>lookupResult</code> and <code>lookupAll</code>, were
1.196 + added to <code>Lookup</code> to encapsulate the most common usage patterns
1.197 + with less typing, and more importantly avoiding the need to explicitly
1.198 + make a <code>Lookup.Template</code> object.
1.199 + </p>
1.200 + </description>
1.201 + <class package="org.openide.util" name="Lookup"/>
1.202 + <issue number="73848"/>
1.203 + </change>
1.204 + <change id="less-events-from-proxylookup" >
1.205 + <api name="lookup"/>
1.206 + <summary>Less change notifications from ProxyLookup</summary>
1.207 + <version major="6" minor="7"/>
1.208 + <date day="11" month="11" year="2005"/>
1.209 + <author login="jtulach"/>
1.210 + <compatibility addition="no" modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no"/>
1.211 + <description>
1.212 + <a href="@TOP@/org/openide/util/lookup/ProxyLookup.html">ProxyLookup.setLookups</a>
1.213 + used to fire <a href="@TOP@/org/openide/util/LookupEvent.html">LookupEvent</a> every
1.214 + time it was called. Now it always checks whether there was a change to the
1.215 + previous state. This will reduce the number of events delivered when a small
1.216 + change is made. Also results from both
1.217 + <a href="@TOP@/org/openide/util/lookup/ProxyLookup.html">ProxyLookup</a>
1.218 + and <a href="@TOP@/org/openide/util/lookup/AbstractLookup.html">AbstractLookup</a>
1.219 + were modified to return immutable <code>Collection</code>s.
1.220 + So do not try to modify them. It was always documented that the
1.221 + results, are immutable and also it was never said that a change is
1.222 + delivered when there is no change in the result, so this is considered
1.223 + compatible change, even it is know that at least one piece of code
1.224 + in NetBeans relied on this behaviour.
1.225 + </description>
1.226 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.227 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.228 + <issue number="68031"/>
1.229 + </change>
1.230 +
1.231 +
1.232 + <change id="excluding-lookup">
1.233 + <api name="lookup"/>
1.234 + <summary>
1.235 +<code>Lookups.exclude</code> added to simplify writing of lookups that filter content of other lookups</summary>
1.236 + <version major="5" minor="4"/>
1.237 + <date day="14" month="1" year="2005"/>
1.238 + <author login="jtulach"/>
1.239 + <compatibility binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no" modification="no"/>
1.240 + <description>
1.241 + <p>New method that takes lookup and set of classes and return new lookup
1.242 + which contains everything from the original one except instances of
1.243 + the specified classes has been added.
1.244 + </p>
1.245 + </description>
1.246 + <class package="org.openide.util.lookup" name="Lookups"/>
1.247 + <issue number="53058"/>
1.248 + </change>
1.249 + <change>
1.250 + <api name="lookup"/>
1.251 + <summary>Added ability to order items in META-INF/services/ lookup</summary>
1.252 + <version major="4" minor="34"/>
1.253 + <date day="9" month="5" year="2004"/>
1.254 + <author login="dkonecny"/>
1.255 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.256 + <description>
1.257 + Items in META-INF/services/ lookup can be followed by advisory
1.258 + "position" attribute. The resulting lookup will list first items with lower
1.259 + position value. Items without position attribute will be listed
1.260 + last. See documentation for more details on format.
1.261 + </description>
1.262 + <class package="org.openide.util.lookup" name="Lookups"/>
1.263 + <issue number="41606"/>
1.264 + </change>
1.265 + <change>
1.266 + <api name="lookup"/>
1.267 + <summary>New <code>lookupItem()</code> method in Lookups</summary>
1.268 + <version major="4" minor="8"/>
1.269 + <date day="9" month="7" year="2003"/>
1.270 + <author login="vstejskal"/>
1.271 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.272 + <description>
1.273 + New method that returns Lookup.Item implementation for given instance and key identifying
1.274 + that instance in the lookup. This method is useful when writing Looks which need to
1.275 + return some cookies (Collection of Lookup.Items).
1.276 + </description>
1.277 + <class package="org.openide.util.lookup" name="Lookups"/>
1.278 + </change>
1.279 + <change>
1.280 + <api name="lookup"/>
1.281 + <summary>New method Lookups.metaInfServices</summary>
1.282 + <version major="3" minor="35"/>
1.283 + <date day="5" month="2" year="2003"/>
1.284 + <author login="dstrupl"/>
1.285 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.286 + <description>
1.287 + A lookup that implements the JDK1.3 JAR services mechanism and delegates
1.288 + to META-INF/services/name.of.class files. This lookup was (is) used by core
1.289 + and the core had to use reflection to create an instance. Moreover can
1.290 + be usefull for module authors and in standalone library.
1.291 + </description>
1.292 + <class package="org.openide.util.lookup" name="Lookups"/>
1.293 + <issue number="29126"/>
1.294 + </change>
1.295 + <change>
1.296 + <api name="lookup"/>
1.297 + <summary>New method Lookups.proxy</summary>
1.298 + <version major="3" minor="9"/>
1.299 + <date day="20" month="9" year="2002"/>
1.300 + <author login="dstrupl"/>
1.301 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.302 + <description>
1.303 + Creates a lookup that delegates to another one but that one can change
1.304 + from time to time. The returned lookup checks every time somebody calls
1.305 + lookup or lookupItem method whether the provider still returns
1.306 + the same lookup. If not, it updates state of all Lookup.Results
1.307 + that it created (and that still exists).
1.308 + </description>
1.309 + <class package="org.openide.util.lookup" name="Lookups"/>
1.310 + <issue number="27425"/>
1.311 + </change>
1.312 + <change id="meta-inf-services">
1.313 + <api name="lookup"/>
1.314 + <summary>Modules can specify the content of Lookup.getDefault
1.315 + in META-INF/services</summary>
1.316 + <version major="3" minor="3"/>
1.317 + <date day="22" month="7" year="2002"/>
1.318 + <author login="jtulach"/>
1.319 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.320 + <description>
1.321 + The content of <code>Lookup.getDefault()</code> can be specified
1.322 + by a standard JDK registration mechanism, using JARs'
1.323 + <a href="http://java.sun.com/j2se/1.4/docs/guide/jar/jar.html#Service%20Provider" shape="rect">
1.324 + META-INF/services
1.325 + </a>
1.326 + directory. This is suitable for services that do not change,
1.327 + do not require user modification and that need to be ready
1.328 + soon during initialization of the system.
1.329 + </description>
1.330 + </change>
1.331 + <change>
1.332 + <api name="lookup"/>
1.333 + <summary>Added org.openide.util.lookup.Lookups</summary>
1.334 + <version major="2" minor="21"/>
1.335 + <date day="28" month="5" year="2002"/>
1.336 + <author login="dstrupl"/>
1.337 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.338 + <description>New utility class added. The class cannot be instantiated
1.339 + and contains following static methods:
1.340 + <pre xml:space="preserve">
1.341 +<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.342 +<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.343 +<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.344 +</pre>
1.345 + The methods return an instance of simple lookup implementation
1.346 + that holds the objects passed a parameter.
1.347 + </description>
1.348 + <class package="org.openide.util.lookup" name="Lookups"/>
1.349 + <issue number="20550"/>
1.350 + </change>
1.351 + <change id="AbstractLookup.Content-ProxyLookup.beforeLookup">
1.352 + <api name="lookup"/>
1.353 + <summary>Enhanced usage of ProxyLookup & AbstractLookup.Content</summary>
1.354 + <version major="1" minor="31"/>
1.355 + <date day="18" month="8" year="2001"/>
1.356 + <author login="jtulach"/>
1.357 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.358 + <description>
1.359 + <code>AbstractLookup.Content</code> made public to allow its usage
1.360 + for objects that do not subclass AbstractLookup. <code>ProxyLookup.beforeLookup</code>
1.361 + added so subclasses can update themselves (call setLookups (...)) before the actual lookup is
1.362 + performed.
1.363 + </description>
1.364 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.365 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.366 + </change>
1.367 + <change>
1.368 + <api name="lookup"/>
1.369 + <summary>Instance content simplifies creation of lookups</summary>
1.370 + <version major="1" minor="25"/>
1.371 + <!-- XXX date unknown -->
1.372 + <author login="jtulach"/>
1.373 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.374 + <description>
1.375 + Added <code>AbstractLookup.Content</code> which can be passed to an
1.376 + abstract lookup in its constructor and used to control the contents
1.377 + easily. Also <code>InstanceLookup</code> provides the common easy
1.378 + implementation.
1.379 + </description>
1.380 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.381 + <class package="org.openide.util.lookup" name="InstanceContent"/>
1.382 + </change>
1.383 + <change>
1.384 + <api name="lookup"/>
1.385 + <summary>Folder lookup may be serialized</summary>
1.386 + <version major="3" minor="27"/>
1.387 + <date day="7" month="1" year="2003"/>
1.388 + <author login="jglick"/>
1.389 + <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no">
1.390 + Modules which rely on a data object under <samp>Services/</samp> gaining
1.391 + or losing <code>InstanceCookie</code> between sessions may not work
1.392 + correctly with the cache. This is probably very rare.
1.393 + </compatibility>
1.394 + <description>
1.395 + To implement lookup caching, some lookup implementations are now
1.396 + serializable: <code>AbstractLookup</code> as well as
1.397 + <code>FolderLookup</code>'s lookup. <code>ProxyLookup</code> has a
1.398 + protected subclass constructor permitting subclasses to be serializable.
1.399 + </description>
1.400 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.401 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.402 + <issue number="20190"/>
1.403 + </change>
1.404 + <change>
1.405 + <api name="lookup"/>
1.406 + <summary>Changes in access protection of proxy lookup</summary>
1.407 + <version major="1" minor="19"/>
1.408 + <date day="8" month="7" year="2001"/>
1.409 + <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no">
1.410 + Changes to newly added feature.
1.411 + </compatibility>
1.412 + <description>
1.413 + <code>ProxyLookup.setLookups</code> made protected instead of public so
1.414 + nobody can misuse the method except the creator of the object and
1.415 + <code>ProxyLookup.getLookups</code> added. <code>ProxyLookup</code> made
1.416 + non final.
1.417 + </description>
1.418 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.419 + </change>
1.420 + <change>
1.421 + <api name="lookup"/>
1.422 + <summary>Lookup service providers package created</summary>
1.423 + <version major="1" minor="9"/>
1.424 + <date day="1" month="6" year="2001"/>
1.425 + <author login="jtulach"/>
1.426 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.427 + <description>
1.428 + Package <code>org.openide.util.lookup</code> created, should hold SPI
1.429 + interfaces for lookup. Initially filled with <code>AbstractLookup</code>
1.430 + which introduces <code>AbstractLookup.Pair</code> and with
1.431 + <code>ProxyLookup</code>.
1.432 + </description>
1.433 + <class package="org.openide.util.lookup" name="AbstractLookup"/>
1.434 + <class package="org.openide.util.lookup" name="ProxyLookup"/>
1.435 + <package name="org.openide.util.lookup"/>
1.436 + </change>
1.437 + <change>
1.438 + <api name="lookup"/>
1.439 + <summary>Added lookup items and support APIs</summary>
1.440 + <version major="1" minor="8"/>
1.441 + <date day="25" month="5" year="2001"/>
1.442 + <author login="jtulach"/>
1.443 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.444 + <description>
1.445 + <code>Lookup</code> enhanced. Interface <code>Lookup.Item</code> and
1.446 + additional methods to access it also added.
1.447 + </description>
1.448 + <class package="org.openide.util" name="Lookup"/>
1.449 + </change>
1.450 + <change>
1.451 + <api name="lookup"/>
1.452 + <summary>Lookup system introduced</summary>
1.453 + <date day="1" month="3" year="2001"/>
1.454 + <author login="jtulach"/>
1.455 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
1.456 + <description>
1.457 + Better version of <code>Lookup</code> introduced. There is a
1.458 + <code>org.openide.util.Lookup</code> with bunch of inner classes and
1.459 + <code>org.openide.util.LookupListener</code> and
1.460 + <code>org.openide.util.LookupEvent</code>.
1.461 + </description>
1.462 + <class package="org.openide.util" name="Lookup"/>
1.463 + <class package="org.openide.util" name="LookupEvent"/>
1.464 + <class package="org.openide.util" name="LookupListener"/>
1.465 + </change>
1.466 +</changes>
1.467 +<htmlcontents>
1.468 +<head>
1.469 +<title>Change History for the Lookup API</title>
1.470 +<link rel="stylesheet" href="prose.css" type="text/css"/>
1.471 +</head>
1.472 +<body>
1.473 +<p class="overviewlink">
1.474 +<a href="overview-summary.html">Overview</a>
1.475 +</p>
1.476 +<h1>Introduction</h1>
1.477 +<h2>What do the Dates Mean?</h2>
1.478 +<p>The supplied dates indicate when the API change was made, on the CVS
1.479 +trunk. From this you can generally tell whether the change should be
1.480 +present in a given build or not; for trunk builds, simply whether it
1.481 +was made before or after the change; for builds on a stabilization
1.482 +branch, whether the branch was made before or after the given date. In
1.483 +some cases corresponding API changes have been made both in the trunk
1.484 +and in an in-progress stabilization branch, if they were needed for a
1.485 +bug fix; this ought to be marked in this list.</p>
1.486 +<ul>
1.487 +<li>The <code>release41</code> branch was made on Apr 03 '05 for use in the NetBeans 4.1 release.
1.488 +Specification versions: 6.0 begins after this point.</li>
1.489 +<li>The <code>release40</code> branch was made on Nov 01 '04 for use in the NetBeans 4.0 release.
1.490 +Specification versions: 5.0 begins after this point.</li>
1.491 +</ul>
1.492 +<hr/>
1.493 +<standard-changelists module-code-name="$codebase"/>
1.494 +<hr/>
1.495 +<p>@FOOTER@</p>
1.496 +</body>
1.497 +</htmlcontents>
1.498 +</apichanges>
2.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
2.2 +++ b/openide.util.lookup/manifest.mf Fri Jan 22 10:02:41 2010 -0500
2.3 @@ -0,0 +1,5 @@
2.4 +Manifest-Version: 1.0
2.5 +OpenIDE-Module: org.openide.util.lookup
2.6 +OpenIDE-Module-Localizing-Bundle: org/openide/util/lookup/Bundle.properties
2.7 +OpenIDE-Module-Specification-Version: 8.1
2.8 +
3.1 --- a/openide.util.lookup/nbproject/project.properties Fri Jan 22 10:09:12 2010 -0500
3.2 +++ b/openide.util.lookup/nbproject/project.properties Fri Jan 22 10:02:41 2010 -0500
3.3 @@ -40,7 +40,8 @@
3.4 module.jar.dir=lib
3.5 javac.source=1.6
3.6 javac.compilerargs=-Xlint -Xlint:-serial
3.7 -spec.version.base=8.0.0
3.8
3.9 javadoc.arch=${basedir}/arch.xml
3.10 javadoc.apichanges=${basedir}/apichanges.xml
3.11 +# Hide org.openide.util.lookup.implspi:
3.12 +module.javadoc.packages=org.openide.util,org.openide.util.lookup
4.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
4.2 +++ b/openide.util.lookup/nbproject/project.xml Fri Jan 22 10:02:41 2010 -0500
4.3 @@ -0,0 +1,29 @@
4.4 +<?xml version="1.0" encoding="UTF-8"?>
4.5 +<project xmlns="http://www.netbeans.org/ns/project/1">
4.6 + <type>org.netbeans.modules.apisupport.project</type>
4.7 + <configuration>
4.8 + <data xmlns="http://www.netbeans.org/ns/nb-module-project/3">
4.9 + <code-name-base>org.openide.util.lookup</code-name-base>
4.10 + <module-dependencies/>
4.11 + <test-dependencies>
4.12 + <test-type>
4.13 + <name>unit</name>
4.14 + <test-dependency>
4.15 + <code-name-base>org.netbeans.libs.junit4</code-name-base>
4.16 + <compile-dependency/>
4.17 + </test-dependency>
4.18 + <test-dependency>
4.19 + <code-name-base>org.netbeans.modules.nbjunit</code-name-base>
4.20 + <recursive/>
4.21 + <compile-dependency/>
4.22 + </test-dependency>
4.23 + </test-type>
4.24 + </test-dependencies>
4.25 + <public-packages>
4.26 + <package>org.openide.util</package>
4.27 + <package>org.openide.util.lookup</package>
4.28 + <package>org.openide.util.lookup.implspi</package>
4.29 + </public-packages>
4.30 + </data>
4.31 + </configuration>
4.32 +</project>
5.1 --- a/openide.util.lookup/src/org/netbeans/modules/openide/util/AbstractServiceProviderProcessor.java Fri Jan 22 10:09:12 2010 -0500
5.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
5.3 @@ -1,296 +0,0 @@
5.4 -/*
5.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
5.6 - *
5.7 - * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
5.8 - *
5.9 - * The contents of this file are subject to the terms of either the GNU
5.10 - * General Public License Version 2 only ("GPL") or the Common
5.11 - * Development and Distribution License("CDDL") (collectively, the
5.12 - * "License"). You may not use this file except in compliance with the
5.13 - * License. You can obtain a copy of the License at
5.14 - * http://www.netbeans.org/cddl-gplv2.html
5.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
5.16 - * specific language governing permissions and limitations under the
5.17 - * License. When distributing the software, include this License Header
5.18 - * Notice in each file and include the License file at
5.19 - * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
5.20 - * particular file as subject to the "Classpath" exception as provided
5.21 - * by Sun in the GPL Version 2 section of the License file that
5.22 - * accompanied this code. If applicable, add the following below the
5.23 - * License Header, with the fields enclosed by brackets [] replaced by
5.24 - * your own identifying information:
5.25 - * "Portions Copyrighted [year] [name of copyright owner]"
5.26 - *
5.27 - * If you wish your version of this file to be governed by only the CDDL
5.28 - * or only the GPL Version 2, indicate your decision by adding
5.29 - * "[Contributor] elects to include this software in this distribution
5.30 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
5.31 - * single choice of license, a recipient has the option to distribute
5.32 - * your version of this file under either the CDDL, the GPL Version 2 or
5.33 - * to extend the choice of license to its licensees as provided above.
5.34 - * However, if you add GPL Version 2 code and therefore, elected the GPL
5.35 - * Version 2 license, then the option applies only if the new code is
5.36 - * made subject to such option by the copyright holder.
5.37 - *
5.38 - * Contributor(s):
5.39 - *
5.40 - * Portions Copyrighted 2009 Sun Microsystems, Inc.
5.41 - */
5.42 -
5.43 -package org.netbeans.modules.openide.util;
5.44 -
5.45 -import java.io.BufferedReader;
5.46 -import java.io.FileNotFoundException;
5.47 -import java.io.IOException;
5.48 -import java.io.InputStream;
5.49 -import java.io.InputStreamReader;
5.50 -import java.io.OutputStream;
5.51 -import java.io.OutputStreamWriter;
5.52 -import java.io.PrintWriter;
5.53 -import java.lang.annotation.Annotation;
5.54 -import java.util.ArrayList;
5.55 -import java.util.HashMap;
5.56 -import java.util.List;
5.57 -import java.util.Map;
5.58 -import java.util.Set;
5.59 -import java.util.WeakHashMap;
5.60 -import javax.annotation.processing.AbstractProcessor;
5.61 -import javax.annotation.processing.ProcessingEnvironment;
5.62 -import javax.annotation.processing.RoundEnvironment;
5.63 -import javax.lang.model.element.AnnotationMirror;
5.64 -import javax.lang.model.element.AnnotationValue;
5.65 -import javax.lang.model.element.Element;
5.66 -import javax.lang.model.element.ExecutableElement;
5.67 -import javax.lang.model.element.Modifier;
5.68 -import javax.lang.model.element.TypeElement;
5.69 -import javax.lang.model.type.TypeMirror;
5.70 -import javax.lang.model.util.ElementFilter;
5.71 -import javax.tools.Diagnostic.Kind;
5.72 -import javax.tools.FileObject;
5.73 -import javax.tools.StandardLocation;
5.74 -
5.75 -/**
5.76 - * Infrastructure for generating {@code META-INF/services/*} and
5.77 - * {@code META-INF/namedservices/*} registrations from annotations.
5.78 - */
5.79 -public abstract class AbstractServiceProviderProcessor extends AbstractProcessor {
5.80 -
5.81 - private final Map<ProcessingEnvironment,Map<String,List<String>>> outputFilesByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<String>>>();
5.82 - private final Map<ProcessingEnvironment,Map<String,List<Element>>> originatingElementsByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<Element>>>();
5.83 - private final Map<TypeElement,Boolean> verifiedClasses = new WeakHashMap<TypeElement,Boolean>();
5.84 -
5.85 - /** For access by subclasses. */
5.86 - protected AbstractServiceProviderProcessor() {}
5.87 -
5.88 - public @Override final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
5.89 - if (roundEnv.errorRaised()) {
5.90 - return false;
5.91 - }
5.92 - if (roundEnv.processingOver()) {
5.93 - writeServices();
5.94 - outputFilesByProcessor.clear();
5.95 - originatingElementsByProcessor.clear();
5.96 - return true;
5.97 - } else {
5.98 - return handleProcess(annotations, roundEnv);
5.99 - }
5.100 - }
5.101 -
5.102 - /**
5.103 - * The regular body of {@link #process}.
5.104 - * Called during regular rounds if there are no outstanding errors.
5.105 - * In the last round, one of the processors will write out generated registrations.
5.106 - * @param annotations as in {@link #process}
5.107 - * @param roundEnv as in {@link #process}
5.108 - * @return as in {@link #process}
5.109 - */
5.110 - protected abstract boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);
5.111 -
5.112 - /**
5.113 - * Register a service.
5.114 - * If the class does not have an appropriate signature, an error will be printed and the registration skipped.
5.115 - * @param clazz the service implementation type
5.116 - * @param annotation the (top-level) annotation registering the service, for diagnostic purposes
5.117 - * @param type the type to which the implementation must be assignable
5.118 - * @param path a path under which to register, or "" if inapplicable
5.119 - * @param position a position at which to register, or {@link Integer#MAX_VALUE} to skip
5.120 - * @param supersedes possibly empty list of implementation to supersede
5.121 - */
5.122 - protected final void register(TypeElement clazz, Class<? extends Annotation> annotation,
5.123 - TypeMirror type, String path, int position, String[] supersedes) {
5.124 - Boolean verify = verifiedClasses.get(clazz);
5.125 - if (verify == null) {
5.126 - verify = verifyServiceProviderSignature(clazz, annotation);
5.127 - verifiedClasses.put(clazz, verify);
5.128 - }
5.129 - if (!verify) {
5.130 - return;
5.131 - }
5.132 - String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
5.133 - String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
5.134 - if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
5.135 - AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
5.136 - processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
5.137 - clazz, ann, findAnnotationValue(ann, "service"));
5.138 - return;
5.139 - }
5.140 - processingEnv.getMessager().printMessage(Kind.NOTE,
5.141 - impl + " to be registered as a " + xface + (path.length() > 0 ? " under " + path : ""));
5.142 - String rsrc = (path.length() > 0 ? "META-INF/namedservices/" + path + "/" : "META-INF/services/") + xface;
5.143 - {
5.144 - Map<String,List<Element>> originatingElements = originatingElementsByProcessor.get(processingEnv);
5.145 - if (originatingElements == null) {
5.146 - originatingElements = new HashMap<String,List<Element>>();
5.147 - originatingElementsByProcessor.put(processingEnv, originatingElements);
5.148 - }
5.149 - List<Element> origEls = originatingElements.get(rsrc);
5.150 - if (origEls == null) {
5.151 - origEls = new ArrayList<Element>();
5.152 - originatingElements.put(rsrc, origEls);
5.153 - }
5.154 - origEls.add(clazz);
5.155 - }
5.156 - Map<String,List<String>> outputFiles = outputFilesByProcessor.get(processingEnv);
5.157 - if (outputFiles == null) {
5.158 - outputFiles = new HashMap<String,List<String>>();
5.159 - outputFilesByProcessor.put(processingEnv, outputFiles);
5.160 - }
5.161 - List<String> lines = outputFiles.get(rsrc);
5.162 - if (lines == null) {
5.163 - lines = new ArrayList<String>();
5.164 - try {
5.165 - try {
5.166 - FileObject in = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", rsrc);
5.167 - in.openInputStream().close();
5.168 - processingEnv.getMessager().printMessage(Kind.ERROR,
5.169 - "Cannot generate " + rsrc + " because it already exists in sources: " + in.toUri());
5.170 - return;
5.171 - } catch (NullPointerException ex) {
5.172 - // trying to prevent java.lang.NullPointerException
5.173 - // at com.sun.tools.javac.util.DefaultFileManager.getFileForOutput(DefaultFileManager.java:1078)
5.174 - // at com.sun.tools.javac.util.DefaultFileManager.getFileForOutput(DefaultFileManager.java:1054)
5.175 - // at com.sun.tools.javac.processing.JavacFiler.getResource(JavacFiler.java:434)
5.176 - // at org.netbeans.modules.openide.util.AbstractServiceProviderProcessor.register(AbstractServiceProviderProcessor.java:163)
5.177 - // at org.netbeans.modules.openide.util.ServiceProviderProcessor.register(ServiceProviderProcessor.java:99)
5.178 - } catch (FileNotFoundException x) {
5.179 - // Good.
5.180 - }
5.181 - try {
5.182 - FileObject in = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", rsrc);
5.183 - InputStream is = in.openInputStream();
5.184 - try {
5.185 - BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
5.186 - String line;
5.187 - while ((line = r.readLine()) != null) {
5.188 - lines.add(line);
5.189 - }
5.190 - } finally {
5.191 - is.close();
5.192 - }
5.193 - } catch (FileNotFoundException x) {
5.194 - // OK, created for the first time
5.195 - }
5.196 - } catch (IOException x) {
5.197 - processingEnv.getMessager().printMessage(Kind.ERROR, x.toString());
5.198 - return;
5.199 - }
5.200 - outputFiles.put(rsrc, lines);
5.201 - }
5.202 - int idx = lines.indexOf(impl);
5.203 - if (idx != -1) {
5.204 - lines.remove(idx);
5.205 - while (lines.size() > idx && lines.get(idx).matches("#position=.+|#-.+")) {
5.206 - lines.remove(idx);
5.207 - }
5.208 - }
5.209 - lines.add(impl);
5.210 - if (position != Integer.MAX_VALUE) {
5.211 - lines.add("#position=" + position);
5.212 - }
5.213 - for (String exclude : supersedes) {
5.214 - lines.add("#-" + exclude);
5.215 - }
5.216 - }
5.217 -
5.218 - /**
5.219 - * @param element a source element
5.220 - * @param annotation a type of annotation
5.221 - * @return the instance of that annotation on the element, or null if not found
5.222 - */
5.223 - private AnnotationMirror findAnnotationMirror(Element element, Class<? extends Annotation> annotation) {
5.224 - for (AnnotationMirror ann : element.getAnnotationMirrors()) {
5.225 - if (processingEnv.getElementUtils().getBinaryName((TypeElement) ann.getAnnotationType().asElement()).
5.226 - contentEquals(annotation.getName())) {
5.227 - return ann;
5.228 - }
5.229 - }
5.230 - return null;
5.231 - }
5.232 -
5.233 - /**
5.234 - * @param annotation an annotation instance (null permitted)
5.235 - * @param name the name of an attribute of that annotation
5.236 - * @return the corresponding value if found
5.237 - */
5.238 - private AnnotationValue findAnnotationValue(AnnotationMirror annotation, String name) {
5.239 - if (annotation != null) {
5.240 - for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()) {
5.241 - if (entry.getKey().getSimpleName().contentEquals(name)) {
5.242 - return entry.getValue();
5.243 - }
5.244 - }
5.245 - }
5.246 - return null;
5.247 - }
5.248 -
5.249 - private final boolean verifyServiceProviderSignature(TypeElement clazz, Class<? extends Annotation> annotation) {
5.250 - AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
5.251 - if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
5.252 - processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must be public", clazz, ann);
5.253 - return false;
5.254 - }
5.255 - if (clazz.getModifiers().contains(Modifier.ABSTRACT)) {
5.256 - processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must not be abstract", clazz, ann);
5.257 - return false;
5.258 - }
5.259 - {
5.260 - boolean hasDefaultCtor = false;
5.261 - for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
5.262 - if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) {
5.263 - hasDefaultCtor = true;
5.264 - break;
5.265 - }
5.266 - }
5.267 - if (!hasDefaultCtor) {
5.268 - processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must have a public no-argument constructor", clazz, ann);
5.269 - return false;
5.270 - }
5.271 - }
5.272 - return true;
5.273 - }
5.274 -
5.275 - private void writeServices() {
5.276 - for (Map.Entry<ProcessingEnvironment,Map<String,List<String>>> outputFiles : outputFilesByProcessor.entrySet()) {
5.277 - for (Map.Entry<String, List<String>> entry : outputFiles.getValue().entrySet()) {
5.278 - try {
5.279 - FileObject out = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", entry.getKey(),
5.280 - originatingElementsByProcessor.get(outputFiles.getKey()).get(entry.getKey()).toArray(new Element[0]));
5.281 - OutputStream os = out.openOutputStream();
5.282 - try {
5.283 - PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
5.284 - for (String line : entry.getValue()) {
5.285 - w.println(line);
5.286 - }
5.287 - w.flush();
5.288 - w.close();
5.289 - } finally {
5.290 - os.close();
5.291 - }
5.292 - } catch (IOException x) {
5.293 - processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
5.294 - }
5.295 - }
5.296 - }
5.297 - }
5.298 -
5.299 -}
6.1 --- a/openide.util.lookup/src/org/netbeans/modules/openide/util/ActiveQueue.java Fri Jan 22 10:09:12 2010 -0500
6.2 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000
6.3 @@ -1,108 +0,0 @@
6.4 -package org.netbeans.modules.openide.util;
6.5 -
6.6 -import java.lang.ref.Reference;
6.7 -import java.lang.ref.ReferenceQueue;
6.8 -import java.util.logging.Level;
6.9 -import java.util.logging.Logger;
6.10 -
6.11 -/**
6.12 - * Implementation of the active reference queue.
6.13 - */
6.14 -public final class ActiveQueue extends ReferenceQueue<Object> implements Runnable {
6.15 -
6.16 - private static final Logger LOGGER = Logger.getLogger(ActiveQueue.class.getName().replace('$', '.'));
6.17 - private static ActiveQueue activeReferenceQueue;
6.18 -
6.19 - /** number of known outstanding references */
6.20 - private int count;
6.21 - private boolean deprecated;
6.22 -
6.23 - ActiveQueue(boolean deprecated) {
6.24 - super();
6.25 - this.deprecated = deprecated;
6.26 - }
6.27 -
6.28 - public static synchronized ReferenceQueue<Object> queue() {
6.29 - if (activeReferenceQueue == null) {
6.30 - activeReferenceQueue = new ActiveQueue(false);
6.31 - }
6.32 -
6.33 - activeReferenceQueue.ping();
6.34 -
6.35 - return activeReferenceQueue;
6.36 - }
6.37 -
6.38 - @Override
6.39 - public Reference<Object> poll() {
6.40 - throw new UnsupportedOperationException();
6.41 - }
6.42 -
6.43 - @Override
6.44 - public Reference<Object> remove(long timeout) throws IllegalArgumentException, InterruptedException {
6.45 - throw new InterruptedException();
6.46 - }
6.47 -
6.48 - @Override
6.49 - public Reference<Object> remove() throws InterruptedException {
6.50 - throw new InterruptedException();
6.51 - }
6.52 -
6.53 - public void run() {
6.54 - while (true) {
6.55 - try {
6.56 - Reference<?> ref = super.remove(0);
6.57 - LOGGER.finer("dequeued reference");
6.58 - if (!(ref instanceof Runnable)) {
6.59 - LOGGER.warning("A reference not implementing runnable has been added to the Utilities.activeReferenceQueue(): " + ref.getClass());
6.60 - continue;
6.61 - }
6.62 - if (deprecated) {
6.63 - LOGGER.warning("Utilities.ACTIVE_REFERENCE_QUEUE has been deprecated for " + ref.getClass() + " use Utilities.activeReferenceQueue");
6.64 - }
6.65 - // do the cleanup
6.66 - try {
6.67 - ((Runnable) ref).run();
6.68 - } catch (ThreadDeath td) {
6.69 - throw td;
6.70 - } catch (Throwable t) {
6.71 - // Should not happen.
6.72 - // If it happens, it is a bug in client code, notify!
6.73 - LOGGER.log(Level.WARNING, null, t);
6.74 - } finally {
6.75 - // to allow GC
6.76 - ref = null;
6.77 - }
6.78 - } catch (InterruptedException ex) {
6.79 - // Can happen during VM shutdown, it seems. Ignore.
6.80 - continue;
6.81 - }
6.82 - synchronized (this) {
6.83 - assert count > 0;
6.84 - count--;
6.85 - if (count == 0) {
6.86 - // We have processed all we have to process (for now at least).
6.87 - // Could be restarted later if ping() called again.
6.88 - // This could also happen in case someone called queue() once and tried
6.89 - // to use it for several references; in that case run() might never be called on
6.90 - // the later ones to be collected. Can't really protect against that situation.
6.91 - // See issue #86625 for details.
6.92 - LOGGER.fine("stopping thread");
6.93 - break;
6.94 - }
6.95 - }
6.96 - }
6.97 - }
6.98 -
6.99 - synchronized void ping() {
6.100 - if (count == 0) {
6.101 - Thread t = new Thread(this, "Active Reference Queue Daemon");
6.102 - t.setPriority(Thread.MIN_PRIORITY);
6.103 - t.setDaemon(true);
6.104 - t.start();
6.105 - LOGGER.fine("starting thread");
6.106 - } else {
6.107 - LOGGER.finer("enqueuing reference");
6.108 - }
6.109 - count++;
6.110 - }
6.111 -}
7.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
7.2 +++ b/openide.util.lookup/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java Fri Jan 22 10:02:41 2010 -0500
7.3 @@ -0,0 +1,174 @@
7.4 +/*
7.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
7.6 + *
7.7 + * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
7.8 + *
7.9 + * The contents of this file are subject to the terms of either the GNU
7.10 + * General Public License Version 2 only ("GPL") or the Common
7.11 + * Development and Distribution License("CDDL") (collectively, the
7.12 + * "License"). You may not use this file except in compliance with the
7.13 + * License. You can obtain a copy of the License at
7.14 + * http://www.netbeans.org/cddl-gplv2.html
7.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
7.16 + * specific language governing permissions and limitations under the
7.17 + * License. When distributing the software, include this License Header
7.18 + * Notice in each file and include the License file at
7.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
7.20 + * particular file as subject to the "Classpath" exception as provided
7.21 + * by Sun in the GPL Version 2 section of the License file that
7.22 + * accompanied this code. If applicable, add the following below the
7.23 + * License Header, with the fields enclosed by brackets [] replaced by
7.24 + * your own identifying information:
7.25 + * "Portions Copyrighted [year] [name of copyright owner]"
7.26 + *
7.27 + * If you wish your version of this file to be governed by only the CDDL
7.28 + * or only the GPL Version 2, indicate your decision by adding
7.29 + * "[Contributor] elects to include this software in this distribution
7.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
7.31 + * single choice of license, a recipient has the option to distribute
7.32 + * your version of this file under either the CDDL, the GPL Version 2 or
7.33 + * to extend the choice of license to its licensees as provided above.
7.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
7.35 + * Version 2 license, then the option applies only if the new code is
7.36 + * made subject to such option by the copyright holder.
7.37 + *
7.38 + * Contributor(s):
7.39 + *
7.40 + * Portions Copyrighted 2008 Sun Microsystems, Inc.
7.41 + */
7.42 +
7.43 +package org.netbeans.modules.openide.util;
7.44 +
7.45 +import java.lang.annotation.Annotation;
7.46 +import java.util.Arrays;
7.47 +import java.util.Collection;
7.48 +import java.util.Collections;
7.49 +import java.util.HashSet;
7.50 +import java.util.LinkedList;
7.51 +import java.util.List;
7.52 +import java.util.Set;
7.53 +import javax.annotation.processing.Completion;
7.54 +import javax.annotation.processing.RoundEnvironment;
7.55 +import javax.annotation.processing.SupportedSourceVersion;
7.56 +import javax.lang.model.SourceVersion;
7.57 +import javax.lang.model.element.AnnotationMirror;
7.58 +import javax.lang.model.element.Element;
7.59 +import javax.lang.model.element.ExecutableElement;
7.60 +import javax.lang.model.element.TypeElement;
7.61 +import javax.lang.model.type.MirroredTypeException;
7.62 +import javax.lang.model.type.TypeKind;
7.63 +import javax.lang.model.type.TypeMirror;
7.64 +import org.openide.util.lookup.ServiceProvider;
7.65 +import org.openide.util.lookup.ServiceProviders;
7.66 +import org.openide.util.lookup.implspi.AbstractServiceProviderProcessor;
7.67 +
7.68 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
7.69 +public class ServiceProviderProcessor extends AbstractServiceProviderProcessor {
7.70 +
7.71 + public @Override Set<String> getSupportedAnnotationTypes() {
7.72 + return new HashSet<String>(Arrays.asList(
7.73 + ServiceProvider.class.getCanonicalName(),
7.74 + ServiceProviders.class.getCanonicalName()
7.75 + ));
7.76 + }
7.77 +
7.78 + /** public for ServiceLoader */
7.79 + public ServiceProviderProcessor() {}
7.80 +
7.81 + protected boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
7.82 + for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProvider.class)) {
7.83 + TypeElement clazz = (TypeElement) el;
7.84 + ServiceProvider sp = clazz.getAnnotation(ServiceProvider.class);
7.85 + register(clazz, ServiceProvider.class, sp);
7.86 + }
7.87 + for (Element el : roundEnv.getElementsAnnotatedWith(ServiceProviders.class)) {
7.88 + TypeElement clazz = (TypeElement) el;
7.89 + ServiceProviders spp = clazz.getAnnotation(ServiceProviders.class);
7.90 + for (ServiceProvider sp : spp.value()) {
7.91 + register(clazz, ServiceProviders.class, sp);
7.92 + }
7.93 + }
7.94 + return true;
7.95 + }
7.96 +
7.97 + private void register(TypeElement clazz, Class<? extends Annotation> annotation, ServiceProvider svc) {
7.98 + try {
7.99 + svc.service();
7.100 + assert false;
7.101 + return;
7.102 + } catch (MirroredTypeException e) {
7.103 + register(clazz, annotation, e.getTypeMirror(), svc.path(), svc.position(), svc.supersedes());
7.104 + }
7.105 + }
7.106 +
7.107 + @Override
7.108 + public Iterable<? extends Completion> getCompletions(Element annotated, AnnotationMirror annotation, ExecutableElement attr, String userText) {
7.109 + if (processingEnv == null || annotated == null || !annotated.getKind().isClass()) {
7.110 + return Collections.emptyList();
7.111 + }
7.112 +
7.113 + if ( annotation == null
7.114 + || !"org.openide.util.lookup.ServiceProvider".contentEquals(((TypeElement) annotation.getAnnotationType().asElement()).getQualifiedName())) {
7.115 + return Collections.emptyList();
7.116 + }
7.117 +
7.118 + if (!"service".contentEquals(attr.getSimpleName())) {
7.119 + return Collections.emptyList();
7.120 + }
7.121 +
7.122 + TypeElement jlObject = processingEnv.getElementUtils().getTypeElement("java.lang.Object");
7.123 +
7.124 + if (jlObject == null) {
7.125 + return Collections.emptyList();
7.126 + }
7.127 +
7.128 + Collection<Completion> result = new LinkedList<Completion>();
7.129 + List<TypeElement> toProcess = new LinkedList<TypeElement>();
7.130 +
7.131 + toProcess.add((TypeElement) annotated);
7.132 +
7.133 + while (!toProcess.isEmpty()) {
7.134 + TypeElement c = toProcess.remove(0);
7.135 +
7.136 + result.add(new TypeCompletion(c.getQualifiedName().toString() + ".class"));
7.137 +
7.138 + List<TypeMirror> parents = new LinkedList<TypeMirror>();
7.139 +
7.140 + parents.add(c.getSuperclass());
7.141 + parents.addAll(c.getInterfaces());
7.142 +
7.143 + for (TypeMirror tm : parents) {
7.144 + if (tm == null || tm.getKind() != TypeKind.DECLARED) {
7.145 + continue;
7.146 + }
7.147 +
7.148 + TypeElement type = (TypeElement) processingEnv.getTypeUtils().asElement(tm);
7.149 +
7.150 + if (!jlObject.equals(type)) {
7.151 + toProcess.add(type);
7.152 + }
7.153 + }
7.154 + }
7.155 +
7.156 + return result;
7.157 + }
7.158 +
7.159 + private static final class TypeCompletion implements Completion {
7.160 +
7.161 + private final String type;
7.162 +
7.163 + public TypeCompletion(String type) {
7.164 + this.type = type;
7.165 + }
7.166 +
7.167 + public String getValue() {
7.168 + return type;
7.169 + }
7.170 +
7.171 + public String getMessage() {
7.172 + return null;
7.173 + }
7.174 +
7.175 + }
7.176 +
7.177 +}
8.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
8.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/AbstractLookup.java Fri Jan 22 10:02:41 2010 -0500
8.3 @@ -0,0 +1,1463 @@
8.4 +/*
8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
8.6 + *
8.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
8.8 + *
8.9 + * The contents of this file are subject to the terms of either the GNU
8.10 + * General Public License Version 2 only ("GPL") or the Common
8.11 + * Development and Distribution License("CDDL") (collectively, the
8.12 + * "License"). You may not use this file except in compliance with the
8.13 + * License. You can obtain a copy of the License at
8.14 + * http://www.netbeans.org/cddl-gplv2.html
8.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
8.16 + * specific language governing permissions and limitations under the
8.17 + * License. When distributing the software, include this License Header
8.18 + * Notice in each file and include the License file at
8.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
8.20 + * particular file as subject to the "Classpath" exception as provided
8.21 + * by Sun in the GPL Version 2 section of the License file that
8.22 + * accompanied this code. If applicable, add the following below the
8.23 + * License Header, with the fields enclosed by brackets [] replaced by
8.24 + * your own identifying information:
8.25 + * "Portions Copyrighted [year] [name of copyright owner]"
8.26 + *
8.27 + * Contributor(s):
8.28 + *
8.29 + * The Original Software is NetBeans. The Initial Developer of the Original
8.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
8.31 + * Microsystems, Inc. All Rights Reserved.
8.32 + *
8.33 + * If you wish your version of this file to be governed by only the CDDL
8.34 + * or only the GPL Version 2, indicate your decision by adding
8.35 + * "[Contributor] elects to include this software in this distribution
8.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
8.37 + * single choice of license, a recipient has the option to distribute
8.38 + * your version of this file under either the CDDL, the GPL Version 2 or
8.39 + * to extend the choice of license to its licensees as provided above.
8.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
8.41 + * Version 2 license, then the option applies only if the new code is
8.42 + * made subject to such option by the copyright holder.
8.43 + */
8.44 +package org.openide.util.lookup;
8.45 +
8.46 +import java.io.IOException;
8.47 +import java.io.ObjectOutputStream;
8.48 +import java.io.Serializable;
8.49 +import java.lang.ref.ReferenceQueue;
8.50 +import java.lang.ref.WeakReference;
8.51 +import java.util.ArrayList;
8.52 +import java.util.Arrays;
8.53 +import java.util.Collection;
8.54 +import java.util.Collections;
8.55 +import java.util.Enumeration;
8.56 +import java.util.HashMap;
8.57 +import java.util.HashSet;
8.58 +import java.util.Iterator;
8.59 +import java.util.LinkedHashSet;
8.60 +import java.util.Map;
8.61 +import java.util.Set;
8.62 +import java.util.TreeSet;
8.63 +import java.util.concurrent.Executor;
8.64 +import org.openide.util.Lookup;
8.65 +import org.openide.util.LookupEvent;
8.66 +import org.openide.util.LookupListener;
8.67 +import org.openide.util.lookup.implspi.ActiveQueue;
8.68 +
8.69 +
8.70 +/** Implementation of the lookup from OpenAPIs that is based on the
8.71 + * introduction of Item. This class should provide the default way
8.72 + * of how to store (Class, Object) pairs in the lookups. It offers
8.73 + * protected methods for subclasses to register the pairs.
8.74 + * <p>Serializable since 3.27.
8.75 + * @author Jaroslav Tulach
8.76 + * @since 1.9
8.77 + */
8.78 +public class AbstractLookup extends Lookup implements Serializable {
8.79 + static final long serialVersionUID = 5L;
8.80 +
8.81 + /** lock for initialization of the maps of lookups */
8.82 + private static final Object treeLock = new Object();
8.83 +
8.84 + /** the tree that registers all items (or Integer as a treshold size) */
8.85 + private Object tree;
8.86 +
8.87 + /** count of items in to lookup */
8.88 + private int count;
8.89 +
8.90 + /** Constructor to create this lookup and associate it with given
8.91 + * Content. The content than allows the creator to invoke protected
8.92 + * methods which are not accessible for any other user of the lookup.
8.93 + *
8.94 + * @param content the content to assciate with
8.95 + *
8.96 + * @since 1.25
8.97 + */
8.98 + public AbstractLookup(Content content) {
8.99 + content.attach(this);
8.100 + }
8.101 +
8.102 + /** Constructor for testing purposes that allows specification of storage
8.103 + * as mechanism as well.
8.104 + */
8.105 + AbstractLookup(Content content, Storage<?> storage) {
8.106 + this(content);
8.107 + this.tree = storage;
8.108 + initialize();
8.109 + }
8.110 +
8.111 + /** Constructor for testing purposes that allows specification of storage
8.112 + * as mechanism as well.
8.113 + * @param trashhold number of Pair to "remain small"
8.114 + */
8.115 + AbstractLookup(Content content, Integer trashhold) {
8.116 + this(content);
8.117 + this.tree = trashhold;
8.118 + }
8.119 +
8.120 + /** Default constructor for subclasses that do not need to provide a content
8.121 + */
8.122 + protected AbstractLookup() {
8.123 + }
8.124 +
8.125 + @Override
8.126 + public String toString() {
8.127 + if (tree instanceof Storage) {
8.128 + return "AbstractLookup" + lookup(new Lookup.Template<Object>(Object.class)).allItems(); // NOI18N
8.129 + } else {
8.130 + return super.toString();
8.131 + }
8.132 + }
8.133 +
8.134 + /** Entres the storage management system.
8.135 + */
8.136 + @SuppressWarnings("unchecked")
8.137 + private <T> AbstractLookup.Storage<T> enterStorage() {
8.138 + for (;;) {
8.139 + synchronized (treeLock) {
8.140 + if (tree instanceof AbstractLookup.Storage) {
8.141 + if (tree instanceof DelegatingStorage) {
8.142 + // somebody is using the lookup right now
8.143 + DelegatingStorage del = (DelegatingStorage) tree;
8.144 +
8.145 + // check whether there is not access from the same
8.146 + // thread (can throw exception)
8.147 + del.checkForTreeModification();
8.148 +
8.149 + try {
8.150 + treeLock.wait();
8.151 + } catch (InterruptedException ex) {
8.152 + // ignore and go on
8.153 + }
8.154 +
8.155 + continue;
8.156 + } else {
8.157 + // ok, tree is initialized and nobody is using it yet
8.158 + tree = new DelegatingStorage((Storage<T>) tree);
8.159 +
8.160 + return (Storage<T>) tree;
8.161 + }
8.162 + }
8.163 +
8.164 + // first time initialization of the tree
8.165 + if (tree instanceof Integer) {
8.166 + tree = new ArrayStorage((Integer) tree);
8.167 + } else {
8.168 + tree = new ArrayStorage();
8.169 + }
8.170 + }
8.171 +
8.172 + // the tree has not yet been initilized, initialize and go on again
8.173 + initialize();
8.174 + }
8.175 + }
8.176 +
8.177 + /** Exists tree ownership.
8.178 + */
8.179 + private AbstractLookup.Storage exitStorage() {
8.180 + synchronized (treeLock) {
8.181 + AbstractLookup.Storage stor = ((DelegatingStorage) tree).exitDelegate();
8.182 + tree = stor;
8.183 + treeLock.notifyAll();
8.184 +
8.185 + return stor;
8.186 + }
8.187 + }
8.188 +
8.189 + /** Method for subclasses to initialize them selves.
8.190 + */
8.191 + protected void initialize() {
8.192 + }
8.193 +
8.194 + /** Notifies subclasses that a query is about to be processed.
8.195 + * @param template the template
8.196 + */
8.197 + protected void beforeLookup(Template<?> template) {
8.198 + }
8.199 +
8.200 + /** The method to add instance to the lookup with.
8.201 + * @param pair class/instance pair
8.202 + */
8.203 + protected final void addPair(Pair<?> pair) {
8.204 + addPairImpl(pair, null);
8.205 + }
8.206 +
8.207 + /** The method to add instance to the lookup with.
8.208 + * @param pair class/instance pair
8.209 + * @param notifyIn the executor that will handle the notification of events
8.210 + * @since 7.16
8.211 + */
8.212 + protected final void addPair(Pair<?> pair, Executor notifyIn) {
8.213 + addPairImpl(pair, notifyIn);
8.214 + }
8.215 +
8.216 + private final <Transaction> void addPairImpl(Pair<?> pair, Executor notifyIn) {
8.217 + HashSet<R> toNotify = new HashSet<R>();
8.218 +
8.219 + AbstractLookup.Storage<Transaction> t = enterStorage();
8.220 + Transaction transaction = null;
8.221 +
8.222 + try {
8.223 + transaction = t.beginTransaction(-2);
8.224 +
8.225 + if (t.add(pair, transaction)) {
8.226 + try {
8.227 + pair.setIndex(t, count++);
8.228 + } catch (IllegalStateException ex) {
8.229 + // remove the pair
8.230 + t.remove(pair, transaction);
8.231 +
8.232 + // rethrow the exception
8.233 + throw ex;
8.234 + }
8.235 +
8.236 + // if the pair is newly added and was not there before
8.237 + t.endTransaction(transaction, toNotify);
8.238 + } else {
8.239 + // just finish the process by calling endTransaction
8.240 + t.endTransaction(transaction, new HashSet<R>());
8.241 + }
8.242 + } finally {
8.243 + exitStorage();
8.244 + }
8.245 +
8.246 + notifyIn(notifyIn, toNotify);
8.247 + }
8.248 +
8.249 + /** Remove instance.
8.250 + * @param pair class/instance pair
8.251 + */
8.252 + protected final void removePair(Pair<?> pair) {
8.253 + removePairImpl(pair, null);
8.254 + }
8.255 + /** Remove instance.
8.256 + * @param pair class/instance pair
8.257 + * @param notifyIn the executor that will handle the notification of events
8.258 + * @since 7.16
8.259 + */
8.260 + protected final void removePair(Pair<?> pair, Executor notifyIn) {
8.261 + removePairImpl(pair, notifyIn);
8.262 + }
8.263 +
8.264 + private <Transaction> void removePairImpl(Pair<?> pair, Executor notifyIn) {
8.265 + HashSet<R> toNotify = new HashSet<R>();
8.266 +
8.267 + AbstractLookup.Storage<Transaction> t = enterStorage();
8.268 + Transaction transaction = null;
8.269 +
8.270 + try {
8.271 + transaction = t.beginTransaction(-1);
8.272 + t.remove(pair, transaction);
8.273 + t.endTransaction(transaction, toNotify);
8.274 + } finally {
8.275 + exitStorage();
8.276 + }
8.277 +
8.278 + notifyIn(notifyIn, toNotify);
8.279 + }
8.280 +
8.281 + /** Changes all pairs in the lookup to new values.
8.282 + * @param collection the collection of (Pair) objects
8.283 + */
8.284 + protected final void setPairs(Collection<? extends Pair> collection) {
8.285 + setPairs(collection, null);
8.286 + }
8.287 +
8.288 + /** Changes all pairs in the lookup to new values, notifies listeners
8.289 + * using provided executor.
8.290 + *
8.291 + * @param collection the collection of (Pair) objects
8.292 + * @param notifyIn the executor that will handle the notification of events
8.293 + * @since 7.16
8.294 + */
8.295 + protected final void setPairs(Collection<? extends Pair> collection, Executor notifyIn) {
8.296 + HashSet<R> listeners = setPairsAndCollectListeners(collection);
8.297 + notifyIn(notifyIn, listeners);
8.298 + }
8.299 +
8.300 + private final void notifyIn(Executor notifyIn, final HashSet<R> listeners) {
8.301 + NotifyListeners notify = new NotifyListeners(listeners);
8.302 + if (notify.shallRun()) {
8.303 + if (notifyIn == null) {
8.304 + notify.run();
8.305 + } else {
8.306 + notifyIn.execute(notify);
8.307 + }
8.308 + }
8.309 + }
8.310 +
8.311 + /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
8.312 + * @return a LinkedHashSet that can be modified
8.313 + */
8.314 + final LinkedHashSet<Pair<?>> getPairsAsLHS() {
8.315 + AbstractLookup.Storage<?> t = enterStorage();
8.316 +
8.317 + try {
8.318 + Enumeration<Pair<Object>> en = t.lookup(Object.class);
8.319 + TreeSet<Pair<?>> arr = new TreeSet<Pair<?>>(ALPairComparator.DEFAULT);
8.320 + while (en.hasMoreElements()) {
8.321 + Pair<Object> item = en.nextElement();
8.322 + arr.add(item);
8.323 + }
8.324 + return new LinkedHashSet<Pair<?>>(arr);
8.325 + } finally {
8.326 + exitStorage();
8.327 + }
8.328 + }
8.329 +
8.330 + /** Collects listeners without notification. Needed in MetaInfServicesLookup
8.331 + * right now, but maybe will become an API later.
8.332 + */
8.333 + final <Transaction> HashSet<R> setPairsAndCollectListeners(Collection<? extends Pair> collection) {
8.334 + HashSet<R> toNotify = new HashSet<R>(27);
8.335 +
8.336 + AbstractLookup.Storage<Transaction> t = enterStorage();
8.337 + Transaction transaction = null;
8.338 +
8.339 + try {
8.340 + // map between the Items and their indexes (Integer)
8.341 + HashMap<Item<?>,Info> shouldBeThere = new HashMap<Item<?>,Info>(collection.size() * 2);
8.342 +
8.343 + count = 0;
8.344 +
8.345 + Iterator it = collection.iterator();
8.346 + transaction = t.beginTransaction(collection.size());
8.347 +
8.348 + while (it.hasNext()) {
8.349 + Pair item = (Pair) it.next();
8.350 +
8.351 + if (t.add(item, transaction)) {
8.352 + // the item has not been there yet
8.353 + //t.endTransaction(transaction, toNotify);
8.354 + }
8.355 +
8.356 + // remeber the item, because it should not be removed
8.357 + shouldBeThere.put(item, new Info(count++, transaction));
8.358 +
8.359 + // arr.clear ();
8.360 + }
8.361 +
8.362 + // Object transaction = t.beginTransaction ();
8.363 + // deletes all objects that should not be there and
8.364 + t.retainAll(shouldBeThere, transaction);
8.365 +
8.366 + // collect listeners
8.367 + t.endTransaction(transaction, toNotify);
8.368 +
8.369 + /*
8.370 + // check consistency
8.371 + Enumeration en = t.lookup (java.lang.Object.class);
8.372 + boolean[] max = new boolean[count];
8.373 + int mistake = -1;
8.374 + while (en.hasMoreElements ()) {
8.375 + Pair item = (Pair)en.nextElement ();
8.376 +
8.377 + if (max[item.index]) {
8.378 + mistake = item.index;
8.379 + }
8.380 + max[item.index] = true;
8.381 + }
8.382 +
8.383 + if (mistake != -1) {
8.384 + System.err.println ("Mistake at: " + mistake);
8.385 + tree.print (System.err, true);
8.386 + }
8.387 + */
8.388 + } finally {
8.389 + exitStorage();
8.390 + }
8.391 +
8.392 + return toNotify;
8.393 + }
8.394 +
8.395 + private final void writeObject(ObjectOutputStream oos)
8.396 + throws IOException {
8.397 + AbstractLookup.Storage s = enterStorage();
8.398 +
8.399 + try {
8.400 + // #36830: Serializing only InheritanceTree no ArrayStorage
8.401 + s.beginTransaction(Integer.MAX_VALUE);
8.402 +
8.403 + // #32040: don't write half-made changes
8.404 + oos.defaultWriteObject();
8.405 + } finally {
8.406 + exitStorage();
8.407 + }
8.408 + }
8.409 +
8.410 + public final <T> T lookup(Class<T> clazz) {
8.411 + Lookup.Item<T> item = lookupItem(new Lookup.Template<T>(clazz));
8.412 + return (item == null) ? null : item.getInstance();
8.413 + }
8.414 +
8.415 + @Override
8.416 + public final <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
8.417 + AbstractLookup.this.beforeLookup(template);
8.418 +
8.419 + ArrayList<Pair<T>> list = null;
8.420 + AbstractLookup.Storage<?> t = enterStorage();
8.421 +
8.422 + try {
8.423 + Enumeration<Pair<T>> en;
8.424 +
8.425 + try {
8.426 + en = t.lookup(template.getType());
8.427 +
8.428 + return findSmallest(en, template, false);
8.429 + } catch (AbstractLookup.ISE ex) {
8.430 + // not possible to enumerate the exception, ok, copy it
8.431 + // to create new
8.432 + list = new ArrayList<Pair<T>>();
8.433 + en = t.lookup(null); // this should get all the items without any checks
8.434 +
8.435 + // the checks will be done out side of the storage
8.436 + while (en.hasMoreElements()) {
8.437 + list.add(en.nextElement());
8.438 + }
8.439 + }
8.440 + } finally {
8.441 + exitStorage();
8.442 + }
8.443 +
8.444 + return findSmallest(Collections.enumeration(list), template, true);
8.445 + }
8.446 +
8.447 + private static <T> Pair<T> findSmallest(Enumeration<Pair<T>> en, Lookup.Template<T> template, boolean deepCheck) {
8.448 + int smallest = InheritanceTree.unsorted(en) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
8.449 + Pair<T> res = null;
8.450 +
8.451 + while (en.hasMoreElements()) {
8.452 + Pair<T> item = en.nextElement();
8.453 +
8.454 + if (matches(template, item, deepCheck)) {
8.455 + if (smallest == Integer.MIN_VALUE) {
8.456 + // ok, sorted enumeration the first that matches is fine
8.457 + return item;
8.458 + } else {
8.459 + // check for the smallest item
8.460 + if (smallest > item.getIndex()) {
8.461 + smallest = item.getIndex();
8.462 + res = item;
8.463 + }
8.464 + }
8.465 + }
8.466 + }
8.467 +
8.468 + return res;
8.469 + }
8.470 +
8.471 + public final <T> Lookup.Result<T> lookup(Lookup.Template<T> template) {
8.472 + for (;;) {
8.473 + AbstractLookup.ISE toRun = null;
8.474 +
8.475 + AbstractLookup.Storage<?> t = enterStorage();
8.476 +
8.477 + try {
8.478 + R<T> r = new R<T>();
8.479 + ReferenceToResult<T> newRef = new ReferenceToResult<T>(r, this, template);
8.480 + newRef.next = t.registerReferenceToResult(newRef);
8.481 +
8.482 + return r;
8.483 + } catch (AbstractLookup.ISE ex) {
8.484 + toRun = ex;
8.485 + } finally {
8.486 + exitStorage();
8.487 + }
8.488 +
8.489 + toRun.recover(this);
8.490 +
8.491 + // and try again
8.492 + }
8.493 + }
8.494 +
8.495 + /** Notifies listeners.
8.496 + * @param allAffectedResults set of R
8.497 + */
8.498 + static final class NotifyListeners implements Runnable {
8.499 + private final ArrayList<Object> evAndListeners;
8.500 +
8.501 + public NotifyListeners(Set<R> allAffectedResults) {
8.502 + if (allAffectedResults.isEmpty()) {
8.503 + evAndListeners = null;
8.504 + return;
8.505 + }
8.506 +
8.507 + evAndListeners = new ArrayList<Object>();
8.508 + {
8.509 + for (R<?> result : allAffectedResults) {
8.510 + result.collectFires(evAndListeners);
8.511 + }
8.512 + }
8.513 + }
8.514 +
8.515 + public boolean shallRun() {
8.516 + return evAndListeners != null && !evAndListeners.isEmpty();
8.517 + }
8.518 +
8.519 + public void run() {
8.520 + Iterator it = evAndListeners.iterator();
8.521 + while (it.hasNext()) {
8.522 + LookupEvent ev = (LookupEvent)it.next();
8.523 + LookupListener l = (LookupListener)it.next();
8.524 + l.resultChanged(ev);
8.525 + }
8.526 + }
8.527 + }
8.528 +
8.529 + /**
8.530 + * Call resultChanged on all listeners.
8.531 + * @param listeners array of listeners in the format used by
8.532 + * javax.swing.EventListenerList. It means that there are Class
8.533 + * objects on even positions and the listeners on odd positions
8.534 + * @param ev the event to fire
8.535 + */
8.536 + static void notifyListeners(Object[] listeners, LookupEvent ev, Collection<Object> evAndListeners) {
8.537 + for (int i = listeners.length - 1; i >= 0; i--) {
8.538 + if (! (listeners[i] instanceof LookupListener)) {
8.539 + continue;
8.540 + }
8.541 + LookupListener ll = (LookupListener)listeners[i];
8.542 +
8.543 + try {
8.544 + if (evAndListeners != null) {
8.545 + if (ll instanceof WaitableResult) {
8.546 + WaitableResult<?> wr = (WaitableResult<?>)ll;
8.547 + wr.collectFires(evAndListeners);
8.548 + } else {
8.549 + evAndListeners.add(ev);
8.550 + evAndListeners.add(ll);
8.551 + }
8.552 + } else {
8.553 + ll.resultChanged(ev);
8.554 + }
8.555 + } catch (StackOverflowError err) {
8.556 + throw new CycleError(evAndListeners); // NOI18N
8.557 + } catch (RuntimeException e) {
8.558 + // Such as e.g. occurred in #32040. Do not halt other things.
8.559 + e.printStackTrace();
8.560 + }
8.561 + }
8.562 + }
8.563 +
8.564 + private static class CycleError extends StackOverflowError {
8.565 + private final Collection<Object> print;
8.566 + public CycleError(Collection<Object> evAndListeners) {
8.567 + this.print = evAndListeners;
8.568 + }
8.569 +
8.570 + @Override
8.571 + public String getMessage() {
8.572 + StringBuilder sb = new StringBuilder();
8.573 + sb.append("StackOverflowError, here are the listeners:\n"); // NOI18N
8.574 + for (Object o : print) {
8.575 + sb.append('\n').append(o);
8.576 + if (sb.length() > 10000) {
8.577 + break;
8.578 + }
8.579 + }
8.580 + return sb.toString();
8.581 + }
8.582 + } // end of CycleError
8.583 +
8.584 + /** A method that defines matching between Item and Template.
8.585 + * @param t template providing the criteria
8.586 + * @param item the item to match
8.587 + * @param deepCheck true if type of the pair should be tested, false if it is already has been tested
8.588 + * @return true if item matches the template requirements, false if not
8.589 + */
8.590 + static boolean matches(Template<?> t, Pair<?> item, boolean deepCheck) {
8.591 + String id = t.getId();
8.592 +
8.593 + if (id != null && !id.equals(item.getId())) {
8.594 + return false;
8.595 + }
8.596 +
8.597 + Object instance = t.getInstance();
8.598 +
8.599 + if ((instance != null) && !item.creatorOf(instance)) {
8.600 + return false;
8.601 + }
8.602 +
8.603 + if (deepCheck) {
8.604 + return item.instanceOf(t.getType());
8.605 + } else {
8.606 + return true;
8.607 + }
8.608 + }
8.609 +
8.610 + /**
8.611 + * Compares the array elements for equality.
8.612 + * @return true if all elements in the arrays are equal
8.613 + * (by calling equals(Object x) method)
8.614 + */
8.615 + private static boolean compareArrays(Object[] a, Object[] b) {
8.616 + // handle null values
8.617 + if (a == null) {
8.618 + return (b == null);
8.619 + } else {
8.620 + if (b == null) {
8.621 + return false;
8.622 + }
8.623 + }
8.624 +
8.625 + if (a.length != b.length) {
8.626 + return false;
8.627 + }
8.628 +
8.629 + for (int i = 0; i < a.length; i++) {
8.630 + // handle null values for individual elements
8.631 + if (a[i] == null) {
8.632 + if (b[i] != null) {
8.633 + return false;
8.634 + }
8.635 +
8.636 + // both are null --> ok, take next
8.637 + continue;
8.638 + } else {
8.639 + if (b[i] == null) {
8.640 + return false;
8.641 + }
8.642 + }
8.643 +
8.644 + // perform the comparison
8.645 + if (!a[i].equals(b[i])) {
8.646 + return false;
8.647 + }
8.648 + }
8.649 +
8.650 + return true;
8.651 + }
8.652 +
8.653 + /** Method to be called when a result is cleared to signal that the list
8.654 + * of all result should be checked for clearing.
8.655 + * @param template the template the result was for
8.656 + * @return true if the hash map with all items has been cleared
8.657 + */
8.658 + <T> boolean cleanUpResult(Lookup.Template<T> template) {
8.659 + AbstractLookup.Storage<?> t = enterStorage();
8.660 +
8.661 + try {
8.662 + return t.cleanUpResult(template) == null;
8.663 + } finally {
8.664 + exitStorage();
8.665 + }
8.666 + }
8.667 +
8.668 + /** Storage check for tests. */
8.669 + static boolean isSimple(AbstractLookup l) {
8.670 + return DelegatingStorage.isSimple((Storage)l.tree);
8.671 + }
8.672 +
8.673 + /** Generic support for listeners, so it can be used in other results
8.674 + * as well.
8.675 + * @param add true to add it, false to modify
8.676 + * @param l listener to modify
8.677 + * @param ref the value of the reference to listener or listener list
8.678 + * @return new value to the reference to listener or list
8.679 + */
8.680 + @SuppressWarnings("unchecked")
8.681 + static Object modifyListenerList(boolean add, LookupListener l, Object ref) {
8.682 + if (add) {
8.683 + if (ref == null) {
8.684 + return l;
8.685 + }
8.686 +
8.687 + if (ref instanceof LookupListener) {
8.688 + ArrayList arr = new ArrayList();
8.689 + arr.add(ref);
8.690 + ref = arr;
8.691 + }
8.692 +
8.693 + ((ArrayList) ref).add(l);
8.694 +
8.695 + return ref;
8.696 + } else {
8.697 + // remove
8.698 + if (ref == null) {
8.699 + return null;
8.700 + }
8.701 +
8.702 + if (ref == l) {
8.703 + return null;
8.704 + }
8.705 +
8.706 + ArrayList arr = (ArrayList) ref;
8.707 + arr.remove(l);
8.708 +
8.709 + if (arr.size() == 1) {
8.710 + return arr.iterator().next();
8.711 + } else {
8.712 + return arr;
8.713 + }
8.714 + }
8.715 + }
8.716 +
8.717 + private static ReferenceQueue<Object> activeQueue() {
8.718 + return ActiveQueue.queue();
8.719 + }
8.720 +
8.721 + /** Storage to keep the internal structure of Pairs and to answer
8.722 + * different queries.
8.723 + */
8.724 + interface Storage<Transaction> {
8.725 + /** Initializes a modification operation by creating an object
8.726 + * that will be passsed to all add, remove, retainAll methods
8.727 + * and should collect enough information about the change to
8.728 + * notify listeners about the transaction later
8.729 + *
8.730 + * @param ensure the amount of items that will appear in the storage
8.731 + * after the modifications (-1 == remove one, -2 == add one, >= 0
8.732 + * the amount of objects at the end
8.733 + * @return a token to identify the transaction
8.734 + */
8.735 + public Transaction beginTransaction(int ensure);
8.736 +
8.737 + /** Collects all affected results R that were modified in the
8.738 + * given transaction.
8.739 + *
8.740 + * @param modified place to add results R to
8.741 + * @param transaction the transaction indentification
8.742 + */
8.743 + public void endTransaction(Transaction transaction, Set<R> modifiedResults);
8.744 +
8.745 + /** Adds an item into the storage.
8.746 + * @param item to add
8.747 + * @param transaction transaction token
8.748 + * @return true if the Item has been added for the first time or false if some other
8.749 + * item equal to this one already existed in the lookup
8.750 + */
8.751 + public boolean add(AbstractLookup.Pair<?> item, Transaction transaction);
8.752 +
8.753 + /** Removes an item.
8.754 + */
8.755 + public void remove(AbstractLookup.Pair item, Transaction transaction);
8.756 +
8.757 + /** Removes all items that are not present in the provided collection.
8.758 + * @param retain collection of Pairs to keep them in
8.759 + * @param transaction the transaction context
8.760 + */
8.761 + public void retainAll(Map retain, Transaction transaction);
8.762 +
8.763 + /** Queries for instances of given class.
8.764 + * @param clazz the class to check
8.765 + * @return enumeration of Item
8.766 + * @see #unsorted
8.767 + */
8.768 + public <T> Enumeration<Pair<T>> lookup(Class<T> clazz);
8.769 +
8.770 + /** Registers another reference to a result with the storage. This method
8.771 + * has also a special meaning.
8.772 + *
8.773 + * @param newRef the new reference to remember
8.774 + * @return the previous reference that was kept (null if newRef is the first one)
8.775 + * the applications is expected to link from newRef to this returned
8.776 + * value to form a linked list
8.777 + */
8.778 + public ReferenceToResult<?> registerReferenceToResult(ReferenceToResult<?> newRef);
8.779 +
8.780 + /** Given the provided template, Do cleanup the results.
8.781 + * @param templ template of a result(s) that should be checked
8.782 + * @return null if all references for this template were cleared or one of them
8.783 + */
8.784 + public ReferenceToResult<?> cleanUpResult(Lookup.Template<?> templ);
8.785 + }
8.786 +
8.787 + /** Extension to the default lookup item that offers additional information
8.788 + * for the data structures use in AbstractLookup
8.789 + */
8.790 + public static abstract class Pair<T> extends Lookup.Item<T> implements Serializable {
8.791 + private static final long serialVersionUID = 1L;
8.792 +
8.793 + /** possition of this item in the lookup, manipulated in addPair, removePair, setPairs methods */
8.794 + private int index = -1;
8.795 +
8.796 + /** For use by subclasses. */
8.797 + protected Pair() {
8.798 + }
8.799 +
8.800 + final int getIndex() {
8.801 + return index;
8.802 + }
8.803 +
8.804 + final void setIndex(AbstractLookup.Storage<?> tree, int x) {
8.805 + if (tree == null) {
8.806 + this.index = x;
8.807 +
8.808 + return;
8.809 + }
8.810 +
8.811 + if (this.index == -1) {
8.812 + this.index = x;
8.813 + } else {
8.814 + throw new IllegalStateException("You cannot use " + this + " in more than one AbstractLookup. Prev: " + this.index + " new: " + x); // NOI18N
8.815 + }
8.816 + }
8.817 +
8.818 + /** Tests whether this item can produce object
8.819 + * of class c.
8.820 + */
8.821 + protected abstract boolean instanceOf(Class<?> c);
8.822 +
8.823 + /** Method that can test whether an instance of a class has been created
8.824 + * by this item.
8.825 + *
8.826 + * @param obj the instance
8.827 + * @return if the item has already create an instance and it is the same
8.828 + * as obj.
8.829 + */
8.830 + protected abstract boolean creatorOf(Object obj);
8.831 + }
8.832 +
8.833 + /** Result based on one instance returned.
8.834 + */
8.835 + static final class R<T> extends WaitableResult<T> {
8.836 + /** reference our result is attached to (do not modify) */
8.837 + public ReferenceToResult<T> reference;
8.838 +
8.839 + /** listeners on the results or pointer to one listener */
8.840 + private Object listeners;
8.841 +
8.842 + public R() {
8.843 + }
8.844 +
8.845 + /** Checks whether we have simple behaviour of complex.
8.846 + */
8.847 + private boolean isSimple() {
8.848 + Storage s = (Storage) reference.lookup.tree;
8.849 +
8.850 + return DelegatingStorage.isSimple(s);
8.851 + }
8.852 +
8.853 + //
8.854 + // Handling cache management for both cases, no caches
8.855 + // for simple (but mark that we needed them, so refresh can
8.856 + // be done in cloneList) and complex when all 3 types
8.857 + // of result are cached
8.858 + //
8.859 + private Object getFromCache(int indx) {
8.860 + if (isSimple()) {
8.861 + return null;
8.862 + }
8.863 +
8.864 + Object maybeArray = reference.caches;
8.865 +
8.866 + if (maybeArray instanceof Object[]) {
8.867 + return ((Object[]) maybeArray)[indx];
8.868 + }
8.869 +
8.870 + return null;
8.871 + }
8.872 +
8.873 + @SuppressWarnings("unchecked")
8.874 + private Set<Class<? extends T>> getClassesCache() {
8.875 + return (Set<Class<? extends T>>) getFromCache(0);
8.876 + }
8.877 +
8.878 + private void setClassesCache(Set s) {
8.879 + if (isSimple()) {
8.880 + // mark it as being used
8.881 + reference.caches = reference;
8.882 +
8.883 + return;
8.884 + }
8.885 +
8.886 + if (!(reference.caches instanceof Object[])) {
8.887 + reference.caches = new Object[3];
8.888 + }
8.889 +
8.890 + ((Object[]) reference.caches)[0] = s;
8.891 + }
8.892 +
8.893 + @SuppressWarnings("unchecked")
8.894 + private Collection<T> getInstancesCache() {
8.895 + return (Collection<T>) getFromCache(1);
8.896 + }
8.897 +
8.898 + private void setInstancesCache(Collection c) {
8.899 + if (isSimple()) {
8.900 + // mark it as being used
8.901 + reference.caches = reference;
8.902 +
8.903 + return;
8.904 + }
8.905 +
8.906 + if (!(reference.caches instanceof Object[])) {
8.907 + reference.caches = new Object[3];
8.908 + }
8.909 +
8.910 + ((Object[]) reference.caches)[1] = c;
8.911 + }
8.912 +
8.913 + @SuppressWarnings("unchecked")
8.914 + private Pair<T>[] getItemsCache() {
8.915 + return (Pair<T>[]) getFromCache(2);
8.916 + }
8.917 +
8.918 + private void setItemsCache(Collection<?> c) {
8.919 + if (isSimple()) {
8.920 + // mark it as being used
8.921 + reference.caches = reference;
8.922 +
8.923 + return;
8.924 + }
8.925 +
8.926 + if (!(reference.caches instanceof Object[])) {
8.927 + reference.caches = new Object[3];
8.928 + }
8.929 +
8.930 + ((Object[]) reference.caches)[2] = c.toArray(new Pair[0]);
8.931 + }
8.932 +
8.933 + private void clearCaches() {
8.934 + if (reference.caches instanceof Object[]) {
8.935 + reference.caches = new Object[3];
8.936 + }
8.937 + }
8.938 +
8.939 + /** Ok, register listeners to all classes and super classes.
8.940 + */
8.941 + public synchronized void addLookupListener(LookupListener l) {
8.942 + listeners = modifyListenerList(true, l, listeners);
8.943 + }
8.944 +
8.945 + /** Ok, register listeners to all classes and super classes.
8.946 + */
8.947 + public synchronized void removeLookupListener(LookupListener l) {
8.948 + listeners = modifyListenerList(false, l, listeners);
8.949 + }
8.950 +
8.951 + /** Delete all cached values, the template changed.
8.952 + */
8.953 + protected void collectFires(Collection<Object> evAndListeners) {
8.954 + Object[] previousItems = getItemsCache();
8.955 + clearCaches();
8.956 +
8.957 + if (previousItems != null) {
8.958 + Object[] newArray = allItemsWithoutBeforeLookup().toArray();
8.959 +
8.960 + if (compareArrays(previousItems, newArray)) {
8.961 + // do not fire any change if nothing has been changed
8.962 + return;
8.963 + }
8.964 + }
8.965 +
8.966 + LookupListener[] arr;
8.967 +
8.968 + synchronized (this) {
8.969 + if (listeners == null) {
8.970 + return;
8.971 + }
8.972 +
8.973 + if (listeners instanceof LookupListener) {
8.974 + arr = new LookupListener[] { (LookupListener) listeners };
8.975 + } else {
8.976 + ArrayList<?> l = (ArrayList<?>) listeners;
8.977 + arr = l.toArray(new LookupListener[l.size()]);
8.978 + }
8.979 + }
8.980 +
8.981 + final LookupListener[] ll = arr;
8.982 + final LookupEvent ev = new LookupEvent(this);
8.983 + notifyListeners(ll, ev, evAndListeners);
8.984 + }
8.985 +
8.986 + public Collection<T> allInstances() {
8.987 + reference.lookup.beforeLookup(reference.template);
8.988 +
8.989 + Collection<T> s = getInstancesCache();
8.990 +
8.991 + if (s != null) {
8.992 + return s;
8.993 + }
8.994 +
8.995 + Collection<Pair<T>> items = allItemsWithoutBeforeLookup();
8.996 + ArrayList<T> list = new ArrayList<T>(items.size());
8.997 +
8.998 + Iterator<Pair<T>> it = items.iterator();
8.999 +
8.1000 + while (it.hasNext()) {
8.1001 + Pair<T> item = it.next();
8.1002 + T obj = item.getInstance();
8.1003 +
8.1004 + if (reference.template.getType().isInstance(obj)) {
8.1005 + list.add(obj);
8.1006 + }
8.1007 + }
8.1008 +
8.1009 + s = Collections.unmodifiableList(list);
8.1010 + setInstancesCache(s);
8.1011 +
8.1012 + return s;
8.1013 + }
8.1014 +
8.1015 + /** Set of all classes.
8.1016 + *
8.1017 + */
8.1018 + @Override
8.1019 + public Set<Class<? extends T>> allClasses() {
8.1020 + reference.lookup.beforeLookup(reference.template);
8.1021 +
8.1022 + Set<Class<? extends T>> s = getClassesCache();
8.1023 +
8.1024 + if (s != null) {
8.1025 + return s;
8.1026 + }
8.1027 +
8.1028 + s = new HashSet<Class<? extends T>>();
8.1029 +
8.1030 + for (Pair<T> item : allItemsWithoutBeforeLookup()) {
8.1031 + Class<? extends T> clazz = item.getType();
8.1032 +
8.1033 + if (clazz != null) {
8.1034 + s.add(clazz);
8.1035 + }
8.1036 + }
8.1037 +
8.1038 + s = Collections.unmodifiableSet(s);
8.1039 + setClassesCache(s);
8.1040 +
8.1041 + return s;
8.1042 + }
8.1043 +
8.1044 + /** Items are stored directly in the allItems.
8.1045 + */
8.1046 + @Override
8.1047 + public Collection<? extends Item<T>> allItems() {
8.1048 + reference.lookup.beforeLookup(reference.template);
8.1049 +
8.1050 + return allItemsWithoutBeforeLookup();
8.1051 + }
8.1052 +
8.1053 + /** Implements the search for allItems, but without asking for before lookup */
8.1054 + private Collection<Pair<T>> allItemsWithoutBeforeLookup() {
8.1055 + Pair<T>[] c = getItemsCache();
8.1056 +
8.1057 + if (c != null) {
8.1058 + return Collections.unmodifiableList(Arrays.asList(c));
8.1059 + }
8.1060 +
8.1061 + ArrayList<Pair<Object>> saferCheck = null;
8.1062 + AbstractLookup.Storage<?> t = reference.lookup.enterStorage();
8.1063 +
8.1064 + try {
8.1065 + try {
8.1066 + return Collections.unmodifiableCollection(initItems(t));
8.1067 + } catch (AbstractLookup.ISE ex) {
8.1068 + // do less effective evaluation of items outside of the
8.1069 + // locked storage
8.1070 + saferCheck = new ArrayList<Pair<Object>>();
8.1071 +
8.1072 + Enumeration<Pair<Object>> en = t.lookup(null); // get all Pairs
8.1073 +
8.1074 + while (en.hasMoreElements()) {
8.1075 + Pair<Object> i = en.nextElement();
8.1076 + saferCheck.add(i);
8.1077 + }
8.1078 + }
8.1079 + } finally {
8.1080 + reference.lookup.exitStorage();
8.1081 + }
8.1082 + return extractPairs(saferCheck);
8.1083 + }
8.1084 +
8.1085 + @SuppressWarnings("unchecked")
8.1086 + private Collection<Pair<T>> extractPairs(final ArrayList<Pair<Object>> saferCheck) {
8.1087 + TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
8.1088 + for (Pair<Object> i : saferCheck) {
8.1089 + if (matches(reference.template, i, false)) {
8.1090 + items.add((Pair<T>)i);
8.1091 + }
8.1092 + }
8.1093 + return Collections.unmodifiableCollection(items);
8.1094 + }
8.1095 +
8.1096 + /** Initializes items.
8.1097 + */
8.1098 + private Collection<Pair<T>> initItems(Storage<?> t) {
8.1099 + // manipulation with the tree must be synchronized
8.1100 + Enumeration<Pair<T>> en = t.lookup(reference.template.getType());
8.1101 +
8.1102 + // InheritanceTree is comparator for AbstractLookup.Pairs
8.1103 + TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
8.1104 +
8.1105 + while (en.hasMoreElements()) {
8.1106 + Pair<T> i = en.nextElement();
8.1107 +
8.1108 + if (matches(reference.template, i, false)) {
8.1109 + items.add(i);
8.1110 + }
8.1111 + }
8.1112 +
8.1113 + // create a correctly sorted copy using the tree as the comparator
8.1114 + setItemsCache(items);
8.1115 +
8.1116 + return items;
8.1117 + }
8.1118 +
8.1119 + /** Used by proxy results to synchronize before lookup.
8.1120 + */
8.1121 + protected void beforeLookup(Lookup.Template t) {
8.1122 + if (t.getType() == reference.template.getType()) {
8.1123 + reference.lookup.beforeLookup(t);
8.1124 + }
8.1125 + }
8.1126 +
8.1127 + /* Do not need to implement it, the default way is ok.
8.1128 + public boolean equals(java.lang.Object obj) {
8.1129 + return obj == this;
8.1130 + }
8.1131 + */
8.1132 + @Override
8.1133 + public String toString() {
8.1134 + return super.toString() + " for " + reference.template;
8.1135 + }
8.1136 + }
8.1137 + // end of R
8.1138 +
8.1139 + /** A class that can be used by the creator of the AbstractLookup to
8.1140 + * control its content. It can be passed to AbstractLookup constructor
8.1141 + * and used to add and remove pairs.
8.1142 + *
8.1143 + * @since 1.25
8.1144 + */
8.1145 + public static class Content extends Object implements Serializable {
8.1146 + private static final long serialVersionUID = 1L;
8.1147 +
8.1148 + // one of them is always null (except attach stage)
8.1149 +
8.1150 + /** abstract lookup we are connected to */
8.1151 + private AbstractLookup al;
8.1152 + private transient Object notifyIn;
8.1153 +
8.1154 + /** Default constructor.
8.1155 + */
8.1156 + public Content() {
8.1157 + this(null);
8.1158 + }
8.1159 +
8.1160 + /** Creates a content associated with an executor to handle dispatch
8.1161 + * of changes.
8.1162 + * @param notifyIn the executor to notify changes in
8.1163 + * @since 7.16
8.1164 + */
8.1165 + public Content(Executor notifyIn) {
8.1166 + this.notifyIn = notifyIn;
8.1167 + }
8.1168 +
8.1169 + /** for testing purposes */
8.1170 + final void attachExecutor(Executor notifyIn) {
8.1171 + this.notifyIn = notifyIn;
8.1172 + }
8.1173 +
8.1174 + /** A lookup attaches to this object.
8.1175 + */
8.1176 + final synchronized void attach(AbstractLookup al) {
8.1177 + if (this.al == null) {
8.1178 + this.al = al;
8.1179 +
8.1180 + ArrayList<Pair> ep = getEarlyPairs();
8.1181 + if (ep != null) {
8.1182 + notifyIn = null;
8.1183 + setPairs(ep);
8.1184 + }
8.1185 + } else {
8.1186 + throw new IllegalStateException(
8.1187 + "Trying to use content for " + al + " but it is already used for " + this.al
8.1188 + ); // NOI18N
8.1189 + }
8.1190 + }
8.1191 +
8.1192 + /** The method to add instance to the lookup with.
8.1193 + * @param pair class/instance pair
8.1194 + */
8.1195 + public final void addPair(Pair<?> pair) {
8.1196 + AbstractLookup a = al;
8.1197 + Executor e = getExecutor();
8.1198 +
8.1199 + if (a != null || e != null) {
8.1200 + a.addPair(pair, e);
8.1201 + } else {
8.1202 + if (notifyIn == null) {
8.1203 + notifyIn = new ArrayList<Pair>(3);
8.1204 + }
8.1205 +
8.1206 + getEarlyPairs().add(pair);
8.1207 + }
8.1208 + }
8.1209 +
8.1210 + /** Remove instance.
8.1211 + * @param pair class/instance pair
8.1212 + */
8.1213 + public final void removePair(Pair<?> pair) {
8.1214 + AbstractLookup a = al;
8.1215 + Executor e = getExecutor();
8.1216 +
8.1217 + if (a != null || e != null) {
8.1218 + a.removePair(pair, e);
8.1219 + } else {
8.1220 + if (notifyIn == null) {
8.1221 + notifyIn = new ArrayList<Pair>(3);
8.1222 + }
8.1223 +
8.1224 + getEarlyPairs().remove(pair);
8.1225 + }
8.1226 + }
8.1227 +
8.1228 + /** Changes all pairs in the lookup to new values.
8.1229 + * @param c the collection of (Pair) objects
8.1230 + */
8.1231 + public final void setPairs(Collection<? extends Pair> c) {
8.1232 + AbstractLookup a = al;
8.1233 + Executor e = getExecutor();
8.1234 +
8.1235 + if (a != null || e != null) {
8.1236 + a.setPairs(c, e);
8.1237 + } else {
8.1238 + notifyIn = new ArrayList<Pair>(c);
8.1239 + }
8.1240 + }
8.1241 +
8.1242 + @SuppressWarnings("unchecked")
8.1243 + private ArrayList<Pair> getEarlyPairs() {
8.1244 + Object o = notifyIn;
8.1245 + return o instanceof ArrayList ? (ArrayList<Pair>)o : null;
8.1246 + }
8.1247 +
8.1248 + private Executor getExecutor() {
8.1249 + Object o = notifyIn;
8.1250 + return o instanceof Executor ? (Executor)o : null;
8.1251 + }
8.1252 + }
8.1253 + // end of Content
8.1254 +
8.1255 + /** Just a holder for index & modified values.
8.1256 + */
8.1257 + final static class Info extends Object {
8.1258 + public int index;
8.1259 + public Object transaction;
8.1260 +
8.1261 + public Info(int i, Object t) {
8.1262 + index = i;
8.1263 + transaction = t;
8.1264 + }
8.1265 + }
8.1266 +
8.1267 + /** Reference to a result R
8.1268 + */
8.1269 + static final class ReferenceToResult<T> extends WeakReference<R<T>> implements Runnable {
8.1270 + /** next refernece in chain, modified only from AbstractLookup or this */
8.1271 + private ReferenceToResult<?> next;
8.1272 +
8.1273 + /** the template for the result */
8.1274 + public final Template<T> template;
8.1275 +
8.1276 + /** the lookup we are attached to */
8.1277 + public final AbstractLookup lookup;
8.1278 +
8.1279 + /** caches for results */
8.1280 + public Object caches;
8.1281 +
8.1282 + /** Creates a weak refernece to a new result R in context of lookup
8.1283 + * for given template
8.1284 + */
8.1285 + private ReferenceToResult(R<T> result, AbstractLookup lookup, Template<T> template) {
8.1286 + super(result, activeQueue());
8.1287 + this.template = template;
8.1288 + this.lookup = lookup;
8.1289 + getResult().reference = this;
8.1290 + }
8.1291 +
8.1292 + /** Returns the result or null
8.1293 + */
8.1294 + R<T> getResult() {
8.1295 + return get();
8.1296 + }
8.1297 +
8.1298 + /** Cleans the reference. Implements Runnable interface, do not call
8.1299 + * directly.
8.1300 + */
8.1301 + public void run() {
8.1302 + lookup.cleanUpResult(this.template);
8.1303 + }
8.1304 +
8.1305 + /** Clones the reference list to given Storage.
8.1306 + * @param storage storage to clone to
8.1307 + */
8.1308 + public void cloneList(AbstractLookup.Storage<?> storage) {
8.1309 + ReferenceIterator it = new ReferenceIterator(this);
8.1310 +
8.1311 + while (it.next()) {
8.1312 + ReferenceToResult<?> current = it.current();
8.1313 + ReferenceToResult<?> newRef = current.cloneRef();
8.1314 + newRef.next = storage.registerReferenceToResult(newRef);
8.1315 + newRef.caches = current.caches;
8.1316 +
8.1317 + if (current.caches == current) {
8.1318 + current.getResult().initItems(storage);
8.1319 + }
8.1320 + }
8.1321 + }
8.1322 +
8.1323 + private ReferenceToResult<T> cloneRef() {
8.1324 + return new ReferenceToResult<T>(getResult(), lookup, template);
8.1325 + }
8.1326 + }
8.1327 + // end of ReferenceToResult
8.1328 +
8.1329 + /** Supporting class to iterate over linked list of ReferenceToResult
8.1330 + * Use:
8.1331 + * <PRE>
8.1332 + * ReferenceIterator it = new ReferenceIterator (this.ref);
8.1333 + * while (it.next ()) {
8.1334 + * it.current (): // do some work
8.1335 + * }
8.1336 + * this.ref = it.first (); // remember the first one
8.1337 + */
8.1338 + static final class ReferenceIterator extends Object {
8.1339 + private ReferenceToResult<?> first;
8.1340 + private ReferenceToResult<?> current;
8.1341 +
8.1342 + /** hard reference to current result, so it is not GCed meanwhile */
8.1343 + private R<?> currentResult;
8.1344 +
8.1345 + /** Initializes the iterator with first reference.
8.1346 + */
8.1347 + public ReferenceIterator(ReferenceToResult<?> first) {
8.1348 + this.first = first;
8.1349 + }
8.1350 +
8.1351 + /** Moves the current to next possition */
8.1352 + public boolean next() {
8.1353 + ReferenceToResult<?> prev;
8.1354 + ReferenceToResult<?> ref;
8.1355 +
8.1356 + if (current == null) {
8.1357 + ref = first;
8.1358 + prev = null;
8.1359 + } else {
8.1360 + prev = current;
8.1361 + ref = current.next;
8.1362 + }
8.1363 +
8.1364 + while (ref != null) {
8.1365 + R<?> result = ref.get();
8.1366 +
8.1367 + if (result == null) {
8.1368 + if (prev == null) {
8.1369 + // move the head
8.1370 + first = ref.next;
8.1371 + } else {
8.1372 + // skip over this reference
8.1373 + prev.next = ref.next;
8.1374 + }
8.1375 +
8.1376 + prev = ref;
8.1377 + ref = ref.next;
8.1378 + } else {
8.1379 + // we have found next item
8.1380 + currentResult = result;
8.1381 + current = ref;
8.1382 +
8.1383 + return true;
8.1384 + }
8.1385 + }
8.1386 +
8.1387 + currentResult = null;
8.1388 + current = null;
8.1389 +
8.1390 + return false;
8.1391 + }
8.1392 +
8.1393 + /** Access to current reference.
8.1394 + */
8.1395 + public ReferenceToResult<?> current() {
8.1396 + return current;
8.1397 + }
8.1398 +
8.1399 + /** Access to reference that is supposed to be the first one.
8.1400 + */
8.1401 + public ReferenceToResult<?> first() {
8.1402 + return first;
8.1403 + }
8.1404 + }
8.1405 +
8.1406 + /** Signals that a lookup is being modified from a lookup query.
8.1407 + *
8.1408 + * @author Jaroslav Tulach
8.1409 + */
8.1410 + static final class ISE extends IllegalStateException {
8.1411 + static final long serialVersionUID = 100L;
8.1412 +
8.1413 + /** list of jobs to execute. */
8.1414 + private java.util.List<Job> jobs;
8.1415 +
8.1416 + /** @param msg message
8.1417 + */
8.1418 + public ISE(String msg) {
8.1419 + super(msg);
8.1420 + }
8.1421 +
8.1422 + /** Registers a job to be executed partially out and partially in
8.1423 + * the lock over storage.
8.1424 + */
8.1425 + public void registerJob(Job job) {
8.1426 + if (jobs == null) {
8.1427 + jobs = new java.util.ArrayList<Job>();
8.1428 + }
8.1429 +
8.1430 + jobs.add(job);
8.1431 + }
8.1432 +
8.1433 + /** Executes the jobs outside, and then inside a locked session.
8.1434 + */
8.1435 + public void recover(AbstractLookup lookup) {
8.1436 + if (jobs == null) {
8.1437 + // no recovery plan, throw itself
8.1438 + throw this;
8.1439 + }
8.1440 +
8.1441 + for (Job j : jobs) {
8.1442 + j.before();
8.1443 + }
8.1444 +
8.1445 + AbstractLookup.Storage s = lookup.enterStorage();
8.1446 +
8.1447 + try {
8.1448 + for (Job j : jobs) {
8.1449 + j.inside();
8.1450 + }
8.1451 + } finally {
8.1452 + lookup.exitStorage();
8.1453 + }
8.1454 + }
8.1455 +
8.1456 + /** A job to be executed partially outside and partially inside
8.1457 + * the storage lock.
8.1458 + */
8.1459 + static interface Job {
8.1460 + public void before();
8.1461 +
8.1462 + public void inside();
8.1463 + }
8.1464 + }
8.1465 + // end of ISE
8.1466 +}
9.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
9.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/Lookups.java Fri Jan 22 10:02:41 2010 -0500
9.3 @@ -0,0 +1,325 @@
9.4 +/*
9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
9.6 + *
9.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
9.8 + *
9.9 + * The contents of this file are subject to the terms of either the GNU
9.10 + * General Public License Version 2 only ("GPL") or the Common
9.11 + * Development and Distribution License("CDDL") (collectively, the
9.12 + * "License"). You may not use this file except in compliance with the
9.13 + * License. You can obtain a copy of the License at
9.14 + * http://www.netbeans.org/cddl-gplv2.html
9.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
9.16 + * specific language governing permissions and limitations under the
9.17 + * License. When distributing the software, include this License Header
9.18 + * Notice in each file and include the License file at
9.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
9.20 + * particular file as subject to the "Classpath" exception as provided
9.21 + * by Sun in the GPL Version 2 section of the License file that
9.22 + * accompanied this code. If applicable, add the following below the
9.23 + * License Header, with the fields enclosed by brackets [] replaced by
9.24 + * your own identifying information:
9.25 + * "Portions Copyrighted [year] [name of copyright owner]"
9.26 + *
9.27 + * Contributor(s):
9.28 + *
9.29 + * The Original Software is NetBeans. The Initial Developer of the Original
9.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2009 Sun
9.31 + * Microsystems, Inc. All Rights Reserved.
9.32 + *
9.33 + * If you wish your version of this file to be governed by only the CDDL
9.34 + * or only the GPL Version 2, indicate your decision by adding
9.35 + * "[Contributor] elects to include this software in this distribution
9.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
9.37 + * single choice of license, a recipient has the option to distribute
9.38 + * your version of this file under either the CDDL, the GPL Version 2 or
9.39 + * to extend the choice of license to its licensees as provided above.
9.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
9.41 + * Version 2 license, then the option applies only if the new code is
9.42 + * made subject to such option by the copyright holder.
9.43 + */
9.44 +
9.45 +package org.openide.util.lookup;
9.46 +
9.47 +import java.lang.ref.Reference;
9.48 +import java.lang.ref.WeakReference;
9.49 +import java.util.Arrays;
9.50 +import java.util.Collections;
9.51 +import java.util.HashMap;
9.52 +import java.util.Map;
9.53 +import org.openide.util.Lookup;
9.54 +import org.openide.util.lookup.implspi.NamedServicesProvider;
9.55 +
9.56 +/**
9.57 + * Static factory methods for creating common lookup implementations.
9.58 + *
9.59 + * @author David Strupl
9.60 + * @since 2.21
9.61 + */
9.62 +public class Lookups {
9.63 +
9.64 + /** static methods only */
9.65 + private Lookups() {}
9.66 +
9.67 + /**
9.68 + * Creates a singleton lookup. It means lookup that contains only
9.69 + * one object specified via the supplied parameter. The lookup will
9.70 + * either return the object or null if the supplied template does
9.71 + * not match the class. If the specified argument is null the method
9.72 + * will end with NullPointerException.
9.73 + * @return Fully initialized lookup object ready to use
9.74 + * @throws NullPointerException if the supplied argument is null
9.75 + * @since 2.21
9.76 + */
9.77 + public static Lookup singleton(Object objectToLookup) {
9.78 + if (objectToLookup == null) {
9.79 + throw new NullPointerException();
9.80 + }
9.81 +
9.82 + return new SingletonLookup(objectToLookup);
9.83 + }
9.84 +
9.85 + /**
9.86 + * Creates a lookup that contains an array of objects specified via the
9.87 + * parameter. The resulting lookup is fixed in the following sense: it
9.88 + * contains only fixed set of objects passed in by the array parameter.
9.89 + * Its contents never changes so registering listeners on such lookup
9.90 + * does not have any observable effect (the listeners are never called).
9.91 + *
9.92 + * @param objectsToLookup list of objects to include
9.93 + * @return Fully initialized lookup object ready to use
9.94 + * @throws NullPointerException if the supplied argument is null
9.95 + * @since 2.21
9.96 + *
9.97 + */
9.98 + public static Lookup fixed(Object... objectsToLookup) {
9.99 + if (objectsToLookup == null) {
9.100 + throw new NullPointerException();
9.101 + }
9.102 +
9.103 + if (objectsToLookup.length == 0) {
9.104 + return Lookup.EMPTY;
9.105 + }
9.106 +
9.107 + if (objectsToLookup.length == 1) {
9.108 + return singleton(objectsToLookup[0]);
9.109 + }
9.110 +
9.111 + return new SimpleLookup(Arrays.asList(objectsToLookup));
9.112 + }
9.113 +
9.114 + /**
9.115 + * Creates a lookup that contains an array of objects specified via the
9.116 + * parameter. The resulting lookup is fixed in the following sense: it
9.117 + * contains only fixed set of objects passed in by the array parameter.
9.118 + * The objects returned from this lookup are converted to real objects
9.119 + * before they are returned by the lookup.
9.120 + * Its contents never changes so registering listeners on such lookup
9.121 + * does not have any observable effect (the listeners are never called).
9.122 + *
9.123 + * @return Fully initialized lookup object ready to use
9.124 + * @throws NullPointerException if the any of the arguments is null
9.125 + * @since 2.21
9.126 + *
9.127 + */
9.128 + public static <T,R> Lookup fixed(T[] keys, InstanceContent.Convertor<? super T,R> convertor) {
9.129 + if (keys == null) {
9.130 + throw new NullPointerException();
9.131 + }
9.132 +
9.133 + if (convertor == null) {
9.134 + throw new NullPointerException();
9.135 + }
9.136 +
9.137 + return new SimpleLookup(Arrays.asList(keys), convertor);
9.138 + }
9.139 +
9.140 + /** Creates a lookup that delegates to another one but that one can change
9.141 + * from time to time. The returned lookup checks every time somebody calls
9.142 + * <code>lookup</code> or <code>lookupItem</code> method whether the
9.143 + * provider still returns the same lookup. If not, it updates state of
9.144 + * all {@link org.openide.util.Lookup.Result}s
9.145 + * that it created (and that still exists).
9.146 + * <P>
9.147 + * The user of this method has to implement its provider's <code>getLookup</code>
9.148 + * method (must be thread safe and fast, will be called often and from any thread)
9.149 + * pass it to this method and use the returned lookup. Whenever the user
9.150 + * changes the return value from the <code>getLookup</code> method and wants
9.151 + * to notify listeners on the lookup about that it should trigger the event
9.152 + * firing, for example by calling <code>lookup.lookup (Object.class)</code>
9.153 + * directly on the lookup returned by this method
9.154 + * that forces a check of the return value of {@link org.openide.util.Lookup.Provider#getLookup}</code>.
9.155 + *
9.156 + * @param provider the provider that returns a lookup to delegate to
9.157 + * @return lookup delegating to the lookup returned by the provider
9.158 + * @since 3.9
9.159 + */
9.160 + public static Lookup proxy(Lookup.Provider provider) {
9.161 + return new SimpleProxyLookup(provider);
9.162 + }
9.163 +
9.164 + /** Returns a lookup that implements the JDK1.3 JAR services mechanism and delegates
9.165 + * to META-INF/services/name.of.class files.
9.166 + * <p>Some extensions to the JAR services specification are implemented:
9.167 + * <ol>
9.168 + * <li>An entry may be followed by a line of the form <code>#position=<i>integer</i></code>
9.169 + * to specify ordering. (Smaller numbers first, entries with unspecified position last.)
9.170 + * <li>A line of the form <code>#-<i>classname</i></code> suppresses an entry registered
9.171 + * in another file, so can be used to supersede one implementation with another.
9.172 + * </ol>
9.173 + * <p>Note: It is not dynamic - so if you need to change the classloader or JARs,
9.174 + * wrap it in a {@link ProxyLookup} and change the delegate when necessary.
9.175 + * Existing instances will be kept if the implementation classes are unchanged,
9.176 + * so there is "stability" in doing this provided some parent loaders are the same
9.177 + * as the previous ones.
9.178 + * @since 3.35
9.179 + * @see ServiceProvider
9.180 + */
9.181 + public static Lookup metaInfServices(ClassLoader classLoader) {
9.182 + return new MetaInfServicesLookup(classLoader, "META-INF/services/"); // NOI18N
9.183 + }
9.184 +
9.185 + /** Returns a lookup that behaves exactly like {@link #metaInfServices(ClassLoader)}
9.186 + * except that it does not read data from <code>META-INF/services/</code>, but instead
9.187 + * from the specified prefix.
9.188 + * @param classLoader class loader to use for loading
9.189 + * @param prefix prefix to prepend to the class name when searching
9.190 + * @since 7.9
9.191 + */
9.192 + public static Lookup metaInfServices(ClassLoader classLoader, String prefix) {
9.193 + return new MetaInfServicesLookup(classLoader, prefix);
9.194 + }
9.195 +
9.196 + /** Creates a <q>named</q> lookup.
9.197 + * It is a lookup identified by a given path.
9.198 + * Two lookups with the same path should have the same content.
9.199 + * <p>It is expected that each <q>named</q> lookup
9.200 + * will contain a superset of what would be created by:
9.201 + * <code>{@linkplain #metaInfServices(ClassLoader,String) metaInfServices}(theRightLoader, "META-INF/namedservices/" + path + "/")</code>
9.202 + *
9.203 + * <p class="nonnormative">Various environments can add their own
9.204 + * extensions to its content. As such
9.205 + * {@link Lookups#forPath(java.lang.String)} can combine lookups
9.206 + * from several sources. In current NetBeans Runtime Container, two lookups are used:
9.207 + * </p>
9.208 + * <ul class="nonnormative">
9.209 + * <li><code>Lookups.metaInfServices("META-INF/namedservices/" + path)</code></li>
9.210 + * <li><code>org.openide.loaders.FolderLookup(path)</code></li>
9.211 + * </ul>
9.212 + * <p class="nonnormative">
9.213 + * Please note that these lookups differ in the way they inspect sub-folders.
9.214 + * The first lookup just returns instances from the given path, ignoring
9.215 + * sub-folders, the second one retrieves instances from the whole sub-tree.
9.216 + * </p>
9.217 + * <p>
9.218 + * Read more about the <a href="@org-openide-util@/org/openide/util/doc-files/api.html#folderlookup">usage of this method</a>.
9.219 + *
9.220 + * @param path the path identifying the lookup, e.g. <code>Projects/Actions</code>
9.221 + * @return lookup associated with this path
9.222 + * @since 7.9
9.223 + */
9.224 + public static Lookup forPath(String path) {
9.225 + if (!path.endsWith("/")) {
9.226 + path = path + "/";
9.227 + }
9.228 + return NamedServicesProvider.forPath(path);
9.229 + }
9.230 +
9.231 + /** Creates a lookup that wraps another one and filters out instances
9.232 + * of specified classes. If you have a lookup and
9.233 + * you want to remove all instances of ActionMap you can use:
9.234 + * <pre>
9.235 + * l = Lookups.exclude(lookup, ActionMap.class);
9.236 + * </pre>
9.237 + * Then anybody who asks for <code>l.lookup(ActionMap.class)</code> or
9.238 + * subclass will get <code>null</code>. Even if the original lookup contains the
9.239 + * value.
9.240 + * To create empty lookup (well, just an example, otherwise use {@link Lookup#EMPTY}) one could use:
9.241 + * <pre>
9.242 + * Lookup.exclude(anyLookup, Object.class);
9.243 + * </pre>
9.244 + * as any instance in any lookup is of type Object and thus would be excluded.
9.245 + * <p>
9.246 + * The complete behavior can be described as <code>classes</code> being
9.247 + * a barrier. For an object not to be excluded, there has to be an inheritance
9.248 + * path between the queried class and the actual class of the instance,
9.249 + * that is not blocked by any of the excluded classes:
9.250 + * <pre>
9.251 + * interface A {}
9.252 + * interface B {}
9.253 + * class C implements A, B {}
9.254 + * Object c = new C();
9.255 + * Lookup l1 = Lookups.singleton(c);
9.256 + * Lookup l2 = Lookups.exclude(l1, A.class);
9.257 + * assertNull("A is directly excluded", l2.lookup(A.class));
9.258 + * assertEquals("Returns C as A.class is not between B and C", c, l2.lookup(B.class));
9.259 + * </pre>
9.260 + * For more info check the
9.261 + * <a href="http://hg.netbeans.org/main-golden/annotate/4883eaeda744/openide.util/test/unit/src/org/openide/util/lookup/ExcludingLookupTest.java">
9.262 + * excluding lookup tests</a> and the discussion in issue
9.263 + * <a href="http://openide.netbeans.org/issues/show_bug.cgi?id=53058">53058</a>.
9.264 + *
9.265 + * @param lookup the original lookup that should be filtered
9.266 + * @param classes array of classes those instances should be excluded
9.267 + * @since 5.4
9.268 + */
9.269 + public static Lookup exclude(Lookup lookup, Class... classes) {
9.270 + return new ExcludingLookup(lookup, classes);
9.271 + }
9.272 +
9.273 + /** Creates <code>Lookup.Item</code> representing the instance passed in.
9.274 + *
9.275 + * @param instance the object for which Lookup.Item should be creted
9.276 + * @param id unique identification of the object, for details see {@link org.openide.util.Lookup.Item#getId},
9.277 + * can be <code>null</code>
9.278 + * @return lookup item representing instance
9.279 + * @since 4.8
9.280 + */
9.281 + public static <T> Lookup.Item<T> lookupItem(T instance, String id) {
9.282 + return new LookupItem<T>(instance, id);
9.283 + }
9.284 +
9.285 + private static class LookupItem<T> extends Lookup.Item<T> {
9.286 + private String id;
9.287 + private T instance;
9.288 +
9.289 + public LookupItem(T instance) {
9.290 + this(instance, null);
9.291 + }
9.292 +
9.293 + public LookupItem(T instance, String id) {
9.294 + this.id = id;
9.295 + this.instance = instance;
9.296 + }
9.297 +
9.298 + public String getDisplayName() {
9.299 + return getId();
9.300 + }
9.301 +
9.302 + public String getId() {
9.303 + return (id == null) ? instance.toString() : id;
9.304 + }
9.305 +
9.306 + public T getInstance() {
9.307 + return instance;
9.308 + }
9.309 +
9.310 + @SuppressWarnings("unchecked")
9.311 + public Class<? extends T> getType() {
9.312 + return (Class<? extends T>)instance.getClass();
9.313 + }
9.314 +
9.315 + public @Override boolean equals(Object object) {
9.316 + if (object instanceof LookupItem) {
9.317 + return instance == ((LookupItem) object).getInstance();
9.318 + }
9.319 +
9.320 + return false;
9.321 + }
9.322 +
9.323 + public @Override int hashCode() {
9.324 + return instance.hashCode();
9.325 + }
9.326 + }
9.327 + // End of LookupItem class
9.328 +}
10.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
10.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/implspi/AbstractServiceProviderProcessor.java Fri Jan 22 10:02:41 2010 -0500
10.3 @@ -0,0 +1,307 @@
10.4 +/*
10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
10.6 + *
10.7 + * Copyright 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 + * If you wish your version of this file to be governed by only the CDDL
10.28 + * or only the GPL Version 2, indicate your decision by adding
10.29 + * "[Contributor] elects to include this software in this distribution
10.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
10.31 + * single choice of license, a recipient has the option to distribute
10.32 + * your version of this file under either the CDDL, the GPL Version 2 or
10.33 + * to extend the choice of license to its licensees as provided above.
10.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
10.35 + * Version 2 license, then the option applies only if the new code is
10.36 + * made subject to such option by the copyright holder.
10.37 + *
10.38 + * Contributor(s):
10.39 + *
10.40 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
10.41 + */
10.42 +
10.43 +package org.openide.util.lookup.implspi;
10.44 +
10.45 +import java.io.BufferedReader;
10.46 +import java.io.FileNotFoundException;
10.47 +import java.io.IOException;
10.48 +import java.io.InputStream;
10.49 +import java.io.InputStreamReader;
10.50 +import java.io.OutputStream;
10.51 +import java.io.OutputStreamWriter;
10.52 +import java.io.PrintWriter;
10.53 +import java.lang.annotation.Annotation;
10.54 +import java.util.ArrayList;
10.55 +import java.util.HashMap;
10.56 +import java.util.List;
10.57 +import java.util.Map;
10.58 +import java.util.Set;
10.59 +import java.util.WeakHashMap;
10.60 +import javax.annotation.processing.AbstractProcessor;
10.61 +import javax.annotation.processing.ProcessingEnvironment;
10.62 +import javax.annotation.processing.RoundEnvironment;
10.63 +import javax.lang.model.element.AnnotationMirror;
10.64 +import javax.lang.model.element.AnnotationValue;
10.65 +import javax.lang.model.element.Element;
10.66 +import javax.lang.model.element.ExecutableElement;
10.67 +import javax.lang.model.element.Modifier;
10.68 +import javax.lang.model.element.TypeElement;
10.69 +import javax.lang.model.type.TypeMirror;
10.70 +import javax.lang.model.util.ElementFilter;
10.71 +import javax.tools.Diagnostic.Kind;
10.72 +import javax.tools.FileObject;
10.73 +import javax.tools.StandardLocation;
10.74 +
10.75 +/**
10.76 + * Infrastructure for generating {@code META-INF/services/*} and
10.77 + * {@code META-INF/namedservices/*} registrations from annotations.
10.78 + * @since 8.1
10.79 + */
10.80 +public abstract class AbstractServiceProviderProcessor extends AbstractProcessor {
10.81 +
10.82 + private final Map<ProcessingEnvironment,Map<String,List<String>>> outputFilesByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<String>>>();
10.83 + private final Map<ProcessingEnvironment,Map<String,List<Element>>> originatingElementsByProcessor = new WeakHashMap<ProcessingEnvironment,Map<String,List<Element>>>();
10.84 + private final Map<TypeElement,Boolean> verifiedClasses = new WeakHashMap<TypeElement,Boolean>();
10.85 +
10.86 + /** Throws IllegalStateException. For access by selected subclasses. */
10.87 + protected AbstractServiceProviderProcessor() {
10.88 + if (getClass().getName().equals("org.netbeans.modules.openide.util.ServiceProviderProcessor")) { // NOI18N
10.89 + // OK subclass
10.90 + return;
10.91 + }
10.92 + if (getClass().getName().equals("org.netbeans.modules.openide.util.URLStreamHandlerRegistrationProcessor")) { // NOI18N
10.93 + // OK subclass
10.94 + return;
10.95 + }
10.96 + throw new IllegalStateException();
10.97 + }
10.98 +
10.99 + public @Override final boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
10.100 + if (roundEnv.errorRaised()) {
10.101 + return false;
10.102 + }
10.103 + if (roundEnv.processingOver()) {
10.104 + writeServices();
10.105 + outputFilesByProcessor.clear();
10.106 + originatingElementsByProcessor.clear();
10.107 + return true;
10.108 + } else {
10.109 + return handleProcess(annotations, roundEnv);
10.110 + }
10.111 + }
10.112 +
10.113 + /**
10.114 + * The regular body of {@link #process}.
10.115 + * Called during regular rounds if there are no outstanding errors.
10.116 + * In the last round, one of the processors will write out generated registrations.
10.117 + * @param annotations as in {@link #process}
10.118 + * @param roundEnv as in {@link #process}
10.119 + * @return as in {@link #process}
10.120 + */
10.121 + protected abstract boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv);
10.122 +
10.123 + /**
10.124 + * Register a service.
10.125 + * If the class does not have an appropriate signature, an error will be printed and the registration skipped.
10.126 + * @param clazz the service implementation type
10.127 + * @param annotation the (top-level) annotation registering the service, for diagnostic purposes
10.128 + * @param type the type to which the implementation must be assignable
10.129 + * @param path a path under which to register, or "" if inapplicable
10.130 + * @param position a position at which to register, or {@link Integer#MAX_VALUE} to skip
10.131 + * @param supersedes possibly empty list of implementation to supersede
10.132 + */
10.133 + protected final void register(TypeElement clazz, Class<? extends Annotation> annotation,
10.134 + TypeMirror type, String path, int position, String[] supersedes) {
10.135 + Boolean verify = verifiedClasses.get(clazz);
10.136 + if (verify == null) {
10.137 + verify = verifyServiceProviderSignature(clazz, annotation);
10.138 + verifiedClasses.put(clazz, verify);
10.139 + }
10.140 + if (!verify) {
10.141 + return;
10.142 + }
10.143 + String impl = processingEnv.getElementUtils().getBinaryName(clazz).toString();
10.144 + String xface = processingEnv.getElementUtils().getBinaryName((TypeElement) processingEnv.getTypeUtils().asElement(type)).toString();
10.145 + if (!processingEnv.getTypeUtils().isAssignable(clazz.asType(), type)) {
10.146 + AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
10.147 + processingEnv.getMessager().printMessage(Kind.ERROR, impl + " is not assignable to " + xface,
10.148 + clazz, ann, findAnnotationValue(ann, "service"));
10.149 + return;
10.150 + }
10.151 + processingEnv.getMessager().printMessage(Kind.NOTE,
10.152 + impl + " to be registered as a " + xface + (path.length() > 0 ? " under " + path : ""));
10.153 + String rsrc = (path.length() > 0 ? "META-INF/namedservices/" + path + "/" : "META-INF/services/") + xface;
10.154 + {
10.155 + Map<String,List<Element>> originatingElements = originatingElementsByProcessor.get(processingEnv);
10.156 + if (originatingElements == null) {
10.157 + originatingElements = new HashMap<String,List<Element>>();
10.158 + originatingElementsByProcessor.put(processingEnv, originatingElements);
10.159 + }
10.160 + List<Element> origEls = originatingElements.get(rsrc);
10.161 + if (origEls == null) {
10.162 + origEls = new ArrayList<Element>();
10.163 + originatingElements.put(rsrc, origEls);
10.164 + }
10.165 + origEls.add(clazz);
10.166 + }
10.167 + Map<String,List<String>> outputFiles = outputFilesByProcessor.get(processingEnv);
10.168 + if (outputFiles == null) {
10.169 + outputFiles = new HashMap<String,List<String>>();
10.170 + outputFilesByProcessor.put(processingEnv, outputFiles);
10.171 + }
10.172 + List<String> lines = outputFiles.get(rsrc);
10.173 + if (lines == null) {
10.174 + lines = new ArrayList<String>();
10.175 + try {
10.176 + try {
10.177 + FileObject in = processingEnv.getFiler().getResource(StandardLocation.SOURCE_PATH, "", rsrc);
10.178 + in.openInputStream().close();
10.179 + processingEnv.getMessager().printMessage(Kind.ERROR,
10.180 + "Cannot generate " + rsrc + " because it already exists in sources: " + in.toUri());
10.181 + return;
10.182 + } catch (NullPointerException ex) {
10.183 + // trying to prevent java.lang.NullPointerException
10.184 + // at com.sun.tools.javac.util.DefaultFileManager.getFileForOutput(DefaultFileManager.java:1078)
10.185 + // at com.sun.tools.javac.util.DefaultFileManager.getFileForOutput(DefaultFileManager.java:1054)
10.186 + // at com.sun.tools.javac.processing.JavacFiler.getResource(JavacFiler.java:434)
10.187 + // at org.netbeans.modules.openide.util.AbstractServiceProviderProcessor.register(AbstractServiceProviderProcessor.java:163)
10.188 + // at org.netbeans.modules.openide.util.ServiceProviderProcessor.register(ServiceProviderProcessor.java:99)
10.189 + } catch (FileNotFoundException x) {
10.190 + // Good.
10.191 + }
10.192 + try {
10.193 + FileObject in = processingEnv.getFiler().getResource(StandardLocation.CLASS_OUTPUT, "", rsrc);
10.194 + InputStream is = in.openInputStream();
10.195 + try {
10.196 + BufferedReader r = new BufferedReader(new InputStreamReader(is, "UTF-8"));
10.197 + String line;
10.198 + while ((line = r.readLine()) != null) {
10.199 + lines.add(line);
10.200 + }
10.201 + } finally {
10.202 + is.close();
10.203 + }
10.204 + } catch (FileNotFoundException x) {
10.205 + // OK, created for the first time
10.206 + }
10.207 + } catch (IOException x) {
10.208 + processingEnv.getMessager().printMessage(Kind.ERROR, x.toString());
10.209 + return;
10.210 + }
10.211 + outputFiles.put(rsrc, lines);
10.212 + }
10.213 + int idx = lines.indexOf(impl);
10.214 + if (idx != -1) {
10.215 + lines.remove(idx);
10.216 + while (lines.size() > idx && lines.get(idx).matches("#position=.+|#-.+")) {
10.217 + lines.remove(idx);
10.218 + }
10.219 + }
10.220 + lines.add(impl);
10.221 + if (position != Integer.MAX_VALUE) {
10.222 + lines.add("#position=" + position);
10.223 + }
10.224 + for (String exclude : supersedes) {
10.225 + lines.add("#-" + exclude);
10.226 + }
10.227 + }
10.228 +
10.229 + /**
10.230 + * @param element a source element
10.231 + * @param annotation a type of annotation
10.232 + * @return the instance of that annotation on the element, or null if not found
10.233 + */
10.234 + private AnnotationMirror findAnnotationMirror(Element element, Class<? extends Annotation> annotation) {
10.235 + for (AnnotationMirror ann : element.getAnnotationMirrors()) {
10.236 + if (processingEnv.getElementUtils().getBinaryName((TypeElement) ann.getAnnotationType().asElement()).
10.237 + contentEquals(annotation.getName())) {
10.238 + return ann;
10.239 + }
10.240 + }
10.241 + return null;
10.242 + }
10.243 +
10.244 + /**
10.245 + * @param annotation an annotation instance (null permitted)
10.246 + * @param name the name of an attribute of that annotation
10.247 + * @return the corresponding value if found
10.248 + */
10.249 + private AnnotationValue findAnnotationValue(AnnotationMirror annotation, String name) {
10.250 + if (annotation != null) {
10.251 + for (Map.Entry<? extends ExecutableElement,? extends AnnotationValue> entry : annotation.getElementValues().entrySet()) {
10.252 + if (entry.getKey().getSimpleName().contentEquals(name)) {
10.253 + return entry.getValue();
10.254 + }
10.255 + }
10.256 + }
10.257 + return null;
10.258 + }
10.259 +
10.260 + private final boolean verifyServiceProviderSignature(TypeElement clazz, Class<? extends Annotation> annotation) {
10.261 + AnnotationMirror ann = findAnnotationMirror(clazz, annotation);
10.262 + if (!clazz.getModifiers().contains(Modifier.PUBLIC)) {
10.263 + processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must be public", clazz, ann);
10.264 + return false;
10.265 + }
10.266 + if (clazz.getModifiers().contains(Modifier.ABSTRACT)) {
10.267 + processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must not be abstract", clazz, ann);
10.268 + return false;
10.269 + }
10.270 + {
10.271 + boolean hasDefaultCtor = false;
10.272 + for (ExecutableElement constructor : ElementFilter.constructorsIn(clazz.getEnclosedElements())) {
10.273 + if (constructor.getModifiers().contains(Modifier.PUBLIC) && constructor.getParameters().isEmpty()) {
10.274 + hasDefaultCtor = true;
10.275 + break;
10.276 + }
10.277 + }
10.278 + if (!hasDefaultCtor) {
10.279 + processingEnv.getMessager().printMessage(Kind.ERROR, clazz + " must have a public no-argument constructor", clazz, ann);
10.280 + return false;
10.281 + }
10.282 + }
10.283 + return true;
10.284 + }
10.285 +
10.286 + private void writeServices() {
10.287 + for (Map.Entry<ProcessingEnvironment,Map<String,List<String>>> outputFiles : outputFilesByProcessor.entrySet()) {
10.288 + for (Map.Entry<String, List<String>> entry : outputFiles.getValue().entrySet()) {
10.289 + try {
10.290 + FileObject out = processingEnv.getFiler().createResource(StandardLocation.CLASS_OUTPUT, "", entry.getKey(),
10.291 + originatingElementsByProcessor.get(outputFiles.getKey()).get(entry.getKey()).toArray(new Element[0]));
10.292 + OutputStream os = out.openOutputStream();
10.293 + try {
10.294 + PrintWriter w = new PrintWriter(new OutputStreamWriter(os, "UTF-8"));
10.295 + for (String line : entry.getValue()) {
10.296 + w.println(line);
10.297 + }
10.298 + w.flush();
10.299 + w.close();
10.300 + } finally {
10.301 + os.close();
10.302 + }
10.303 + } catch (IOException x) {
10.304 + processingEnv.getMessager().printMessage(Kind.ERROR, "Failed to write to " + entry.getKey() + ": " + x.toString());
10.305 + }
10.306 + }
10.307 + }
10.308 + }
10.309 +
10.310 +}
11.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
11.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/implspi/ActiveQueue.java Fri Jan 22 10:02:41 2010 -0500
11.3 @@ -0,0 +1,120 @@
11.4 +package org.openide.util.lookup.implspi;
11.5 +
11.6 +import java.lang.ref.Reference;
11.7 +import java.lang.ref.ReferenceQueue;
11.8 +import java.util.logging.Level;
11.9 +import java.util.logging.Logger;
11.10 +
11.11 +/**
11.12 + * Implementation of the active reference queue.
11.13 + * @since 8.1
11.14 + */
11.15 +public final class ActiveQueue {
11.16 +
11.17 + private ActiveQueue() {}
11.18 +
11.19 + private static final Logger LOGGER = Logger.getLogger(ActiveQueue.class.getName().replace('$', '.'));
11.20 + private static Impl activeReferenceQueue;
11.21 +
11.22 + /**
11.23 + * Gets the active reference queue.
11.24 + * @return the singleton queue
11.25 + */
11.26 + public static synchronized ReferenceQueue<Object> queue() {
11.27 + if (activeReferenceQueue == null) {
11.28 + activeReferenceQueue = new Impl(false);
11.29 + }
11.30 +
11.31 + activeReferenceQueue.ping();
11.32 +
11.33 + return activeReferenceQueue;
11.34 + }
11.35 +
11.36 + private static final class Impl extends ReferenceQueue<Object> implements Runnable {
11.37 +
11.38 + /** number of known outstanding references */
11.39 + private int count;
11.40 + private boolean deprecated;
11.41 +
11.42 + Impl(boolean deprecated) {
11.43 + super();
11.44 + this.deprecated = deprecated;
11.45 + }
11.46 +
11.47 + @Override
11.48 + public Reference<Object> poll() {
11.49 + throw new UnsupportedOperationException();
11.50 + }
11.51 +
11.52 + @Override
11.53 + public Reference<Object> remove(long timeout) throws IllegalArgumentException, InterruptedException {
11.54 + throw new InterruptedException();
11.55 + }
11.56 +
11.57 + @Override
11.58 + public Reference<Object> remove() throws InterruptedException {
11.59 + throw new InterruptedException();
11.60 + }
11.61 +
11.62 + public void run() {
11.63 + while (true) {
11.64 + try {
11.65 + Reference<?> ref = super.remove(0);
11.66 + LOGGER.finer("dequeued reference");
11.67 + if (!(ref instanceof Runnable)) {
11.68 + LOGGER.warning("A reference not implementing runnable has been added to the Utilities.activeReferenceQueue(): " + ref.getClass());
11.69 + continue;
11.70 + }
11.71 + if (deprecated) {
11.72 + LOGGER.warning("Utilities.ACTIVE_REFERENCE_QUEUE has been deprecated for " + ref.getClass() + " use Utilities.activeReferenceQueue");
11.73 + }
11.74 + // do the cleanup
11.75 + try {
11.76 + ((Runnable) ref).run();
11.77 + } catch (ThreadDeath td) {
11.78 + throw td;
11.79 + } catch (Throwable t) {
11.80 + // Should not happen.
11.81 + // If it happens, it is a bug in client code, notify!
11.82 + LOGGER.log(Level.WARNING, null, t);
11.83 + } finally {
11.84 + // to allow GC
11.85 + ref = null;
11.86 + }
11.87 + } catch (InterruptedException ex) {
11.88 + // Can happen during VM shutdown, it seems. Ignore.
11.89 + continue;
11.90 + }
11.91 + synchronized (this) {
11.92 + assert count > 0;
11.93 + count--;
11.94 + if (count == 0) {
11.95 + // We have processed all we have to process (for now at least).
11.96 + // Could be restarted later if ping() called again.
11.97 + // This could also happen in case someone called queue() once and tried
11.98 + // to use it for several references; in that case run() might never be called on
11.99 + // the later ones to be collected. Can't really protect against that situation.
11.100 + // See issue #86625 for details.
11.101 + LOGGER.fine("stopping thread");
11.102 + break;
11.103 + }
11.104 + }
11.105 + }
11.106 + }
11.107 +
11.108 + synchronized void ping() {
11.109 + if (count == 0) {
11.110 + Thread t = new Thread(this, "Active Reference Queue Daemon");
11.111 + t.setPriority(Thread.MIN_PRIORITY);
11.112 + t.setDaemon(true);
11.113 + t.start();
11.114 + LOGGER.fine("starting thread");
11.115 + } else {
11.116 + LOGGER.finer("enqueuing reference");
11.117 + }
11.118 + count++;
11.119 + }
11.120 +
11.121 + }
11.122 +
11.123 +}
12.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
12.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/implspi/NamedServicesProvider.java Fri Jan 22 10:02:41 2010 -0500
12.3 @@ -0,0 +1,137 @@
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.
12.31 + *
12.32 + * Portions Copyrighted 2006 Sun Microsystems, Inc.
12.33 + */
12.34 +
12.35 +package org.openide.util.lookup.implspi;
12.36 +
12.37 +import java.lang.ref.Reference;
12.38 +import java.lang.ref.WeakReference;
12.39 +import java.util.Collections;
12.40 +import java.util.HashMap;
12.41 +import java.util.Map;
12.42 +import org.openide.util.Lookup;
12.43 +import org.openide.util.lookup.Lookups;
12.44 +
12.45 +/** Infrastructure provider interface for those who control the overall
12.46 + * registration of services in the system. The first instance of this interface
12.47 + * found in {@link Lookup#getDefault()} is consulted when providing answers
12.48 + * to {@link Lookups#forPath(java.lang.String)} queries. Current implementation
12.49 + * is not ready for multiple instances of this interface (the first one wins)
12.50 + * and also changing the instances during runtime.
12.51 + *
12.52 + * <div class="nonnormative">
12.53 + * The basic implementation of this interface is provided in
12.54 + * <a href="@org-openide-filesystems@/overview-summary.html">Filesystem API</a>
12.55 + * and recognizes the
12.56 + * <a href="@org-openide-util@/org/openide/util/doc-files/api.html#instance-folders">.instance files</a>
12.57 + * registered in XML layers. As such one can rely on
12.58 + * <a href="@org-openide-util@/org/openide/util/doc-files/api.html#instance-folders">.instance files</a>
12.59 + * being recognized in unit tests, if the
12.60 + * <a href="@org-openide-filesystems@/overview-summary.html">Filesystem API</a>
12.61 + * is included.
12.62 + * The implementation
12.63 + * is then refined in
12.64 + * <a href="@org-netbeans-modules-settings@/overview-summary.html">Settings API</a>
12.65 + * to handle also <a href="@org-openide-util@/org/openide/util/doc-files/api.html#settings">.settings files</a>.
12.66 + * Again, including this module in unit tests
12.67 + * ensures
12.68 + * <a href="@org-openide-util@/org/openide/util/doc-files/api.html#settings">.settings files</a>
12.69 + * files are recognized.
12.70 + * </div>
12.71 + *
12.72 + * @author Jaroslav Tulach
12.73 + * @since 8.1
12.74 + */
12.75 +public abstract class NamedServicesProvider {
12.76 + private static final Map<String,Reference<Lookup>> namedServicesProviders = Collections.synchronizedMap(new HashMap<String,Reference<Lookup>>());
12.77 +
12.78 + public static Lookup forPath(String path) {
12.79 +
12.80 + Reference<Lookup> ref = namedServicesProviders.get(path);
12.81 + Lookup lkp = ref == null ? null : ref.get();
12.82 + if (lkp != null) {
12.83 + return lkp;
12.84 + }
12.85 + NamedServicesProvider prov = Lookup.getDefault().lookup(NamedServicesProvider.class);
12.86 + if (prov != null &&
12.87 + /* avoid stack overflow during initialization */
12.88 + !path.startsWith(
12.89 + "URLStreamHandler/"
12.90 + /*URLStreamHandlerRegistrationProcessor.REGISTRATION_PREFIX*/
12.91 + )
12.92 + ) {
12.93 + lkp = prov.create(path);
12.94 + } else {
12.95 + ClassLoader l = Lookup.getDefault().lookup(ClassLoader.class);
12.96 + if (l == null) {
12.97 + l = Thread.currentThread().getContextClassLoader();
12.98 + if (l == null) {
12.99 + l = NamedServicesProvider.class.getClassLoader();
12.100 + }
12.101 + }
12.102 + lkp = Lookups.metaInfServices(l, "META-INF/namedservices/" + path);
12.103 + }
12.104 +
12.105 + namedServicesProviders.put(path, new WeakReference<Lookup>(lkp));
12.106 + return lkp;
12.107 + }
12.108 +
12.109 + /** Throws an exception. Prevents unwanted instantiation of this class
12.110 + * by unknown subclasses.
12.111 + */
12.112 + protected NamedServicesProvider() {
12.113 + if (getClass().getName().equals("org.openide.util.lookup.PathInLookupTest$P")) { // NOI18N
12.114 + // OK for tests
12.115 + return;
12.116 + }
12.117 + if (getClass().getName().equals("org.openide.util.UtilitiesTest$NamedServicesProviderImpl")) { // NOI18N
12.118 + // OK for tests
12.119 + return;
12.120 + }
12.121 + if (getClass().getName().equals("org.netbeans.modules.openide.filesystems.RecognizeInstanceFiles")) { // NOI18N
12.122 + // OK for openide.filesystems
12.123 + return;
12.124 + }
12.125 + if (getClass().getName().equals("org.netbeans.modules.settings.RecognizeInstanceObjects")) { // NOI18N
12.126 + // OK for settings
12.127 + return;
12.128 + }
12.129 + throw new IllegalStateException();
12.130 + }
12.131 +
12.132 + /** Create the lookup for given path. Called as a result of query to
12.133 + * {@link Lookups#forPath(java.lang.String)}.
12.134 + *
12.135 + * @param path the identification of the path
12.136 + * @return the lookup representing objects in this path.
12.137 + */
12.138 + protected abstract Lookup create(String path);
12.139 +
12.140 +}
13.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
13.2 +++ b/openide.util.lookup/src/org/openide/util/lookup/implspi/package-info.java Fri Jan 22 10:02:41 2010 -0500
13.3 @@ -0,0 +1,43 @@
13.4 +/*
13.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
13.6 + *
13.7 + * Copyright 2010 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 + * If you wish your version of this file to be governed by only the CDDL
13.28 + * or only the GPL Version 2, indicate your decision by adding
13.29 + * "[Contributor] elects to include this software in this distribution
13.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
13.31 + * single choice of license, a recipient has the option to distribute
13.32 + * your version of this file under either the CDDL, the GPL Version 2 or
13.33 + * to extend the choice of license to its licensees as provided above.
13.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
13.35 + * Version 2 license, then the option applies only if the new code is
13.36 + * made subject to such option by the copyright holder.
13.37 + *
13.38 + * Contributor(s):
13.39 + *
13.40 + * Portions Copyrighted 2010 Sun Microsystems, Inc.
13.41 + */
13.42 +
13.43 +/**
13.44 + * Interfaces intended to be used within the NetBeans Platform.
13.45 + */
13.46 +package org.openide.util.lookup.implspi;
14.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
14.2 +++ b/openide.util.lookup/test/unit/src/org/netbeans/modules/openide/util/ActiveQueueTest.java Fri Jan 22 10:02:41 2010 -0500
14.3 @@ -0,0 +1,133 @@
14.4 +/*
14.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
14.6 + *
14.7 + * Copyright 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 + * If you wish your version of this file to be governed by only the CDDL
14.28 + * or only the GPL Version 2, indicate your decision by adding
14.29 + * "[Contributor] elects to include this software in this distribution
14.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
14.31 + * single choice of license, a recipient has the option to distribute
14.32 + * your version of this file under either the CDDL, the GPL Version 2 or
14.33 + * to extend the choice of license to its licensees as provided above.
14.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
14.35 + * Version 2 license, then the option applies only if the new code is
14.36 + * made subject to such option by the copyright holder.
14.37 + *
14.38 + * Contributor(s):
14.39 + *
14.40 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
14.41 + */
14.42 +
14.43 +package org.netbeans.modules.openide.util;
14.44 +
14.45 +import java.lang.ref.Reference;
14.46 +import java.lang.ref.ReferenceQueue;
14.47 +import java.lang.ref.WeakReference;
14.48 +import java.net.URL;
14.49 +import java.net.URLClassLoader;
14.50 +import org.netbeans.junit.NbTestCase;
14.51 +import org.openide.util.lookup.implspi.ActiveQueue;
14.52 +
14.53 +/**
14.54 + *
14.55 + * @author Jaroslav Tulach <jtulach@netbeans.org>
14.56 + */
14.57 +public class ActiveQueueTest extends NbTestCase{
14.58 +
14.59 + public ActiveQueueTest(String name) {
14.60 + super(name);
14.61 + }
14.62 +
14.63 + public void testMemoryLeak() throws Exception {
14.64 + final Class<?> u1 = ActiveQueue.class;
14.65 + class L extends URLClassLoader {
14.66 + public L() {
14.67 + super(new URL[] {u1.getProtectionDomain().getCodeSource().getLocation()}, u1.getClassLoader().getParent());
14.68 + }
14.69 + @Override
14.70 + protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
14.71 + if (name.equals(u1.getName()) || name.startsWith(u1.getName() + "$")) {
14.72 + Class c = findLoadedClass(name);
14.73 + if (c == null) {
14.74 + c = findClass(name);
14.75 + }
14.76 + if (resolve) {
14.77 + resolveClass(c);
14.78 + }
14.79 + return c;
14.80 + } else {
14.81 + return super.loadClass(name, resolve);
14.82 + }
14.83 + }
14.84 + }
14.85 + ClassLoader l = new L();
14.86 + Class<?> u2 = l.loadClass(u1.getName());
14.87 + assertEquals(l, u2.getClassLoader());
14.88 + Object obj = new Object();
14.89 + @SuppressWarnings("unchecked")
14.90 + ReferenceQueue<Object> q = (ReferenceQueue<Object>) u2.getMethod("queue").invoke(null);
14.91 + RunnableRef ref = new RunnableRef(obj, q);
14.92 + synchronized (ref) {
14.93 + obj = null;
14.94 + assertGC("Ref should be GC'ed as usual", ref);
14.95 + ref.wait();
14.96 + assertTrue("Run method has been executed", ref.executed);
14.97 + }
14.98 + Reference<?> r = new WeakReference<Object>(u2);
14.99 + q = null;
14.100 + u2 = null;
14.101 + l = null;
14.102 + assertGC("#86625: Utilities.class can also be collected now", r);
14.103 + }
14.104 +
14.105 +
14.106 + private static class RunnableRef extends WeakReference<Object>
14.107 + implements Runnable {
14.108 + public boolean wait;
14.109 + public boolean entered;
14.110 + public boolean executed;
14.111 +
14.112 + public RunnableRef (Object o) {
14.113 + this(o, ActiveQueue.queue());
14.114 + }
14.115 +
14.116 + public RunnableRef(Object o, ReferenceQueue<Object> q) {
14.117 + super(o, q);
14.118 + }
14.119 +
14.120 + public synchronized void run () {
14.121 + entered = true;
14.122 + if (wait) {
14.123 + // notify we are here
14.124 + notify ();
14.125 + try {
14.126 + wait ();
14.127 + } catch (InterruptedException ex) {
14.128 + }
14.129 + }
14.130 + executed = true;
14.131 +
14.132 + notifyAll ();
14.133 + }
14.134 + }
14.135 +
14.136 +}
14.137 \ No newline at end of file
15.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
15.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupMemoryTest.java Fri Jan 22 10:02:41 2010 -0500
15.3 @@ -0,0 +1,160 @@
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 +
15.45 +package org.openide.util.lookup;
15.46 +
15.47 +import java.util.Arrays;
15.48 +import java.util.Collections;
15.49 +import org.netbeans.junit.NbTestCase;
15.50 +import org.netbeans.junit.NbTestSuite;
15.51 +import org.openide.util.Lookup;
15.52 +import org.openide.util.lookup.implspi.ActiveQueue;
15.53 +
15.54 +/** Testing memory consumption of various AbstractLookup aspects.
15.55 + */
15.56 +public class AbstractLookupMemoryTest extends NbTestCase {
15.57 + public AbstractLookupMemoryTest(java.lang.String testName) {
15.58 + super(testName);
15.59 + }
15.60 +
15.61 + public static void main(java.lang.String[] args) {
15.62 + junit.textui.TestRunner.run(new NbTestSuite(AbstractLookupMemoryTest.class));
15.63 + }
15.64 +
15.65 + public void testEmptySize () {
15.66 + AbstractLookup instanceLookup = new AbstractLookup ();
15.67 + assertSize ("Empty lookup should be small", 16, instanceLookup);
15.68 +
15.69 + InstanceContent ic = new InstanceContent ();
15.70 + instanceLookup = new AbstractLookup (ic);
15.71 + assertSize ("Lookup with InstanceContent should be small as well", 16, instanceLookup);
15.72 + }
15.73 +
15.74 + public void testPairSize () {
15.75 + AbstractLookup.Pair pair = new EmptyPair ();
15.76 + assertSize ("Pair occupies only 16 bytes", 16, pair);
15.77 + }
15.78 +
15.79 + public void testPairWithOnePointerSize () {
15.80 + AbstractLookup.Pair pair = new OneItemPair ();
15.81 + assertSize ("Pair occupies only 16 bytes", 16, pair);
15.82 + }
15.83 +
15.84 + public void testLookupWithPairs () {
15.85 + Lookup.Template<Object> t = new Lookup.Template<Object>(Object.class);
15.86 + class L implements org.openide.util.LookupListener {
15.87 + public int cnt;
15.88 + public void resultChanged (org.openide.util.LookupEvent ev) {
15.89 + cnt++;
15.90 + }
15.91 + }
15.92 + L listener = new L ();
15.93 + L listener2 = new L ();
15.94 +
15.95 + EmptyPair[] pairs = {
15.96 + new EmptyPair(),
15.97 + new EmptyPair(),
15.98 + new EmptyPair(),
15.99 + new EmptyPair(),
15.100 + };
15.101 + Object[] ignore = {
15.102 + pairs[0],
15.103 + pairs[1],
15.104 + pairs[2],
15.105 + pairs[3],
15.106 + t,
15.107 + ActiveQueue.queue(),
15.108 + listener,
15.109 + listener2,
15.110 + new Integer (11) // trashhold is shared
15.111 + };
15.112 +
15.113 + AbstractLookup.Content c = new AbstractLookup.Content ();
15.114 + AbstractLookup l = new AbstractLookup (c, (Integer)ignore[ignore.length - 1]);
15.115 +
15.116 + c.addPair ((EmptyPair)ignore[0]);
15.117 + assertSize ("Should be really small (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
15.118 +
15.119 + c.addPair ((EmptyPair)ignore[1]);
15.120 + assertSize ("Is bigger I guess (not counting the pair sizes)", Collections.singleton (l), 56, ignore);
15.121 +
15.122 + c.setPairs(Arrays.asList(pairs).subList(0, 3));
15.123 + assertSize ("Even bigger (not counting the pair sizes)", Collections.singleton (l), 64, ignore);
15.124 +
15.125 + c.setPairs(Arrays.asList(pairs).subList(0, 4));
15.126 + assertSize ("Now not that much(not counting the pair sizes)", Collections.singleton (l), 64, ignore);
15.127 +
15.128 + Lookup.Result res = l.lookup (t);
15.129 +
15.130 + assertSize ("After creating a result", Collections.singleton (l), 120, ignore);
15.131 +
15.132 + res.addLookupListener (listener);
15.133 +
15.134 + assertSize ("And attaching one listener", Collections.singleton (l), 120, ignore);
15.135 +
15.136 + res.addLookupListener (listener2);
15.137 + assertSize ("Second listener makes the situation much worse", Collections.singleton (l), 200, ignore);
15.138 + res.removeLookupListener(listener2);
15.139 + assertSize ("But removing it returns us back to original size", Collections.singleton (l), 120, ignore);
15.140 +
15.141 +
15.142 + assertEquals ("Current for pairs are in", res.allItems ().size (), 4); // also activates the listener
15.143 + assertSize ("and making the listener to work", Collections.singleton (l), 120, ignore);
15.144 +
15.145 + c.removePair ((EmptyPair)ignore[0]);
15.146 + assertEquals ("A changes has been delivered", 1, listener.cnt);
15.147 + }
15.148 +
15.149 + /** Simple pair with no data */
15.150 + private static class EmptyPair extends AbstractLookup.Pair {
15.151 + protected boolean creatorOf(Object obj) { return false; }
15.152 + public String getDisplayName() { return ""; }
15.153 + public String getId() { return ""; }
15.154 + public Object getInstance() { return null; }
15.155 + public Class getType() { return Object.class; }
15.156 + protected boolean instanceOf(Class c) { return c == getType (); }
15.157 + } // end of EmptyPair
15.158 +
15.159 + /** Pair with one item (like InstanceContent.Pair) */
15.160 + private static class OneItemPair extends EmptyPair {
15.161 + private Object pointer;
15.162 + }
15.163 +}
16.1 --- a/openide.util.lookup/test/unit/src/org/openide/util/lookup/PathInLookupTest.java Fri Jan 22 10:09:12 2010 -0500
16.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/PathInLookupTest.java Fri Jan 22 10:02:41 2010 -0500
16.3 @@ -45,8 +45,8 @@
16.4 import java.util.logging.Level;
16.5 import org.netbeans.junit.MockServices;
16.6 import org.netbeans.junit.NbTestCase;
16.7 -import org.netbeans.modules.openide.util.NamedServicesProvider;
16.8 import org.openide.util.Lookup;
16.9 +import org.openide.util.lookup.implspi.NamedServicesProvider;
16.10
16.11 /**
16.12 * @author Jaroslav Tulach
16.13 @@ -98,8 +98,6 @@
16.14 new AbstractLookup(ic1), new AbstractLookup(ic2)
16.15 };
16.16
16.17 -
16.18 - @Override
16.19 public Lookup create(String path) {
16.20 int indx = -1;
16.21 if (path.equals("MyServices/")) {
17.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
17.2 +++ b/openide.util.lookup/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java Fri Jan 22 10:02:41 2010 -0500
17.3 @@ -0,0 +1,657 @@
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 +
17.45 +package org.openide.util.lookup;
17.46 +
17.47 +import java.io.Serializable;
17.48 +
17.49 +import java.lang.ref.Reference;
17.50 +import java.lang.ref.WeakReference;
17.51 +import java.util.ArrayList;
17.52 +import java.util.Collection;
17.53 +import java.util.Collections;
17.54 +import java.util.concurrent.Executor;
17.55 +import junit.framework.Test;
17.56 +import org.netbeans.junit.NbTestSuite;
17.57 +import org.openide.util.Lookup;
17.58 +import org.openide.util.Lookup.Result;
17.59 +import org.openide.util.LookupEvent;
17.60 +import org.openide.util.LookupListener;
17.61 +import org.openide.util.lookup.implspi.ActiveQueue;
17.62 +
17.63 +/** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
17.64 + */
17.65 +@SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
17.66 +public class ProxyLookupTest extends AbstractLookupBaseHid
17.67 +implements AbstractLookupBaseHid.Impl {
17.68 + public ProxyLookupTest(java.lang.String testName) {
17.69 + super(testName, null);
17.70 + }
17.71 +
17.72 + public static Test suite() {
17.73 + return new NbTestSuite (ProxyLookupTest.class);
17.74 +// return new ProxyLookupTest("testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679");
17.75 + }
17.76 +
17.77 + /** Creates an lookup for given lookup. This class just returns
17.78 + * the object passed in, but subclasses can be different.
17.79 + * @param lookup in lookup
17.80 + * @return a lookup to use
17.81 + */
17.82 + public Lookup createLookup (Lookup lookup) {
17.83 + return new ProxyLookup (new Lookup[] { lookup });
17.84 + }
17.85 +
17.86 + public Lookup createInstancesLookup (InstanceContent ic) {
17.87 + return new AbstractLookup (ic);
17.88 + }
17.89 +
17.90 +
17.91 + public void clearCaches () {
17.92 + }
17.93 +
17.94 +
17.95 + /** Check whether setLookups method does not fire when there is no
17.96 + * change in the lookups.
17.97 + */
17.98 + public void testProxyListener () {
17.99 + ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
17.100 +
17.101 + final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
17.102 + final Object[] IGNORE = {
17.103 + ProxyLookup.ImmutableInternalData.EMPTY,
17.104 + ProxyLookup.ImmutableInternalData.EMPTY_ARR,
17.105 + ActiveQueue.queue(),
17.106 + Collections.emptyMap(),
17.107 + Collections.emptyList(),
17.108 + Collections.emptySet()
17.109 + };
17.110 +
17.111 + assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
17.112 +
17.113 + Lookup.Result<Object> res = lookup.lookup (template);
17.114 +
17.115 + assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
17.116 +
17.117 + LL ll = new LL ();
17.118 + res.addLookupListener (ll);
17.119 + Collection allRes = res.allInstances ();
17.120 +
17.121 + lookup.setLookups (new Lookup[0]);
17.122 +
17.123 + if (ll.getCount () != 0) {
17.124 + fail ("Calling setLookups (emptyarray) fired a change");
17.125 + }
17.126 +
17.127 + InstanceContent t = new InstanceContent();
17.128 + Lookup del = new AbstractLookup (t);
17.129 + t.add("Ahoj");
17.130 + lookup.setLookups (new Lookup[] { del });
17.131 +
17.132 + if (ll.getCount () != 1) {
17.133 + fail ("Changing lookups did not generate an event");
17.134 + }
17.135 +
17.136 + lookup.setLookups (new Lookup[] { del });
17.137 +
17.138 + if (ll.getCount () != 0) {
17.139 + fail ("Calling setLookups (thesamearray) fired a change");
17.140 + }
17.141 + }
17.142 +
17.143 + public void testNoListenersProxyListener () {
17.144 + ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
17.145 + class E implements Executor {
17.146 + Runnable r;
17.147 + public void execute(Runnable command) {
17.148 + assertNull("NO previous", r);
17.149 + r = command;
17.150 + }
17.151 + public void perform() {
17.152 + assertNotNull("We shall have a runnable", r);
17.153 + r.run();
17.154 + r = null;
17.155 + }
17.156 + }
17.157 + E executor = new E();
17.158 +
17.159 +
17.160 + final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
17.161 + final Object[] IGNORE = {
17.162 + ProxyLookup.ImmutableInternalData.EMPTY,
17.163 + ProxyLookup.ImmutableInternalData.EMPTY_ARR,
17.164 + ActiveQueue.queue(),
17.165 + Collections.emptyMap(),
17.166 + Collections.emptyList(),
17.167 + Collections.emptySet()
17.168 + };
17.169 +
17.170 + assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
17.171 +
17.172 + Lookup.Result<Object> res = lookup.lookup (template);
17.173 +
17.174 + assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
17.175 +
17.176 + LL ll = new LL ();
17.177 + res.addLookupListener (ll);
17.178 + Collection allRes = res.allInstances ();
17.179 +
17.180 + lookup.setLookups (executor, new Lookup[0]);
17.181 + if (ll.getCount () != 0) {
17.182 + fail ("Calling setLookups (emptyarray) fired a change");
17.183 + }
17.184 +
17.185 + InstanceContent t = new InstanceContent();
17.186 + Lookup del = new AbstractLookup (t);
17.187 + t.add("Ahoj");
17.188 + lookup.setLookups (executor, new Lookup[] { del });
17.189 + assertEquals("No change yet", 0, ll.getCount());
17.190 + executor.perform();
17.191 + if (ll.getCount () != 1) {
17.192 + fail ("Changing lookups did not generate an event");
17.193 + }
17.194 +
17.195 + lookup.setLookups (executor, new Lookup[] { del });
17.196 + if (ll.getCount () != 0) {
17.197 + fail ("Calling setLookups (thesamearray) fired a change");
17.198 + }
17.199 + }
17.200 +
17.201 + public void testSetLookups () throws Exception {
17.202 + AbstractLookup a1 = new AbstractLookup (new InstanceContent ());
17.203 + AbstractLookup a2 = new AbstractLookup (new InstanceContent ());
17.204 +
17.205 + InstanceContent i3 = new InstanceContent ();
17.206 + i3.add (i3);
17.207 + AbstractLookup a3 = new AbstractLookup (i3);
17.208 +
17.209 + final ProxyLookup p = new ProxyLookup (new Lookup[] { a1, a2 });
17.210 + final Lookup.Result res1 = p.lookup (new Lookup.Template (Object.class));
17.211 + Collection c1 = res1.allInstances();
17.212 +
17.213 + Lookup.Result res2 = p.lookup (new Lookup.Template (String.class));
17.214 + Collection c2 = res2.allInstances ();
17.215 +
17.216 +
17.217 + assertTrue ("We need two results", res1 != res2);
17.218 +
17.219 + final Object blocked = new Object ();
17.220 +
17.221 + class L extends Object implements LookupListener {
17.222 + public void resultChanged (LookupEvent ev) {
17.223 + try {
17.224 + res1.removeLookupListener(this);
17.225 +
17.226 + // waiting for second thread to start #111#
17.227 + blocked.wait ();
17.228 +
17.229 + } catch (Exception ex) {
17.230 + ex.printStackTrace();
17.231 + fail ("An exception occured ");
17.232 + }
17.233 + }
17.234 + }
17.235 +
17.236 + final L listener1 = new L ();
17.237 + res1.addLookupListener (listener1);
17.238 +
17.239 +
17.240 + Runnable newLookupSetter = new Runnable() {
17.241 + public void run () {
17.242 + synchronized (blocked) {
17.243 + try {
17.244 + p.setLookups (new Lookup[0]);
17.245 + } catch (Exception ex) {
17.246 + ex.printStackTrace();
17.247 + fail ("setLookups failed.");
17.248 + } finally {
17.249 + // starts the main thread #111#
17.250 + blocked.notify ();
17.251 + }
17.252 + }
17.253 + }
17.254 + };
17.255 +
17.256 + synchronized (blocked) {
17.257 + new Thread (newLookupSetter).start ();
17.258 +
17.259 + p.setLookups (new Lookup[] { a1, a2, a3 });
17.260 + }
17.261 + }
17.262 +
17.263 + public void testProxyLookupTemplateCaching(){
17.264 + Lookup lookups[] = new Lookup[1];
17.265 + doProxyLookupTemplateCaching(lookups, false);
17.266 + }
17.267 +
17.268 + public void testProxyLookupTemplateCachingOnSizeTwoArray() {
17.269 + Lookup lookups[] = new Lookup[2];
17.270 + lookups[1] = Lookup.EMPTY;
17.271 + doProxyLookupTemplateCaching(lookups, false);
17.272 + }
17.273 + public void testProxyLookupShallNotAllowModificationOfGetLookups(){
17.274 + Lookup lookups[] = new Lookup[1];
17.275 + doProxyLookupTemplateCaching(lookups, true);
17.276 + }
17.277 +
17.278 + public void testProxyLookupShallNotAllowModificationOfGetLookupsOnSizeTwoArray() {
17.279 + Lookup lookups[] = new Lookup[2];
17.280 + lookups[1] = Lookup.EMPTY;
17.281 + doProxyLookupTemplateCaching(lookups, true);
17.282 + }
17.283 +
17.284 + /** Index 0 of lookups will be modified, the rest is up to the
17.285 + * setup code.
17.286 + */
17.287 + private void doProxyLookupTemplateCaching(Lookup[] lookups, boolean reget) {
17.288 + // Create MyProxyLookup with one lookup containing the String object
17.289 + InstanceContent inst = new InstanceContent();
17.290 + inst.add(new String("Hello World")); //NOI18N
17.291 + lookups[0] = new AbstractLookup(inst);
17.292 + ProxyLookup proxy = new ProxyLookup(lookups);
17.293 + if (reget) {
17.294 + lookups = proxy.getLookups();
17.295 + }
17.296 +
17.297 + // Performing template lookup for String object
17.298 + Lookup.Result result = proxy.lookup(new Lookup.Template(String.class, null, null));
17.299 + int stringTemplateResultSize = result.allInstances().size();
17.300 + assertEquals ("Ensure, there is only one instance of String.class in proxyLookup:", //NOI18N
17.301 + 1, stringTemplateResultSize);
17.302 +
17.303 + // Changing lookup in proxy lookup, now it will contain
17.304 + // StringBuffer Object instead of String
17.305 + InstanceContent ic2 = new InstanceContent();
17.306 + ic2.add(new Integer(1234567890));
17.307 + lookups[0] = new AbstractLookup(ic2);
17.308 + proxy.setLookups(lookups);
17.309 +
17.310 + assertEquals ("the old result is updated", 0, result.allInstances().size());
17.311 +
17.312 + // Instance of String.class should not appear in proxyLookup
17.313 + Lookup.Result r2 = proxy.lookup(new Lookup.Template(String.class, null, null));
17.314 + assertEquals ("Instance of String.class should not appear in proxyLookup:", //NOI18N
17.315 + 0, r2.allInstances().size());
17.316 +
17.317 + Lookup.Result r3 = proxy.lookup(new Lookup.Template(Integer.class, null, null));
17.318 + assertEquals ("There is only one instance of Integer.class in proxyLookup:", //NOI18N
17.319 + 1, r3.allInstances().size());
17.320 + }
17.321 +
17.322 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
17.323 + doListeningAndQueryingByTwoListenersSetLookups(0, 1);
17.324 + }
17.325 + public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
17.326 + doListeningAndQueryingByTwoListenersSetLookups(1, 1);
17.327 + }
17.328 + public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
17.329 + doListeningAndQueryingByTwoListenersSetLookups(2, 1);
17.330 + }
17.331 +
17.332 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
17.333 + doListeningAndQueryingByTwoListenersSetLookups(0, 2);
17.334 + }
17.335 + public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
17.336 + doListeningAndQueryingByTwoListenersSetLookups(1, 2);
17.337 + }
17.338 + public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
17.339 + doListeningAndQueryingByTwoListenersSetLookups(2, 2);
17.340 + }
17.341 + public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
17.342 + doListeningAndQueryingByTwoListenersSetLookups(0, 22);
17.343 + }
17.344 + public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
17.345 + doListeningAndQueryingByTwoListenersSetLookups(1, 22);
17.346 + }
17.347 + public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
17.348 + doListeningAndQueryingByTwoListenersSetLookups(2, 22);
17.349 + }
17.350 +
17.351 + private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth) {
17.352 + ProxyLookup orig = new ProxyLookup();
17.353 + ProxyLookup on = orig;
17.354 +
17.355 + while (--depth > 0) {
17.356 + on = new ProxyLookup(new Lookup[] { on });
17.357 + }
17.358 +
17.359 +
17.360 + final ProxyLookup lookup = on;
17.361 +
17.362 + class L implements LookupListener {
17.363 + Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
17.364 + Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
17.365 + Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
17.366 +
17.367 + {
17.368 + integer.addLookupListener(this);
17.369 + number.addLookupListener(this);
17.370 + serial.addLookupListener(this);
17.371 + }
17.372 +
17.373 + int round;
17.374 +
17.375 + public void resultChanged(LookupEvent ev) {
17.376 + Collection c1 = get(type, integer);
17.377 + Collection c2 = get(type, number);
17.378 + Collection c3 = get(type, serial);
17.379 +
17.380 + assertEquals("round " + round + " c1 vs. c2", c1, c2);
17.381 + assertEquals("round " + round + " c1 vs. c3", c1, c3);
17.382 + assertEquals("round " + round + " c2 vs. c3", c2, c3);
17.383 +
17.384 + round++;
17.385 + }
17.386 +
17.387 + private Collection get(int type, Lookup.Result res) {
17.388 + Collection c;
17.389 + switch(type) {
17.390 + case 0: c = res.allInstances(); break;
17.391 + case 1: c = res.allClasses(); break;
17.392 + case 2: c = res.allItems(); break;
17.393 + default: c = null; fail("Type: " + type); break;
17.394 + }
17.395 +
17.396 + assertNotNull(c);
17.397 + return new ArrayList(c);
17.398 + }
17.399 + }
17.400 +
17.401 + L listener = new L();
17.402 + listener.resultChanged(null);
17.403 + ArrayList arr = new ArrayList();
17.404 + for(int i = 0; i < 100; i++) {
17.405 + arr.add(new Integer(i));
17.406 +
17.407 + orig.setLookups(new Lookup[] { Lookups.fixed(arr.toArray()) });
17.408 + }
17.409 +
17.410 + assertEquals("3x100+1 checks", 301, listener.round);
17.411 + }
17.412 +
17.413 + static Object holder;
17.414 +
17.415 + public void testProxyWithLiveResultCanBeCollected() {
17.416 + Lookup layer0 = Lookups.singleton("Hello");
17.417 + Lookup layer1 = new ProxyLookup(new Lookup[] { layer0 });
17.418 + Lookup layer2 = new ProxyLookup(new Lookup[] { layer1 });
17.419 + Lookup.Result result1 = layer1.lookup(new Lookup.Template(String.class));
17.420 +
17.421 + assertEquals("One instance", 1, result1.allInstances().size());
17.422 +
17.423 + // this will create ProxyLookup$R which listens on origResult
17.424 + Lookup.Result result2 = layer2.lookup(new Lookup.Template(String.class));
17.425 +
17.426 + // this line is necessary. W/o actually querying the result,
17.427 + // it will nether compute it nor attach the listener.
17.428 + assertEquals("One instance", 1, result2.allInstances().size());
17.429 +
17.430 + result2.addLookupListener(new LookupListener() {
17.431 + public void resultChanged(LookupEvent ev) {}
17.432 + });
17.433 +
17.434 + Reference ref = new WeakReference(layer2);
17.435 + layer2 = null;
17.436 + result2 = null;
17.437 + try {
17.438 + holder = result1;
17.439 + assertGC ("The proxy lookup not been garbage collected!", ref);
17.440 + } finally {
17.441 + holder = null;
17.442 + }
17.443 + }
17.444 +
17.445 + public void testArrayIndexAsInIssue119292() throws Exception {
17.446 + final ProxyLookup pl = new ProxyLookup();
17.447 + final int[] cnt = { 0 };
17.448 +
17.449 + class L extends Lookup {
17.450 + L[] set;
17.451 + Lookup l;
17.452 +
17.453 + public L(String s) {
17.454 + l = Lookups.singleton(s);
17.455 + }
17.456 +
17.457 + @Override
17.458 + public <T> T lookup(Class<T> clazz) {
17.459 + return l.lookup(clazz);
17.460 + }
17.461 +
17.462 + @Override
17.463 + public <T> Result<T> lookup(Template<T> template) {
17.464 + return l.lookup(template);
17.465 + }
17.466 +
17.467 + @Override
17.468 + @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
17.469 + public boolean equals(Object obj) {
17.470 + if (set != null) {
17.471 + cnt[0]++;
17.472 + pl.setLookups(set);
17.473 + }
17.474 + return super.equals(obj);
17.475 + }
17.476 +
17.477 + @Override
17.478 + public int hashCode() {
17.479 + int hash = 3;
17.480 + return hash;
17.481 + }
17.482 + }
17.483 +
17.484 + Result<String> res = pl.lookupResult(String.class);
17.485 + assertEquals(Collections.EMPTY_LIST, res.allItems());
17.486 +
17.487 + L[] old = { new L("A"), new L("B") };
17.488 + L[] now = { new L("C") };
17.489 +
17.490 + pl.setLookups(old);
17.491 + cnt[0] = 0;
17.492 +
17.493 + old[0].set = new L[0];
17.494 + pl.setLookups(now);
17.495 +
17.496 + assertEquals("No call to equals", 0, cnt[0]);
17.497 +
17.498 + assertEquals("Still assigned to C", Collections.singletonList("C"), res.allInstances());
17.499 + }
17.500 +
17.501 + public void testArrayIndexWithAddRemoveListenerAsInIssue119292() throws Exception {
17.502 + final ProxyLookup pl = new ProxyLookup();
17.503 + final int[] cnt = { 0 };
17.504 +
17.505 + class L extends Lookup {
17.506 + L[] set;
17.507 + Lookup l;
17.508 +
17.509 + public L(String s) {
17.510 + l = Lookups.singleton(s);
17.511 + }
17.512 +
17.513 + @Override
17.514 + public <T> T lookup(Class<T> clazz) {
17.515 + return l.lookup(clazz);
17.516 + }
17.517 +
17.518 + @Override
17.519 + public <T> Result<T> lookup(Template<T> template) {
17.520 + Result<T> r = l.lookup(template);
17.521 + return new R<T>(r);
17.522 + }
17.523 +
17.524 + final class R<T> extends Result<T> {
17.525 + private Result<T> delegate;
17.526 +
17.527 + public R(Result<T> delegate) {
17.528 + this.delegate = delegate;
17.529 + }
17.530 +
17.531 + @Override
17.532 + public void addLookupListener(LookupListener l) {
17.533 + cnt[0]++;
17.534 + if (set != null) {
17.535 + pl.setLookups(set);
17.536 + }
17.537 + delegate.addLookupListener(l);
17.538 + }
17.539 +
17.540 + @Override
17.541 + public void removeLookupListener(LookupListener l) {
17.542 + cnt[0]++;
17.543 + if (set != null) {
17.544 + pl.setLookups(set);
17.545 + }
17.546 + delegate.removeLookupListener(l);
17.547 + }
17.548 +
17.549 + @Override
17.550 + public Collection<? extends T> allInstances() {
17.551 + return delegate.allInstances();
17.552 + }
17.553 + }
17.554 + }
17.555 +
17.556 + Result<String> res = pl.lookupResult(String.class);
17.557 + assertEquals(Collections.EMPTY_LIST, res.allItems());
17.558 +
17.559 + L[] old = { new L("A"), new L("B") };
17.560 + L[] now = { new L("C") };
17.561 +
17.562 + pl.setLookups(old);
17.563 + cnt[0] = 0;
17.564 +
17.565 + old[0].set = new L[0];
17.566 + pl.setLookups(now);
17.567 +
17.568 + if (cnt[0] == 0) {
17.569 + fail("There should be calls to listeners");
17.570 + }
17.571 +
17.572 + assertEquals("C is overriden from removeLookupListener", Collections.emptyList(), res.allInstances());
17.573 + }
17.574 +
17.575 +
17.576 + public void testArrayIndexWithSetLookupAsInIssue123679() throws Exception {
17.577 + final ProxyLookup pl = new ProxyLookup();
17.578 + final int[] cnt = { 0 };
17.579 +
17.580 + class L extends Lookup {
17.581 + L[] set;
17.582 + Lookup l;
17.583 + Collection<? extends Serializable> res;
17.584 +
17.585 + public L(String s) {
17.586 + l = Lookups.singleton(s);
17.587 + }
17.588 +
17.589 + @Override
17.590 + public <T> T lookup(Class<T> clazz) {
17.591 + return l.lookup(clazz);
17.592 + }
17.593 +
17.594 + @Override
17.595 + public <T> Result<T> lookup(Template<T> template) {
17.596 + cnt[0]++;
17.597 + if (set != null) {
17.598 + pl.setLookups(set);
17.599 + res = pl.lookupAll(Serializable.class);
17.600 + }
17.601 + Result<T> r = l.lookup(template);
17.602 + return r;
17.603 + }
17.604 + }
17.605 +
17.606 + L[] now = { new L("A"), new L("B") };
17.607 + L[] old = { new L("C") };
17.608 + pl.setLookups(old);
17.609 + old[0].set = now;
17.610 +
17.611 + Result<String> res = pl.lookupResult(String.class);
17.612 + assertEquals("New items visible", 2, res.allItems().size());
17.613 +
17.614 +
17.615 + pl.setLookups(new L("X"), new L("Y"), new L("Z"));
17.616 + }
17.617 +
17.618 + public void testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679() throws Exception {
17.619 + final ProxyLookup pl = new ProxyLookup();
17.620 + final int[] cnt = { 0 };
17.621 +
17.622 + class L extends Lookup {
17.623 + L[] set;
17.624 + Lookup l;
17.625 + Collection<? extends Serializable> res;
17.626 +
17.627 + public L(String s) {
17.628 + l = Lookups.singleton(s);
17.629 + }
17.630 +
17.631 + @Override
17.632 + public <T> T lookup(Class<T> clazz) {
17.633 + return l.lookup(clazz);
17.634 + }
17.635 +
17.636 + @Override
17.637 + public <T> Result<T> lookup(Template<T> template) {
17.638 + cnt[0]++;
17.639 + if (set != null) {
17.640 + pl.setLookups(set);
17.641 + res = pl.lookupAll(Serializable.class);
17.642 + }
17.643 + Result<T> r = l.lookup(template);
17.644 + return r;
17.645 + }
17.646 + }
17.647 +
17.648 + L dupl = new L("A");
17.649 + L[] now = { dupl };
17.650 + L[] old = { new L("C") };
17.651 + pl.setLookups(old);
17.652 + old[0].set = now;
17.653 +
17.654 + Result<String> res = pl.lookupResult(String.class);
17.655 + assertEquals("New items visible", 1, res.allItems().size());
17.656 +
17.657 +
17.658 + pl.setLookups(old);
17.659 + }
17.660 +}
18.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
18.2 +++ b/openide.util/apichanges.xml Fri Jan 22 10:02:41 2010 -0500
18.3 @@ -0,0 +1,1492 @@
18.4 +<?xml version="1.0" encoding="UTF-8"?>
18.5 +<!--
18.6 +DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
18.7 +
18.8 +Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
18.9 +
18.10 +
18.11 +The contents of this file are subject to the terms of either the GNU
18.12 +General Public License Version 2 only ("GPL") or the Common
18.13 +Development and Distribution License("CDDL") (collectively, the
18.14 +"License"). You may not use this file except in compliance with the
18.15 +License. You can obtain a copy of the License at
18.16 +http://www.netbeans.org/cddl-gplv2.html
18.17 +or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
18.18 +specific language governing permissions and limitations under the
18.19 +License. When distributing the software, include this License Header
18.20 +Notice in each file and include the License file at
18.21 +nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
18.22 +particular file as subject to the "Classpath" exception as provided
18.23 +by Sun in the GPL Version 2 section of the License file that
18.24 +accompanied this code. If applicable, add the following below the
18.25 +License Header, with the fields enclosed by brackets [] replaced by
18.26 +your own identifying information:
18.27 +"Portions Copyrighted [year] [name of copyright owner]"
18.28 +
18.29 +Contributor(s):
18.30 +
18.31 +The Original Software is NetBeans. The Initial Developer of the Original
18.32 +Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
18.33 +Microsystems, Inc. All Rights Reserved.
18.34 +
18.35 +If you wish your version of this file to be governed by only the CDDL
18.36 +or only the GPL Version 2, indicate your decision by adding
18.37 +"[Contributor] elects to include this software in this distribution
18.38 +under the [CDDL or GPL Version 2] license." If you do not indicate a
18.39 +single choice of license, a recipient has the option to distribute
18.40 +your version of this file under either the CDDL, the GPL Version 2 or
18.41 +to extend the choice of license to its licensees as provided above.
18.42 +However, if you add GPL Version 2 code and therefore, elected the GPL
18.43 +Version 2 license, then the option applies only if the new code is
18.44 +made subject to such option by the copyright holder.
18.45 +-->
18.46 +<!DOCTYPE apichanges PUBLIC "-//NetBeans//DTD API changes list 1.0//EN" "../nbbuild/javadoctools/apichanges.dtd">
18.47 +<apichanges>
18.48 +<apidefs>
18.49 + <apidef name="util">Utilities API</apidef>
18.50 + <apidef name="xml">XML API</apidef>
18.51 + <apidef name="actions">Actions API</apidef>
18.52 +</apidefs>
18.53 +<changes>
18.54 + <change id="ActionInvoker-ActionPresenterProvider">
18.55 + <api name="actions"/>
18.56 + <summary>Action SPI interfaces added</summary>
18.57 + <version major="8" minor="1"/>
18.58 + <date day="21" month="1" year="2010"/>
18.59 + <author login="jglick"/>
18.60 + <compatibility addition="yes"/>
18.61 + <description>
18.62 + <p>
18.63 + Added some internal SPI interfaces.
18.64 + </p>
18.65 + </description>
18.66 + <class package="org.openide.util.actions" name="ActionInvoker"/>
18.67 + <class package="org.openide.util.actions" name="ActionPresenterProvider"/>
18.68 + <issue number="179289"/>
18.69 + </change>
18.70 + <change id="NbPreferences.Provider">
18.71 + <api name="util"/>
18.72 + <summary><code>NbPreferences.Provider</code> added</summary>
18.73 + <version major="8" minor="1"/>
18.74 + <date day="21" month="1" year="2010"/>
18.75 + <author login="jglick"/>
18.76 + <compatibility addition="yes"/>
18.77 + <description>
18.78 + <p>
18.79 + Added an internal SPI interface.
18.80 + </p>
18.81 + </description>
18.82 + <class package="org.openide.util" name="NbPreferences"/>
18.83 + <issue number="179289"/>
18.84 + </change>
18.85 + <change id="lookup.is.free">
18.86 + <api name="util"/>
18.87 + <summary>Lookup API extracted</summary>
18.88 + <version major="8" minor="0"/>
18.89 + <date day="20" month="12" year="2009"/>
18.90 + <author login="jtulach"/>
18.91 + <compatibility modification="yes">
18.92 + <p>
18.93 + Runtime compatibility remains, compile time compatibility is
18.94 + mostly preserved too. It is however recommended to upgrade
18.95 + dependencies of your modules. Try running
18.96 + <code>ant fix-dependencies</code> in your Ant module.
18.97 + </p>
18.98 + </compatibility>
18.99 + <description>
18.100 + <p>
18.101 + <a href="@org-openide-util-lookup@/org/openide/util/Lookup.html">Lookup</a>
18.102 + and its associated interfaces are now available as a
18.103 + <a href="@org-openide-util-lookup@/overview-summary.html">separate module</a>.
18.104 + </p>
18.105 + </description>
18.106 + <issue number="170056"/>
18.107 + </change>
18.108 + <change id="URLStreamHandlerRegistration">
18.109 + <api name="util"/>
18.110 + <summary>Added <code>@URLStreamHandlerRegistration</code></summary>
18.111 + <version major="7" minor="31"/>
18.112 + <date day="30" month="10" year="2009"/>
18.113 + <author login="jglick"/>
18.114 + <compatibility addition="yes">
18.115 + <p>
18.116 + Modules registering <code>URLStreamHandlerFactory</code>s into
18.117 + global lookup will still work but are advised to switch to this
18.118 + annotation, which is both easier to use and more efficient.
18.119 + </p>
18.120 + </compatibility>
18.121 + <description>
18.122 + <p>
18.123 + Introduced an annotation to register URL protocols.
18.124 + </p>
18.125 + </description>
18.126 + <class package="org.openide.util" name="URLStreamHandlerRegistration"/>
18.127 + <issue number="20838"/>
18.128 + </change>
18.129 + <change id="ImageUtilities.createDisabled">
18.130 + <api name="util"/>
18.131 + <summary><code>ImageUtilities.createDisabledIcon</code> and <code>ImageUtilities.createDisabledImage</code> added.</summary>
18.132 + <version major="7" minor="28"/>
18.133 + <date day="10" month="9" year="2009"/>
18.134 + <author login="t_h"/>
18.135 + <compatibility addition="yes"/>
18.136 + <description>
18.137 + <p>
18.138 + <code>ImageUtilities.createDisabledIcon</code> now can be used
18.139 + to create low color saturation icon for disabled buttons. Also
18.140 + <code>ImageUtilities.createDisabledImage</code> was added.
18.141 + </p>
18.142 + </description>
18.143 + <class package="org.openide.util" name="ImageUtilities"/>
18.144 + <issue number="171400"/>
18.145 + </change>
18.146 + <change id="NbBundle.varargs">
18.147 + <api name="util"/>
18.148 + <summary><code>NbBundle.getMessage</code> can take arbitrarily many format arguments</summary>
18.149 + <version major="7" minor="27"/>
18.150 + <date day="5" month="8" year="2009"/>
18.151 + <author login="jglick"/>
18.152 + <compatibility addition="yes"/>
18.153 + <description>
18.154 + <p>
18.155 + <code>NbBundle.getMessage</code> now has a varargs overload that
18.156 + permits you to specify four or more format arguments without
18.157 + explicitly constructing an array.
18.158 + </p>
18.159 + </description>
18.160 + <class package="org.openide.util" name="NbBundle"/>
18.161 + </change>
18.162 + <change id="EditableProperties">
18.163 + <api name="util"/>
18.164 + <summary>Copied API from <code>project.ant</code> for <code>EditableProperties</code>.</summary>
18.165 + <version major="7" minor="26"/>
18.166 + <date day="29" month="7" year="2009"/>
18.167 + <author login="jglick"/>
18.168 + <compatibility addition="yes"/>
18.169 + <description>
18.170 + <p>
18.171 + <code>EditableProperties</code> now available in Utilities API
18.172 + so it can be used more broadly.
18.173 + </p>
18.174 + </description>
18.175 + <class package="org.openide.util" name="EditableProperties"/>
18.176 + <issue number="66577"/>
18.177 + </change>
18.178 + <change id="LifecycleManager.markForRestart">
18.179 + <api name="util"/>
18.180 + <summary>Added way to request that the platform restart.</summary>
18.181 + <version major="7" minor="25"/>
18.182 + <date day="14" month="7" year="2009"/>
18.183 + <author login="jglick"/>
18.184 + <compatibility addition="yes"/>
18.185 + <description>
18.186 + <p>
18.187 + Can now use <code>LifecycleManager.markForRestart</code> to cause
18.188 + the application to restart after exiting. Formerly needed to
18.189 + create special files in the userdir or use similar tricks.
18.190 + </p>
18.191 + </description>
18.192 + <class package="org.openide" name="LifecycleManager"/>
18.193 + <issue number="168257"/>
18.194 + </change>
18.195 + <change id="enableStackTraces">
18.196 + <api name="util"/>
18.197 + <summary>Added constructor <code>RequestProcessor(String name, int throughput, boolean interruptThread, boolean enableStackTraces)</code></summary>
18.198 + <version major="7" minor="24"/>
18.199 + <date day="8" month="6" year="2009"/>
18.200 + <author login="rmichalsky"/>
18.201 + <compatibility addition="yes"/>
18.202 + <description>
18.203 + <p>
18.204 + Newly added constructor allows to disable (slow) filling stack traces before posting each task.
18.205 + </p>
18.206 + </description>
18.207 + <class package="org.openide.util" name="RequestProcessor"/>
18.208 + <issue number="165862"/>
18.209 + </change>
18.210 + <change id="ImageUtilities.loadImageIcon">
18.211 + <api name="util"/>
18.212 + <summary>Added <code>loadImageIcon(String resource, boolean localized)</code></summary>
18.213 + <version major="7" minor="22"/>
18.214 + <date day="26" month="1" year="2009"/>
18.215 + <author login="t_h"/>
18.216 + <compatibility addition="yes"/>
18.217 + <description>
18.218 + <p>
18.219 + Convenient method for loading icons.
18.220 + </p>
18.221 + </description>
18.222 + <class package="org.openide.util" name="ImageUtilities"/>
18.223 + <issue number="157254"/>
18.224 + </change>
18.225 + <change id="Utilities.keyToString">
18.226 + <api name="util"/>
18.227 + <summary>Added <code>keyToString(KeyStroke stroke, boolean portable)</code></summary>
18.228 + <version major="7" minor="21"/>
18.229 + <date day="8" month="1" year="2009"/>
18.230 + <author login="msauer"/>
18.231 + <compatibility addition="yes"/>
18.232 + <description>
18.233 + <p>
18.234 + <code>keyToString(KeyStroke stroke, boolean portable)</code>
18.235 + provides cross-platform compitable keystroke textual representation
18.236 + instead of hardcoding Ctrl, Meta or Alt key.
18.237 + </p>
18.238 + </description>
18.239 + <class package="org.openide.util" name="Utilities"/>
18.240 + <issue number="110492"/>
18.241 + </change>
18.242 + <change id="Utilities.OS_OPENBSD">
18.243 + <api name="util"/>
18.244 + <summary>Added <code>OS_OPENBSD</code> and <code>OS_UNIX_OTHER</code> fields</summary>
18.245 + <version major="7" minor="18"/>
18.246 + <date day="16" month="9" year="2008"/>
18.247 + <author login="jskrivanek"/>
18.248 + <compatibility addition="yes"/>
18.249 + <description>
18.250 + <p>
18.251 + Added a new <code>Utilities.OS_OPENBSD</code> and <code>OS_UNIX_OTHER</code>
18.252 + fields. Deprecated <code>OS_WINDOWS_MASK</code> and <code>OS_UNIX_MASK</code>.
18.253 + </p>
18.254 + </description>
18.255 + <class package="org.openide.util" name="Utilities"/>
18.256 + <issue number="145462"/>
18.257 + </change>
18.258 + <change id="Utilities.OS_WINVISTA">
18.259 + <api name="util"/>
18.260 + <summary>Added <code>OS_WINVISTA</code> field</summary>
18.261 + <version major="7" minor="17"/>
18.262 + <date day="8" month="8" year="2008"/>
18.263 + <author login="jskrivanek"/>
18.264 + <compatibility addition="yes"/>
18.265 + <description>
18.266 + <p>
18.267 + Added a new <code>Utilities.OS_WINVISTA</code> field to be able
18.268 + to recognize Windows Vista operating system.
18.269 + </p>
18.270 + </description>
18.271 + <class package="org.openide.util" name="Utilities"/>
18.272 + <issue number="142629"/>
18.273 + </change>
18.274 + <change id="XMLUtil.validate">
18.275 + <api name="xml"/>
18.276 + <summary>Added <code>XMLUtil.validate</code></summary>
18.277 + <version major="7" minor="17"/>
18.278 + <date day="11" month="7" year="2008"/>
18.279 + <author login="jglick"/>
18.280 + <compatibility addition="yes"/>
18.281 + <description>
18.282 + <p>
18.283 + Added a new method to validate XML documents against schemas.
18.284 + </p>
18.285 + </description>
18.286 + <class package="org.openide.xml" name="XMLUtil"/>
18.287 + <issue number="42686"/>
18.288 + </change>
18.289 + <change id="RequestProcessor.Executor">
18.290 + <api name="util"/>
18.291 + <summary>RequestProcessor implements Executor interface</summary>
18.292 + <version major="7" minor="16"/>
18.293 + <date day="27" month="6" year="2008"/>
18.294 + <author login="jtulach"/>
18.295 + <compatibility addition="yes"/>
18.296 + <description>
18.297 + <p>
18.298 + In order to align <code>RequestProcessor</code> closer to standard
18.299 + Java 5 concurrency utilities, the class now implements
18.300 + <a href="@JDK@/java/util/concurrent/Executor.html">Executor</a>
18.301 + interfaces and its <code>execute(Runnable)</code> method.
18.302 + </p>
18.303 + </description>
18.304 + <class package="org.openide.util" name="RequestProcessor"/>
18.305 + <issue number="134297"/>
18.306 + </change>
18.307 + <change id="Utilities.toolTips">
18.308 + <api name="util"/>
18.309 + <summary>ImageUtilities class (with additional methods) was created as
18.310 + replacement for "image methods" in Utilities. </summary>
18.311 + <version major="7" minor="15"/>
18.312 + <date day="6" month="6" year="2008"/>
18.313 + <author login="t_h"/>
18.314 + <compatibility addition="yes"/>
18.315 + <description>
18.316 + <p>
18.317 + Image methods were separated to <a href="@TOP@/org/openide/util/ImageUtilities.html">ImageUtilities</a>
18.318 + (renamed IconManager) as replacement for methods in Utilities.
18.319 + There are some additional methods for image tool tips manipulation.
18.320 + </p>
18.321 + <p>
18.322 + New methods for tool tips manipulation:
18.323 + <code>Image assignToolTipToImage(Image image, String text)</code>;
18.324 + <code>String getImageToolTip(Image image)</code>;
18.325 + <code>Image addToolTipToImage(Image image, String text)</code>;
18.326 + </p>
18.327 + <p>
18.328 + New method for conversion from Image to Icon:
18.329 + <code>Icon image2Icon(Image image)</code>;
18.330 + </p>
18.331 + <p>
18.332 + "Moved" methods from <a href="@TOP@/org/openide/util/Utilities.html">Utilities</a>:
18.333 + <code>Image icon2Image(Icon icon)</code>;
18.334 + <code>Image loadImage(String resourceID)</code>;
18.335 + <code>Image loadImage(String resource, boolean localized)</code>;
18.336 + <code>Image mergeImages(Image image1, Image image2, int x, int y)</code>;
18.337 + </p>
18.338 + </description>
18.339 + <class package="org.openide.util" name="Utilities"/>
18.340 + <class package="org.openide.util" name="ImageUtilities"/>
18.341 + <issue number="123469"/>
18.342 + </change>
18.343 + <change id="Mutex.Wrapper">
18.344 + <api name="util"/>
18.345 + <summary>Mutex made pluggable</summary>
18.346 + <version major="7" minor="12"/>
18.347 + <date day="3" month="1" year="2008"/>
18.348 + <author login="jtulach"/>
18.349 + <compatibility addition="yes"/>
18.350 + <description>
18.351 + <p>
18.352 + Added new constructor
18.353 + <a href="@TOP@/org/openide/util/Mutex.html">Mutex(Privileged, Executor)</a>
18.354 + that allows creators of the mutex to intercept and wrap all actions running
18.355 + inside the mutex with custom code.
18.356 + </p>
18.357 + </description>
18.358 + <class package="org.openide.util" name="Mutex"/>
18.359 + <issue number="123832"/>
18.360 + </change>
18.361 + <change id="Utilities.isLargeFrameIcons">
18.362 + <api name="util"/>
18.363 + <summary>Obsolete method <code>Utilities.isLargeFrameIcons</code> deprecated.</summary>
18.364 + <version major="7" minor="10"/>
18.365 + <date day="23" month="10" year="2007"/>
18.366 + <author login="mslama"/>
18.367 + <compatibility addition="no" deprecation="yes"/>
18.368 + <description>
18.369 + <p>
18.370 + Javadoc says: Test whether the operating system supports icons on frames (windows).
18.371 + But window system used this method to decide if small 16x16 or bigger 32x32 icon
18.372 + should be used for frame (main window). So usage and Javadoc is inconsistent.
18.373 + All OS support small icon in frame. From JDK 6 it is possible to set multiple size
18.374 + icons for frame so OS WM selects appropriate size.
18.375 + I removed useless usage of this method from window system code and this method is
18.376 + not used elsewhere.
18.377 + </p>
18.378 + </description>
18.379 + <class package="org.openide.util" name="Utilities"/>
18.380 + <issue number="119069"/>
18.381 + </change>
18.382 +
18.383 + <change id="ChangeSupport">
18.384 + <api name="util"/>
18.385 + <summary>Added <code>ChangeSupport</code></summary>
18.386 + <version major="7" minor="8"/>
18.387 + <date day="26" month="3" year="2007"/>
18.388 + <author login="abadea"/>
18.389 + <compatibility addition="yes"/>
18.390 + <description>
18.391 + <p>
18.392 + Added a <code>ChangeSupport</code> class to simplify
18.393 + the management of <code>ChangeListener</code>s and the
18.394 + firing of <code>ChangeEvent</code>s.
18.395 + </p>
18.396 + </description>
18.397 + <class package="org.openide.util" name="ChangeSupport"/>
18.398 + <issue number="95885"/>
18.399 + </change>
18.400 +
18.401 + <change id="Utilities.isMac">
18.402 + <api name="util"/>
18.403 + <summary>Added <code>Utilities.isMac()</code> method</summary>
18.404 + <version major="7" minor="7"/>
18.405 + <date day="11" month="1" year="2007"/>
18.406 + <author login="rkubacki"/>
18.407 + <compatibility addition="yes"/>
18.408 + <description>
18.409 + <p>
18.410 + Added a <code>Utilities.isMac()</code> method for checking
18.411 + if current platform is Mac.
18.412 + </p>
18.413 + </description>
18.414 + <class package="org.openide.util" name="Utilities"/>
18.415 + <issue number="61044"/>
18.416 + </change>
18.417 +
18.418 + <change id="Parameters">
18.419 + <api name="util"/>
18.420 + <summary>Added <code>Parameters</code></summary>
18.421 + <version major="7" minor="6"/>
18.422 + <date day="8" month="12" year="2006"/>
18.423 + <author login="abadea"/>
18.424 + <compatibility addition="yes"/>
18.425 + <description>
18.426 + <p>
18.427 + Added a <code>Parameters</code> class for checking the
18.428 + values of method parameters.
18.429 + </p>
18.430 + </description>
18.431 + <class package="org.openide.util" name="Parameters"/>
18.432 + <issue number="89768"/>
18.433 + </change>
18.434 +
18.435 + <change id="NbCollections.iterable">
18.436 + <api name="util"/>
18.437 + <summary>Added <code>NbCollections.iterable(...)</code> methods</summary>
18.438 + <version major="7" minor="5"/>
18.439 + <date day="13" month="11" year="2006"/>
18.440 + <author login="jglick"/>
18.441 + <compatibility addition="yes"/>
18.442 + <description>
18.443 + <p>
18.444 + Added two new methods to make enhanced for-loops easier to use
18.445 + with legacy APIs returning <code>Iterator</code> or <code>Enumeration</code>.
18.446 + </p>
18.447 + </description>
18.448 + <class package="org.openide.util" name="NbCollections"/>
18.449 + <issue number="88606"/>
18.450 + </change>
18.451 +
18.452 + <change id="nbpreferences">
18.453 + <api name="util"/>
18.454 + <summary>Added <code>NbPreferences.forModule(Class cls)</code> and
18.455 + <code>NbPreferences.root()</code> methods as static factory methods
18.456 + for getting preference node from NetBeans preference tree.</summary>
18.457 + <version major="7" minor="4"/>
18.458 + <date day="10" month="11" year="2006"/>
18.459 + <author login="rmatous"/>
18.460 + <compatibility addition="yes" deprecation="no"/>
18.461 + <description>
18.462 + <p>
18.463 + NetBeans preference tree is provided by NetBeans implementation of preferences
18.464 + which uses userdir as a storage. Both newly added methods return
18.465 + preferences node from NetBeans preference tree.
18.466 + Method <code>NbPreferences.root()</code> returns root preference
18.467 + node.
18.468 + Method <code>NbPreferences.forModule(Class cls)</code> returns
18.469 + preference node whose
18.470 + path depends whether class provided as a parameter
18.471 + was loaded as a part of any module or not. If so, then absolute path corresponds to slashified
18.472 + code name base of module. If not, then absolute path corresponds to class's package.
18.473 + See document
18.474 + <a href="@TOP@/org/openide/util/doc-files/preferences.html">Preferences in NetBeans</a>
18.475 + to learn more about preferences in NetBeans.
18.476 + </p>
18.477 + </description>
18.478 + <class package="org.openide.util" name="NbPreferences"/>
18.479 + <issue number="73474"/>
18.480 + </change>
18.481 +
18.482 + <change id="icon2image">
18.483 + <api name="util"/>
18.484 + <summary>Added <code>Utilities.icon2Image</code> method to perform conversion from <code>Icon</code> to Image</summary>
18.485 + <version major="7" minor="3"/>
18.486 + <date day="4" month="7" year="2006"/>
18.487 + <author login="rkubacki"/>
18.488 + <compatibility addition="yes" deprecation="no"/>
18.489 + <description>
18.490 + <p>
18.491 + Conversion from <code>Icon</code> to <code>Image</code> is done
18.492 + at various places and newly introduced method avoids the need to
18.493 + duplicate the same code.
18.494 + </p>
18.495 + </description>
18.496 + <class package="org.openide.util" name="Utilities"/>
18.497 + <issue number="52562"/>
18.498 + </change>
18.499 +
18.500 + <change id="Exceptions">
18.501 + <api name="util"/>
18.502 + <summary>Added <code>Exceptions</code> class as a replacement for <code>ErrorManager</code></summary>
18.503 + <version major="7" minor="2"/>
18.504 + <date day="20" month="6" year="2006"/>
18.505 + <author login="jtulach"/>
18.506 + <compatibility addition="yes" deprecation="yes"/>
18.507 + <description>
18.508 + <p>
18.509 + <code>ErrorManager</code> is now deprecated and its replacement
18.510 + is either <a href="@JDK@/java/util/logging/Logger.html">Logger</a>
18.511 + or <code>Exceptions</code>.
18.512 + </p>
18.513 + </description>
18.514 + <class package="org.openide.util" name="Exceptions"/>
18.515 + <issue number="35067"/>
18.516 + </change>
18.517 +
18.518 + <change id="NbCollections">
18.519 + <api name="util"/>
18.520 + <summary>Added <code>NbCollections</code> and <code>Union2</code></summary>
18.521 + <version major="7" minor="1"/>
18.522 + <date day="5" month="6" year="2006"/>
18.523 + <author login="jglick"/>
18.524 + <compatibility addition="yes"/>
18.525 + <description>
18.526 + <p>
18.527 + Added two new classes useful for transitioning to JDK 5 generics.
18.528 + </p>
18.529 + </description>
18.530 + <class package="org.openide.util" name="NbCollections"/>
18.531 + <class package="org.openide.util" name="Union2"/>
18.532 + <issue number="73637"/>
18.533 + </change>
18.534 +
18.535 + <change id="use-logging" >
18.536 + <api name="util"/>
18.537 + <summary>Do not use ErrorManager for logging</summary>
18.538 + <version major="7" minor="0"/>
18.539 + <date day="15" month="4" year="2006"/>
18.540 + <author login="jtulach"/>
18.541 + <compatibility addition="yes" modification="yes" binary="compatible" source="compatible" semantic="incompatible" deprecation="no" deletion="no"/>
18.542 + <description>
18.543 + <a href="@TOP@/org/openide/ErrorManager.html">ErrorManager</a>
18.544 + is no longer the recommended way to do logging in NetBeans based
18.545 + application. Instead NetBeans now fully support logging two JDK's
18.546 + standard <a href="@JDK@/java/util/logging/Logger.html">Logger</a>.
18.547 + See the
18.548 + <a href="@TOP@/org/openide/util/doc-files/logging.html">NetBeans logging guide</a>
18.549 + to learn the best practises for logging in NetBeans.
18.550 + <br/>
18.551 + <a href="@TOP@/org/openide/ErrorManager.html">ErrorManager</a>
18.552 + is still kept around for annotating exceptions with localized
18.553 + messages and advanced manipulation and its behaviour is fully
18.554 + backward compatible. However modules are adviced to migrate to
18.555 + <a href="@JDK@/java/util/logging/Logger.html">logging</a> whereever
18.556 + possible.
18.557 + <br/>
18.558 + To migrate your modules you can install Jackpot modules from
18.559 + autoupdate (if they are not yet part of your IDE) and apply
18.560 + precreate <a href="http://www.netbeans.org/source/browse/openide/util/Attic/ErrorManagerJackpot.rules">
18.561 + javapot error manager rule</a>.
18.562 + <br/>
18.563 + There is one possible incompatibility from end user point of view.
18.564 + The way to <em>enable logging</em> for certain components when
18.565 + running inside the whole NetBeans container has changed:
18.566 + If there is
18.567 + <a href="@JDK@/java/util/logging/Logger.html">Logger</a> or
18.568 + <a href="@TOP@/org/openide/ErrorManager.html">ErrorManager</a>
18.569 + named <q>org.mymodule.MyComponent</q> then the correct way
18.570 + to turn the logging is now to invoke NetBeans with
18.571 + <code>-J-Dorg.mymodule.MyComponent<b>.level</b>=100</code>
18.572 + (where the possible constants are taken form
18.573 + a JDK's definition of <a href="@JDK@/java/util/logging/Level.html">level</a>).
18.574 + There is however a certain benefit in this change, the value
18.575 + of the property (like <q>org.mymodule.MyComponent.level</q>)
18.576 + can be changed during runtime and thus the logging can be
18.577 + enabled or disabled dynamically (after changing the value, it is
18.578 + necessary to call
18.579 + <a href="@JDK@/java/util/logging/LogManager.html">LogManager.readConfiguration()</a>).
18.580 + </description>
18.581 + <class package="org.openide" name="ErrorManager"/>
18.582 + <issue number="56311"/>
18.583 + </change>
18.584 + <change id="rp-create-true" >
18.585 + <api name="util"/>
18.586 + <summary>Ability to create finished RequestProcessor task</summary>
18.587 + <version major="6" minor="8"/>
18.588 + <date day="22" month="11" year="2005"/>
18.589 + <author login="jtulach"/>
18.590 + <compatibility addition="yes" modification="no" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no"/>
18.591 + <description>
18.592 + <a href="@TOP@/org/openide/util/RequestProcessor.html">RequestProcessor.create(Runnable, boolean)</a>
18.593 + has been added to allow creation of
18.594 + <a href="@TOP@/org/openide/util/RequestProcessor.Task.html">Task</a>
18.595 + that has not executed its runnable yet, but looks like it is finished.
18.596 + </description>
18.597 + <class package="org.openide.util" name="RequestProcessor"/>
18.598 + <issue number="68031"/>
18.599 + </change>
18.600 +
18.601 + <change>
18.602 + <api name="util"/>
18.603 + <summary>DynamicMenuContent interface added</summary>
18.604 + <version major="6" minor="4"/>
18.605 + <date day="12" month="6" year="2005"/>
18.606 + <author login="mkleint"/>
18.607 + <compatibility addition="no" modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no"/>
18.608 + <description>
18.609 + In order to support MacOSX top menus and to fix problems with deprecated JInlineMenu, this new
18.610 + interface was added that allows to handle dynamic content in
18.611 +<a href="@TOP@/org/openide/util/actions/Presenter.Menu.html">Presenter.Menu</a>
18.612 + and <a href="@TOP@/org/openide/util/actions/Presenter.Popup.html">Presenter.Popup</a>.
18.613 + If the instance returned by Presenter.Menu/Popup is an instance of
18.614 +<a href="@org-openide-awt@/org/openide/awt/DynamicMenuContent.html">DynamicMenuContent</a>, it's methods are
18.615 + consulted when creating/updating the menu.
18.616 + </description>
18.617 + <class package="org.openide.util.actions" name="Presenter"/>
18.618 + <issue number="35827"/>
18.619 + </change>
18.620 +
18.621 +
18.622 +
18.623 + <change>
18.624 + <api name="util"/>
18.625 + <summary>Support for interruption of RequestProcessor tasks</summary>
18.626 + <version major="6" minor="3"/>
18.627 + <date day="10" month="6" year="2005"/>
18.628 + <author login="jtulach"/>
18.629 + <compatibility addition="yes" modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no"/>
18.630 + <description>
18.631 + When one calls <a href="@TOP@/org/openide/util/RequestProcessor.Task.html">RequestProcessor.Task</a>.cancel(),
18.632 + the running thread gets interrupted if the
18.633 + <a href="@TOP@/org/openide/util/RequestProcessor.html#RequestProcessor(java.lang.String,%20int,%20boolean)">
18.634 + RequestProcessor(string, int, boolean)
18.635 + </a>
18.636 + constructor is used.
18.637 + There always was a way how to cancel not yet running Task,
18.638 + but if the task was already running, one was out of luck. Since now
18.639 + the thread running the task is interrupted and the Runnable can check
18.640 + for that and terminate its execution sooner. In the runnable one shall
18.641 + check for thread interruption and
18.642 + if true, return immediatelly as in this example:
18.643 + <pre>
18.644 +public void run () {
18.645 + while (veryLongTimeLook) {
18.646 + doAPieceOfIt ();
18.647 +
18.648 + if (Thread.interrupted ()) return;
18.649 + }
18.650 +}
18.651 +</pre>
18.652 + </description>
18.653 + <class package="org.openide.util" name="RequestProcessor"/>
18.654 + <issue number="33467"/>
18.655 + </change>
18.656 + <change id="textual-icons-for-actions" >
18.657 + <api name="actions"/>
18.658 + <summary>Can create textual icons for actions</summary>
18.659 + <date day="23" month="3" year="2000"/>
18.660 + <author login="jglick"/>
18.661 + <compatibility addition="yes" modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no"/>
18.662 + <description>
18.663 + <code>iconResource</code> may now return <code>null</code> to indicate no
18.664 + icon. <code>getIcon(true)</code> may be used to get an icon created from
18.665 + the label if there is no icon specified.
18.666 + </description>
18.667 + <class package="org.openide.util.actions" name="SystemAction"/>
18.668 + </change>
18.669 + <change id="use-icon-instead-of-imageicon" >
18.670 + <api name="actions"/>
18.671 + <summary>
18.672 + <code>SystemAction</code> refers to <code>Icon</code> rather than <code>ImageIcon</code>
18.673 + </summary>
18.674 + <date day="11" month="4" year="2000"/>
18.675 + <author login="jglick"/>
18.676 + <compatibility modification="yes" binary="compatible" source="incompatible" semantic="compatible" deprecation="no" addition="no" deletion="no">
18.677 + First broken, later restored binary compatibility in trunk and
18.678 + <code>boston</code>. Any code explicitly using this calls before may break
18.679 + (source code may be compatible in many cases; binary compatibility has
18.680 + been preserved). These calls were known to be used only for
18.681 + <code>Actions</code> to create presenters; normal code which constructs
18.682 + <code>SystemAction</code>s and implements <code>iconResource</code> should
18.683 + be unaffected. Actions using the "grouping action" template should check
18.684 + their <code>getMenuPresenter</code> method which may be
18.685 + binary-incompatible; it is easy to replace the code with safer code such
18.686 + as:
18.687 + <pre xml:space="preserve">
18.688 +<span class="comment">// ....
18.689 +</span>
18.690 +<span class="keyword">private</span> <span class="keyword">static</span> <span class="type">Icon</span> <span class="variable-name">icon</span> = <span class="constant">null</span>;
18.691 +<span class="comment">// ....
18.692 +</span>
18.693 +<span class="keyword">public</span> <span class="type">JMenuItem</span> <span class="function-name">getMenuPresenter</span>() {
18.694 + <span class="type">JMenu</span> <span class="variable-name">menu</span> = <span class="keyword">new</span> <span class="type">JMenu</span>(getName ());
18.695 + <span class="keyword">if</span> (icon == <span class="constant">null</span>) {
18.696 + icon = <span class="keyword">new</span> <span class="type">ImageIcon</span>(MyAction.<span class="keyword">class</span>.getResource(iconResource()));
18.697 + }
18.698 + menu.setIcon(icon);
18.699 + <span class="comment">// ....</span>
18.700 +</pre>
18.701 + </compatibility>
18.702 + <description>
18.703 + <code>getIcon</code> and <code>setIcon</code> now use the interface
18.704 + <code>Icon</code> rather than the particular implementation
18.705 + <code>ImageIcon</code>. This corrects an API bug (excessive specificity).
18.706 + </description>
18.707 + <class package="org.openide.util.actions" name="SystemAction"/>
18.708 + </change>
18.709 + <change>
18.710 + <api name="actions"/>
18.711 + <summary>New Actions system - part I.</summary>
18.712 + <version major="3" minor="29"/>
18.713 + <date day="8" month="1" year="2003"/>
18.714 + <author login="jtulach"/>
18.715 + <author login="pzavadsky"/>
18.716 + <compatibility deprecation="yes" addition="yes" modification="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no"/>
18.717 + <description>
18.718 + <p>
18.719 + Introduction of new action system, which generally means
18.720 + move from usage of <code>SystemAction</code> to <code>Action</code> instances.
18.721 + That document also focuses on declarative actions
18.722 + usage which is not subject of current change, it will be part of later changes.
18.723 + </p>
18.724 + </description>
18.725 + <class package="org.openide.util" name="ContextAwareAction"/>
18.726 + <class package="org.openide.util" name="Utilities"/>
18.727 + <class package="org.openide.util.actions" name="CallbackSystemAction"/>
18.728 + <issue number="27868"/>
18.729 + </change>
18.730 +
18.731 +<change id="Task-waitFinished-timeout">
18.732 + <api name="util"/>
18.733 + <summary>New method <code>task.waitFinished(timeout)</code> added</summary>
18.734 + <version major="5" minor="0"/>
18.735 + <date day="2" month="11" year="2004"/>
18.736 + <author login="jtulach"/>
18.737 + <compatibility addition="yes" binary="compatible" semantic="compatible" source="compatible" deprecation="no" deletion="no" modification="no"/>
18.738 + <description>
18.739 + <p>It is not possible to wait for a limited amount of time for
18.740 + completion of any task. The <code>RequestProcessor.Task</code>
18.741 + version is optimized, the <code>Task</code> version ensures that
18.742 + the sematics will be compatible for all subclasses, even they did
18.743 + not know about the method at all.
18.744 + </p>
18.745 + </description>
18.746 + <class package="org.openide.util" name="Task"/>
18.747 + <class package="org.openide.util" name="RequestProcessor"/>
18.748 + <issue number="16849"/>
18.749 + </change>
18.750 +<change id="add-detection-of-FreeBSD-OS">
18.751 + <api name="util"/>
18.752 + <summary>Added field <code>OS_FREEBSD</code> to <code>Utilities</code>
18.753 +</summary>
18.754 + <version major="4" minor="50"/>
18.755 + <date day="29" month="10" year="2004"/>
18.756 + <author login="jrechtacek"/>
18.757 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.758 + <description>
18.759 + <p>FreeBSD was not recognized as Unix OS. <code>Utilities</code> has been
18.760 + enlarged with new field <code>OS_FREEBSD</code>, part of OS Unix mask. <code>Utilities.isUnix()</code>
18.761 + now returns <code>true</code> for applications run on FreeBSD.
18.762 + </p>
18.763 + </description>
18.764 + <class package="org.openide.util" name="Utilities"/>
18.765 + </change>
18.766 + <change id="Mutex.isReadWriteAccess">
18.767 + <api name="util"/>
18.768 + <summary>Added <code>Mutex.isReadAccess()</code> and <code>Mutex.isWriteAcess()</code>
18.769 +</summary>
18.770 + <version major="4" minor="48"/>
18.771 + <date day="30" month="9" year="2004"/>
18.772 + <author login="jtulach"/>
18.773 + <compatibility addition="yes" binary="compatible" semantic="compatible" source="compatible" deprecation="no" deletion="no" modification="no"/>
18.774 + <description>
18.775 + A thread can now check whether read or write access on a <code>Mutex</code>
18.776 + has already been
18.777 + granted to it and use it to decide whether it is safe to perform
18.778 + certain operations or delay them.
18.779 + </description>
18.780 + <class package="org.openide.util" name="Mutex"/>
18.781 + <issue number="49459"/>
18.782 + </change>
18.783 +<change id="SharedClassObject.reset">
18.784 + <api name="util"/>
18.785 + <summary>Added <code>SharedClassObject.reset</code> method to allow subclasses to implement reset correctly</summary>
18.786 + <version major="4" minor="46"/>
18.787 + <date day="2" month="9" year="2004"/>
18.788 + <author login="jtulach"/>
18.789 + <compatibility addition="yes" binary="compatible" semantic="compatible" source="compatible" deprecation="no" deletion="no" modification="no"/>
18.790 + <description>
18.791 + The new <code>SharedClassObject.reset</code> method is called
18.792 + by the infrastructure in moments when an original (at the time
18.793 + of start) state of an option or any other <code>SharedClassObject</code>
18.794 + is requested. Interested subclasses are free to implement any kind of clean
18.795 + they need. The <code>SystemOption</code> provides a default
18.796 + implementation based on fired property changed events, so
18.797 + its correctly written subclasses do not need
18.798 + to do anything.
18.799 + </description>
18.800 + <class package="org.openide.util" name="SharedClassObject"/>
18.801 + <issue number="20962"/>
18.802 + </change>
18.803 +<change>
18.804 + <api name="util"/>
18.805 + <summary>enum package deprecated and replaced by Enumerations factory class</summary>
18.806 + <version major="4" minor="37"/>
18.807 + <date day="7" month="6" year="2004"/>
18.808 + <author login="jtulach"/>
18.809 + <compatibility deprecation="yes" addition="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no"/>
18.810 + <description>
18.811 + enum is a keyword in JDK 1.5 and as such it should not be used.
18.812 + That is the reason why we had to deprecated our
18.813 + <code>org.openide.util.enum</code> package. We are providing
18.814 + replacements of the original classes in form of factory methods
18.815 + <code>org.openide.util.Enumerations</code>.
18.816 + </description>
18.817 + <class package="org.openide.util" name="Enumerations"/>
18.818 + <issue number="41166"/>
18.819 + </change>
18.820 +<change>
18.821 + <api name="util"/>
18.822 + <summary>Support for complicated listeners</summary>
18.823 + <version major="4" minor="12"/>
18.824 + <date day="2" month="9" year="2003"/>
18.825 + <author login="jtulach"/>
18.826 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.827 + <description>
18.828 + Improved support for hierarchic listeners (aka NamingListener vs. ObjectChangeListener from
18.829 + javax.naming.event package).
18.830 + </description>
18.831 + <class package="org.openide.util" name="WeakListeners"/>
18.832 + <issue number="35726"/>
18.833 + </change>
18.834 +<change id="Utilities.actionsGlobalContext">
18.835 + <api name="util"/>
18.836 + <summary>Global action context as <code>Lookup</code>
18.837 +</summary>
18.838 + <version major="4" minor="10"/>
18.839 + <date day="12" month="8" year="2003"/>
18.840 + <author login="jtulach"/>
18.841 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.842 + <description>
18.843 + As part of the work on separation of openide.jar into smaller parts
18.844 + a new interface <code>ContextGlobalProvider</code> and new method
18.845 + in utilities <code>Utilities.actionsGlobalContext()</code> had to be
18.846 + added in order to separate the implementation of actions like
18.847 + <code>CallbackSystemAction</code> and <code>NodeAction</code> from
18.848 + their dependency on window system.
18.849 + </description>
18.850 + <class package="org.openide.util" name="ContextGlobalProvider"/>
18.851 + <class package="org.openide.util" name="Utilities"/>
18.852 + <issue number="34758"/>
18.853 + </change>
18.854 +<change id="WeakListeners">
18.855 + <api name="util"/>
18.856 + <summary>Old <code>WeakListener</code> replaced by <code>WeakListeners</code> class</summary>
18.857 + <version major="4" minor="10"/>
18.858 + <date day="12" month="8" year="2003"/>
18.859 + <author login="jtulach"/>
18.860 + <compatibility deprecation="yes" addition="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no"/>
18.861 + <description>
18.862 + <p>
18.863 + As part of the work on separation of openide.jar into smaller parts
18.864 + the <code>WeakListener</code> had to be deprecated as it referenced too
18.865 + many classes around and replaced by more general <code>WeakListeners</code>
18.866 + factory class that provides a generic <code>create</code> method and
18.867 + specialized factory methods just for JDK own interfaces.
18.868 + </p>
18.869 + <p>
18.870 + Also few factory methods were spread into appropriate packages like
18.871 + <code>FileUtil.weakFileChangeListener</code> and
18.872 + <code>NodeOp.weakNodeListener</code>.
18.873 + </p>
18.874 + </description>
18.875 + <class package="org.openide.util" name="WeakListeners"/>
18.876 + <issue number="34758"/>
18.877 + </change>
18.878 + <change id="HelpCtx.findHelp">
18.879 + <api name="util"/>
18.880 + <summary>New method to find HelpCtx</summary>
18.881 + <version major="4" minor="3"/>
18.882 + <date day="2" month="4" year="2003"/>
18.883 + <author login="jtulach"/>
18.884 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.885 + <description>
18.886 + A new method for finding HelpCtx (<code>HelpCtx.findHelp(Object)</code>)
18.887 + has been added to replace
18.888 + the old <code>InstanceSupport.findHelp</code> that has been
18.889 + separated out from the openide.jar.
18.890 + </description>
18.891 + <class package="org.openide.util" name="HelpCtx"/>
18.892 + <issue number="32143"/>
18.893 + </change>
18.894 +<change>
18.895 + <api name="util"/>
18.896 + <summary>Retrofit of interface Cancellable into RequestProcessor.Task</summary>
18.897 + <version major="4" minor="1"/>
18.898 + <date day="14" month="3" year="2003"/>
18.899 + <author login="dsimonek"/>
18.900 + <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no"/>
18.901 + <description>
18.902 + RequestProcessor.Task was made to implement util.Cancellable interface.
18.903 + No change of implementation at all, RP.Task already had method from
18.904 + interface implemented, this is just a logical retrofit.
18.905 + </description>
18.906 + <class package="org.openide.util" name="RequestProcessor"/>
18.907 + </change>
18.908 +<change>
18.909 + <api name="util"/>
18.910 + <summary>Support for asynchronous init of UI components</summary>
18.911 + <version major="3" minor="36"/>
18.912 + <date day="5" month="2" year="2003"/>
18.913 + <author login="dsimonek"/>
18.914 + <compatibility deprecation="no" addition="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no"/>
18.915 + <description>
18.916 + <p>
18.917 + Performance related API addition, allows clients to write asynchronous
18.918 + initialization of UI components easily by providing <code>AsyncGUIJob</code>
18.919 + implementation. Also introduced <code>Cancellable</code> ability.
18.920 + <code>Utilities.attachInitJob</code> couples init job with target
18.921 + UI component.
18.922 + </p>
18.923 + </description>
18.924 + <class package="org.openide.util" name="AsyncGUIJob"/>
18.925 + <class package="org.openide.util" name="Cancellable"/>
18.926 + <class package="org.openide.util" name="Utilities"/>
18.927 + <issue number="30604"/>
18.928 + </change>
18.929 +<change>
18.930 + <api name="util"/>
18.931 + <summary>org.openide.util.Utilities.createProgressCursor added</summary>
18.932 + <version major="3" minor="23"/>
18.933 + <date day="2" month="12" year="2002"/>
18.934 + <author login="dsimonek"/>
18.935 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.936 + <description>
18.937 + Method java.awt.Cursor createProgressCursor(java.awt.Component comp) was
18.938 + added into Utilities class. Method creates mouse cursor suitable for
18.939 + components which are busy, but still reacts to the input events. (don't
18.940 + block UI).
18.941 + </description>
18.942 + <class package="org.openide.util" name="Utilities"/>
18.943 + </change>
18.944 +<change>
18.945 + <api name="util"/>
18.946 + <summary>Added interface HelpCtx.Provider</summary>
18.947 + <version major="3" minor="20"/>
18.948 + <date day="11" month="11" year="2002"/>
18.949 + <author login="pnejedly"/>
18.950 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.951 + <description>
18.952 + An interface HelpCtx.Provider with one method getHelpCtx was added
18.953 + and the logic in HelpCtx.findHelp and InstanceSupport.findHelp
18.954 + was extended to take this interface into accout.
18.955 + Various classes with existing getHelpCtx method were retrofitted
18.956 + to implement this interface.
18.957 + </description>
18.958 + <class package="org.openide.util" name="HelpCtx"/>
18.959 + <class package="org.openide" name="ServiceType"/>
18.960 + <class package="org.openide.util.actions" name="SystemAction"/>
18.961 + <class package="org.openide.util.datatransfer" name="NewType"/>
18.962 + <class package="org.openide.util.datatransfer" name="PasteType"/>
18.963 + </change>
18.964 +<change>
18.965 + <api name="util"/>
18.966 + <summary>Can load localized cached images</summary>
18.967 + <version major="3" minor="24"/>
18.968 + <date day="15" month="12" year="2002"/>
18.969 + <author login="jglick"/>
18.970 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.971 + <description>
18.972 + Added method <code>Utilities.loadImage(String, boolean)</code>
18.973 + which works like <code>Utilities.loadImage(String)</code> except
18.974 + that it will search for localized images. Also
18.975 + <code>SystemAction.getIcon()</code> will load a localized image now
18.976 + if there is one.
18.977 + </description>
18.978 + <class package="org.openide.util" name="Utilities"/>
18.979 + <class package="org.openide.util.actions" name="SystemAction"/>
18.980 + <issue number="22156"/>
18.981 + </change>
18.982 +<change>
18.983 + <api name="util"/>
18.984 + <summary>Utilities.activeReferenceQueue()</summary>
18.985 + <version major="3" minor="11"/>
18.986 + <date day="7" month="10" year="2002"/>
18.987 + <author login="jtulach"/>
18.988 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.989 + <description>
18.990 + Active java.util.ref.ReferenceQueue that polls for all
18.991 + enqued instances (that should implement Runnable) and
18.992 + invokes their run method to do actual cleanup.
18.993 + </description>
18.994 + <class package="org.openide.util" name="Utilities"/>
18.995 + <issue number="27238"/>
18.996 + </change>
18.997 +<change>
18.998 + <api name="util"/>
18.999 + <summary>Deprecation of parts of MouseUtils.PopupMenuAdapter</summary>
18.1000 + <version major="3" minor="4"/>
18.1001 + <date day="6" month="8" year="2002"/>
18.1002 + <author login="dsimonek"/>
18.1003 + <compatibility deprecation="yes" binary="compatible" source="compatible" semantic="compatible" addition="no" deletion="no" modification="no"/>
18.1004 + <description>
18.1005 + Constructor MouseUtils.PopupMenuAdapter(int) and public static field
18.1006 + DEFAULT_THESHOLD are now obsoleted, performs no action.
18.1007 + PopupMenuAdapter now delegates to isPopupTrigger crossplatform call,
18.1008 + should be constructed via default constructor.
18.1009 + </description>
18.1010 + </change>
18.1011 +<change>
18.1012 + <api name="util"/>
18.1013 + <summary>
18.1014 +<code>Utilities.toFile</code> and <code>toURL</code> added</summary>
18.1015 + <version major="3" minor="26"/>
18.1016 + <date day="24" month="12" year="2002"/>
18.1017 + <author login="jglick"/>
18.1018 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no">
18.1019 + Existing code which uses the JDK 1.3 method <code>File.toURL</code> should be
18.1020 + examined, as it may be better to call <code>Utilities.toURL</code>.
18.1021 + Similarly, code which gets the path from a URL and calls the <code>File</code>
18.1022 + constructor may need to be changed to call <code>Utilities.toFile</code>.
18.1023 + Such changes should improve robustness of code when used in strangely
18.1024 + named directories.
18.1025 + </compatibility>
18.1026 + <description>
18.1027 + Two new utility methods were added which permit easy interconversion between
18.1028 + files and URLs using the <code>file</code> protocol. This task is easy and
18.1029 + safe under JDK 1.4, yet JDK 1.3 lacks a single call to do these tasks which
18.1030 + will handle unusual characters in file names, especially hash marks. The
18.1031 + utility methods use the JDK 1.4 variants when possible, else use specially
18.1032 + coded versions of the JDK 1.3 variants which handle hash marks.
18.1033 + </description>
18.1034 + <class package="org.openide.util" name="Utilities"/>
18.1035 + <issue number="29711"/>
18.1036 + </change>
18.1037 +<change>
18.1038 + <api name="util"/>
18.1039 + <summary>Added RequestProcessor.getDefault(), deprecated static methods in RequestProcessor</summary>
18.1040 + <version major="2" minor="12"/>
18.1041 + <date day="15" month="4" year="2002"/>
18.1042 + <author login="pnejedly"/>
18.1043 + <compatibility addition="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no"/>
18.1044 + <description>Sharing of singlethreaded
18.1045 + <code>RequestProcessor.DEFAULT</code>
18.1046 + through the static methods is inherently deadlock-prone,
18.1047 + so the methods are deprecated and their usage should phase out
18.1048 + in the favor of using private <code>RequestProcessor</code>s
18.1049 + or the shared multithreaded instance available through the new
18.1050 + static method <code>RequestProcessor.getDefault()</code>.
18.1051 + </description>
18.1052 + <class package="org.openide.util" name="RequestProcessor"/>
18.1053 + </change>
18.1054 +<change>
18.1055 + <api name="util"/>
18.1056 + <summary>Added helper methods to aid module developers to write code which works correctly with multiple monitors</summary>
18.1057 + <version major="2" minor="5"/>
18.1058 + <date day="26" month="2" year="2002"/>
18.1059 + <author login="ttran"/>
18.1060 + <compatibility addition="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no"/>
18.1061 + <description>
18.1062 + The added methods are
18.1063 + <pre xml:space="preserve">
18.1064 +<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Rectangle</span> <span class="function-name">getUsableScreenBounds</span>();
18.1065 +<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Rectangle</span> <span class="function-name">getUsableScreenBounds</span>(<span class="type">GraphicsConfiguration</span> <span class="variable-name">gconf</span>);
18.1066 +<span class="keyword">public</span> <span class="keyword">static</span> <span class="type">Rectangle</span> <span class="function-name">findCenterBounds</span>(<span class="type">Dimension</span> <span class="variable-name">componentSize</span>);
18.1067 +</pre>
18.1068 + One should use these methods instead of calling
18.1069 + <code>Toolkit.getScreenSize()</code>. For the same reason
18.1070 + <code>Utilities.getScreenSize()</code> is now deprecated.
18.1071 + </description>
18.1072 + <class package="org.openide.util" name="Utilities"/>
18.1073 + <issue number="20882"/>
18.1074 + </change>
18.1075 +<change id="ErrorManager.getDefault">
18.1076 + <api name="util"/>
18.1077 + <summary>Added accessibility method ErrorManager.getDefault () that always returns non-null values</summary>
18.1078 + <version major="2" minor="1"/>
18.1079 + <date day="17" month="1" year="2002"/>
18.1080 + <author login="jtulach"/>
18.1081 + <compatibility addition="yes" modification="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no"/>
18.1082 + <description>
18.1083 + <p>
18.1084 + This method allows independent libraries (nodes, filesystems, utilities) to use the ErrorManager without
18.1085 + testing if it is really present. Just call <code>ErrorManager.getDefault ()</code> and you can be sure
18.1086 + that a valid instance will be returned.
18.1087 + </p>
18.1088 + <p>
18.1089 + Also <code>TopManager.getErrorManager</code> is no longer useful (<a href="#ErrorManager.getDefault" shape="rect">see change</a>) and is now deprecated.
18.1090 + It is also not abstract as it just delegates.
18.1091 + <code>notifyException</code> is similarly deprecated.
18.1092 + </p>
18.1093 + </description>
18.1094 + <class package="org.openide" name="ErrorManager"/>
18.1095 + <issue number="16854"/>
18.1096 + </change>
18.1097 + <change id="logging-added-to-error-manager" >
18.1098 + <api name="util"/>
18.1099 + <summary>
18.1100 +<code>ErrorManager.isLoggable</code> added</summary>
18.1101 + <date day="2" month="12" year="2000"/>
18.1102 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1103 + <description>
18.1104 + <code>isLoggable(int severity)</code> added to <code>ErrorManager</code>.
18.1105 + </description>
18.1106 + <class package="org.openide" name="ErrorManager"/>
18.1107 + </change>
18.1108 +<change>
18.1109 + <api name="util"/>
18.1110 + <summary>Logging and hierarchy support added to <code>ErrorManager</code>
18.1111 +</summary>
18.1112 + <date day="18" month="8" year="2000"/>
18.1113 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1114 + <description>
18.1115 + <code>getInstance(String name)</code>, <code>log(int severity, String s)</code>, and
18.1116 + <code>log(String s)</code> added to <code>ErrorManager</code>.
18.1117 + </description>
18.1118 + <class package="org.openide" name="ErrorManager"/>
18.1119 + </change>
18.1120 + <change>
18.1121 + <api name="xml"/>
18.1122 + <summary>Can register entity resolvers</summary>
18.1123 + <date day="20" month="12" year="2000"/>
18.1124 + <compatibility addition="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no">
18.1125 + Subsequently deprecated on <date day="3" month="3" year="2001"/> by
18.1126 + <a href="#created-XMLUtil" shape="rect">
18.1127 +<code>EntityCatalog</code>
18.1128 +</a>.
18.1129 + </compatibility>
18.1130 + <description>
18.1131 + <code>addEntityResolver</code> and <code>removeEntityResolver</code>
18.1132 + added. These methods allow a user to develop own implementation of
18.1133 + functionality similar to <code>registerCatalogEntry</code>. E.g. a user
18.1134 + can register <code>EntityResolver</code> that reads data from persistent
18.1135 + catalog avoiding bunch of calls to the register method in module
18.1136 + <code>restore</code> code.
18.1137 + </description>
18.1138 + <class package="org.openide.xml" name="EntityCatalog"/>
18.1139 + </change>
18.1140 +<change>
18.1141 + <api name="xml"/>
18.1142 + <summary>Updated DOM to level 2 and added document writability</summary>
18.1143 + <date day="26" month="1" year="2001"/>
18.1144 + <author login="pkuzel"/>
18.1145 + <compatibility modification="yes" binary="incompatible" source="incompatible" deprecation="yes" semantic="compatible" addition="no" deletion="no">
18.1146 + Any code implementing DOM interfaces could be broken by the level 2
18.1147 + interfaces. Clients of the DOM API should be unaffected.
18.1148 + </compatibility>
18.1149 + <description>
18.1150 + <ul>
18.1151 + <li>All level 1 <code>Document</code>s interfaces became level 2 ones.</li>
18.1152 + <li>Deprecated <code>write(Document, Writer)</code>
18.1153 + <p>A conflict between encoding declared in document and
18.1154 + actual Writer encoding can cause data loss. Suitable
18.1155 + just for UTF-8 and UTF-16 writers.
18.1156 + </p>
18.1157 + </li>
18.1158 + <li>introduced <code>write(Document, OutputStream, String encoding)</code>
18.1159 + <p>
18.1160 + The write method is supposed to be used as an implementation
18.1161 + independent way for writing DOM documents until self-writable
18.1162 + documents specification will be introduced. The self-writability
18.1163 + is considered to be a part of DOM level 3 specs.
18.1164 + </p>
18.1165 + <p>
18.1166 + Nowadays it is implemented that it can handle following DOM implementations:
18.1167 + </p>
18.1168 + <ul>
18.1169 + <li>Crimson</li>
18.1170 + <li>JAXP 1.0 reference implementation</li>
18.1171 + <li>All others using Apache's serializers if available.</li>
18.1172 + </ul>
18.1173 + </li>
18.1174 + </ul>
18.1175 + </description>
18.1176 + <class package="org.openide.xml" name="XMLUtil"/>
18.1177 + </change>
18.1178 +<change id="Utilities.topologicalSort">
18.1179 + <api name="util"/>
18.1180 + <summary>Improved method for topological sort</summary>
18.1181 + <version major="3" minor="30"/>
18.1182 + <date day="10" month="1" year="2003"/>
18.1183 + <author login="jglick"/>
18.1184 + <compatibility deprecation="yes" addition="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no"/>
18.1185 + <description>
18.1186 + The method <code>Utilities.topologicalSort</code> was added. It should be
18.1187 + faster and probably more robust than the older <code>partialSort</code>
18.1188 + method, which required a <code>Comparator</code>; the new method requires
18.1189 + a list of ordering constraints, which should be <i>O(n + m)</i>
18.1190 + rather than <i>O(n<sup>2</sup>)</i> (where <i>n</i> is the number of
18.1191 + nodes to sort and <i>m</i> the number of edges). If the graph is
18.1192 + not a DAG a <code>TopologicalSortException</code> is thrown containing
18.1193 + description of unsortable parts of the graph and the best partitial sort
18.1194 + that fullfils as much of ordering constraints as possible. These
18.1195 + information can be used for error reporting and recovery.
18.1196 + </description>
18.1197 + <class package="org.openide.util" name="Utilities"/>
18.1198 + <class package="org.openide.util" name="TopologicalSortException"/>
18.1199 + <issue number="27286"/>
18.1200 + </change>
18.1201 +<change>
18.1202 + <api name="xml"/>
18.1203 + <summary>Moved XML static methods into separate inner class</summary>
18.1204 + <date day="16" month="2" year="2001"/>
18.1205 + <author login="pkuzel"/>
18.1206 + <compatibility addition="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no">
18.1207 + <code>XMLDataObject.Util</code> itself deprecated on
18.1208 + <date day="3" month="3" year="2001"/> in favor of
18.1209 + <a href="#created-XMLUtil" shape="rect">
18.1210 +<code>XMLUtil</code>
18.1211 +</a>.
18.1212 + </compatibility>
18.1213 + <description>
18.1214 + <ul>
18.1215 + <li>
18.1216 + Deprecated all static: <code>write()</code>s, <code>parse()</code>s,
18.1217 + <code>createDocument()</code>, <code>createInputSource()</code> and
18.1218 + <code>createParser()</code>s methods.
18.1219 + </li>
18.1220 + <li>
18.1221 + Introduced public static inner class named <code>Util</code> providing
18.1222 + utility methods replacing deprecated ones.
18.1223 + </li>
18.1224 + </ul>
18.1225 + </description>
18.1226 + <class package="org.openide.xml" name="XMLUtil"/>
18.1227 + </change>
18.1228 + <change id="Mutex.Privileged">
18.1229 + <api name="util"/>
18.1230 + <summary>Permit privileged access to mutexes to avoid inner classes</summary>
18.1231 + <version major="1" minor="17"/>
18.1232 + <date day="27" month="6" year="2001"/>
18.1233 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1234 + <description>
18.1235 + Added a new inner class and a constructor that takes an instance of that
18.1236 + inner class as a parameter. The inner class is <code>Privileged</code>.
18.1237 + Through its public methods one can enter internal states of the
18.1238 + <code>Mutex</code> to which it was passed.
18.1239 + </description>
18.1240 + <class package="org.openide.util" name="Mutex"/>
18.1241 + </change>
18.1242 +<change id="Task.notifyRunning">
18.1243 + <api name="util"/>
18.1244 + <summary>More flexibility in controlling running of tasks</summary>
18.1245 + <version major="1" minor="5"/>
18.1246 + <date day="27" month="4" year="2001"/>
18.1247 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1248 + <description>
18.1249 + <code>Task</code> has new protected constructor for subclasses and
18.1250 + methods <code>notifyRunning ()</code> and also non-final version of
18.1251 + <code>waitFinished ()</code>.
18.1252 + </description>
18.1253 + <class package="org.openide.util" name="Task"/>
18.1254 + </change>
18.1255 + <change>
18.1256 + <api name="util"/>
18.1257 + <summary>
18.1258 + <code>ErrorManager.isNotifiable</code> added</summary>
18.1259 + <version major="3" minor="18"/>
18.1260 + <date day="3" month="11" year="2002"/>
18.1261 + <author login="jglick"/>
18.1262 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no">
18.1263 + Existing code which assumes (incorrectly) that <code>isLoggable</code>
18.1264 + can be used for this purpose, or which calls <code>notify</code> at a low
18.1265 + level such as <code>INFORMATIONAL</code> without first checking
18.1266 + <code>isNotifiable</code> for efficiency, should be revised.
18.1267 + </compatibility>
18.1268 + <description>
18.1269 + The method <code>ErrorManager.isNotifiable</code> was added to capture
18.1270 + the fact that an error manager implementation might be more aggressive
18.1271 + about displaying stack traces than log messages.
18.1272 + </description>
18.1273 + <class package="org.openide" name="ErrorManager"/>
18.1274 + <issue number="24056"/>
18.1275 + </change>
18.1276 + <change id="clone-service-type" >
18.1277 + <api name="util"/>
18.1278 + <summary>
18.1279 + <code>ServiceType.createClone</code> added</summary>
18.1280 + <date day="30" month="11" year="2000"/>
18.1281 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no">Subclasses are encouraged to implement <code>Cloneable</code>.</compatibility>
18.1282 + <description>
18.1283 + <code>public final ServiceType createClone()</code> added.
18.1284 + </description>
18.1285 + <class package="org.openide" name="ServiceType"/>
18.1286 + </change>
18.1287 +<change>
18.1288 + <api name="util"/>
18.1289 + <summary>Icon & image cache manager added</summary>
18.1290 + <date day="9" month="3" year="2001"/>
18.1291 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1292 + <description>
18.1293 + Loading icons and images can be done through
18.1294 + <code>Utilities.loadImage()</code> that uses cache to avoid duplicate
18.1295 + loading of images. <code>mergeImages</code> uses the cache, too, for the
18.1296 + results of merge.
18.1297 + </description>
18.1298 + <class package="org.openide.util" name="Utilities"/>
18.1299 + </change>
18.1300 +<change>
18.1301 + <api name="util"/>
18.1302 + <summary>Updated DEC -> Compaq OS names</summary>
18.1303 + <date day="15" month="12" year="2000"/>
18.1304 + <compatibility modification="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" addition="no" deletion="no"/>
18.1305 + <description>
18.1306 + Operating system <code>OS_DEC</code> changed to <code>OS_TRU64</code>,
18.1307 + and added <code>OS_VMS</code>.
18.1308 + </description>
18.1309 + <class package="org.openide.util" name="Utilities"/>
18.1310 + </change>
18.1311 +<change>
18.1312 + <api name="util"/>
18.1313 + <summary>Proper break iterators used when wrapping text strings</summary>
18.1314 + <date day="11" month="8" year="2000"/>
18.1315 + <compatibility modification="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" addition="no" deletion="no">
18.1316 + Deprecated version first removed, later re-added with deprecation in the
18.1317 + trunk.
18.1318 + </compatibility>
18.1319 + <description>
18.1320 + Added method <code>wrapString</code> which uses
18.1321 + <code>BreakIterator</code> instead of a flag and a heuristic solution.
18.1322 + <code>wrapString(String,int,boolean,boolean)</code> deprecated.
18.1323 + </description>
18.1324 + <class package="org.openide.util" name="Utilities"/>
18.1325 + </change>
18.1326 +<change>
18.1327 + <api name="util"/>
18.1328 + <summary>Support for merging icons added</summary>
18.1329 + <date day="25" month="1" year="2001"/>
18.1330 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1331 + <description>
18.1332 + Added method <code>mergeImages(Image image1, Image image2, int x, int
18.1333 + y)</code> for merging images.
18.1334 + </description>
18.1335 + <class package="org.openide.util" name="Utilities"/>
18.1336 + </change>
18.1337 +<change>
18.1338 + <api name="util"/>
18.1339 + <summary>Can get a list of localizing suffixes</summary>
18.1340 + <date day="1" month="1" year="2001"/>
18.1341 + <author login="jglick"/>
18.1342 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1343 + <description>
18.1344 + <code>getLocalizingSuffixes</code> added.
18.1345 + </description>
18.1346 + <class package="org.openide.util" name="NbBundle"/>
18.1347 + </change>
18.1348 +<change>
18.1349 + <api name="util"/>
18.1350 + <summary>Can find localized variants of extensionless resources</summary>
18.1351 + <date day="6" month="10" year="2000"/>
18.1352 + <author login="jglick"/>
18.1353 + <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no"/>
18.1354 + <description>
18.1355 + <code>getLocalizedFile</code> now accepts <code>null</code> extensions
18.1356 + to suppress the addition of a dot to the resource name.
18.1357 + </description>
18.1358 + <class package="org.openide.util" name="NbBundle"/>
18.1359 + </change>
18.1360 +<change>
18.1361 + <api name="util"/>
18.1362 + <summary>Added search for branded variants as part of locale lookup</summary>
18.1363 + <date day="20" month="7" year="2000"/>
18.1364 + <author login="jglick"/>
18.1365 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1366 + <description>
18.1367 + Added methods <code>getBranding</code> and <code>setBranding</code>.
18.1368 + Normally these should only be called by the core implementation during
18.1369 + startup, not module authors. All methods to look up localized objects
18.1370 + may now also search for branded variants, if applicable.
18.1371 + </description>
18.1372 + <class package="org.openide.util" name="NbBundle"/>
18.1373 + </change>
18.1374 +<change>
18.1375 + <api name="util"/>
18.1376 + <summary>Classloader finder for <code>NbBundle</code> is obsolete</summary>
18.1377 + <date day="11" month="4" year="2000"/>
18.1378 + <compatibility deletion="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" modification="no">
18.1379 + First removed, later re-added but deprecated in trunk and
18.1380 + <code>boston</code>. No one outside of <code>NbBundle</code> and the
18.1381 + core implementation should have been using these classes to begin with.
18.1382 + </compatibility>
18.1383 + <description>
18.1384 + <code>NbBundle.ClassLoaderFinder</code> and
18.1385 + <code>NbBundle.setClassLoaderFinder</code> have been deprecated; they
18.1386 + were quite obsolete.
18.1387 + </description>
18.1388 + <class package="org.openide.util" name="NbBundle"/>
18.1389 + </change>
18.1390 +<change>
18.1391 + <api name="util"/>
18.1392 + <summary>Special exception thrown to request interaction with user</summary>
18.1393 + <date day="5" month="3" year="2001"/>
18.1394 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1395 + <description>
18.1396 + Added the first revision. This exception is thrown when a process is
18.1397 + about to perform some action that requires user confirmation.
18.1398 + </description>
18.1399 + <class package="org.openide.util" name="UserQuestionException"/>
18.1400 + </change>
18.1401 +<change>
18.1402 + <api name="util"/>
18.1403 + <summary>
18.1404 +<code>SafeException</code> is a <code>FoldingIOException</code>
18.1405 +</summary>
18.1406 + <date day="9" month="3" year="2000"/>
18.1407 + <compatibility modification="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" addition="no" deletion="no"/>
18.1408 + <description>
18.1409 + Now extends <code>FoldingIOException</code>, meaning that it should
18.1410 + delegate the detail message, etc. to the original.
18.1411 + </description>
18.1412 + <class package="org.openide.util.io" name="SafeException"/>
18.1413 + </change>
18.1414 + <change id="created-XMLUtil">
18.1415 + <api name="xml"/>
18.1416 + <summary>Independent XML API created</summary>
18.1417 + <date day="3" month="3" year="2001"/>
18.1418 + <author login="pkuzel"/>
18.1419 + <compatibility addition="yes" deprecation="yes" binary="compatible" source="compatible" semantic="compatible" deletion="no" modification="no"/>
18.1420 + <description>
18.1421 + <code>XMLUtil</code> utility class introduced. The class provides set of
18.1422 + static methods useful for XML processing. <code>EntityCatalog</code>
18.1423 + class introduced. It provides access to entity mapping registrations
18.1424 + provided by installed modules.
18.1425 + </description>
18.1426 + <class package="org.openide.xml" name="XMLUtil"/>
18.1427 + <class package="org.openide.xml" name="EntityCatalog"/>
18.1428 + <package name="org.openide.xml"/>
18.1429 + </change>
18.1430 + <change id="XMLUtil-1.29">
18.1431 + <api name="xml"/>
18.1432 + <summary>XML attribute and hexadecimal utilities added</summary>
18.1433 + <version major="1" minor="29"/>
18.1434 + <date day="8" month="8" year="2001"/>
18.1435 + <compatibility addition="yes" binary="compatible" source="compatible" semantic="compatible" deprecation="no" deletion="no" modification="no"/>
18.1436 + <description>
18.1437 + <code>toAttribute(String, char, boolean)</code>, <code>toContent(String,
18.1438 + boolean)</code>, <code>toHex(byte[], int, int)</code> and
18.1439 + <code>fromHex(char[], int, int)</code> methods added.
18.1440 + </description>
18.1441 + <class package="org.openide.xml" name="XMLUtil"/>
18.1442 + </change>
18.1443 + <change>
18.1444 + <api name="xml"/>
18.1445 + <summary>XML attribute and hexadecimal utilities modified</summary>
18.1446 + <version major="1" minor="40"/>
18.1447 + <date day="18" month="10" year="2001"/>
18.1448 + <compatibility binary="incompatible" source="incompatible" modification="yes" semantic="compatible" deprecation="no" addition="no" deletion="no">
18.1449 + The original versions of these methods were not in any public release.
18.1450 + </compatibility>
18.1451 + <description>
18.1452 + <code>toAttribute(String, char, boolean)</code> method replaced by
18.1453 + <code>toAttributeValue(String)</code>
18.1454 + and
18.1455 + <code>toContent(String, boolean)</code> method replaced by
18.1456 + <code>toElementContent(String)</code>. These new simplified
18.1457 + signatures and particular semantics should cover 99% usage of
18.1458 + previous ones. See the original <a href="#XMLUtil-1.29" shape="rect">additions</a>.
18.1459 + </description>
18.1460 + <class package="org.openide.xml" name="XMLUtil"/>
18.1461 + <issue number="16629"/>
18.1462 + </change>
18.1463 +</changes>
18.1464 +<htmlcontents>
18.1465 +<head>
18.1466 +<title>Change History for the Utilities API</title>
18.1467 +<link rel="stylesheet" href="prose.css" type="text/css"/>
18.1468 +</head>
18.1469 +<body>
18.1470 +<p class="overviewlink">
18.1471 +<a href="overview-summary.html">Overview</a>
18.1472 +</p>
18.1473 +<h1>Introduction</h1>
18.1474 +<h2>What do the Dates Mean?</h2>
18.1475 +<p>The supplied dates indicate when the API change was made, on the CVS
18.1476 +trunk. From this you can generally tell whether the change should be
18.1477 +present in a given build or not; for trunk builds, simply whether it
18.1478 +was made before or after the change; for builds on a stabilization
18.1479 +branch, whether the branch was made before or after the given date. In
18.1480 +some cases corresponding API changes have been made both in the trunk
18.1481 +and in an in-progress stabilization branch, if they were needed for a
18.1482 +bug fix; this ought to be marked in this list.</p>
18.1483 +<ul>
18.1484 +<li>The <code>release41</code> branch was made on Apr 03 '05 for use in the NetBeans 4.1 release.
18.1485 +Specification versions: 6.0 begins after this point.</li>
18.1486 +<li>The <code>release40</code> branch was made on Nov 01 '04 for use in the NetBeans 4.0 release.
18.1487 +Specification versions: 5.0 begins after this point.</li>
18.1488 +</ul>
18.1489 +<hr/>
18.1490 +<standard-changelists module-code-name="$codebase"/>
18.1491 +<hr/>
18.1492 +<p>@FOOTER@</p>
18.1493 +</body>
18.1494 +</htmlcontents>
18.1495 +</apichanges>
19.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
19.2 +++ b/openide.util/manifest.mf Fri Jan 22 10:02:41 2010 -0500
19.3 @@ -0,0 +1,5 @@
19.4 +Manifest-Version: 1.0
19.5 +OpenIDE-Module: org.openide.util
19.6 +OpenIDE-Module-Localizing-Bundle: org/openide/util/Bundle.properties
19.7 +OpenIDE-Module-Specification-Version: 8.1
19.8 +
20.1 --- a/openide.util/nbproject/project.properties Fri Jan 22 10:09:12 2010 -0500
20.2 +++ b/openide.util/nbproject/project.properties Fri Jan 22 10:02:41 2010 -0500
20.3 @@ -41,7 +41,6 @@
20.4 javac.source=1.6
20.5 module.jar.dir=lib
20.6
20.7 -spec.version.base=8.0.0
20.8
20.9 # For XMLSerializer, needed for XMLUtil.write to work w/ namespaces under JDK 1.4:
20.10
21.1 --- a/openide.util/nbproject/project.xml Fri Jan 22 10:09:12 2010 -0500
21.2 +++ b/openide.util/nbproject/project.xml Fri Jan 22 10:02:41 2010 -0500
21.3 @@ -51,7 +51,7 @@
21.4 <build-prerequisite/>
21.5 <compile-dependency/>
21.6 <run-dependency>
21.7 - <implementation-version/>
21.8 + <specification-version>8.1</specification-version>
21.9 </run-dependency>
21.10 </dependency>
21.11 </module-dependencies>
21.12 @@ -77,9 +77,8 @@
21.13 <public-packages>
21.14 <package>org.openide</package>
21.15 <package>org.openide.util</package>
21.16 + <package>org.openide.util.actions</package>
21.17 <package>org.openide.util.datatransfer</package>
21.18 - <package>org.openide.util.actions</package>
21.19 - <package>org.openide.util.lookup</package>
21.20 <package>org.openide.util.io</package>
21.21 <package>org.openide.xml</package>
21.22 </public-packages>
22.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
22.2 +++ b/openide.util/src/org/netbeans/modules/openide/util/URLStreamHandlerRegistrationProcessor.java Fri Jan 22 10:02:41 2010 -0500
22.3 @@ -0,0 +1,80 @@
22.4 +/*
22.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
22.6 + *
22.7 + * Copyright 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 + * If you wish your version of this file to be governed by only the CDDL
22.28 + * or only the GPL Version 2, indicate your decision by adding
22.29 + * "[Contributor] elects to include this software in this distribution
22.30 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
22.31 + * single choice of license, a recipient has the option to distribute
22.32 + * your version of this file under either the CDDL, the GPL Version 2 or
22.33 + * to extend the choice of license to its licensees as provided above.
22.34 + * However, if you add GPL Version 2 code and therefore, elected the GPL
22.35 + * Version 2 license, then the option applies only if the new code is
22.36 + * made subject to such option by the copyright holder.
22.37 + *
22.38 + * Contributor(s):
22.39 + *
22.40 + * Portions Copyrighted 2009 Sun Microsystems, Inc.
22.41 + */
22.42 +
22.43 +package org.netbeans.modules.openide.util;
22.44 +
22.45 +import java.net.URLStreamHandler;
22.46 +import java.util.Collections;
22.47 +import java.util.Set;
22.48 +import javax.annotation.processing.RoundEnvironment;
22.49 +import javax.annotation.processing.SupportedSourceVersion;
22.50 +import javax.lang.model.SourceVersion;
22.51 +import javax.lang.model.element.Element;
22.52 +import javax.lang.model.element.TypeElement;
22.53 +import javax.lang.model.type.TypeMirror;
22.54 +import org.openide.util.URLStreamHandlerRegistration;
22.55 +import org.openide.util.lookup.implspi.AbstractServiceProviderProcessor;
22.56 +
22.57 +@SupportedSourceVersion(SourceVersion.RELEASE_6)
22.58 +public class URLStreamHandlerRegistrationProcessor extends AbstractServiceProviderProcessor {
22.59 +
22.60 + public @Override Set<String> getSupportedAnnotationTypes() {
22.61 + return Collections.singleton(URLStreamHandlerRegistration.class.getCanonicalName());
22.62 + }
22.63 +
22.64 + public static final String REGISTRATION_PREFIX = "URLStreamHandler/"; // NOI18N
22.65 +
22.66 + /** public for ServiceLoader */
22.67 + public URLStreamHandlerRegistrationProcessor() {}
22.68 +
22.69 + protected boolean handleProcess(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {
22.70 + for (Element el : roundEnv.getElementsAnnotatedWith(URLStreamHandlerRegistration.class)) {
22.71 + TypeElement clazz = (TypeElement) el;
22.72 + URLStreamHandlerRegistration r = clazz.getAnnotation(URLStreamHandlerRegistration.class);
22.73 + TypeMirror type = processingEnv.getTypeUtils().getDeclaredType(
22.74 + processingEnv.getElementUtils().getTypeElement(URLStreamHandler.class.getName()));
22.75 + for (String protocol : r.protocol()) {
22.76 + register(clazz, URLStreamHandlerRegistration.class, type,
22.77 + REGISTRATION_PREFIX + protocol, r.position(), new String[0]);
22.78 + }
22.79 + }
22.80 + return true;
22.81 + }
22.82 +
22.83 +}
23.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
23.2 +++ b/openide.util/src/org/openide/util/NbPreferences.java Fri Jan 22 10:02:41 2010 -0500
23.3 @@ -0,0 +1,140 @@
23.4 +/*
23.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
23.6 + *
23.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
23.8 + *
23.9 + * The contents of this file are subject to the terms of either the GNU
23.10 + * General Public License Version 2 only ("GPL") or the Common
23.11 + * Development and Distribution License("CDDL") (collectively, the
23.12 + * "License"). You may not use this file except in compliance with the
23.13 + * License. You can obtain a copy of the License at
23.14 + * http://www.netbeans.org/cddl-gplv2.html
23.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
23.16 + * specific language governing permissions and limitations under the
23.17 + * License. When distributing the software, include this License Header
23.18 + * Notice in each file and include the License file at
23.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
23.20 + * particular file as subject to the "Classpath" exception as provided
23.21 + * by Sun in the GPL Version 2 section of the License file that
23.22 + * accompanied this code. If applicable, add the following below the
23.23 + * License Header, with the fields enclosed by brackets [] replaced by
23.24 + * your own identifying information:
23.25 + * "Portions Copyrighted [year] [name of copyright owner]"
23.26 + *
23.27 + * Contributor(s):
23.28 + *
23.29 + * The Original Software is NetBeans. The Initial Developer of the Original
23.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
23.31 + * Microsystems, Inc. All Rights Reserved.
23.32 + *
23.33 + * If you wish your version of this file to be governed by only the CDDL
23.34 + * or only the GPL Version 2, indicate your decision by adding
23.35 + * "[Contributor] elects to include this software in this distribution
23.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
23.37 + * single choice of license, a recipient has the option to distribute
23.38 + * your version of this file under either the CDDL, the GPL Version 2 or
23.39 + * to extend the choice of license to its licensees as provided above.
23.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
23.41 + * Version 2 license, then the option applies only if the new code is
23.42 + * made subject to such option by the copyright holder.
23.43 + */
23.44 +
23.45 +package org.openide.util;
23.46 +
23.47 +import java.io.ByteArrayOutputStream;
23.48 +import java.io.PrintStream;
23.49 +import java.util.logging.Level;
23.50 +import java.util.logging.Logger;
23.51 +import java.util.prefs.Preferences;
23.52 +
23.53 +/**
23.54 + * Provides an implementation of the Preferences API which may be backed by
23.55 + * a NetBeans-specific implementation.
23.56 + * @see <a href="doc-files/preferences.html">Preferences API in NetBeans</a>
23.57 + * @since org.openide.util 7.4
23.58 + * @author Radek Matous
23.59 + */
23.60 +public final class NbPreferences {
23.61 + private static Provider PREFS_IMPL;
23.62 +
23.63 + private NbPreferences() {}
23.64 +
23.65 + /**
23.66 + * Returns user preference node . {@link Preferences#absolutePath} of such
23.67 + * a node depends whether class provided as a parameter was loaded as a part of any module
23.68 + * or not. If so, then absolute path corresponds to slashified code name base of module.
23.69 + * If not, then absolute path corresponds to class's package.
23.70 + *
23.71 + * @param cls the class for which a user preference node is desired.
23.72 + * @return the user preference node
23.73 + */
23.74 + public static Preferences forModule(Class cls) {
23.75 + if (PREFS_IMPL == null) {
23.76 + PREFS_IMPL = getPreferencesProvider();
23.77 + }
23.78 + return PREFS_IMPL.preferencesForModule(cls);
23.79 + }
23.80 +
23.81 + /**
23.82 + * Returns the root preference node.
23.83 + *
23.84 + * @return the root preference node.
23.85 + */
23.86 + public static Preferences root() {
23.87 + if (PREFS_IMPL == null) {
23.88 + PREFS_IMPL = getPreferencesProvider();
23.89 + }
23.90 + return PREFS_IMPL.preferencesRoot();
23.91 + }
23.92 +
23.93 + private static Provider getPreferencesProvider() {
23.94 + Provider retval = Lookup.getDefault().lookup(Provider.class);
23.95 + if (retval == null) {
23.96 + retval = new Provider() {
23.97 + public Preferences preferencesForModule(Class cls) {
23.98 + return Preferences.userNodeForPackage(cls);
23.99 + }
23.100 +
23.101 + public Preferences preferencesRoot() {
23.102 + return Preferences.userRoot();
23.103 + }
23.104 + };
23.105 + // Avoided warning in case it is set
23.106 + //(e.g. from NbTestCase - org.netbeans.junit.internal.MemoryPreferencesFactory).
23.107 + String prefsFactory = System.getProperty("java.util.prefs.PreferencesFactory");//NOI18N
23.108 + if (!"org.netbeans.junit.internal.MemoryPreferencesFactory".equals(prefsFactory)) {//NOI18N
23.109 + Logger logger = Logger.getLogger(NbPreferences.class.getName());
23.110 + ByteArrayOutputStream bos = new ByteArrayOutputStream();
23.111 + new Exception().printStackTrace(new PrintStream(bos));
23.112 + logger.log(prefsFactory == null ? Level.WARNING : Level.FINE,
23.113 + "NetBeans implementation of Preferences not found: " + bos.toString() );//NOI18N
23.114 + }
23.115 + }
23.116 + return retval;
23.117 + }
23.118 +
23.119 + /**
23.120 + * Implementation of {@link NbPreferences} methods.
23.121 + * Not intended for use outside the NetBeans Platform.
23.122 + * @since org.openide.util 8.1
23.123 + */
23.124 + public interface Provider {
23.125 + /**
23.126 + * Returns user preference node. {@link Preferences#absolutePath} of such
23.127 + * a node depends whether class provided as a parameter was loaded as a part of any module
23.128 + * or not. If so, then absolute path corresponds to slashified code name base of module.
23.129 + * If not, then absolute path corresponds to class's package.
23.130 + *
23.131 + * @param cls the class for which a user preference node is desired.
23.132 + * @return the user preference node
23.133 + */
23.134 + Preferences preferencesForModule(Class cls);
23.135 + /**
23.136 + * Returns the root preference node.
23.137 + *
23.138 + * @return the root preference node.
23.139 + */
23.140 + Preferences preferencesRoot();
23.141 + }
23.142 +
23.143 +}
24.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
24.2 +++ b/openide.util/src/org/openide/util/Utilities.java Fri Jan 22 10:02:41 2010 -0500
24.3 @@ -0,0 +1,3115 @@
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;
24.46 +
24.47 +import java.awt.BorderLayout;
24.48 +import java.awt.Component;
24.49 +import java.awt.Container;
24.50 +import java.awt.Cursor;
24.51 +import java.awt.Dialog;
24.52 +import java.awt.Dimension;
24.53 +import java.awt.Event;
24.54 +import java.awt.Frame;
24.55 +import java.awt.GraphicsConfiguration;
24.56 +import java.awt.GraphicsEnvironment;
24.57 +import java.awt.Image;
24.58 +import java.awt.Insets;
24.59 +import java.awt.KeyboardFocusManager;
24.60 +import java.awt.Point;
24.61 +import java.awt.Rectangle;
24.62 +import java.awt.Toolkit;
24.63 +import java.awt.Window;
24.64 +import java.awt.event.ActionEvent;
24.65 +import java.awt.event.ActionListener;
24.66 +import java.awt.event.KeyEvent;
24.67 +import java.io.BufferedReader;
24.68 +import java.io.File;
24.69 +import java.io.IOException;
24.70 +import java.io.InputStreamReader;
24.71 +import java.lang.ref.Reference;
24.72 +import java.lang.ref.ReferenceQueue;
24.73 +import java.lang.ref.SoftReference;
24.74 +import java.lang.reflect.Field;
24.75 +import java.lang.reflect.Method;
24.76 +import java.lang.reflect.Modifier;
24.77 +import java.net.MalformedURLException;
24.78 +import java.net.URI;
24.79 +import java.net.URISyntaxException;
24.80 +import java.net.URL;
24.81 +import java.text.BreakIterator;
24.82 +import java.util.ArrayList;
24.83 +import java.util.Arrays;
24.84 +import java.util.Collection;
24.85 +import java.util.Collections;
24.86 +import java.util.Comparator;
24.87 +import java.util.Enumeration;
24.88 +import java.util.HashMap;
24.89 +import java.util.HashSet;
24.90 +import java.util.Iterator;
24.91 +import java.util.LinkedList;
24.92 +import java.util.List;
24.93 +import java.util.Locale;
24.94 +import java.util.Map;
24.95 +import java.util.NoSuchElementException;
24.96 +import java.util.Set;
24.97 +import java.util.StringTokenizer;
24.98 +import java.util.TreeSet;
24.99 +import java.util.Vector;
24.100 +import java.util.logging.Level;
24.101 +import java.util.logging.Logger;
24.102 +import javax.swing.Action;
24.103 +import javax.swing.Icon;
24.104 +import javax.swing.JMenuItem;
24.105 +import javax.swing.JPopupMenu;
24.106 +import javax.swing.JSeparator;
24.107 +import javax.swing.KeyStroke;
24.108 +import javax.swing.SwingUtilities;
24.109 +import javax.swing.Timer;
24.110 +import org.openide.util.actions.Presenter;
24.111 +import org.openide.util.lookup.Lookups;
24.112 +import org.openide.util.lookup.implspi.ActiveQueue;
24.113 +import org.openide.util.actions.ActionPresenterProvider;
24.114 +
24.115 +/** Otherwise uncategorized useful static methods.
24.116 +*
24.117 +* @author Jan Palka, Ian Formanek, Jaroslav Tulach
24.118 +*/
24.119 +public final class Utilities {
24.120 +
24.121 + private static final Logger LOG = Logger.getLogger(Utilities.class.getName());
24.122 +
24.123 + /** Operating system is Windows NT. */
24.124 + public static final int OS_WINNT = 1 << 0;
24.125 +
24.126 + /** Operating system is Windows 95. */
24.127 + public static final int OS_WIN95 = OS_WINNT << 1;
24.128 +
24.129 + /** Operating system is Windows 98. */
24.130 + public static final int OS_WIN98 = OS_WIN95 << 1;
24.131 +
24.132 + /** Operating system is Solaris. */
24.133 + public static final int OS_SOLARIS = OS_WIN98 << 1;
24.134 +
24.135 + /** Operating system is Linux. */
24.136 + public static final int OS_LINUX = OS_SOLARIS << 1;
24.137 +
24.138 + /** Operating system is HP-UX. */
24.139 + public static final int OS_HP = OS_LINUX << 1;
24.140 +
24.141 + /** Operating system is IBM AIX. */
24.142 + public static final int OS_AIX = OS_HP << 1;
24.143 +
24.144 + /** Operating system is SGI IRIX. */
24.145 + public static final int OS_IRIX = OS_AIX << 1;
24.146 +
24.147 + /** Operating system is Sun OS. */
24.148 + public static final int OS_SUNOS = OS_IRIX << 1;
24.149 +
24.150 + /** Operating system is Compaq TRU64 Unix */
24.151 + public static final int OS_TRU64 = OS_SUNOS << 1;
24.152 +
24.153 + /** @deprecated please use OS_TRU64 instead */
24.154 + @Deprecated
24.155 + public static final int OS_DEC = OS_TRU64 << 1;
24.156 +
24.157 + /** Operating system is OS/2. */
24.158 + public static final int OS_OS2 = OS_DEC << 1;
24.159 +
24.160 + /** Operating system is Mac. */
24.161 + public static final int OS_MAC = OS_OS2 << 1;
24.162 +
24.163 + /** Operating system is Windows 2000. */
24.164 + public static final int OS_WIN2000 = OS_MAC << 1;
24.165 +
24.166 + /** Operating system is Compaq OpenVMS */
24.167 + public static final int OS_VMS = OS_WIN2000 << 1;
24.168 +
24.169 + /**
24.170 + *Operating system is one of the Windows variants but we don't know which
24.171 + *one it is
24.172 + */
24.173 + public static final int OS_WIN_OTHER = OS_VMS << 1;
24.174 +
24.175 + /** Operating system is unknown. */
24.176 + public static final int OS_OTHER = OS_WIN_OTHER << 1;
24.177 +
24.178 + /** Operating system is FreeBSD
24.179 + * @since 4.50
24.180 + */
24.181 + public static final int OS_FREEBSD = OS_OTHER << 1;
24.182 +
24.183 + /** Operating system is Windows Vista.
24.184 + * @since 7.17
24.185 + */
24.186 + public static final int OS_WINVISTA = OS_FREEBSD << 1;
24.187 +
24.188 + /** Operating system is one of the Unix variants but we don't know which
24.189 + * one it is.
24.190 + * @since 7.18
24.191 + */
24.192 + public static final int OS_UNIX_OTHER = OS_WINVISTA << 1;
24.193 +
24.194 + /** Operating system is OpenBSD.
24.195 + * @since 7.18
24.196 + */
24.197 + public static final int OS_OPENBSD = OS_UNIX_OTHER << 1;
24.198 +
24.199 + /** A mask for Windows platforms.
24.200 + * @deprecated Use {@link #isWindows()} instead.
24.201 + */
24.202 + @Deprecated
24.203 + public static final int OS_WINDOWS_MASK = OS_WINNT | OS_WIN95 | OS_WIN98 | OS_WIN2000 | OS_WINVISTA | OS_WIN_OTHER;
24.204 +
24.205 + /** A mask for Unix platforms.
24.206 + * @deprecated Use {@link #isUnix()} instead.
24.207 + */
24.208 + @Deprecated
24.209 + public static final int OS_UNIX_MASK = OS_SOLARIS | OS_LINUX | OS_HP | OS_AIX | OS_IRIX | OS_SUNOS | OS_TRU64 |
24.210 + OS_MAC | OS_FREEBSD | OS_OPENBSD | OS_UNIX_OTHER;
24.211 +
24.212 + /** A height of the windows's taskbar */
24.213 + public static final int TYPICAL_WINDOWS_TASKBAR_HEIGHT = 27;
24.214 +
24.215 + /** A height of the Mac OS X's menu */
24.216 + private static final int TYPICAL_MACOSX_MENU_HEIGHT = 24;
24.217 +
24.218 + /** The operating system on which NetBeans runs*/
24.219 + private static int operatingSystem = -1;
24.220 + private static final String[] keywords = new String[] {
24.221 +
24.222 + //If adding to this, insert in alphabetical order!
24.223 + "abstract", "assert", "boolean", "break", "byte", "case", //NOI18N
24.224 + "catch", "char", "class", "const", "continue", "default", //NOI18N
24.225 + "do", "double", "else", "enum", "extends", "false", "final", //NOI18N
24.226 + "finally", "float", "for", "goto", "if", "implements", //NOI18N
24.227 + "import", "instanceof", "int", "interface", "long", //NOI18N
24.228 + "native", "new", "null", "package", "private", //NOI18N
24.229 + "protected", "public", "return", "short", "static", //NOI18N
24.230 + "strictfp", "super", "switch", "synchronized", "this", //NOI18N
24.231 + "throw", "throws", "transient", "true", "try", "void", //NOI18N
24.232 + "volatile", "while" //NOI18N
24.233 + };
24.234 + private static Timer clearIntrospector;
24.235 + private static ActionListener doClear;
24.236 + private static final int CTRL_WILDCARD_MASK = 32768;
24.237 + private static final int ALT_WILDCARD_MASK = CTRL_WILDCARD_MASK * 2;
24.238 +
24.239 + // Package retranslation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
24.240 + private static final String TRANS_LOCK = "TRANS_LOCK";
24.241 +
24.242 + /** last used classloader or if run in test mode the TRANS_LOCK */
24.243 + private static Object transLoader;
24.244 +
24.245 + /** regular expression to with all changes */
24.246 + private static RE transExp;
24.247 +
24.248 + //
24.249 + // Support for work with actions
24.250 + //
24.251 +
24.252 + /** the found actionsGlobalContext */
24.253 + private static Lookup global;
24.254 +
24.255 + private Utilities() {
24.256 + }
24.257 +
24.258 + /**
24.259 + * Useful queue for all parts of system that use <code>java.lang.ref.Reference</code>s
24.260 + * together with some <code>ReferenceQueue</code> and need to do some clean up
24.261 + * when the reference is enqueued. Usually, in order to be notified about that, one
24.262 + * needs to either create a dedicated thread that blocks on the queue and is
24.263 + * <code>Object.notify</code>-ed, which is the right approach but consumes
24.264 + * valuable system resources (threads) or one can periodically check the content
24.265 + * of the queue by <code>RequestProcessor.Task.schedule</code> which is
24.266 + * completely wrong, because it wakes up the system every (say) 15 seconds.
24.267 + * In order to provide useful support for this problem, this queue has been
24.268 + * provided.
24.269 + * <P>
24.270 + * If you have a reference that needs cleanup, make it implement <link>Runnable</link>
24.271 + * and register it with the queue:
24.272 + * <PRE>
24.273 + * class MyReference extends WeakReference<Thing> implements Runnable {
24.274 + * private final OtherInfo dataToCleanUp;
24.275 + * public MyReference(Thing ref, OtherInfo data) {
24.276 + * super(ref, Utilities.queue());
24.277 + * dataToCleanUp = data;
24.278 + * }
24.279 + * public void run() {
24.280 + * dataToCleanUp.releaseOrWhateverYouNeed();
24.281 + * }
24.282 + * }
24.283 + * </PRE>
24.284 + * When the <code>ref</code> object is garbage collected, your run method
24.285 + * will be invoked by calling
24.286 + * <code>((Runnable) reference).run()</code>
24.287 + * and you can perform whatever cleanup is necessary. Be sure not to block
24.288 + * in such cleanup for a long time as this prevents other waiting references
24.289 + * from cleaning themselves up.
24.290 + * <P>
24.291 + * Do not call any <code>ReferenceQueue</code> methods. They
24.292 + * will throw exceptions. You may only enqueue a reference.
24.293 + * <p>
24.294 + * Be sure to call this method anew for each reference.
24.295 + * Do not attempt to cache the return value.
24.296 + * @since 3.11
24.297 + */
24.298 + public static ReferenceQueue<Object> activeReferenceQueue() {
24.299 + return ActiveQueue.queue();
24.300 + }
24.301 +
24.302 + /** Get the operating system on which NetBeans is running.
24.303 + * @return one of the <code>OS_*</code> constants (such as {@link #OS_WINNT})
24.304 + */
24.305 + public static final int getOperatingSystem() {
24.306 + if (operatingSystem == -1) {
24.307 + String osName = System.getProperty("os.name");
24.308 +
24.309 + if ("Windows NT".equals(osName)) { // NOI18N
24.310 + operatingSystem = OS_WINNT;
24.311 + } else if ("Windows 95".equals(osName)) { // NOI18N
24.312 + operatingSystem = OS_WIN95;
24.313 + } else if ("Windows 98".equals(osName)) { // NOI18N
24.314 + operatingSystem = OS_WIN98;
24.315 + } else if ("Windows 2000".equals(osName)) { // NOI18N
24.316 + operatingSystem = OS_WIN2000;
24.317 + } else if ("Windows Vista".equals(osName)) { // NOI18N
24.318 + operatingSystem = OS_WINVISTA;
24.319 + } else if (osName.startsWith("Windows ")) { // NOI18N
24.320 + operatingSystem = OS_WIN_OTHER;
24.321 + } else if ("Solaris".equals(osName)) { // NOI18N
24.322 + operatingSystem = OS_SOLARIS;
24.323 + } else if (osName.startsWith("SunOS")) { // NOI18N
24.324 + operatingSystem = OS_SOLARIS;
24.325 + }
24.326 + // JDK 1.4 b2 defines os.name for me as "Redhat Linux" -jglick
24.327 + else if (osName.endsWith("Linux")) { // NOI18N
24.328 + operatingSystem = OS_LINUX;
24.329 + } else if ("HP-UX".equals(osName)) { // NOI18N
24.330 + operatingSystem = OS_HP;
24.331 + } else if ("AIX".equals(osName)) { // NOI18N
24.332 + operatingSystem = OS_AIX;
24.333 + } else if ("Irix".equals(osName)) { // NOI18N
24.334 + operatingSystem = OS_IRIX;
24.335 + } else if ("SunOS".equals(osName)) { // NOI18N
24.336 + operatingSystem = OS_SUNOS;
24.337 + } else if ("Digital UNIX".equals(osName)) { // NOI18N
24.338 + operatingSystem = OS_TRU64;
24.339 + } else if ("OS/2".equals(osName)) { // NOI18N
24.340 + operatingSystem = OS_OS2;
24.341 + } else if ("OpenVMS".equals(osName)) { // NOI18N
24.342 + operatingSystem = OS_VMS;
24.343 + } else if (osName.equals("Mac OS X")) { // NOI18N
24.344 + operatingSystem = OS_MAC;
24.345 + } else if (osName.startsWith("Darwin")) { // NOI18N
24.346 + operatingSystem = OS_MAC;
24.347 + } else if (osName.toLowerCase(Locale.US).startsWith("freebsd")) { // NOI18N
24.348 + operatingSystem = OS_FREEBSD;
24.349 + } else if ("OpenBSD".equals(osName)) { // NOI18N
24.350 + operatingSystem = OS_OPENBSD;
24.351 + } else if (File.pathSeparatorChar == ':') { // NOI18N
24.352 + operatingSystem = OS_UNIX_OTHER;
24.353 + } else {
24.354 + operatingSystem = OS_OTHER;
24.355 + }
24.356 + }
24.357 +
24.358 + return operatingSystem;
24.359 + }
24.360 +
24.361 + /** Test whether NetBeans is running on some variant of Windows.
24.362 + * @return <code>true</code> if Windows, <code>false</code> if some other manner of operating system
24.363 + */
24.364 + public static final boolean isWindows() {
24.365 + return (getOperatingSystem() & OS_WINDOWS_MASK) != 0;
24.366 + }
24.367 +
24.368 + /** Test whether NetBeans is running on MacOS.
24.369 + * @since 7.7
24.370 + * @return <code>true</code> if Mac, <code>false</code> if some other manner of operating system
24.371 + */
24.372 + public static final boolean isMac() {
24.373 + return (getOperatingSystem() & OS_MAC) != 0;
24.374 + }
24.375 +
24.376 + /** Test whether NetBeans is running on some variant of Unix.
24.377 + * Linux is included as well as the commercial vendors.
24.378 + * @return <code>true</code> some sort of Unix, <code>false</code> if some other manner of operating system
24.379 + */
24.380 + public static final boolean isUnix() {
24.381 + return (getOperatingSystem() & OS_UNIX_MASK) != 0;
24.382 + }
24.383 +
24.384 + // only for UtilitiesTest purposes
24.385 + final static void resetOperatingSystem() {
24.386 + operatingSystem = -1;
24.387 + }
24.388 +
24.389 + /** Test whether a given string is a valid Java identifier.
24.390 + * @param id string which should be checked
24.391 + * @return <code>true</code> if a valid identifier
24.392 + */
24.393 + public static final boolean isJavaIdentifier(String id) {
24.394 + if (id == null) {
24.395 + return false;
24.396 + }
24.397 +
24.398 + if (id.equals("")) {
24.399 + return false;
24.400 + }
24.401 +
24.402 + if (!(java.lang.Character.isJavaIdentifierStart(id.charAt(0)))) {
24.403 + return false;
24.404 + }
24.405 +
24.406 + for (int i = 1; i < id.length(); i++) {
24.407 + if (!(java.lang.Character.isJavaIdentifierPart(id.charAt(i)))) {
24.408 + return false;
24.409 + }
24.410 + }
24.411 +
24.412 + return Arrays.binarySearch(keywords, id) < 0;
24.413 + }
24.414 +
24.415 + /** Central method for obtaining <code>BeanInfo</code> for potential JavaBean classes.
24.416 + * @param clazz class of the bean to provide the <code>BeanInfo</code> for
24.417 + * @return the bean info
24.418 + * @throws java.beans.IntrospectionException for the usual reasons
24.419 + * @see java.beans.Introspector#getBeanInfo(Class)
24.420 + */
24.421 + public static java.beans.BeanInfo getBeanInfo(Class clazz)
24.422 + throws java.beans.IntrospectionException {
24.423 + java.beans.BeanInfo bi;
24.424 +
24.425 + try {
24.426 + bi = java.beans.Introspector.getBeanInfo(clazz);
24.427 + } catch (java.beans.IntrospectionException ie) {
24.428 + Exceptions.attachMessage(ie,
24.429 + "Encountered while introspecting " +
24.430 + clazz.getName()); // NOI18N
24.431 + throw ie;
24.432 + } catch (Error e) {
24.433 + // Could be a bug in Introspector triggered by NB code.
24.434 + Exceptions.attachMessage(e,
24.435 + "Encountered while introspecting " +
24.436 + clazz.getName()); // NOI18N
24.437 + throw e;
24.438 + }
24.439 +
24.440 + if (java.awt.Component.class.isAssignableFrom(clazz)) {
24.441 + java.beans.PropertyDescriptor[] pds = bi.getPropertyDescriptors();
24.442 +
24.443 + for (int i = 0; i < pds.length; i++) {
24.444 + if (pds[i].getName().equals("cursor")) { // NOI18N
24.445 +
24.446 + try {
24.447 + Method getter = Component.class.getDeclaredMethod("getCursor", new Class[0]); // NOI18N
24.448 + Method setter = Component.class.getDeclaredMethod("setCursor", new Class[] { Cursor.class }); // NOI18N
24.449 + pds[i] = new java.beans.PropertyDescriptor("cursor", getter, setter); // NOI18N
24.450 + } catch (NoSuchMethodException e) {
24.451 + e.printStackTrace();
24.452 + }
24.453 +
24.454 + break;
24.455 + }
24.456 + }
24.457 + }
24.458 +
24.459 + // clears about 1000 instances of Method
24.460 + if (bi != null) {
24.461 + if (clearIntrospector == null) {
24.462 + doClear = new ActionListener() {
24.463 + public void actionPerformed(ActionEvent ev) {
24.464 + java.beans.Introspector.flushCaches();
24.465 + }
24.466 + };
24.467 + clearIntrospector = new Timer(15000, doClear);
24.468 + clearIntrospector.setRepeats(false);
24.469 + }
24.470 +
24.471 + clearIntrospector.restart();
24.472 + }
24.473 +
24.474 + return bi;
24.475 + }
24.476 +
24.477 + /** Central method for obtaining <code>BeanInfo</code> for potential JavaBean classes, with a stop class.
24.478 + * @param clazz class of the bean to provide the <code>BeanInfo</code> for
24.479 + * @param stopClass the stop class
24.480 + * @return the bean info
24.481 + * @throws java.beans.IntrospectionException for the usual reasons
24.482 + * @see java.beans.Introspector#getBeanInfo(Class, Class)
24.483 + */
24.484 + public static java.beans.BeanInfo getBeanInfo(Class clazz, Class stopClass)
24.485 + throws java.beans.IntrospectionException {
24.486 + return java.beans.Introspector.getBeanInfo(clazz, stopClass);
24.487 + }
24.488 +
24.489 + /** Wrap multi-line strings (and get the individual lines).
24.490 + * @param original the original string to wrap
24.491 + * @param width the maximum width of lines
24.492 + * @param wrapWords if <code>true</code>, the lines are wrapped on word boundaries (if possible);
24.493 + * if <code>false</code>, character boundaries are used
24.494 + * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored
24.495 + * @return the lines after wrapping
24.496 + * @deprecated use {@link #wrapStringToArray(String, int, BreakIterator, boolean)} since it is better for I18N
24.497 + */
24.498 + @Deprecated
24.499 + public static String[] wrapStringToArray(String original, int width, boolean wrapWords, boolean removeNewLines) {
24.500 + BreakIterator bi = (wrapWords ? BreakIterator.getWordInstance() : BreakIterator.getCharacterInstance());
24.501 +
24.502 + return wrapStringToArray(original, width, bi, removeNewLines);
24.503 + }
24.504 +
24.505 + /** Wrap multi-line strings (and get the individual lines).
24.506 + * @param original the original string to wrap
24.507 + * @param width the maximum width of lines
24.508 + * @param breakIterator breaks original to chars, words, sentences, depending on what instance you provide.
24.509 + * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored
24.510 + * @return the lines after wrapping
24.511 + */
24.512 + public static String[] wrapStringToArray(
24.513 + String original, int width, BreakIterator breakIterator, boolean removeNewLines
24.514 + ) {
24.515 + if (original.length() == 0) {
24.516 + return new String[] { original };
24.517 + }
24.518 +
24.519 + String[] workingSet;
24.520 +
24.521 + // substitute original newlines with spaces,
24.522 + // remove newlines from head and tail
24.523 + if (removeNewLines) {
24.524 + original = trimString(original);
24.525 + original = original.replace('\n', ' ');
24.526 + workingSet = new String[] { original };
24.527 + } else {
24.528 + StringTokenizer tokens = new StringTokenizer(original, "\n"); // NOI18N
24.529 + int len = tokens.countTokens();
24.530 + workingSet = new String[len];
24.531 +
24.532 + for (int i = 0; i < len; i++) {
24.533 + workingSet[i] = tokens.nextToken();
24.534 + }
24.535 + }
24.536 +
24.537 + if (width < 1) {
24.538 + width = 1;
24.539 + }
24.540 +
24.541 + if (original.length() <= width) {
24.542 + return workingSet;
24.543 + }
24.544 +
24.545 +widthcheck: {
24.546 + boolean ok = true;
24.547 +
24.548 + for (int i = 0; i < workingSet.length; i++) {
24.549 + ok = ok && (workingSet[i].length() < width);
24.550 +
24.551 + if (!ok) {
24.552 + break widthcheck;
24.553 + }
24.554 + }
24.555 +
24.556 + return workingSet;
24.557 + }
24.558 +
24.559 + java.util.ArrayList<String> lines = new java.util.ArrayList<String>();
24.560 +
24.561 + int lineStart = 0; // the position of start of currently processed line in the original string
24.562 +
24.563 + for (int i = 0; i < workingSet.length; i++) {
24.564 + if (workingSet[i].length() < width) {
24.565 + lines.add(workingSet[i]);
24.566 + } else {
24.567 + breakIterator.setText(workingSet[i]);
24.568 +
24.569 + int nextStart = breakIterator.next();
24.570 + int prevStart = 0;
24.571 +
24.572 + do {
24.573 + while (((nextStart - lineStart) < width) && (nextStart != BreakIterator.DONE)) {
24.574 + prevStart = nextStart;
24.575 + nextStart = breakIterator.next();
24.576 + }
24.577 +
24.578 + if (nextStart == BreakIterator.DONE) {
24.579 + nextStart = prevStart = workingSet[i].length();
24.580 + }
24.581 +
24.582 + if (prevStart == 0) {
24.583 + prevStart = nextStart;
24.584 + }
24.585 +
24.586 + lines.add(workingSet[i].substring(lineStart, prevStart));
24.587 +
24.588 + lineStart = prevStart;
24.589 + prevStart = 0;
24.590 + } while (lineStart < workingSet[i].length());
24.591 +
24.592 + lineStart = 0;
24.593 + }
24.594 + }
24.595 +
24.596 + String[] s = new String[lines.size()];
24.597 +
24.598 + return lines.toArray(s);
24.599 + }
24.600 +
24.601 + /** trims String
24.602 + * @param s a String to trim
24.603 + * @return trimmed String
24.604 + */
24.605 + private static String trimString(String s) {
24.606 + int idx = 0;
24.607 + char c;
24.608 + final int slen = s.length();
24.609 +
24.610 + if (slen == 0) {
24.611 + return s;
24.612 + }
24.613 +
24.614 + do {
24.615 + c = s.charAt(idx++);
24.616 + } while (((c == '\n') || (c == '\r')) && (idx < slen));
24.617 +
24.618 + s = s.substring(--idx);
24.619 + idx = s.length() - 1;
24.620 +
24.621 + if (idx < 0) {
24.622 + return s;
24.623 + }
24.624 +
24.625 + do {
24.626 + c = s.charAt(idx--);
24.627 + } while (((c == '\n') || (c == '\r')) && (idx >= 0));
24.628 +
24.629 + return s.substring(0, idx + 2);
24.630 + }
24.631 +
24.632 + /** Wrap multi-line strings.
24.633 + * @param original the original string to wrap
24.634 + * @param width the maximum width of lines
24.635 + * @param breakIterator algorithm for breaking lines
24.636 + * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored
24.637 + * @return the whole string with embedded newlines
24.638 + */
24.639 + public static String wrapString(String original, int width, BreakIterator breakIterator, boolean removeNewLines) {
24.640 + String[] sarray = wrapStringToArray(original, width, breakIterator, removeNewLines);
24.641 + StringBuffer retBuf = new StringBuffer();
24.642 +
24.643 + for (int i = 0; i < sarray.length; i++) {
24.644 + retBuf.append(sarray[i]);
24.645 + retBuf.append('\n');
24.646 + }
24.647 +
24.648 + return retBuf.toString();
24.649 + }
24.650 +
24.651 + /** Wrap multi-line strings.
24.652 + * @param original the original string to wrap
24.653 + * @param width the maximum width of lines
24.654 + * @param wrapWords if <code>true</code>, the lines are wrapped on word boundaries (if possible);
24.655 + * if <code>false</code>, character boundaries are used
24.656 + * @param removeNewLines if <code>true</code>, any newlines in the original string are ignored
24.657 + * @return the whole string with embedded newlines
24.658 + * @deprecated Use {@link #wrapString (String, int, BreakIterator, boolean)} as it is friendlier to I18N.
24.659 + */
24.660 + @Deprecated
24.661 + public static String wrapString(String original, int width, boolean wrapWords, boolean removeNewLines) {
24.662 + // substitute original newlines with spaces,
24.663 + // remove newlines from head and tail
24.664 + if (removeNewLines) {
24.665 + while (original.startsWith("\n")) // NOI18N
24.666 +
24.667 + original = original.substring(1);
24.668 +
24.669 + while (original.endsWith("\n")) // NOI18N
24.670 +
24.671 + original = original.substring(0, original.length() - 1);
24.672 +
24.673 + original = original.replace('\n', ' ');
24.674 + }
24.675 +
24.676 + if (width < 1) {
24.677 + width = 1;
24.678 + }
24.679 +
24.680 + if (original.length() <= width) {
24.681 + return original;
24.682 + }
24.683 +
24.684 + java.util.Vector<String> lines = new java.util.Vector<String>();
24.685 + int lineStart = 0; // the position of start of currently processed line in the original string
24.686 + int lastSpacePos = -1;
24.687 +
24.688 + for (int i = 0; i < original.length(); i++) {
24.689 + if (lineStart >= (original.length() - 1)) {
24.690 + break;
24.691 + }
24.692 +
24.693 + // newline in the original string
24.694 + if (original.charAt(i) == '\n') {
24.695 + lines.addElement(original.substring(lineStart, i));
24.696 + lineStart = i + 1;
24.697 + lastSpacePos = -1;
24.698 +
24.699 + continue;
24.700 + }
24.701 +
24.702 + // remember last space position
24.703 + if (Character.isSpaceChar(original.charAt(i))) {
24.704 + lastSpacePos = i;
24.705 + }
24.706 +
24.707 + // last position in the original string
24.708 + if (i == (original.length() - 1)) {
24.709 + lines.addElement(original.substring(lineStart));
24.710 +
24.711 + break;
24.712 + }
24.713 +
24.714 + // reached width
24.715 + if ((i - lineStart) == width) {
24.716 + if (wrapWords && (lastSpacePos != -1)) {
24.717 + lines.addElement(original.substring(lineStart, lastSpacePos));
24.718 + lineStart = lastSpacePos + 1; // the space is consumed for the newline
24.719 + lastSpacePos = -1;
24.720 + } else {
24.721 + lines.addElement(original.substring(lineStart, i));
24.722 + lineStart = i;
24.723 + lastSpacePos = -1;
24.724 + }
24.725 + }
24.726 + }
24.727 +
24.728 + StringBuffer retBuf = new StringBuffer();
24.729 +
24.730 + for (java.util.Enumeration e = lines.elements(); e.hasMoreElements();) {
24.731 + retBuf.append((String) e.nextElement());
24.732 + retBuf.append('\n');
24.733 + }
24.734 +
24.735 + return retBuf.toString();
24.736 + }
24.737 +
24.738 + /** Search-and-replace fixed string matches within a string.
24.739 + * @param original the original string
24.740 + * @param replaceFrom the substring to be find
24.741 + * @param replaceTo the substring to replace it with
24.742 + * @return a new string with all occurrences replaced
24.743 + * @deprecated Use {@link String#replace(CharSequence,CharSequence)} instead
24.744 + */
24.745 + @Deprecated
24.746 + public static String replaceString(String original, String replaceFrom, String replaceTo) {
24.747 + int index = 0;
24.748 +
24.749 + if ("".equals(replaceFrom)) {
24.750 + return original; // NOI18N
24.751 + }
24.752 +
24.753 + StringBuffer buf = new StringBuffer();
24.754 +
24.755 + while (true) {
24.756 + int pos = original.indexOf(replaceFrom, index);
24.757 +
24.758 + if (pos == -1) {
24.759 + buf.append(original.substring(index));
24.760 +
24.761 + return buf.toString();
24.762 + }
24.763 +
24.764 + buf.append(original.substring(index, pos));
24.765 + buf.append(replaceTo);
24.766 + index = pos + replaceFrom.length();
24.767 +
24.768 + if (index == original.length()) {
24.769 + return buf.toString();
24.770 + }
24.771 + }
24.772 + }
24.773 +
24.774 + /** Turn full name of an inner class into its pure form.
24.775 + * @param fullName e.g. <code>some.pkg.SomeClass$Inner</code>
24.776 + * @return e.g. <code>Inner</code>
24.777 + */
24.778 + public static final String pureClassName(final String fullName) {
24.779 + final int index = fullName.indexOf('$');
24.780 +
24.781 + if ((index >= 0) && (index < fullName.length())) {
24.782 + return fullName.substring(index + 1, fullName.length());
24.783 + }
24.784 +
24.785 + return fullName;
24.786 + }
24.787 +
24.788 + /** Test whether the operating system supports icons on frames (windows).
24.789 + * @return <code>true</code> if it does <em>not</em>
24.790 + * @deprecated Obsolete, useless method, no replacement.
24.791 + */
24.792 + @Deprecated public static final boolean isLargeFrameIcons() {
24.793 + return (getOperatingSystem() == OS_SOLARIS) || (getOperatingSystem() == OS_HP);
24.794 + }
24.795 +
24.796 + /** Compute hash code of array.
24.797 + * Asks all elements for their own code and composes the
24.798 + * values.
24.799 + * @param arr array of objects, can contain <code>null</code>s
24.800 + * @return the hash code
24.801 + * @see Object#hashCode
24.802 + */
24.803 + public static int arrayHashCode(Object[] arr) {
24.804 + int c = 0;
24.805 + int len = arr.length;
24.806 +
24.807 + for (int i = 0; i < len; i++) {
24.808 + Object o = arr[i];
24.809 + int v = (o == null) ? 1 : o.hashCode();
24.810 + c += (v ^ i);
24.811 + }
24.812 +
24.813 + return c;
24.814 + }
24.815 +
24.816 + /** Safe equality check.
24.817 + * The supplied objects are equal if: <UL>
24.818 + * <LI> both are <code>null</code>
24.819 + * <LI> both are arrays with same length and equal items (if the items are arrays,
24.820 + * they are <em>not</em> checked the same way again)
24.821 + * <LI> the two objects are {@link Object#equals}
24.822 + * </UL>
24.823 + * This method is <code>null</code>-safe, so if one of the parameters is true and the second not,
24.824 + * it returns <code>false</code>.
24.825 + * @param o1 the first object to compare
24.826 + * @param o2 the second object to compare
24.827 + * @return <code>true</code> if the objects are equal
24.828 + */
24.829 + public static boolean compareObjects(Object o1, Object o2) {
24.830 + return compareObjectsImpl(o1, o2, 1);
24.831 + }
24.832 +
24.833 + /** Safe equality check with array recursion.
24.834 + * @param o1 the first object to compare
24.835 + * @param o2 the second object to compare
24.836 + * @param checkArraysDepth the depth to which arrays should be compared for equality (negative for infinite depth, zero for no comparison of elements, one for shallow, etc.)
24.837 + * @return <code>true</code> if the objects are equal
24.838 + * @see #compareObjects(Object, Object)
24.839 + */
24.840 + public static boolean compareObjectsImpl(Object o1, Object o2, int checkArraysDepth) {
24.841 + // handle null values
24.842 + if (o1 == null) {
24.843 + return (o2 == null);
24.844 + } else if (o2 == null) {
24.845 + return false;
24.846 + }
24.847 +
24.848 + // handle arrays
24.849 + if (checkArraysDepth > 0) {
24.850 + if ((o1 instanceof Object[]) && (o2 instanceof Object[])) {
24.851 + // Note: also handles multidimensional arrays of primitive types correctly.
24.852 + // I.e. new int[0][] instanceof Object[]
24.853 + Object[] o1a = (Object[]) o1;
24.854 + Object[] o2a = (Object[]) o2;
24.855 + int l1 = o1a.length;
24.856 + int l2 = o2a.length;
24.857 +
24.858 + if (l1 != l2) {
24.859 + return false;
24.860 + }
24.861 +
24.862 + for (int i = 0; i < l1; i++) {
24.863 + if (!compareObjectsImpl(o1a[i], o2a[i], checkArraysDepth - 1)) {
24.864 + return false;
24.865 + }
24.866 + }
24.867 +
24.868 + return true;
24.869 + } else if ((o1 instanceof byte[]) && (o2 instanceof byte[])) {
24.870 + byte[] o1a = (byte[]) o1;
24.871 + byte[] o2a = (byte[]) o2;
24.872 + int l1 = o1a.length;
24.873 + int l2 = o2a.length;
24.874 +
24.875 + if (l1 != l2) {
24.876 + return false;
24.877 + }
24.878 +
24.879 + for (int i = 0; i < l1; i++)
24.880 + if (o1a[i] != o2a[i]) {
24.881 + return false;
24.882 + }
24.883 +
24.884 + return true;
24.885 + } else if ((o1 instanceof short[]) && (o2 instanceof short[])) {
24.886 + short[] o1a = (short[]) o1;
24.887 + short[] o2a = (short[]) o2;
24.888 + int l1 = o1a.length;
24.889 + int l2 = o2a.length;
24.890 +
24.891 + if (l1 != l2) {
24.892 + return false;
24.893 + }
24.894 +
24.895 + for (int i = 0; i < l1; i++)
24.896 + if (o1a[i] != o2a[i]) {
24.897 + return false;
24.898 + }
24.899 +
24.900 + return true;
24.901 + } else if ((o1 instanceof int[]) && (o2 instanceof int[])) {
24.902 + int[] o1a = (int[]) o1;
24.903 + int[] o2a = (int[]) o2;
24.904 + int l1 = o1a.length;
24.905 + int l2 = o2a.length;
24.906 +
24.907 + if (l1 != l2) {
24.908 + return false;
24.909 + }
24.910 +
24.911 + for (int i = 0; i < l1; i++)
24.912 + if (o1a[i] != o2a[i]) {
24.913 + return false;
24.914 + }
24.915 +
24.916 + return true;
24.917 + } else if ((o1 instanceof long[]) && (o2 instanceof long[])) {
24.918 + long[] o1a = (long[]) o1;
24.919 + long[] o2a = (long[]) o2;
24.920 + int l1 = o1a.length;
24.921 + int l2 = o2a.length;
24.922 +
24.923 + if (l1 != l2) {
24.924 + return false;
24.925 + }
24.926 +
24.927 + for (int i = 0; i < l1; i++)
24.928 + if (o1a[i] != o2a[i]) {
24.929 + return false;
24.930 + }
24.931 +
24.932 + return true;
24.933 + } else if ((o1 instanceof float[]) && (o2 instanceof float[])) {
24.934 + float[] o1a = (float[]) o1;
24.935 + float[] o2a = (float[]) o2;
24.936 + int l1 = o1a.length;
24.937 + int l2 = o2a.length;
24.938 +
24.939 + if (l1 != l2) {
24.940 + return false;
24.941 + }
24.942 +
24.943 + for (int i = 0; i < l1; i++)
24.944 + if (o1a[i] != o2a[i]) {
24.945 + return false;
24.946 + }
24.947 +
24.948 + return true;
24.949 + } else if ((o1 instanceof double[]) && (o2 instanceof double[])) {
24.950 + double[] o1a = (double[]) o1;
24.951 + double[] o2a = (double[]) o2;
24.952 + int l1 = o1a.length;
24.953 + int l2 = o2a.length;
24.954 +
24.955 + if (l1 != l2) {
24.956 + return false;
24.957 + }
24.958 +
24.959 + for (int i = 0; i < l1; i++)
24.960 + if (o1a[i] != o2a[i]) {
24.961 + return false;
24.962 + }
24.963 +
24.964 + return true;
24.965 + } else if ((o1 instanceof char[]) && (o2 instanceof char[])) {
24.966 + char[] o1a = (char[]) o1;
24.967 + char[] o2a = (char[]) o2;
24.968 + int l1 = o1a.length;
24.969 + int l2 = o2a.length;
24.970 +
24.971 + if (l1 != l2) {
24.972 + return false;
24.973 + }
24.974 +
24.975 + for (int i = 0; i < l1; i++)
24.976 + if (o1a[i] != o2a[i]) {
24.977 + return false;
24.978 + }
24.979 +
24.980 + return true;
24.981 + } else if ((o1 instanceof boolean[]) && (o2 instanceof boolean[])) {
24.982 + boolean[] o1a = (boolean[]) o1;
24.983 + boolean[] o2a = (boolean[]) o2;
24.984 + int l1 = o1a.length;
24.985 + int l2 = o2a.length;
24.986 +
24.987 + if (l1 != l2) {
24.988 + return false;
24.989 + }
24.990 +
24.991 + for (int i = 0; i < l1; i++)
24.992 + if (o1a[i] != o2a[i]) {
24.993 + return false;
24.994 + }
24.995 +
24.996 + return true;
24.997 + }
24.998 +
24.999 + // else not array type
24.1000 + }
24.1001 +
24.1002 + // handle common objects--non-arrays, or arrays when depth == 0
24.1003 + return o1.equals(o2);
24.1004 + }
24.1005 +
24.1006 + /** Assemble a human-presentable class name for a specified class.
24.1007 + * Arrays are represented as e.g. <code>java.lang.String[]</code>.
24.1008 + * @param clazz the class to name
24.1009 + * @return the human-presentable name
24.1010 + */
24.1011 + public static String getClassName(Class clazz) {
24.1012 + // if it is an array, get short name of element type and append []
24.1013 + if (clazz.isArray()) {
24.1014 + return getClassName(clazz.getComponentType()) + "[]"; // NOI18N
24.1015 + } else {
24.1016 + return clazz.getName();
24.1017 + }
24.1018 + }
24.1019 +
24.1020 + /** Assemble a human-presentable class name for a specified class (omitting the package).
24.1021 + * Arrays are represented as e.g. <code>String[]</code>.
24.1022 + * @param clazz the class to name
24.1023 + * @return the human-presentable name
24.1024 + */
24.1025 + public static String getShortClassName(Class clazz) {
24.1026 + // if it is an array, get short name of element type and append []
24.1027 + if (clazz.isArray()) {
24.1028 + return getShortClassName(clazz.getComponentType()) + "[]"; // NOI18N
24.1029 + }
24.1030 +
24.1031 + String name = clazz.getName().replace('$', '.');
24.1032 +
24.1033 + return name.substring(name.lastIndexOf(".") + 1, name.length()); // NOI18N
24.1034 + }
24.1035 +
24.1036 + /**
24.1037 + * Convert an array of objects to an array of primitive types.
24.1038 + * E.g. an <code>Integer[]</code> would be changed to an <code>int[]</code>.
24.1039 + * @param array the wrapper array
24.1040 + * @return a primitive array
24.1041 + * @throws IllegalArgumentException if the array element type is not a primitive wrapper
24.1042 + */
24.1043 + public static Object toPrimitiveArray(Object[] array) {
24.1044 + if (array instanceof Integer[]) {
24.1045 + int[] r = new int[array.length];
24.1046 + int i;
24.1047 + int k = array.length;
24.1048 +
24.1049 + for (i = 0; i < k; i++)
24.1050 + r[i] = (((Integer) array[i]) == null) ? 0 : ((Integer) array[i]).intValue();
24.1051 +
24.1052 + return r;
24.1053 + }
24.1054 +
24.1055 + if (array instanceof Boolean[]) {
24.1056 + boolean[] r = new boolean[array.length];
24.1057 + int i;
24.1058 + int k = array.length;
24.1059 +
24.1060 + for (i = 0; i < k; i++)
24.1061 + r[i] = (((Boolean) array[i]) == null) ? false : ((Boolean) array[i]).booleanValue();
24.1062 +
24.1063 + return r;
24.1064 + }
24.1065 +
24.1066 + if (array instanceof Byte[]) {
24.1067 + byte[] r = new byte[array.length];
24.1068 + int i;
24.1069 + int k = array.length;
24.1070 +
24.1071 + for (i = 0; i < k; i++)
24.1072 + r[i] = (((Byte) array[i]) == null) ? 0 : ((Byte) array[i]).byteValue();
24.1073 +
24.1074 + return r;
24.1075 + }
24.1076 +
24.1077 + if (array instanceof Character[]) {
24.1078 + char[] r = new char[array.length];
24.1079 + int i;
24.1080 + int k = array.length;
24.1081 +
24.1082 + for (i = 0; i < k; i++)
24.1083 + r[i] = (((Character) array[i]) == null) ? 0 : ((Character) array[i]).charValue();
24.1084 +
24.1085 + return r;
24.1086 + }
24.1087 +
24.1088 + if (array instanceof Double[]) {
24.1089 + double[] r = new double[array.length];
24.1090 + int i;
24.1091 + int k = array.length;
24.1092 +
24.1093 + for (i = 0; i < k; i++)
24.1094 + r[i] = (((Double) array[i]) == null) ? 0 : ((Double) array[i]).doubleValue();
24.1095 +
24.1096 + return r;
24.1097 + }
24.1098 +
24.1099 + if (array instanceof Float[]) {
24.1100 + float[] r = new float[array.length];
24.1101 + int i;
24.1102 + int k = array.length;
24.1103 +
24.1104 + for (i = 0; i < k; i++)
24.1105 + r[i] = (((Float) array[i]) == null) ? 0 : ((Float) array[i]).floatValue();
24.1106 +
24.1107 + return r;
24.1108 + }
24.1109 +
24.1110 + if (array instanceof Long[]) {
24.1111 + long[] r = new long[array.length];
24.1112 + int i;
24.1113 + int k = array.length;
24.1114 +
24.1115 + for (i = 0; i < k; i++)
24.1116 + r[i] = (((Long) array[i]) == null) ? 0 : ((Long) array[i]).longValue();
24.1117 +
24.1118 + return r;
24.1119 + }
24.1120 +
24.1121 + if (array instanceof Short[]) {
24.1122 + short[] r = new short[array.length];
24.1123 + int i;
24.1124 + int k = array.length;
24.1125 +
24.1126 + for (i = 0; i < k; i++)
24.1127 + r[i] = (((Short) array[i]) == null) ? 0 : ((Short) array[i]).shortValue();
24.1128 +
24.1129 + return r;
24.1130 + }
24.1131 +
24.1132 + throw new IllegalArgumentException();
24.1133 + }
24.1134 +
24.1135 + /**
24.1136 + * Convert an array of primitive types to an array of objects.
24.1137 + * E.g. an <code>int[]</code> would be turned into an <code>Integer[]</code>.
24.1138 + * @param array the primitive array
24.1139 + * @return a wrapper array
24.1140 + * @throws IllegalArgumentException if the array element type is not primitive
24.1141 + */
24.1142 + public static Object[] toObjectArray(Object array) {
24.1143 + if (array instanceof Object[]) {
24.1144 + return (Object[]) array;
24.1145 + }
24.1146 +
24.1147 + if (array instanceof int[]) {
24.1148 + int i;
24.1149 + int k = ((int[]) array).length;
24.1150 + Integer[] r = new Integer[k];
24.1151 +
24.1152 + for (i = 0; i < k; i++)
24.1153 + r[i] = new Integer(((int[]) array)[i]);
24.1154 +
24.1155 + return r;
24.1156 + }
24.1157 +
24.1158 + if (array instanceof boolean[]) {
24.1159 + int i;
24.1160 + int k = ((boolean[]) array).length;
24.1161 + Boolean[] r = new Boolean[k];
24.1162 +
24.1163 + for (i = 0; i < k; i++)
24.1164 + r[i] = ((boolean[]) array)[i] ? Boolean.TRUE : Boolean.FALSE;
24.1165 +
24.1166 + return r;
24.1167 + }
24.1168 +
24.1169 + if (array instanceof byte[]) {
24.1170 + int i;
24.1171 + int k = ((byte[]) array).length;
24.1172 + Byte[] r = new Byte[k];
24.1173 +
24.1174 + for (i = 0; i < k; i++)
24.1175 + r[i] = new Byte(((byte[]) array)[i]);
24.1176 +
24.1177 + return r;
24.1178 + }
24.1179 +
24.1180 + if (array instanceof char[]) {
24.1181 + int i;
24.1182 + int k = ((char[]) array).length;
24.1183 + Character[] r = new Character[k];
24.1184 +
24.1185 + for (i = 0; i < k; i++)
24.1186 + r[i] = new Character(((char[]) array)[i]);
24.1187 +
24.1188 + return r;
24.1189 + }
24.1190 +
24.1191 + if (array instanceof double[]) {
24.1192 + int i;
24.1193 + int k = ((double[]) array).length;
24.1194 + Double[] r = new Double[k];
24.1195 +
24.1196 + for (i = 0; i < k; i++)
24.1197 + r[i] = new Double(((double[]) array)[i]);
24.1198 +
24.1199 + return r;
24.1200 + }
24.1201 +
24.1202 + if (array instanceof float[]) {
24.1203 + int i;
24.1204 + int k = ((float[]) array).length;
24.1205 + Float[] r = new Float[k];
24.1206 +
24.1207 + for (i = 0; i < k; i++)
24.1208 + r[i] = new Float(((float[]) array)[i]);
24.1209 +
24.1210 + return r;
24.1211 + }
24.1212 +
24.1213 + if (array instanceof long[]) {
24.1214 + int i;
24.1215 + int k = ((long[]) array).length;
24.1216 + Long[] r = new Long[k];
24.1217 +
24.1218 + for (i = 0; i < k; i++)
24.1219 + r[i] = new Long(((long[]) array)[i]);
24.1220 +
24.1221 + return r;
24.1222 + }
24.1223 +
24.1224 + if (array instanceof short[]) {
24.1225 + int i;
24.1226 + int k = ((short[]) array).length;
24.1227 + Short[] r = new Short[k];
24.1228 +
24.1229 + for (i = 0; i < k; i++)
24.1230 + r[i] = new Short(((short[]) array)[i]);
24.1231 +
24.1232 + return r;
24.1233 + }
24.1234 +
24.1235 + throw new IllegalArgumentException();
24.1236 + }
24.1237 +
24.1238 + /**
24.1239 + * Get the object type for given primitive type.
24.1240 + *
24.1241 + * @param c primitive type (e.g. <code>int</code>)
24.1242 + * @return object type (e.g. <code>Integer</code>)
24.1243 + */
24.1244 + public static Class getObjectType(Class c) {
24.1245 + if (!c.isPrimitive()) {
24.1246 + return c;
24.1247 + }
24.1248 +
24.1249 + if (c == Integer.TYPE) {
24.1250 + return Integer.class;
24.1251 + }
24.1252 +
24.1253 + if (c == Boolean.TYPE) {
24.1254 + return Boolean.class;
24.1255 + }
24.1256 +
24.1257 + if (c == Byte.TYPE) {
24.1258 + return Byte.class;
24.1259 + }
24.1260 +
24.1261 + if (c == Character.TYPE) {
24.1262 + return Character.class;
24.1263 + }
24.1264 +
24.1265 + if (c == Double.TYPE) {
24.1266 + return Double.class;
24.1267 + }
24.1268 +
24.1269 + if (c == Float.TYPE) {
24.1270 + return Float.class;
24.1271 + }
24.1272 +
24.1273 + if (c == Long.TYPE) {
24.1274 + return Long.class;
24.1275 + }
24.1276 +
24.1277 + if (c == Short.TYPE) {
24.1278 + return Short.class;
24.1279 + }
24.1280 +
24.1281 + throw new IllegalArgumentException();
24.1282 + }
24.1283 +
24.1284 + /**
24.1285 + * Get the primitive type for given object type.
24.1286 + *
24.1287 + * @param c object type (e.g. <code>Integer</code>)
24.1288 + * @return primitive type (e.g. <code>int</code>)
24.1289 + */
24.1290 + public static Class getPrimitiveType(Class c) {
24.1291 + if (!c.isPrimitive()) {
24.1292 + return c;
24.1293 + }
24.1294 +
24.1295 + if (c == Integer.class) {
24.1296 + return Integer.TYPE;
24.1297 + }
24.1298 +
24.1299 + if (c == Boolean.class) {
24.1300 + return Boolean.TYPE;
24.1301 + }
24.1302 +
24.1303 + if (c == Byte.class) {
24.1304 + return Byte.TYPE;
24.1305 + }
24.1306 +
24.1307 + if (c == Character.class) {
24.1308 + return Character.TYPE;
24.1309 + }
24.1310 +
24.1311 + if (c == Double.class) {
24.1312 + return Double.TYPE;
24.1313 + }
24.1314 +
24.1315 + if (c == Float.class) {
24.1316 + return Float.TYPE;
24.1317 + }
24.1318 +
24.1319 + if (c == Long.class) {
24.1320 + return Long.TYPE;
24.1321 + }
24.1322 +
24.1323 + if (c == Short.class) {
24.1324 + return Short.TYPE;
24.1325 + }
24.1326 +
24.1327 + throw new IllegalArgumentException();
24.1328 + }
24.1329 +
24.1330 + /** Find a focus-traverable component.
24.1331 + * @param c the component to look in
24.1332 + * @return the same component if traversable, else a child component if present, else <code>null</code>
24.1333 + * @see Component#isFocusTraversable
24.1334 + */
24.1335 + public static Component getFocusTraversableComponent(Component c) {
24.1336 + if (c.isFocusable()) {
24.1337 + return c;
24.1338 + }
24.1339 +
24.1340 + if (!(c instanceof Container)) {
24.1341 + return null;
24.1342 + }
24.1343 +
24.1344 + int i;
24.1345 + int k = ((Container) c).getComponentCount();
24.1346 +
24.1347 + for (i = 0; i < k; i++) {
24.1348 + Component v = ((Container) c).getComponent(i);
24.1349 +
24.1350 + if (v != null) {
24.1351 + return v;
24.1352 + }
24.1353 + }
24.1354 +
24.1355 + return null;
24.1356 + }
24.1357 +
24.1358 + /** Parses parameters from a given string in shell-like manner.
24.1359 + * Users of the Bourne shell (e.g. on Unix) will already be familiar with the behavior.
24.1360 + * For example, when using <code>org.openide.execution.NbProcessDescriptor</code> (Execution API)
24.1361 + * you should be able to:
24.1362 + * <ul>
24.1363 + * <li>Include command names with embedded spaces, such as <code>c:\Program Files\jdk\bin\javac</code>.
24.1364 + * <li>Include extra command arguments, such as <code>-Dname=value</code>.
24.1365 + * <li>Do anything else which might require unusual characters or processing. For example:
24.1366 + * <p><code><pre>
24.1367 + * "c:\program files\jdk\bin\java" -Dmessage="Hello /\\/\\ there!" -Xmx128m
24.1368 + * </pre></code>
24.1369 + * <p>This example would create the following executable name and arguments:
24.1370 + * <ol>
24.1371 + * <li> <code>c:\program files\jdk\bin\java</code>
24.1372 + * <li> <code>-Dmessage=Hello /\/\ there!</code>
24.1373 + * <li> <code>-Xmx128m</code>
24.1374 + * </ol>
24.1375 + * Note that the command string does not escape its backslashes--under the assumption
24.1376 + * that Windows users will not think to do this, meaningless escapes are just left
24.1377 + * as backslashes plus following character.
24.1378 + * </ul>
24.1379 + * <em>Caveat</em>: even after parsing, Windows programs (such as the Java launcher)
24.1380 + * may not fully honor certain
24.1381 + * characters, such as quotes, in command names or arguments. This is because programs
24.1382 + * under Windows frequently perform their own parsing and unescaping (since the shell
24.1383 + * cannot be relied on to do this). On Unix, this problem should not occur.
24.1384 + * @param s a string to parse
24.1385 + * @return an array of parameters
24.1386 + */
24.1387 + public static String[] parseParameters(String s) {
24.1388 + int NULL = 0x0; // STICK + whitespace or NULL + non_"
24.1389 + int INPARAM = 0x1; // NULL + " or STICK + " or INPARAMPENDING + "\ // NOI18N
24.1390 + int INPARAMPENDING = 0x2; // INPARAM + \
24.1391 + int STICK = 0x4; // INPARAM + " or STICK + non_" // NOI18N
24.1392 + int STICKPENDING = 0x8; // STICK + \
24.1393 + Vector<String> params = new Vector<String>(5, 5);
24.1394 + char c;
24.1395 +
24.1396 + int state = NULL;
24.1397 + StringBuffer buff = new StringBuffer(20);
24.1398 + int slength = s.length();
24.1399 +
24.1400 + for (int i = 0; i < slength; i++) {
24.1401 + c = s.charAt(i);
24.1402 +
24.1403 + if (Character.isWhitespace(c)) {
24.1404 + if (state == NULL) {
24.1405 + if (buff.length() > 0) {
24.1406 + params.addElement(buff.toString());
24.1407 + buff.setLength(0);
24.1408 + }
24.1409 + } else if (state == STICK) {
24.1410 + params.addElement(buff.toString());
24.1411 + buff.setLength(0);
24.1412 + state = NULL;
24.1413 + } else if (state == STICKPENDING) {
24.1414 + buff.append('\\');
24.1415 + params.addElement(buff.toString());
24.1416 + buff.setLength(0);
24.1417 + state = NULL;
24.1418 + } else if (state == INPARAMPENDING) {
24.1419 + state = INPARAM;
24.1420 + buff.append('\\');
24.1421 + buff.append(c);
24.1422 + } else { // INPARAM
24.1423 + buff.append(c);
24.1424 + }
24.1425 +
24.1426 + continue;
24.1427 + }
24.1428 +
24.1429 + if (c == '\\') {
24.1430 + if (state == NULL) {
24.1431 + ++i;
24.1432 +
24.1433 + if (i < slength) {
24.1434 + char cc = s.charAt(i);
24.1435 +
24.1436 + if ((cc == '"') || (cc == '\\')) {
24.1437 + buff.append(cc);
24.1438 + } else if (Character.isWhitespace(cc)) {
24.1439 + buff.append(c);
24.1440 + --i;
24.1441 + } else {
24.1442 + buff.append(c);
24.1443 + buff.append(cc);
24.1444 + }
24.1445 + } else {
24.1446 + buff.append('\\');
24.1447 +
24.1448 + break;
24.1449 + }
24.1450 +
24.1451 + continue;
24.1452 + } else if (state == INPARAM) {
24.1453 + state = INPARAMPENDING;
24.1454 + } else if (state == INPARAMPENDING) {
24.1455 + buff.append('\\');
24.1456 + state = INPARAM;
24.1457 + } else if (state == STICK) {
24.1458 + state = STICKPENDING;
24.1459 + } else if (state == STICKPENDING) {
24.1460 + buff.append('\\');
24.1461 + state = STICK;
24.1462 + }
24.1463 +
24.1464 + continue;
24.1465 + }
24.1466 +
24.1467 + if (c == '"') {
24.1468 + if (state == NULL) {
24.1469 + state = INPARAM;
24.1470 + } else if (state == INPARAM) {
24.1471 + state = STICK;
24.1472 + } else if (state == STICK) {
24.1473 + state = INPARAM;
24.1474 + } else if (state == STICKPENDING) {
24.1475 + buff.append('"');
24.1476 + state = STICK;
24.1477 + } else { // INPARAMPENDING
24.1478 + buff.append('"');
24.1479 + state = INPARAM;
24.1480 + }
24.1481 +
24.1482 + continue;
24.1483 + }
24.1484 +
24.1485 + if (state == INPARAMPENDING) {
24.1486 + buff.append('\\');
24.1487 + state = INPARAM;
24.1488 + } else if (state == STICKPENDING) {
24.1489 + buff.append('\\');
24.1490 + state = STICK;
24.1491 + }
24.1492 +
24.1493 + buff.append(c);
24.1494 + }
24.1495 +
24.1496 + // collect
24.1497 + if (state == INPARAM) {
24.1498 + params.addElement(buff.toString());
24.1499 + } else if ((state & (INPARAMPENDING | STICKPENDING)) != 0) {
24.1500 + buff.append('\\');
24.1501 + params.addElement(buff.toString());
24.1502 + } else { // NULL or STICK
24.1503 +
24.1504 + if (buff.length() != 0) {
24.1505 + params.addElement(buff.toString());
24.1506 + }
24.1507 + }
24.1508 +
24.1509 + String[] ret = new String[params.size()];
24.1510 + params.copyInto(ret);
24.1511 +
24.1512 + return ret;
24.1513 + }
24.1514 +
24.1515 + /** Complementary method to parseParameters
24.1516 + * @see #parseParameters
24.1517 + */
24.1518 + public static String escapeParameters(String[] params) {
24.1519 + StringBuffer sb = new StringBuffer();
24.1520 +
24.1521 + for (int i = 0; i < params.length; i++) {
24.1522 + escapeString(params[i], sb);
24.1523 + sb.append(' ');
24.1524 + }
24.1525 +
24.1526 + final int len = sb.length();
24.1527 +
24.1528 + if (len > 0) {
24.1529 + sb.setLength(len - 1);
24.1530 + }
24.1531 +
24.1532 + return sb.toString().trim();
24.1533 + }
24.1534 +
24.1535 + /** Escapes one string
24.1536 + * @see #escapeParameters
24.1537 + */
24.1538 + private static void escapeString(String s, StringBuffer sb) {
24.1539 + if (s.length() == 0) {
24.1540 + sb.append("\"\"");
24.1541 +
24.1542 + return;
24.1543 + }
24.1544 +
24.1545 + boolean hasSpace = false;
24.1546 + final int sz = sb.length();
24.1547 + final int slen = s.length();
24.1548 + char c;
24.1549 +
24.1550 + for (int i = 0; i < slen; i++) {
24.1551 + c = s.charAt(i);
24.1552 +
24.1553 + if (Character.isWhitespace(c)) {
24.1554 + hasSpace = true;
24.1555 + sb.append(c);
24.1556 +
24.1557 + continue;
24.1558 + }
24.1559 +
24.1560 + if (c == '\\') {
24.1561 + sb.append('\\').append('\\');
24.1562 +
24.1563 + continue;
24.1564 + }
24.1565 +
24.1566 + if (c == '"') {
24.1567 + sb.append('\\').append('"');
24.1568 +
24.1569 + continue;
24.1570 + }
24.1571 +
24.1572 + sb.append(c);
24.1573 + }
24.1574 +
24.1575 + if (hasSpace) {
24.1576 + sb.insert(sz, '"');
24.1577 + sb.append('"');
24.1578 + }
24.1579 + }
24.1580 +
24.1581 + //
24.1582 + // Key conversions
24.1583 + //
24.1584 +
24.1585 + private static final class NamesAndValues {
24.1586 + final Map<Integer,String> keyToString;
24.1587 + final Map<String,Integer> stringToKey;
24.1588 + NamesAndValues(Map<Integer,String> keyToString, Map<String,Integer> stringToKey) {
24.1589 + this.keyToString = keyToString;
24.1590 + this.stringToKey = stringToKey;
24.1591 + }
24.1592 + }
24.1593 +
24.1594 + private static Reference<NamesAndValues> namesAndValues;
24.1595 +
24.1596 + private static synchronized NamesAndValues initNameAndValues() {
24.1597 + if (namesAndValues != null) {
24.1598 + NamesAndValues nav = namesAndValues.get();
24.1599 + if (nav != null) {
24.1600 + return nav;
24.1601 + }
24.1602 + }
24.1603 +
24.1604 + Field[] fields = KeyEvent.class.getDeclaredFields();
24.1605 +
24.1606 + Map<String,Integer> names = new HashMap<String,Integer>(fields.length * 4 / 3 + 5, 0.75f);
24.1607 + Map<Integer,String> values = new HashMap<Integer,String>(fields.length * 4 / 3 + 5, 0.75f);
24.1608 +
24.1609 + for (Field f : fields) {
24.1610 + if (Modifier.isStatic(f.getModifiers())) {
24.1611 + String name = f.getName();
24.1612 + if (name.startsWith("VK_")) { // NOI18N
24.1613 + // exclude VK
24.1614 + name = name.substring(3);
24.1615 + try {
24.1616 + int numb = f.getInt(null);
24.1617 + names.put(name, numb);
24.1618 + values.put(numb, name);
24.1619 + } catch (IllegalArgumentException ex) {
24.1620 + } catch (IllegalAccessException ex) {
24.1621 + }
24.1622 + }
24.1623 + }
24.1624 + }
24.1625 +
24.1626 + if (names.get("CONTEXT_MENU") == null) { // NOI18N
24.1627 + names.put("CONTEXT_MENU", 0x20C); // NOI18N
24.1628 + values.put(0x20C, "CONTEXT_MENU"); // NOI18N
24.1629 + names.put("WINDOWS", 0x20D); // NOI18N
24.1630 + values.put(0x20D, "WINDOWS"); // NOI18N
24.1631 + }
24.1632 +
24.1633 + NamesAndValues nav = new NamesAndValues(values, names);
24.1634 + namesAndValues = new SoftReference<NamesAndValues>(nav);
24.1635 + return nav;
24.1636 + }
24.1637 +
24.1638 + /** Converts a Swing key stroke descriptor to a familiar Emacs-like name.
24.1639 + * @param stroke key description
24.1640 + * @return name of the key (e.g. <code>CS-F1</code> for control-shift-function key one)
24.1641 + * @see #stringToKey
24.1642 + */
24.1643 + public static String keyToString(KeyStroke stroke) {
24.1644 + StringBuilder sb = new StringBuilder();
24.1645 +
24.1646 + // add modifiers that must be pressed
24.1647 + if (addModifiers(sb, stroke.getModifiers())) {
24.1648 + sb.append('-');
24.1649 + }
24.1650 +
24.1651 + appendRest(sb, stroke);
24.1652 + return sb.toString();
24.1653 + }
24.1654 +
24.1655 + private static void appendRest(StringBuilder sb, KeyStroke stroke) {
24.1656 + String c = initNameAndValues().keyToString.get(Integer.valueOf(stroke.getKeyCode()));
24.1657 +
24.1658 + if (c == null) {
24.1659 + sb.append(stroke.getKeyChar());
24.1660 + } else {
24.1661 + sb.append(c);
24.1662 + }
24.1663 + }
24.1664 +
24.1665 + /**
24.1666 + * Converts a Swing key stroke descriptor to a familiar Emacs-like name,
24.1667 + * but in a portable way, ie. <code>Meta-C</code> on Mac => <code>D-C</code>
24.1668 + * @param stroke key description
24.1669 + * @return name of the key (e.g. <code>CS-F1</code> for control-shift-function key one)
24.1670 + * @see #stringToKey
24.1671 + */
24.1672 + public static String keyToString(KeyStroke stroke, boolean portable) {
24.1673 + if (portable) {
24.1674 + StringBuilder sb = new StringBuilder();
24.1675 +
24.1676 + // add modifiers that must be pressed
24.1677 + if (addModifiersPortable(sb, stroke.getModifiers())) {
24.1678 + sb.append('-');
24.1679 + }
24.1680 +
24.1681 + appendRest(sb, stroke);
24.1682 + return sb.toString();
24.1683 + }
24.1684 + return keyToString(stroke);
24.1685 + }
24.1686 +
24.1687 + /** Construct a new key description from a given universal string
24.1688 + * description.
24.1689 + * Provides mapping between Emacs-like textual key descriptions and the
24.1690 + * <code>KeyStroke</code> object used in Swing.
24.1691 + * <P>
24.1692 + * This format has following form:
24.1693 + * <P><code>[C][A][S][M]-<em>identifier</em></code>
24.1694 + * <p>Where:
24.1695 + * <UL>
24.1696 + * <LI> <code>C</code> stands for the Control key
24.1697 + * <LI> <code>A</code> stands for the Alt key
24.1698 + * <LI> <code>S</code> stands for the Shift key
24.1699 + * <LI> <code>M</code> stands for the Meta key
24.1700 + * </UL>
24.1701 + * The format also supports two wildcard codes, to support differences in
24.1702 + * platforms. These are the preferred choices for registering keystrokes,
24.1703 + * since platform conflicts will automatically be handled:
24.1704 + * <UL>
24.1705 + * <LI> <code>D</code> stands for the default menu accelerator - the Control
24.1706 + * key on most platforms, the Command (meta) key on Macintosh</LI>
24.1707 + * <LI> <code>O</code> stands for the alternate accelerator - the Alt key on
24.1708 + * most platforms, the Ctrl key on Macintosh (Macintosh uses Alt as a
24.1709 + * secondary shift key for composing international characters - if you bind
24.1710 + * Alt-8 to an action, a mac user with a French keyboard will not be able
24.1711 + * to type the <code>[</code> character, which is a significant handicap</LI>
24.1712 + * </UL>
24.1713 + * If you use the wildcard characters, and specify a key which will conflict
24.1714 + * with keys the operating system consumes, it will be mapped to whichever
24.1715 + * choice can work - for example, on Macintosh, Command-Q is always consumed
24.1716 + * by the operating system, so <code>D-Q</code> will always map to Control-Q.
24.1717 + * <p>
24.1718 + * Every modifier before the hyphen must be pressed.
24.1719 + * <em>identifier</EM> can be any text constant from {@link KeyEvent} but
24.1720 + * without the leading <code>VK_</code> characters. So {@link KeyEvent#VK_ENTER} is described as
24.1721 + * <code>ENTER</code>.
24.1722 + *
24.1723 + * @param s the string with the description of the key
24.1724 + * @return key description object, or <code>null</code> if the string does not represent any valid key
24.1725 + */
24.1726 + public static KeyStroke stringToKey(String s) {
24.1727 + StringTokenizer st = new StringTokenizer(s.toUpperCase(Locale.ENGLISH), "-", true); // NOI18N
24.1728 +
24.1729 + int needed = 0;
24.1730 +
24.1731 + Map<String,Integer> names = initNameAndValues().stringToKey;
24.1732 +
24.1733 + int lastModif = -1;
24.1734 +
24.1735 + try {
24.1736 + for (;;) {
24.1737 + String el = st.nextToken();
24.1738 +
24.1739 + // required key
24.1740 + if (el.equals("-")) { // NOI18N
24.1741 +
24.1742 + if (lastModif != -1) {
24.1743 + needed |= lastModif;
24.1744 + lastModif = -1;
24.1745 + }
24.1746 +
24.1747 + continue;
24.1748 + }
24.1749 +
24.1750 + // if there is more elements
24.1751 + if (st.hasMoreElements()) {
24.1752 + // the text should describe modifiers
24.1753 + lastModif = readModifiers(el);
24.1754 + } else {
24.1755 + // last text must be the key code
24.1756 + Integer i = names.get(el);
24.1757 + boolean wildcard = (needed & CTRL_WILDCARD_MASK) != 0;
24.1758 +
24.1759 + //Strip out the explicit mask - KeyStroke won't know
24.1760 + //what to do with it
24.1761 + needed = needed & ~CTRL_WILDCARD_MASK;
24.1762 +
24.1763 + boolean macAlt = (needed & ALT_WILDCARD_MASK) != 0;
24.1764 + needed = needed & ~ALT_WILDCARD_MASK;
24.1765 +
24.1766 + if (i != null) {
24.1767 + //#26854 - Default accelerator should be Command on mac
24.1768 + if (wildcard) {
24.1769 + needed |= getMenuShortcutKeyMask();
24.1770 +
24.1771 + if (isMac()) {
24.1772 + if (!usableKeyOnMac(i, needed)) {
24.1773 + needed &= ~getMenuShortcutKeyMask();
24.1774 + needed |= KeyEvent.CTRL_MASK;
24.1775 + }
24.1776 + }
24.1777 + }
24.1778 +
24.1779 + if (macAlt) {
24.1780 + if (getOperatingSystem() == OS_MAC) {
24.1781 + needed |= KeyEvent.CTRL_MASK;
24.1782 + } else {
24.1783 + needed |= KeyEvent.ALT_MASK;
24.1784 + }
24.1785 + }
24.1786 +
24.1787 + return KeyStroke.getKeyStroke(i, needed);
24.1788 + } else {
24.1789 + return null;
24.1790 + }
24.1791 + }
24.1792 + }
24.1793 + } catch (NoSuchElementException ex) {
24.1794 + return null;
24.1795 + }
24.1796 + }
24.1797 +
24.1798 + private static final boolean usableKeyOnMac(int key, int mask) {
24.1799 + //All permutations fail for Q except ctrl
24.1800 + if (key == KeyEvent.VK_Q) {
24.1801 + return false;
24.1802 + }
24.1803 +
24.1804 + boolean isMeta = ((mask & KeyEvent.META_MASK) != 0) || ((mask & KeyEvent.CTRL_DOWN_MASK) != 0);
24.1805 +
24.1806 + boolean isAlt = ((mask & KeyEvent.ALT_MASK) != 0) || ((mask & KeyEvent.ALT_DOWN_MASK) != 0);
24.1807 +
24.1808 + boolean isOnlyMeta = isMeta && ((mask & ~(KeyEvent.META_DOWN_MASK | KeyEvent.META_MASK)) == 0);
24.1809 +
24.1810 + //Mac OS consumes keys Command+ these keys - the app will never see
24.1811 + //them, so CTRL should not be remapped for these
24.1812 + if (isOnlyMeta) {
24.1813 + return (key != KeyEvent.VK_H) && (key != KeyEvent.VK_SPACE) && (key != KeyEvent.VK_TAB);
24.1814 + } else if ((key == KeyEvent.VK_D) && isMeta && isAlt) {
24.1815 + return false;
24.1816 + } else {
24.1817 + return true;
24.1818 + }
24.1819 + }
24.1820 +
24.1821 + private static final int getMenuShortcutKeyMask() {
24.1822 + // #152050 - work in headless environment too
24.1823 + if (GraphicsEnvironment.isHeadless()) {
24.1824 + return Event.CTRL_MASK;
24.1825 + }
24.1826 + return Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
24.1827 + }
24.1828 +
24.1829 + /** Convert a space-separated list of user-friendly key binding names to a list of Swing key strokes.
24.1830 + * @param s the string with keys
24.1831 + * @return array of key strokes, or <code>null</code> if the string description is not valid
24.1832 + * @see #stringToKey
24.1833 + */
24.1834 + public static KeyStroke[] stringToKeys(String s) {
24.1835 + StringTokenizer st = new StringTokenizer(s.toUpperCase(Locale.ENGLISH), " "); // NOI18N
24.1836 + ArrayList<KeyStroke> arr = new ArrayList<KeyStroke>();
24.1837 +
24.1838 + while (st.hasMoreElements()) {
24.1839 + s = st.nextToken();
24.1840 +
24.1841 + KeyStroke k = stringToKey(s);
24.1842 +
24.1843 + if (k == null) {
24.1844 + return null;
24.1845 + }
24.1846 +
24.1847 + arr.add(k);
24.1848 + }
24.1849 +
24.1850 + return arr.toArray(new KeyStroke[arr.size()]);
24.1851 + }
24.1852 +
24.1853 + /** Adds characters for modifiers to the buffer.
24.1854 + * @param buf buffer to add to
24.1855 + * @param modif modifiers to add (KeyEvent.XXX_MASK)
24.1856 + * @return true if something has been added
24.1857 + */
24.1858 + private static boolean addModifiers(StringBuilder buf, int modif) {
24.1859 + boolean b = false;
24.1860 +
24.1861 + if ((modif & KeyEvent.CTRL_MASK) != 0) {
24.1862 + buf.append("C"); // NOI18N
24.1863 + b = true;
24.1864 + }
24.1865 +
24.1866 + if ((modif & KeyEvent.ALT_MASK) != 0) {
24.1867 + buf.append("A"); // NOI18N
24.1868 + b = true;
24.1869 + }
24.1870 +
24.1871 + if ((modif & KeyEvent.SHIFT_MASK) != 0) {
24.1872 + buf.append("S"); // NOI18N
24.1873 + b = true;
24.1874 + }
24.1875 +
24.1876 + if ((modif & KeyEvent.META_MASK) != 0) {
24.1877 + buf.append("M"); // NOI18N
24.1878 + b = true;
24.1879 + }
24.1880 +
24.1881 + if ((modif & CTRL_WILDCARD_MASK) != 0) {
24.1882 + buf.append("D");
24.1883 + b = true;
24.1884 + }
24.1885 +
24.1886 + if ((modif & ALT_WILDCARD_MASK) != 0) {
24.1887 + buf.append("O");
24.1888 + b = true;
24.1889 + }
24.1890 +
24.1891 + return b;
24.1892 + }
24.1893 +
24.1894 + private static boolean addModifiersPortable(StringBuilder buf, int modifiers) {
24.1895 + boolean b = false;
24.1896 +
24.1897 + if ((modifiers & KeyEvent.SHIFT_MASK) != 0) {
24.1898 + buf.append('S');
24.1899 + b = true;
24.1900 + }
24.1901 +
24.1902 + if (Utilities.isMac() && ((modifiers & KeyEvent.META_MASK) != 0) || !Utilities.isMac() && ((modifiers & KeyEvent.CTRL_MASK) != 0)) {
24.1903 + buf.append('D');
24.1904 + b = true;
24.1905 + }
24.1906 +
24.1907 + if (Utilities.isMac() && ((modifiers & KeyEvent.CTRL_MASK) != 0) || !Utilities.isMac() && ((modifiers & KeyEvent.ALT_MASK) != 0)) {
24.1908 + buf.append('O');
24.1909 + b = true;
24.1910 + }
24.1911 + // mac alt fallback
24.1912 + if (Utilities.isMac() && ((modifiers & KeyEvent.ALT_MASK) != 0)) {
24.1913 + buf.append('A');
24.1914 + b = true;
24.1915 + }
24.1916 +
24.1917 + return b;
24.1918 + }
24.1919 +
24.1920 + /** Reads for modifiers and creates integer with required mask.
24.1921 + * @param s string with modifiers
24.1922 + * @return integer with mask
24.1923 + * @exception NoSuchElementException if some letter is not modifier
24.1924 + */
24.1925 + private static int readModifiers(String s) throws NoSuchElementException {
24.1926 + int m = 0;
24.1927 +
24.1928 + for (int i = 0; i < s.length(); i++) {
24.1929 + switch (s.charAt(i)) {
24.1930 + case 'C':
24.1931 + m |= KeyEvent.CTRL_MASK;
24.1932 +
24.1933 + break;
24.1934 +
24.1935 + case 'A':
24.1936 + m |= KeyEvent.ALT_MASK;
24.1937 +
24.1938 + break;
24.1939 +
24.1940 + case 'M':
24.1941 + m |= KeyEvent.META_MASK;
24.1942 +
24.1943 + break;
24.1944 +
24.1945 + case 'S':
24.1946 + m |= KeyEvent.SHIFT_MASK;
24.1947 +
24.1948 + break;
24.1949 +
24.1950 + case 'D':
24.1951 + m |= CTRL_WILDCARD_MASK;
24.1952 +
24.1953 + break;
24.1954 +
24.1955 + case 'O':
24.1956 + m |= ALT_WILDCARD_MASK;
24.1957 +
24.1958 + break;
24.1959 +
24.1960 + default:
24.1961 + throw new NoSuchElementException(s);
24.1962 + }
24.1963 + }
24.1964 +
24.1965 + return m;
24.1966 + }
24.1967 +
24.1968 + /**
24.1969 + * Finds out the monitor where the user currently has the input focus.
24.1970 + * This method is usually used to help the client code to figure out on
24.1971 + * which monitor it should place newly created windows/frames/dialogs.
24.1972 + *
24.1973 + * @return the GraphicsConfiguration of the monitor which currently has the
24.1974 + * input focus
24.1975 + */
24.1976 + private static GraphicsConfiguration getCurrentGraphicsConfiguration() {
24.1977 + Component focusOwner = KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();
24.1978 + if (focusOwner != null) {
24.1979 + Window w = SwingUtilities.getWindowAncestor(focusOwner);
24.1980 + if (w != null) {
24.1981 + return w.getGraphicsConfiguration();
24.1982 + }
24.1983 + }
24.1984 +
24.1985 + return GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
24.1986 + }
24.1987 +
24.1988 + /**
24.1989 + * Returns the usable area of the screen where applications can place its
24.1990 + * windows. The method subtracts from the screen the area of taskbars,
24.1991 + * system menus and the like. The screen this method applies to is the one
24.1992 + * which is considered current, ussually the one where the current input
24.1993 + * focus is.
24.1994 + *
24.1995 + * @return the rectangle of the screen where one can place windows
24.1996 + *
24.1997 + * @since 2.5
24.1998 + */
24.1999 + public static Rectangle getUsableScreenBounds() {
24.2000 + return getUsableScreenBounds(getCurrentGraphicsConfiguration());
24.2001 + }
24.2002 +
24.2003 + /**
24.2004 + * Returns the usable area of the screen where applications can place its
24.2005 + * windows. The method subtracts from the screen the area of taskbars,
24.2006 + * system menus and the like.
24.2007 + *
24.2008 + * @param gconf the GraphicsConfiguration of the monitor
24.2009 + * @return the rectangle of the screen where one can place windows
24.2010 + *
24.2011 + * @since 2.5
24.2012 + */
24.2013 + public static Rectangle getUsableScreenBounds(GraphicsConfiguration gconf) {
24.2014 + if (gconf == null) {
24.2015 + gconf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
24.2016 + }
24.2017 +
24.2018 + Rectangle bounds = new Rectangle(gconf.getBounds());
24.2019 +
24.2020 + String str;
24.2021 +
24.2022 + str = System.getProperty("netbeans.screen.insets"); // NOI18N
24.2023 +
24.2024 + if (str != null) {
24.2025 + StringTokenizer st = new StringTokenizer(str, ", "); // NOI18N
24.2026 +
24.2027 + if (st.countTokens() == 4) {
24.2028 + try {
24.2029 + bounds.y = Integer.parseInt(st.nextToken());
24.2030 + bounds.x = Integer.parseInt(st.nextToken());
24.2031 + bounds.height -= (bounds.y + Integer.parseInt(st.nextToken()));
24.2032 + bounds.width -= (bounds.x + Integer.parseInt(st.nextToken()));
24.2033 + } catch (NumberFormatException ex) {
24.2034 + LOG.log(Level.WARNING, null, ex);
24.2035 + }
24.2036 + }
24.2037 +
24.2038 + return bounds;
24.2039 + }
24.2040 +
24.2041 + str = System.getProperty("netbeans.taskbar.height"); // NOI18N
24.2042 +
24.2043 + if (str != null) {
24.2044 + bounds.height -= Integer.getInteger(str, 0).intValue();
24.2045 +
24.2046 + return bounds;
24.2047 + }
24.2048 +
24.2049 + try {
24.2050 + Toolkit toolkit = Toolkit.getDefaultToolkit();
24.2051 + Insets insets = toolkit.getScreenInsets(gconf);
24.2052 + bounds.y += insets.top;
24.2053 + bounds.x += insets.left;
24.2054 + bounds.height -= (insets.top + insets.bottom);
24.2055 + bounds.width -= (insets.left + insets.right);
24.2056 + } catch (Exception ex) {
24.2057 + LOG.log(Level.WARNING, null, ex);
24.2058 + }
24.2059 +
24.2060 + return bounds;
24.2061 + }
24.2062 +
24.2063 + /**
24.2064 + * Helps client code place components on the center of the screen. It
24.2065 + * handles multiple monitor configuration correctly
24.2066 + *
24.2067 + * @param componentSize the size of the component
24.2068 + * @return bounds of the centered component
24.2069 + *
24.2070 + * @since 2.5
24.2071 + */
24.2072 + public static Rectangle findCenterBounds(Dimension componentSize) {
24.2073 + return findCenterBounds(getCurrentGraphicsConfiguration(), componentSize);
24.2074 + }
24.2075 +
24.2076 + /**
24.2077 + * Helps client code place components on the center of the screen. It
24.2078 + * handles multiple monitor configuration correctly
24.2079 + *
24.2080 + * @param gconf the GraphicsConfiguration of the monitor
24.2081 + * @param componentSize the size of the component
24.2082 + * @return bounds of the centered component
24.2083 + */
24.2084 + private static Rectangle findCenterBounds(GraphicsConfiguration gconf, Dimension componentSize) {
24.2085 + if (gconf == null) {
24.2086 + gconf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
24.2087 + }
24.2088 +
24.2089 + Rectangle bounds = gconf.getBounds();
24.2090 +
24.2091 + return new Rectangle(
24.2092 + bounds.x + ((bounds.width - componentSize.width) / 2),
24.2093 + bounds.y + ((bounds.height - componentSize.height) / 2), componentSize.width, componentSize.height
24.2094 + );
24.2095 + }
24.2096 +
24.2097 + /** @return size of the screen. The size is modified for Windows OS
24.2098 + * - some points are subtracted to reflect a presence of the taskbar
24.2099 + *
24.2100 + * @deprecated this method is almost useless in multiple monitor configuration
24.2101 + *
24.2102 + * @see #getUsableScreenBounds()
24.2103 + * @see #findCenterBounds(Dimension)
24.2104 + */
24.2105 + @Deprecated
24.2106 + public static final Dimension getScreenSize() {
24.2107 + Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
24.2108 +
24.2109 + if (isWindows() && !Boolean.getBoolean("netbeans.no.taskbar")) {
24.2110 + screenSize.height -= TYPICAL_WINDOWS_TASKBAR_HEIGHT;
24.2111 + } else if (isMac()) {
24.2112 + screenSize.height -= TYPICAL_MACOSX_MENU_HEIGHT;
24.2113 + }
24.2114 +
24.2115 + return screenSize;
24.2116 + }
24.2117 +
24.2118 + /** Utility method for avoiding of memory leak in JDK 1.3 / JFileChooser.showDialog(...)
24.2119 + * @param parent
24.2120 + * @param approveButtonText
24.2121 + * @deprecated Not needed in JDK 1.4.
24.2122 + * @see <a href="@org-openide-filesystems@/org/openide/filesystems/FileChooserBuilder.html"><code>FileChooserBuilder</code></a>
24.2123 + */
24.2124 + @Deprecated
24.2125 + public static final int showJFileChooser(
24.2126 + javax.swing.JFileChooser chooser, java.awt.Component parent, java.lang.String approveButtonText
24.2127 + ) {
24.2128 + if (approveButtonText != null) {
24.2129 + chooser.setApproveButtonText(approveButtonText);
24.2130 + chooser.setDialogType(javax.swing.JFileChooser.CUSTOM_DIALOG);
24.2131 + }
24.2132 +
24.2133 + Frame frame = null;
24.2134 + Dialog parentDlg = null;
24.2135 +
24.2136 + if (parent instanceof Dialog) {
24.2137 + parentDlg = (Dialog) parent;
24.2138 + } else {
24.2139 + frame = (parent instanceof java.awt.Frame) ? (Frame) parent
24.2140 + : (Frame) javax.swing.SwingUtilities.getAncestorOfClass(
24.2141 + Frame.class, parent
24.2142 + );
24.2143 + }
24.2144 +
24.2145 + String title = chooser.getDialogTitle();
24.2146 +
24.2147 + if (title == null) {
24.2148 + title = chooser.getUI().getDialogTitle(chooser);
24.2149 + }
24.2150 +
24.2151 + final javax.swing.JDialog dialog;
24.2152 +
24.2153 + if (parentDlg != null) {
24.2154 + dialog = new javax.swing.JDialog(parentDlg, title, true);
24.2155 + } else {
24.2156 + dialog = new javax.swing.JDialog(frame, title, true);
24.2157 + }
24.2158 +
24.2159 + dialog.setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
24.2160 +
24.2161 + Container contentPane = dialog.getContentPane();
24.2162 + contentPane.setLayout(new BorderLayout());
24.2163 + contentPane.add(chooser, BorderLayout.CENTER);
24.2164 +
24.2165 + dialog.pack();
24.2166 + dialog.setBounds(findCenterBounds(parent.getGraphicsConfiguration(), dialog.getSize()));
24.2167 +
24.2168 + chooser.rescanCurrentDirectory();
24.2169 +
24.2170 + final int[] retValue = {javax.swing.JFileChooser.CANCEL_OPTION};
24.2171 +
24.2172 + java.awt.event.ActionListener l = new java.awt.event.ActionListener() {
24.2173 + public void actionPerformed(java.awt.event.ActionEvent ev) {
24.2174 + if (javax.swing.JFileChooser.APPROVE_SELECTION.equals(ev.getActionCommand())) {
24.2175 + retValue[0] = javax.swing.JFileChooser.APPROVE_OPTION;
24.2176 + }
24.2177 +
24.2178 + dialog.setVisible(false);
24.2179 + dialog.dispose();
24.2180 + }
24.2181 + };
24.2182 +
24.2183 + chooser.addActionListener(l);
24.2184 +
24.2185 + dialog.show();
24.2186 +
24.2187 + return retValue[0];
24.2188 + }
24.2189 +
24.2190 + /** Sort a list according to a specified partial order.
24.2191 + * Note that in the current implementation, the comparator will be called
24.2192 + * exactly once for each distinct pair of list elements, ignoring order,
24.2193 + * so caching its results is a waste of time.
24.2194 + * @param l the list to sort (will not be modified)
24.2195 + * @param c a comparator to impose the partial order; "equal" means that the elements
24.2196 + * are not ordered with respect to one another, i.e. may be only a partial order
24.2197 + * @param stable whether to attempt a stable sort, meaning that the position of elements
24.2198 + * will be disturbed as little as possible; might be slightly slower
24.2199 + * @return the partially-sorted list
24.2200 + * @throws UnorderableException if the specified partial order is inconsistent on this list
24.2201 + * @deprecated Deprecated in favor of the potentially much faster (and possibly more correct) {@link #topologicalSort}.
24.2202 + */
24.2203 + @SuppressWarnings("unchecked") // do not bother, it is deprecated anyway
24.2204 + @Deprecated
24.2205 + public static List partialSort(List l, Comparator c, boolean stable)
24.2206 + throws UnorderableException {
24.2207 + // map from objects in the list to null or sets of objects they are greater than
24.2208 + // (i.e. must appear after):
24.2209 + Map deps = new HashMap(); // Map<Object,Set<Object>>
24.2210 + int size = l.size();
24.2211 +
24.2212 + // Create a table of dependencies.
24.2213 + for (int i = 0; i < size; i++) {
24.2214 + for (int j = i + 1; j < size; j++) {
24.2215 + int cmp = c.compare(l.get(i), l.get(j));
24.2216 +
24.2217 + if (cmp != 0) {
24.2218 + Object earlier = l.get((cmp < 0) ? i : j);
24.2219 + Object later = l.get((cmp > 0) ? i : j);
24.2220 + Set s = (Set) deps.get(later);
24.2221 +
24.2222 + if (s == null) {
24.2223 + deps.put(later, s = new HashSet());
24.2224 + }
24.2225 +
24.2226 + s.add(earlier);
24.2227 + }
24.2228 + }
24.2229 + }
24.2230 +
24.2231 + // Lists of items to process, and items sorted.
24.2232 + List left = new LinkedList(l);
24.2233 + List sorted = new ArrayList(size);
24.2234 +
24.2235 + while (left.size() > 0) {
24.2236 + boolean stillGoing = false;
24.2237 + Iterator it = left.iterator();
24.2238 +
24.2239 + while (it.hasNext()) {
24.2240 + Object elt = it.next();
24.2241 + Set eltDeps = (Set) deps.get(elt);
24.2242 +
24.2243 + if ((eltDeps == null) || (eltDeps.size() == 0)) {
24.2244 + // This one is OK to add to the result now.
24.2245 + it.remove();
24.2246 + stillGoing = true;
24.2247 + sorted.add(elt);
24.2248 +
24.2249 + // Mark other elements that should be later
24.2250 + // than this as having their dep satisfied.
24.2251 + Iterator it2 = left.iterator();
24.2252 +
24.2253 + while (it2.hasNext()) {
24.2254 + Object elt2 = it2.next();
24.2255 + Set eltDeps2 = (Set) deps.get(elt2);
24.2256 +
24.2257 + if (eltDeps2 != null) {
24.2258 + eltDeps2.remove(elt);
24.2259 + }
24.2260 + }
24.2261 +
24.2262 + if (stable) {
24.2263 + break;
24.2264 + }
24.2265 + }
24.2266 + }
24.2267 +
24.2268 + if (!stillGoing) {
24.2269 + // Clean up deps to only include "interesting" problems.
24.2270 + it = deps.entrySet().iterator();
24.2271 +
24.2272 + while (it.hasNext()) {
24.2273 + Map.Entry me = (Map.Entry) it.next();
24.2274 +
24.2275 + if (!left.contains(me.getKey())) {
24.2276 + it.remove();
24.2277 + } else {
24.2278 + Set s = (Set) me.getValue();
24.2279 + Iterator it2 = s.iterator();
24.2280 +
24.2281 + while (it2.hasNext()) {
24.2282 + if (!left.contains(it2.next())) {
24.2283 + it2.remove();
24.2284 + }
24.2285 + }
24.2286 +
24.2287 + if (s.isEmpty()) {
24.2288 + it.remove();
24.2289 + }
24.2290 + }
24.2291 + }
24.2292 +
24.2293 + throw new UnorderableException(left, deps);
24.2294 + }
24.2295 + }
24.2296 +
24.2297 + return sorted;
24.2298 + }
24.2299 +
24.2300 + /**
24.2301 + * Topologically sort some objects.
24.2302 + * <p>There may not be any nulls among the objects, nor duplicates
24.2303 + * (as per hash/equals), nor duplicates among the edge lists.
24.2304 + * The edge map need not contain an entry for every object, only if it
24.2305 + * has some outgoing edges (empty but not null map values are permitted).
24.2306 + * The edge map shall not contain neither keys nor value entries for objects not
24.2307 + * in the collection to be sorted, if that happens they will be ignored (since version 7.9).
24.2308 + * <p>The incoming parameters will not be modified; they must not be changed
24.2309 + * during the call and possible calls to TopologicalSortException methods.
24.2310 + * The returned list will support modifications.
24.2311 + * <p>There is a <em>weak</em> stability guarantee: if there are no edges
24.2312 + * which contradict the incoming order, the resulting list will be in the same
24.2313 + * order as the incoming elements. However if some elements need to be rearranged,
24.2314 + * it is <em>not</em> guaranteed that others will not also be rearranged, even
24.2315 + * if they did not strictly speaking need to be.
24.2316 + * @param c a collection of objects to be topologically sorted
24.2317 + * @param edges constraints among those objects, of type <code>Map<Object,Collection></code>;
24.2318 + * if an object is a key in this map, the resulting order will
24.2319 + * have that object before any objects listed in the value
24.2320 + * @return a partial ordering of the objects in the collection,
24.2321 + * @exception TopologicalSortException if the sort cannot succeed due to cycles in the graph, the
24.2322 + * exception contains additional information to describe and possibly recover from the error
24.2323 + * @since 3.30
24.2324 + * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=27286">Issue #27286</a>
24.2325 + */
24.2326 + public static <T> List<T> topologicalSort(Collection<T> c, Map<? super T, ? extends Collection<? extends T>> edges)
24.2327 + throws TopologicalSortException {
24.2328 + Map<T,Boolean> finished = new HashMap<T,Boolean>();
24.2329 + List<T> r = new ArrayList<T>(Math.max(c.size(), 1));
24.2330 + List<T> cRev = new ArrayList<T>(c);
24.2331 + Collections.reverse(cRev);
24.2332 +
24.2333 + Iterator<T> it = cRev.iterator();
24.2334 +
24.2335 + while (it.hasNext()) {
24.2336 + List<T> cycle = visit(it.next(), edges, finished, r);
24.2337 +
24.2338 + if (cycle != null) {
24.2339 + throw new TopologicalSortException(cRev, edges);
24.2340 + }
24.2341 + }
24.2342 +
24.2343 + Collections.reverse(r);
24.2344 + if (r.size() != c.size()) {
24.2345 + r.retainAll(c);
24.2346 + }
24.2347 +
24.2348 + return r;
24.2349 + }
24.2350 +
24.2351 + /**
24.2352 + * Visit one node in the DAG.
24.2353 + * @param node node to visit
24.2354 + * @param edges edges in the DAG
24.2355 + * @param finished which nodes are finished; a node has no entry if it has not yet
24.2356 + * been visited, else it is set to false while recurring and true
24.2357 + * when it has finished
24.2358 + * @param r the order in progress
24.2359 + * @return list with detected cycle
24.2360 + */
24.2361 + static <T> List<T> visit(
24.2362 + T node,
24.2363 + Map<? super T, ? extends Collection<? extends T>> edges,
24.2364 + Map<T,Boolean> finished,
24.2365 + List<T> r
24.2366 + ) {
24.2367 + Boolean b = finished.get(node);
24.2368 +
24.2369 + //System.err.println("node=" + node + " color=" + b);
24.2370 + if (b != null) {
24.2371 + if (b.booleanValue()) {
24.2372 + return null;
24.2373 + }
24.2374 +
24.2375 + ArrayList<T> cycle = new ArrayList<T>();
24.2376 + cycle.add(node);
24.2377 + finished.put(node, null);
24.2378 +
24.2379 + return cycle;
24.2380 + }
24.2381 +
24.2382 + Collection<? extends T> e = edges.get(node);
24.2383 +
24.2384 + if (e != null) {
24.2385 + finished.put(node, Boolean.FALSE);
24.2386 +
24.2387 + Iterator<? extends T> it = e.iterator();
24.2388 +
24.2389 + while (it.hasNext()) {
24.2390 + List<T> cycle = visit(it.next(), edges, finished, r);
24.2391 +
24.2392 + if (cycle != null) {
24.2393 + if (cycle instanceof ArrayList) {
24.2394 + // if cycle instanceof ArrayList we are still in the
24.2395 + // cycle and we want to collect new members
24.2396 + if (Boolean.FALSE == finished.get(node)) {
24.2397 + // another member in the cycle
24.2398 + cycle.add(node);
24.2399 + } else {
24.2400 + // we have reached the head of the cycle
24.2401 + // do not add additional cycles anymore
24.2402 + Collections.reverse(cycle);
24.2403 +
24.2404 + // changing cycle to not be ArrayList
24.2405 + cycle = Collections.unmodifiableList(cycle);
24.2406 + }
24.2407 + }
24.2408 +
24.2409 + // mark this node as tested
24.2410 + finished.put(node, Boolean.TRUE);
24.2411 +
24.2412 + // and report an error
24.2413 + return cycle;
24.2414 + }
24.2415 + }
24.2416 + }
24.2417 +
24.2418 + finished.put(node, Boolean.TRUE);
24.2419 + r.add(node);
24.2420 +
24.2421 + return null;
24.2422 + }
24.2423 +
24.2424 + /** Provides support for parts of the system that deal with classnames
24.2425 + * (use <code>Class.forName</code>, <code>NbObjectInputStream</code>, etc.).
24.2426 + * <P>
24.2427 + * Often class names (especially package names) changes during lifecycle
24.2428 + * of a module. When some piece of the system stores the name of a class
24.2429 + * in certain point of a time and wants to find the correct <code>Class</code>
24.2430 + * later it needs to count with the possibility of rename.
24.2431 + * <P>
24.2432 + * For such purposes this method has been created. It allows modules to
24.2433 + * register their classes that changed names and other parts of system that
24.2434 + * deal with class names to find the correct names.
24.2435 + * <P>
24.2436 + * To register a mapping from old class names to new ones create a file
24.2437 + * <code>META-INF/netbeans/translate.names</code> in your module and fill it
24.2438 + * with your mapping:
24.2439 + * <PRE>
24.2440 + * #
24.2441 + * # Mapping of legacy classes to new ones
24.2442 + * #
24.2443 + *
24.2444 + * org.oldpackage.MyClass=org.newpackage.MyClass # rename of package for one class
24.2445 + * org.mypackage.OldClass=org.mypackage.NewClass # rename of class in a package
24.2446 + *
24.2447 + * # rename of class and package
24.2448 + * org.oldpackage.OldClass=org.newpackage.NewClass
24.2449 + *
24.2450 + * # rename of whole package
24.2451 + * org.someoldpackage=org.my.new.package.structure
24.2452 + *
24.2453 + * # class was removed without replacement
24.2454 + * org.mypackage.OldClass=
24.2455 + *
24.2456 + * </PRE>
24.2457 + * Btw. one can use spaces instead of <code>=</code> sign.
24.2458 + * For a real world example
24.2459 + * check the
24.2460 + * <a href="http://www.netbeans.org/source/browse/xml/text-edit/compat/src/META-INF/netbeans/">
24.2461 + * xml module</a>.
24.2462 + *
24.2463 + * <P>
24.2464 + * For purposes of <link>org.openide.util.io.NbObjectInputStream</link> there is
24.2465 + * a following special convention:
24.2466 + * If the
24.2467 + * className is not listed as one that is to be renamed, the returned
24.2468 + * string == className, if the className is registered to be renamed
24.2469 + * than the className != returned value, even in a case when className.equals (retValue)
24.2470 + *
24.2471 + * @param className fully qualified name of a class to translate
24.2472 + * @return new name of the class according to renaming rules.
24.2473 + */
24.2474 + public static String translate(final String className) {
24.2475 + checkMapping();
24.2476 +
24.2477 + RE exp;
24.2478 +
24.2479 + synchronized (TRANS_LOCK) {
24.2480 + exp = transExp;
24.2481 + }
24.2482 +
24.2483 + if (exp == null) {
24.2484 + // no transition table found
24.2485 + return className;
24.2486 + }
24.2487 +
24.2488 + synchronized (exp) {
24.2489 + // refusing convertions as fast as possible
24.2490 + return exp.convert(className);
24.2491 + }
24.2492 + }
24.2493 +
24.2494 + /** Loads all resources that contain renaming information.
24.2495 + * @param l classloader to load packages from
24.2496 + */
24.2497 + private static void checkMapping() {
24.2498 + // test if we run in test mode
24.2499 + if (transLoader == TRANS_LOCK) {
24.2500 + // no check
24.2501 + return;
24.2502 + }
24.2503 +
24.2504 + ClassLoader current = Lookup.getDefault().lookup(ClassLoader.class);
24.2505 +
24.2506 + if (current == null) {
24.2507 + current = ClassLoader.getSystemClassLoader();
24.2508 + }
24.2509 +
24.2510 + if (transLoader == current) {
24.2511 + // no change, no rescan
24.2512 + return;
24.2513 + }
24.2514 +
24.2515 + initForLoader(current, current);
24.2516 + }
24.2517 +
24.2518 + /* Initializes the content of transition table from a classloader.
24.2519 + * @param loader loader to read data from
24.2520 + * @param set loader to set as the transLoader or null if we run in test mode
24.2521 + */
24.2522 + static void initForLoader(ClassLoader current, Object set) {
24.2523 + if (set == null) {
24.2524 + set = TRANS_LOCK;
24.2525 + }
24.2526 +
24.2527 + Enumeration en;
24.2528 +
24.2529 + try {
24.2530 + en = current.getResources("META-INF/netbeans/translate.names");
24.2531 + } catch (IOException ex) {
24.2532 + LOG.log(Level.WARNING, null, ex);
24.2533 + en = null;
24.2534 + }
24.2535 +
24.2536 + if ((en == null) || !en.hasMoreElements()) {
24.2537 + synchronized (TRANS_LOCK) {
24.2538 + transLoader = set;
24.2539 + transExp = null;
24.2540 + }
24.2541 +
24.2542 + return;
24.2543 + }
24.2544 +
24.2545 + // format of line in the meta files
24.2546 + //
24.2547 + // # comments are allowed
24.2548 + // a.name.in.a.Package=another.Name # with comment is allowed
24.2549 + // for.compatibility.one.can.use.Space instead.of.Equal
24.2550 + //
24.2551 + RE re = null;
24.2552 +
24.2553 + // [pnejedly:perf] commented out. The RegExp based translation was way slower
24.2554 + // than the hand-written RE13
24.2555 + // if (Dependency.JAVA_SPEC.compareTo(new SpecificationVersion("1.4")) >= 0) { // NOI18N
24.2556 + // try {
24.2557 + // re = (RE)Class.forName ("org.openide.util.RE14").newInstance ();
24.2558 + // } catch (ThreadDeath t) {
24.2559 + // throw t;
24.2560 + // } catch (Throwable t) {
24.2561 + // }
24.2562 + // }
24.2563 + // if (re == null) {
24.2564 + re = new RE13();
24.2565 +
24.2566 + // }
24.2567 + TreeSet<String[]> list = new TreeSet<String[]>(
24.2568 + new Comparator<String[]>() {
24.2569 + public int compare(String[] o1, String[] o2) {
24.2570 + String s1 = o1[0];
24.2571 + String s2 = o2[0];
24.2572 +
24.2573 + int i1 = s1.length();
24.2574 + int i2 = s2.length();
24.2575 +
24.2576 + if (i1 != i2) {
24.2577 + return i2 - i1;
24.2578 + }
24.2579 +
24.2580 + return s2.compareTo(s1);
24.2581 + }
24.2582 + }
24.2583 + );
24.2584 +
24.2585 + while (en.hasMoreElements()) {
24.2586 + URL u = (URL) en.nextElement();
24.2587 +
24.2588 + try {
24.2589 + BufferedReader reader = new BufferedReader(
24.2590 + new InputStreamReader(u.openStream(), "UTF8") // use explicit encoding //NOI18N
24.2591 + );
24.2592 + loadTranslationFile(re, reader, list);
24.2593 + reader.close();
24.2594 + } catch (IOException ex) {
24.2595 + LOG.log(Level.WARNING, "Problematic file: " + u);
24.2596 + LOG.log(Level.WARNING, null, ex);
24.2597 + }
24.2598 + }
24.2599 +
24.2600 + // construct a regular expression of following form. Let "1", "2", "3", "4"
24.2601 + // be the keys:
24.2602 + // "^
24.2603 + // thus if 4 is matched five groups will be created
24.2604 + String[] arr = new String[list.size()];
24.2605 + String[] pattern = new String[arr.length];
24.2606 +
24.2607 + int i = 0;
24.2608 + Iterator it = list.iterator();
24.2609 +
24.2610 + while (it.hasNext()) {
24.2611 + String[] pair = (String[]) it.next();
24.2612 + arr[i] = pair[1].intern(); // name of the track
24.2613 + pattern[i] = pair[0]; // original object
24.2614 + i++;
24.2615 + }
24.2616 +
24.2617 + synchronized (TRANS_LOCK) {
24.2618 + // last check
24.2619 + if (arr.length == 0) {
24.2620 + transExp = null;
24.2621 + } else {
24.2622 + transExp = re;
24.2623 + transExp.init(pattern, arr);
24.2624 + }
24.2625 +
24.2626 + transLoader = set;
24.2627 + }
24.2628 + }
24.2629 +
24.2630 + /**
24.2631 + * Load single translation file.
24.2632 + * @param resource URL identifiing transaction table
24.2633 + * @param results will be filled with String[2]
24.2634 + */
24.2635 + private static void loadTranslationFile(RE re, BufferedReader reader, Set<String[]> results)
24.2636 + throws IOException {
24.2637 + for (;;) {
24.2638 + String line = reader.readLine();
24.2639 +
24.2640 + if (line == null) {
24.2641 + break;
24.2642 + }
24.2643 +
24.2644 + if ((line.length() == 0) || line.startsWith("#")) { // NOI18N
24.2645 +
24.2646 + continue;
24.2647 + }
24.2648 +
24.2649 + String[] pair = re.readPair(line);
24.2650 +
24.2651 + if (pair == null) {
24.2652 + throw new java.io.InvalidObjectException("Line is invalid: " + line);
24.2653 + }
24.2654 +
24.2655 + results.add(pair);
24.2656 + }
24.2657 + }
24.2658 +
24.2659 + /** This method merges two images into the new one. The second image is drawn
24.2660 + * over the first one with its top-left corner at x, y. Images need not be of the same size.
24.2661 + * New image will have a size of max(second image size + top-left corner, first image size).
24.2662 + * Method is used mostly when second image contains transparent pixels (e.g. for badging).
24.2663 + * @param image1 underlying image
24.2664 + * @param image2 second image
24.2665 + * @param x x position of top-left corner
24.2666 + * @param y y position of top-left corner
24.2667 + * @return new merged image
24.2668 + * @deprecated Use {@link ImageUtilities#mergeImages}.
24.2669 + */
24.2670 + @Deprecated
24.2671 + public static final Image mergeImages(Image image1, Image image2, int x, int y) {
24.2672 + return ImageUtilities.mergeImages(image1, image2, x, y);
24.2673 + }
24.2674 +
24.2675 + /**
24.2676 + * Loads an image from the specified resource ID. The image is loaded using the "system" classloader registered in
24.2677 + * Lookup.
24.2678 + * @param resourceID resource path of the icon (no initial slash)
24.2679 + * @return icon's Image, or null, if the icon cannot be loaded.
24.2680 + * @deprecated Use {@link ImageUtilities#loadImage(java.lang.String)}.
24.2681 + */
24.2682 + @Deprecated
24.2683 + public static final Image loadImage(String resourceID) {
24.2684 + return ImageUtilities.loadImage(resourceID);
24.2685 + }
24.2686 +
24.2687 + /**
24.2688 + * Converts given icon to a {@link java.awt.Image}.
24.2689 + *
24.2690 + * @param icon {@link javax.swing.Icon} to be converted.
24.2691 + * @since 7.3
24.2692 + * @deprecated Use {@link ImageUtilities#icon2Image}.
24.2693 + */
24.2694 + @Deprecated
24.2695 + public static final Image icon2Image(Icon icon) {
24.2696 + return ImageUtilities.icon2Image(icon);
24.2697 + }
24.2698 +
24.2699 + /** Builds a popup menu from actions for provided context specified by
24.2700 + * <code>Lookup</code>.
24.2701 + * Takes list of actions and for actions whic are instances of
24.2702 + * <code>ContextAwareAction</code> creates and uses the context aware instance.
24.2703 + * Then gets the action presenter or simple menu item for the action to the
24.2704 + * popup menu for each action (or separator for each 'lonely' null array member).
24.2705 + *
24.2706 + * @param actions array of actions to build menu for. Can contain null
24.2707 + * elements, they will be replaced by separators
24.2708 + * @param context the context for which the popup is build
24.2709 + * @return the constructed popup menu
24.2710 + * @see ContextAwareAction
24.2711 + * @since 3.29
24.2712 + */
24.2713 + public static JPopupMenu actionsToPopup(Action[] actions, Lookup context) {
24.2714 + // keeps actions for which was menu item created already (do not add them twice)
24.2715 + Set<Action> counted = new HashSet<Action>();
24.2716 + // components to be added (separators are null)
24.2717 + List<Component> components = new ArrayList<Component>();
24.2718 +
24.2719 + for (Action action : actions) {
24.2720 + if (action != null && counted.add(action)) {
24.2721 + // switch to replacement action if there is some
24.2722 + if (action instanceof ContextAwareAction) {
24.2723 + Action contextAwareAction = ((ContextAwareAction) action).createContextAwareInstance(context);
24.2724 + if (contextAwareAction == null) {
24.2725 + Logger.getLogger(Utilities.class.getName()).warning(
24.2726 + "ContextAwareAction.createContextAwareInstance(context) returns null. That is illegal!" // NOI18N
24.2727 + + " action=" + action + ", context=" + context); // NOI18N
24.2728 + } else {
24.2729 + action = contextAwareAction;
24.2730 + }
24.2731 + }
24.2732 +
24.2733 + JMenuItem item;
24.2734 + if (action instanceof Presenter.Popup) {
24.2735 + item = ((Presenter.Popup) action).getPopupPresenter();
24.2736 + if (item == null) {
24.2737 + Logger.getLogger(Utilities.class.getName()).warning(
24.2738 + "findContextMenuImpl, getPopupPresenter returning null for " + action); // NOI18N
24.2739 + continue;
24.2740 + }
24.2741 + } else {
24.2742 + // We need to correctly handle mnemonics with '&' etc.
24.2743 + item = ActionPresenterProvider.getDefault().createPopupPresenter(action);
24.2744 + }
24.2745 +
24.2746 + for (Component c : ActionPresenterProvider.getDefault().convertComponents(item)) {
24.2747 + if (c instanceof JSeparator) {
24.2748 + components.add(null);
24.2749 + } else {
24.2750 + components.add(c);
24.2751 + }
24.2752 + }
24.2753 + } else {
24.2754 + components.add(null);
24.2755 + }
24.2756 + }
24.2757 +
24.2758 + // Now create actual menu. Strip adjacent, leading, and trailing separators.
24.2759 + JPopupMenu menu = ActionPresenterProvider.getDefault().createEmptyPopup();
24.2760 + boolean nonempty = false; // has anything been added yet?
24.2761 + boolean pendingSep = false; // should there be a separator before any following item?
24.2762 + for (Component c : components) {
24.2763 + if (c == null) {
24.2764 + pendingSep = nonempty;
24.2765 + } else {
24.2766 + nonempty = true;
24.2767 + if (pendingSep) {
24.2768 + pendingSep = false;
24.2769 + menu.addSeparator();
24.2770 + }
24.2771 + menu.add(c);
24.2772 + }
24.2773 + }
24.2774 + return menu;
24.2775 + }
24.2776 +
24.2777 + /** Builds a popup menu for provided component. It retrieves context
24.2778 + * (lookup) from provided component instance or one of its parent
24.2779 + * (it searches up to the hierarchy for <code>Lookup.Provider</code> instance).
24.2780 + * If none of the components is <code>Lookup.Provider</code> instance, then
24.2781 + * it is created context which is fed with composite ActionMap which delegates
24.2782 + * to all components up to hierarchy started from the specified one.
24.2783 + * Then <code>actionsToPopup(Action[], Lookup)</code>} is called with
24.2784 + * the found <code>Lookup</code> instance, which actually creates a popup menu.
24.2785 + *
24.2786 + * @param actions array of actions to build menu for. Can contain null
24.2787 + * elements, they will be replaced by separators
24.2788 + * @param component a component in which to search for a context
24.2789 + * @return the constructed popup menu
24.2790 + * @see Lookup.Provider
24.2791 + * @see #actionsToPopup(Action[], Lookup)
24.2792 + * @since 3.29
24.2793 + */
24.2794 + public static javax.swing.JPopupMenu actionsToPopup(Action[] actions, java.awt.Component component) {
24.2795 + Lookup lookup = null;
24.2796 +
24.2797 + for (Component c = component; c != null; c = c.getParent()) {
24.2798 + if (c instanceof Lookup.Provider) {
24.2799 + lookup = ((Lookup.Provider) c).getLookup();
24.2800 +
24.2801 + if (lookup != null) {
24.2802 + break;
24.2803 + }
24.2804 + }
24.2805 + }
24.2806 +
24.2807 + if (lookup == null) {
24.2808 + // Fallback to composite action map, even it is questionable,
24.2809 + // whether we should support component which is not (nor
24.2810 + // none of its parents) lookup provider.
24.2811 + UtilitiesCompositeActionMap map = new UtilitiesCompositeActionMap(component);
24.2812 + lookup = org.openide.util.lookup.Lookups.singleton(map);
24.2813 + }
24.2814 +
24.2815 + return actionsToPopup(actions, lookup);
24.2816 + }
24.2817 +
24.2818 + /**
24.2819 + * Load a menu sequence from a lookup path.
24.2820 + * Any {@link Action} instances are returned as is;
24.2821 + * any {@link JSeparator} instances are translated to nulls.
24.2822 + * Warnings are logged for any other instances.
24.2823 + * @param path a path as given to {@link Lookups#forPath}, generally a layer folder name
24.2824 + * @return a list of actions interspersed with null separators
24.2825 + * @since org.openide.util 7.14
24.2826 + */
24.2827 + public static List<? extends Action> actionsForPath(String path) {
24.2828 + List<Action> actions = new ArrayList<Action>();
24.2829 + for (Lookup.Item<Object> item : Lookups.forPath(path).lookupResult(Object.class).allItems()) {
24.2830 + if (Action.class.isAssignableFrom(item.getType())) {
24.2831 + Object instance = item.getInstance();
24.2832 + if (instance != null) {
24.2833 + actions.add((Action) instance);
24.2834 + }
24.2835 + } else if (JSeparator.class.isAssignableFrom(item.getType())) {
24.2836 + actions.add(null);
24.2837 + } else {
24.2838 + Logger.getLogger(Utilities.class.getName()).warning("Unrecognized object of " + item.getType() + " found in actions path " + path);
24.2839 + }
24.2840 + }
24.2841 + return actions;
24.2842 + }
24.2843 +
24.2844 + /**
24.2845 + * Global context for actions. Toolbar, menu or any other "global"
24.2846 + * action presenters shall operate in this context.
24.2847 + * Presenters for context menu items should <em>not</em> use
24.2848 + * this method; instead see {@link ContextAwareAction}.
24.2849 + * @see ContextGlobalProvider
24.2850 + * @see ContextAwareAction
24.2851 + * @see <a href="http://wiki.netbeans.org/DevFaqActionContextSensitive">NetBeans FAQ</a>
24.2852 + * @return the context for actions
24.2853 + * @since 4.10
24.2854 + */
24.2855 + public static Lookup actionsGlobalContext() {
24.2856 + synchronized (ContextGlobalProvider.class) {
24.2857 + if (global != null) {
24.2858 + return global;
24.2859 + }
24.2860 + }
24.2861 +
24.2862 + ContextGlobalProvider p = Lookup.getDefault().lookup(ContextGlobalProvider.class);
24.2863 + Lookup l = (p == null) ? Lookup.EMPTY : p.createGlobalContext();
24.2864 +
24.2865 + synchronized (ContextGlobalProvider.class) {
24.2866 + if (global == null) {
24.2867 + global = l;
24.2868 + }
24.2869 +
24.2870 + return global;
24.2871 + }
24.2872 + }
24.2873 +
24.2874 + //
24.2875 + // end of actions stuff
24.2876 + //
24.2877 +
24.2878 + /**
24.2879 + * Loads an image based on resource path.
24.2880 + * Exactly like {@link #loadImage(String)} but may do a localized search.
24.2881 + * For example, requesting <samp>org/netbeans/modules/foo/resources/foo.gif</samp>
24.2882 + * might actually find <samp>org/netbeans/modules/foo/resources/foo_ja.gif</samp>
24.2883 + * or <samp>org/netbeans/modules/foo/resources/foo_mybranding.gif</samp>.
24.2884 + *
24.2885 + * <p>Caching of loaded images can be used internally to improve performance.
24.2886 + *
24.2887 + * @since 3.24
24.2888 + * @deprecated Use {@link ImageUtilities#loadImage(java.lang.String, boolean)}.
24.2889 + */
24.2890 + @Deprecated
24.2891 + public static final Image loadImage(String resource, boolean localized) {
24.2892 + return ImageUtilities.loadImage(resource, localized);
24.2893 + }
24.2894 +
24.2895 + /**
24.2896 + * Returns a cursor with an arrow and an hourglass (or stop watch) badge,
24.2897 + * to be used when a component is busy but the UI is still responding to the user.
24.2898 + *
24.2899 + * Similar to the predefined {@link Cursor#WAIT_CURSOR}, but has an arrow to indicate
24.2900 + * a still-responsive UI.
24.2901 + *
24.2902 + * <p>Typically you will set the cursor only temporarily:
24.2903 + *
24.2904 + * <pre>
24.2905 + * <font class="comment">// code is running in other then event dispatch thread</font>
24.2906 + * currentComponent.setCursor(Utilities.createProgressCursor(currentComponent));
24.2907 + * <font class="keyword">try</font> {
24.2908 + * <font class="comment">// perform some work in other than event dispatch thread
24.2909 + * // (do not block UI)</font>
24.2910 + * } <font class="keyword">finally</font> {
24.2911 + * currentComponent.setCursor(<font class="constant">null</font>);
24.2912 + * }
24.2913 + * </pre>
24.2914 + *
24.2915 + * <p>This implementation provides one cursor for all Mac systems, one for all
24.2916 + * Unix systems (regardless of window manager), and one for all other systems
24.2917 + * including Windows. Note: The cursor does not have to look native in some
24.2918 + * cases on some platforms!
24.2919 + *
24.2920 + * @param component the non-null component that will use the progress cursor
24.2921 + * @return a progress cursor (Unix, Windows or Mac)
24.2922 + *
24.2923 + * @since 3.23
24.2924 + */
24.2925 + public static final Cursor createProgressCursor(Component component) {
24.2926 + // refuse null component
24.2927 + if (component == null) {
24.2928 + throw new NullPointerException("Given component is null"); //NOI18N
24.2929 + }
24.2930 +
24.2931 + Image image = null;
24.2932 +
24.2933 + // First check for Mac because its part of the Unix_Mask
24.2934 + if (isMac()) {
24.2935 + image = ImageUtilities.loadImage("org/openide/util/progress-cursor-mac.gif"); //NOI18N
24.2936 + } else if (isUnix()) {
24.2937 + image = ImageUtilities.loadImage("org/openide/util/progress-cursor-motif.gif"); //NOI18N
24.2938 + }
24.2939 + // All other OS, including Windows, use Windows cursor
24.2940 + else {
24.2941 + image = ImageUtilities.loadImage("org/openide/util/progress-cursor-win.gif"); //NOI18N
24.2942 + }
24.2943 +
24.2944 + return createCustomCursor(component, image, "PROGRESS_CURSOR"); //NOI18N
24.2945 + }
24.2946 +
24.2947 + // added to fix issue #30665 (bad size on linux)
24.2948 + public static Cursor createCustomCursor(Component component, Image icon, String name) {
24.2949 + Toolkit t = component.getToolkit();
24.2950 + Dimension d = t.getBestCursorSize(16, 16);
24.2951 + Image i = icon;
24.2952 +
24.2953 + if (d.width != icon.getWidth(null)) {
24.2954 + if (((d.width) == 0) && (d.height == 0)) {
24.2955 + // system doesn't support custom cursors, falling back
24.2956 + return Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR);
24.2957 + }
24.2958 +
24.2959 + // need to resize the icon
24.2960 + Image empty = ImageUtilities.createBufferedImage(d.width, d.height);
24.2961 + i = ImageUtilities.mergeImages(icon, empty, 0, 0);
24.2962 + }
24.2963 +
24.2964 + return t.createCustomCursor(i, new Point(1, 1), name);
24.2965 + }
24.2966 +
24.2967 + /** Attaches asynchronous init job to given component.
24.2968 + * {@link AsyncGUIJob#construct()} will be called after first
24.2969 + * paint, when paint event arrives. Later, {@link AsyncGUIJob#finished()}
24.2970 + * will be called according to the rules of the <code>AsyncGUIJob</code> interface.
24.2971 + *
24.2972 + * Useful for components that have slower initialization phase, component
24.2973 + * can benefit from more responsive behaviour during init.
24.2974 + *
24.2975 + * @param comp4Init Regular component in its pre-inited state, state in which
24.2976 + * component will be shown between first paint and init completion.
24.2977 + * @param initJob Initialization job to be called asynchronously. Job can
24.2978 + * optionally implement {@link Cancellable}
24.2979 + * interface for proper cancel logic. Cancel method will be called
24.2980 + * when component stops to be showing during job's progress.
24.2981 + * See {@link java.awt.Component#isShowing}
24.2982 + *
24.2983 + * @since 3.36
24.2984 + */
24.2985 + public static final void attachInitJob(Component comp4Init, AsyncGUIJob initJob) {
24.2986 + new AsyncInitSupport(comp4Init, initJob);
24.2987 + }
24.2988 +
24.2989 + /**
24.2990 + * Convert a file to a matching <code>file:</code> URL.
24.2991 + * @param f a file (absolute only)
24.2992 + * @return a URL using the <code>file</code> protocol
24.2993 + * @throws MalformedURLException for no good reason
24.2994 + * @see #toFile
24.2995 + * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=29711">Issue #29711</a>
24.2996 + * @since 3.26
24.2997 + * @deprecated Use {@link File#toURI} and {@link URI#toURL} instead under JDK 1.4.
24.2998 + * ({@link File#toURL} is buggy in JDK 1.3 and the bugs are not fixed in JDK 1.4.)
24.2999 + */
24.3000 + @Deprecated
24.3001 + public static URL toURL(File f) throws MalformedURLException {
24.3002 + if (f == null) {
24.3003 + throw new NullPointerException();
24.3004 + }
24.3005 +
24.3006 + if (!f.isAbsolute()) {
24.3007 + throw new IllegalArgumentException("Relative path: " + f); // NOI18N
24.3008 + }
24.3009 +
24.3010 + URI uri = f.toURI();
24.3011 +
24.3012 + return uri.toURL();
24.3013 + }
24.3014 +
24.3015 + /**
24.3016 + * Convert a <code>file:</code> URL to a matching file.
24.3017 + * <p>You may not use a URL generated from a file on a different
24.3018 + * platform, as file name conventions may make the result meaningless
24.3019 + * or even unparsable.
24.3020 + * @param u a URL with the <code>file</code> protocol
24.3021 + * @return an absolute file it points to, or <code>null</code> if the URL
24.3022 + * does not seem to point to a file at all
24.3023 + * @see #toURL
24.3024 + * @see <a href="http://www.netbeans.org/issues/show_bug.cgi?id=29711">Issue #29711</a>
24.3025 + * @since 3.26
24.3026 + * @deprecated Use {@link URI#URI(String)} and {@link File#File(URI)} instead under JDK 1.4.
24.3027 + * (There was no proper equivalent under JDK 1.3.)
24.3028 + */
24.3029 + @Deprecated
24.3030 + public static File toFile(URL u) {
24.3031 + if (u == null) {
24.3032 + throw new NullPointerException();
24.3033 + }
24.3034 +
24.3035 + try {
24.3036 + URI uri = new URI(u.toExternalForm());
24.3037 +
24.3038 + return new File(uri);
24.3039 + } catch (URISyntaxException use) {
24.3040 + // malformed URL
24.3041 + return null;
24.3042 + } catch (IllegalArgumentException iae) {
24.3043 + // not a file: URL
24.3044 + return null;
24.3045 + }
24.3046 + }
24.3047 +
24.3048 + /** Interfaces for communication between Utilities.translate and regular
24.3049 + * expression impl.
24.3050 + *
24.3051 + * Order of methods is:
24.3052 + * readPair few times
24.3053 + * init once
24.3054 + * convert many times
24.3055 + */
24.3056 + static interface RE {
24.3057 + public void init(String[] original, String[] newversion);
24.3058 +
24.3059 + public String convert(String pattern);
24.3060 +
24.3061 + /** Parses line of text to two parts: the key and the rest
24.3062 + */
24.3063 + public String[] readPair(String line);
24.3064 + }
24.3065 +
24.3066 + /** Exception indicating that a given list could not be partially-ordered.
24.3067 + * @see #partialSort
24.3068 + * @deprecated Used only by the deprecated partialSort
24.3069 + */
24.3070 + @Deprecated
24.3071 + public static class UnorderableException extends RuntimeException {
24.3072 + static final long serialVersionUID = 6749951134051806661L;
24.3073 + private Collection unorderable;
24.3074 + private Map deps;
24.3075 +
24.3076 + /** Create a new unorderable-list exception with no detail message.
24.3077 + * @param unorderable a collection of list elements which could not be ordered
24.3078 + * (because there was some sort of cycle)
24.3079 + * @param deps dependencies associated with the list; a map from list elements
24.3080 + * to sets of list elements which that element must appear after
24.3081 + */
24.3082 + public UnorderableException(Collection unorderable, Map deps) {
24.3083 + super( /* "Cannot be ordered: " + unorderable */
24.3084 + ); // NOI18N
24.3085 + this.unorderable = unorderable;
24.3086 + this.deps = deps;
24.3087 + }
24.3088 +
24.3089 + /** Create a new unorderable-list exception with a specified detail message.
24.3090 + * @param message the detail message
24.3091 + * @param unorderable a collection of list elements which could not be ordered
24.3092 + * (because there was some sort of cycle)
24.3093 + * @param deps dependencies associated with the list; a map from list elements
24.3094 + * to sets of list elements which that element must appear after
24.3095 + */
24.3096 + public UnorderableException(String message, Collection unorderable, Map deps) {
24.3097 + super(message);
24.3098 + this.unorderable = unorderable;
24.3099 + this.deps = deps;
24.3100 + }
24.3101 +
24.3102 + /** Get the unorderable elements.
24.3103 + * @return the elements
24.3104 + * @see Utilities.UnorderableException#Utilities.UnorderableException(Collection,Map)
24.3105 + */
24.3106 + public Collection getUnorderable() {
24.3107 + return unorderable;
24.3108 + }
24.3109 +
24.3110 + /** Get the dependencies.
24.3111 + * @return the dependencies
24.3112 + * @see Utilities.UnorderableException#Utilities.UnorderableException(Collection,Map)
24.3113 + */
24.3114 + public Map getDeps() {
24.3115 + return deps;
24.3116 + }
24.3117 + }
24.3118 +}
25.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
25.2 +++ b/openide.util/src/org/openide/util/actions/ActionInvoker.java Fri Jan 22 10:02:41 2010 -0500
25.3 @@ -0,0 +1,187 @@
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.actions;
25.46 +
25.47 +import java.awt.event.ActionEvent;
25.48 +import java.beans.PropertyChangeListener;
25.49 +import javax.swing.Action;
25.50 +import org.openide.util.Lookup;
25.51 +import org.openide.util.RequestProcessor;
25.52 +import org.openide.util.actions.SystemAction;
25.53 +import org.openide.util.lookup.ServiceProvider;
25.54 +
25.55 +/** A mixture of a utility class allowing to invoke actions and also a
25.56 + * <a href="http://wiki.apidesign.org/wiki/CodeInjection">
25.57 + * code injection mechanism</a> to allow overall system to be aware of invoked
25.58 + * actions.
25.59 + * <p>
25.60 + * Callers shall use the {@link #invokeAction(javax.swing.Action, java.awt.event.ActionEvent, boolean, java.lang.Runnable)}
25.61 + * method.
25.62 + * <p>
25.63 + * Implementors register an implementation of this class via {@link ServiceProvider}
25.64 + * annotation.
25.65 + *
25.66 + * @since 8.1
25.67 + */
25.68 +public abstract class ActionInvoker extends Object {
25.69 + /** thread to run actions in */
25.70 + private static final RequestProcessor RP = new RequestProcessor("Module-Actions", Integer.MAX_VALUE); // NOI18N
25.71 +
25.72 + /** Subclass constructor. */
25.73 + protected ActionInvoker() {}
25.74 +
25.75 + /** An infrastructure method that handles invocation of an an action.
25.76 + * @param action the action to invoke
25.77 + * @param ev the event used during invocation
25.78 + */
25.79 + protected abstract void invokeAction(Action action, ActionEvent ev);
25.80 +
25.81 + /** Invokes the action in the currently registered ActionsBridge.
25.82 + *
25.83 + * @param action the action that is to be invoked
25.84 + * @param ev the event used to invoke the action
25.85 + * @param asynchronous shall the execution be performed in a background thread?
25.86 + * @param invoker the actual code that shall be performed to "run" the action. If null, action.actionPerformed(ev) will be called
25.87 + */
25.88 + public static void invokeAction(Action action, ActionEvent ev, boolean asynchronous, final Runnable invoker) {
25.89 + ActionRunnable r = new ActionRunnable(ev, action, asynchronous) {
25.90 + @Override
25.91 + protected void run() {
25.92 + if (invoker == null) {
25.93 + action.actionPerformed(ev);
25.94 + } else {
25.95 + invoker.run();
25.96 + }
25.97 + }
25.98 + };
25.99 + doPerformAction(action, r);
25.100 + }
25.101 +
25.102 + private static void doPerformAction(Action action, final ActionInvoker.ActionRunnable r) {
25.103 + assert java.awt.EventQueue.isDispatchThread() : "Action " + action.getClass().getName() +
25.104 + " may not be invoked from the thread " + Thread.currentThread().getName() +
25.105 + ", only the event queue: http://www.netbeans.org/download/4_1/javadoc/OpenAPIs/apichanges.html#actions-event-thread";
25.106 +
25.107 + if (r.async && !r.needsToBeSynchronous()) {
25.108 + Runnable r2 = new Runnable() {
25.109 + public void run() {
25.110 + r.doRun();
25.111 + }
25.112 + };
25.113 +
25.114 + RP.post(r2);
25.115 + } else {
25.116 + r.run();
25.117 + }
25.118 + }
25.119 +
25.120 + /** Special class that can be passed to invokeAction and delegates
25.121 + * to correct values
25.122 + */
25.123 + private static abstract class ActionRunnable implements Action {
25.124 + final ActionEvent ev;
25.125 + final Action action;
25.126 + final boolean async;
25.127 +
25.128 + public ActionRunnable(ActionEvent ev, SystemAction action, boolean async) {
25.129 + this(ev, (Action)action, async);
25.130 + }
25.131 + public ActionRunnable(ActionEvent ev, Action action, boolean async) {
25.132 + this.ev = ev;
25.133 + this.action = action;
25.134 + this.async = async;
25.135 + }
25.136 +
25.137 + public static ActionRunnable create(ActionEvent ev, Action a, boolean async) {
25.138 + return new ActionRunnable(ev, a, async) {
25.139 + @Override
25.140 + protected void run() {
25.141 + action.actionPerformed(ev);
25.142 + }
25.143 + };
25.144 + }
25.145 +
25.146 + public final boolean needsToBeSynchronous() {
25.147 + return "waitFinished".equals(ev.getActionCommand()); // NOI18N
25.148 + }
25.149 +
25.150 + public final void doRun() {
25.151 + ActionInvoker bridge = Lookup.getDefault().lookup(ActionInvoker.class);
25.152 + if (bridge != null) {
25.153 + bridge.invokeAction (this, ev);
25.154 + } else {
25.155 + this.actionPerformed(ev);
25.156 + }
25.157 + }
25.158 +
25.159 + protected abstract void run();
25.160 +
25.161 + public final void actionPerformed(ActionEvent e) {
25.162 + run();
25.163 + }
25.164 +
25.165 + public final void addPropertyChangeListener(PropertyChangeListener listener) {
25.166 + throw new UnsupportedOperationException();
25.167 + }
25.168 +
25.169 + public final Object getValue(String key) {
25.170 + return action.getValue(key);
25.171 + }
25.172 +
25.173 + public final boolean isEnabled() {
25.174 + return action.isEnabled();
25.175 + }
25.176 +
25.177 + public final void putValue(String key, Object value) {
25.178 + throw new UnsupportedOperationException();
25.179 + }
25.180 +
25.181 + public final void removePropertyChangeListener(PropertyChangeListener listener) {
25.182 + throw new UnsupportedOperationException();
25.183 + }
25.184 +
25.185 + public final void setEnabled(boolean b) {
25.186 + throw new UnsupportedOperationException();
25.187 + }
25.188 + }
25.189 + // end of ActionRunnable
25.190 +}
26.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
26.2 +++ b/openide.util/src/org/openide/util/actions/ActionPresenterProvider.java Fri Jan 22 10:02:41 2010 -0500
26.3 @@ -0,0 +1,128 @@
26.4 +/*
26.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
26.6 + *
26.7 + * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
26.8 + *
26.9 + * The contents of this file are subject to the terms of either the GNU
26.10 + * General Public License Version 2 only ("GPL") or the Common
26.11 + * Development and Distribution License("CDDL") (collectively, the
26.12 + * "License"). You may not use this file except in compliance with the
26.13 + * License. You can obtain a copy of the License at
26.14 + * http://www.netbeans.org/cddl-gplv2.html
26.15 + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
26.16 + * specific language governing permissions and limitations under the
26.17 + * License. When distributing the software, include this License Header
26.18 + * Notice in each file and include the License file at
26.19 + * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
26.20 + * particular file as subject to the "Classpath" exception as provided
26.21 + * by Sun in the GPL Version 2 section of the License file that
26.22 + * accompanied this code. If applicable, add the following below the
26.23 + * License Header, with the fields enclosed by brackets [] replaced by
26.24 + * your own identifying information:
26.25 + * "Portions Copyrighted [year] [name of copyright owner]"
26.26 + *
26.27 + * Contributor(s):
26.28 + *
26.29 + * The Original Software is NetBeans. The Initial Developer of the Original
26.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
26.31 + * Microsystems, Inc. All Rights Reserved.
26.32 + *
26.33 + * If you wish your version of this file to be governed by only the CDDL
26.34 + * or only the GPL Version 2, indicate your decision by adding
26.35 + * "[Contributor] elects to include this software in this distribution
26.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
26.37 + * single choice of license, a recipient has the option to distribute
26.38 + * your version of this file under either the CDDL, the GPL Version 2 or
26.39 + * to extend the choice of license to its licensees as provided above.
26.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
26.41 + * Version 2 license, then the option applies only if the new code is
26.42 + * made subject to such option by the copyright holder.
26.43 + */
26.44 +
26.45 +package org.openide.util.actions;
26.46 +
26.47 +import java.awt.Component;
26.48 +import javax.swing.Action;
26.49 +import javax.swing.JButton;
26.50 +import javax.swing.JMenuItem;
26.51 +import javax.swing.JPopupMenu;
26.52 +import org.openide.util.Lookup;
26.53 +
26.54 +/** Provider of action presentations. Based on type of the action
26.55 + * should be able to derive its menu, popup menu and toolbar
26.56 + * presenter.
26.57 + * <P>
26.58 + * In order to provide greater flexibility this is made as a pluggable component
26.59 + * to allow other parts of the system to provide more enhanced
26.60 + * visualizations.
26.61 + * @since 8.1
26.62 + */
26.63 +public abstract class ActionPresenterProvider extends Object {
26.64 + /** Gets the default implementation from lookup.
26.65 + * @return the presenter
26.66 + */
26.67 + public static ActionPresenterProvider getDefault () {
26.68 + ActionPresenterProvider ap = Lookup.getDefault().lookup(ActionPresenterProvider.class);
26.69 + return ap == null ? new Default () : ap;
26.70 + }
26.71 +
26.72 + /** Subclass constructor. */
26.73 + protected ActionPresenterProvider() {}
26.74 +
26.75 + /** Creates a default empty implementation of popup menu.
26.76 + * @return popup menu
26.77 + */
26.78 + public abstract JPopupMenu createEmptyPopup();
26.79 +
26.80 + /** Creates a menu item that can present this action in a {@link javax.swing.JMenu}.
26.81 + * @param action the action to represent
26.82 + * @return the representation for this action
26.83 + */
26.84 + public abstract JMenuItem createMenuPresenter (Action action);
26.85 +
26.86 + /** Get a menu item that can present this action in a {@link javax.swing.JPopupMenu}.
26.87 + * @param action the action to represent
26.88 + * @return the representation for this action
26.89 + */
26.90 + public abstract JMenuItem createPopupPresenter (Action action);
26.91 +
26.92 + /** Get a component that can present this action in a {@link javax.swing.JToolBar}.
26.93 + * @param action the action to represent
26.94 + * @return the representation for this action
26.95 + */
26.96 + public abstract Component createToolbarPresenter (Action action);
26.97 +
26.98 + /**
26.99 + * Used for implementation of <a href="@org-openide-awt@/org/openide/awt/DynamicMenuContent.html"><code>DynamicMenuContent</code></a>.
26.100 + * @param comp a component
26.101 + * @return zero or more components to display in its place
26.102 + */
26.103 + public abstract Component[] convertComponents(Component comp);
26.104 +
26.105 + //
26.106 + // Default implementation of the the presenter
26.107 + //
26.108 +
26.109 + private static final class Default extends ActionPresenterProvider {
26.110 +
26.111 + public JMenuItem createMenuPresenter(Action action) {
26.112 + return new JMenuItem(action);
26.113 + }
26.114 +
26.115 + public JMenuItem createPopupPresenter(Action action) {
26.116 + return new JMenuItem(action);
26.117 + }
26.118 +
26.119 + public Component createToolbarPresenter(Action action) {
26.120 + return new JButton(action);
26.121 + }
26.122 +
26.123 + public JPopupMenu createEmptyPopup() {
26.124 + return new JPopupMenu();
26.125 + }
26.126 +
26.127 + public Component[] convertComponents(Component comp) {
26.128 + return new Component[] {comp};
26.129 + }
26.130 + }
26.131 +}
27.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
27.2 +++ b/openide.util/src/org/openide/util/actions/BooleanStateAction.java Fri Jan 22 10:02:41 2010 -0500
27.3 @@ -0,0 +1,120 @@
27.4 +/*
27.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
27.6 + *
27.7 + * Copyright 1997-2009 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 + * Contributor(s):
27.28 + *
27.29 + * The Original Software is NetBeans. The Initial Developer of the Original
27.30 + * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
27.31 + * Microsystems, Inc. All Rights Reserved.
27.32 + *
27.33 + * If you wish your version of this file to be governed by only the CDDL
27.34 + * or only the GPL Version 2, indicate your decision by adding
27.35 + * "[Contributor] elects to include this software in this distribution
27.36 + * under the [CDDL or GPL Version 2] license." If you do not indicate a
27.37 + * single choice of license, a recipient has the option to distribute
27.38 + * your version of this file under either the CDDL, the GPL Version 2 or
27.39 + * to extend the choice of license to its licensees as provided above.
27.40 + * However, if you add GPL Version 2 code and therefore, elected the GPL
27.41 + * Version 2 license, then the option applies only if the new code is
27.42 + * made subject to such option by the copyright holder.
27.43 + */
27.44 +package org.openide.util.actions;
27.45 +
27.46 +
27.47 +/** An action that can be toggled on or off.
27.48 +* The actual "performing" of the action is the toggle itself, so
27.49 +* this action should be used by listening to the {@link #PROP_BOOLEAN_STATE} property.
27.50 +* <p>The default value of the state is <code>true</code> (on).
27.51 +*
27.52 +*
27.53 +* @author Ian Formanek, Petr Hamernik
27.54 +*/
27.55 +public abstract class BooleanStateAction extends SystemAction implements Presenter.Menu, Presenter.Popup,
27.56 + Presenter.Toolbar {
27.57 + /** serialVersionUID */
27.58 + static final long serialVersionUID = 6394800019181426199L;
27.59 +
27.60 + /** Name of property hold the state of the action. */
27.61 + public static final String PROP_BOOLEAN_STATE = "booleanState"; // NOI18N
27.62 +
27.63 + /* Returns a JMenuItem that presents the Action, that implements this
27.64 + * interface, in a MenuBar.
27.65 + * @return the JMenuItem representation for the Action
27.66 + */
27.67 + public javax.swing.JMenuItem getMenuPresenter() {
27.68 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createMenuPresenter(this);
27.69 + }
27.70 +
27.71 + /* Returns a JMenuItem that presents the Action, that implements this
27.72 + * interface, in a Popup Menu.
27.73 + * The default implmentation returns the same JMenuItem as the getMenuPresenter.
27.74 + * @return the JMenuItem representation for the Action
27.75 + */
27.76 + public javax.swing.JMenuItem getPopupPresenter() {
27.77 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createPopupPresenter(this);
27.78 + }
27.79 +
27.80 + /* Returns a Component that presents the Action, that implements this
27.81 + * interface, in a ToolBar.
27.82 + * @return the Component representation for the Action
27.83 + */
27.84 + public java.awt.Component getToolbarPresenter() {
27.85 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createToolbarPresenter(this);
27.86 + }
27.87 +
27.88 + /** Get the current state.
27.89 + * @return <code>true</code> if on
27.90 + */
27.91 + public boolean getBooleanState() {
27.92 + return getProperty(PROP_BOOLEAN_STATE).equals(Boolean.TRUE);
27.93 + }
27.94 +
27.95 + /** Set the current state.
27.96 + * Fires a change event, which should be used to affect other components when
27.97 + * its state is toggled.
27.98 + * @param value <code>true</code> to turn on, <code>false</code> to turn off
27.99 + */
27.100 + public void setBooleanState(boolean value) {
27.101 + Boolean newValue = value ? Boolean.TRUE : Boolean.FALSE;
27.102 + Boolean oldValue = (Boolean) putProperty(PROP_BOOLEAN_STATE, newValue);
27.103 +
27.104 + firePropertyChange(PROP_BOOLEAN_STATE, oldValue, newValue);
27.105 + }
27.106 +
27.107 + /* Initializes its own properties (and let superclass initialize
27.108 + * too).
27.109 + */
27.110 + protected void initialize() {
27.111 + putProperty(PROP_BOOLEAN_STATE, Boolean.TRUE);
27.112 + super.initialize();
27.113 + }
27.114 +
27.115 + /* Implementation of method of javax.swing.Action interface.
27.116 + * Changes the boolean state.
27.117 + *
27.118 + * @param ev ignored
27.119 + */
27.120 + public void actionPerformed(java.awt.event.ActionEvent ev) {
27.121 + setBooleanState(!getBooleanState());
27.122 + }
27.123 +}
28.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
28.2 +++ b/openide.util/src/org/openide/util/actions/CallableSystemAction.java Fri Jan 22 10:02:41 2010 -0500
28.3 @@ -0,0 +1,164 @@
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 +
28.45 +package org.openide.util.actions;
28.46 +
28.47 +import java.awt.Toolkit;
28.48 +import java.awt.event.ActionEvent;
28.49 +import java.util.Set;
28.50 +import java.util.logging.Logger;
28.51 +import org.openide.util.WeakSet;
28.52 +
28.53 +/** Not preferred anymore, use <a href="@org-openide-awt@/org/openide/awt/Actions.html#alwaysEnabled(java.awt.event.ActionListener,%20java.lang.String,%20java.lang.String,%20boolean)">Actions.alwaysEnabled</a>
28.54 +* instead. To migrate your
28.55 +* <a href="@org-openide-modules@/org/openide/modules/doc-files/api.html#how-layer">
28.56 +* layer definition</a> use:
28.57 +* <pre>
28.58 +* <file name="your-pkg-action-id.instance">
28.59 +* <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/>
28.60 +* <attr name="delegate" methodvalue="your.pkg.YourAction.factoryMethod"/>
28.61 +* <attr name="displayName" bundlevalue="your.pkg.Bundle#key"/>
28.62 +* <attr name="iconBase" stringvalue="your/pkg/YourImage.png"/>
28.63 +* <!-- if desired: <attr name="noIconInMenu" boolvalue="false"/> -->
28.64 +* </file>
28.65 +* </pre>
28.66 +*
28.67 +* @author Ian Formanek, Jaroslav Tulach, Jan Jancura, Petr Hamernik
28.68 +*/
28.69 +public abstract class CallableSystemAction extends SystemAction implements Presenter.Menu, Presenter.Popup,
28.70 + Presenter.Toolbar {
28.71 + /** serialVersionUID */
28.72 + static final long serialVersionUID = 2339794599168944156L;
28.73 +
28.74 + // ASYNCHRONICITY
28.75 + // Adapted from org.netbeans.core.ModuleActions by jglick
28.76 +
28.77 + /**
28.78 + * Set of action classes for which we have already issued a warning that
28.79 + * {@link #asynchronous} was not overridden to return false.
28.80 + */
28.81 + private static final Set<Class> warnedAsynchronousActions = new WeakSet<Class>();
28.82 + private static final boolean DEFAULT_ASYNCH = !Boolean.getBoolean(
28.83 + "org.openide.util.actions.CallableSystemAction.synchronousByDefault"
28.84 + );
28.85 +
28.86 + /* Returns a JMenuItem that presents the Action, that implements this
28.87 + * interface, in a MenuBar.
28.88 + * @return the JMenuItem representation for the Action
28.89 + */
28.90 + public javax.swing.JMenuItem getMenuPresenter() {
28.91 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createMenuPresenter(this);
28.92 + }
28.93 +
28.94 + /* Returns a JMenuItem that presents the Action, that implements this
28.95 + * interface, in a Popup Menu.
28.96 + * @return the JMenuItem representation for the Action
28.97 + */
28.98 + public javax.swing.JMenuItem getPopupPresenter() {
28.99 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createPopupPresenter(this);
28.100 + }
28.101 +
28.102 + /* Returns a Component that presents the Action, that implements this
28.103 + * interface, in a ToolBar.
28.104 + * @return the Component representation for the Action
28.105 + */
28.106 + public java.awt.Component getToolbarPresenter() {
28.107 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createToolbarPresenter(this);
28.108 + }
28.109 +
28.110 + /** Actually perform the action.
28.111 + * This is the method which should be called programmatically.
28.112 + * Presenters in <a href="@org-openide-awt@/org/openide/awt/Actions.html">Actions</a> use this.
28.113 + * <p>See {@link SystemAction#actionPerformed} for a note on
28.114 + * threading usage: in particular, do not access GUI components
28.115 + * without explicitly asking for the AWT event thread!
28.116 + */
28.117 + public abstract void performAction();
28.118 +
28.119 + /* Implementation of method of javax.swing.Action interface.
28.120 + * Delegates the execution to performAction method.
28.121 + *
28.122 + * @param ev the action event
28.123 + */
28.124 + public void actionPerformed(ActionEvent ev) {
28.125 + if (isEnabled()) {
28.126 + org.openide.util.actions.ActionInvoker.invokeAction(
28.127 + this, ev, asynchronous(), new Runnable() {
28.128 + public void run() {
28.129 + performAction();
28.130 + }
28.131 + }
28.132 + );
28.133 + } else {
28.134 + // Should not normally happen.
28.135 + Toolkit.getDefaultToolkit().beep();
28.136 + }
28.137 + }
28.138 +
28.139 + /**
28.140 + * If true, this action should be performed asynchronously in a private thread.
28.141 + * If false, it will be performed synchronously as called in the event thread.
28.142 + * <p>The default value is true for compatibility reasons; subclasses are strongly
28.143 + * encouraged to override it to be false, and to either do their work promptly
28.144 + * in the event thread and return, or to somehow do work asynchronously (for example
28.145 + * using {@link org.openide.util.RequestProcessor#getDefault}).
28.146 + * <p class="nonnormative">You may currently set the global default to false
28.147 + * by setting the system property
28.148 + * <code>org.openide.util.actions.CallableSystemAction.synchronousByDefault</code>
28.149 + * to <code>true</code>.</p>
28.150 + * <p class="nonnormative">When true, the current implementation also provides for a wait cursor during
28.151 + * the execution of the action. Subclasses which override to return false should
28.152 + * consider directly providing a wait or busy cursor if the nature of the action
28.153 + * merits it.</p>
28.154 + * @return true if this action should automatically be performed asynchronously
28.155 + * @since 4.11
28.156 + */
28.157 + protected boolean asynchronous() {
28.158 + if (warnedAsynchronousActions.add(getClass())) {
28.159 + Logger.getLogger(CallableSystemAction.class.getName()).warning(
28.160 + "Warning - " + getClass().getName() +
28.161 + " should override CallableSystemAction.asynchronous() to return false"
28.162 + );
28.163 + }
28.164 +
28.165 + return DEFAULT_ASYNCH;
28.166 + }
28.167 +}
29.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000
29.2 +++ b/openide.util/src/org/openide/util/actions/CallbackSystemAction.java Fri Jan 22 10:02:41 2010 -0500
29.3 @@ -0,0 +1,749 @@
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-2008 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 +
29.45 +package org.openide.util.actions;
29.46 +
29.47 +import java.awt.Component;
29.48 +import java.awt.Toolkit;
29.49 +import java.awt.event.ActionEvent;
29.50 +import java.beans.PropertyChangeEvent;
29.51 +import java.beans.PropertyChangeListener;
29.52 +import java.beans.PropertyChangeSupport;
29.53 +import java.lang.ref.Reference;
29.54 +import java.lang.ref.WeakReference;
29.55 +import java.util.ArrayList;
29.56 +import java.util.Collection;
29.57 +import java.util.Collections;
29.58 +import java.util.Iterator;
29.59 +import java.util.List;
29.60 +import java.util.logging.Level;
29.61 +import java.util.logging.Logger;
29.62 +import javax.swing.Action;
29.63 +import javax.swing.ActionMap;
29.64 +import org.openide.util.ContextAwareAction;
29.65 +import org.openide.util.Lookup;
29.66 +import org.openide.util.LookupListener;
29.67 +import org.openide.util.Mutex;
29.68 +import org.openide.util.Utilities;
29.69 +import org.openide.util.WeakListeners;
29.70 +import org.openide.util.WeakSet;
29.71 +
29.72 +/** Not preferred anymore, the replacement is
29.73 +* <a href="@org-openide-awt@/org/openide/awt/Actions.html#callback(java.lang.String,%20javax.swing.Action,%20boolean,%20java.lang.String,%20java.lang.String,%20boolean)">Actions.callback</a> factory method.
29.74 +* To migrate to the new API just remove the definition of your action in
29.75 +* <a href="@org-openide-modules@/org/openide/modules/doc-files/api.html#how-layer">
29.76 +* layer file</a> and replace it with:
29.77 +* <pre>
29.78 +* <file name="action-pkg-ClassName.instance">
29.79 +* <attr name="instanceCreate" methodvalue="org.openide.awt.Actions.callback"/>
29.80 +* <attr name="key" stringvalue="KeyInActionMap"/>
29.81 +* <attr name="surviveFocusChange" boolvalue="false"/> <!-- defaults to false -->
29.82 +* <attr name="fallback" newvalue="action.pkg.DefaultAction"/> <!-- may be missing -->
29.83 +* <attr name="displayName" bundlevalue="your.pkg.Bundle#key"/>
29.84 +* <attr name="iconBase" stringvalue="your/pkg/YourImage.png"/>
29.85 +* <!-- if desired: <attr name="noIconInMenu" boolvalue="false"/> -->
29.86 +* </file>
29.87 +* </pre>
29.88 +*
29.89 +*
29.90 +* @author Ian Formanek, Jaroslav Tulach, Petr Hamernik
29.91 +*/
29.92 +public abstract class CallbackSystemAction extends CallableSystemAction implements ContextAwareAction {
29.93 + /** action performer */
29.94 + private static final String PROP_ACTION_PERFORMER = "actionPerformer"; // NOI18N
29.95 +
29.96 + /** a list of all actions that has survive focus change set to false */
29.97 + private static final WeakSet<Class<? extends CallbackSystemAction>> notSurviving = new WeakSet<Class<? extends CallbackSystemAction>>(37);
29.98 +
29.99 + /** a list of actions surviving focus change */
29.100 + private static final WeakSet<Class<? extends CallbackSystemAction>> surviving = new WeakSet<Class<? extends CallbackSystemAction>>(37);
29.101 +
29.102 + /** key to access listener */
29.103 + private static final Object LISTENER = new Object();
29.104 + static final long serialVersionUID = -6305817805474624653L;
29.105 +
29.106 + /** logging */
29.107 + private static final Logger err = Logger.getLogger(
29.108 + "org.openide.util.actions.CallbackSystemAction"
29.109 + ); // NOI18N
29.110 +
29.111 + /** Initialize the action to have no performer.
29.112 + */
29.113 + protected void initialize() {
29.114 + super.initialize();
29.115 + updateEnabled();
29.116 + setSurviveFocusChange(false);
29.117 + }
29.118 +
29.119 + /** Get the current action performer.
29.120 + * @return the current action performer, or <code>null</code> if there is currently no performer
29.121 + * @deprecated use TopComponent.getActionMap() as described in the javadoc
29.122 + */
29.123 + @Deprecated
29.124 + public ActionPerformer getActionPerformer() {
29.125 + return (ActionPerformer) getProperty(PROP_ACTION_PERFORMER);
29.126 + }
29.127 +
29.128 + /** Set the action performer.
29.129 + * The specified value can be <code>null</code>, which means that the action will have no performer
29.130 + * and is disabled. ({@link #isEnabled} will return <code>false</code> regardless its previous state.)
29.131 + * <P>
29.132 + * This method is <em>too dynamic</em> it depends on the actuall order of callers and
29.133 + * is for example very fragile with respect to focus switching and correct delivering of
29.134 + * focus change events. That is why an alternative based on
29.135 + * <a href="http://openide.netbeans.org/proposals/actions/design.html#callback">ActionMap proposal</a>
29.136 + * has been developed.
29.137 + * <P>
29.138 + * So if you are providing a <a href="@org-openide-windows@/org/openide/windows/TopComponent.html">TopComponent</a>
29.139 + * and want to provide
29.140 + * your own handling of <a href="@org-openide-actions@/org/openide/actions/CopyAction.html">CopyAction</a> use following code:
29.141 + * <PRE>
29.142 + * TopComponent tc = ...;
29.143 + * javax.swing.Action yourCopyAction = ...; // the action to invoke instead of Copy
29.144 + *
29.145 + * CopyAction globalCopyAction = SystemAction.get (CopyAction.class);
29.146 + * Object key = globalCopyAction.getActionMapKey(); // key is a special value defined by all CallbackSystemActions
29.147 + *
29.148 + * // and finally:
29.149 + * tc.getActionMap ().put (key, yourCopyAction);
29.150 + * </PRE>
29.151 + * This code registers <code>yourCopyAction</code> with <code>tc</code>
29.152 + * top component, so whenever a <code>globalCopyAction</code> is invoked,
29.153 + * your action is being delegated to.
29.154 + *
29.155 + * @param performer the new action performer or <code>null</code> to disable
29.156 + *
29.157 + * @deprecated use TopComponent.getActionMap() as described in the javadoc
29.158 + */
29.159 + @Deprecated
29.160 + public void setActionPerformer(ActionPerformer performer) {
29.161 + putProperty(PROP_ACTION_PERFORMER, performer);
29.162 + updateEnabled();
29.163 + }
29.164 +
29.165 + /** Updates the enabled state by checking performer and ActionMap
29.166 + */
29.167 + private void updateEnabled() {
29.168 + Action action = GlobalManager.getDefault().findGlobalAction(
29.169 + getActionMapKey(), getSurviveFocusChange()
29.170 + );
29.171 +
29.172 + if (action != null) {
29.173 + setEnabled(action.isEnabled());
29.174 +
29.175 + synchronized (LISTENER) {
29.176 + ActionDelegateListener l = (ActionDelegateListener) getProperty(LISTENER);
29.177 +
29.178 + if ((l == null) || (l.get() != this)) {
29.179 + l = new ActionDelegateListener(this, action);
29.180 + putProperty(LISTENER, l);
29.181 + } else {
29.182 + l.attach(action);
29.183 + }
29.184 + }
29.185 + } else {
29.186 + if (getActionPerformer() != null) {
29.187 + // we have performer
29.188 + setEnabled(true);
29.189 + } else {
29.190 + setEnabled(false);
29.191 + }
29.192 +
29.193 + clearListener();
29.194 + }
29.195 + }
29.196 +
29.197 + /** Clears the listener.
29.198 + */
29.199 + private void clearListener() {
29.200 + synchronized (LISTENER) {
29.201 + // remove listener on any action
29.202 + ActionDelegateListener l = (ActionDelegateListener) getProperty(LISTENER);
29.203 +
29.204 + if (l != null) {
29.205 + l.clear();
29.206 + putProperty(LISTENER, null);
29.207 + }
29.208 + }
29.209 + }
29.210 +
29.211 + /** Perform the action. Tries the performer and then scans the ActionMap
29.212 + * of selected topcomponent.
29.213 + */
29.214 + public void actionPerformed(final ActionEvent ev) {
29.215 + // First try global context action.
29.216 + final Action action = GlobalManager.getDefault().findGlobalAction(getActionMapKey(), getSurviveFocusChange());
29.217 +
29.218 + if (action != null) {
29.219 + if (action.isEnabled()) {
29.220 + action.actionPerformed(ev);
29.221 + } else {
29.222 + Toolkit.getDefaultToolkit().beep();
29.223 + }
29.224 +
29.225 + return;
29.226 + }
29.227 +
29.228 + final Object ap = getActionPerformer();
29.229 +
29.230 + if (ap != null) {
29.231 + org.openide.util.actions.ActionInvoker.invokeAction(
29.232 + this, ev, asynchronous(), new Runnable() {
29.233 + public void run() {
29.234 + if (ap == getActionPerformer()) {
29.235 + getActionPerformer().performAction(CallbackSystemAction.this);
29.236 + }
29.237 + }
29.238 + }
29.239 + );
29.240 +
29.241 + return;
29.242 + }
29.243 +
29.244 + Toolkit.getDefaultToolkit().beep();
29.245 + }
29.246 +
29.247 + /** Perform the action.
29.248 + * This default implementation calls the assigned action performer if it
29.249 + * exists, otherwise does nothing.
29.250 + * @deprecated This only uses {@link ActionPerformer}. Use {@link #actionPerformed} instead.
29.251 + */
29.252 + @Deprecated
29.253 + public void performAction() {
29.254 + ActionPerformer ap = getActionPerformer();
29.255 +
29.256 + if (ap != null) {
29.257 + ap.performAction(this);
29.258 + }
29.259 + }
29.260 +
29.261 + /** Getter for action map key, which is used to find action from provided
29.262 + * context (i.e. <code>ActionMap</code> provided by the context),
29.263 + * which acts as a callback.
29.264 + * Override this method in subclasses to provide 'nice' key.
29.265 + * @return key which is used to find the action which performs callback,
29.266 + * default returned key is a class name.
29.267 + * @since 3.29 */
29.268 + public Object getActionMapKey() {
29.269 + return getClass().getName();
29.270 + }
29.271 +
29.272 + /** Test whether the action will survive a change in focus.
29.273 + * By default, it will not.
29.274 + * @return <code>true</code> if the enabled state of the action survives focus changes
29.275 + */
29.276 + public boolean getSurviveFocusChange() {
29.277 + getProperty(null); // force initialization
29.278 +
29.279 + return !notSurviving.contains(getClass());
29.280 + }
29.281 +
29.282 + /** Implements <code>ContextAwareAction</code> interface method. */
29.283 + public Action createContextAwareInstance(Lookup actionContext) {
29.284 + return new DelegateAction(this, actionContext);
29.285 + }
29.286 +
29.287 + /** Set whether the action will survive a change in focus.
29.288 + * If <code>false</code>, then the action will be automatically
29.289 + * disabled (using {@link #setActionPerformer}) when the window
29.290 + * focus changes.
29.291 + *
29.292 + * @param b <code>true</code> to survive focus changes, <code>false</code> to be sensitive to them
29.293 + */
29.294 + public void setSurviveFocusChange(boolean b) {
29.295 + synchronized (notSurviving) {
29.296 + if (b) {
29.297 + notSurviving.remove(getClass());
29.298 + surviving.add(getClass());
29.299 + } else {
29.300 + notSurviving.add(getClass());
29.301 + surviving.remove(getClass());
29.302 + }
29.303 + }
29.304 + }
29.305 +
29.306 + /** Array of actions from a set of classes.
29.307 + */
29.308 + private static List<CallbackSystemAction> toInstances(java.util.Set<Class<? extends CallbackSystemAction>> s) {
29.309 + List<CallbackSystemAction> actions;
29.310 +
29.311 + synchronized (notSurviving) {
29.312 + actions = new ArrayList<CallbackSystemAction>(s.size());
29.313 +
29.314 + for (Class<? extends CallbackSystemAction> c : s) {
29.315 +
29.316 + CallbackSystemAction a = SystemAction.findObject(c, false);
29.317 +
29.318 + if (a != null) {
29.319 + actions.add(a);
29.320 + }
29.321 + }
29.322 + }
29.323 +
29.324 + return actions;
29.325 + }
29.326 +
29.327 + /** Clears all action performers for those that has setSurviveFocusChange
29.328 + * on true.
29.329 + */
29.330 + private static void clearActionPerformers() {
29.331 + List<CallbackSystemAction> actions = toInstances(notSurviving);
29.332 +
29.333 + // clear the performers out of any loop
29.334 + for (CallbackSystemAction a : actions) {
29.335 + a.setActionPerformer(null);
29.336 + }
29.337 +
29.338 + actions = toInstances(surviving);
29.339 +
29.340 + // clear the performers out of any loop
29.341 + for (CallbackSystemAction a : actions) {
29.342 +
29.343 + if (err.isLoggable(Level.FINE)) {
29.344 + err.fine("updateEnabled: " + a); // NOI18N
29.345 + }
29.346 +
29.347 + a.updateEnabled();
29.348 + }
29.349 + }
29.350 +
29.351 + /** Listener on a global context.
29.352 + */
29.353 + private static final class GlobalManager implements LookupListener {
29.354 + private static GlobalManager instance;
29.355 + private Lookup.Result<ActionMap> result;
29.356 + private List<Reference<ActionMap>> actionMaps = new ArrayList<Reference<ActionMap>>(2);
29.357 + private final ActionMap survive = new ActionMap();
29.358 +
29.359 + private GlobalManager() {
29.360 + result = Utilities.actionsGlobalContext().lookup(new Lookup.Template<ActionMap>(ActionMap.class));
29.361 + result.addLookupListener(this);
29.362 + resultChanged(null);
29.363 + }
29.364 +
29.365 + public synchronized static GlobalManager getDefault() {
29.366 + if (instance != null) {
29.367 + return instance;
29.368 + }
29.369 +
29.370 + instance = new GlobalManager();
29.371 +
29.372 + return instance;
29.373 + }
29.374 +
29.375 + public Action findGlobalAction(Object key, boolean surviveFocusChange) {
29.376 + // search action in all action maps from global context
29.377 + Action a = null;
29.378 + for (Reference<ActionMap> ref : actionMaps) {
29.379 + ActionMap am = ref.get();
29.380 + a = am == null ? null : am.get(key);
29.381 + if (a != null) {
29.382 + break;
29.383 + }
29.384 + }
29.385 +
29.386 + if (surviveFocusChange) {
29.387 + if (a == null) {
29.388 + a = survive.get(key);
29.389 +
29.390 + if (a != null) {
29.391 + a = ((WeakAction) a).getDelegate();
29.392 + }
29.393 +
29.394 + if (err.isLoggable(Level.FINE)) {
29.395 + err.fine("No action for key: " + key + " using delegate: " + a); // NOI18N
29.396 + }
29.397 + } else {
29.398 + if (err.isLoggable(Level.FINE)) {
29.399 + err.fine("New action for key: " + key + " put: " + a);
29.400 + }
29.401 +
29.402 + survive.put(key, new WeakAction(a));
29.403 + }
29.404 + }
29.405 +
29.406 + if (err.isLoggable(Level.FINE)) {
29.407 + err.fine("Action for key: " + key + " is: " + a); // NOI18N
29.408 + }
29.409 +
29.410 + return a;
29.411 + }
29.412 +
29.413 + /** Change all that do not survive ActionMap change */
29.414 + public void resultChanged(org.openide.util.LookupEvent ev) {
29.415 + Collection<? extends ActionMap> ams = result.allInstances();
29.416 +
29.417 + if (err.isLoggable(Level.FINE)) {
29.418 + err.fine("changed maps : " + ams); // NOI18N
29.419 + err.fine("previous maps: " + actionMaps); // NOI18N
29.420 + }
29.421 +
29.422 + // do nothing if maps are actually the same
29.423 + if (ams.size() == actionMaps.size()) {
29.424 + boolean theSame = true;
29.425 + int i = 0;
29.426 + for (Iterator<? extends ActionMap> newMaps = ams.iterator(); newMaps.hasNext(); i++) {
29.427 + ActionMap oldMap = actionMaps.get(i).get();
29.428 + if (oldMap == null || oldMap != newMaps.next()) {
29.429 + theSame = false;
29.430 + break;
29.431 + }
29.432 + }
29.433 + if (theSame) {
29.434 + return;
29.435 + }
29.436 + }
29.437 +
29.438 + // update actionMaps
29.439 + List<Reference<ActionMap>> tempActionMaps = new ArrayList<Reference<ActionMap>>(2);
29.440 + for (ActionMap actionMap : ams) {
29.441 + tempActionMaps.add(new WeakReference<ActionMap>(actionMap));
29.442 + }
29.443 + actionMaps = tempActionMaps;
29.444 +
29.445 + if (err.isLoggable(Level.FINE)) {
29.446 + err.fine("clearActionPerformers"); // NOI18N
29.447 + }
29.448 +
29.449 + Mutex.EVENT.readAccess(new Runnable() {
29.450 + public void run() {
29.451 + clearActionPerformers();
29.452 + }
29.453 + });
29.454 + }
29.455 + }
29.456 + // end of LookupListener
29.457 +
29.458 + /** An action that holds a weak reference to other action.
29.459 + */
29.460 + private static final class WeakAction extends WeakReference<Action> implements Action {
29.461 + public WeakAction(Action delegate) {
29.462 + super(delegate);
29.463 + }
29.464 +
29.465 + public Action getDelegate() {
29.466 + return get();
29.467 + }
29.468 +
29.469 + public Object getValue(String key) {
29.470 + throw new UnsupportedOperationException();
29.471 + }
29.472 +
29.473 + public void putValue(String key, Object value) {
29.474 + throw new UnsupportedOperationException();
29.475 + }
29.476 +
29.477 + public void actionPerformed(ActionEvent e) {
29.478 + throw new UnsupportedOperationException();
29.479 + }
29.480 +
29.481 + public void removePropertyChangeListener(PropertyChangeListener listener) {
29.482 + throw new UnsupportedOperationException();
29.483 + }
29.484 +
29.485 + public void addPropertyChangeListener(PropertyChangeListener listener) {
29.486 + throw new UnsupportedOperationException();
29.487 + }
29.488 +
29.489 + public void setEnabled(boolean b) {
29.490 + throw new UnsupportedOperationException();
29.491 + }
29.492 +
29.493 + public boolean isEnabled() {
29.494 + throw new UnsupportedOperationException();
29.495 + }
29.496 + }
29.497 +
29.498 + /** A class that listens on changes in enabled state of an action
29.499 + * and updates the state of the action according to it.
29.500 + */
29.501 + private static final class ActionDelegateListener extends WeakReference<CallbackSystemAction> implements PropertyChangeListener {
29.502 + private Reference<Action> delegate;
29.503 +
29.504 + public ActionDelegateListener(CallbackSystemAction c, Action delegate) {
29.505 + super(c);
29.506 + this.delegate = new WeakReference<Action>(delegate);
29.507 + delegate.addPropertyChangeListener(this);
29.508 + }
29.509 +
29.510 + public void clear() {
29.511 + Action a;
29.512 +
29.513 + Reference<Action> d = delegate;
29.514 + a = d == null ? null : d.get();
29.515 +
29.516 + if (a == null) {
29.517 + return;
29.518 + }
29.519 +
29.520 + delegate = null;
29.521 +
29.522 + a.removePropertyChangeListener(this);
29.523 + }
29.524 +
29.525 + public void attach(Action action) {
29.526 + Reference<Action> d = delegate;
29.527 +
29.528 + if ((d != null) && (d.get() == action)) {
29.529 + return;
29.530 + }
29.531 +
29.532 + Action prev = d.get();
29.533 +
29.534 + // reattaches to different action
29.535 + if (prev != null) {
29.536 + prev.removePropertyChangeListener(this);
29.537 + }
29.538 +
29.539 + this.delegate = new WeakReference<Action>(action);
29.540 + action.addPropertyChangeListener(this);
29.541 + }
29.542 +
29.543 + public void propertyChange(java.beans.PropertyChangeEvent evt) {
29.544 + synchronized (LISTENER) {
29.545 + Reference<Action> d = delegate;
29.546 +
29.547 + if ((d == null) || (d.get() == null)) {
29.548 + return;
29.549 + }
29.550 + }
29.551 +
29.552 + CallbackSystemAction c = get();
29.553 +
29.554 + if (c != null) {
29.555 + c.updateEnabled();
29.556 + }
29.557 + }
29.558 + }
29.559 +
29.560 + /** A delegate action that is usually associated with a specific lookup and
29.561 + * extract the nodes it operates on from it. Otherwise it delegates to the
29.562 + * regular NodeAction.
29.563 + */
29.564 + private static final class DelegateAction extends Object implements Action,
29.565 + LookupListener, Presenter.Menu, Presenter.Popup, Presenter.Toolbar, PropertyChangeListener {
29.566 + /** action to delegate too */
29.567 + private CallbackSystemAction delegate;
29.568 +
29.569 + /** lookup we are associated with (or null) */
29.570 + private Lookup.Result<ActionMap> result;
29.571 +
29.572 + /** previous state of enabled */
29.573 + private boolean enabled;
29.574 +
29.575 + /** support for listeners */
29.576 + private PropertyChangeSupport support = new PropertyChangeSupport(this);
29.577 +
29.578 + /** listener to check listen on state of action(s) we delegate to */
29.579 + private PropertyChangeListener weakL;
29.580 +
29.581 + /** last action we were listening to */
29.582 + private Reference<Action> lastRef;
29.583 +
29.584 + public DelegateAction(CallbackSystemAction a, Lookup actionContext) {
29.585 + this.delegate = a;
29.586 + this.weakL = org.openide.util.WeakListeners.propertyChange(this, null);
29.587 + this.enabled = a.getActionPerformer() != null;
29.588 +
29.589 + this.result = actionContext.lookup(new Lookup.Template<ActionMap>(ActionMap.class));
29.590 + this.result.addLookupListener(WeakListeners.create(LookupListener.class, this, this.result));
29.591 + resultChanged(null);
29.592 + }
29.593 +
29.594 + /** Overrides superclass method, adds delegate description. */
29.595 + public String toString() {
29.596 + return super.toString() + "[delegate=" + delegate + "]"; // NOI18N
29.597 + }
29.598 +
29.599 + /** Invoked when an action occurs.
29.600 + */
29.601 + public void actionPerformed(final java.awt.event.ActionEvent e) {
29.602 + final Action a = findAction();
29.603 +
29.604 + if (a != null) {
29.605 + Runnable run = new Runnable() {
29.606 + public void run() {
29.607 + a.actionPerformed(e);
29.608 + }
29.609 + };
29.610 + org.openide.util.actions.ActionInvoker.invokeAction(delegate, e, delegate.asynchronous(), run);
29.611 + } else {
29.612 + // XXX #30303 if the action falls back to the old behaviour
29.613 + // it may not be performed in case it is in dialog and
29.614 + // is not transmodal.
29.615 + // This is just a hack, see TopComponent.processKeyBinding.
29.616 + Object source = e.getSource();
29.617 +
29.618 + if (
29.619 + source instanceof Component &&
29.620 + javax.swing.SwingUtilities.getWindowAncestor((Component) source) instanceof java.awt.Dialog
29.621 + ) {
29.622 + Object value = delegate.getValue("OpenIDE-Transmodal-Action"); // NOI18N
29.623 +
29.624 + if (!Boolean.TRUE.equals(value)) {
29.625 + return;
29.626 + }
29.627 + }
29.628 +
29.629 + delegate.actionPerformed(e);
29.630 + }
29.631 + }
29.632 +
29.633 + public boolean isEnabled() {
29.634 + Action a = findAction();
29.635 +
29.636 + if (a == null) {
29.637 + a = delegate;
29.638 + }
29.639 +
29.640 + // 40915 - hold last action weakly
29.641 + Action last = lastRef == null ? null : lastRef.get();
29.642 +
29.643 + if (a != last) {
29.644 + if (last != null) {
29.645 + last.removePropertyChangeListener(weakL);
29.646 + }
29.647 +
29.648 + lastRef = new WeakReference<Action>(a);
29.649 + a.addPropertyChangeListener(weakL);
29.650 + }
29.651 +
29.652 + return a.isEnabled();
29.653 + }
29.654 +
29.655 + public void addPropertyChangeListener(PropertyChangeListener listener) {
29.656 + support.addPropertyChangeListener(listener);
29.657 + }
29.658 +
29.659 + public void removePropertyChangeListener(PropertyChangeListener listener) {
29.660 + support.removePropertyChangeListener(listener);
29.661 + }
29.662 +
29.663 + public void putValue(String key, Object o) {
29.664 + }
29.665 +
29.666 + public Object getValue(String key) {
29.667 + return delegate.getValue(key);
29.668 + }
29.669 +
29.670 + public void setEnabled(boolean b) {
29.671 + }
29.672 +
29.673 + public void resultChanged(org.openide.util.LookupEvent ev) {
29.674 + boolean newEnabled = isEnabled();
29.675 +
29.676 + if (newEnabled != enabled) {
29.677 + support.firePropertyChange(PROP_ENABLED, enabled, newEnabled);
29.678 + enabled = newEnabled;
29.679 + }
29.680 + }
29.681 +
29.682 + public void propertyChange(PropertyChangeEvent evt) {
29.683 + resultChanged(null);
29.684 + }
29.685 +
29.686 + /*** Finds an action that we should delegate to
29.687 + * @return the action or null
29.688 + */
29.689 + private Action findAction() {
29.690 + Collection<? extends ActionMap> c = result != null ? result.allInstances() : Collections.<ActionMap>emptySet();
29.691 +
29.692 + if (!c.isEmpty()) {
29.693 + Object key = delegate.getActionMapKey();
29.694 + for (ActionMap map : c) {
29.695 + Action action = map.get(key);
29.696 + if (action != null) {
29.697 + return action;
29.698 + }
29.699 + }
29.700 + }
29.701 +
29.702 + return null;
29.703 + }
29.704 +
29.705 + public javax.swing.JMenuItem getMenuPresenter() {
29.706 + if (isMethodOverridden(delegate, "getMenuPresenter")) { // NOI18N
29.707 +
29.708 + return delegate.getMenuPresenter();
29.709 + } else {
29.710 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createMenuPresenter(this);
29.711 + }
29.712 + }
29.713 +
29.714 + public javax.swing.JMenuItem getPopupPresenter() {
29.715 + if (isMethodOverridden(delegate, "getPopupPresenter")) { // NOI18N
29.716 +
29.717 + return delegate.getPopupPresenter();
29.718 + } else {
29.719 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createPopupPresenter(this);
29.720 + }
29.721 + }
29.722 +
29.723 + public java.awt.Component getToolbarPresenter() {
29.724 + if (isMethodOverridden(delegate, "getToolbarPresenter")) { // NOI18N
29.725 +
29.726 + return delegate.getToolbarPresenter();
29.727 + } else {
29.728 + return org.openide.util.actions.ActionPresenterProvider.getDefault().createToolbarPresenter(this);
29.729 + }
29.730 + }
29.731 +
29.732 + private boolean isMethodOverridden(CallableSystemAction d, String name) {
29.733 + try {
29.734 + java.lang.reflect.Method m = d.getClass().getMethod(name, new Class[0]);
29.735 +
29.736 + return m.getDeclaringClass() != CallableSystemAction.class;
29.737 + } catch (java.lang.NoSuchMethodException ex) {
29.738 + ex.printStackTrace();
29.739 + throw new IllegalStateException("Error searching for method " + name + " in " + d); // NOI18N
29.740 + }
29.741 + }
29.742 +
29.743 + protected void finalize() {
29.744 + Action last = lastRef == null ? null : lastRef.get();
29.745 +
29.746 + if (last != null) {
29.747 + last.removePropertyChangeListener(weakL);
29.748 + }
29.749 + }
29.750 + }
29.751 + // end of DelegateAction
29.752 +}
30.1 --- a/openide.util/test/unit/src/org/openide/util/UtilitiesTest.java Fri Jan 22 10:09:12 2010 -0500
30.2 +++ b/openide.util/test/unit/src/org/openide/util/UtilitiesTest.java Fri Jan 22 10:02:41 2010 -0500
30.3 @@ -128,12 +128,12 @@
30.4 import junit.framework.Assert;
30.5 import org.netbeans.junit.MockServices;
30.6 import org.netbeans.junit.NbTestCase;
30.7 -import org.netbeans.modules.openide.util.AWTBridge;
30.8 -import org.netbeans.modules.openide.util.NamedServicesProvider;
30.9 import org.openide.util.actions.Presenter;
30.10 import org.openide.util.lookup.AbstractLookup;
30.11 import org.openide.util.lookup.InstanceContent;
30.12 import org.openide.util.lookup.Lookups;
30.13 +import org.openide.util.lookup.implspi.NamedServicesProvider;
30.14 +import org.openide.util.actions.ActionPresenterProvider;
30.15 import org.openide.util.test.MockLookup;
30.16
30.17 /**
30.18 @@ -342,53 +342,7 @@
30.19 }
30.20
30.21 public void testActionsForPath() throws Exception {
30.22 - MockLookup.setInstances(new NamedServicesProvider() {
30.23 - public Lookup create(String path) {
30.24 - if (!path.equals("stuff/")) {
30.25 - return Lookup.EMPTY;
30.26 - }
30.27 - InstanceContent content = new InstanceContent();
30.28 - InstanceContent.Convertor<String,Action> actionConvertor = new InstanceContent.Convertor<String,Action>() {
30.29 - public Action convert(final String obj) {
30.30 - return new AbstractAction() {
30.31 - public void actionPerformed(ActionEvent e) {}
30.32 - public @Override String toString() {
30.33 - return obj;
30.34 - }
30.35 -
30.36 - };
30.37 - }
30.38 - public Class<? extends Action> type(String obj) {
30.39 - return AbstractAction.class;
30.40 - }
30.41 - public String id(String obj) {
30.42 - return obj;
30.43 - }
30.44 - public String displayName(String obj) {
30.45 - return id(obj);
30.46 - }
30.47 - };
30.48 - InstanceContent.Convertor<Boolean,JSeparator> separatorConvertor = new InstanceContent.Convertor<Boolean,JSeparator>() {
30.49 - public JSeparator convert(Boolean obj) {
30.50 - Assert.fail("should not be creating the JSeparator yet");
30.51 - return new JSeparator();
30.52 - }
30.53 - public Class<? extends JSeparator> type(Boolean obj) {
30.54 - return JSeparator.class;
30.55 - }
30.56 - public String id(Boolean obj) {
30.57 - return "sep";
30.58 - }
30.59 - public String displayName(Boolean obj) {
30.60 - return id(obj);
30.61 - }
30.62 - };
30.63 - content.add("hello", actionConvertor);
30.64 - content.add(true, separatorConvertor);
30.65 - content.add("there", actionConvertor);
30.66 - return new AbstractLookup(content);
30.67 - }
30.68 - });
30.69 + MockLookup.setInstances(new NamedServicesProviderImpl());
30.70 // #156829: ensure that no tree lock is acquired.
30.71 final Semaphore ready = new Semaphore(0);
30.72 final Semaphore done = new Semaphore(0);
30.73 @@ -618,7 +572,7 @@
30.74 }
30.75 }
30.76
30.77 - public static final class AwtBridgeImpl extends AWTBridge {
30.78 + public static final class AwtBridgeImpl extends ActionPresenterProvider {
30.79 public JPopupMenu createEmptyPopup() {
30.80 return new JPopupMenu();
30.81 }
30.82 @@ -639,5 +593,68 @@
30.83 }
30.84 }
30.85 }
30.86 +
30.87 + private class NamedServicesProviderImpl extends NamedServicesProvider {
30.88 +
30.89 + public NamedServicesProviderImpl() {
30.90 + }
30.91 +
30.92 + public Lookup create(String path) {
30.93 + if (!path.equals("stuff/")) {
30.94 + return Lookup.EMPTY;
30.95 + }
30.96 + InstanceContent content = new InstanceContent();
30.97 + InstanceContent.Convertor<String, Action> actionConvertor = new InstanceContent.Convertor<String, Action>() {
30.98 +
30.99 + public Action convert(final String obj) {
30.100 + return new AbstractAction() {
30.101 +
30.102 + public void actionPerformed(ActionEvent e) {
30.103 + }
30.104 +
30.105 + @Override
30.106 + public String toString() {
30.107 + return obj;
30.108 + }
30.109 + };
30.110 + }
30.111 +
30.112 + public Class<? extends Action> type(String obj) {
30.113 + return AbstractAction.class;
30.114 + }
30.115 +
30.116 + public String id(String obj) {
30.117 + return obj;
30.118 + }
30.119 +
30.120 + public String displayName(String obj) {
30.121 + return id(obj);
30.122 + }
30.123 + };
30.124 + InstanceContent.Convertor<Boolean, JSeparator> separatorConvertor = new InstanceContent.Convertor<Boolean, JSeparator>() {
30.125 +
30.126 + public JSeparator convert(Boolean obj) {
30.127 + Assert.fail("should not be creating the JSeparator yet");
30.128 + return new JSeparator();
30.129 + }
30.130 +
30.131 + public Class<? extends JSeparator> type(Boolean obj) {
30.132 + return JSeparator.class;
30.133 + }
30.134 +
30.135 + public String id(Boolean obj) {
30.136 + return "sep";
30.137 + }
30.138 +
30.139 + public String displayName(Boolean obj) {
30.140 + return id(obj);
30.141 + }
30.142 + };
30.143 + content.add("hello", actionConvertor);
30.144 + content.add(true, separatorConvertor);
30.145 + content.add("there", actionConvertor);
30.146 + return new AbstractLookup(content);
30.147 + }
30.148 + }
30.149
30.150 }