Warnings.
2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
6 * The contents of this file are subject to the terms of either the GNU
7 * General Public License Version 2 only ("GPL") or the Common
8 * Development and Distribution License("CDDL") (collectively, the
9 * "License"). You may not use this file except in compliance with the
10 * License. You can obtain a copy of the License at
11 * http://www.netbeans.org/cddl-gplv2.html
12 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
13 * specific language governing permissions and limitations under the
14 * License. When distributing the software, include this License Header
15 * Notice in each file and include the License file at
16 * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
17 * particular file as subject to the "Classpath" exception as provided
18 * by Sun in the GPL Version 2 section of the License file that
19 * accompanied this code. If applicable, add the following below the
20 * License Header, with the fields enclosed by brackets [] replaced by
21 * your own identifying information:
22 * "Portions Copyrighted [year] [name of copyright owner]"
26 * The Original Software is NetBeans. The Initial Developer of the Original
27 * Software is Sun Microsystems, Inc. Portions Copyright 1997-2006 Sun
28 * Microsystems, Inc. All Rights Reserved.
30 * If you wish your version of this file to be governed by only the CDDL
31 * or only the GPL Version 2, indicate your decision by adding
32 * "[Contributor] elects to include this software in this distribution
33 * under the [CDDL or GPL Version 2] license." If you do not indicate a
34 * single choice of license, a recipient has the option to distribute
35 * your version of this file under either the CDDL, the GPL Version 2 or
36 * to extend the choice of license to its licensees as provided above.
37 * However, if you add GPL Version 2 code and therefore, elected the GPL
38 * Version 2 license, then the option applies only if the new code is
39 * made subject to such option by the copyright holder.
42 package org.openide.util.lookup;
44 import java.io.Serializable;
46 import java.lang.ref.Reference;
47 import java.lang.ref.WeakReference;
49 import java.util.concurrent.Executor;
50 import junit.framework.*;
51 import org.netbeans.junit.*;
52 import org.netbeans.modules.openide.util.ActiveQueue;
53 import org.openide.util.Lookup;
54 import org.openide.util.Lookup.Result;
55 import org.openide.util.LookupEvent;
56 import org.openide.util.LookupListener;
58 /** Runs all NbLookupTest tests on ProxyLookup and adds few additional.
60 @SuppressWarnings("unchecked") // XXX ought to be corrected, just a lot of them
61 public class ProxyLookupTest extends AbstractLookupBaseHid
62 implements AbstractLookupBaseHid.Impl {
63 public ProxyLookupTest(java.lang.String testName) {
64 super(testName, null);
67 public static Test suite() {
68 return new NbTestSuite (ProxyLookupTest.class);
69 // return new ProxyLookupTest("testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679");
72 /** Creates an lookup for given lookup. This class just returns
73 * the object passed in, but subclasses can be different.
74 * @param lookup in lookup
75 * @return a lookup to use
77 public Lookup createLookup (Lookup lookup) {
78 return new ProxyLookup (new Lookup[] { lookup });
81 public Lookup createInstancesLookup (InstanceContent ic) {
82 return new AbstractLookup (ic);
86 public void clearCaches () {
90 /** Check whether setLookups method does not fire when there is no
91 * change in the lookups.
93 public void testProxyListener () {
94 ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
96 final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
97 final Object[] IGNORE = {
98 ProxyLookup.ImmutableInternalData.EMPTY,
99 ProxyLookup.ImmutableInternalData.EMPTY_ARR,
101 Collections.emptyMap(),
102 Collections.emptyList(),
103 Collections.emptySet()
106 assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
108 Lookup.Result<Object> res = lookup.lookup (template);
110 assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
113 res.addLookupListener (ll);
114 Collection allRes = res.allInstances ();
116 lookup.setLookups (new Lookup[0]);
118 if (ll.getCount () != 0) {
119 fail ("Calling setLookups (emptyarray) fired a change");
122 InstanceContent t = new InstanceContent();
123 Lookup del = new AbstractLookup (t);
125 lookup.setLookups (new Lookup[] { del });
127 if (ll.getCount () != 1) {
128 fail ("Changing lookups did not generate an event");
131 lookup.setLookups (new Lookup[] { del });
133 if (ll.getCount () != 0) {
134 fail ("Calling setLookups (thesamearray) fired a change");
138 public void testNoListenersProxyListener () {
139 ProxyLookup lookup = new ProxyLookup (new Lookup[0]);
140 class E implements Executor {
142 public void execute(Runnable command) {
143 assertNull("NO previous", r);
146 public void perform() {
147 assertNotNull("We shall have a runnable", r);
152 E executor = new E();
155 final Lookup.Template<Object> template = new Lookup.Template<Object>(Object.class);
156 final Object[] IGNORE = {
157 ProxyLookup.ImmutableInternalData.EMPTY,
158 ProxyLookup.ImmutableInternalData.EMPTY_ARR,
160 Collections.emptyMap(),
161 Collections.emptyList(),
162 Collections.emptySet()
165 assertSize("Pretty small", Collections.singleton(lookup), 16, IGNORE);
167 Lookup.Result<Object> res = lookup.lookup (template);
169 assertSize("Bigger", Collections.singleton(lookup), 216, IGNORE);
172 res.addLookupListener (ll);
173 Collection allRes = res.allInstances ();
175 lookup.setLookups (executor, new Lookup[0]);
176 if (ll.getCount () != 0) {
177 fail ("Calling setLookups (emptyarray) fired a change");
180 InstanceContent t = new InstanceContent();
181 Lookup del = new AbstractLookup (t);
183 lookup.setLookups (executor, new Lookup[] { del });
184 assertEquals("No change yet", 0, ll.getCount());
186 if (ll.getCount () != 1) {
187 fail ("Changing lookups did not generate an event");
190 lookup.setLookups (executor, new Lookup[] { del });
191 if (ll.getCount () != 0) {
192 fail ("Calling setLookups (thesamearray) fired a change");
196 public void testSetLookups () throws Exception {
197 AbstractLookup a1 = new AbstractLookup (new InstanceContent ());
198 AbstractLookup a2 = new AbstractLookup (new InstanceContent ());
200 InstanceContent i3 = new InstanceContent ();
202 AbstractLookup a3 = new AbstractLookup (i3);
204 final ProxyLookup p = new ProxyLookup (new Lookup[] { a1, a2 });
205 final Lookup.Result res1 = p.lookup (new Lookup.Template (Object.class));
206 Collection c1 = res1.allInstances();
208 Lookup.Result res2 = p.lookup (new Lookup.Template (String.class));
209 Collection c2 = res2.allInstances ();
212 assertTrue ("We need two results", res1 != res2);
214 final Object blocked = new Object ();
216 class L extends Object implements LookupListener {
217 public void resultChanged (LookupEvent ev) {
219 res1.removeLookupListener(this);
221 // waiting for second thread to start #111#
224 } catch (Exception ex) {
225 ex.printStackTrace();
226 fail ("An exception occured ");
231 final L listener1 = new L ();
232 res1.addLookupListener (listener1);
235 Runnable newLookupSetter = new Runnable() {
237 synchronized (blocked) {
239 p.setLookups (new Lookup[0]);
240 } catch (Exception ex) {
241 ex.printStackTrace();
242 fail ("setLookups failed.");
244 // starts the main thread #111#
251 synchronized (blocked) {
252 new Thread (newLookupSetter).start ();
254 p.setLookups (new Lookup[] { a1, a2, a3 });
258 public void testProxyLookupTemplateCaching(){
259 Lookup lookups[] = new Lookup[1];
260 doProxyLookupTemplateCaching(lookups, false);
263 public void testProxyLookupTemplateCachingOnSizeTwoArray() {
264 Lookup lookups[] = new Lookup[2];
265 lookups[1] = Lookup.EMPTY;
266 doProxyLookupTemplateCaching(lookups, false);
268 public void testProxyLookupShallNotAllowModificationOfGetLookups(){
269 Lookup lookups[] = new Lookup[1];
270 doProxyLookupTemplateCaching(lookups, true);
273 public void testProxyLookupShallNotAllowModificationOfGetLookupsOnSizeTwoArray() {
274 Lookup lookups[] = new Lookup[2];
275 lookups[1] = Lookup.EMPTY;
276 doProxyLookupTemplateCaching(lookups, true);
279 /** Index 0 of lookups will be modified, the rest is up to the
282 private void doProxyLookupTemplateCaching(Lookup[] lookups, boolean reget) {
283 // Create MyProxyLookup with one lookup containing the String object
284 InstanceContent inst = new InstanceContent();
285 inst.add(new String("Hello World")); //NOI18N
286 lookups[0] = new AbstractLookup(inst);
287 ProxyLookup proxy = new ProxyLookup(lookups);
289 lookups = proxy.getLookups();
292 // Performing template lookup for String object
293 Lookup.Result result = proxy.lookup(new Lookup.Template(String.class, null, null));
294 int stringTemplateResultSize = result.allInstances().size();
295 assertEquals ("Ensure, there is only one instance of String.class in proxyLookup:", //NOI18N
296 1, stringTemplateResultSize);
298 // Changing lookup in proxy lookup, now it will contain
299 // StringBuffer Object instead of String
300 InstanceContent ic2 = new InstanceContent();
301 ic2.add(new Integer(1234567890));
302 lookups[0] = new AbstractLookup(ic2);
303 proxy.setLookups(lookups);
305 assertEquals ("the old result is updated", 0, result.allInstances().size());
307 // Instance of String.class should not appear in proxyLookup
308 Lookup.Result r2 = proxy.lookup(new Lookup.Template(String.class, null, null));
309 assertEquals ("Instance of String.class should not appear in proxyLookup:", //NOI18N
310 0, r2.allInstances().size());
312 Lookup.Result r3 = proxy.lookup(new Lookup.Template(Integer.class, null, null));
313 assertEquals ("There is only one instance of Integer.class in proxyLookup:", //NOI18N
314 1, r3.allInstances().size());
317 public void testListeningAndQueryingByTwoListenersInstancesSetLookups() {
318 doListeningAndQueryingByTwoListenersSetLookups(0, 1);
320 public void testListeningAndQueryingByTwoListenersClassesSetLookups() {
321 doListeningAndQueryingByTwoListenersSetLookups(1, 1);
323 public void testListeningAndQueryingByTwoListenersItemsSetLookups() {
324 doListeningAndQueryingByTwoListenersSetLookups(2, 1);
327 public void testListeningAndQueryingByTwoListenersInstancesSetLookups2() {
328 doListeningAndQueryingByTwoListenersSetLookups(0, 2);
330 public void testListeningAndQueryingByTwoListenersClassesSetLookups2() {
331 doListeningAndQueryingByTwoListenersSetLookups(1, 2);
333 public void testListeningAndQueryingByTwoListenersItemsSetLookups2() {
334 doListeningAndQueryingByTwoListenersSetLookups(2, 2);
336 public void testListeningAndQueryingByTwoListenersInstancesSetLookups22() {
337 doListeningAndQueryingByTwoListenersSetLookups(0, 22);
339 public void testListeningAndQueryingByTwoListenersClassesSetLookups22() {
340 doListeningAndQueryingByTwoListenersSetLookups(1, 22);
342 public void testListeningAndQueryingByTwoListenersItemsSetLookups22() {
343 doListeningAndQueryingByTwoListenersSetLookups(2, 22);
346 private void doListeningAndQueryingByTwoListenersSetLookups(final int type, int depth) {
347 ProxyLookup orig = new ProxyLookup();
348 ProxyLookup on = orig;
350 while (--depth > 0) {
351 on = new ProxyLookup(new Lookup[] { on });
355 final ProxyLookup lookup = on;
357 class L implements LookupListener {
358 Lookup.Result integer = lookup.lookup(new Lookup.Template(Integer.class));
359 Lookup.Result number = lookup.lookup(new Lookup.Template(Number.class));
360 Lookup.Result serial = lookup.lookup(new Lookup.Template(Serializable.class));
363 integer.addLookupListener(this);
364 number.addLookupListener(this);
365 serial.addLookupListener(this);
370 public void resultChanged(LookupEvent ev) {
371 Collection c1 = get(type, integer);
372 Collection c2 = get(type, number);
373 Collection c3 = get(type, serial);
375 assertEquals("round " + round + " c1 vs. c2", c1, c2);
376 assertEquals("round " + round + " c1 vs. c3", c1, c3);
377 assertEquals("round " + round + " c2 vs. c3", c2, c3);
382 private Collection get(int type, Lookup.Result res) {
385 case 0: c = res.allInstances(); break;
386 case 1: c = res.allClasses(); break;
387 case 2: c = res.allItems(); break;
388 default: c = null; fail("Type: " + type); break;
392 return new ArrayList(c);
396 L listener = new L();
397 listener.resultChanged(null);
398 ArrayList arr = new ArrayList();
399 for(int i = 0; i < 100; i++) {
400 arr.add(new Integer(i));
402 orig.setLookups(new Lookup[] { Lookups.fixed(arr.toArray()) });
405 assertEquals("3x100+1 checks", 301, listener.round);
408 static Object holder;
410 public void testProxyWithLiveResultCanBeCollected() {
411 Lookup layer0 = Lookups.singleton("Hello");
412 Lookup layer1 = new ProxyLookup(new Lookup[] { layer0 });
413 Lookup layer2 = new ProxyLookup(new Lookup[] { layer1 });
414 Lookup.Result result1 = layer1.lookup(new Lookup.Template(String.class));
416 assertEquals("One instance", 1, result1.allInstances().size());
418 // this will create ProxyLookup$R which listens on origResult
419 Lookup.Result result2 = layer2.lookup(new Lookup.Template(String.class));
421 // this line is necessary. W/o actually querying the result,
422 // it will nether compute it nor attach the listener.
423 assertEquals("One instance", 1, result2.allInstances().size());
425 result2.addLookupListener(new LookupListener() {
426 public void resultChanged(LookupEvent ev) {}
429 Reference ref = new WeakReference(layer2);
434 assertGC ("The proxy lookup not been garbage collected!", ref);
440 public void testArrayIndexAsInIssue119292() throws Exception {
441 final ProxyLookup pl = new ProxyLookup();
442 final int[] cnt = { 0 };
444 class L extends Lookup {
449 l = Lookups.singleton(s);
453 public <T> T lookup(Class<T> clazz) {
454 return l.lookup(clazz);
458 public <T> Result<T> lookup(Template<T> template) {
459 return l.lookup(template);
463 @SuppressWarnings("EqualsWhichDoesntCheckParameterClass")
464 public boolean equals(Object obj) {
469 return super.equals(obj);
473 public int hashCode() {
479 Result<String> res = pl.lookupResult(String.class);
480 assertEquals(Collections.EMPTY_LIST, res.allItems());
482 L[] old = { new L("A"), new L("B") };
483 L[] now = { new L("C") };
488 old[0].set = new L[0];
491 assertEquals("No call to equals", 0, cnt[0]);
493 assertEquals("Still assigned to C", Collections.singletonList("C"), res.allInstances());
496 public void testArrayIndexWithAddRemoveListenerAsInIssue119292() throws Exception {
497 final ProxyLookup pl = new ProxyLookup();
498 final int[] cnt = { 0 };
500 class L extends Lookup {
505 l = Lookups.singleton(s);
509 public <T> T lookup(Class<T> clazz) {
510 return l.lookup(clazz);
514 public <T> Result<T> lookup(Template<T> template) {
515 Result<T> r = l.lookup(template);
519 final class R<T> extends Result<T> {
520 private Result<T> delegate;
522 public R(Result<T> delegate) {
523 this.delegate = delegate;
527 public void addLookupListener(LookupListener l) {
532 delegate.addLookupListener(l);
536 public void removeLookupListener(LookupListener l) {
541 delegate.removeLookupListener(l);
545 public Collection<? extends T> allInstances() {
546 return delegate.allInstances();
551 Result<String> res = pl.lookupResult(String.class);
552 assertEquals(Collections.EMPTY_LIST, res.allItems());
554 L[] old = { new L("A"), new L("B") };
555 L[] now = { new L("C") };
560 old[0].set = new L[0];
564 fail("There should be calls to listeners");
567 assertEquals("C is overriden from removeLookupListener", Collections.emptyList(), res.allInstances());
571 public void testArrayIndexWithSetLookupAsInIssue123679() throws Exception {
572 final ProxyLookup pl = new ProxyLookup();
573 final int[] cnt = { 0 };
575 class L extends Lookup {
578 Collection<? extends Serializable> res;
581 l = Lookups.singleton(s);
585 public <T> T lookup(Class<T> clazz) {
586 return l.lookup(clazz);
590 public <T> Result<T> lookup(Template<T> template) {
594 res = pl.lookupAll(Serializable.class);
596 Result<T> r = l.lookup(template);
601 L[] now = { new L("A"), new L("B") };
602 L[] old = { new L("C") };
606 Result<String> res = pl.lookupResult(String.class);
607 assertEquals("New items visible", 2, res.allItems().size());
610 pl.setLookups(new L("X"), new L("Y"), new L("Z"));
613 public void testDuplicatedLookupArrayIndexWithSetLookupAsInIssue123679() throws Exception {
614 final ProxyLookup pl = new ProxyLookup();
615 final int[] cnt = { 0 };
617 class L extends Lookup {
620 Collection<? extends Serializable> res;
623 l = Lookups.singleton(s);
627 public <T> T lookup(Class<T> clazz) {
628 return l.lookup(clazz);
632 public <T> Result<T> lookup(Template<T> template) {
636 res = pl.lookupAll(Serializable.class);
638 Result<T> r = l.lookup(template);
645 L[] old = { new L("C") };
649 Result<String> res = pl.lookupResult(String.class);
650 assertEquals("New items visible", 1, res.allItems().size());