[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[equinox-dev] problem with ServiceTracker.open() and refreshThread in Equinox

I ran into a problem with Equinox 3.5.1.R35x_v20090806:

In my log file I find the following exception stack trace after calling PackageAdmin.refreshPackages(null).

org.osgi.framework.BundleException: Exception in com.tibco.xxx.Activator.start() of bundle com.tibco.xxx.
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:805)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.start(BundleContextImpl.java:754)
at org.eclipse.osgi.framework.internal.core.BundleHost.startWorker(BundleHost.java:352)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:280)
at org.eclipse.osgi.framework.internal.core.AbstractBundle.start(AbstractBundle.java:272)
at com.tibco.xxx.refreshRuntime(xxx.java:872)
at com.tibco.xx.access$6(xxxImpl.java:569)
at com.tibco.xxx$2.run(xxxImpl.java:229)
at java.lang.Thread.run(Thread.java:619)
Caused by: java.lang.IllegalStateException: The service has been unregistered
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistrationImpl.getReferenceImpl(ServiceRegistrationImpl.java:277)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.lookupServiceRegistrations(ServiceRegistry.java:867)
at org.eclipse.osgi.internal.serviceregistry.ServiceRegistry.getServiceReferences(ServiceRegistry.java:290)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.getAllServiceReferences(BundleContextImpl.java:577)
at org.osgi.util.tracker.ServiceTracker.getInitialReferences(ServiceTracker.java:360)
at org.osgi.util.tracker.ServiceTracker.open(ServiceTracker.java:321)
at com.tibco.xxx.start(xxx.java:150)
at com.tibco.xxx.Activator.start(Activator.java:39)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl$1.run(BundleContextImpl.java:782)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.osgi.framework.internal.core.BundleContextImpl.startActivator(BundleContextImpl.java:773)

The exception is thrown while starting a bundle after the refreshPackages call. I assume the refreshThread is still ongoing in the background and as part of the process stops and restarts bundles, which causes OSGi services to be unregistered and then (hopefully) registered again.

The ServiceTracker of the bundle that is started wants to look for all services that have a certain property set. However, during the initial scan of all services, one of them is unregistered, which causes the seen exception.

There seems to be a race condition in which lookupServiceRegistrations() acquires the lock to ServiceRegistry and copies the results to an ArrayList.

private List lookupServiceRegistrations(String clazz, Filter filter) {
List result;
synchronized (this) {
if (clazz == null) { /* all services */
result = allPublishedServices;
} else {
/* services registered under the class name */
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 */
}

In the meantime the service is unregistered and removed from allPublishedServices:

void removeServiceRegistration(BundleContextImpl context, ServiceRegistrationImpl serviceReg) {
// 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 ServiceRegistrationImpl from the list of Services published by Class Name.
String[] clazzes = serviceReg.getClasses();
for (int i = 0, size = clazzes.length; i < size; i++) {
String clazz = clazzes[i];
List services = (List) publishedServicesByClass.get(clazz);
services.remove(serviceReg);
}

// Remove the ServiceRegistrationImpl from the list of all published Services.
allPublishedServices.remove(serviceReg);
}

However, lookupServiceRegistrations() goes on to iterate over the result list and runs into the exception above.

for (Iterator iter = result.iterator(); iter.hasNext();) {
ServiceRegistrationImpl registration = (ServiceRegistrationImpl) iter.next();
if (!filter.match(registration.getReferenceImpl())) {
iter.remove();
}
}


Has anyone seen this? Is this a know problem? I guess I could file a bug for this.

Thanks,

   Tim.

"It is a simple task to make things complex, but a complex task to make them simple."
 -- Fortune Cookie