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);          
+       }
+
+}


Reply via email to