Modify service registry to use a CapabilitySet for indexed service
lookup. (FELIX-2040)
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@927304 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/framework/src/main/java/org/apache/felix/framework/Felix.java b/framework/src/main/java/org/apache/felix/framework/Felix.java
index 0b6fee7..4c70fa2 100644
--- a/framework/src/main/java/org/apache/felix/framework/Felix.java
+++ b/framework/src/main/java/org/apache/felix/framework/Felix.java
@@ -34,6 +34,7 @@
import org.apache.felix.framework.capabilityset.Directive;
import org.apache.felix.framework.resolver.Module;
import org.apache.felix.framework.capabilityset.Requirement;
+import org.apache.felix.framework.capabilityset.SimpleFilter;
import org.apache.felix.framework.resolver.Wire;
import org.apache.felix.framework.ext.SecurityProvider;
import org.apache.felix.framework.resolver.ResolveException;
@@ -2848,10 +2849,17 @@
throws InvalidSyntaxException
{
// Define filter if expression is not null.
- Filter filter = null;
+ SimpleFilter filter = null;
if (expr != null)
{
- filter = FrameworkUtil.createFilter(expr);
+ try
+ {
+ filter = SimpleFilter.parse(expr);
+ }
+ catch (Exception ex)
+ {
+ throw new InvalidSyntaxException(ex.getMessage(), expr);
+ }
}
// Ask the service registry for all matching service references.
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
index 8cd05e2..f17acb6 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistrationImpl.java
@@ -22,6 +22,9 @@
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.*;
+import org.apache.felix.framework.capabilityset.Attribute;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.Directive;
import org.apache.felix.framework.resolver.Module;
import org.apache.felix.framework.resolver.Wire;
@@ -69,9 +72,6 @@
// This reference is the "standard" reference for this
// service and will always be returned by getReference().
- // Since all reference to this service are supposed to
- // be equal, we use the hashcode of this reference for
- // a references to this service in ServiceReference.
m_ref = new ServiceReferenceImpl();
}
@@ -164,7 +164,8 @@
// Case 2.
if ((m_factory != null)
&& (m_factory.getClass().getClassLoader() instanceof BundleReference)
- && !((BundleReference) m_factory.getClass().getClassLoader()).getBundle().equals(m_bundle))
+ && !((BundleReference) m_factory.getClass()
+ .getClassLoader()).getBundle().equals(m_bundle))
{
return true;
}
@@ -315,7 +316,8 @@
{
for (int i = 0; i < m_classes.length; i++)
{
- Class clazz = Util.loadClassUsingClass(svcObj.getClass(), m_classes[i], Felix.m_secureAction);
+ Class clazz = Util.loadClassUsingClass(
+ svcObj.getClass(), m_classes[i], Felix.m_secureAction);
if ((clazz == null) || !clazz.isAssignableFrom(svcObj.getClass()))
{
if (clazz == null)
@@ -376,7 +378,11 @@
}
}
- class ServiceReferenceImpl implements ServiceReference
+ //
+ // ServiceReference implementation
+ //
+
+ class ServiceReferenceImpl implements ServiceReference, Capability
{
private ServiceReferenceImpl() {}
@@ -385,6 +391,46 @@
return ServiceRegistrationImpl.this;
}
+ //
+ // Capability methods.
+ //
+
+ public Module getModule()
+ {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ public String getNamespace()
+ {
+ return "service-reference";
+ }
+
+ public Directive getDirective(String name)
+ {
+ return null;
+ }
+
+ public List<Directive> getDirectives()
+ {
+ return Collections.emptyList();
+ }
+
+ public Attribute getAttribute(String name)
+ {
+ Object value = ServiceRegistrationImpl.this.getProperty(name);
+ return (value == null) ? null : new Attribute(name, value, false);
+ }
+
+ public List<Attribute> getAttributes()
+ {
+ return Collections.emptyList();
+ }
+
+ public List<String> getUses()
+ {
+ return Collections.emptyList();
+ }
+
public Object getProperty(String s)
{
return ServiceRegistrationImpl.this.getProperty(s);
diff --git a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
index f1ba5fc..758d1df 100644
--- a/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
+++ b/framework/src/main/java/org/apache/felix/framework/ServiceRegistry.java
@@ -19,8 +19,10 @@
package org.apache.felix.framework;
import java.util.*;
+import org.apache.felix.framework.capabilityset.Capability;
+import org.apache.felix.framework.capabilityset.CapabilitySet;
+import org.apache.felix.framework.capabilityset.SimpleFilter;
-import org.apache.felix.framework.util.FelixConstants;
import org.osgi.framework.*;
import org.osgi.framework.hooks.service.*;
import org.osgi.framework.launch.Framework;
@@ -30,13 +32,16 @@
private final Logger m_logger;
private long m_currentServiceId = 1L;
// Maps bundle to an array of service registrations.
- private final Map m_serviceRegsMap = Collections.synchronizedMap(new HashMap());
+ private final Map m_regsMap = Collections.synchronizedMap(new HashMap());
+ // Capability set for all service registrations.
+ private final CapabilitySet m_regCapSet;
+
// Maps registration to thread to keep track when a
// registration is in use, which will cause other
// threads to wait.
- private Map m_lockedRegsMap = new HashMap();
+ private final Map m_lockedRegsMap = new HashMap();
// Maps bundle to an array of usage counts.
- private Map m_inUseMap = new HashMap();
+ private final Map m_inUseMap = new HashMap();
private final ServiceRegistryCallbacks m_callbacks;
@@ -48,11 +53,15 @@
{
m_logger = logger;
m_callbacks = callbacks;
+
+ List indices = new ArrayList();
+ indices.add(Constants.OBJECTCLASS);
+ m_regCapSet = new CapabilitySet(indices);
}
public ServiceReference[] getRegisteredServices(Bundle bundle)
{
- ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
+ ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
if (regs != null)
{
List refs = new ArrayList(regs.length);
@@ -75,7 +84,7 @@
public ServiceRegistration registerService(
Bundle bundle, String[] classNames, Object svcObj, Dictionary dict)
{
- ServiceRegistration reg = null;
+ ServiceRegistrationImpl reg = null;
synchronized (this)
{
@@ -87,8 +96,9 @@
addHooks(classNames, svcObj, reg.getReference());
// Get the bundles current registered services.
- ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
- m_serviceRegsMap.put(bundle, addServiceRegistration(regs, reg));
+ ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+ m_regsMap.put(bundle, addServiceRegistration(regs, reg));
+ m_regCapSet.addCapability((Capability) reg.getReference());
}
// Notify callback objects about registered service.
@@ -114,8 +124,9 @@
// new bundles will be able to look up the service.
// Now remove the registered service.
- ServiceRegistration[] regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
- m_serviceRegsMap.put(bundle, removeServiceRegistration(regs, reg));
+ ServiceRegistration[] regs = (ServiceRegistration[]) m_regsMap.get(bundle);
+ m_regsMap.put(bundle, removeServiceRegistration(regs, reg));
+ m_regCapSet.removeCapability((Capability) reg.getReference());
}
// Notify callback objects about unregistering service.
@@ -151,7 +162,7 @@
ServiceRegistration[] regs = null;
synchronized (this)
{
- regs = (ServiceRegistration[]) m_serviceRegsMap.get(bundle);
+ regs = (ServiceRegistration[]) m_regsMap.get(bundle);
}
// Note, there is no race condition here with respect to the
@@ -171,73 +182,35 @@
// Now remove the bundle itself.
synchronized (this)
{
- m_serviceRegsMap.remove(bundle);
+ m_regsMap.remove(bundle);
}
}
- public List getServiceReferences(String className, Filter filter)
+ public synchronized List getServiceReferences(String className, SimpleFilter filter)
{
- // Create a filtered list of service references.
- List list = new ArrayList();
-
- Object[] registrations = m_serviceRegsMap.values().toArray();
-
- // Iterator over all service registrations.
- for (int i = 0; i < registrations.length; i++)
+ if ((className == null) && (filter == null))
{
- ServiceRegistration[] regs = (ServiceRegistration[]) registrations[i];
-
- for (int regIdx = 0;
- (regs != null) && (regIdx < regs.length);
- regIdx++)
- {
- try
- {
- // Determine if the registered services matches
- // the search criteria.
- boolean matched = false;
-
- // If className is null, then look at filter only.
- if ((className == null) &&
- ((filter == null) || filter.match(regs[regIdx].getReference())))
- {
- matched = true;
- }
- // If className is not null, then first match the
- // objectClass property before looking at the
- // filter.
- else if (className != null)
- {
- String[] objectClass = (String[])
- ((ServiceRegistrationImpl) regs[regIdx])
- .getProperty(FelixConstants.OBJECTCLASS);
- for (int classIdx = 0;
- classIdx < objectClass.length;
- classIdx++)
- {
- if (objectClass[classIdx].equals(className) &&
- ((filter == null) || filter.match(regs[regIdx].getReference())))
- {
- matched = true;
- break;
- }
- }
- }
-
- // Add reference if it was a match.
- if (matched)
- {
- list.add(regs[regIdx].getReference());
- }
- }
- catch (IllegalStateException ex)
- {
- // Don't include the reference as it is not valid anymore
- }
- }
+ // Return all services.
+ filter = new SimpleFilter(Constants.OBJECTCLASS, "*", SimpleFilter.PRESENT);
}
+ else if ((className != null) && (filter == null))
+ {
+ // Return services matching the class name.
+ filter = new SimpleFilter(Constants.OBJECTCLASS, className, SimpleFilter.EQ);
+ }
+ else if ((className != null) && (filter != null))
+ {
+ // Return services matching the class name and filter.
+ List filters = new ArrayList(2);
+ filters.add(new SimpleFilter(Constants.OBJECTCLASS, className, SimpleFilter.EQ));
+ filters.add(filter);
+ filter = new SimpleFilter(null, filters, SimpleFilter.AND);
+ }
+ // else just use the specified filter.
- return list;
+ Set<Capability> matches = m_regCapSet.match(filter, false);
+
+ return new ArrayList(matches);
}
public synchronized ServiceReference[] getServicesInUse(Bundle bundle)
diff --git a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
index 626f6b1..43ab382 100644
--- a/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
+++ b/framework/src/main/java/org/apache/felix/framework/capabilityset/CapabilitySet.java
@@ -132,10 +132,13 @@
Map<Object, Set<Capability>> index, Capability cap, Object capValue)
{
Set<Capability> caps = index.get(capValue);
- caps.remove(cap);
- if (caps.size() == 0)
+ if (caps != null)
{
- index.remove(capValue);
+ caps.remove(cap);
+ if (caps.size() == 0)
+ {
+ index.remove(capValue);
+ }
}
}