Implemented a filter index that speeds up aspects.
Some bugfixes.
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1095365 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
index 5ac4974..07ec03a 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/DependencyManager.java
@@ -35,6 +35,7 @@
import org.apache.felix.dm.impl.dependencies.ServiceDependencyImpl;
import org.apache.felix.dm.impl.dependencies.TemporalServiceDependencyImpl;
import org.apache.felix.dm.impl.metatype.PropertyMetaDataImpl;
+import org.apache.felix.dm.index.AspectFilterIndex;
import org.apache.felix.dm.index.MultiPropertyExactFilter;
import org.apache.felix.dm.index.ServiceRegistryCache;
import org.osgi.framework.BundleContext;
@@ -78,13 +79,18 @@
private static ServiceRegistryCache m_serviceRegistryCache;
static {
String index = System.getProperty(SERVICEREGISTRY_CACHE_INDICES);
- m_serviceRegistryCache = new ServiceRegistryCache(FrameworkUtil.getBundle(DependencyManager.class).getBundleContext());
- m_serviceRegistryCache.open(); // TODO close it somewhere
if (index != null) {
+ m_serviceRegistryCache = new ServiceRegistryCache(FrameworkUtil.getBundle(DependencyManager.class).getBundleContext());
+ m_serviceRegistryCache.open(); // TODO close it somewhere
String[] props = index.split(";");
for (int i = 0; i < props.length; i++) {
- String[] propList = props[i].split(",");
- m_serviceRegistryCache.addFilterIndex(new MultiPropertyExactFilter(propList));
+ if (props[i].equals("*aspect*")) {
+ m_serviceRegistryCache.addFilterIndex(new AspectFilterIndex());
+ }
+ else {
+ String[] propList = props[i].split(",");
+ m_serviceRegistryCache.addFilterIndex(new MultiPropertyExactFilter(propList));
+ }
// System.out.println("DM: Creating index on " + props[i]);
}
}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/index/AspectFilterIndex.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/index/AspectFilterIndex.java
new file mode 100644
index 0000000..2223f7d
--- /dev/null
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/index/AspectFilterIndex.java
@@ -0,0 +1,265 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.dm.index;
+
+import java.util.ArrayList;
+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.ServiceUtil;
+import org.apache.felix.dm.tracker.ServiceTracker;
+import org.apache.felix.dm.tracker.ServiceTrackerCustomizer;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceEvent;
+import org.osgi.framework.ServiceListener;
+import org.osgi.framework.ServiceReference;
+
+public class AspectFilterIndex implements FilterIndex, ServiceTrackerCustomizer {
+ 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 + "=";
+ private static final String FILTER_SUBSTRING_2 = ")(" + DependencyManager.ASPECT + "=";
+ private static final String FILTER_END = "))))";
+ 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();
+
+ public void open(BundleContext context) {
+ synchronized (m_lock) {
+ if (m_context != null) {
+ throw new IllegalStateException("Filter already open.");
+ }
+ try {
+ m_tracker = new ServiceTracker(context, context.createFilter("(" + Constants.OBJECTCLASS + "=*)"), this);
+ }
+ catch (InvalidSyntaxException e) {
+ throw new Error();
+ }
+ m_context = context;
+ }
+ m_tracker.open(true);
+ }
+
+ public void close() {
+ ServiceTracker tracker;
+ synchronized (m_lock) {
+ if (m_context == null) {
+ throw new IllegalStateException("Filter already closed.");
+ }
+ tracker = m_tracker;
+ m_tracker = null;
+ m_context = null;
+ }
+ tracker.close();
+ }
+
+ public boolean isApplicable(String clazz, String filter) {
+ return getFilterData(clazz, filter) != null;
+ }
+
+ /** 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=com.beinformed.wiringtest.Model)(&(|(!(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))
+ ) {
+ int i0 = filter.indexOf(FILTER_SUBSTRING_0);
+ if (i0 == -1) {
+ return null;
+ }
+ int i1 = filter.indexOf(FILTER_SUBSTRING_1);
+ if (i1 == -1 || i1 <= i0) {
+ return null;
+ }
+ int i2 = filter.indexOf(FILTER_SUBSTRING_2);
+ if (i2 == -1 || i2 <= i1) {
+ return null;
+ }
+ long sid = Long.parseLong(filter.substring(i1 + FILTER_SUBSTRING_1.length(), i2));
+ long sid2 = Long.parseLong(filter.substring(i2 + FILTER_SUBSTRING_2.length(), filter.length() - FILTER_END.length()));
+ if (sid != sid2) {
+ return null;
+ }
+ FilterData result = new FilterData();
+ result.className = filter.substring(FILTER_START.length(), i0);
+ result.serviceId = sid;
+ result.ranking = Integer.parseInt(filter.substring(i0 + FILTER_SUBSTRING_0.length(), i1));
+ return result;
+ }
+ return null;
+ }
+
+ public List getAllServiceReferences(String clazz, String filter) {
+ List /* <ServiceReference> */ result = new ArrayList();
+ FilterData data = getFilterData(clazz, filter);
+ if (data != null) {
+ SortedSet /* <ServiceReference> */ list = (SortedSet) m_sidToServiceReferencesMap.get(Long.valueOf(data.serviceId));
+ if (list != null) {
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ServiceReference reference = (ServiceReference) iterator.next();
+ if (ServiceUtil.getRanking(reference) <= data.ranking) {
+ result.add(reference);
+ }
+ }
+ }
+ }
+ return result;
+ }
+
+ public void serviceChanged(ServiceEvent event) {
+ List list = new ArrayList();
+ ServiceReference reference = event.getServiceReference();
+ Long sid = 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());
+ }
+ }
+ }
+ }
+ Iterator iterator = list.iterator();
+ while (iterator.hasNext()) {
+ ServiceListener listener = (ServiceListener) iterator.next();
+ listener.serviceChanged(event);
+ }
+ }
+
+ public void addServiceListener(ServiceListener listener, String filter) {
+ 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);
+ if (rankingToListenersMap == null) {
+ rankingToListenersMap = new TreeMap();
+ m_sidToRankingToListenersMap.put(sidObject, rankingToListenersMap);
+ }
+ rankingToListenersMap.put(Integer.valueOf(data.ranking), listener);
+ m_listenerToFilterMap.put(listener, filter);
+ }
+ }
+ }
+
+ public void removeServiceListener(ServiceListener listener) {
+ synchronized (m_sidToRankingToListenersMap) {
+ String filter = (String) m_listenerToFilterMap.remove(listener);
+ 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));
+ }
+ }
+ }
+ }
+ }
+
+ public Object addingService(ServiceReference reference) {
+ BundleContext context;
+ synchronized (m_lock) {
+ context = m_context;
+ }
+ if (context != null) {
+ return context.getService(reference);
+ }
+ else {
+ 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(", 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;
+ }
+}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/index/BundleContextInterceptor.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/index/BundleContextInterceptor.java
index c34775a..7f4281d 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/index/BundleContextInterceptor.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/index/BundleContextInterceptor.java
@@ -108,6 +108,9 @@
ServiceReference[] references;
try {
references = getServiceReferences(clazz, null);
+ if (references == null || references.length == 0) {
+ return null;
+ }
Arrays.sort(references);
return references[references.length - 1];
}
diff --git a/dependencymanager/core/src/main/java/org/apache/felix/dm/index/ServiceRegistryCache.java b/dependencymanager/core/src/main/java/org/apache/felix/dm/index/ServiceRegistryCache.java
index 7f4f871..052675e 100644
--- a/dependencymanager/core/src/main/java/org/apache/felix/dm/index/ServiceRegistryCache.java
+++ b/dependencymanager/core/src/main/java/org/apache/felix/dm/index/ServiceRegistryCache.java
@@ -24,14 +24,12 @@
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
-import org.eclipse.osgi.framework.console.CommandInterpreter;
-import org.eclipse.osgi.framework.console.CommandProvider;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceRegistration;
-public class ServiceRegistryCache implements ServiceListener, CommandProvider {
+public class ServiceRegistryCache implements ServiceListener/*, CommandProvider*/ {
private final List /* <FilterIndex> */ m_filterIndexList = new CopyOnWriteArrayList();
private final BundleContext m_context;
private final FilterIndexBundleContext m_filterIndexBundleContext;
@@ -49,11 +47,11 @@
public void open() {
m_context.addServiceListener(this);
- m_registration = m_context.registerService(CommandProvider.class.getName(), this, null);
+// m_registration = m_context.registerService(CommandProvider.class.getName(), this, null);
}
public void close() {
- m_registration.unregister();
+// m_registration.unregister();
m_context.removeServiceListener(this);
}
@@ -117,49 +115,49 @@
}
}
- public void _sc(CommandInterpreter ci) {
- ci.println(toString());
- }
-
- public void _fi(CommandInterpreter ci) {
- String arg = ci.nextArgument();
- if (arg != null) {
- int x = Integer.parseInt(arg);
- FilterIndex filterIndex = (FilterIndex) m_filterIndexList.get(x);
- String a1 = ci.nextArgument();
- String a2 = null;
- if (a1 != null) {
- if ("-".equals(a1)) {
- a1 = null;
- }
- a2 = ci.nextArgument();
- }
- if (filterIndex.isApplicable(a1, a2)) {
- List /* <ServiceReference> */ references = filterIndex.getAllServiceReferences(a1, a2);
- ci.println("Found " + references.size() + " references:");
- for (int i = 0; i < references.size(); i++) {
- ci.println("" + i + " - " + references.get(i));
- }
- }
- else {
- ci.println("Filter not applicable.");
- }
- }
- else {
- ci.println("FilterIndices:");
- Iterator iterator = m_filterIndexList.iterator();
- int index = 0;
- while (iterator.hasNext()) {
- FilterIndex filterIndex = (FilterIndex) iterator.next();
- ci.println("" + index + " " + filterIndex);
- index++;
- }
- }
- }
-
- public String getHelp() {
- return "I'm not going to help you!";
- }
+// public void _sc(CommandInterpreter ci) {
+// ci.println(toString());
+// }
+//
+// public void _fi(CommandInterpreter ci) {
+// String arg = ci.nextArgument();
+// if (arg != null) {
+// int x = Integer.parseInt(arg);
+// FilterIndex filterIndex = (FilterIndex) m_filterIndexList.get(x);
+// String a1 = ci.nextArgument();
+// String a2 = null;
+// if (a1 != null) {
+// if ("-".equals(a1)) {
+// a1 = null;
+// }
+// a2 = ci.nextArgument();
+// }
+// if (filterIndex.isApplicable(a1, a2)) {
+// List /* <ServiceReference> */ references = filterIndex.getAllServiceReferences(a1, a2);
+// ci.println("Found " + references.size() + " references:");
+// for (int i = 0; i < references.size(); i++) {
+// ci.println("" + i + " - " + references.get(i));
+// }
+// }
+// else {
+// ci.println("Filter not applicable.");
+// }
+// }
+// else {
+// ci.println("FilterIndices:");
+// Iterator iterator = m_filterIndexList.iterator();
+// int index = 0;
+// while (iterator.hasNext()) {
+// FilterIndex filterIndex = (FilterIndex) iterator.next();
+// ci.println("" + index + " " + filterIndex);
+// index++;
+// }
+// }
+// }
+//
+// public String getHelp() {
+// return "I'm not going to help you!";
+// }
public String toString() {
StringBuffer sb = new StringBuffer();