FELIX-3828 Fixed both the Adapter and the Aspect filter index.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1425276 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AbstractFactoryFilterIndex.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AbstractFactoryFilterIndex.java
new file mode 100644
index 0000000..272f162
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AbstractFactoryFilterIndex.java
@@ -0,0 +1,74 @@
+package org.apache.felix.dm.impl.index;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
+
+import org.apache.felix.dm.ServiceUtil;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+
+public abstract class AbstractFactoryFilterIndex {
+
+ protected final Map /* <Long, SortedSet<ServiceReference>> */ m_sidToServiceReferencesMap = new HashMap();
+ protected final Map /* <ServiceListener, String> */ m_listenerToFilterMap = new HashMap();
+
+ public void addedService(ServiceReference reference, Object service) {
+ add(reference);
+ }
+
+ public void modifiedService(ServiceReference reference, Object service) {
+ modify(reference);
+ }
+
+ public void removedService(ServiceReference reference, Object service) {
+ remove(reference);
+ }
+
+ public void add(ServiceReference reference) {
+ Long sid = ServiceUtil.getServiceIdObject(reference);
+ synchronized (m_sidToServiceReferencesMap) {
+ Set list = (Set) m_sidToServiceReferencesMap.get(sid);
+ if (list == null) {
+ list = new TreeSet();
+ m_sidToServiceReferencesMap.put(sid, list);
+ }
+ list.add(reference);
+ }
+ }
+
+ public void modify(ServiceReference reference) {
+ remove(reference);
+ add(reference);
+ }
+
+ public void remove(ServiceReference reference) {
+ Long sid = ServiceUtil.getServiceIdObject(reference);
+ synchronized (m_sidToServiceReferencesMap) {
+ Set list = (Set) m_sidToServiceReferencesMap.get(sid);
+ if (list != null) {
+ list.remove(reference);
+ }
+ }
+ }
+
+ protected boolean referenceMatchesObjectClass(ServiceReference ref, String objectClass) {
+ boolean matches = false;
+ Object value = ref.getProperty(Constants.OBJECTCLASS);
+ matches = Arrays.asList((String[])value).contains(objectClass);
+ return matches;
+ }
+
+ /** Structure to hold internal filter data. */
+ protected static class FilterData {
+ public long serviceId;
+ public String objectClass;
+ public int ranking;
+
+ public String toString() {
+ return "FilterData [serviceId=" + serviceId + "]";
+ }
+ }
+}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AdapterFilterIndex.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AdapterFilterIndex.java
index 36447e5..e212f39 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AdapterFilterIndex.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AdapterFilterIndex.java
@@ -23,9 +23,9 @@
import java.util.Iterator;
import java.util.List;
import java.util.Map;
-import java.util.Set;
import java.util.SortedSet;
-import java.util.TreeSet;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.FilterIndex;
@@ -42,18 +42,17 @@
/**
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
-public class AdapterFilterIndex implements FilterIndex, ServiceTrackerCustomizer {
+public class AdapterFilterIndex extends AbstractFactoryFilterIndex implements FilterIndex, ServiceTrackerCustomizer {
// (&(objectClass=foo.Bar)(|(service.id=18233)(org.apache.felix.dependencymanager.aspect=18233)))
- private static final String FILTER_START = "(&(" + Constants.OBJECTCLASS + "=";
- private static final String FILTER_SUBSTRING_0 = ")(|(" + Constants.SERVICE_ID + "=";
- private static final String FILTER_SUBSTRING_1 = ")(" + DependencyManager.ASPECT + "=";
- private static final String FILTER_END = ")))";
+ private static final String FILTER_REGEXP = "\\(&\\(" + Constants.OBJECTCLASS + "=([a-zA-Z\\.\\$0-9]*)\\)\\(\\|\\("
+ + Constants.SERVICE_ID + "=([0-9]*)\\)\\("
+ + DependencyManager.ASPECT + "=([0-9]*)\\)\\)\\)";
+ private static final Pattern PATTERN = Pattern.compile(FILTER_REGEXP);
private final Object m_lock = new Object();
private ServiceTracker m_tracker;
private BundleContext m_context;
- private final Map /* <Long, SortedSet<ServiceReference>> */ m_sidToServiceReferencesMap = new HashMap();
private final Map /* <String, List<ServiceListener>> */ m_sidToListenersMap = new HashMap();
- private final Map /* <ServiceListener, String> */ m_listenerToFilterMap = new HashMap();
+ protected final Map /* <ServiceListener, String> */ m_listenerToObjectClassMap = new HashMap();
public void open(BundleContext context) {
synchronized (m_lock) {
@@ -91,51 +90,47 @@
/** Returns a value object with the relevant filter data, or <code>null</code> if this filter was not valid. */
private FilterData getFilterData(String clazz, String filter) {
// something like:
- // (&(objectClass=foo.Bar)(|(service.id=18233)(org.apache.felix.dependencymanager.aspect=18233)))
- if ((filter != null)
- && (filter.startsWith(FILTER_START))
- && (filter.endsWith(FILTER_END))
- ) {
- // service-id =
- int i0 = filter.indexOf(FILTER_SUBSTRING_0);
- if (i0 == -1) {
- return null;
- }
- // org.apache.felix.dependencymanager.aspect =
- int i1 = filter.indexOf(FILTER_SUBSTRING_1);
- if (i1 == -1 || i1 <= i0) {
- return null;
- }
- long sid = Long.parseLong(filter.substring(i0 + FILTER_SUBSTRING_0.length(), i1));
- long sid2 = Long.parseLong(filter.substring(i1 + FILTER_SUBSTRING_1.length(), filter.length() - FILTER_END.length()));
- if (sid != sid2) {
- return null;
- }
- FilterData result = new FilterData();
- result.serviceId = sid;
- return result;
- }
- return null;
+ // (&(objectClass=foo.Bar)(|(service.id=18233)(org.apache.felix.dependencymanager.aspect=18233)))
+ FilterData resultData = null;
+ if (filter != null) {
+ Matcher matcher = PATTERN.matcher(filter);
+ if (matcher.matches()) {
+ String sid = matcher.group(2);
+ String sid2 = matcher.group(3);
+ if (sid.equals(sid2)) {
+ resultData = new FilterData();
+ resultData.serviceId = Long.parseLong(sid);
+ }
+ }
+ }
+ return resultData;
}
- public List getAllServiceReferences(String clazz, String filter) {
- List /* <ServiceReference> */ result = new ArrayList();
- FilterData data = getFilterData(clazz, filter);
- if (data != null) {
- SortedSet /* <ServiceReference> */ list = null;
- synchronized (m_sidToServiceReferencesMap) {
- list = (SortedSet) m_sidToServiceReferencesMap.get(Long.valueOf(data.serviceId));
- if (list != null) {
- Iterator iterator = list.iterator();
- while (iterator.hasNext()) {
- result.add((ServiceReference) iterator.next());
- }
- }
+ public List getAllServiceReferences(String clazz, String filter) {
+ List /* <ServiceReference> */result = new ArrayList();
+ Matcher matcher = PATTERN.matcher(filter);
+ if (matcher.matches()) {
+ FilterData data = getFilterData(clazz, filter);
+ if (data != null) {
+ SortedSet /* <ServiceReference> */list = null;
+ synchronized (m_sidToServiceReferencesMap) {
+ list = (SortedSet) m_sidToServiceReferencesMap.get(Long.valueOf(data.serviceId));
+ if (list != null) {
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ServiceReference ref = (ServiceReference) iterator.next();
+ String objectClass = matcher.group(1);
+ if (referenceMatchesObjectClass(ref, objectClass)) {
+ result.add(ref);
+ }
+ }
+ }
+ }
}
- }
- return result;
- }
-
+ }
+ return result;
+ }
+
public void serviceChanged(ServiceEvent event) {
ServiceReference reference = event.getServiceReference();
Long sid = ServiceUtil.getServiceIdObject(reference);
@@ -143,7 +138,14 @@
synchronized (m_sidToListenersMap) {
List /* <ServiceListener> */ list = (ArrayList) m_sidToListenersMap.get(sid);
if (list != null) {
- notificationList.addAll(list);
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ServiceListener listener = (ServiceListener) iterator.next();
+ String objectClass = (String) m_listenerToObjectClassMap.get(listener);
+ if (referenceMatchesObjectClass(reference, objectClass)) {
+ notificationList.add(listener);
+ }
+ }
}
}
// notify
@@ -166,12 +168,21 @@
}
listeners.add(listener);
m_listenerToFilterMap.put(listener, filter);
+ Matcher matcher = PATTERN.matcher(filter);
+ if (matcher.matches()) {
+ String objectClass = matcher.group(1);
+ m_listenerToObjectClassMap.put(listener, objectClass);
+ } else {
+ throw new IllegalArgumentException("Filter string does not match index pattern");
+ }
+
}
}
}
public void removeServiceListener(ServiceListener listener) {
synchronized (m_sidToListenersMap) {
+ m_listenerToObjectClassMap.remove(listener);
String filter = (String) m_listenerToFilterMap.remove(listener);
if (filter != null) {
// the listener does exist
@@ -200,45 +211,6 @@
}
}
- public void addedService(ServiceReference reference, Object service) {
- add(reference);
- }
-
- public void modifiedService(ServiceReference reference, Object service) {
- modify(reference);
- }
-
- public void removedService(ServiceReference reference, Object service) {
- remove(reference);
- }
-
- public void add(ServiceReference reference) {
- Long sid = ServiceUtil.getServiceIdObject(reference);
- synchronized (m_sidToServiceReferencesMap) {
- Set list = (Set) m_sidToServiceReferencesMap.get(sid);
- if (list == null) {
- list = new TreeSet();
- m_sidToServiceReferencesMap.put(sid, list);
- }
- list.add(reference);
- }
- }
-
- public void modify(ServiceReference reference) {
- remove(reference);
- add(reference);
- }
-
- public void remove(ServiceReference reference) {
- Long sid = ServiceUtil.getServiceIdObject(reference);
- synchronized (m_sidToServiceReferencesMap) {
- Set list = (Set) m_sidToServiceReferencesMap.get(sid);
- if (list != null) {
- list.remove(reference);
- }
- }
- }
-
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("AdapterFilterIndex[");
@@ -249,9 +221,4 @@
return sb.toString();
}
- /** Structure to hold internal filter data. */
- private static class FilterData {
- public long serviceId;
- }
-
}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java
index 4e79eb4..6a98bfa 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/impl/index/AspectFilterIndex.java
@@ -19,16 +19,15 @@
package org.apache.felix.dm.impl.index;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
-import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.TreeMap;
-import java.util.TreeSet;
import org.apache.felix.dm.DependencyManager;
import org.apache.felix.dm.FilterIndex;
@@ -45,7 +44,8 @@
/**
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
-public class AspectFilterIndex implements FilterIndex, ServiceTrackerCustomizer {
+public class AspectFilterIndex extends AbstractFactoryFilterIndex implements FilterIndex, ServiceTrackerCustomizer {
+ // (&(objectClass=foo.Bar)(|(!(service.ranking=*))(service.ranking<=99))(|(service.id=4451)(org.apache.felix.dependencymanager.aspect=4451)))
private static final String FILTER_START = "(&(" + Constants.OBJECTCLASS + "=";
private static final String FILTER_SUBSTRING_0 = ")(&(|(!(" + Constants.SERVICE_RANKING + "=*))(" + Constants.SERVICE_RANKING + "<=";
private static final String FILTER_SUBSTRING_1 = "))(|(" + Constants.SERVICE_ID + "=";
@@ -54,9 +54,8 @@
private final Object m_lock = new Object();
private ServiceTracker m_tracker;
private BundleContext m_context;
- private final Map /* <Long, SortedSet<ServiceReference>> */ m_sidToServiceReferencesMap = new HashMap();
- private final Map /* <Long, SortedMap<Integer, ServiceListener>> */ m_sidToRankingToListenersMap = new HashMap();
- private final Map /* <ServiceListener, String> */ m_listenerToFilterMap = new HashMap();
+
+ private final Map /* <Long, Map<String, SortedMap<Integer, Collection<ServiceListener>>> */ m_sidToObjectClassToRankingToListenersMap = new HashMap();
public void open(BundleContext context) {
synchronized (m_lock) {
@@ -96,8 +95,8 @@
// something like:
// (&(objectClass=foo.Bar)(&(|(!(service.ranking=*))(service.ranking<=9))(|(service.id=37)(org.apache.felix.dependencymanager.aspect=37))))
if ((filter != null)
- && (filter.startsWith(FILTER_START))
- && (filter.endsWith(FILTER_END))
+ && (filter.startsWith(FILTER_START)) // (&(objectClass=
+ && (filter.endsWith(FILTER_END)) // ))))
) {
int i0 = filter.indexOf(FILTER_SUBSTRING_0);
if (i0 == -1) {
@@ -117,7 +116,7 @@
return null;
}
FilterData result = new FilterData();
- result.className = filter.substring(FILTER_START.length(), i0);
+ result.objectClass = filter.substring(FILTER_START.length(), i0);
result.serviceId = sid;
result.ranking = Integer.parseInt(filter.substring(i0 + FILTER_SUBSTRING_0.length(), i1));
return result;
@@ -136,7 +135,7 @@
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
ServiceReference reference = (ServiceReference) iterator.next();
- if (ServiceUtil.getRanking(reference) <= data.ranking) {
+ if (referenceMatchesObjectClass(reference, data.objectClass) && ServiceUtil.getRanking(reference) <= data.ranking) {
result.add(reference);
}
}
@@ -149,20 +148,29 @@
public void serviceChanged(ServiceEvent event) {
List list = new ArrayList();
ServiceReference reference = event.getServiceReference();
- Long sid = ServiceUtil.getServiceIdObject(reference);
+ Long sidObject = ServiceUtil.getServiceIdObject(reference);
int ranking = ServiceUtil.getRanking(reference);
- synchronized (m_sidToRankingToListenersMap) {
- SortedMap /* <Integer, ServiceListener> */ map = (SortedMap) m_sidToRankingToListenersMap.get(sid);
- if (map != null) {
- Iterator iterator = map.entrySet().iterator();
- while (iterator.hasNext()) {
- Entry entry = (Entry) iterator.next();
- if (ranking <= ((Integer) entry.getKey()).intValue()) {
- list.add((ServiceListener) entry.getValue());
- }
- }
- }
- }
+ String[] objectClasses = (String[]) reference.getProperty(Constants.OBJECTCLASS);
+
+ synchronized (m_sidToObjectClassToRankingToListenersMap) {
+ for (int i = 0; i < objectClasses.length; i++) {
+ // handle each of the object classes separately since aspects only work on one object class at a time
+ String objectClass = objectClasses[i];
+ Map /* <String, Map<Integer, Collection<ServiceListener>>> */ objectClassToRankingToListenersMap = (SortedMap) m_sidToObjectClassToRankingToListenersMap.get(sidObject);
+ if (objectClassToRankingToListenersMap != null) {
+ SortedMap /* Integer, ServiceListener> */ rankingToListenersMap = (SortedMap) objectClassToRankingToListenersMap.get(objectClass);
+ if (rankingToListenersMap != null) {
+ Iterator iterator = rankingToListenersMap.entrySet().iterator();
+ while (iterator.hasNext()) {
+ Entry entry = (Entry) iterator.next();
+ if (ranking <= ((Integer) entry.getKey()).intValue()) {
+ list.addAll((Collection)entry.getValue());
+ }
+ }
+ }
+ }
+ }
+ }
Iterator iterator = list.iterator();
while (iterator.hasNext()) {
ServiceListener listener = (ServiceListener) iterator.next();
@@ -174,34 +182,63 @@
FilterData data = getFilterData(null, filter);
if (data != null) {
Long sidObject = Long.valueOf(data.serviceId);
- synchronized (m_sidToRankingToListenersMap) {
- SortedMap /* <Integer, ServiceListener> */ rankingToListenersMap = (SortedMap) m_sidToRankingToListenersMap.get(sidObject);
+ synchronized (m_sidToObjectClassToRankingToListenersMap) {
+ Map /* <String, Map<Integer, Collection<ServiceListener>>> */ objectClassToRankingToListenersMap = (SortedMap) m_sidToObjectClassToRankingToListenersMap.get(sidObject);
+ if (objectClassToRankingToListenersMap == null) {
+ objectClassToRankingToListenersMap = new TreeMap();
+ m_sidToObjectClassToRankingToListenersMap.put(sidObject, objectClassToRankingToListenersMap);
+ }
+
+ SortedMap /* Integer, ServiceListener> */ rankingToListenersMap = (SortedMap) objectClassToRankingToListenersMap.get(data.objectClass);
if (rankingToListenersMap == null) {
rankingToListenersMap = new TreeMap();
- m_sidToRankingToListenersMap.put(sidObject, rankingToListenersMap);
- }
- rankingToListenersMap.put(Integer.valueOf(data.ranking), listener);
+ objectClassToRankingToListenersMap.put(data.objectClass, rankingToListenersMap);
+ }
+
+ Collection listeners = (Collection) rankingToListenersMap.get(Integer.valueOf(data.ranking));
+ if (listeners == null) {
+ listeners = new ArrayList();
+ rankingToListenersMap.put(Integer.valueOf(data.ranking), listeners);
+ }
+
+ listeners.add(listener);
m_listenerToFilterMap.put(listener, filter);
}
}
}
public void removeServiceListener(ServiceListener listener) {
- synchronized (m_sidToRankingToListenersMap) {
- String filter = (String) m_listenerToFilterMap.remove(listener);
- if (filter != null) {
- // the listener does exist
- FilterData data = getFilterData(null, filter);
- if (data != null) {
- synchronized (m_sidToRankingToListenersMap) {
- SortedMap /* <Integer, ServiceListener> */ rankingToListenersMap = (SortedMap) m_sidToRankingToListenersMap.get(Long.valueOf(data.serviceId));
- if (rankingToListenersMap != null) {
- rankingToListenersMap.remove(Integer.valueOf(data.ranking));
- }
- }
- }
- }
- }
+ synchronized (m_sidToObjectClassToRankingToListenersMap) {
+ String filter = (String) m_listenerToFilterMap.remove(listener);
+ if (filter != null) {
+ // the listener does exist
+ FilterData data = getFilterData(null, filter);
+ if (data != null) {
+ // this index is applicable
+ Long sidObject = Long.valueOf(data.serviceId);
+ Map /* <String, Map<Integer, Collection<ServiceListener>>> */ objectClassToRankingToListenersMap = (SortedMap) m_sidToObjectClassToRankingToListenersMap.get(sidObject);
+ if (objectClassToRankingToListenersMap != null) {
+ SortedMap /* Integer, ServiceListener> */ rankingToListenersMap = (SortedMap) objectClassToRankingToListenersMap.get(data.objectClass);
+ if (rankingToListenersMap != null) {
+ Collection listeners = (Collection) rankingToListenersMap.get(Integer.valueOf(data.ranking));
+ if (listeners != null) {
+ listeners.remove(listener);
+ }
+ // cleanup
+ if (listeners.isEmpty()) {
+ rankingToListenersMap.remove(Integer.valueOf(data.ranking));
+ }
+ if (rankingToListenersMap.isEmpty()) {
+ objectClassToRankingToListenersMap.remove(data.objectClass);
+ }
+ if (objectClassToRankingToListenersMap.isEmpty()) {
+ m_sidToObjectClassToRankingToListenersMap.remove(sidObject);
+ }
+ }
+ }
+ }
+ }
+ }
}
public Object addingService(ServiceReference reference) {
@@ -216,60 +253,15 @@
throw new IllegalStateException("No valid bundle context.");
}
}
-
- public void addedService(ServiceReference reference, Object service) {
- add(reference);
- }
-
- public void modifiedService(ServiceReference reference, Object service) {
- modify(reference);
- }
-
- public void removedService(ServiceReference reference, Object service) {
- remove(reference);
- }
-
- public void add(ServiceReference reference) {
- Long sid = ServiceUtil.getServiceIdObject(reference);
- synchronized (m_sidToServiceReferencesMap) {
- Set list = (Set) m_sidToServiceReferencesMap.get(sid);
- if (list == null) {
- list = new TreeSet();
- m_sidToServiceReferencesMap.put(sid, list);
- }
- list.add(reference);
- }
- }
-
- public void modify(ServiceReference reference) {
- remove(reference);
- add(reference);
- }
-
- public void remove(ServiceReference reference) {
- Long sid = ServiceUtil.getServiceIdObject(reference);
- synchronized (m_sidToServiceReferencesMap) {
- Set list = (Set) m_sidToServiceReferencesMap.get(sid);
- if (list != null) {
- list.remove(reference);
- }
- }
- }
public String toString() {
StringBuffer sb = new StringBuffer();
sb.append("AspectFilterIndex[");
- sb.append("S2R2L: " + m_sidToRankingToListenersMap.size());
+ sb.append("S2R2L: " + m_sidToObjectClassToRankingToListenersMap.size());
sb.append(", S2SR: " + m_sidToServiceReferencesMap.size());
sb.append(", L2F: " + m_listenerToFilterMap.size());
sb.append("]");
return sb.toString();
}
- /** Structure to hold internal filter data. */
- private static class FilterData {
- public String className;
- public long serviceId;
- public int ranking;
- }
}