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