179289: remove impl deps from platform cluster.
authorJesse Glick <jglick@netbeans.org>
Fri, 22 Jan 2010 10:02:41 -0500
changeset 969fdbfdc759045
parent 968 7479a9c25061
child 970 03dc6e747bb8
179289: remove impl deps from platform cluster.
openide.util.lookup/apichanges.xml
openide.util.lookup/manifest.mf
openide.util.lookup/nbproject/project.properties
openide.util.lookup/nbproject/project.xml
openide.util.lookup/src/org/netbeans/modules/openide/util/AbstractServiceProviderProcessor.java
openide.util.lookup/src/org/netbeans/modules/openide/util/ActiveQueue.java
openide.util.lookup/src/org/netbeans/modules/openide/util/ServiceProviderProcessor.java
openide.util.lookup/src/org/openide/util/lookup/AbstractLookup.java
openide.util.lookup/src/org/openide/util/lookup/Lookups.java
openide.util.lookup/src/org/openide/util/lookup/implspi/AbstractServiceProviderProcessor.java
openide.util.lookup/src/org/openide/util/lookup/implspi/ActiveQueue.java
openide.util.lookup/src/org/openide/util/lookup/implspi/NamedServicesProvider.java
openide.util.lookup/src/org/openide/util/lookup/implspi/package-info.java
openide.util.lookup/test/unit/src/org/netbeans/modules/openide/util/ActiveQueueTest.java
openide.util.lookup/test/unit/src/org/openide/util/lookup/AbstractLookupMemoryTest.java
openide.util.lookup/test/unit/src/org/openide/util/lookup/PathInLookupTest.java
openide.util.lookup/test/unit/src/org/openide/util/lookup/ProxyLookupTest.java
openide.util/apichanges.xml
openide.util/manifest.mf
openide.util/nbproject/project.properties
openide.util/nbproject/project.xml
openide.util/src/org/netbeans/modules/openide/util/URLStreamHandlerRegistrationProcessor.java
openide.util/src/org/openide/util/NbPreferences.java
openide.util/src/org/openide/util/Utilities.java
openide.util/src/org/openide/util/actions/ActionInvoker.java
openide.util/src/org/openide/util/actions/ActionPresenterProvider.java
openide.util/src/org/openide/util/actions/BooleanStateAction.java
openide.util/src/org/openide/util/actions/CallableSystemAction.java
openide.util/src/org/openide/util/actions/CallbackSystemAction.java
openide.util/test/unit/src/org/openide/util/UtilitiesTest.java
     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 &amp; 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 &amp; 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 -&gt; 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&lt;Object,Collection&gt;</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[],&nbsp;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 +* &lt;file name="your-pkg-action-id.instance"&gt;
   28.59 +*   &lt;attr name="instanceCreate" methodvalue="org.openide.awt.Actions.alwaysEnabled"/&gt;
   28.60 +*   &lt;attr name="delegate" methodvalue="your.pkg.YourAction.factoryMethod"/&gt;
   28.61 +*   &lt;attr name="displayName" bundlevalue="your.pkg.Bundle#key"/&gt;
   28.62 +*   &lt;attr name="iconBase" stringvalue="your/pkg/YourImage.png"/&gt;
   28.63 +*   &lt;!-- if desired: &lt;attr name="noIconInMenu" boolvalue="false"/&gt; --&gt;
   28.64 +* &lt;/file&gt;
   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 +* &lt;file name="action-pkg-ClassName.instance"&gt;
   29.79 +*   &lt;attr name="instanceCreate" methodvalue="org.openide.awt.Actions.callback"/&gt;
   29.80 +*   &lt;attr name="key" stringvalue="KeyInActionMap"/&gt;
   29.81 +*   &lt;attr name="surviveFocusChange" boolvalue="false"/&gt; &lt;!-- defaults to false --&gt;
   29.82 +*   &lt;attr name="fallback" newvalue="action.pkg.DefaultAction"/&gt; &lt;!-- may be missing --&gt;
   29.83 +*   &lt;attr name="displayName" bundlevalue="your.pkg.Bundle#key"/&gt;
   29.84 +*   &lt;attr name="iconBase" stringvalue="your/pkg/YourImage.png"/&gt;
   29.85 +*   &lt;!-- if desired: &lt;attr name="noIconInMenu" boolvalue="false"/&gt; --&gt;
   29.86 +* &lt;/file&gt;
   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  }