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 -}