Skip to main content
aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBJ Hargrave2008-10-01 19:49:49 +0000
committerBJ Hargrave2008-10-01 19:49:49 +0000
commit19c51e86352d7f6ef6f0dd1c525ce14c118585e5 (patch)
tree48cdfce5479b2ec4eb26a005d96a90823e375a44
parentbe5cb5ffadb37eca2cf7fd201fe0b397d580c9cb (diff)
downloadrt.equinox.framework-19c51e86352d7f6ef6f0dd1c525ce14c118585e5.tar.gz
rt.equinox.framework-19c51e86352d7f6ef6f0dd1c525ce14c118585e5.tar.xz
rt.equinox.framework-19c51e86352d7f6ef6f0dd1c525ce14c118585e5.zip
ASSIGNED - bug 244625: Implement new service registry hooks (RFC 126)
https://bugs.eclipse.org/bugs/show_bug.cgi?id=244625 Add FindHook support
-rw-r--r--bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ServiceRegistryBundleTests.java377
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java2
-rwxr-xr-xbundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceReferenceImpl.java28
-rwxr-xr-xbundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java52
-rwxr-xr-xbundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java241
-rwxr-xr-xbundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceUse.java2
-rw-r--r--bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ShrinkableCollection.java90
7 files changed, 626 insertions, 166 deletions
diff --git a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ServiceRegistryBundleTests.java b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ServiceRegistryBundleTests.java
index db6eeb2bb..0f35baa24 100644
--- a/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ServiceRegistryBundleTests.java
+++ b/bundles/org.eclipse.osgi.tests/src/org/eclipse/osgi/tests/bundles/ServiceRegistryBundleTests.java
@@ -10,11 +10,11 @@
*******************************************************************************/
package org.eclipse.osgi.tests.bundles;
-import java.util.Hashtable;
-import junit.framework.Test;
-import junit.framework.TestSuite;
+import java.util.*;
+import junit.framework.*;
import org.eclipse.osgi.tests.OSGiTestsActivator;
import org.osgi.framework.*;
+import org.osgi.framework.hooks.service.FindHook;
import org.osgi.util.tracker.ServiceTracker;
import org.osgi.util.tracker.ServiceTrackerCustomizer;
@@ -24,6 +24,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceTracker01() {
+ final String testMethodName = "testServiceTracker01"; //$NON-NLS-1$
// simple ServiceTracker test
Runnable runIt = new Runnable() {
public void run() {
@@ -31,7 +32,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
};
Hashtable props = new Hashtable();
- props.put("testServiceTracker01", Boolean.TRUE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.TRUE);
ServiceRegistration reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runIt, props);
ServiceTracker testTracker = null;
try {
@@ -51,7 +52,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
};
try {
- testTracker = new ServiceTracker(OSGiTestsActivator.getContext(), FrameworkUtil.createFilter("(&(objectClass=java.lang.Runnable)(testServiceTracker01=true))"), testCustomizer); //$NON-NLS-1$
+ testTracker = new ServiceTracker(OSGiTestsActivator.getContext(), FrameworkUtil.createFilter("(&(objectClass=java.lang.Runnable)(" + testMethodName + "=true))"), testCustomizer); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("filter error", e); //$NON-NLS-1$
}
@@ -70,7 +71,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props to no longer match
- props.put("testServiceTracker01", Boolean.FALSE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.FALSE);
reg.setProperties(props);
assertFalse("Did call addingService", results[0]); //$NON-NLS-1$
assertFalse("Did call modifiedService", results[1]); //$NON-NLS-1$
@@ -86,7 +87,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props back to match
- props.put("testServiceTracker01", Boolean.TRUE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.TRUE);
reg.setProperties(props);
assertTrue("Did not call addingService", results[0]); //$NON-NLS-1$
assertFalse("Did call modifiedService", results[1]); //$NON-NLS-1$
@@ -102,6 +103,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceTracker02() {
+ final String testMethodName = "testServiceTracker02"; //$NON-NLS-1$
// simple ServiceTracker test
Runnable runIt = new Runnable() {
public void run() {
@@ -109,7 +111,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
};
Hashtable props = new Hashtable();
- props.put("testServiceTracker02", Boolean.FALSE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.FALSE);
ServiceRegistration reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runIt, props);
ServiceTracker testTracker = null;
try {
@@ -129,7 +131,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
};
try {
- testTracker = new ServiceTracker(OSGiTestsActivator.getContext(), FrameworkUtil.createFilter("(&(objectClass=java.lang.Runnable)(testServiceTracker02=true))"), testCustomizer); //$NON-NLS-1$
+ testTracker = new ServiceTracker(OSGiTestsActivator.getContext(), FrameworkUtil.createFilter("(&(objectClass=java.lang.Runnable)(" + testMethodName + "=true))"), testCustomizer); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("filter error", e); //$NON-NLS-1$
}
@@ -140,7 +142,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props to match
- props.put("testServiceTracker02", Boolean.TRUE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.TRUE);
reg.setProperties(props);
assertTrue("Did not call addingService", results[0]); //$NON-NLS-1$
assertFalse("Did call modifiedService", results[1]); //$NON-NLS-1$
@@ -156,7 +158,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props to no longer match
- props.put("testServiceTracker02", Boolean.FALSE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.FALSE);
reg.setProperties(props);
assertFalse("Did call addingService", results[0]); //$NON-NLS-1$
assertFalse("Did call modifiedService", results[1]); //$NON-NLS-1$
@@ -180,6 +182,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceListener01() {
+ final String testMethodName = "testServiceListener01"; //$NON-NLS-1$
// simple ServiceListener test
Runnable runIt = new Runnable() {
public void run() {
@@ -206,7 +209,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
};
try {
- OSGiTestsActivator.getContext().addServiceListener(testListener, "(&(objectClass=java.lang.Runnable)(testServiceListener01=true))"); //$NON-NLS-1$
+ OSGiTestsActivator.getContext().addServiceListener(testListener, "(&(objectClass=java.lang.Runnable)(" + testMethodName + "=true))"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("filter error", e); //$NON-NLS-1$
}
@@ -214,7 +217,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
try {
// register service which matches
Hashtable props = new Hashtable();
- props.put("testServiceListener01", Boolean.TRUE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.TRUE);
reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runIt, props);
assertTrue("Did not get ServiceEvent.REGISTERED", results[0]); //$NON-NLS-1$
assertFalse("Did get ServiceEvent.MODIFIED", results[1]); //$NON-NLS-1$
@@ -232,7 +235,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props to no longer match
- props.put("testServiceListener01", Boolean.FALSE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.FALSE);
reg.setProperties(props);
assertFalse("Did get ServiceEvent.REGISTERED", results[0]); //$NON-NLS-1$
assertFalse("Did get ServiceEvent.MODIFIED", results[1]); //$NON-NLS-1$
@@ -250,7 +253,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props back to match
- props.put("testServiceListener01", Boolean.TRUE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.TRUE);
reg.setProperties(props);
assertFalse("Did get ServiceEvent.REGISTERED", results[0]); //$NON-NLS-1$
assertTrue("Did not get ServiceEvent.MODIFIED", results[1]); //$NON-NLS-1$
@@ -274,6 +277,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceListener02() {
+ final String testMethodName = "testServiceListener02"; //$NON-NLS-1$
// simple ServiceListener test
Runnable runIt = new Runnable() {
public void run() {
@@ -300,7 +304,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
};
try {
- OSGiTestsActivator.getContext().addServiceListener(testListener, "(&(objectClass=java.lang.Runnable)(testServiceListener02=true))"); //$NON-NLS-1$
+ OSGiTestsActivator.getContext().addServiceListener(testListener, "(&(objectClass=java.lang.Runnable)(" + testMethodName + "=true))"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("filter error", e); //$NON-NLS-1$
}
@@ -308,7 +312,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
try {
// register service which does not match
Hashtable props = new Hashtable();
- props.put("testServiceListener02", Boolean.FALSE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.FALSE);
reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runIt, props);
assertFalse("Did get ServiceEvent.REGISTERED", results[0]); //$NON-NLS-1$
assertFalse("Did get ServiceEvent.MODIFIED", results[1]); //$NON-NLS-1$
@@ -326,7 +330,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props to match
- props.put("testServiceListener02", Boolean.TRUE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.TRUE);
reg.setProperties(props);
assertFalse("Did get ServiceEvent.REGISTERED", results[0]); //$NON-NLS-1$
assertTrue("Did not get ServiceEvent.MODIFIED", results[1]); //$NON-NLS-1$
@@ -344,7 +348,7 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
clearResults(results);
// change props to no longer match
- props.put("testServiceListener02", Boolean.FALSE); //$NON-NLS-1$
+ props.put(testMethodName, Boolean.FALSE);
reg.setProperties(props);
assertFalse("Did get ServiceEvent.REGISTERED", results[0]); //$NON-NLS-1$
assertFalse("Did get ServiceEvent.MODIFIED", results[1]); //$NON-NLS-1$
@@ -368,17 +372,18 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceException01() {
+ final String testMethodName = "testServiceException01"; //$NON-NLS-1$
// test a service factory which returns wrong object types
ServiceExceptionServiceFactory wrongObjectFactory = new ServiceExceptionServiceFactory("A String"); //$NON-NLS-1$
Hashtable props = new Hashtable();
- props.put("name", "testServiceException01"); //$NON-NLS-1$ //$NON-NLS-2$
+ props.put("name", testMethodName); //$NON-NLS-1$
ServiceRegistration reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), wrongObjectFactory, props);
ServiceExceptionFrameworkListener listener = new ServiceExceptionFrameworkListener(OSGiTestsActivator.getContext().getBundle(), null, ServiceException.FACTORY_ERROR);
OSGiTestsActivator.getContext().addFrameworkListener(listener);
try {
ServiceReference[] refs = null;
try {
- refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=testServiceException01)"); //$NON-NLS-1$
+ refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=" + testMethodName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("Unexpected syntax error", e); //$NON-NLS-1$
}
@@ -405,17 +410,18 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceException02() {
+ final String testMethodName = "testServiceException02"; //$NON-NLS-1$
// test a service factory which returns null objects
ServiceExceptionServiceFactory nullObjectFactory = new ServiceExceptionServiceFactory(null);
Hashtable props = new Hashtable();
- props.put("name", "testServiceException02"); //$NON-NLS-1$ //$NON-NLS-2$
+ props.put("name", testMethodName); //$NON-NLS-1$
ServiceRegistration reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), nullObjectFactory, props);
ServiceExceptionFrameworkListener listener = new ServiceExceptionFrameworkListener(OSGiTestsActivator.getContext().getBundle(), null, ServiceException.FACTORY_ERROR);
OSGiTestsActivator.getContext().addFrameworkListener(listener);
try {
ServiceReference[] refs = null;
try {
- refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=testServiceException02)"); //$NON-NLS-1$
+ refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=" + testMethodName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("Unexpected syntax error", e); //$NON-NLS-1$
}
@@ -442,18 +448,19 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceException03() {
+ final String testMethodName = "testServiceException03"; //$NON-NLS-1$
// test a service factory which throws a RuntimeException
- RuntimeException cause = new RuntimeException("testServiceException03"); //$NON-NLS-1$
+ RuntimeException cause = new RuntimeException(testMethodName);
ServiceExceptionServiceFactory runtimeExceptionFactory = new ServiceExceptionServiceFactory(cause);
Hashtable props = new Hashtable();
- props.put("name", "testServiceException03"); //$NON-NLS-1$ //$NON-NLS-2$
+ props.put("name", testMethodName); //$NON-NLS-1$
ServiceRegistration reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runtimeExceptionFactory, props);
ServiceExceptionFrameworkListener listener = new ServiceExceptionFrameworkListener(OSGiTestsActivator.getContext().getBundle(), cause, ServiceException.FACTORY_EXCEPTION);
OSGiTestsActivator.getContext().addFrameworkListener(listener);
try {
ServiceReference[] refs = null;
try {
- refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=testServiceException03)"); //$NON-NLS-1$
+ refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=" + testMethodName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("Unexpected syntax error", e); //$NON-NLS-1$
}
@@ -480,18 +487,19 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
public void testServiceException04() {
+ final String testMethodName = "testServiceException04"; //$NON-NLS-1$
// test a service factory which throws an Error
- Error cause = new Error("testServiceException04"); //$NON-NLS-1$
+ Error cause = new Error(testMethodName);
ServiceExceptionServiceFactory errorFactory = new ServiceExceptionServiceFactory(cause);
Hashtable props = new Hashtable();
- props.put("name", "testServiceException03"); //$NON-NLS-1$ //$NON-NLS-2$
+ props.put("name", testMethodName); //$NON-NLS-1$
ServiceRegistration reg = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), errorFactory, props);
ServiceExceptionFrameworkListener listener = new ServiceExceptionFrameworkListener(OSGiTestsActivator.getContext().getBundle(), cause, ServiceException.FACTORY_EXCEPTION);
OSGiTestsActivator.getContext().addFrameworkListener(listener);
try {
ServiceReference[] refs = null;
try {
- refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=testServiceException03)"); //$NON-NLS-1$
+ refs = OSGiTestsActivator.getContext().getServiceReferences(Runnable.class.getName(), "(name=" + testMethodName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
} catch (InvalidSyntaxException e) {
fail("Unexpected syntax error", e); //$NON-NLS-1$
}
@@ -517,6 +525,317 @@ public class ServiceRegistryBundleTests extends AbstractBundleTests {
}
}
+ public void testServiceOrdering01() {
+ final String testMethodName = "testServiceOrdering01"; //$NON-NLS-1$
+ // test that getServiceReference returns the proper service
+ Runnable runIt = new Runnable() {
+ public void run() {
+ // nothing
+ }
+ };
+ Hashtable props = new Hashtable();
+ props.put("name", testMethodName); //$NON-NLS-1$
+ props.put(Constants.SERVICE_DESCRIPTION, "min value"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE));
+ ServiceRegistration reg1 = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runIt, props);
+
+ props.put(Constants.SERVICE_DESCRIPTION, "max value first"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
+ ServiceRegistration reg2 = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runIt, props);
+
+ props.put(Constants.SERVICE_DESCRIPTION, "max value second"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
+ ServiceRegistration reg3 = OSGiTestsActivator.getContext().registerService(Runnable.class.getName(), runIt, props);
+
+ try {
+ ServiceReference ref = null;
+ ref = OSGiTestsActivator.getContext().getServiceReference(Runnable.class.getName());
+ assertNotNull("service ref is null", ref); //$NON-NLS-1$
+ assertEquals("Wrong references", reg2.getReference(), ref); //$NON-NLS-1$
+ } finally {
+ if (reg1 != null)
+ reg1.unregister();
+ if (reg2 != null)
+ reg2.unregister();
+ if (reg3 != null)
+ reg3.unregister();
+ }
+ }
+
+ public void testFindHook01() {
+ final String testMethodName = "testFindHook01"; //$NON-NLS-1$
+ // test the FindHook is called and can remove a reference from the results
+ Runnable runIt = new Runnable() {
+ public void run() {
+ // nothing
+ }
+ };
+ final BundleContext testContext = OSGiTestsActivator.getContext();
+ // register services
+ Hashtable props = new Hashtable();
+ props.put("name", testMethodName); //$NON-NLS-1$
+ props.put(Constants.SERVICE_DESCRIPTION, "service 1"); //$NON-NLS-1$
+ final ServiceRegistration reg1 = testContext.registerService(Runnable.class.getName(), runIt, props);
+
+ props.put(Constants.SERVICE_DESCRIPTION, "service 2"); //$NON-NLS-1$
+ final ServiceRegistration reg2 = testContext.registerService(Runnable.class.getName(), runIt, props);
+
+ props.put(Constants.SERVICE_DESCRIPTION, "service 3"); //$NON-NLS-1$
+ final ServiceRegistration reg3 = testContext.registerService(Runnable.class.getName(), runIt, props);
+
+ final int[] hookCalled = new int[] {0, 0, 0, 0, 0};
+ final AssertionFailedError[] hookError = new AssertionFailedError[] {null, null, null, null};
+
+ // register find hook 1
+ props.put(Constants.SERVICE_DESCRIPTION, "find hook 1"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_DESCRIPTION, "min value"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MIN_VALUE));
+ ServiceRegistration regHook1 = testContext.registerService(FindHook.class.getName(), new FindHook() {
+ public void find(BundleContext context, String name, String filter, boolean allServices, Collection references) {
+ try {
+ synchronized (hookCalled) {
+ hookCalled[++hookCalled[0]] = 1;
+ }
+ assertEquals("wrong context in hook", testContext, context); //$NON-NLS-1$
+ assertEquals("wrong name in hook", Runnable.class.getName(), name); //$NON-NLS-1$
+ assertEquals("wrong filter in hook", "(name=" + testMethodName + ")", filter); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ assertEquals("wrong allservices in hook", false, allServices); //$NON-NLS-1$
+ assertEquals("wrong number of services in hook", 1, references.size()); //$NON-NLS-1$
+ Iterator iter = references.iterator();
+ while (iter.hasNext()) {
+ ServiceReference ref = (ServiceReference) iter.next();
+ if (ref.equals(reg1.getReference())) {
+ fail("service 1 is present"); //$NON-NLS-1$
+ }
+ if (ref.equals(reg2.getReference())) {
+ fail("service 2 is present"); //$NON-NLS-1$
+ }
+ }
+
+ try {
+ references.add(reg1.getReference());
+ fail("add to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ try {
+ references.addAll(Arrays.asList(new ServiceReference[] {reg1.getReference()}));
+ fail("addAll to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ } catch (AssertionFailedError a) {
+ hookError[0] = a;
+ return;
+ }
+ }
+ }, props);
+
+ // register find hook 2
+ props.put(Constants.SERVICE_DESCRIPTION, "find hook 2"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_DESCRIPTION, "max value first"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
+ ServiceRegistration regHook2 = testContext.registerService(FindHook.class.getName(), new FindHook() {
+ public void find(BundleContext context, String name, String filter, boolean allServices, Collection references) {
+ try {
+ synchronized (hookCalled) {
+ hookCalled[++hookCalled[0]] = 2;
+ }
+ assertEquals("wrong context in hook", testContext, context); //$NON-NLS-1$
+ assertEquals("wrong name in hook", Runnable.class.getName(), name); //$NON-NLS-1$
+ assertEquals("wrong filter in hook", "(name=" + testMethodName + ")", filter); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ assertEquals("wrong allservices in hook", false, allServices); //$NON-NLS-1$
+ assertEquals("wrong number of services in hook", 3, references.size()); //$NON-NLS-1$
+ Iterator iter = references.iterator();
+ while (iter.hasNext()) {
+ ServiceReference ref = (ServiceReference) iter.next();
+ if (ref.equals(reg2.getReference())) {
+ iter.remove();
+ }
+ }
+
+ try {
+ references.add(reg2.getReference());
+ fail("add to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ try {
+ references.addAll(Arrays.asList(new ServiceReference[] {reg2.getReference()}));
+ fail("addAll to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ } catch (AssertionFailedError a) {
+ hookError[1] = a;
+ return;
+ }
+ }
+ }, props);
+
+ // register find hook 3
+ props.put(Constants.SERVICE_DESCRIPTION, "find hook 3"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_DESCRIPTION, "max value second"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
+ ServiceRegistration regHook3 = testContext.registerService(FindHook.class.getName(), new FindHook() {
+ public void find(BundleContext context, String name, String filter, boolean allServices, Collection references) {
+ try {
+ synchronized (hookCalled) {
+ hookCalled[++hookCalled[0]] = 3;
+ }
+ assertEquals("wrong context in hook", testContext, context); //$NON-NLS-1$
+ assertEquals("wrong name in hook", Runnable.class.getName(), name); //$NON-NLS-1$
+ assertEquals("wrong filter in hook", "(name=" + testMethodName + ")", filter); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ assertEquals("wrong allservices in hook", false, allServices); //$NON-NLS-1$
+ assertEquals("wrong number of services in hook", 2, references.size()); //$NON-NLS-1$
+ Iterator iter = references.iterator();
+ while (iter.hasNext()) {
+ ServiceReference ref = (ServiceReference) iter.next();
+ if (ref.equals(reg2.getReference())) {
+ fail("service 2 is present"); //$NON-NLS-1$
+ }
+ }
+
+ try {
+ references.add(reg2.getReference());
+ fail("add to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ try {
+ references.addAll(Arrays.asList(new ServiceReference[] {reg2.getReference()}));
+ fail("addAll to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ } catch (AssertionFailedError a) {
+ hookError[2] = a;
+ return;
+ }
+ // throw an exception from the hook to test that the next hooks are called.
+ throw new RuntimeException(testMethodName);
+ }
+ }, props);
+
+ // register find hook 4
+ props.put(Constants.SERVICE_DESCRIPTION, "find hook 4"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_DESCRIPTION, "max value third"); //$NON-NLS-1$
+ props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
+ ServiceRegistration regHook4 = testContext.registerService(FindHook.class.getName(), new FindHook() {
+ public void find(BundleContext context, String name, String filter, boolean allServices, Collection references) {
+ try {
+ synchronized (hookCalled) {
+ hookCalled[++hookCalled[0]] = 4;
+ }
+ assertEquals("wrong context in hook", testContext, context); //$NON-NLS-1$
+ assertEquals("wrong name in hook", Runnable.class.getName(), name); //$NON-NLS-1$
+ assertEquals("wrong filter in hook", "(name=" + testMethodName + ")", filter); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
+ assertEquals("wrong allservices in hook", false, allServices); //$NON-NLS-1$
+ assertEquals("wrong number of services in hook", 2, references.size()); //$NON-NLS-1$
+ Iterator iter = references.iterator();
+ while (iter.hasNext()) {
+ ServiceReference ref = (ServiceReference) iter.next();
+ if (ref.equals(reg1.getReference())) {
+ iter.remove();
+ }
+ if (ref.equals(reg2.getReference())) {
+ fail("service 2 is present"); //$NON-NLS-1$
+ }
+ }
+
+ try {
+ references.add(reg2.getReference());
+ fail("add to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ try {
+ references.addAll(Arrays.asList(new ServiceReference[] {reg2.getReference()}));
+ fail("addAll to collection succeeded"); //$NON-NLS-1$
+ } catch (Exception e) {
+ // should get an exception
+ }
+ } catch (AssertionFailedError a) {
+ hookError[3] = a;
+ return;
+ }
+ }
+ }, props);
+
+ // get reference and hook removes some services
+ try {
+ ServiceReference[] refs = null;
+ try {
+ refs = testContext.getServiceReferences(Runnable.class.getName(), "(name=" + testMethodName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (InvalidSyntaxException e) {
+ fail("Unexpected syntax error", e); //$NON-NLS-1$
+ }
+ assertEquals("all hooks not called", 4, hookCalled[0]); //$NON-NLS-1$
+ assertEquals("hook 2 not called first", 2, hookCalled[1]); //$NON-NLS-1$
+ assertEquals("hook 3 not called second", 3, hookCalled[2]); //$NON-NLS-1$
+ assertEquals("hook 4 not called third", 4, hookCalled[3]); //$NON-NLS-1$
+ assertEquals("hook 1 not called fourth ", 1, hookCalled[4]); //$NON-NLS-1$
+ for (int i = 0; i < hookError.length; i++) {
+ if (hookError[i] != null) {
+ throw hookError[i];
+ }
+ }
+ assertNotNull("service refs is null", refs); //$NON-NLS-1$
+ assertEquals("Wrong number of references", 1, refs.length); //$NON-NLS-1$
+
+ // test removed services are not in the result
+ List refList = Arrays.asList(refs);
+ assertFalse("contains service 1", refList.contains(reg1.getReference())); //$NON-NLS-1$
+ assertFalse("contains service 2", refList.contains(reg2.getReference())); //$NON-NLS-1$
+ assertTrue("missing service 3", refList.contains(reg3.getReference())); //$NON-NLS-1$
+
+ // remove the hooks
+ regHook1.unregister();
+ regHook1 = null;
+ regHook2.unregister();
+ regHook2 = null;
+ regHook3.unregister();
+ regHook3 = null;
+ regHook4.unregister();
+ regHook4 = null;
+
+ // get services and make sure none are filtered
+ refs = null;
+ hookCalled[0] = 0;
+
+ try {
+ refs = testContext.getServiceReferences(Runnable.class.getName(), "(name=" + testMethodName + ")"); //$NON-NLS-1$ //$NON-NLS-2$
+ } catch (InvalidSyntaxException e) {
+ fail("Unexpected syntax error", e); //$NON-NLS-1$
+ }
+ assertEquals("hooks called", 0, hookCalled[0]); //$NON-NLS-1$
+ assertNotNull("service refs is null", refs); //$NON-NLS-1$
+ assertEquals("Wrong number of references", 3, refs.length); //$NON-NLS-1$
+
+ // test result contains all expected services
+ refList = Arrays.asList(refs);
+ assertTrue("missing service 1", refList.contains(reg1.getReference())); //$NON-NLS-1$
+ assertTrue("missing service 2", refList.contains(reg2.getReference())); //$NON-NLS-1$
+ assertTrue("missing service 3", refList.contains(reg3.getReference())); //$NON-NLS-1$
+ } finally {
+ // unregister hook and services
+ if (regHook1 != null)
+ regHook1.unregister();
+ if (regHook2 != null)
+ regHook2.unregister();
+ if (regHook3 != null)
+ regHook3.unregister();
+ if (regHook4 != null)
+ regHook4.unregister();
+ if (reg1 != null)
+ reg1.unregister();
+ if (reg2 != null)
+ reg2.unregister();
+ if (reg3 != null)
+ reg3.unregister();
+ }
+ }
+
private void clearResults(boolean[] results) {
for (int i = 0; i < results.length; i++)
results[i] = false;
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java
index d401374f4..76b4c0a4c 100644
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/framework/internal/core/Framework.java
@@ -210,7 +210,7 @@ public class Framework implements EventDispatcher, EventPublisher, Runnable {
if (Profile.PROFILE && Profile.STARTUP)
Profile.logTime("Framework.initialze()", "done new EventManager"); //$NON-NLS-1$ //$NON-NLS-2$
/* create the service registry */
- serviceRegistry = new ServiceRegistry();
+ serviceRegistry = new ServiceRegistry(this);
// Initialize the installLock; there is no way of knowing
// what the initial size should be, at most it will be the number
// of threads trying to install a bundle (probably a very low number).
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceReferenceImpl.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceReferenceImpl.java
index 954e94b2f..345924288 100755
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceReferenceImpl.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceReferenceImpl.java
@@ -188,7 +188,7 @@ public class ServiceReferenceImpl implements ServiceReference, Comparable {
* {@link Constants#SERVICE_ID service id} and greater if it has a lower
* service id.
*
- * @param reference The <code>ServiceReference</code> to be compared.
+ * @param object The <code>ServiceReference</code> to be compared.
* @return Returns a negative integer, zero, or a positive integer if this
* <code>ServiceReference</code> is less than, equal to, or
* greater than the specified <code>ServiceReference</code>.
@@ -196,9 +196,7 @@ public class ServiceReferenceImpl implements ServiceReference, Comparable {
*/
public int compareTo(Object object) {
ServiceReferenceImpl other = (ServiceReferenceImpl) object;
- if (this.getRanking() != other.getRanking())
- return this.getRanking() > other.getRanking() ? -1 : 1;
- return this.getId() == other.getId() ? 0 : this.getId() > other.getId() ? 1 : -1;
+ return registration.compareTo(other.registration);
}
/**
@@ -219,11 +217,11 @@ public class ServiceReferenceImpl implements ServiceReference, Comparable {
*/
public boolean equals(Object obj) {
if (obj == this) {
- return (true);
+ return true;
}
if (!(obj instanceof ServiceReferenceImpl)) {
- return (false);
+ return false;
}
ServiceReferenceImpl other = (ServiceReferenceImpl) obj;
@@ -257,22 +255,4 @@ public class ServiceReferenceImpl implements ServiceReference, Comparable {
String[] getClasses() {
return registration.getClasses();
}
-
- /**
- * Return the service id of the ServiceRegistration.
- *
- * @return service.id of the service
- */
- long getId() {
- return registration.getId();
- }
-
- /**
- * Return the service ranking of the ServiceRegistration.
- *
- * @return service.ranking of the service
- */
- int getRanking() {
- return registration.getRanking();
- }
}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java
index 7a8db27f8..58e1a6f14 100755
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistrationImpl.java
@@ -34,7 +34,7 @@ import org.osgi.framework.Constants;
*
* @ThreadSafe
*/
-public class ServiceRegistrationImpl implements ServiceRegistration {
+public class ServiceRegistrationImpl implements ServiceRegistration, Comparable {
/** Internal framework object. */
private final Framework framework;
@@ -56,17 +56,18 @@ public class ServiceRegistrationImpl implements ServiceRegistration {
/* @GuardedBy("registrationLock") */
private ServiceReferenceImpl reference;
- /** list of contexts using the service. */
+ /** List of contexts using the service.
+ * List&lt;BundleContextImpl&gt;.
+ * */
/* @GuardedBy("registrationLock") */
- private ArrayList contextsUsing;
+ private List contextsUsing;
/** properties for this registration. */
/* @GuardedBy("registrationLock") */
private ServiceProperties properties;
/** service id. */
- /* @GuardedBy("registrationLock") */
- private long serviceid;
+ private final long serviceid;
/** service ranking. */
/* @GuardedBy("registrationLock") */
@@ -94,7 +95,9 @@ public class ServiceRegistrationImpl implements ServiceRegistration {
this.framework = context.getFramework();
this.clazzes = clazzes; /* must be set before calling createProperties. */
this.service = service;
+
synchronized (registrationLock) {
+ this.serviceid = registry.getNextServiceId(); /* must be set before calling createProperties. */
this.contextsUsing = null;
/* We leak this from the constructor here, but it is ok
* because the ServiceReferenceImpl constructor only
@@ -114,7 +117,6 @@ public class ServiceRegistrationImpl implements ServiceRegistration {
context.checkValid();
synchronized (registrationLock) {
ref = reference; /* used to publish event outside sync */
- serviceid = registry.getNextServiceId(); /* must be set before calling createProperties. */
this.properties = createProperties(props); /* must be valid after unregister is called. */
}
if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
@@ -347,9 +349,7 @@ public class ServiceRegistrationImpl implements ServiceRegistration {
* @return The service id for this service.
*/
long getId() {
- synchronized (registrationLock) {
- return serviceid;
- }
+ return serviceid;
}
/**
@@ -366,7 +366,7 @@ public class ServiceRegistrationImpl implements ServiceRegistration {
return clazzes;
}
- Object getService() {
+ Object getServiceObject() {
return service;
}
@@ -596,4 +596,36 @@ public class ServiceRegistrationImpl implements ServiceRegistration {
return sb.toString();
}
+
+ /**
+ * Compares this <code>ServiceRegistrationImpl</code> with the specified
+ * <code>ServiceRegistrationImpl</code> for order.
+ *
+ * <p>
+ * If this <code>ServiceRegistrationImpl</code> and the specified
+ * <code>ServiceRegistrationImpl</code> have the same
+ * {@link Constants#SERVICE_ID service id} they are equal. This
+ * <code>ServiceRegistrationImpl</code> is less than the specified
+ * <code>ServiceRegistrationImpl</code> if it has a lower
+ * {@link Constants#SERVICE_RANKING service ranking} and greater if it has a
+ * higher service ranking. Otherwise, if this <code>ServiceRegistrationImpl</code>
+ * and the specified <code>ServiceRegistrationImpl</code> have the same
+ * {@link Constants#SERVICE_RANKING service ranking}, this
+ * <code>ServiceRegistrationImpl</code> is less than the specified
+ * <code>ServiceRegistrationImpl</code> if it has a higher
+ * {@link Constants#SERVICE_ID service id} and greater if it has a lower
+ * service id.
+ *
+ * @param object The <code>ServiceRegistrationImpl</code> to be compared.
+ * @return Returns a negative integer, zero, or a positive integer if this
+ * <code>ServiceRegistrationImpl</code> is less than, equal to, or
+ * greater than the specified <code>ServiceRegistrationImpl</code>.
+ */
+ public int compareTo(Object object) {
+ ServiceRegistrationImpl other = (ServiceRegistrationImpl) object;
+
+ if (this.getRanking() != other.getRanking())
+ return this.getRanking() > other.getRanking() ? -1 : 1;
+ return this.getId() == other.getId() ? 0 : this.getId() > other.getId() ? 1 : -1;
+ }
}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java
index d159302d4..33bdad7d9 100755
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceRegistry.java
@@ -18,6 +18,7 @@ import org.eclipse.osgi.framework.internal.core.*;
import org.eclipse.osgi.util.NLS;
import org.osgi.framework.*;
import org.osgi.framework.Constants;
+import org.osgi.framework.hooks.service.FindHook;
/**
* The Service Registry. This class is the main control point for service
@@ -29,26 +30,39 @@ public class ServiceRegistry {
public static final String PROP_SCOPE_SERVICE_EVENTS = "osgi.scopeServiceEvents"; //$NON-NLS-1$
public static final boolean scopeEvents = Boolean.valueOf(FrameworkProperties.getProperty(PROP_SCOPE_SERVICE_EVENTS, "true")).booleanValue(); //$NON-NLS-1$
- /** Published services by class name. Key is a String class name; Value is a ArrayList of ServiceRegistrations */
+ /** Published services by class name.
+ * Map&lt;String,List&lt;ServiceRegistrationImpl&gt;&gt;
+ * The List&lt;ServiceRegistrationImpl&gt;s are sorted.
+ */
/* @GuardedBy("this") */
- private final HashMap/*<String,ArrayList<ServiceRegistrationImpl>>*/publishedServicesByClass;
- /** All published services. Value is ServiceRegistrations */
+ private final Map/*<String,List<ServiceRegistrationImpl>>*/publishedServicesByClass;
+ /** All published services.
+ * List&lt;ServiceRegistrationImpl&gt;.
+ * The List&lt;ServiceRegistrationImpl&gt; is sorted.
+ */
/* @GuardedBy("this") */
- private final ArrayList/*<ServiceRegistrationImpl>*/allPublishedServices;
- /** Published services by BundleContext. Key is a BundleContext; Value is a ArrayList of ServiceRegistrations*/
+ private final List/*<ServiceRegistrationImpl>*/allPublishedServices;
+ /** Published services by BundleContextImpl.
+ * Map&lt;BundleContextImpl,List&lt;ServiceRegistrationImpl&gt;&gt;.
+ * The List&lt;ServiceRegistrationImpl&gt;s are NOT sorted.
+ */
/* @GuardedBy("this") */
- private final HashMap/*<BundleContextImpl,ArrayList<ServiceRegistrationImpl>*/publishedServicesByContext;
+ private final Map/*<BundleContextImpl,List<ServiceRegistrationImpl>>*/publishedServicesByContext;
/** next free service id. */
/* @GuardedBy("this") */
private long serviceid;
/** initial capacity of the data structure */
private static final int initialCapacity = 50;
+ /** framework which created this service registry */
+ private final Framework framework;
+
/**
* Initializes the internal data structures of this ServiceRegistry.
*
*/
- public ServiceRegistry() {
+ public ServiceRegistry(Framework framework) {
+ this.framework = framework;
serviceid = 1;
publishedServicesByClass = new HashMap(initialCapacity);
publishedServicesByContext = new HashMap(initialCapacity);
@@ -58,8 +72,8 @@ public class ServiceRegistry {
/**
* Registers the specified service object with the specified properties
* under the specified class names into the Framework. A
- * <code>ServiceRegistration</code> object is returned. The
- * <code>ServiceRegistration</code> object is for the private use of the
+ * <code>ServiceRegistrationImpl</code> object is returned. The
+ * <code>ServiceRegistrationImpl</code> object is for the private use of the
* bundle registering the service and should not be shared with other
* bundles. The registering bundle is defined to be the context bundle.
* Other bundles can locate the service by using either the
@@ -106,7 +120,7 @@ public class ServiceRegistry {
* The set of properties may be <code>null</code> if the service
* has no properties.
*
- * @return A <code>ServiceRegistration</code> object for use by the bundle
+ * @return A <code>ServiceRegistrationImpl</code> object for use by the bundle
* registering the service to update the service's properties or to
* unregister the service.
*
@@ -174,12 +188,11 @@ public class ServiceRegistry {
ServiceRegistrationImpl registration = new ServiceRegistrationImpl(this, context, clazzes, service);
registration.register(properties);
return registration;
-
}
/**
- * Returns an array of <code>ServiceReference</code> objects. The returned
- * array of <code>ServiceReference</code> objects contains services that
+ * Returns an array of <code>ServiceReferenceImpl</code> objects. The returned
+ * array of <code>ServiceReferenceImpl</code> objects contains services that
* were registered under the specified class, match the specified filter
* criteria, and the packages for the class names under which the services
* were registered match the context bundle's packages as defined in
@@ -203,19 +216,19 @@ public class ServiceRegistry {
*
* <p>
* The following steps are required to select a set of
- * <code>ServiceReference</code> objects:
+ * <code>ServiceReferenceImpl</code> objects:
* <ol>
* <li>If the filter string is not <code>null</code>, the filter string
- * is parsed and the set <code>ServiceReference</code> objects of
+ * is parsed and the set <code>ServiceReferenceImpl</code> objects of
* registered services that satisfy the filter is produced. If the filter
* string is <code>null</code>, then all registered services are
* considered to satisfy the filter.
* <li>If the Java Runtime Environment supports permissions, the set of
- * <code>ServiceReference</code> objects produced by the previous step is
+ * <code>ServiceReferenceImpl</code> objects produced by the previous step is
* reduced by checking that the caller has the
* <code>ServicePermission</code> to get at least one of the class names
* under which the service was registered. If the caller does not have the
- * correct permission for a particular <code>ServiceReference</code>
+ * correct permission for a particular <code>ServiceReferenceImpl</code>
* object, then it is removed from the set.
* <li>If <code>clazz</code> is not <code>null</code>, the set is
* further reduced to those services that are an <code>instanceof</code>
@@ -227,12 +240,12 @@ public class ServiceRegistry {
* <code>ServiceReference</code> object and calling
* {@link ServiceReference#isAssignableTo(Bundle, String)} with the context
* bundle and each class name under which the <code>ServiceReference</code>
- * object was registered. For any given <code>ServiceReference</code>
+ * object was registered. For any given <code>ServiceReferenceImpl</code>
* object, if any call to
* {@link ServiceReference#isAssignableTo(Bundle, String)} returns
* <code>false</code>, then it is removed from the set of
- * <code>ServiceReference</code> objects.
- * <li>An array of the remaining <code>ServiceReference</code> objects is
+ * <code>ServiceReferenceImpl</code> objects.
+ * <li>An array of the remaining <code>ServiceReferenceImpl</code> objects is
* returned.
* </ol>
*
@@ -241,7 +254,7 @@ public class ServiceRegistry {
* <code>null</code> for all services.
* @param filterstring The filter criteria.
* @param allservices True if the bundle called getAllServiceReferences.
- * @return An array of <code>ServiceReference</code> objects or
+ * @return An array of <code>ServiceReferenceImpl</code> objects or
* <code>null</code> if no services are registered which satisfy
* the search.
* @throws InvalidSyntaxException If <code>filter</code> contains an
@@ -261,9 +274,9 @@ public class ServiceRegistry {
}
}
Filter filter = (filterstring == null) ? null : context.createFilter(filterstring);
- List references = null;
+ List references;
synchronized (this) {
- references = lookupServiceReferences(clazz, filter);
+ references = changeRegistrationsToReferences(lookupServiceRegistrations(clazz, filter));
Iterator iter = references.iterator();
while (iter.hasNext()) {
ServiceReferenceImpl reference = (ServiceReferenceImpl) iter.next();
@@ -281,6 +294,8 @@ public class ServiceRegistry {
}
}
+ processFindHooks(context, clazz, filterstring, allservices, references);
+
int size = references.size();
if (size == 0) {
return null;
@@ -328,48 +343,9 @@ public class ServiceRegistry {
ServiceReferenceImpl[] references = getServiceReferences(context, clazz, null, false);
if (references != null) {
- int index = 0;
-
- int length = references.length;
-
- if (length > 1) /* if more than one service, select highest ranking */{
- int rankings[] = new int[length];
- int count = 0;
- int maxRanking = Integer.MIN_VALUE;
-
- for (int i = 0; i < length; i++) {
- int ranking = references[i].getRanking();
-
- rankings[i] = ranking;
-
- if (ranking > maxRanking) {
- index = i;
- maxRanking = ranking;
- count = 1;
- } else {
- if (ranking == maxRanking) {
- count++;
- }
- }
- }
-
- if (count > 1) /* if still more than one service, select lowest id */{
- long minId = Long.MAX_VALUE;
-
- for (int i = 0; i < length; i++) {
- if (rankings[i] == maxRanking) {
- long id = references[i].getId();
-
- if (id < minId) {
- index = i;
- minId = id;
- }
- }
- }
- }
- }
-
- return references[index];
+ // Since we maintain the registrations in a sorted List, the first element is always the
+ // correct one to return.
+ return references[0];
}
} catch (InvalidSyntaxException e) {
if (Debug.DEBUG && Debug.DEBUG_GENERAL) {
@@ -517,7 +493,7 @@ public class ServiceRegistry {
* @see ServicePermission
*/
public synchronized ServiceReferenceImpl[] getRegisteredServices(BundleContextImpl context) {
- List references = lookupServiceReferences(context);
+ List references = changeRegistrationsToReferences(lookupServiceRegistrations(context));
ListIterator iter = references.listIterator();
while (iter.hasNext()) {
ServiceReferenceImpl reference = (ServiceReferenceImpl) iter.next();
@@ -678,33 +654,39 @@ public class ServiceRegistry {
*/
/* @GuardedBy("this") */
void addServiceRegistration(BundleContextImpl context, ServiceRegistrationImpl registration) {
- // Add the ServiceRegistration to the list of Services published by BundleContext.
- ArrayList contextServices = (ArrayList) publishedServicesByContext.get(context);
+ // Add the ServiceRegistrationImpl to the list of Services published by BundleContextImpl.
+ List contextServices = (List) publishedServicesByContext.get(context);
if (contextServices == null) {
contextServices = new ArrayList(10);
publishedServicesByContext.put(context, contextServices);
}
+ // The list is NOT sorted, so we just add
contextServices.add(registration);
- // Add the ServiceRegistration to the list of Services published by Class Name.
+ // Add the ServiceRegistrationImpl to the list of Services published by Class Name.
String[] clazzes = registration.getClasses();
int size = clazzes.length;
+ int insertIndex;
for (int i = 0; i < size; i++) {
String clazz = clazzes[i];
- ArrayList services = (ArrayList) publishedServicesByClass.get(clazz);
+ List services = (List) publishedServicesByClass.get(clazz);
if (services == null) {
services = new ArrayList(10);
publishedServicesByClass.put(clazz, services);
}
- services.add(registration);
+ // The list is sorted, so we must find the proper location to insert
+ insertIndex = -Collections.binarySearch(services, registration) - 1;
+ services.add(insertIndex, registration);
}
- // Add the ServiceRegistration to the list of all published Services.
- allPublishedServices.add(registration);
+ // Add the ServiceRegistrationImpl to the list of all published Services.
+ // The list is sorted, so we must find the proper location to insert
+ insertIndex = -Collections.binarySearch(allPublishedServices, registration) - 1;
+ allPublishedServices.add(insertIndex, registration);
}
/**
@@ -715,55 +697,58 @@ public class ServiceRegistry {
*/
/* @GuardedBy("this") */
void removeServiceRegistration(BundleContextImpl context, ServiceRegistrationImpl serviceReg) {
- // Remove the ServiceRegistration from the list of Services published by BundleContext.
- ArrayList contextServices = (ArrayList) publishedServicesByContext.get(context);
+ // Remove the ServiceRegistrationImpl from the list of Services published by BundleContextImpl.
+ List contextServices = (List) publishedServicesByContext.get(context);
if (contextServices != null) {
contextServices.remove(serviceReg);
}
- // Remove the ServiceRegistration from the list of Services published by Class Name.
+ // Remove the ServiceRegistrationImpl from the list of Services published by Class Name.
String[] clazzes = serviceReg.getClasses();
int size = clazzes.length;
for (int i = 0; i < size; i++) {
String clazz = clazzes[i];
- ArrayList services = (ArrayList) publishedServicesByClass.get(clazz);
+ List services = (List) publishedServicesByClass.get(clazz);
services.remove(serviceReg);
}
- // Remove the ServiceRegistration from the list of all published Services.
+ // Remove the ServiceRegistrationImpl from the list of all published Services.
allPublishedServices.remove(serviceReg);
}
/**
- * Lookup Service References in the data structure by class name and filter.
+ * Lookup Service Registrations in the data structure by class name and filter.
*
* @param clazz The class name with which the service was registered or
* <code>null</code> for all services.
* @param filter The filter criteria.
+ * @return List<ServiceRegistrationImpl>
*/
/* @GuardedBy("this") */
- private List lookupServiceReferences(String clazz, Filter filter) {
- ArrayList result;
+ private List lookupServiceRegistrations(String clazz, Filter filter) {
+ List result;
if (clazz == null) { /* all services */
result = allPublishedServices;
} else {
/* services registered under the class name */
- result = (ArrayList) publishedServicesByClass.get(clazz);
- if (result == null) {
- return Collections.EMPTY_LIST;
- }
+ result = (List) publishedServicesByClass.get(clazz);
+ }
+
+ if ((result == null) || (result.size() == 0)) {
+ return Collections.EMPTY_LIST;
}
result = new ArrayList(result); /* make a new list since we don't want to change the real list */
+ if (filter == null) {
+ return result;
+ }
+
ListIterator iter = result.listIterator();
while (iter.hasNext()) {
ServiceRegistrationImpl registration = (ServiceRegistrationImpl) iter.next();
- ServiceReferenceImpl reference = registration.getReferenceImpl();
- if ((filter == null) || filter.match(reference)) {
- iter.set(reference); /* replace the registration with its reference */
- } else {
+ if (!filter.match(registration.getReferenceImpl())) {
iter.remove();
}
}
@@ -774,33 +759,30 @@ public class ServiceRegistry {
* Lookup Service Registrations in the data structure by BundleContext.
*
* @param context The BundleContext for which to return Service Registrations.
+ * @return List<ServiceRegistrationImpl>
*/
/* @GuardedBy("this") */
private List lookupServiceRegistrations(BundleContextImpl context) {
- ArrayList result = (ArrayList) publishedServicesByContext.get(context);
+ List result = (List) publishedServicesByContext.get(context);
- if (result == null) {
+ if ((result == null) || (result.size() == 0)) {
return Collections.EMPTY_LIST;
}
- result = new ArrayList(result); /* make a new list since we don't want to change the real list */
- return result;
+ return new ArrayList(result); /* make a new list since we don't want to change the real list */
}
/**
- * Lookup Service References in the data structure by BundleContext.
+ * Modify a List<ServiceRegistrationImpl> to a List<ServiceReferenceImpl>.
*
- * @param context The BundleContext for which to return Service References.
+ * @param result The input List<ServiceRegistrationImpl>.
+ * @return List<ServiceReferenceImpl>
*/
- /* @GuardedBy("this") */
- private List lookupServiceReferences(BundleContextImpl context) {
- List result = lookupServiceRegistrations(context);
-
+ private static List changeRegistrationsToReferences(List result) {
ListIterator iter = result.listIterator();
while (iter.hasNext()) {
ServiceRegistrationImpl registration = (ServiceRegistrationImpl) iter.next();
- ServiceReferenceImpl reference = registration.getReferenceImpl();
- iter.set(reference); /* replace the registration with its reference */
+ iter.set(registration.getReferenceImpl()); /* replace the registration with its reference */
}
return result;
}
@@ -923,4 +905,61 @@ public class ServiceRegistry {
return false;
return true;
}
+
+ private static final String findHookName = FindHook.class.getName();
+
+ /**
+ * Call the registered FindHook services to allow them to inspect and possibly shrink the result.
+ * The FindHook must be called in order: descending by service.ranking, then ascending by service.id.
+ * This is the natural order for ServiceReference.
+ *
+ * @param context The context of the bundle getting the service references.
+ * @param clazz The class name used to search for the service references.
+ * @param filterstring The filter used to search for the service references.
+ * @param allservices True if getAllServiceReferences called.
+ * @param result The result to return to the caller which may have been shrunk by the FindHooks.
+ */
+ private void processFindHooks(BundleContextImpl context, String clazz, String filterstring, boolean allservices, Collection result) {
+ BundleContextImpl systemBundleContext = framework.getSystemBundleContext();
+ if (systemBundleContext == null) { // if no system bundle context, we are done!
+ return;
+ }
+
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
+ Debug.println("processFindHook(" + context.getBundleImpl() + "," + clazz + "," + filterstring + "," + allservices + "," + result + ")"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$ //$NON-NLS-6$
+ }
+
+ Collection references = new ShrinkableCollection(result); // prevent hooks from adding to result
+ List hooks;
+ synchronized (this) {
+ hooks = lookupServiceRegistrations(findHookName, null);
+ }
+ // Since the list is already sorted, we don't need to sort the list to call the hooks
+ // in the proper order.
+
+ Iterator iter = hooks.iterator();
+ while (iter.hasNext()) {
+ ServiceRegistrationImpl registration = (ServiceRegistrationImpl) iter.next();
+ Object findHook = registration.getService(systemBundleContext);
+ if (findHook == null) { // if the hook is null
+ continue;
+ }
+ try {
+ if (findHook instanceof FindHook) { // if the hook is usable
+ ((FindHook) findHook).find(context, clazz, filterstring, allservices, references);
+ }
+ } catch (Throwable t) {
+ if (Debug.DEBUG && Debug.DEBUG_SERVICES) {
+ Debug.println(findHook + ".find() exception: " + t.getMessage()); //$NON-NLS-1$
+ Debug.printStackTrace(t);
+ }
+ // allow the adaptor to handle this unexpected error
+ framework.getAdaptor().handleRuntimeError(t);
+ ServiceException se = new ServiceException(NLS.bind(Msg.SERVICE_FACTORY_EXCEPTION, findHook.getClass().getName(), "find"), t); //$NON-NLS-1$
+ framework.publishFrameworkEvent(FrameworkEvent.ERROR, registration.getBundle(), se);
+ } finally {
+ registration.ungetService(systemBundleContext);
+ }
+ }
+ }
}
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceUse.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceUse.java
index 8e297527f..b67baf9b4 100755
--- a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceUse.java
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ServiceUse.java
@@ -56,7 +56,7 @@ public class ServiceUse {
*/
ServiceUse(BundleContextImpl context, ServiceRegistrationImpl registration) {
this.useCount = 0;
- Object service = registration.getService();
+ Object service = registration.getServiceObject();
if (service instanceof ServiceFactory) {
this.factory = (ServiceFactory) service;
this.cachedService = null;
diff --git a/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ShrinkableCollection.java b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ShrinkableCollection.java
new file mode 100644
index 000000000..cbc70ec7e
--- /dev/null
+++ b/bundles/org.eclipse.osgi/core/framework/org/eclipse/osgi/internal/serviceregistry/ShrinkableCollection.java
@@ -0,0 +1,90 @@
+/*******************************************************************************
+ * Copyright (c) 2008 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+
+package org.eclipse.osgi.internal.serviceregistry;
+
+import java.util.Collection;
+import java.util.Iterator;
+
+/**
+ * A Shrinkable Collection. This class provides a wrapper for a collection
+ * that allows items to be removed from the wrapped collection (shrinking) but
+ * does not allow items to be added to the wrapped collection.
+ *
+ * <p>
+ * All the optional <code>Collection</code> operations except
+ * <code>add</code> and <code>addAll</code> are supported. Attempting to add to the
+ * collection will result in an <code>UnsupportedOperationException</code>.
+ *
+ */
+
+public class ShrinkableCollection implements Collection {
+ private final Collection collection;
+
+ ShrinkableCollection(Collection c) {
+ if (c == null) {
+ throw new NullPointerException();
+ }
+ collection = c;
+ }
+
+ public boolean add(Object var0) {
+ throw new UnsupportedOperationException();
+ }
+
+ public boolean addAll(Collection var0) {
+ throw new UnsupportedOperationException();
+ }
+
+ public void clear() {
+ collection.clear();
+ }
+
+ public boolean contains(Object var0) {
+ return collection.contains(var0);
+ }
+
+ public boolean containsAll(Collection var0) {
+ return collection.containsAll(var0);
+ }
+
+ public boolean isEmpty() {
+ return collection.isEmpty();
+ }
+
+ public Iterator iterator() {
+ return collection.iterator();
+ }
+
+ public boolean remove(Object var0) {
+ return collection.remove(var0);
+ }
+
+ public boolean removeAll(Collection var0) {
+ return collection.removeAll(var0);
+ }
+
+ public boolean retainAll(Collection var0) {
+ return collection.retainAll(var0);
+ }
+
+ public int size() {
+ return collection.size();
+ }
+
+ public Object[] toArray() {
+ return collection.toArray();
+ }
+
+ public Object[] toArray(Object[] var0) {
+ return collection.toArray(var0);
+ }
+}

Back to the top