lookup/src/main/java/org/openide/util/lookup/AbstractLookup.java
changeset 972 a2947558c966
parent 971 b3ae88304dd0
child 973 5653a70ebb56
     1.1 --- a/lookup/src/main/java/org/openide/util/lookup/AbstractLookup.java	Wed Jan 27 17:46:23 2010 -0500
     1.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.3 @@ -1,1467 +0,0 @@
     1.4 -/*
     1.5 - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     1.6 - *
     1.7 - * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
     1.8 - *
     1.9 - * The contents of this file are subject to the terms of either the GNU
    1.10 - * General Public License Version 2 only ("GPL") or the Common
    1.11 - * Development and Distribution License("CDDL") (collectively, the
    1.12 - * "License"). You may not use this file except in compliance with the
    1.13 - * License. You can obtain a copy of the License at
    1.14 - * http://www.netbeans.org/cddl-gplv2.html
    1.15 - * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
    1.16 - * specific language governing permissions and limitations under the
    1.17 - * License.  When distributing the software, include this License Header
    1.18 - * Notice in each file and include the License file at
    1.19 - * nbbuild/licenses/CDDL-GPL-2-CP.  Sun designates this
    1.20 - * particular file as subject to the "Classpath" exception as provided
    1.21 - * by Sun in the GPL Version 2 section of the License file that
    1.22 - * accompanied this code. If applicable, add the following below the
    1.23 - * License Header, with the fields enclosed by brackets [] replaced by
    1.24 - * your own identifying information:
    1.25 - * "Portions Copyrighted [year] [name of copyright owner]"
    1.26 - *
    1.27 - * Contributor(s):
    1.28 - *
    1.29 - * The Original Software is NetBeans. The Initial Developer of the Original
    1.30 - * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
    1.31 - * Microsystems, Inc. All Rights Reserved.
    1.32 - *
    1.33 - * If you wish your version of this file to be governed by only the CDDL
    1.34 - * or only the GPL Version 2, indicate your decision by adding
    1.35 - * "[Contributor] elects to include this software in this distribution
    1.36 - * under the [CDDL or GPL Version 2] license." If you do not indicate a
    1.37 - * single choice of license, a recipient has the option to distribute
    1.38 - * your version of this file under either the CDDL, the GPL Version 2 or
    1.39 - * to extend the choice of license to its licensees as provided above.
    1.40 - * However, if you add GPL Version 2 code and therefore, elected the GPL
    1.41 - * Version 2 license, then the option applies only if the new code is
    1.42 - * made subject to such option by the copyright holder.
    1.43 - */
    1.44 -package org.openide.util.lookup;
    1.45 -
    1.46 -import java.io.PrintStream;
    1.47 -import org.openide.util.Lookup;
    1.48 -import org.openide.util.LookupEvent;
    1.49 -import org.openide.util.LookupListener;
    1.50 -
    1.51 -import java.io.IOException;
    1.52 -import java.io.ObjectOutputStream;
    1.53 -import java.io.Serializable;
    1.54 -
    1.55 -import java.lang.ref.ReferenceQueue;
    1.56 -import java.lang.ref.WeakReference;
    1.57 -import java.util.ArrayList;
    1.58 -import java.util.Arrays;
    1.59 -import java.util.Collection;
    1.60 -import java.util.Collections;
    1.61 -import java.util.Enumeration;
    1.62 -import java.util.HashMap;
    1.63 -import java.util.HashSet;
    1.64 -import java.util.Iterator;
    1.65 -import java.util.LinkedHashSet;
    1.66 -import java.util.Map;
    1.67 -import java.util.Set;
    1.68 -import java.util.TreeSet;
    1.69 -
    1.70 -import java.util.concurrent.Executor;
    1.71 -import org.netbeans.modules.openide.util.ActiveQueue;
    1.72 -
    1.73 -
    1.74 -/** Implementation of the lookup from OpenAPIs that is based on the
    1.75 - * introduction of Item. This class should provide the default way
    1.76 - * of how to store (Class, Object) pairs in the lookups. It offers
    1.77 - * protected methods for subclasses to register the pairs.
    1.78 - * <p>Serializable since 3.27.
    1.79 - * @author  Jaroslav Tulach
    1.80 - * @since 1.9
    1.81 - */
    1.82 -public class AbstractLookup extends Lookup implements Serializable {
    1.83 -    static final long serialVersionUID = 5L;
    1.84 -
    1.85 -    /** lock for initialization of the maps of lookups */
    1.86 -    private static final Object treeLock = new Object();
    1.87 -
    1.88 -    /** the tree that registers all items (or Integer as a treshold size) */
    1.89 -    private Object tree;
    1.90 -
    1.91 -    /** count of items in to lookup */
    1.92 -    private int count;
    1.93 -
    1.94 -    /** Constructor to create this lookup and associate it with given
    1.95 -     * Content. The content than allows the creator to invoke protected
    1.96 -     * methods which are not accessible for any other user of the lookup.
    1.97 -     *
    1.98 -     * @param content the content to assciate with
    1.99 -     *
   1.100 -     * @since 1.25
   1.101 -     */
   1.102 -    public AbstractLookup(Content content) {
   1.103 -        content.attach(this);
   1.104 -    }
   1.105 -
   1.106 -    /** Constructor for testing purposes that allows specification of storage
   1.107 -     * as mechanism as well.
   1.108 -     */
   1.109 -    AbstractLookup(Content content, Storage<?> storage) {
   1.110 -        this(content);
   1.111 -        this.tree = storage;
   1.112 -        initialize();
   1.113 -    }
   1.114 -
   1.115 -    /** Constructor for testing purposes that allows specification of storage
   1.116 -     * as mechanism as well.
   1.117 -     * @param trashhold number of Pair to "remain small"
   1.118 -     */
   1.119 -    AbstractLookup(Content content, Integer trashhold) {
   1.120 -        this(content);
   1.121 -        this.tree = trashhold;
   1.122 -    }
   1.123 -
   1.124 -    /** Default constructor for subclasses that do not need to provide a content
   1.125 -     */
   1.126 -    protected AbstractLookup() {
   1.127 -    }
   1.128 -
   1.129 -    @Override
   1.130 -    public String toString() {
   1.131 -        if (tree instanceof Storage) {
   1.132 -            return "AbstractLookup" + lookup(new Lookup.Template<Object>(Object.class)).allItems(); // NOI18N
   1.133 -        } else {
   1.134 -            return super.toString();
   1.135 -        }
   1.136 -    }
   1.137 -
   1.138 -    /** Entres the storage management system.
   1.139 -     */
   1.140 -    @SuppressWarnings("unchecked")
   1.141 -    private <T> AbstractLookup.Storage<T> enterStorage() {
   1.142 -        for (;;) {
   1.143 -            synchronized (treeLock) {
   1.144 -                if (tree instanceof AbstractLookup.Storage) {
   1.145 -                    if (tree instanceof DelegatingStorage) {
   1.146 -                        // somebody is using the lookup right now
   1.147 -                        DelegatingStorage del = (DelegatingStorage) tree;
   1.148 -
   1.149 -                        // check whether there is not access from the same 
   1.150 -                        // thread (can throw exception)
   1.151 -                        del.checkForTreeModification();
   1.152 -
   1.153 -                        try {
   1.154 -                            treeLock.wait();
   1.155 -                        } catch (InterruptedException ex) {
   1.156 -                            // ignore and go on
   1.157 -                        }
   1.158 -
   1.159 -                        continue;
   1.160 -                    } else {
   1.161 -                        // ok, tree is initialized and nobody is using it yet
   1.162 -                        tree = new DelegatingStorage((Storage<T>) tree);
   1.163 -
   1.164 -                        return (Storage<T>) tree;
   1.165 -                    }
   1.166 -                }
   1.167 -
   1.168 -                // first time initialization of the tree
   1.169 -                if (tree instanceof Integer) {
   1.170 -                    tree = new ArrayStorage((Integer) tree);
   1.171 -                } else {
   1.172 -                    tree = new ArrayStorage();
   1.173 -                }
   1.174 -            }
   1.175 -
   1.176 -            // the tree has not yet been initilized, initialize and go on again
   1.177 -            initialize();
   1.178 -        }
   1.179 -    }
   1.180 -
   1.181 -    /** Exists tree ownership.
   1.182 -     */
   1.183 -    private AbstractLookup.Storage exitStorage() {
   1.184 -        synchronized (treeLock) {
   1.185 -            AbstractLookup.Storage stor = ((DelegatingStorage) tree).exitDelegate();
   1.186 -            tree = stor;
   1.187 -            treeLock.notifyAll();
   1.188 -
   1.189 -            return stor;
   1.190 -        }
   1.191 -    }
   1.192 -
   1.193 -    /** Method for subclasses to initialize them selves.
   1.194 -     */
   1.195 -    protected void initialize() {
   1.196 -    }
   1.197 -
   1.198 -    /** Notifies subclasses that a query is about to be processed.
   1.199 -     * @param template the template
   1.200 -     */
   1.201 -    protected void beforeLookup(Template<?> template) {
   1.202 -    }
   1.203 -
   1.204 -    /** The method to add instance to the lookup with.
   1.205 -     * @param pair class/instance pair
   1.206 -     */
   1.207 -    protected final void addPair(Pair<?> pair) {
   1.208 -        addPairImpl(pair, null);
   1.209 -    }
   1.210 -
   1.211 -    /** The method to add instance to the lookup with.
   1.212 -     * @param pair class/instance pair
   1.213 -     * @param notifyIn the executor that will handle the notification of events
   1.214 -     * @since 7.16
   1.215 -     */
   1.216 -    protected final void addPair(Pair<?> pair, Executor notifyIn) {
   1.217 -        addPairImpl(pair, notifyIn);
   1.218 -    }
   1.219 -
   1.220 -    private final <Transaction> void addPairImpl(Pair<?> pair, Executor notifyIn) {
   1.221 -        HashSet<R> toNotify = new HashSet<R>();
   1.222 -
   1.223 -        AbstractLookup.Storage<Transaction> t = enterStorage();
   1.224 -        Transaction transaction = null;
   1.225 -
   1.226 -        try {
   1.227 -            transaction = t.beginTransaction(-2);
   1.228 -
   1.229 -            if (t.add(pair, transaction)) {
   1.230 -                try {
   1.231 -                    pair.setIndex(t, count++);
   1.232 -                } catch (IllegalStateException ex) {
   1.233 -                    // remove the pair
   1.234 -                    t.remove(pair, transaction);
   1.235 -
   1.236 -                    // rethrow the exception
   1.237 -                    throw ex;
   1.238 -                }
   1.239 -
   1.240 -                // if the pair is newly added and was not there before
   1.241 -                t.endTransaction(transaction, toNotify);
   1.242 -            } else {
   1.243 -                // just finish the process by calling endTransaction
   1.244 -                t.endTransaction(transaction, new HashSet<R>());
   1.245 -            }
   1.246 -        } finally {
   1.247 -            exitStorage();
   1.248 -        }
   1.249 -
   1.250 -        notifyIn(notifyIn, toNotify);
   1.251 -    }
   1.252 -
   1.253 -    /** Remove instance.
   1.254 -     * @param pair class/instance pair
   1.255 -     */
   1.256 -    protected final void removePair(Pair<?> pair) {
   1.257 -        removePairImpl(pair, null);
   1.258 -    }
   1.259 -    /** Remove instance.
   1.260 -     * @param pair class/instance pair
   1.261 -     * @param notifyIn the executor that will handle the notification of events
   1.262 -     * @since 7.16
   1.263 -     */
   1.264 -    protected final void removePair(Pair<?> pair, Executor notifyIn) {
   1.265 -        removePairImpl(pair, notifyIn);
   1.266 -    }
   1.267 -
   1.268 -    private <Transaction> void removePairImpl(Pair<?> pair, Executor notifyIn) {
   1.269 -        HashSet<R> toNotify = new HashSet<R>();
   1.270 -
   1.271 -        AbstractLookup.Storage<Transaction> t = enterStorage();
   1.272 -        Transaction transaction = null;
   1.273 -
   1.274 -        try {
   1.275 -            transaction = t.beginTransaction(-1);
   1.276 -            t.remove(pair, transaction);
   1.277 -            t.endTransaction(transaction, toNotify);
   1.278 -        } finally {
   1.279 -            exitStorage();
   1.280 -        }
   1.281 -
   1.282 -        notifyIn(notifyIn, toNotify);
   1.283 -    }
   1.284 -
   1.285 -    /** Changes all pairs in the lookup to new values.
   1.286 -     * @param collection the collection of (Pair) objects
   1.287 -     */
   1.288 -    protected final void setPairs(Collection<? extends Pair> collection) {
   1.289 -        setPairs(collection, null);
   1.290 -    }
   1.291 -
   1.292 -    /** Changes all pairs in the lookup to new values, notifies listeners
   1.293 -     * using provided executor.
   1.294 -     * 
   1.295 -     * @param collection the collection of (Pair) objects
   1.296 -     * @param notifyIn the executor that will handle the notification of events
   1.297 -     * @since 7.16
   1.298 -     */
   1.299 -    protected final void setPairs(Collection<? extends Pair> collection, Executor notifyIn) {
   1.300 -        HashSet<R> listeners = setPairsAndCollectListeners(collection);
   1.301 -        notifyIn(notifyIn, listeners);
   1.302 -    }
   1.303 -    
   1.304 -    private final void notifyIn(Executor notifyIn, final HashSet<R> listeners) {
   1.305 -        NotifyListeners notify = new NotifyListeners(listeners);
   1.306 -        if (notify.shallRun()) {
   1.307 -            if (notifyIn == null) {
   1.308 -                notify.run();
   1.309 -            } else {
   1.310 -                notifyIn.execute(notify);
   1.311 -            }
   1.312 -        }
   1.313 -    }
   1.314 -    
   1.315 -    /** Getter for set of pairs. Package private contract with MetaInfServicesLookup.
   1.316 -     * @return a LinkedHashSet that can be modified
   1.317 -     */
   1.318 -    final LinkedHashSet<Pair<?>> getPairsAsLHS() {
   1.319 -        AbstractLookup.Storage<?> t = enterStorage();
   1.320 -
   1.321 -        try {
   1.322 -            Enumeration<Pair<Object>> en = t.lookup(Object.class);
   1.323 -            TreeSet<Pair<?>> arr = new TreeSet<Pair<?>>(ALPairComparator.DEFAULT);
   1.324 -            while (en.hasMoreElements()) {
   1.325 -                Pair<Object> item = en.nextElement();
   1.326 -                arr.add(item);
   1.327 -            }
   1.328 -            return new LinkedHashSet<Pair<?>>(arr);
   1.329 -        } finally {
   1.330 -            exitStorage();
   1.331 -        }
   1.332 -    }
   1.333 -
   1.334 -    /** Collects listeners without notification. Needed in MetaInfServicesLookup
   1.335 -     * right now, but maybe will become an API later.
   1.336 -     */
   1.337 -    final <Transaction> HashSet<R> setPairsAndCollectListeners(Collection<? extends Pair> collection) {
   1.338 -        HashSet<R> toNotify = new HashSet<R>(27);
   1.339 -
   1.340 -        AbstractLookup.Storage<Transaction> t = enterStorage();
   1.341 -        Transaction transaction = null;
   1.342 -
   1.343 -        try {
   1.344 -            // map between the Items and their indexes (Integer)
   1.345 -            HashMap<Item<?>,Info> shouldBeThere = new HashMap<Item<?>,Info>(collection.size() * 2);
   1.346 -
   1.347 -            count = 0;
   1.348 -
   1.349 -            Iterator it = collection.iterator();
   1.350 -            transaction = t.beginTransaction(collection.size());
   1.351 -
   1.352 -            while (it.hasNext()) {
   1.353 -                Pair item = (Pair) it.next();
   1.354 -
   1.355 -                if (t.add(item, transaction)) {
   1.356 -                    // the item has not been there yet
   1.357 -                    //t.endTransaction(transaction, toNotify);
   1.358 -                }
   1.359 -
   1.360 -                // remeber the item, because it should not be removed
   1.361 -                shouldBeThere.put(item, new Info(count++, transaction));
   1.362 -
   1.363 -                //                    arr.clear ();
   1.364 -            }
   1.365 -
   1.366 -            //            Object transaction = t.beginTransaction ();
   1.367 -            // deletes all objects that should not be there and
   1.368 -            t.retainAll(shouldBeThere, transaction);
   1.369 -
   1.370 -            // collect listeners
   1.371 -            t.endTransaction(transaction, toNotify);
   1.372 -
   1.373 -            /*
   1.374 -            // check consistency
   1.375 -            Enumeration en = t.lookup (java.lang.Object.class);
   1.376 -            boolean[] max = new boolean[count];
   1.377 -            int mistake = -1;
   1.378 -            while (en.hasMoreElements ()) {
   1.379 -                Pair item = (Pair)en.nextElement ();
   1.380 -
   1.381 -                if (max[item.index]) {
   1.382 -                    mistake = item.index;
   1.383 -                }
   1.384 -                max[item.index] = true;
   1.385 -            }
   1.386 -
   1.387 -            if (mistake != -1) {
   1.388 -                System.err.println ("Mistake at: " + mistake);
   1.389 -                tree.print (System.err, true);
   1.390 -            }
   1.391 -            */
   1.392 -        } finally {
   1.393 -            exitStorage();
   1.394 -        }
   1.395 -
   1.396 -        return toNotify;
   1.397 -    }
   1.398 -
   1.399 -    private final void writeObject(ObjectOutputStream oos)
   1.400 -    throws IOException {
   1.401 -        AbstractLookup.Storage s = enterStorage();
   1.402 -
   1.403 -        try {
   1.404 -            // #36830: Serializing only InheritanceTree no ArrayStorage
   1.405 -            s.beginTransaction(Integer.MAX_VALUE);
   1.406 -
   1.407 -            // #32040: don't write half-made changes
   1.408 -            oos.defaultWriteObject();
   1.409 -        } finally {
   1.410 -            exitStorage();
   1.411 -        }
   1.412 -    }
   1.413 -
   1.414 -    public final <T> T lookup(Class<T> clazz) {
   1.415 -        Lookup.Item<T> item = lookupItem(new Lookup.Template<T>(clazz));
   1.416 -        return (item == null) ? null : item.getInstance();
   1.417 -    }
   1.418 -
   1.419 -    @Override
   1.420 -    public final <T> Lookup.Item<T> lookupItem(Lookup.Template<T> template) {
   1.421 -        AbstractLookup.this.beforeLookup(template);
   1.422 -
   1.423 -        ArrayList<Pair<T>> list = null;
   1.424 -        AbstractLookup.Storage<?> t = enterStorage();
   1.425 -
   1.426 -        try {
   1.427 -            Enumeration<Pair<T>> en;
   1.428 -
   1.429 -            try {
   1.430 -                en = t.lookup(template.getType());
   1.431 -
   1.432 -                return findSmallest(en, template, false);
   1.433 -            } catch (AbstractLookup.ISE ex) {
   1.434 -                // not possible to enumerate the exception, ok, copy it 
   1.435 -                // to create new
   1.436 -                list = new ArrayList<Pair<T>>();
   1.437 -                en = t.lookup(null); // this should get all the items without any checks
   1.438 -
   1.439 -                // the checks will be done out side of the storage
   1.440 -                while (en.hasMoreElements()) {
   1.441 -                    list.add(en.nextElement());
   1.442 -                }
   1.443 -            }
   1.444 -        } finally {
   1.445 -            exitStorage();
   1.446 -        }
   1.447 -
   1.448 -        return findSmallest(Collections.enumeration(list), template, true);
   1.449 -    }
   1.450 -
   1.451 -    private static <T> Pair<T> findSmallest(Enumeration<Pair<T>> en, Lookup.Template<T> template, boolean deepCheck) {
   1.452 -        int smallest = InheritanceTree.unsorted(en) ? Integer.MAX_VALUE : Integer.MIN_VALUE;
   1.453 -        Pair<T> res = null;
   1.454 -
   1.455 -        while (en.hasMoreElements()) {
   1.456 -            Pair<T> item = en.nextElement();
   1.457 -
   1.458 -            if (matches(template, item, deepCheck)) {
   1.459 -                if (smallest == Integer.MIN_VALUE) {
   1.460 -                    // ok, sorted enumeration the first that matches is fine
   1.461 -                    return item;
   1.462 -                } else {
   1.463 -                    // check for the smallest item
   1.464 -                    if (smallest > item.getIndex()) {
   1.465 -                        smallest = item.getIndex();
   1.466 -                        res = item;
   1.467 -                    }
   1.468 -                }
   1.469 -            }
   1.470 -        }
   1.471 -
   1.472 -        return res;
   1.473 -    }
   1.474 -
   1.475 -    public final <T> Lookup.Result<T> lookup(Lookup.Template<T> template) {
   1.476 -        for (;;) {
   1.477 -            AbstractLookup.ISE toRun = null;
   1.478 -
   1.479 -            AbstractLookup.Storage<?> t = enterStorage();
   1.480 -
   1.481 -            try {
   1.482 -                R<T> r = new R<T>();
   1.483 -                ReferenceToResult<T> newRef = new ReferenceToResult<T>(r, this, template);
   1.484 -                newRef.next = t.registerReferenceToResult(newRef);
   1.485 -
   1.486 -                return r;
   1.487 -            } catch (AbstractLookup.ISE ex) {
   1.488 -                toRun = ex;
   1.489 -            } finally {
   1.490 -                exitStorage();
   1.491 -            }
   1.492 -
   1.493 -            toRun.recover(this);
   1.494 -
   1.495 -            // and try again
   1.496 -        }
   1.497 -    }
   1.498 -
   1.499 -    /** Notifies listeners.
   1.500 -     * @param allAffectedResults set of R
   1.501 -     */
   1.502 -    static final class NotifyListeners implements Runnable {
   1.503 -        private final ArrayList<Object> evAndListeners;
   1.504 -        
   1.505 -        public NotifyListeners(Set<R> allAffectedResults) {
   1.506 -            if (allAffectedResults.isEmpty()) {
   1.507 -                evAndListeners = null;
   1.508 -                return;
   1.509 -            }
   1.510 -
   1.511 -            evAndListeners = new ArrayList<Object>();
   1.512 -            {
   1.513 -                for (R<?> result : allAffectedResults) {
   1.514 -                    result.collectFires(evAndListeners);
   1.515 -                }
   1.516 -            }
   1.517 -        }
   1.518 -
   1.519 -        public boolean shallRun() {
   1.520 -            return evAndListeners != null && !evAndListeners.isEmpty();
   1.521 -        }
   1.522 -
   1.523 -        public void run() {
   1.524 -            Iterator it = evAndListeners.iterator();
   1.525 -            while (it.hasNext()) {
   1.526 -                LookupEvent ev = (LookupEvent)it.next();
   1.527 -                LookupListener l = (LookupListener)it.next();
   1.528 -                l.resultChanged(ev);
   1.529 -            }
   1.530 -        }
   1.531 -    }
   1.532 -
   1.533 -    /**
   1.534 -     * Call resultChanged on all listeners.
   1.535 -     * @param listeners array of listeners in the format used by
   1.536 -     *        javax.swing.EventListenerList. It means that there are Class
   1.537 -     *        objects on even positions and the listeners on odd positions
   1.538 -     * @param ev the event to fire
   1.539 -     */
   1.540 -    static void notifyListeners(Object[] listeners, LookupEvent ev, Collection<Object> evAndListeners) {
   1.541 -        for (int i = listeners.length - 1; i >= 0; i--) {
   1.542 -            if (! (listeners[i] instanceof LookupListener)) {
   1.543 -                continue;
   1.544 -            }
   1.545 -            LookupListener ll = (LookupListener)listeners[i];
   1.546 -
   1.547 -            try {
   1.548 -                if (evAndListeners != null) {
   1.549 -                    if (ll instanceof WaitableResult) {
   1.550 -                        WaitableResult<?> wr = (WaitableResult<?>)ll;
   1.551 -                        wr.collectFires(evAndListeners);
   1.552 -                    } else {
   1.553 -                        evAndListeners.add(ev);
   1.554 -                        evAndListeners.add(ll);
   1.555 -                    }
   1.556 -                } else {
   1.557 -                    ll.resultChanged(ev);
   1.558 -                }
   1.559 -            } catch (StackOverflowError err) {
   1.560 -                throw new CycleError(evAndListeners); // NOI18N
   1.561 -            } catch (RuntimeException e) {
   1.562 -                // Such as e.g. occurred in #32040. Do not halt other things.
   1.563 -                e.printStackTrace();
   1.564 -            }
   1.565 -        }
   1.566 -    }
   1.567 -
   1.568 -    private static class CycleError extends StackOverflowError {
   1.569 -        private final Collection<Object> print;
   1.570 -        public CycleError(Collection<Object> evAndListeners) {
   1.571 -            this.print = evAndListeners;
   1.572 -        }
   1.573 -
   1.574 -        @Override
   1.575 -        public String getMessage() {
   1.576 -            StringBuilder sb = new StringBuilder();
   1.577 -            sb.append("StackOverflowError, here are the listeners:\n"); // NOI18N
   1.578 -            for (Object o : print) {
   1.579 -                sb.append('\n').append(o);
   1.580 -                if (sb.length() > 10000) {
   1.581 -                    break;
   1.582 -                }
   1.583 -            }
   1.584 -            return sb.toString();
   1.585 -        }
   1.586 -    } // end of CycleError
   1.587 -
   1.588 -    /** A method that defines matching between Item and Template.
   1.589 -     * @param t template providing the criteria
   1.590 -     * @param item the item to match
   1.591 -     * @param deepCheck true if type of the pair should be tested, false if it is already has been tested
   1.592 -     * @return true if item matches the template requirements, false if not
   1.593 -     */
   1.594 -    static boolean matches(Template<?> t, Pair<?> item, boolean deepCheck) {
   1.595 -        String id = t.getId();
   1.596 -
   1.597 -        if (id != null && !id.equals(item.getId())) {
   1.598 -            return false;
   1.599 -        }
   1.600 -
   1.601 -        Object instance = t.getInstance();
   1.602 -
   1.603 -        if ((instance != null) && !item.creatorOf(instance)) {
   1.604 -            return false;
   1.605 -        }
   1.606 -
   1.607 -        if (deepCheck) {
   1.608 -            return item.instanceOf(t.getType());
   1.609 -        } else {
   1.610 -            return true;
   1.611 -        }
   1.612 -    }
   1.613 -
   1.614 -    /**
   1.615 -     * Compares the array elements for equality.
   1.616 -     * @return true if all elements in the arrays are equal
   1.617 -     *  (by calling equals(Object x) method)
   1.618 -     */
   1.619 -    private static boolean compareArrays(Object[] a, Object[] b) {
   1.620 -        // handle null values
   1.621 -        if (a == null) {
   1.622 -            return (b == null);
   1.623 -        } else {
   1.624 -            if (b == null) {
   1.625 -                return false;
   1.626 -            }
   1.627 -        }
   1.628 -
   1.629 -        if (a.length != b.length) {
   1.630 -            return false;
   1.631 -        }
   1.632 -
   1.633 -        for (int i = 0; i < a.length; i++) {
   1.634 -            // handle null values for individual elements
   1.635 -            if (a[i] == null) {
   1.636 -                if (b[i] != null) {
   1.637 -                    return false;
   1.638 -                }
   1.639 -
   1.640 -                // both are null --> ok, take next
   1.641 -                continue;
   1.642 -            } else {
   1.643 -                if (b[i] == null) {
   1.644 -                    return false;
   1.645 -                }
   1.646 -            }
   1.647 -
   1.648 -            // perform the comparison
   1.649 -            if (!a[i].equals(b[i])) {
   1.650 -                return false;
   1.651 -            }
   1.652 -        }
   1.653 -
   1.654 -        return true;
   1.655 -    }
   1.656 -
   1.657 -    /** Method to be called when a result is cleared to signal that the list
   1.658 -     * of all result should be checked for clearing.
   1.659 -     * @param template the template the result was for
   1.660 -     * @return true if the hash map with all items has been cleared
   1.661 -     */
   1.662 -    <T> boolean cleanUpResult(Lookup.Template<T> template) {
   1.663 -        AbstractLookup.Storage<?> t = enterStorage();
   1.664 -
   1.665 -        try {
   1.666 -            return t.cleanUpResult(template) == null;
   1.667 -        } finally {
   1.668 -            exitStorage();
   1.669 -        }
   1.670 -    }
   1.671 -
   1.672 -    /** Storage check for tests. */
   1.673 -    static boolean isSimple(AbstractLookup l) {
   1.674 -        return DelegatingStorage.isSimple((Storage)l.tree);
   1.675 -    }
   1.676 -
   1.677 -    /** Generic support for listeners, so it can be used in other results
   1.678 -     * as well.
   1.679 -     * @param add true to add it, false to modify
   1.680 -     * @param l listener to modify
   1.681 -     * @param ref the value of the reference to listener or listener list
   1.682 -     * @return new value to the reference to listener or list
   1.683 -     */
   1.684 -    @SuppressWarnings("unchecked")
   1.685 -    static Object modifyListenerList(boolean add, LookupListener l, Object ref) {
   1.686 -        if (add) {
   1.687 -            if (ref == null) {
   1.688 -                return l;
   1.689 -            }
   1.690 -
   1.691 -            if (ref instanceof LookupListener) {
   1.692 -                ArrayList arr = new ArrayList();
   1.693 -                arr.add(ref);
   1.694 -                ref = arr;
   1.695 -            }
   1.696 -
   1.697 -            ((ArrayList) ref).add(l);
   1.698 -
   1.699 -            return ref;
   1.700 -        } else {
   1.701 -            // remove
   1.702 -            if (ref == null) {
   1.703 -                return null;
   1.704 -            }
   1.705 -
   1.706 -            if (ref == l) {
   1.707 -                return null;
   1.708 -            }
   1.709 -
   1.710 -            ArrayList arr = (ArrayList) ref;
   1.711 -            arr.remove(l);
   1.712 -
   1.713 -            if (arr.size() == 1) {
   1.714 -                return arr.iterator().next();
   1.715 -            } else {
   1.716 -                return arr;
   1.717 -            }
   1.718 -        }
   1.719 -    }
   1.720 -
   1.721 -    private static ReferenceQueue<Object> activeQueue() {
   1.722 -        return ActiveQueue.queue();
   1.723 -    }
   1.724 -
   1.725 -    /** Storage to keep the internal structure of Pairs and to answer
   1.726 -     * different queries.
   1.727 -     */
   1.728 -    interface Storage<Transaction> {
   1.729 -        /** Initializes a modification operation by creating an object
   1.730 -         * that will be passsed to all add, remove, retainAll methods
   1.731 -         * and should collect enough information about the change to
   1.732 -         * notify listeners about the transaction later
   1.733 -         *
   1.734 -         * @param ensure the amount of items that will appear in the storage
   1.735 -         *   after the modifications (-1 == remove one, -2 == add one, >= 0
   1.736 -         *   the amount of objects at the end
   1.737 -         * @return a token to identify the transaction
   1.738 -         */
   1.739 -        public Transaction beginTransaction(int ensure);
   1.740 -
   1.741 -        /** Collects all affected results R that were modified in the
   1.742 -         * given transaction.
   1.743 -         *
   1.744 -         * @param modified place to add results R to
   1.745 -         * @param transaction the transaction indentification
   1.746 -         */
   1.747 -        public void endTransaction(Transaction transaction, Set<R> modifiedResults);
   1.748 -
   1.749 -        /** Adds an item into the storage.
   1.750 -        * @param item to add
   1.751 -        * @param transaction transaction token
   1.752 -        * @return true if the Item has been added for the first time or false if some other
   1.753 -        *    item equal to this one already existed in the lookup
   1.754 -        */
   1.755 -        public boolean add(AbstractLookup.Pair<?> item, Transaction transaction);
   1.756 -
   1.757 -        /** Removes an item.
   1.758 -        */
   1.759 -        public void remove(AbstractLookup.Pair item, Transaction transaction);
   1.760 -
   1.761 -        /** Removes all items that are not present in the provided collection.
   1.762 -        * @param retain collection of Pairs to keep them in
   1.763 -        * @param transaction the transaction context
   1.764 -        */
   1.765 -        public void retainAll(Map retain, Transaction transaction);
   1.766 -
   1.767 -        /** Queries for instances of given class.
   1.768 -        * @param clazz the class to check
   1.769 -        * @return enumeration of Item
   1.770 -        * @see #unsorted
   1.771 -        */
   1.772 -        public <T> Enumeration<Pair<T>> lookup(Class<T> clazz);
   1.773 -
   1.774 -        /** Registers another reference to a result with the storage. This method
   1.775 -         * has also a special meaning.
   1.776 -         *
   1.777 -         * @param newRef the new reference to remember
   1.778 -         * @return the previous reference that was kept (null if newRef is the first one)
   1.779 -         *    the applications is expected to link from newRef to this returned
   1.780 -         *    value to form a linked list
   1.781 -         */
   1.782 -        public ReferenceToResult<?> registerReferenceToResult(ReferenceToResult<?> newRef);
   1.783 -
   1.784 -        /** Given the provided template, Do cleanup the results.
   1.785 -         * @param templ template of a result(s) that should be checked
   1.786 -         * @return null if all references for this template were cleared or one of them
   1.787 -         */
   1.788 -        public ReferenceToResult<?> cleanUpResult(Lookup.Template<?> templ);
   1.789 -    }
   1.790 -
   1.791 -    /** Extension to the default lookup item that offers additional information
   1.792 -     * for the data structures use in AbstractLookup
   1.793 -     */
   1.794 -    public static abstract class Pair<T> extends Lookup.Item<T> implements Serializable {
   1.795 -        private static final long serialVersionUID = 1L;
   1.796 -
   1.797 -        /** possition of this item in the lookup, manipulated in addPair, removePair, setPairs methods */
   1.798 -        private int index = -1;
   1.799 -
   1.800 -        /** For use by subclasses. */
   1.801 -        protected Pair() {
   1.802 -        }
   1.803 -
   1.804 -        final int getIndex() {
   1.805 -            return index;
   1.806 -        }
   1.807 -
   1.808 -        final void setIndex(AbstractLookup.Storage<?> tree, int x) {
   1.809 -            if (tree == null) {
   1.810 -                this.index = x;
   1.811 -
   1.812 -                return;
   1.813 -            }
   1.814 -
   1.815 -            if (this.index == -1) {
   1.816 -                this.index = x;
   1.817 -            } else {
   1.818 -                throw new IllegalStateException("You cannot use " + this + " in more than one AbstractLookup. Prev: " + this.index + " new: " + x); // NOI18N
   1.819 -            }
   1.820 -        }
   1.821 -
   1.822 -        /** Tests whether this item can produce object
   1.823 -        * of class c.
   1.824 -        */
   1.825 -        protected abstract boolean instanceOf(Class<?> c);
   1.826 -
   1.827 -        /** Method that can test whether an instance of a class has been created
   1.828 -         * by this item.
   1.829 -         *
   1.830 -         * @param obj the instance
   1.831 -         * @return if the item has already create an instance and it is the same
   1.832 -         *   as obj.
   1.833 -         */
   1.834 -        protected abstract boolean creatorOf(Object obj);
   1.835 -    }
   1.836 -
   1.837 -    /** Result based on one instance returned.
   1.838 -     */
   1.839 -    static final class R<T> extends WaitableResult<T> {
   1.840 -        /** reference our result is attached to (do not modify) */
   1.841 -        public ReferenceToResult<T> reference;
   1.842 -
   1.843 -        /** listeners on the results or pointer to one listener */
   1.844 -        private Object listeners;
   1.845 -
   1.846 -        public R() {
   1.847 -        }
   1.848 -
   1.849 -        /** Checks whether we have simple behaviour of complex.
   1.850 -         */
   1.851 -        private boolean isSimple() {
   1.852 -            Storage s = (Storage) reference.lookup.tree;
   1.853 -
   1.854 -            return DelegatingStorage.isSimple(s);
   1.855 -        }
   1.856 -
   1.857 -        //
   1.858 -        // Handling cache management for both cases, no caches
   1.859 -        // for simple (but mark that we needed them, so refresh can
   1.860 -        // be done in cloneList) and complex when all 3 types
   1.861 -        // of result are cached
   1.862 -        //
   1.863 -        private Object getFromCache(int indx) {
   1.864 -            if (isSimple()) {
   1.865 -                return null;
   1.866 -            }
   1.867 -
   1.868 -            Object maybeArray = reference.caches;
   1.869 -
   1.870 -            if (maybeArray instanceof Object[]) {
   1.871 -                return ((Object[]) maybeArray)[indx];
   1.872 -            }
   1.873 -
   1.874 -            return null;
   1.875 -        }
   1.876 -
   1.877 -        @SuppressWarnings("unchecked")
   1.878 -        private Set<Class<? extends T>> getClassesCache() {
   1.879 -            return (Set<Class<? extends T>>) getFromCache(0);
   1.880 -        }
   1.881 -
   1.882 -        private void setClassesCache(Set s) {
   1.883 -            if (isSimple()) {
   1.884 -                // mark it as being used
   1.885 -                reference.caches = reference;
   1.886 -
   1.887 -                return;
   1.888 -            }
   1.889 -
   1.890 -            if (!(reference.caches instanceof Object[])) {
   1.891 -                reference.caches = new Object[3];
   1.892 -            }
   1.893 -
   1.894 -            ((Object[]) reference.caches)[0] = s;
   1.895 -        }
   1.896 -
   1.897 -        @SuppressWarnings("unchecked")
   1.898 -        private Collection<T> getInstancesCache() {
   1.899 -            return (Collection<T>) getFromCache(1);
   1.900 -        }
   1.901 -
   1.902 -        private void setInstancesCache(Collection c) {
   1.903 -            if (isSimple()) {
   1.904 -                // mark it as being used
   1.905 -                reference.caches = reference;
   1.906 -
   1.907 -                return;
   1.908 -            }
   1.909 -
   1.910 -            if (!(reference.caches instanceof Object[])) {
   1.911 -                reference.caches = new Object[3];
   1.912 -            }
   1.913 -
   1.914 -            ((Object[]) reference.caches)[1] = c;
   1.915 -        }
   1.916 -
   1.917 -        @SuppressWarnings("unchecked")
   1.918 -        private Pair<T>[] getItemsCache() {
   1.919 -            return (Pair<T>[]) getFromCache(2);
   1.920 -        }
   1.921 -
   1.922 -        private void setItemsCache(Collection<?> c) {
   1.923 -            if (isSimple()) {
   1.924 -                // mark it as being used
   1.925 -                reference.caches = reference;
   1.926 -
   1.927 -                return;
   1.928 -            }
   1.929 -
   1.930 -            if (!(reference.caches instanceof Object[])) {
   1.931 -                reference.caches = new Object[3];
   1.932 -            }
   1.933 -
   1.934 -            ((Object[]) reference.caches)[2] = c.toArray(new Pair[0]);
   1.935 -        }
   1.936 -
   1.937 -        private void clearCaches() {
   1.938 -            if (reference.caches instanceof Object[]) {
   1.939 -                reference.caches = new Object[3];
   1.940 -            }
   1.941 -        }
   1.942 -
   1.943 -        /** Ok, register listeners to all classes and super classes.
   1.944 -         */
   1.945 -        public synchronized void addLookupListener(LookupListener l) {
   1.946 -            listeners = modifyListenerList(true, l, listeners);
   1.947 -        }
   1.948 -
   1.949 -        /** Ok, register listeners to all classes and super classes.
   1.950 -         */
   1.951 -        public synchronized void removeLookupListener(LookupListener l) {
   1.952 -            listeners = modifyListenerList(false, l, listeners);
   1.953 -        }
   1.954 -
   1.955 -        /** Delete all cached values, the template changed.
   1.956 -         */
   1.957 -        protected  void collectFires(Collection<Object> evAndListeners) {
   1.958 -            Object[] previousItems = getItemsCache();
   1.959 -            clearCaches();
   1.960 -            
   1.961 -            if (previousItems != null) {
   1.962 -                Object[] newArray = allItemsWithoutBeforeLookup().toArray();
   1.963 -
   1.964 -                if (compareArrays(previousItems, newArray)) {
   1.965 -                    // do not fire any change if nothing has been changed
   1.966 -                    return;
   1.967 -                }
   1.968 -            }
   1.969 -
   1.970 -            LookupListener[] arr;
   1.971 -
   1.972 -            synchronized (this) {
   1.973 -                if (listeners == null) {
   1.974 -                    return;
   1.975 -                }
   1.976 -
   1.977 -                if (listeners instanceof LookupListener) {
   1.978 -                    arr = new LookupListener[] { (LookupListener) listeners };
   1.979 -                } else {
   1.980 -                    ArrayList<?> l = (ArrayList<?>) listeners;
   1.981 -                    arr = l.toArray(new LookupListener[l.size()]);
   1.982 -                }
   1.983 -            }
   1.984 -
   1.985 -            final LookupListener[] ll = arr;
   1.986 -            final LookupEvent ev = new LookupEvent(this);
   1.987 -            notifyListeners(ll, ev, evAndListeners);
   1.988 -        }
   1.989 -
   1.990 -        public Collection<T> allInstances() {
   1.991 -            reference.lookup.beforeLookup(reference.template);
   1.992 -
   1.993 -            Collection<T> s = getInstancesCache();
   1.994 -
   1.995 -            if (s != null) {
   1.996 -                return s;
   1.997 -            }
   1.998 -
   1.999 -            Collection<Pair<T>> items = allItemsWithoutBeforeLookup();
  1.1000 -            ArrayList<T> list = new ArrayList<T>(items.size());
  1.1001 -
  1.1002 -            Iterator<Pair<T>> it = items.iterator();
  1.1003 -
  1.1004 -            while (it.hasNext()) {
  1.1005 -                Pair<T> item = it.next();
  1.1006 -                T obj = item.getInstance();
  1.1007 -
  1.1008 -                if (reference.template.getType().isInstance(obj)) {
  1.1009 -                    list.add(obj);
  1.1010 -                }
  1.1011 -            }
  1.1012 -            
  1.1013 -            s = Collections.unmodifiableList(list);
  1.1014 -            setInstancesCache(s);
  1.1015 -
  1.1016 -            return s;
  1.1017 -        }
  1.1018 -
  1.1019 -        /** Set of all classes.
  1.1020 -         *
  1.1021 -         */
  1.1022 -        @Override
  1.1023 -        public Set<Class<? extends T>> allClasses() {
  1.1024 -            reference.lookup.beforeLookup(reference.template);
  1.1025 -
  1.1026 -            Set<Class<? extends T>> s = getClassesCache();
  1.1027 -
  1.1028 -            if (s != null) {
  1.1029 -                return s;
  1.1030 -            }
  1.1031 -
  1.1032 -            s = new HashSet<Class<? extends T>>();
  1.1033 -
  1.1034 -            for (Pair<T> item : allItemsWithoutBeforeLookup()) {
  1.1035 -                Class<? extends T> clazz = item.getType();
  1.1036 -
  1.1037 -                if (clazz != null) {
  1.1038 -                    s.add(clazz);
  1.1039 -                }
  1.1040 -            }
  1.1041 -
  1.1042 -            s = Collections.unmodifiableSet(s);
  1.1043 -            setClassesCache(s);
  1.1044 -
  1.1045 -            return s;
  1.1046 -        }
  1.1047 -
  1.1048 -        /** Items are stored directly in the allItems.
  1.1049 -         */
  1.1050 -        @Override
  1.1051 -        public Collection<? extends Item<T>> allItems() {
  1.1052 -            reference.lookup.beforeLookup(reference.template);
  1.1053 -
  1.1054 -            return allItemsWithoutBeforeLookup();
  1.1055 -        }
  1.1056 -
  1.1057 -        /** Implements the search for allItems, but without asking for before lookup */
  1.1058 -        private Collection<Pair<T>> allItemsWithoutBeforeLookup() {
  1.1059 -            Pair<T>[] c = getItemsCache();
  1.1060 -
  1.1061 -            if (c != null) {
  1.1062 -                return Collections.unmodifiableList(Arrays.asList(c));
  1.1063 -            }
  1.1064 -
  1.1065 -            ArrayList<Pair<Object>> saferCheck = null;
  1.1066 -            AbstractLookup.Storage<?> t = reference.lookup.enterStorage();
  1.1067 -
  1.1068 -            try {
  1.1069 -                try {
  1.1070 -                    return Collections.unmodifiableCollection(initItems(t));
  1.1071 -                } catch (AbstractLookup.ISE ex) {
  1.1072 -                    // do less effective evaluation of items outside of the 
  1.1073 -                    // locked storage
  1.1074 -                    saferCheck = new ArrayList<Pair<Object>>();
  1.1075 -
  1.1076 -                    Enumeration<Pair<Object>> en = t.lookup(null); // get all Pairs
  1.1077 -
  1.1078 -                    while (en.hasMoreElements()) {
  1.1079 -                        Pair<Object> i = en.nextElement();
  1.1080 -                        saferCheck.add(i);
  1.1081 -                    }
  1.1082 -                }
  1.1083 -            } finally {
  1.1084 -                reference.lookup.exitStorage();
  1.1085 -            }
  1.1086 -            return extractPairs(saferCheck);
  1.1087 -        }
  1.1088 -
  1.1089 -        @SuppressWarnings("unchecked")
  1.1090 -        private Collection<Pair<T>> extractPairs(final ArrayList<Pair<Object>> saferCheck) {
  1.1091 -            TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
  1.1092 -            for (Pair<Object> i : saferCheck) {
  1.1093 -                if (matches(reference.template, i, false)) {
  1.1094 -                    items.add((Pair<T>)i);
  1.1095 -                }
  1.1096 -            }
  1.1097 -            return Collections.unmodifiableCollection(items);
  1.1098 -        }
  1.1099 -
  1.1100 -        /** Initializes items.
  1.1101 -         */
  1.1102 -        private Collection<Pair<T>> initItems(Storage<?> t) {
  1.1103 -            // manipulation with the tree must be synchronized
  1.1104 -            Enumeration<Pair<T>> en = t.lookup(reference.template.getType());
  1.1105 -
  1.1106 -            // InheritanceTree is comparator for AbstractLookup.Pairs
  1.1107 -            TreeSet<Pair<T>> items = new TreeSet<Pair<T>>(ALPairComparator.DEFAULT);
  1.1108 -
  1.1109 -            while (en.hasMoreElements()) {
  1.1110 -                Pair<T> i = en.nextElement();
  1.1111 -
  1.1112 -                if (matches(reference.template, i, false)) {
  1.1113 -                    items.add(i);
  1.1114 -                }
  1.1115 -            }
  1.1116 -
  1.1117 -            // create a correctly sorted copy using the tree as the comparator
  1.1118 -            setItemsCache(items);
  1.1119 -
  1.1120 -            return items;
  1.1121 -        }
  1.1122 -
  1.1123 -        /** Used by proxy results to synchronize before lookup.
  1.1124 -         */
  1.1125 -        protected void beforeLookup(Lookup.Template t) {
  1.1126 -            if (t.getType() == reference.template.getType()) {
  1.1127 -                reference.lookup.beforeLookup(t);
  1.1128 -            }
  1.1129 -        }
  1.1130 -
  1.1131 -        /* Do not need to implement it, the default way is ok.
  1.1132 -        public boolean equals(java.lang.Object obj) {
  1.1133 -            return obj == this;
  1.1134 -        }
  1.1135 -        */
  1.1136 -        @Override
  1.1137 -        public String toString() {
  1.1138 -            return super.toString() + " for " + reference.template;
  1.1139 -        }
  1.1140 -    }
  1.1141 -     // end of R
  1.1142 -
  1.1143 -    /** A class that can be used by the creator of the AbstractLookup to
  1.1144 -     * control its content. It can be passed to AbstractLookup constructor
  1.1145 -     * and used to add and remove pairs.
  1.1146 -     *
  1.1147 -     * @since 1.25
  1.1148 -     */
  1.1149 -    public static class Content extends Object implements Serializable {
  1.1150 -        private static final long serialVersionUID = 1L;
  1.1151 -
  1.1152 -        // one of them is always null (except attach stage)
  1.1153 -
  1.1154 -        /** abstract lookup we are connected to */
  1.1155 -        private AbstractLookup al;
  1.1156 -        private transient Object notifyIn;
  1.1157 -        
  1.1158 -        /** Default constructor.
  1.1159 -         */
  1.1160 -        public Content() {
  1.1161 -            this(null);
  1.1162 -        }
  1.1163 -        
  1.1164 -        /** Creates a content associated with an executor to handle dispatch
  1.1165 -         * of changes.
  1.1166 -         * @param notifyIn the executor to notify changes in
  1.1167 -         * @since  7.16
  1.1168 -         */
  1.1169 -        public Content(Executor notifyIn) {
  1.1170 -            this.notifyIn = notifyIn;
  1.1171 -        }
  1.1172 -        
  1.1173 -        /** for testing purposes */
  1.1174 -        final void attachExecutor(Executor notifyIn) {
  1.1175 -            this.notifyIn = notifyIn;
  1.1176 -        }
  1.1177 -
  1.1178 -        /** A lookup attaches to this object.
  1.1179 -         */
  1.1180 -        final synchronized void attach(AbstractLookup al) {
  1.1181 -            if (this.al == null) {
  1.1182 -                this.al = al;
  1.1183 -
  1.1184 -                ArrayList<Pair> ep = getEarlyPairs();
  1.1185 -                if (ep != null) {
  1.1186 -                    notifyIn = null;
  1.1187 -                    setPairs(ep);
  1.1188 -                }
  1.1189 -            } else {
  1.1190 -                throw new IllegalStateException(
  1.1191 -                    "Trying to use content for " + al + " but it is already used for " + this.al
  1.1192 -                ); // NOI18N
  1.1193 -            }
  1.1194 -        }
  1.1195 -
  1.1196 -        /** The method to add instance to the lookup with.
  1.1197 -         * @param pair class/instance pair
  1.1198 -         */
  1.1199 -        public final void addPair(Pair<?> pair) {
  1.1200 -            AbstractLookup a = al;
  1.1201 -            Executor e = getExecutor();
  1.1202 -
  1.1203 -            if (a != null || e != null) {
  1.1204 -                a.addPair(pair, e);
  1.1205 -            } else {
  1.1206 -                if (notifyIn == null) {
  1.1207 -                    notifyIn = new ArrayList<Pair>(3);
  1.1208 -                }
  1.1209 -
  1.1210 -                getEarlyPairs().add(pair);
  1.1211 -            }
  1.1212 -        }
  1.1213 -
  1.1214 -        /** Remove instance.
  1.1215 -         * @param pair class/instance pair
  1.1216 -         */
  1.1217 -        public final void removePair(Pair<?> pair) {
  1.1218 -            AbstractLookup a = al;
  1.1219 -            Executor e = getExecutor();
  1.1220 -
  1.1221 -            if (a != null || e != null) {
  1.1222 -                a.removePair(pair, e);
  1.1223 -            } else {
  1.1224 -                if (notifyIn == null) {
  1.1225 -                    notifyIn = new ArrayList<Pair>(3);
  1.1226 -                }
  1.1227 -
  1.1228 -                getEarlyPairs().remove(pair);
  1.1229 -            }
  1.1230 -        }
  1.1231 -
  1.1232 -        /** Changes all pairs in the lookup to new values.
  1.1233 -         * @param c the collection of (Pair) objects
  1.1234 -         */
  1.1235 -        public final void setPairs(Collection<? extends Pair> c) {
  1.1236 -            AbstractLookup a = al;
  1.1237 -            Executor e = getExecutor();
  1.1238 -            
  1.1239 -            if (a != null || e != null) {
  1.1240 -                a.setPairs(c, e);
  1.1241 -            } else {
  1.1242 -                notifyIn = new ArrayList<Pair>(c);
  1.1243 -            }
  1.1244 -        }
  1.1245 -
  1.1246 -        @SuppressWarnings("unchecked")
  1.1247 -        private ArrayList<Pair> getEarlyPairs() {
  1.1248 -            Object o = notifyIn;
  1.1249 -            return o instanceof ArrayList ? (ArrayList<Pair>)o : null;
  1.1250 -        }
  1.1251 -        
  1.1252 -        private Executor getExecutor() {
  1.1253 -            Object o = notifyIn;
  1.1254 -            return o instanceof Executor ? (Executor)o : null;
  1.1255 -        }
  1.1256 -    }
  1.1257 -     // end of Content
  1.1258 -
  1.1259 -    /** Just a holder for index & modified values.
  1.1260 -     */
  1.1261 -    final static class Info extends Object {
  1.1262 -        public int index;
  1.1263 -        public Object transaction;
  1.1264 -
  1.1265 -        public Info(int i, Object t) {
  1.1266 -            index = i;
  1.1267 -            transaction = t;
  1.1268 -        }
  1.1269 -    }
  1.1270 -
  1.1271 -    /** Reference to a result R
  1.1272 -     */
  1.1273 -    static final class ReferenceToResult<T> extends WeakReference<R<T>> implements Runnable {
  1.1274 -        /** next refernece in chain, modified only from AbstractLookup or this */
  1.1275 -        private ReferenceToResult<?> next;
  1.1276 -
  1.1277 -        /** the template for the result */
  1.1278 -        public final Template<T> template;
  1.1279 -
  1.1280 -        /** the lookup we are attached to */
  1.1281 -        public final AbstractLookup lookup;
  1.1282 -
  1.1283 -        /** caches for results */
  1.1284 -        public Object caches;
  1.1285 -
  1.1286 -        /** Creates a weak refernece to a new result R in context of lookup
  1.1287 -         * for given template
  1.1288 -         */
  1.1289 -        private ReferenceToResult(R<T> result, AbstractLookup lookup, Template<T> template) {
  1.1290 -            super(result, activeQueue());
  1.1291 -            this.template = template;
  1.1292 -            this.lookup = lookup;
  1.1293 -            getResult().reference = this;
  1.1294 -        }
  1.1295 -
  1.1296 -        /** Returns the result or null
  1.1297 -         */
  1.1298 -        R<T> getResult() {
  1.1299 -            return get();
  1.1300 -        }
  1.1301 -
  1.1302 -        /** Cleans the reference. Implements Runnable interface, do not call
  1.1303 -         * directly.
  1.1304 -         */
  1.1305 -        public void run() {
  1.1306 -            lookup.cleanUpResult(this.template);
  1.1307 -        }
  1.1308 -
  1.1309 -        /** Clones the reference list to given Storage.
  1.1310 -         * @param storage storage to clone to
  1.1311 -         */
  1.1312 -        public void cloneList(AbstractLookup.Storage<?> storage) {
  1.1313 -            ReferenceIterator it = new ReferenceIterator(this);
  1.1314 -
  1.1315 -            while (it.next()) {
  1.1316 -                ReferenceToResult<?> current = it.current();
  1.1317 -                ReferenceToResult<?> newRef = current.cloneRef();
  1.1318 -                newRef.next = storage.registerReferenceToResult(newRef);
  1.1319 -                newRef.caches = current.caches;
  1.1320 -
  1.1321 -                if (current.caches == current) {
  1.1322 -                    current.getResult().initItems(storage);
  1.1323 -                }
  1.1324 -            }
  1.1325 -        }
  1.1326 -
  1.1327 -        private ReferenceToResult<T> cloneRef() {
  1.1328 -            return new ReferenceToResult<T>(getResult(), lookup, template);
  1.1329 -        }
  1.1330 -    }
  1.1331 -     // end of ReferenceToResult
  1.1332 -
  1.1333 -    /** Supporting class to iterate over linked list of ReferenceToResult
  1.1334 -     * Use:
  1.1335 -     * <PRE>
  1.1336 -     *  ReferenceIterator it = new ReferenceIterator (this.ref);
  1.1337 -     *  while (it.next ()) {
  1.1338 -     *    it.current (): // do some work
  1.1339 -     *  }
  1.1340 -     *  this.ref = it.first (); // remember the first one
  1.1341 -     */
  1.1342 -    static final class ReferenceIterator extends Object {
  1.1343 -        private ReferenceToResult<?> first;
  1.1344 -        private ReferenceToResult<?> current;
  1.1345 -
  1.1346 -        /** hard reference to current result, so it is not GCed meanwhile */
  1.1347 -        private R<?> currentResult;
  1.1348 -
  1.1349 -        /** Initializes the iterator with first reference.
  1.1350 -         */
  1.1351 -        public ReferenceIterator(ReferenceToResult<?> first) {
  1.1352 -            this.first = first;
  1.1353 -        }
  1.1354 -
  1.1355 -        /** Moves the current to next possition */
  1.1356 -        public boolean next() {
  1.1357 -            ReferenceToResult<?> prev;
  1.1358 -            ReferenceToResult<?> ref;
  1.1359 -
  1.1360 -            if (current == null) {
  1.1361 -                ref = first;
  1.1362 -                prev = null;
  1.1363 -            } else {
  1.1364 -                prev = current;
  1.1365 -                ref = current.next;
  1.1366 -            }
  1.1367 -
  1.1368 -            while (ref != null) {
  1.1369 -                R<?> result = ref.get();
  1.1370 -
  1.1371 -                if (result == null) {
  1.1372 -                    if (prev == null) {
  1.1373 -                        // move the head
  1.1374 -                        first = ref.next;
  1.1375 -                    } else {
  1.1376 -                        // skip over this reference
  1.1377 -                        prev.next = ref.next;
  1.1378 -                    }
  1.1379 -
  1.1380 -                    prev = ref;
  1.1381 -                    ref = ref.next;
  1.1382 -                } else {
  1.1383 -                    // we have found next item
  1.1384 -                    currentResult = result;
  1.1385 -                    current = ref;
  1.1386 -
  1.1387 -                    return true;
  1.1388 -                }
  1.1389 -            }
  1.1390 -
  1.1391 -            currentResult = null;
  1.1392 -            current = null;
  1.1393 -
  1.1394 -            return false;
  1.1395 -        }
  1.1396 -
  1.1397 -        /** Access to current reference.
  1.1398 -         */
  1.1399 -        public ReferenceToResult<?> current() {
  1.1400 -            return current;
  1.1401 -        }
  1.1402 -
  1.1403 -        /** Access to reference that is supposed to be the first one.
  1.1404 -         */
  1.1405 -        public ReferenceToResult<?> first() {
  1.1406 -            return first;
  1.1407 -        }
  1.1408 -    }
  1.1409 -
  1.1410 -    /** Signals that a lookup is being modified from a lookup query.
  1.1411 -     *
  1.1412 -     * @author  Jaroslav Tulach
  1.1413 -     */
  1.1414 -    static final class ISE extends IllegalStateException {
  1.1415 -        static final long serialVersionUID = 100L;
  1.1416 -        
  1.1417 -        /** list of jobs to execute. */
  1.1418 -        private java.util.List<Job> jobs;
  1.1419 -
  1.1420 -        /** @param msg message
  1.1421 -         */
  1.1422 -        public ISE(String msg) {
  1.1423 -            super(msg);
  1.1424 -        }
  1.1425 -
  1.1426 -        /** Registers a job to be executed partially out and partially in
  1.1427 -         * the lock over storage.
  1.1428 -         */
  1.1429 -        public void registerJob(Job job) {
  1.1430 -            if (jobs == null) {
  1.1431 -                jobs = new java.util.ArrayList<Job>();
  1.1432 -            }
  1.1433 -
  1.1434 -            jobs.add(job);
  1.1435 -        }
  1.1436 -
  1.1437 -        /** Executes the jobs outside, and then inside a locked session.
  1.1438 -         */
  1.1439 -        public void recover(AbstractLookup lookup) {
  1.1440 -            if (jobs == null) {
  1.1441 -                // no recovery plan, throw itself
  1.1442 -                throw this;
  1.1443 -            }
  1.1444 -
  1.1445 -            for (Job j : jobs) {
  1.1446 -                j.before();
  1.1447 -            }
  1.1448 -
  1.1449 -            AbstractLookup.Storage s = lookup.enterStorage();
  1.1450 -
  1.1451 -            try {
  1.1452 -                for (Job j : jobs) {
  1.1453 -                    j.inside();
  1.1454 -                }
  1.1455 -            } finally {
  1.1456 -                lookup.exitStorage();
  1.1457 -            }
  1.1458 -        }
  1.1459 -
  1.1460 -        /** A job to be executed partially outside and partially inside
  1.1461 -         * the storage lock.
  1.1462 -         */
  1.1463 -        static interface Job {
  1.1464 -            public void before();
  1.1465 -
  1.1466 -            public void inside();
  1.1467 -        }
  1.1468 -    }
  1.1469 -     // end of ISE
  1.1470 -}