openide.util/test/unit/src/org/openide/util/lookup/AbstractLookupBaseHid.java
author Jesse Glick <jglick@netbeans.org>
Fri, 09 Oct 2009 15:11:13 -0400
changeset 833 0e00857c5827
parent 700 e4c18aa9c111
child 712 140de5cbeb24
permissions -rw-r--r--
Warnings.
     1 /*
     2  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     3  *
     4  * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
     5  *
     6  * The contents of this file are subject to the terms of either the GNU
     7  * General Public License Version 2 only ("GPL") or the Common
     8  * Development and Distribution License("CDDL") (collectively, the
     9  * "License"). You may not use this file except in compliance with the
    10  * License. You can obtain a copy of the License at
    11  * http://www.netbeans.org/cddl-gplv2.html
    12  * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    13  * specific language governing permissions and limitations under the
    14  * License.  When distributing the software, include this License Header
    15  * Notice in each file and include the License file at
    16  * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    17  * particular file as subject to the "Classpath" exception as provided
    18  * by Sun in the GPL Version 2 section of the License file that
    19  * accompanied this code. If applicable, add the following below the
    20  * License Header, with the fields enclosed by brackets [] replaced by
    21  * your own identifying information:
    22  * "Portions Copyrighted [year] [name of copyright owner]"
    23  *
    24  * Contributor(s):
    25  *
    26  * The Original Software is NetBeans. The Initial Developer of the Original
    27  * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    28  * Microsystems, Inc. All Rights Reserved.
    29  *
    30  * If you wish your version of this file to be governed by only the CDDL
    31  * or only the GPL Version 2, indicate your decision by adding
    32  * "[Contributor] elects to include this software in this distribution
    33  * under the [CDDL or GPL Version 2] license." If you do not indicate a
    34  * single choice of license, a recipient has the option to distribute
    35  * your version of this file under either the CDDL, the GPL Version 2 or
    36  * to extend the choice of license to its licensees as provided above.
    37  * However, if you add GPL Version 2 code and therefore, elected the GPL
    38  * Version 2 license, then the option applies only if the new code is
    39  * made subject to such option by the copyright holder.
    40  */
    41 
    42 package org.openide.util.lookup;
    43 
    44 import java.io.ByteArrayInputStream;
    45 import java.io.ByteArrayOutputStream;
    46 import java.io.ObjectInputStream;
    47 import java.io.ObjectOutputStream;
    48 import java.io.Serializable;
    49 import java.lang.ref.WeakReference;
    50 import java.lang.ref.Reference;
    51 import java.util.ArrayList;
    52 import java.util.Arrays;
    53 import java.util.Collection;
    54 import java.util.Collections;
    55 import java.util.Iterator;
    56 import java.util.LinkedList;
    57 import java.util.List;
    58 import java.util.concurrent.Executors;
    59 import java.util.concurrent.TimeUnit;
    60 import javax.swing.ActionMap;
    61 import javax.swing.InputMap;
    62 import org.netbeans.junit.NbTestCase;
    63 import org.openide.util.Lookup;
    64 import org.openide.util.Lookup.Template;
    65 import org.openide.util.LookupEvent;
    66 import org.openide.util.LookupListener;
    67 
    68 @SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
    69 public class AbstractLookupBaseHid extends NbTestCase {
    70     private static AbstractLookupBaseHid running;
    71 
    72     /** instance content to work with */
    73     InstanceContent ic;
    74     /** the lookup to work on */
    75     protected Lookup instanceLookup;
    76     /** the lookup created to work with */
    77     private Lookup lookup;
    78     /** implementation of methods that can influence the behaviour */
    79     Impl impl;
    80     
    81     protected AbstractLookupBaseHid(String testName, Impl impl) {
    82         super(testName);
    83         if (impl == null && (this instanceof Impl)) {
    84             impl = (Impl)this;
    85         }
    86         this.impl = impl;
    87     }
    88     
    89     protected @Override void setUp() {
    90         this.ic = new InstanceContent ();
    91         
    92         beforeActualTest(getName());
    93         
    94         this.instanceLookup = createInstancesLookup (ic);
    95         this.lookup = createLookup (instanceLookup);
    96         running = this;
    97     }        
    98     
    99     protected @Override void tearDown() {
   100         running = null;
   101     }
   102     
   103     /** The methods to influence test behaviour */
   104     public static interface Impl {
   105         /** Creates the initial abstract lookup.
   106          */
   107         public Lookup createInstancesLookup (InstanceContent ic);
   108         /** Creates an lookup for given lookup. This class just returns 
   109          * the object passed in, but subclasses can be different.
   110          * @param lookup in lookup
   111          * @return a lookup to use
   112          */
   113         public Lookup createLookup (Lookup lookup);
   114         
   115         /** If the impl has any caches that would prevent the system
   116          * to not garbage collect correctly, then clear them now.
   117          */
   118         public void clearCaches ();
   119     }
   120     
   121     private Lookup createInstancesLookup (InstanceContent ic) {
   122         return impl.createInstancesLookup (ic);
   123     }
   124     
   125     private Lookup createLookup (Lookup lookup) {
   126         return impl.createLookup (lookup);
   127     }
   128     
   129     /** instances that we register */
   130     private static Object[] INSTANCES = new Object[] {
   131         new Integer (10), 
   132         new Object ()
   133     };
   134     
   135     /** Test if first is really first.
   136      */
   137     public void testFirst () {
   138         Integer i1 = 1;
   139         Integer i2 = 2;
   140         
   141         ic.add (i1);
   142         ic.add (i2);
   143         
   144         Integer found = lookup.lookup(Integer.class);
   145         if (found != i1) {
   146             fail ("First object is not first: " + found + " != " + i1);
   147         }
   148         
   149         List<Integer> list = new ArrayList<Integer>();
   150         list.add (i2);
   151         list.add (i1);
   152         ic.set (list, null);
   153         
   154         found = lookup.lookup (Integer.class);
   155         if (found != i2) {
   156             fail ("Second object is not first after reorder: " + found + " != " + i2);
   157         }
   158         
   159     }
   160 
   161     public void testToString() {
   162         String txt = lookup.toString();
   163         assertNotNull("Something is there", txt);
   164         assertTrue("Something2: " + txt, txt.length() > 0);
   165     }
   166 
   167 
   168     /** Tests ordering of items in the lookup.
   169     */
   170     public void testOrder () {
   171         addInstances (INSTANCES);
   172 
   173         if (INSTANCES[0] != lookup.lookup (INSTANCES[0].getClass ())) {
   174             fail ("First object in intances not found");
   175         }
   176 
   177         Iterator<?> all = lookup.lookupAll(Object.class).iterator();
   178         checkIterator ("Difference between instances added and found", all, Arrays.asList (INSTANCES));
   179     }
   180     
   181     /** Checks the reorder of items in lookup reflects the result.
   182      * Testing both classes and interfaces, because they are often treated
   183      * especially.
   184      */
   185     public void testReorder () {
   186         String s1 = "s2";
   187         String s2 = "s1";
   188         Runnable r1 = new Runnable () {
   189             public void run () {}
   190         };
   191         Runnable r2 = new Runnable () {
   192             public void run () {}
   193         };
   194         List<Object> l = new ArrayList<Object>();
   195 
   196         l.add (s1);
   197         l.add (s2);
   198         l.add (r1);
   199         l.add (r2);
   200         ic.set (l, null);
   201      
   202         assertEquals ("s1 is found", s1, lookup.lookup (String.class));
   203         assertEquals ("r1 is found", r1, lookup.lookup (Runnable.class));
   204         
   205         Collections.reverse (l);
   206         
   207         ic.set (l, null);
   208         
   209         assertEquals ("s2 is found", s2, lookup.lookup (String.class));
   210         assertEquals ("r2 is found", r2, lookup.lookup (Runnable.class));
   211     }
   212     
   213     /** Tries to set empty collection to the lookup.
   214      */
   215     public void testSetEmpty () {
   216         ic.add ("A serializable string");
   217         lookup.lookup (Serializable.class);
   218         
   219         ic.set (Collections.emptyList(), null);
   220     }
   221     
   222     /** Tests a more complex reorder on nodes.
   223      */
   224     public void testComplexReorder () {
   225         Integer i1 = 1;
   226         Long i2 = 2L;
   227         
   228         List<Object> l = new ArrayList<Object>();
   229         l.add (i1);
   230         l.add (i2);
   231         ic.set (l, null);
   232         
   233         assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
   234         assertEquals ("Find long", i2, lookup.lookup (Long.class));
   235         assertEquals ("Find number", i1, lookup.lookup (Number.class));
   236         
   237         Collections.reverse (l);
   238         
   239         ic.set (l, null);
   240         
   241         assertEquals ("Find integer", i1, lookup.lookup (Integer.class));
   242         assertEquals ("Find long", i2, lookup.lookup (Long.class));
   243         assertEquals ("Find number", i2, lookup.lookup (Number.class));
   244     }
   245     
   246     /** Checks whether setPairs keeps the order.
   247      */
   248     public void testSetPairs () {
   249         // test setPairs method
   250         List<Object> li = new ArrayList<Object>();
   251         li.addAll (Arrays.asList (INSTANCES));
   252         ic.set (li, null);
   253         
   254         Lookup.Result<Object> res = lookup.lookupResult(Object.class);
   255         Iterator<?> all = res.allInstances().iterator();
   256         checkIterator ("Original order not kept", all, li);
   257         
   258         // reverse the order
   259         Collections.reverse (li);
   260         
   261         // change the pairs
   262         LL listener = new LL (res);
   263         res.addLookupListener (listener);
   264         ic.set (li, null);
   265         if (listener.getCount () != 1) {
   266             fail ("Result has not changed even we set reversed order");
   267         }
   268         
   269         all = res.allInstances ().iterator ();
   270         checkIterator ("Reversed order not kept", all, li);
   271     }
   272 
   273     /** Checks whether setPairs fires correct events.
   274      */
   275     public void testSetPairsFire () {
   276         // test setPairs method
   277         List<Object> li = new ArrayList<Object>();
   278         li.addAll (Arrays.asList (INSTANCES));
   279         ic.set (li, null);
   280         
   281         Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
   282         Iterator<?> all = res.allInstances().iterator();
   283         checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
   284         
   285         // change the pairs
   286         LL listener = new LL (res);
   287         res.addLookupListener (listener);
   288 
   289         List<Object> l2 = new ArrayList<Object>(li);
   290         l2.remove (INSTANCES[0]);
   291         ic.set (l2, null);
   292 
   293         all = lookup.lookupAll(Object.class).iterator();
   294         checkIterator ("The removed integer is not noticed", all, l2);
   295 
   296         if (listener.getCount () != 1) {
   297             fail ("Nothing has not been fired");
   298         }
   299     }
   300 
   301     /** Checks whether set pairs does not fire when they should not.
   302     */
   303     public void testSetPairsDoesNotFire () {
   304         Object tmp = new Object ();
   305 
   306         List<Object> li = new ArrayList<Object>();
   307         li.add (tmp);
   308         li.addAll (Arrays.asList (INSTANCES));
   309         ic.set (li, null);
   310         
   311         Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
   312         Iterator<?> all = res.allInstances ().iterator ();
   313         checkIterator ("Integer is not there", all, Collections.nCopies (1, INSTANCES[0]));
   314         
   315         // change the pairs
   316         LL listener = new LL (res);
   317         res.addLookupListener (listener);
   318 
   319         List<Object> l2 = new ArrayList<Object>(li);
   320         l2.remove (tmp);
   321         ic.set (l2, null);
   322 
   323         all = lookup.lookupAll(Object.class).iterator();
   324         checkIterator ("The removed integer is not noticed", all, l2);
   325 
   326         if (listener.getCount () != 0) {
   327             fail ("Something has been fired");
   328         }
   329     }
   330     
   331     /** Test whether after registration it is possible to find registered objects
   332     * 
   333      */
   334     public void testLookupAndAdd () throws Exception {
   335         addInstances (INSTANCES);
   336 
   337         for (int i = 0; i < INSTANCES.length; i++) {
   338             Object obj = INSTANCES[i];
   339             findAll (lookup, obj.getClass (), true);
   340         }
   341     }
   342 
   343     /** Tries to find all classes and superclasses in the lookup.
   344     */
   345     private void findAll(Lookup lookup, Class<?> clazz, boolean shouldBeThere) {
   346         if (clazz == null) return;
   347 
   348         Object found = lookup.lookup (clazz);
   349         if (found == null) {
   350             if (shouldBeThere) {
   351                 // should find at either instance or something else, but must
   352                 // find at least something
   353                 fail ("Lookup (" + clazz.getName () + ") found nothing");
   354             }
   355         } else {
   356             if (!shouldBeThere) {
   357                 // should find at either instance or something else, but must
   358                 // find at least something
   359                 fail ("Lookup (" + clazz.getName () + ") found " + found);
   360             }
   361         }
   362 
   363         Lookup.Result<?> res = lookup.lookupResult(clazz);
   364         Collection<?> collection = res.allInstances();
   365 
   366         for (int i = 0; i < INSTANCES.length; i++) {
   367             boolean isSubclass = clazz.isInstance (INSTANCES[i]);
   368             boolean isThere = collection.contains (INSTANCES[i]);
   369 
   370             if (isSubclass != isThere) {
   371                 // a problem found
   372                 // should find at either instance or something else, but must
   373                 // find at least something
   374                 fail ("Lookup.Result (" + clazz.getName () + ") for " + INSTANCES[i] + " is subclass: " + isSubclass + " isThere: " + isThere);
   375             }
   376         }
   377 
   378         // go on for superclasses
   379 
   380         findAll (lookup, clazz.getSuperclass (), shouldBeThere);
   381 
   382         Class[] ies = clazz.getInterfaces ();
   383         for (int i = 0; i < ies.length; i++) {
   384             findAll (lookup, ies[i], shouldBeThere);
   385         }
   386     }
   387     
   388     /** Test if it is possible to remove a registered object. */
   389     public void testRemoveRegisteredObject() {
   390         Integer inst = new Integer(10);
   391         
   392         ic.add(inst);
   393         if (lookup.lookup(inst.getClass()) == null) {
   394             // should find an instance
   395             fail("Lookup (" + inst.getClass().getName () + ") found nothing");
   396         }
   397         
   398         ic.remove(inst);
   399         if (lookup.lookup(inst.getClass()) != null) {
   400             // should NOT find an instance
   401             fail("Lookup (" + inst.getClass().getName () +
   402                 ") found an instance after remove operation");
   403         }
   404     }
   405     
   406     public void testCanReturnReallyStrangeResults () throws Exception {
   407         class QueryingPair extends AbstractLookup.Pair<Object> {
   408             private Integer i = 434;
   409             
   410             //
   411             // do the test
   412             //
   413             
   414             public void doTest () throws Exception {
   415                 ic.add (i);
   416                 ic.addPair (this);
   417                 
   418                 Object found = lookup.lookup (QueryingPair.class);
   419                 assertEquals ("This object is found", this, found);
   420             }
   421             
   422             
   423             //
   424             // Implementation of pair
   425             // 
   426         
   427             public String getId() {
   428                 return getType ().toString();
   429             }
   430 
   431             public String getDisplayName() {
   432                 return getId ();
   433             }
   434 
   435             public Class<?> getType() {
   436                 return getClass ();
   437             }
   438 
   439             protected boolean creatorOf(Object obj) {
   440                 return obj == this;
   441             }
   442 
   443             protected boolean instanceOf(Class<?> c) {
   444                 assertEquals ("Integer found or exception is thrown", i, lookup.lookup (Integer.class));
   445                 return c.isAssignableFrom(getType ());
   446             }
   447 
   448             public Object getInstance() {
   449                 return this;
   450             }
   451             
   452             
   453         }
   454         
   455         
   456         QueryingPair qp = new QueryingPair ();
   457         qp.doTest ();
   458     }
   459     
   460     /** Test of firing events. */
   461     public void testLookupListener() {
   462         Object inst = 10;
   463         Lookup.Result<?> res = lookup.lookupResult(inst.getClass());
   464         res.allInstances ();
   465         
   466         LL listener = new LL(res);
   467         res.addLookupListener(listener);
   468         
   469         ic.add(inst);
   470         if (listener.getCount() == 0) {
   471             fail("None event fired during NbLookup.addPair()");
   472         }
   473         
   474         ic.remove(inst);
   475         if (listener.getCount() == 0) {
   476             fail("None event fired during NbLookup.removePair()");
   477         }
   478         
   479         ic.add(inst);
   480         if (listener.getCount() == 0) {
   481             fail("None event fired during second NbLookup.addPair()");
   482         }
   483         
   484         ic.remove(inst);
   485         if (listener.getCount() == 0) {
   486             fail("None event fired during second NbLookup.removePair()");
   487         }
   488     }
   489     
   490     /** Testing identity of the lookup.
   491      */
   492     public void testId () {
   493         Lookup.Template<?> templ;
   494         int cnt;
   495         
   496         addInstances (INSTANCES);
   497         
   498         Lookup.Result<?> res = lookup.lookupResult(Object.class);
   499         for (AbstractLookup.Item<?> item : res.allItems()) {
   500             
   501             templ = new Lookup.Template<Object>(null, item.getId(), null);
   502             cnt = lookup.lookup (templ).allInstances ().size ();
   503             if (cnt != 1) {
   504                 fail ("Identity lookup failed. Instances = " + cnt);
   505             }
   506 
   507             templ = makeTemplate(item.getType(), item.getId());
   508             cnt = lookup.lookup (templ).allInstances ().size ();
   509             if (cnt != 1) {
   510                 fail ("Identity lookup with type failed. Instances = " + cnt);
   511             }
   512             
   513             templ = makeTemplate(this.getClass(), item.getId());
   514             cnt = lookup.lookup (templ).allInstances ().size ();
   515             if (cnt != 0) {
   516                 fail ("Identity lookup with wrong type failed. Instances = " + cnt);
   517             }
   518             
   519             templ = new Lookup.Template<Object>(null, null, item.getInstance());
   520             cnt = lookup.lookup (templ).allInstances ().size ();
   521             if (cnt != 1) {
   522                 fail ("Instance lookup failed. Instances = " + cnt);
   523             }
   524 
   525             templ = new Lookup.Template<Object>(null, item.getId(), item.getInstance());
   526             cnt = lookup.lookup (templ).allInstances ().size ();
   527             if (cnt != 1) {
   528                 fail ("Instance & identity lookup failed. Instances = " + cnt);
   529             }
   530             
   531         }
   532     }
   533     private static <T> Lookup.Template<T> makeTemplate(Class<T> clazz, String id) { // captures type parameter
   534         return new Lookup.Template<T>(clazz, id, null);
   535     }
   536     
   537     /** Tests adding and removing.
   538      */
   539     public void testAddAndRemove () throws Exception {
   540         Object map = new javax.swing.ActionMap ();
   541         LL ll = new LL ();
   542         
   543         Lookup.Result<?> res = lookup.lookupResult(map.getClass());
   544         res.allItems();
   545         res.addLookupListener (ll);
   546         ll.source = res;
   547         
   548         ic.add (map);
   549         
   550         assertEquals ("First change when adding", ll.getCount (), 1);
   551         
   552         ic.remove (map);
   553         
   554         assertEquals ("Second when removing", ll.getCount (), 1);
   555         
   556         ic.add (map);
   557         
   558         assertEquals ("Third when readding", ll.getCount (), 1);
   559         
   560         ic.remove (map);
   561         
   562         assertEquals ("Forth when reremoving", ll.getCount (), 1);
   563         
   564     }
   565     
   566     /** Will a class garbage collect even it is registered in lookup.
   567      */
   568     public void testGarbageCollect () throws Exception {
   569         ClassLoader l = new CL ();
   570         Class<?> c = l.loadClass(Garbage.class.getName());
   571         Reference<?> ref = new WeakReference<Object>(c);
   572 
   573         lookup.lookup (c);
   574         
   575         // now test garbage collection
   576         c = null;
   577         l = null;
   578         impl.clearCaches ();
   579         assertGC ("The classloader has not been garbage collected!", ref);
   580     }
   581                 
   582     /** Items are the same as results.
   583      */
   584     public void testItemsAndIntances () {
   585         addInstances (INSTANCES);
   586         
   587         Lookup.Result<Object> r = lookup.lookupResult(Object.class);
   588         Collection<? extends Lookup.Item<?>> items = r.allItems();
   589         Collection<?> insts = r.allInstances();
   590         
   591         if (items.size () != insts.size ()) {
   592             fail ("Different size of sets");
   593         }
   594 
   595         for (Lookup.Item<?> item : items) {
   596             if (!insts.contains (item.getInstance ())) {
   597                 fail ("Intance " + item.getInstance () + " is missing in " + insts);
   598             }
   599         }
   600     }
   601     
   602     /** Checks search for interface.
   603      */
   604     public void testSearchForInterface () {
   605         Lookup.Template<Serializable> t = new Lookup.Template<Serializable>(Serializable.class, null, null);
   606         
   607         assertNull("Nothing to find", lookup.lookupItem (t));
   608         
   609         Serializable s = new Serializable () {};
   610         ic.add (s);
   611         
   612         Lookup.Item item = lookup.lookupItem (t);
   613         assertNotNull ("Something found", item);
   614     }
   615 
   616     /** Test to add broken item if it incorrectly answers instanceOf questions.
   617      */
   618     public void testIncorectInstanceOf40364 () {
   619         final Long sharedLong = new Long (0);
   620         
   621         class P extends AbstractLookup.Pair<Object> {
   622             public boolean isLong;
   623             
   624             P (boolean b) {
   625                 isLong = b;
   626             }
   627             
   628             protected boolean creatorOf (Object obj) {
   629                 return obj == sharedLong;
   630             }
   631             
   632             public String getDisplayName () {
   633                 return "";
   634             }
   635             
   636             public String getId () {
   637                 return "";
   638             }
   639             
   640             public Object getInstance () {
   641                 return sharedLong;
   642             }
   643             
   644             public Class<?> getType() {
   645                 return isLong ? Long.class : Number.class;
   646             }
   647             
   648             protected boolean instanceOf(Class<?> c) {
   649                 return c.isAssignableFrom (getType ());
   650             }
   651     
   652             public @Override int hashCode() {
   653                 return getClass ().hashCode ();
   654             }    
   655 
   656             public @Override boolean equals(Object obj) {
   657                 return obj != null && getClass ().equals (obj.getClass ());
   658             }
   659         }
   660         
   661         // to create the right structure in the lookup
   662         lookup.lookup (Object.class);
   663         lookup.lookup (Long.class);
   664         lookup.lookup (Number.class);
   665         
   666         P lng1 = new P (true);
   667         ic.addPair (lng1);
   668 
   669         P lng2 = new P (false);
   670         ic.setPairs (Collections.singleton (lng2));
   671         
   672         Collection<? extends Lookup.Item<?>> res = lookup.lookupResult(Object.class).allItems();
   673         assertEquals ("Just one pair", 1, res.size ());
   674     }
   675 
   676     public void testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly () throws Exception {
   677         class X implements TestInterfaceInheritanceA, TestInterfaceInheritanceB {
   678         }
   679         final X shared = new X ();
   680         
   681         class P extends AbstractLookup.Pair<Object> {
   682             public int howLong;
   683             
   684             P (int b) {
   685                 howLong = b;
   686             }
   687             
   688             protected boolean creatorOf (Object obj) {
   689                 return obj == shared;
   690             }
   691             
   692             public String getDisplayName () {
   693                 return "";
   694             }
   695             
   696             public String getId () {
   697                 return "";
   698             }
   699             
   700             public Object getInstance () {
   701                 return shared;
   702             }
   703             
   704             public Class<?> getType() {
   705                 return howLong == 0 ? TestInterfaceInheritanceB.class : TestInterfaceInheritanceA.class;
   706             }
   707             
   708             protected boolean instanceOf(Class<?> c) {
   709                 return c.isAssignableFrom (getType ());
   710             }
   711     
   712             public @Override int hashCode() {
   713                 return getClass ().hashCode ();
   714             }    
   715 
   716             public @Override boolean equals(Object obj) {
   717                 if (obj instanceof P) {
   718                     P p = (P)obj;
   719                     if (this.howLong > 0) {
   720                         this.howLong--;
   721                         return false;
   722                     }
   723                     if (p.howLong > 0) {
   724                         p.howLong--;
   725                         return false;
   726                     }
   727                     return getClass ().equals (p.getClass ());
   728                 }
   729                 return false;
   730             }
   731         }
   732         
   733         // to create the right structure in the lookup
   734         Lookup.Result<?> a = lookup.lookupResult(TestInterfaceInheritanceA.class);
   735         Lookup.Result<?> b = lookup.lookupResult(TestInterfaceInheritanceB.class);
   736         
   737         P lng1 = new P (0);
   738         ic.addPair (lng1);
   739         
   740         assertEquals ("One in a", 1, a.allItems ().size ());
   741         assertEquals ("One in b", 1, b.allItems ().size ());
   742 
   743         P lng2 = new P (1);
   744         
   745 
   746         /* Following call used to generate this exception:
   747     java.lang.IllegalStateException: Duplicate pair in treePair1:  pair2:  index1: 0 index2: 0 item1: org.openide.util.lookup.AbstractLookupBaseHid$1X@1a457b6 item2: org.openide.util.lookup.AbstractLookupBaseHid$1X@1a457b6 id1: 7a78d3 id2: 929206
   748 	at org.openide.util.lookup.ALPairComparator.compare(ALPairComparator.java:52)
   749 	at java.util.Arrays.mergeSort(Arrays.java:1284)
   750 	at java.util.Arrays.sort(Arrays.java:1223)
   751 	at java.util.Collections.sort(Collections.java:159)
   752 	at org.openide.util.lookup.InheritanceTree.retainAllInterface(InheritanceTree.java:753)
   753 	at org.openide.util.lookup.InheritanceTree.retainAll(InheritanceTree.java:183)
   754 	at org.openide.util.lookup.DelegatingStorage.retainAll(DelegatingStorage.java:83)
   755 	at org.openide.util.lookup.AbstractLookup.setPairsAndCollectListeners(AbstractLookup.java:238)
   756 	at org.openide.util.lookup.AbstractLookup.setPairs(AbstractLookup.java:203)
   757 	at org.openide.util.lookup.AbstractLookup$Content.setPairs(AbstractLookup.java:885)
   758 	at org.openide.util.lookup.AbstractLookupBaseHid.testAbsolutelyCrazyWayToSimulateIssue48590ByChangingTheBehaviourOfEqualOnTheFly(AbstractLookupBaseHid.java:696)
   759 	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
   760 	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
   761 	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
   762 	at org.netbeans.junit.NbTestCase.run(NbTestCase.java:119)
   763     */  
   764         ic.setPairs (Collections.singleton (lng2));
   765 
   766         
   767     }
   768     
   769     public void testInstancesArePreservedFoundWhenFixing48590 () throws Exception {
   770         class X implements Runnable, Serializable {
   771             public void run () {
   772                 
   773             }
   774             
   775             public void assertOnlyMe (String msg, Lookup.Result<?> res) {
   776                 Collection<?> col = res.allInstances();
   777                 assertEquals (msg + " just one", 1, col.size ());
   778                 assertSame (msg + " and it is me", this, col.iterator ().next ());
   779             }
   780         }
   781         
   782         Lookup.Result<?> runnable = lookup.lookupResult(Runnable.class);
   783         Lookup.Result<?> serial = lookup.lookupResult(Serializable.class);
   784         
   785         
   786         X x = new X ();
   787         ic.add (x);
   788         
   789         
   790         x.assertOnlyMe ("x implements it (1)", runnable);
   791         x.assertOnlyMe ("x implements it (2)", serial);
   792         
   793         ic.set (Collections.singleton (x), null);
   794         
   795         x.assertOnlyMe ("x implements it (3)", runnable);
   796         x.assertOnlyMe ("x implements it (4)", serial);
   797     }
   798     
   799     /** Testing lookup of inherited classes. */
   800     public void testInheritance() {
   801         class A {}
   802         class B extends A implements java.rmi.Remote {}
   803         class BB extends B {}
   804         class C extends A implements java.rmi.Remote {}
   805         class D extends A {}
   806         
   807         A[] types = {new B(), new BB(), new C(), new D()};
   808         
   809         for (int i = 0; i < types.length; i++) {
   810             ic.add(types[i]);
   811             if (lookup.lookup(types[i].getClass()) == null) {
   812                 // should find an instance
   813                 fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
   814             }
   815         }
   816         
   817         int size1, size2;
   818         
   819         //interface query
   820         size1 = lookup.lookupAll(java.rmi.Remote.class).size();
   821         size2 = countInstances(types, java.rmi.Remote.class);
   822         
   823         if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
   824         
   825         // superclass query
   826         size1 = lookup.lookupAll(A.class).size();
   827         size2 = countInstances(types, A.class);
   828         
   829         if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
   830     }
   831     
   832     /** Test interface inheritance.
   833      */
   834     public void testInterfaceInheritance() {
   835         TestInterfaceInheritanceA[] types = {
   836             new TestInterfaceInheritanceB() {},
   837             new TestInterfaceInheritanceBB() {},
   838             new TestInterfaceInheritanceC() {},
   839             new TestInterfaceInheritanceD() {}
   840         };
   841         
   842         for (int i = 0; i < types.length; i++) {
   843             ic.add(types[i]);
   844             if (lookup.lookup(types[i].getClass()) == null) {
   845                 // should find an instance
   846                 fail("Lookup (" + types[i].getClass().getName () + ") found nothing");
   847             }
   848         }
   849         
   850         int size1, size2;
   851         
   852         //interface query
   853         LL l = new LL ();
   854         Lookup.Result<?> res = lookup.lookupResult(java.rmi.Remote.class);
   855         l.source = res;
   856         size1 = res.allInstances().size();
   857         size2 = countInstances(types, java.rmi.Remote.class);
   858         
   859         if (size1 != size2) fail("Lookup with interface failed: " + size1 + " != " + size2);
   860         
   861         // superclass query
   862         size1 = lookup.lookupAll(TestInterfaceInheritanceA.class).size();
   863         size2 = countInstances(types, TestInterfaceInheritanceA.class);
   864         
   865         if (size1 != size2) fail("Lookup with superclass failed: " + size1 + " != " + size2);
   866         
   867         res.addLookupListener (l);
   868         ic.remove (types[0]);
   869         
   870         if (l.getCount () != 1) {
   871             fail ("No notification that a Remote is removed");
   872         }
   873     }
   874     
   875     /** Checks whether the AbstractLookup is guarded against modifications
   876      * while doing some kind of modification.
   877      */
   878     public void testModificationArePreventedWhenDoingModifications () throws Exception {
   879         BrokenPair broken = new BrokenPair (true, false);
   880         ic.addPair (broken);
   881         
   882         Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
   883         Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
   884         assertEquals ("Broken is found", broken, item);
   885     }
   886     
   887     public void testModificationArePreventedWhenDoingModificationsResult () throws Exception {
   888         BrokenPair broken = new BrokenPair (false, true);
   889         ic.addPair (broken);
   890         
   891         Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
   892         
   893         Collection<? extends BrokenPair> c = lookup.lookup (templ).allInstances();
   894         assertEquals ("One item", 1, c.size ());
   895         assertEquals ("Broken is found again", broken, c.iterator().next ());
   896     }
   897     
   898     public void testModificationArePreventedWhenDoingModificationsItemAndResult () throws Exception {
   899         BrokenPair broken = new BrokenPair (false, true);
   900         ic.addPair (broken);
   901         
   902         Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
   903         Lookup.Item<BrokenPair> item = lookup.lookupItem (templ);
   904         assertEquals ("Broken is found", broken, item);
   905         
   906         Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
   907         assertEquals ("One item", 1, c.size ());
   908         assertEquals ("Broken is found again", broken, c.iterator().next ());
   909     }
   910 
   911     public void testModificationArePreventedWhenDoingModificationsResultAndItem () throws Exception {
   912         BrokenPair broken = new BrokenPair (false, true);
   913         ic.addPair (broken);
   914         
   915         Lookup.Template<BrokenPair> templ = new Lookup.Template<BrokenPair>(BrokenPair.class);
   916         Collection<? extends BrokenPair> c = lookup.lookup(templ).allInstances();
   917         assertEquals ("One item", 1, c.size ());
   918         assertEquals ("Broken is found again", broken, c.iterator().next ());
   919         
   920         Object item = lookup.lookupItem (templ);
   921         assertEquals ("Broken is found", broken, item);
   922     }
   923     
   924     public void testAddALotOfPairsIntoTheLookupOneByOne () throws Exception {
   925         Lookup.Result<Integer> res = lookup.lookupResult(Integer.class);
   926         for (int i = 0; i < 1000; i++) {
   927             ic.add(i);
   928         }
   929         assertEquals (
   930             "there is the right count", 
   931             1000, 
   932             res.allItems().size ()
   933         );
   934     }
   935     
   936     public void testAddALotOfPairsIntoTheLookup () throws Exception {
   937         List<Integer> arr = new ArrayList<Integer>();
   938         for (int i = 0; i < 1000; i++) {
   939             arr.add(i);
   940         }
   941         ic.set (arr, null);
   942         
   943         assertEquals (
   944             "there is the right count", 
   945             1000, 
   946             lookup.lookupResult(Integer.class).allItems().size()
   947         );
   948     }
   949 
   950     
   951     public void testDoubleAddIssue35274 () throws Exception {
   952         class P extends AbstractLookup.Pair<Object> {
   953             protected boolean creatorOf(Object obj) { return false; }
   954             public String getDisplayName() { return ""; }
   955             public String getId() { return ""; }
   956             public Object getInstance() { return null; }
   957             public Class<?> getType() { return Object.class; }
   958             protected boolean instanceOf(Class<?> c) { return c.isAssignableFrom(getType ()); }
   959             public @Override int hashCode() {return getClass().hashCode();}
   960             public @Override boolean equals(Object obj) {return getClass() == obj.getClass();}
   961         }
   962         
   963         P p = new P ();
   964         
   965         ic.addPair (p);
   966         ic.addPair (p);
   967         
   968         Lookup.Result<Object> result = lookup.lookupResult(Object.class);
   969         Collection res = result.allItems ();
   970         assertEquals ("One item there", 1, res.size ());
   971         assertTrue ("It is the p", p == res.iterator ().next ());
   972         
   973         P p2 = new P ();
   974         ic.addPair (p2);
   975         
   976         Reference<?> ref = new WeakReference<Object>(result);
   977         result = null;
   978         assertGC ("The result can disappear", ref);
   979         
   980         impl.clearCaches ();
   981         
   982         result = lookup.lookupResult(Object.class);
   983         res = result.allItems ();
   984         assertEquals ("One item is still there", 1, res.size ());
   985         assertTrue ("But the p2 replaced p", p2 == res.iterator ().next ());
   986         
   987     }
   988     
   989     /** Test for proper serialization.
   990      */
   991     public void testSerializationSupport () throws Exception {
   992         doSerializationSupport (1);
   993     }
   994     public void testDoubleSerializationSupport () throws Exception {
   995         doSerializationSupport (2);
   996     }
   997 
   998     private void doSerializationSupport (int count) throws Exception {
   999         if (lookup instanceof Serializable) {
  1000             ic.addPair (new SerialPair ("1"));
  1001             ic.addPair (new SerialPair ("2"));
  1002             ic.addPair (new SerialPair ("3"));
  1003 
  1004             Lookup l = (Lookup)reserialize(lookup);
  1005 
  1006             assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
  1007 
  1008             assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
  1009 
  1010             while (count-- > 0) {
  1011                 l = (Lookup)reserialize(l);
  1012             }
  1013 
  1014             assertEquals ("Able to answer simple query", "1", l.lookup (String.class));
  1015 
  1016             assertEquals ("Three objects there", 3, l.lookup (new Lookup.Template (String.class)).allInstances().size ());
  1017         }
  1018     }
  1019 
  1020     /** When a lookup with two different versions of the same class 
  1021      * get's serialized, the results may be very bad. 
  1022      */
  1023     public void testSerializationOfTwoClassesWithTheSameName () throws Exception {
  1024         if (lookup instanceof Serializable) {
  1025             doTwoSerializedClasses (false, false);
  1026         }
  1027     }
  1028     public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSave () throws Exception {
  1029         if (lookup instanceof Serializable) {
  1030             doTwoSerializedClasses (true, false);
  1031         }
  1032     }
  1033     public void testSerializationOfTwoClassesWithTheSameNameWithBroken () throws Exception {
  1034         if (lookup instanceof Serializable) {
  1035             doTwoSerializedClasses (false, true);
  1036         }
  1037     }
  1038     public void testSerializationOfTwoClassesWithTheSameNameButQueryBeforeSaveWithBroken () throws Exception {
  1039         if (lookup instanceof Serializable) {
  1040             doTwoSerializedClasses (true, true);
  1041         }
  1042     }
  1043    
  1044     private void doTwoSerializedClasses (boolean queryBeforeSerialization, boolean useBroken) throws Exception {
  1045         ClassLoader loader = new CL ();
  1046         Class c = loader.loadClass (Garbage.class.getName ());
  1047 
  1048         // in case of InheritanceTree it creates a slot for class Garbage
  1049         lookup.lookup(c);
  1050 
  1051         // but creates new instance and adds it into the lookup
  1052         // without querying for it
  1053         loader = new CL ();
  1054         c = loader.loadClass (Garbage.class.getName ());
  1055 
  1056         Object theInstance = c.newInstance ();
  1057 
  1058         ic.addPair (new SerialPair (theInstance));
  1059 
  1060         Broken2Pair broken = null;
  1061         if (useBroken) {
  1062             broken = new Broken2Pair ();
  1063             ic.addPair (broken);
  1064             
  1065             assertNull (
  1066                 "We need to create the slot for the List as " +
  1067                 "the Broken2Pair will ask for it after deserialization", 
  1068                 lookup.lookup (java.awt.List.class)
  1069             );
  1070         }
  1071 
  1072         if (queryBeforeSerialization) {
  1073             assertEquals ("Instance is found", theInstance, lookup.lookup (c));
  1074         }
  1075         
  1076         // replace the old lookup with new one
  1077         lookup = (Lookup)reserialize(lookup);
  1078         
  1079         Lookup.Result result = lookup.lookup (new Lookup.Template (Garbage.class));
  1080         assertEquals ("One item is the result", 1, result.allInstances ().size ());
  1081         Object r = result.allInstances ().iterator ().next ();
  1082         assertNotNull("A value is found", r);
  1083         assertEquals ("It is of the right class", Garbage.class, r.getClass());
  1084     }
  1085    
  1086     /** Test of reorder and item change which used to fail on interfaces.
  1087      */
  1088     public void testReoderingIssue13779 () throws Exception {
  1089         LinkedList arr = new LinkedList ();
  1090         
  1091         class R extends Exception implements Cloneable {
  1092         }
  1093         Object o1 = new R ();
  1094         Object o2 = new R ();
  1095         Object o3 = new R ();
  1096         
  1097         arr.add (o1);
  1098         arr.add (o2);
  1099         
  1100         ic.set (arr, null);
  1101         
  1102         Lookup.Result objectResult = lookup.lookup (new Lookup.Template (Exception.class));
  1103         Lookup.Result interfaceResult = lookup.lookup (new Lookup.Template (Cloneable.class));
  1104         objectResult.allItems ();
  1105         interfaceResult.allItems ();
  1106         
  1107         LL l1 = new LL (objectResult);
  1108         LL l2 = new LL (interfaceResult);
  1109         
  1110         objectResult.addLookupListener(l1);
  1111         interfaceResult.addLookupListener(l2);
  1112         
  1113         arr.addFirst (o3);
  1114         
  1115         ic.set (arr, null);
  1116         
  1117         assertEquals ("One change on objects", 1, l1.getCount ());
  1118         assertEquals ("One change on interfaces", 1, l2.getCount ());
  1119         
  1120         arr.addFirst (new Cloneable () { });
  1121         ic.set (arr, null);
  1122         
  1123         assertEquals ("No change on objects", 0, l1.getCount ());
  1124         assertEquals ("But one change on interfaces", 1, l2.getCount ());
  1125         
  1126     }
  1127     
  1128     public void testDeadlockBetweenProxyResultAndLookupIssue47772 () throws Exception {
  1129         final String myModule = "My Module";
  1130         ic.add (myModule);
  1131         
  1132         class MyProxy extends ProxyLookup {
  1133             public MyProxy () {
  1134                 super (new Lookup[] { lookup });
  1135             }
  1136         }
  1137         final MyProxy my = new MyProxy ();
  1138         
  1139         final Lookup.Result allModules = my.lookup (new Lookup.Template (String.class));
  1140         
  1141         class PairThatNeedsInfoAboutModules extends AbstractLookup.Pair {
  1142             public String getDisplayName () {
  1143                 return "Need a module";
  1144             }
  1145             public String getId () {
  1146                 return getDisplayName ();
  1147             }
  1148             public Class getType () {
  1149                 return Integer.class;
  1150             }
  1151             protected boolean instanceOf (Class c) {
  1152                 if (c == Integer.class) {
  1153                     synchronized (this) {
  1154                         notifyAll ();
  1155                         try {
  1156                             wait (1000);
  1157                         } catch (InterruptedException ex) {
  1158                             fail (ex.getMessage ());
  1159                         }
  1160                     }
  1161                     java.util.Collection coll = allModules.allInstances ();
  1162                     assertEquals ("Size is 1", 1, coll.size ());
  1163                     assertEquals ("My module is there", myModule, coll.iterator ().next ());
  1164                 }
  1165                 return c.isAssignableFrom (Integer.class);
  1166             }
  1167             
  1168             public Object getInstance () {
  1169                 return new Integer (10);
  1170             }
  1171             
  1172             protected boolean creatorOf (Object obj) {
  1173                 return new Integer (10).equals (obj);
  1174             }
  1175         }
  1176         
  1177         PairThatNeedsInfoAboutModules pair = new PairThatNeedsInfoAboutModules ();
  1178         ic.addPair (pair);
  1179         
  1180         synchronized (pair) {
  1181             class BlockInInstanceOf implements Runnable {
  1182                 public void run () {
  1183                     Integer i = my.lookup(Integer.class);
  1184                     assertEquals (new Integer (10), i);
  1185                 }
  1186             }
  1187             BlockInInstanceOf blk = new BlockInInstanceOf ();
  1188             Executors.newSingleThreadScheduledExecutor().schedule(blk, 0, TimeUnit.MICROSECONDS);
  1189             pair.wait ();
  1190         }
  1191         
  1192         java.util.Collection coll = allModules.allInstances ();
  1193         assertEquals ("Size is 1", 1, coll.size ());
  1194         assertEquals ("My module is there", myModule, coll.iterator ().next ());
  1195     }
  1196 
  1197     public void testAWayToGenerateProblem13779 () {
  1198         ic.add (new Integer (1));
  1199         ic.add (new Integer (2));
  1200         ic.add (new Integer (1));
  1201         ic.add (new Integer (2));
  1202         
  1203         Collection c = lookup.lookup (new Lookup.Template (Integer.class)).allInstances ();
  1204         assertEquals ("There are two objects", 2, c.size ());
  1205         
  1206     }
  1207     
  1208     /** Replacing items with different objects.
  1209      */
  1210     public void testReplacingObjectsDoesNotGenerateException () throws Exception {
  1211         LinkedList arr = new LinkedList ();
  1212         
  1213         class R extends Exception implements Cloneable {
  1214         }
  1215         arr.add (new R ());
  1216         arr.add (new R ());
  1217         
  1218         ic.set (arr, null);
  1219         
  1220         arr.clear();
  1221         
  1222         arr.add (new R ());
  1223         arr.add (new R ());
  1224         
  1225         ic.set (arr, null);
  1226     }
  1227 
  1228     public void testAfterDeserializationNoQueryIsPeformedOnAlreadyQueriedObjects() throws Exception {
  1229         if (! (lookup instanceof Serializable)) {
  1230             // well this test works only for serializable lookups
  1231             return;
  1232         }
  1233         
  1234         SerialPair my = new SerialPair ("no");
  1235         ic.addPair (my);
  1236         
  1237         Lookup.Result res = lookup.lookup (new Lookup.Template (String.class));
  1238         assertEquals ("One instance", 1, res.allInstances().size ());
  1239         assertEquals ("my.instanceOf called once", 1, my.countInstanceOf);
  1240         
  1241         Lookup serial = (Lookup)reserialize(lookup);
  1242         
  1243         Lookup.Result r2 = serial.lookup(new Lookup.Template(String.class));
  1244         
  1245         assertEquals ("One item", 1, r2.allItems ().size ());
  1246         Object one = r2.allItems().iterator().next ();
  1247         assertEquals ("The right class", SerialPair.class, one.getClass());
  1248         SerialPair p = (SerialPair)one;
  1249         
  1250         assertEquals ("p.instanceOf has not been queried", 0, p.countInstanceOf);
  1251     }
  1252     
  1253     /** Checks the iterator */
  1254     private <T> void checkIterator(String msg, Iterator<? extends T> it1, List<? extends T> list) {
  1255         int cnt = 0;
  1256         Iterator<? extends T> it2 = list.iterator();
  1257         while (it1.hasNext () && it2.hasNext ()) {
  1258             T n1 = it1.next();
  1259             T n2 = it2.next();
  1260             
  1261             if (n1 != n2) {
  1262                 fail (msg + " iterator[" + cnt + "] = " + n1 + " but list[" + cnt + "] = " + n2);
  1263             }
  1264             
  1265             cnt++;
  1266         }
  1267         
  1268         if (it1.hasNext ()) {
  1269             fail ("Iterator has more elements than list");
  1270         }
  1271         
  1272         if (it2.hasNext ()) {
  1273             fail ("List has more elements than iterator");
  1274         }
  1275     }
  1276     
  1277     
  1278     public void testResultsAreUnmodifyableOrAtLeastTheyDoNotPropagateToCache() throws Exception {
  1279         String s = "Ahoj";
  1280         
  1281         ic.add(s);
  1282         
  1283         Lookup.Result res = lookup.lookup(new Template(String.class));
  1284         
  1285         for (int i = 1; i < 5; i++) {
  1286             Collection c1 = res.allInstances();
  1287             Collection c2 = res.allClasses();
  1288             Collection c3 = res.allItems();
  1289 
  1290             assertTrue(i + ": c1 has it", c1.contains(s));
  1291             assertTrue(i + ": c2 has it", c2.contains(s.getClass()));
  1292             assertEquals(i + ": c3 has one", 1, c3.size());
  1293             Lookup.Item item = (Lookup.Item) c3.iterator().next();
  1294             assertEquals(i + ": c3 has it", s, item.getInstance());
  1295 
  1296             try {
  1297                 c1.remove(s);
  1298                 assertEquals("No elements now", 0, c1.size());
  1299             } catch (UnsupportedOperationException ex) {
  1300                 // ok, this need not be supported
  1301             }
  1302             try {
  1303                 c2.remove(s.getClass());
  1304                 assertEquals("No elements now", 0, c2.size());
  1305             } catch (UnsupportedOperationException ex) {
  1306                 // ok, this need not be supported
  1307             }
  1308             try {
  1309                 c3.remove(item);
  1310                 assertEquals("No elements now", 0, c3.size());
  1311             } catch (UnsupportedOperationException ex) {
  1312                 // ok, this need not be supported
  1313             }
  1314         }
  1315     }
  1316     
  1317     public void testSomeProblemWithDVBFrameworkSeemsToBeInLookup() {
  1318         for (int i = 0; i < 5; i++) {
  1319             ic.add(lookup);
  1320             assertEquals("Can be found", lookup, lookup.lookup(lookup.getClass()));
  1321             ic.set(Collections.EMPTY_LIST, null);
  1322         }        
  1323     }
  1324 
  1325     public void testListeningAndQueryingByTwoListenersInstances() {
  1326         doListeningAndQueryingByTwoListeners(0);
  1327     }
  1328     public void testListeningAndQueryingByTwoListenersClasses() {
  1329         doListeningAndQueryingByTwoListeners(1);        
  1330     }
  1331     public void testListeningAndQueryingByTwoListenersItems() {
  1332         doListeningAndQueryingByTwoListeners(2);
  1333     }
  1334     
  1335     
  1336     private void doListeningAndQueryingByTwoListeners(final int type) {
  1337         class L implements LookupListener {
  1338             Lookup.Result integer = lookup.lookup(new Template(Integer.class));
  1339             Lookup.Result number = lookup.lookup(new Template(Number.class));
  1340             Lookup.Result serial = lookup.lookup(new Template(Serializable.class));
  1341             
  1342             {
  1343                 integer.addLookupListener(this);
  1344                 number.addLookupListener(this);
  1345                 serial.addLookupListener(this);
  1346             }
  1347             
  1348             int round;
  1349             
  1350             public void resultChanged(LookupEvent ev) {
  1351                 Collection c1 = get(type, integer);
  1352                 Collection c2 = get(type, number);
  1353                 Collection c3 = get(type, serial);
  1354                 
  1355                 assertEquals("round " + round + " c1 vs. c2", c1, c2);
  1356                 assertEquals("round " + round + " c1 vs. c3", c1, c3);
  1357                 assertEquals("round " + round + " c2 vs. c3", c2, c3);
  1358                 
  1359                 round++;
  1360             }            
  1361 
  1362             private Collection get(int type, Lookup.Result res) {
  1363                 Collection c;
  1364                 switch(type) {
  1365                     case 0: c = res.allInstances(); break;
  1366                     case 1: c = res.allClasses(); break;
  1367                     case 2: c = res.allItems(); break;
  1368                     default: c = null; fail("Type: " + type); break;
  1369                 }
  1370                 
  1371                 assertNotNull(c);
  1372                 return new ArrayList(c);
  1373             }
  1374         }
  1375         
  1376         L listener = new L();
  1377         listener.resultChanged(null);
  1378         
  1379         for(int i = 0; i < 100; i++) {
  1380             ic.add(new Integer(i));
  1381         }
  1382         
  1383         assertEquals("3x100+1 checks", 301, listener.round);
  1384     }
  1385     
  1386     public void testChangeOfNodeDoesNotFireChangeInActionMap() {
  1387         ActionMap am = new ActionMap();
  1388         Lookup s = Lookups.singleton(am);
  1389         doChangeOfNodeDoesNotFireChangeInActionMap(am, s, false);
  1390     }
  1391     public void testChangeOfNodeDoesNotFireChangeInActionMapSimple() {
  1392         ActionMap am = new ActionMap();
  1393         Lookup s = Lookups.singleton(am);
  1394         doChangeOfNodeDoesNotFireChangeInActionMap(am, s, true);
  1395     }
  1396 
  1397     public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookupSimple() {
  1398         doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(true);
  1399     }
  1400     
  1401     public void testChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup() {
  1402         doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(false);
  1403     }
  1404     private void doChangeOfNodeDoesNotFireChangeInActionMapWithBeforeLookup(boolean wrapBySimple) {
  1405         final ActionMap am = new ActionMap();
  1406         
  1407         class Before extends AbstractLookup {
  1408             public InstanceContent ic;
  1409             public Before() {
  1410                 this(new InstanceContent());
  1411             }
  1412             
  1413             private Before(InstanceContent ic) {
  1414                 super(ic);
  1415                 this.ic = ic;
  1416             }
  1417 
  1418             protected @Override void beforeLookup(Template template) {
  1419                 if (ic != null) {
  1420                     ic.add(am);
  1421                     ic = null;
  1422                 }
  1423             }
  1424         }
  1425         
  1426         Before s = new Before();
  1427         doChangeOfNodeDoesNotFireChangeInActionMap(am, s, wrapBySimple);
  1428         
  1429         assertNull("beforeLookup called once", s.ic);
  1430     }
  1431     
  1432     private void doChangeOfNodeDoesNotFireChangeInActionMap(final ActionMap am, Lookup actionMapLookup, final boolean wrapBySimple) {
  1433         Lookup[] lookups = { lookup, actionMapLookup };
  1434         
  1435         class Provider implements Lookup.Provider {
  1436             ProxyLookup delegate;
  1437             Lookup query;
  1438             
  1439             public Provider(Lookup[] arr) {
  1440                 if (wrapBySimple) {
  1441                     delegate = new ProxyLookup(arr);
  1442                     query = Lookups.proxy(this);
  1443                 } else {
  1444                     query = delegate = new ProxyLookup(arr);
  1445                 }
  1446             }
  1447             
  1448             public Lookup getLookup() {
  1449                 return delegate;
  1450             }
  1451             
  1452             public void setLookups(Lookup... arr) {
  1453                 if (wrapBySimple) {
  1454                     delegate = new ProxyLookup(arr);                    
  1455                 } else {
  1456                     delegate.setLookups(arr);
  1457                 }
  1458             }
  1459         }
  1460         
  1461         Provider p = new Provider(lookups);
  1462         
  1463         Lookup.Result res = p.query.lookup(new Lookup.Template(ActionMap.class));
  1464         LL ll = new LL();
  1465         res.addLookupListener(ll);
  1466 
  1467         Collection c = res.allInstances();
  1468         assertFalse("Has next", c.isEmpty());
  1469         
  1470         ActionMap am1 = (ActionMap)c.iterator().next();
  1471         assertEquals("Am is there", am, am1);
  1472         
  1473         assertEquals("No change in first get", 0, ll.getCount());
  1474         
  1475         Object m1 = new InputMap();
  1476         Object m2 = new InputMap();
  1477         
  1478         ic.add(m1);
  1479         assertEquals("No change in ActionMap 1", 0, ll.getCount());
  1480         ic.set(Collections.singletonList(m2), null);
  1481         assertEquals("No change in ActionMap 2", 0, ll.getCount());
  1482         ic.add(m2);
  1483         assertEquals("No change in ActionMap 3", 0, ll.getCount());
  1484         p.setLookups(lookup, actionMapLookup, Lookup.EMPTY);
  1485         assertEquals("No change in ActionMap 4", 0, ll.getCount());
  1486         
  1487         ActionMap am2 = p.query.lookup(ActionMap.class);
  1488         assertEquals("Still the same action map", am, am2);
  1489         
  1490         
  1491         class Before extends AbstractLookup {
  1492             public InstanceContent ic;
  1493             public Before() {
  1494                 this(new InstanceContent());
  1495             }
  1496             
  1497             private Before(InstanceContent ic) {
  1498                 super(ic);
  1499                 this.ic = ic;
  1500             }
  1501 
  1502             protected @Override void beforeLookup(Template template) {
  1503                 if (ic != null) {
  1504                     ic.add(am);
  1505                     ic = null;
  1506                 }
  1507             }
  1508         }
  1509         
  1510         Before s = new Before();
  1511         
  1512         // adding different Before, but returning the same instance
  1513         // this happens with metaInfServices lookup often, moreover
  1514         // it adds the instance in beforeLookup, which confuses a lot
  1515         p.setLookups(new Lookup[]{ lookup, new Before() });
  1516         assertEquals("No change in ActionMap 5", 0, ll.getCount());
  1517         
  1518         
  1519     }
  1520 
  1521     public void testTasklistsCase() throws Exception {
  1522         ic.remove(new Object());
  1523     }
  1524     
  1525     
  1526 
  1527     public void testMultipleListeners() {
  1528         Object object = new ImplementationObject();
  1529         ic.add(object);
  1530         
  1531         Listener[] listeners = new Listener[4];
  1532         Lookup.Result result = lookup.lookup(new Lookup.Template(LookupObject.class));
  1533         for(int i = 0; i < listeners.length; ++i) {
  1534             listeners[i] = new Listener();
  1535             result.addLookupListener(listeners[i]);
  1536         }
  1537         // initialize listening
  1538         result.allItems();
  1539         
  1540         ic.remove(object);
  1541         
  1542         // Apparently, only odd-numbered listeners get called when there are multiple LookupListeners on a result
  1543         //for(int i = 0; i < listeners.length; ++i) {
  1544         //    System.out.println("Listener " + i + ": " + listeners[i].wasCalled());            
  1545         //}
  1546         for(int i = 0; i < listeners.length; ++i) {
  1547             assertTrue("Listener " + i + " called", listeners[i].wasCalled());
  1548         }
  1549     }
  1550 
  1551     static Object reserialize(Object o) throws Exception {
  1552         ByteArrayOutputStream os = new ByteArrayOutputStream();
  1553         ObjectOutputStream oos = new ObjectOutputStream(os);
  1554         oos.writeObject(o);
  1555         oos.close();
  1556 
  1557         ByteArrayInputStream is = new ByteArrayInputStream(os.toByteArray());
  1558         ObjectInputStream ois = new ObjectInputStream(is);
  1559         return ois.readObject();
  1560     }
  1561     
  1562     private class Listener implements LookupListener {
  1563         private boolean listenerCalled = false;
  1564         
  1565         public void resultChanged(LookupEvent ev) {
  1566             listenerCalled = true;
  1567         }
  1568         
  1569         public boolean wasCalled() {
  1570             return listenerCalled;
  1571         }
  1572         
  1573         public void reset() {
  1574             listenerCalled = false;
  1575         }
  1576     }
  1577     
  1578     private interface LookupObject {}
  1579     private class ImplementationObject implements LookupObject {}
  1580     private class NullObject implements LookupObject {}
  1581     
  1582     
  1583     public void testReturnSomethingElseThenYouClaimYouWillReturn() {
  1584         class Liar extends AbstractLookup.Pair {
  1585             public Object obj;
  1586             
  1587             protected boolean instanceOf(Class c) {
  1588                 return c.isAssignableFrom(String.class);
  1589             }
  1590 
  1591             protected boolean creatorOf(Object obj) {
  1592                 return this.obj == obj;
  1593             }
  1594 
  1595             public Object getInstance() {
  1596                 return this.obj;
  1597             }
  1598 
  1599             public Class getType() {
  1600                 return String.class;
  1601             }
  1602 
  1603             public String getId() {
  1604                 return String.class.getName();
  1605             }
  1606 
  1607             public String getDisplayName() {
  1608                 return getId();
  1609             }
  1610         }
  1611         
  1612         
  1613         Liar l = new Liar();
  1614         l.obj = new Integer(5);
  1615         
  1616         this.ic.addPair(l);
  1617         
  1618         Collection c = lookup.lookup(new Lookup.Template(String.class)).allInstances();
  1619         assertTrue("It is empty: " + c, c.isEmpty());
  1620     }
  1621 
  1622     public void testCanProxyLookupHaveWrongResults() {
  1623         class L implements LookupListener {
  1624             ProxyLookup pl;
  1625             Lookup.Result<String> original;
  1626             Lookup.Result<String> wrapped;
  1627             boolean ok;
  1628 
  1629             public void test() {
  1630                 pl = new ProxyLookup(lookup);
  1631                 original = lookup.lookupResult(String.class);
  1632 
  1633                 original.addLookupListener(this);
  1634 
  1635                 wrapped = pl.lookupResult(String.class);
  1636 
  1637                 assertEquals("Original empty", 0, original.allInstances().size());
  1638                 assertEquals("Wrapped empty", 0, wrapped.allInstances().size());
  1639 
  1640                 ic.add("Hello!");
  1641             }
  1642 
  1643             public void resultChanged(LookupEvent ev) {
  1644                 ok = true;
  1645 
  1646                 assertEquals("Original has hello", 1, original.allInstances().size());
  1647                 assertEquals("Wrapped has hello", 1, wrapped.allInstances().size());
  1648             }
  1649 
  1650         }
  1651         L listener = new L();
  1652         listener.test();
  1653         assertTrue("Listener called", listener.ok);
  1654     }
  1655 
  1656     public void testObjectFromInstanceContentConverterDisappearsIfNotReferenced() {
  1657         Conv converter = new Conv("foo");
  1658         ic.add (converter, converter);
  1659         Lookup lkp = instanceLookup;
  1660         StringBuilder sb = lookup.lookup (StringBuilder.class);
  1661         assertNotNull (sb);
  1662         int hash = System.identityHashCode(sb);
  1663         assertEquals ("foo", sb.toString());
  1664         Reference<StringBuilder> r = new WeakReference<StringBuilder>(sb);
  1665         sb = null;
  1666         assertGC("Lookup held onto object", r);
  1667         sb = lookup.lookup (StringBuilder.class);
  1668         assertNotSame(hash, System.identityHashCode(sb));
  1669         r = new WeakReference<StringBuilder>(sb);
  1670         sb = null;
  1671         assertGC("Lookup held onto object", r);
  1672         ic.remove (converter, converter);
  1673         Reference <InstanceContent.Convertor> cref = new WeakReference<InstanceContent.Convertor>(converter);
  1674         converter = null;
  1675         assertGC("Converter still referenced", cref); 
  1676 
  1677         sb = lkp.lookup(StringBuilder.class);
  1678         assertNull ("Converter removed from lookup, but object it " +
  1679                 "created still present:'" + sb +"'", sb);
  1680         converter = new Conv("bar");
  1681         ic.add (converter, converter);
  1682         assertNotNull (lkp.lookup(StringBuilder.class));
  1683         assertEquals ("bar", lkp.lookup(StringBuilder.class).toString());
  1684     }
  1685 
  1686     private static class Conv implements InstanceContent.Convertor<Conv, StringBuilder> {
  1687         private final String str;
  1688         private Conv (String str) {
  1689             this.str = str;
  1690         }
  1691 
  1692         public StringBuilder convert(Conv obj) {
  1693             return new StringBuilder (str);
  1694         }
  1695 
  1696         public Class<? extends StringBuilder> type(Conv obj) {
  1697             return StringBuilder.class;
  1698         }
  1699 
  1700         public String id(Conv obj) {
  1701             return "Foo";
  1702         }
  1703 
  1704         public String displayName(Conv obj) {
  1705             return "Foo";
  1706         }
  1707     } // end of Conv
  1708 
  1709     public void testCanGCResults() throws Exception {
  1710         class L implements LookupListener {
  1711             int cnt;
  1712             
  1713             public void resultChanged(LookupEvent ev) {
  1714                 cnt++;
  1715             }
  1716             
  1717         }
  1718         L listener1 = new L();
  1719         L listener2 = new L();
  1720         
  1721         Lookup.Result<String> res1 = this.instanceLookup.lookupResult(String.class);
  1722         Lookup.Result<String> res2 = this.lookup.lookupResult(String.class);
  1723         
  1724         assertEquals("Empty1", 0, res1.allItems().size());
  1725         assertEquals("Empty2", 0, res2.allItems().size());
  1726         
  1727         res1.addLookupListener(listener1);
  1728         res2.addLookupListener(listener2);
  1729         
  1730         addInstances(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15);
  1731         this.ic.add("Ahoj");
  1732         
  1733         assertEquals("Change1", 1, listener1.cnt);
  1734         assertEquals("Change2", 1, listener2.cnt);
  1735         
  1736         assertEquals("Full1", 1, res1.allItems().size());
  1737         assertEquals("Full2", 1, res2.allItems().size());
  1738         
  1739         
  1740         Reference<Object> ref2 = new WeakReference<Object>(res2);
  1741         res2 = null;
  1742         assertGC("Result can disappear", ref2);
  1743     }
  1744     
  1745     void beforeActualTest(String n) {
  1746         if (n.equals("testEqualsIsNotCalledTooMuch")) {
  1747             CntPair.cnt = 0;
  1748             CntPair.hashCnt = 0;
  1749             CntPair.instances = 0;
  1750             int how = 1000;
  1751 
  1752             for(int i = 0; i < how; i++) {
  1753                 this.ic.addPair(new CntPair("x" + i));
  1754             }
  1755 
  1756             assertEquals("No equals called", 0, CntPair.cnt);
  1757             assertEquals("1000 instances ", how, CntPair.instances);
  1758         }
  1759     }
  1760     
  1761     public void testEqualsIsNotCalledTooMuch() throws Exception {
  1762         // most of the work done in beforeActualTest
  1763 
  1764         // desirable: assertEquals("no comparitions", 0, CntPair.cnt);
  1765         // works for InheritanceTree, but not for ArrayStorage, but array
  1766         // storages are generally small
  1767         
  1768         if (CntPair.cnt > 12000) {
  1769             fail("Too much comparitions " + CntPair.cnt);
  1770         }
  1771         if (CntPair.hashCnt > 40000) {
  1772             fail("Too much hashes: " + CntPair.hashCnt);
  1773         }
  1774         
  1775         assertEquals("instaces is enough", 1000, CntPair.instances);
  1776     }
  1777     
  1778     /** Adds instances to the instance lookup.
  1779      */
  1780     private void addInstances (Object... instances) {
  1781         for (int i = 0; i < instances.length; i++) {
  1782             ic.add(instances[i]);
  1783         }
  1784     }
  1785     
  1786     /** Count instances of clazz in an array. */
  1787     private int countInstances (Object[] objs, Class clazz) {
  1788         int count = 0;
  1789         for (int i = 0; i < objs.length; i++) {
  1790             if (clazz.isInstance(objs[i])) count++;
  1791         }
  1792         return count;
  1793     }
  1794     
  1795     /** Counting listener */
  1796     protected static class LL implements LookupListener {
  1797         private int count = 0;
  1798         public Object source;
  1799         public Thread changesIn;
  1800         
  1801         public LL () {
  1802             this (null);
  1803         }
  1804         
  1805         public LL (Object source) {
  1806             this.source = source;
  1807         }
  1808         
  1809         public void resultChanged(LookupEvent ev) {
  1810             if (changesIn != null) {
  1811                 assertEquals("Changes in the same thread", changesIn, Thread.currentThread());
  1812             } else {
  1813                 changesIn = Thread.currentThread();
  1814             }
  1815             ++count;
  1816             if (source != null) {
  1817                 assertSame ("Source is the same", source, ev.getSource ());
  1818 //                assertSame ("Result is the same", source, ev.getResult ());
  1819             }
  1820         }
  1821 
  1822         public int getCount() {
  1823             int i = count;
  1824             count = 0;
  1825             return i;
  1826         }
  1827     };
  1828 
  1829     /** A set of interfaces for testInterfaceInheritance
  1830      */
  1831     interface TestInterfaceInheritanceA {}
  1832     interface TestInterfaceInheritanceB extends TestInterfaceInheritanceA, java.rmi.Remote {}
  1833     interface TestInterfaceInheritanceBB extends TestInterfaceInheritanceB {}
  1834     interface TestInterfaceInheritanceC extends TestInterfaceInheritanceA, java.rmi.Remote {}
  1835     interface TestInterfaceInheritanceD extends TestInterfaceInheritanceA {}
  1836     
  1837     /** A special class for garbage test */
  1838     public static final class Garbage extends Object implements Serializable {
  1839         static final long serialVersionUID = 435340912534L;
  1840     }
  1841     
  1842 
  1843     /* A classloader that can load one class in a special way */
  1844     private static class CL extends ClassLoader {
  1845         public CL () {
  1846             super (null);
  1847         }
  1848 
  1849         public @Override Class findClass(String name) throws ClassNotFoundException {
  1850             if (name.equals (Garbage.class.getName ())) {
  1851                 String n = name.replace ('.', '/');
  1852                 java.io.InputStream is = getClass ().getResourceAsStream ("/" + n + ".class");
  1853                 byte[] arr = new byte[8096];
  1854                 try {
  1855                     int cnt = is.read (arr);
  1856                     if (cnt == arr.length) {
  1857                         fail ("Buffer to load the class is not big enough");
  1858                     }
  1859 
  1860                     return defineClass (name, arr, 0, cnt);
  1861                 } catch (java.io.IOException ex) {
  1862                         ex.printStackTrace();
  1863                         fail ("IO Exception");
  1864                         return null;
  1865                 }
  1866             } else {
  1867                 return null;
  1868             }
  1869         }
  1870 
  1871         /** Convert obj to other object. There is no need to implement
  1872          * cache mechanism. It is provided by AbstractLookup.Item.getInstance().
  1873          * Method should be called more than once because Lookup holds
  1874          * just weak reference.
  1875          */
  1876         public Object convert(Object obj) {
  1877             return null;
  1878         }
  1879 
  1880         /** Return type of converted object. */
  1881         public Class type(Object obj) {
  1882             try {
  1883                 return loadClass (Garbage.class.getName ());
  1884             } catch (ClassNotFoundException ex) {
  1885                 fail ("Class not found");
  1886                 throw new InternalError ();
  1887             }
  1888         }
  1889     }
  1890     
  1891     private static final class CntPair extends AbstractLookup.Pair {
  1892         private static int instances;
  1893         private String txt;
  1894         
  1895         public CntPair(String txt) {
  1896             this.txt = txt;
  1897             instances++;
  1898         }
  1899 
  1900         public static int hashCnt;
  1901         @Override
  1902         public int hashCode() {
  1903             hashCnt++;
  1904             return txt.hashCode() + 3777;
  1905         }
  1906 
  1907         public static int cnt;
  1908         @Override
  1909         public boolean equals(Object obj) {
  1910             cnt++;
  1911             
  1912             if (obj == null) {
  1913                 return false;
  1914             }
  1915             if (getClass() != obj.getClass()) {
  1916                 return false;
  1917             }
  1918             final CntPair other = (CntPair) obj;
  1919             if (this.txt != other.txt && (this.txt == null || !this.txt.equals(other.txt))) {
  1920                 return false;
  1921             }
  1922             return true;
  1923         }
  1924 
  1925         protected boolean instanceOf(Class c) {
  1926             return c.isAssignableFrom(String.class);
  1927         }
  1928 
  1929         protected boolean creatorOf(Object obj) {
  1930             return obj == txt;
  1931         }
  1932 
  1933         public Object getInstance() {
  1934             return txt;
  1935         }
  1936 
  1937         public Class getType() {
  1938             return String.class;
  1939         }
  1940 
  1941         public String getId() {
  1942             return txt;
  1943         }
  1944 
  1945         public String getDisplayName() {
  1946             return txt;
  1947         }
  1948         
  1949     }
  1950 
  1951     public static final class SerialPair extends AbstractLookup.Pair
  1952     implements java.io.Serializable {
  1953         static final long serialVersionUID = 54305834L;
  1954         private Object value;
  1955         public transient int countInstanceOf;
  1956         
  1957         public SerialPair (Object value) {
  1958             this.value = value;
  1959         }
  1960         
  1961         protected boolean creatorOf(Object obj) {
  1962             return obj == value;
  1963         }
  1964         
  1965         public String getDisplayName() {
  1966             return getId ();
  1967         }
  1968         
  1969         public String getId() {
  1970             return value.toString();
  1971         }
  1972         
  1973         public Object getInstance() {
  1974             return value;
  1975         }
  1976         
  1977         public Class getType() {
  1978             return value.getClass ();
  1979         }
  1980         
  1981         protected boolean instanceOf(Class c) {
  1982             countInstanceOf++;
  1983             return c.isInstance(value);
  1984         }
  1985     } // end of SerialPair
  1986     
  1987     private static class BrokenPair extends AbstractLookup.Pair {
  1988         private transient ThreadLocal IN = new ThreadLocal ();
  1989         private boolean checkModify;
  1990         private boolean checkQuery;
  1991         
  1992         public BrokenPair (boolean checkModify, boolean checkQuery) {
  1993             this.checkModify = checkModify;
  1994             this.checkQuery = checkQuery;
  1995         }
  1996         
  1997         protected boolean creatorOf(Object obj) { return this == obj; }
  1998         public String getDisplayName() { return "Broken"; }
  1999         public String getId() { return "broken"; }
  2000         public Object getInstance() { return this; }
  2001         public Class getType() { return getClass (); }
  2002         protected boolean instanceOf(Class c) { 
  2003             
  2004             if (checkQuery) {
  2005                 if (IN.get () == null) {
  2006                     try {
  2007                         IN.set (this);
  2008                         // broken behaviour, tries to modify the lookup
  2009                         // queries have to survive
  2010 
  2011                         running.lookup.lookup (java.awt.List.class);
  2012 
  2013                         // 
  2014                         // creation of new result has to survive as well
  2015                         Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.Button.class));
  2016                         Collection all = myQuery.allItems ();
  2017                     } finally {
  2018                         IN.set (null);
  2019                     }
  2020                 }
  2021             }
  2022                 
  2023 
  2024             if (checkModify) {
  2025                 //
  2026                 // modifications should fail
  2027                 //
  2028 
  2029                 try {
  2030                     running.ic.addPair (new SerialPair (""));
  2031                     fail ("Modification from a query should be prohibited");
  2032                 } catch (IllegalStateException ex) {
  2033                 }
  2034                 
  2035                 try {
  2036                     running.ic.removePair (this);
  2037                     fail ("This has to throw the exception");
  2038                 } catch (IllegalStateException ex) {
  2039                 }
  2040                 try {
  2041                     running.ic.setPairs (Collections.EMPTY_SET);
  2042                     fail ("This has to throw the exception as well");
  2043                 } catch (IllegalStateException ex) {
  2044                 }
  2045             }
  2046             
  2047             return c.isAssignableFrom(getType ()); 
  2048         }
  2049     } // end of BrokenPair
  2050     
  2051     private static class Broken2Pair extends AbstractLookup.Pair {
  2052         static final long serialVersionUID = 4532587018501L;
  2053         public transient ThreadLocal IN;
  2054         
  2055         public Broken2Pair () {
  2056         }
  2057         
  2058         private void writeObject (java.io.ObjectOutputStream oos) throws java.io.IOException {
  2059         }
  2060         
  2061         private void readObject (java.io.ObjectInputStream ois) throws java.io.IOException, ClassNotFoundException {
  2062             IN = new ThreadLocal ();
  2063         }
  2064         
  2065         protected boolean creatorOf(Object obj) { return this == obj; }
  2066         public String getDisplayName() { return "Broken"; }
  2067         public String getId() { return "broken"; }
  2068         public Object getInstance() { return this; }
  2069         public Class getType() { return getClass (); }
  2070         protected boolean instanceOf(Class c) { 
  2071             
  2072             // behaviour gets broken only after deserialization
  2073             if (IN != null && IN.get () == null) {
  2074                 try {
  2075                     IN.set (this);
  2076 
  2077                     // creation of new result has to survive as well
  2078                     Lookup.Result myQuery = running.lookup.lookup (new Lookup.Template (java.awt.List.class));
  2079                     Collection all = myQuery.allItems ();
  2080                 } finally {
  2081                     IN.set (null);
  2082                 }
  2083             }
  2084             
  2085             return c.isAssignableFrom(getType ()); 
  2086         }
  2087     } // end of Broken2Pair    
  2088 }