Author: pderop
Date: Mon May 29 07:03:24 2017
New Revision: 1796576
URL: http://svn.apache.org/viewvc?rev=1796576&view=rev
Log:
FELIX-5619: MultiProperyFilterIndex memory consumption
FELIX-4028: Extensible filter index mechanism
Added:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCacheManager.java
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCache.java
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java?rev=1796576&r1=1796575&r2=1796576&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/DependencyManager.java
Mon May 29 07:03:24 2017
@@ -39,15 +39,10 @@ import org.apache.felix.dm.impl.Resource
import org.apache.felix.dm.impl.ResourceDependencyImpl;
import org.apache.felix.dm.impl.ServiceDependencyImpl;
import org.apache.felix.dm.impl.TemporalServiceDependencyImpl;
-import org.apache.felix.dm.impl.index.AdapterFilterIndex;
-import org.apache.felix.dm.impl.index.AspectFilterIndex;
import org.apache.felix.dm.impl.index.ServiceRegistryCache;
-import org.apache.felix.dm.impl.index.multiproperty.MultiPropertyFilterIndex;
+import org.apache.felix.dm.impl.index.ServiceRegistryCacheManager;
import org.apache.felix.dm.impl.metatype.PropertyMetaDataImpl;
-import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
-import org.osgi.framework.BundleException;
-import org.osgi.framework.FrameworkUtil;
/**
* The dependency manager manages all components and their dependencies. Using
@@ -74,41 +69,7 @@ public class DependencyManager {
private final Logger m_logger;
private final ConcurrentHashMap<Component, Component> m_components = new
ConcurrentHashMap<>();
- // service registry cache
- private static ServiceRegistryCache m_serviceRegistryCache;
private static final Set<WeakReference<DependencyManager>>
m_dependencyManagers = new HashSet<>();
- static {
- try {
- Bundle bundle =
FrameworkUtil.getBundle(DependencyManager.class);
- if (bundle != null) {
- if (bundle.getState() != Bundle.ACTIVE) {
- bundle.start();
- }
- BundleContext bundleContext = bundle.getBundleContext();
- String index =
bundleContext.getProperty(SERVICEREGISTRY_CACHE_INDICES);
- if (index != null) {
- m_serviceRegistryCache = new
ServiceRegistryCache(bundleContext);
- m_serviceRegistryCache.open(); // TODO close it
somewhere
- String[] props = index.split(";");
- for (int i = 0; i < props.length; i++) {
- if (props[i].equals("*aspect*")) {
-
m_serviceRegistryCache.addFilterIndex(new AspectFilterIndex());
- }
- else if (props[i].equals("*adapter*")) {
-
m_serviceRegistryCache.addFilterIndex(new AdapterFilterIndex());
- }
- else {
-
m_serviceRegistryCache.addFilterIndex(new MultiPropertyFilterIndex(props[i]));
- }
- }
- }
- }
- }
- catch (BundleException e) {
- // if we cannot start ourselves, we cannot use the indices
- e.printStackTrace();
- }
- }
/**
* Creates a new dependency manager. You need to supply the
@@ -837,8 +798,9 @@ public class DependencyManager {
}
private BundleContext createContext(BundleContext context) {
- if (m_serviceRegistryCache != null) {
- return
m_serviceRegistryCache.createBundleContextInterceptor(context);
+ ServiceRegistryCache cache = ServiceRegistryCacheManager.getCache();
+ if (cache != null) {
+ return cache.createBundleContextInterceptor(context);
}
else {
return context;
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java?rev=1796576&r1=1796575&r2=1796576&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/Activator.java
Mon May 29 07:03:24 2017
@@ -19,6 +19,9 @@
package org.apache.felix.dm.impl;
import org.apache.felix.dm.ComponentExecutorFactory;
+import org.apache.felix.dm.FilterIndex;
+import org.apache.felix.dm.impl.index.ServiceRegistryCache;
+import org.apache.felix.dm.impl.index.ServiceRegistryCacheManager;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Filter;
@@ -27,40 +30,75 @@ import org.osgi.util.tracker.ServiceTrac
import org.osgi.util.tracker.ServiceTrackerCustomizer;
/**
- * DependencyManager Activator used to track a ComponentExecutorFactory
service optionally registered by
- * a management agent bundle.
+ * DependencyManager Activator used to track a ComponentExecutorFactory service
+ * optionally registered by a management agent bundle.
*
* @see {@link ComponentExecutorFactory}
* @author <a href="mailto:[email protected]">Felix Project Team</a>
*/
-public class Activator implements BundleActivator,
ServiceTrackerCustomizer<ComponentExecutorFactory, ComponentExecutorFactory> {
- private BundleContext m_context;
-
+public class Activator implements BundleActivator {
+ private BundleContext m_context;
+ private ServiceTracker<ComponentExecutorFactory,
ComponentExecutorFactory> m_execTracker;
+ private ServiceTracker<FilterIndex, FilterIndex> m_indexTracker;
+
@Override
- public void start(BundleContext context) throws Exception {
+ public void start(BundleContext context) throws Exception {
+ // make sure the backdoor is set in system properties (needed
by tests)
+ ServiceRegistryCacheManager.init();
+
m_context = context;
- Filter filter = context.createFilter("(objectClass=" +
ComponentExecutorFactory.class.getName() + ")");
- ServiceTracker<ComponentExecutorFactory, ComponentExecutorFactory>
tracker = new ServiceTracker<>(context, filter, this);
- tracker.open();
+ Filter execFilter = context.createFilter("(objectClass=" +
ComponentExecutorFactory.class.getName() + ")");
+ m_execTracker = new ServiceTracker<>(context, execFilter, new
ExecutorFactoryCustomizer());
+ m_execTracker.open();
+
+ Filter indexFilter = context.createFilter("(objectClass=" +
FilterIndex.class.getName() + ")");
+ m_indexTracker = new ServiceTracker<>(context, indexFilter, new
FilterIndexCustomizer());
+ m_indexTracker.open();
}
@Override
public void stop(BundleContext context) throws Exception {
+ if (m_execTracker != null) {
+ m_execTracker.close();
+ }
+ if (m_indexTracker != null) {
+ m_indexTracker.close();
+ }
}
- @Override
- public ComponentExecutorFactory
addingService(ServiceReference<ComponentExecutorFactory> reference) {
- ComponentExecutorFactory factory = (ComponentExecutorFactory)
m_context.getService(reference);
- ComponentScheduler.instance().bind(factory);
- return factory;
- }
-
- @Override
- public void modifiedService(ServiceReference<ComponentExecutorFactory>
reference, ComponentExecutorFactory service) {
+ private class ExecutorFactoryCustomizer implements
ServiceTrackerCustomizer<ComponentExecutorFactory, ComponentExecutorFactory> {
+ @Override
+ public ComponentExecutorFactory
addingService(ServiceReference<ComponentExecutorFactory> reference) {
+ ComponentExecutorFactory factory =
(ComponentExecutorFactory) m_context.getService(reference);
+ ComponentScheduler.instance().bind(factory);
+ return factory;
+ }
+
+ @Override
+ public void
modifiedService(ServiceReference<ComponentExecutorFactory> reference,
ComponentExecutorFactory service) {
+ }
+
+ @Override
+ public void
removedService(ServiceReference<ComponentExecutorFactory> reference,
ComponentExecutorFactory factory) {
+ ComponentScheduler.instance().unbind(factory);
+ }
}
-
- @Override
- public void removedService(ServiceReference<ComponentExecutorFactory>
reference, ComponentExecutorFactory factory) {
- ComponentScheduler.instance().unbind(factory);
+
+ private class FilterIndexCustomizer implements
ServiceTrackerCustomizer<FilterIndex, FilterIndex> {
+ @Override
+ public FilterIndex addingService(ServiceReference<FilterIndex>
reference) {
+ FilterIndex index = m_context.getService(reference);
+ ServiceRegistryCacheManager.registerFilterIndex(index,
m_context);
+ return index;
+ }
+
+ @Override
+ public void modifiedService(ServiceReference<FilterIndex>
reference, FilterIndex service) {
+ }
+
+ @Override
+ public void removedService(ServiceReference<FilterIndex>
reference, FilterIndex index) {
+
ServiceRegistryCacheManager.unregisterFilterIndex(index);
+ }
}
}
Modified:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCache.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCache.java?rev=1796576&r1=1796575&r2=1796576&view=diff
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCache.java
(original)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCache.java
Mon May 29 07:03:24 2017
@@ -62,6 +62,10 @@ public class ServiceRegistryCache implem
index.close();
m_filterIndexList.remove(index);
}
+
+ public int getSize() {
+ return m_filterIndexList.size();
+ }
public void serviceChanged(ServiceEvent event) {
// any incoming event is first dispatched to the list of filter indices
Added:
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCacheManager.java
URL:
http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCacheManager.java?rev=1796576&view=auto
==============================================================================
---
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCacheManager.java
(added)
+++
felix/trunk/dependencymanager/org.apache.felix.dependencymanager/src/org/apache/felix/dm/impl/index/ServiceRegistryCacheManager.java
Mon May 29 07:03:24 2017
@@ -0,0 +1,216 @@
+/*
+ * 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.impl.index;
+
+import java.lang.reflect.Constructor;
+import java.util.function.Consumer;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.FilterIndex;
+import org.apache.felix.dm.impl.index.multiproperty.MultiPropertyFilterIndex;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * This class manages the service registry cache creation.
+ */
+public class ServiceRegistryCacheManager {
+
+ /**
+ * The Service Registry cache, which is created if you specify the
"org.apache.felix.dependencymanager.filterindex" system property
+ * or if you register as a service a FilterIndex in the service
registry.
+ */
+ private static volatile ServiceRegistryCache m_cache;
+
+ /**
+ * Backdoor only used by tests: a Consumer<String> is added in system
properties using the following key and
+ * when tests invoke it, the cache is reintialized as if the JVM would
have been restarted.
+ */
+ private final static String RESET =
"org.apache.felix.dependencymanager.filterindex.reset";
+
+ /**
+ * the DependendencyManager bundle context used by the
ServiceRegistryCache.
+ */
+ private static volatile BundleContext m_context;
+
+ /**
+ * Boolean used to check if we are already initialized
+ */
+ private static volatile boolean m_init = false;
+
+ /**
+ * Static initializer: we create the registry cache in case
"org.apache.felix.dependencymanager.filterindex" system property is configured.
+ */
+ static {
+ init();
+ }
+
+ /**
+ * Gets the service registry cache, if enabled.
+ * @return the service registry cache, if enabled, or null
+ */
+ public static ServiceRegistryCache getCache() {
+ return m_cache;
+ }
+
+ /**
+ * Registers a FilterIndex into the service registry cache. The cache
is created if necessary.
+ * @param index a new FilterIndex to be registered in the cache
+ * @param context the bundle context used by the cache
+ */
+ public static void registerFilterIndex(FilterIndex index, BundleContext
context) {
+ ServiceRegistryCache cache = createCache(context);
+ cache.addFilterIndex(index);
+ }
+
+ /**
+ * Unregister a FilterIndex from the cache, and possibly close the
cache in case it becomes empty.
+ * @param index the FilterIndex to unregister
+ */
+ public static void unregisterFilterIndex(FilterIndex index) {
+ ServiceRegistryCache cache =
ServiceRegistryCacheManager.getCache();
+ if (cache != null) {
+ cache.removeFilterIndex(index);
+ boolean close = false;
+ synchronized (ServiceRegistryCacheManager.class) {
+ if (cache.getSize() == 0) {
+ m_cache = null;
+ close = true;
+ }
+ }
+ if (close) {
+ cache.close();
+ }
+ }
+ }
+
+ /**
+ * Creates the cache if it does not exist.
+ * @param context the bundle context that will be used by the case
+ * @return the created cache (or the existing cache)
+ */
+ private static ServiceRegistryCache createCache(BundleContext context) {
+ ServiceRegistryCache cache = null;
+ boolean open = false;
+ synchronized (ServiceRegistryCacheManager.class) {
+ if (m_cache == null) {
+ m_cache = new ServiceRegistryCache(context);
+ open = true;
+ }
+ cache = m_cache;
+ }
+ if (open) {
+ cache.open();
+ }
+ return cache;
+ }
+
+ /**
+ * Initialize the service registry cache.
+ */
+ public static void init() {
+ try {
+ if (m_init) {
+ return;
+ }
+ Bundle bundle =
FrameworkUtil.getBundle(ServiceRegistryCacheManager.class);
+ if (bundle != null) {
+ if (bundle.getState() != Bundle.STARTING &&
bundle.getState() != Bundle.ACTIVE) {
+ bundle.start(); // take care: may
callback our registerFilterIndex method
+ }
+ m_context = bundle.getBundleContext();
+ String index =
m_context.getProperty(DependencyManager.SERVICEREGISTRY_CACHE_INDICES);
+ if (index != null) {
+ resetIndices(index);
+ }
+ }
+ Consumer<String> reset =
ServiceRegistryCacheManager::reset;
+ System.getProperties().put(RESET, reset);
+ m_init = true;
+ }
+
+ catch (BundleException e) {
+ // if we cannot start ourselves, we cannot use the
indices
+ e.printStackTrace();
+ }
+ }
+
+ private static void resetIndices(String index) {
+ try {
+ if (index != null) {
+ ServiceRegistryCache cache =
createCache(m_context); // may already exist, in case the Activator has called
back our registerFilterIndex method
+
+ String[] props = index.split(";");
+ for (int i = 0; i < props.length; i++) {
+ // Check if a classname is specified
for the current index.
+ // (syntax is "full_class_name:index")
+ int colon = props[i].indexOf(":");
+ if (colon != -1) {
+ String className =
props[i].substring(0, colon).trim();
+ String indexDefinition =
props[i].substring(colon + 1);
+
cache.addFilterIndex(createCustomIndex(className, indexDefinition));
+ } else if (props[i].equals("*aspect*"))
{
+ cache.addFilterIndex(new
AspectFilterIndex());
+ } else if
(props[i].equals("*adapter*")) {
+ cache.addFilterIndex(new
AdapterFilterIndex());
+ } else {
+ cache.addFilterIndex(new
MultiPropertyFilterIndex(props[i]));
+ }
+ }
+ }
+ }
+
+ catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Creates a custom index using its classname, that has been specified
in the org.apache.felix.dependencymanager.filterindex system property.
+ */
+ private static FilterIndex createCustomIndex(String className, String
indexDefinition) {
+ try {
+ Class<?> customIndexClass = Class.forName(className);
+ Constructor<?> ctor =
customIndexClass.getConstructor(String.class);
+ FilterIndex index = (FilterIndex)
ctor.newInstance(indexDefinition);
+ return index;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ /**
+ * Reinitialize the cache. Only called by tests. This method is
registered in the system properties in the form of a Runnable,
+ * with key=ServiceRegistryCacheManager.RESET.
+ */
+ private static void reset(String indices) {
+ if (m_cache != null) {
+ for (FilterIndex index : m_cache.getFilterIndices()) {
+ index.close();
+ }
+ m_cache.close();
+ }
+ m_cache = null;
+ resetIndices(indices);
+ }
+
+}