Index: api/doc/org/openide/doc-files/services-api.html
===================================================================
RCS file: /cvs/openide/api/doc/org/openide/doc-files/services-api.html,v
retrieving revision 1.34
diff -u -r1.34 services-api.html
--- api/doc/org/openide/doc-files/services-api.html 17 Mar 2004 15:03:20 -0000 1.34
+++ api/doc/org/openide/doc-files/services-api.html 30 Apr 2004 10:22:26 -0000
@@ -853,7 +853,7 @@
- The Lookup supports a small extension to the
+ The Lookup supports two small extensions to the
JDK's
standard. It allows a module to remove class registered by
another one. That is why it is possible to write a module that
@@ -871,6 +871,22 @@
compatibility with JDK's implementation. The
# means comment
and thus JDK will not interpret the line and will not get confused by
the
- before class name.
+
+
Second extension allows ordering of items. The class implementing
+ the interface can be followed by advisory position attribute. When
+ querying on an interface, items with a smaller position are guaranteed
+ to be returned before items with a larger position. Items with no defined
+ position are returned last. Example of content of
+ META-INF/services/org.me.MyService
+ file could be:
+
+ org.you.MyServiceImpl
+ #position=10
+
+ It is recommended to pick up larger numbers so that there is
+ gap for other modules if they need to get in front of your item. And,
+ again, to keep compatibility the position attribute must starts with
+ comment delimiter.
Index: src/org/openide/util/lookup/MetaInfServicesLookup.java
===================================================================
RCS file: /cvs/openide/src/org/openide/util/lookup/MetaInfServicesLookup.java,v
retrieving revision 1.6
diff -u -r1.6 MetaInfServicesLookup.java
--- src/org/openide/util/lookup/MetaInfServicesLookup.java 5 Oct 2003 13:17:43 -0000 1.6
+++ src/org/openide/util/lookup/MetaInfServicesLookup.java 30 Apr 2004 10:22:38 -0000
@@ -113,7 +113,7 @@
// has the same entry in it (and they load to the same class).
// Probably would not happen, assuming JARs only list classes
// they own, but just in case...
- Collection foundClasses = new ArrayList (); // Collection
+ List/*- */ foundClasses = new ArrayList();
Collection removeClasses = new ArrayList (); // Collection
boolean foundOne = false;
@@ -152,6 +152,7 @@
}
URL url = (URL)en.nextElement();
+ Item currentItem = null;
try {
InputStream is = url.openStream();
try {
@@ -160,8 +161,26 @@
String line = reader.readLine();
if (line == null) break;
- // Ignore blank lines and comments.
line = line.trim();
+ // is it position attribute?
+ if (line.startsWith("#position=")) {
+ if (currentItem == null) {
+ assert false : "Found line '"+line+"' but there is no item to associate it with!";
+ }
+ try {
+ currentItem.position = Integer.parseInt(line.substring(10));
+ } catch (NumberFormatException e) {
+ // do not use ErrorManager because we are in the startup code
+ // and ErrorManager might not be ready
+ e.printStackTrace();
+ }
+ }
+ if (currentItem != null) {
+ insertItem(currentItem, foundClasses);
+ currentItem = null;
+ }
+
+ // Ignore blank lines and comments.
if (line.length() == 0) continue;
boolean remove = false;
@@ -196,9 +215,17 @@
if (remove) {
removeClasses.add (inst);
} else {
- foundClasses.add(inst);
+ // create new item here, but do not put it into
+ // foundClasses array yet because following line
+ // might specify its position
+ currentItem = new Item();
+ currentItem.clazz = inst;
}
}
+ if (currentItem != null) {
+ insertItem(currentItem, foundClasses);
+ currentItem = null;
+ }
} finally {
is.close();
}
@@ -217,9 +244,44 @@
foundClasses.removeAll (removeClasses);
Iterator it = foundClasses.iterator ();
while (it.hasNext ()) {
- Class inst = (Class)it.next ();
- result.add(new P(inst));
+ Item item = (Item)it.next ();
+ if (removeClasses.contains(item.clazz)) {
+ continue;
+ }
+ result.add(new P(item.clazz));
+ }
+ }
+
+ /**
+ * Insert item to the list according to item.position value.
+ */
+ private void insertItem(Item item, List list) {
+ // no position? -> add it to the end
+ if (item.position == -1) {
+ list.add(item);
+ return;
+ }
+ int index = -1;
+ Iterator it = list.iterator();
+ while (it.hasNext()) {
+ index++;
+ Item i = (Item)it.next();
+ if (i.position == -1) {
+ list.add(index, item);
+ return;
+ } else {
+ if (i.position > item.position) {
+ list.add(index, item);
+ return;
+ }
+ }
}
+ list.add(item);
+ }
+
+ private static class Item {
+ private Class clazz;
+ private int position = -1;
}
/** Pair that holds name of a class and maybe the instance.
Index: test/unit/src/org/openide/util/MetaInfServicesLookupTest.java
===================================================================
RCS file: /cvs/openide/test/unit/src/org/openide/util/MetaInfServicesLookupTest.java,v
retrieving revision 1.6
diff -u -r1.6 MetaInfServicesLookupTest.java
--- test/unit/src/org/openide/util/MetaInfServicesLookupTest.java 11 Sep 2003 15:56:47 -0000 1.6
+++ test/unit/src/org/openide/util/MetaInfServicesLookupTest.java 30 Apr 2004 10:22:42 -0000
@@ -100,6 +100,30 @@
assertNull ("services1.jar defines Runnable, but services2.jar masks it out", l4.lookup (Runnable.class));
}
+ public void testOrdering() throws Exception {
+ Lookup l = Lookups.metaInfServices(c1);
+ Class xface = c1.loadClass("java.util.Comparator");
+ List results = new ArrayList(l.lookup(new Lookup.Template(xface)).allInstances());
+ assertEquals(1, results.size());
+
+ l = Lookups.metaInfServices(c2);
+ xface = c2.loadClass("java.util.Comparator");
+ results = new ArrayList(l.lookup(new Lookup.Template(xface)).allInstances());
+ assertEquals(2, results.size());
+ // Test order:
+ assertEquals("org.bar.Comparator2", results.get(0).getClass().getName());
+ assertEquals("org.foo.impl.Comparator1", results.get(1).getClass().getName());
+
+ // test that items without position are always at the end
+ l = Lookups.metaInfServices(c2);
+ xface = c2.loadClass("java.util.Iterator");
+ results = new ArrayList(l.lookup(new Lookup.Template(xface)).allInstances());
+ assertEquals(2, results.size());
+ // Test order:
+ assertEquals("org.bar.Iterator2", results.get(0).getClass().getName());
+ assertEquals("org.foo.impl.Iterator1", results.get(1).getClass().getName());
+ }
+
public void testListenersAreNotifiedWithoutHoldingALockIssue36035 () throws Exception {
final Lookup l = Lookups.metaInfServices(c2);
final Class xface = c1.loadClass("org.foo.Interface");
Index: test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Comparator
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Comparator
diff -N test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Comparator
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Comparator 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1,4 @@
+#some comment
+org.foo.impl.Comparator1
+#position=10
+#som comment2
Index: test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Iterator
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Iterator
diff -N test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Iterator
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-1/META-INF/services/java.util.Iterator 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1 @@
+org.foo.impl.Iterator1
Index: test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Comparator1.java
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Comparator1.java
diff -N test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Comparator1.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Comparator1.java 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1,7 @@
+
+package org.foo.impl;
+
+public class Comparator1 implements java.util.Comparator {
+ public int compare(Object o1, Object o2) {return 0;}
+ public boolean equals(Object obj) {return true;}
+}
Index: test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Iterator1.java
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Iterator1.java
diff -N test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Iterator1.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-1/org/foo/impl/Iterator1.java 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1,11 @@
+
+package org.foo.impl;
+
+public class Iterator1 implements java.util.Iterator {
+ public boolean hasNext() {return false;}
+
+ public Object next() {return null;}
+
+ public void remove() {}
+
+}
Index: test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Comparator
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Comparator
diff -N test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Comparator
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Comparator 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1,2 @@
+org.bar.Comparator2
+#position=5
Index: test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Iterator
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Iterator
diff -N test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Iterator
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-2/META-INF/services/java.util.Iterator 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1,2 @@
+org.bar.Iterator2
+#position=100
Index: test/unit/src/org/openide/util/data/services-jar-2/org/bar/Comparator2.java
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-2/org/bar/Comparator2.java
diff -N test/unit/src/org/openide/util/data/services-jar-2/org/bar/Comparator2.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-2/org/bar/Comparator2.java 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1,7 @@
+
+package org.bar;
+
+public class Comparator2 implements java.util.Comparator {
+ public int compare(Object o1, Object o2) {return 0;}
+ public boolean equals(Object obj) {return true;}
+}
Index: test/unit/src/org/openide/util/data/services-jar-2/org/bar/Iterator2.java
===================================================================
RCS file: test/unit/src/org/openide/util/data/services-jar-2/org/bar/Iterator2.java
diff -N test/unit/src/org/openide/util/data/services-jar-2/org/bar/Iterator2.java
--- /dev/null 1 Jan 1970 00:00:00 -0000
+++ test/unit/src/org/openide/util/data/services-jar-2/org/bar/Iterator2.java 30 Apr 2004 10:22:42 -0000
@@ -0,0 +1,11 @@
+
+package org.bar;
+
+public class Iterator2 implements java.util.Iterator {
+ public boolean hasNext() {return false;}
+
+ public Object next() {return null;}
+
+ public void remove() {}
+
+}