You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by pd...@apache.org on 2017/05/29 07:28:24 UTC

svn commit: r1796580 - in /felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest: ./ .settings/ bin/ bin_test/ src/ src/org/ src/org/apache/ src/org/apache/felix/ src/org/apache/felix/dm/ src/org/apache/felix/dm/index/ src/org/ap...

Author: pderop
Date: Mon May 29 07:28:24 2017
New Revision: 1796580

URL: http://svn.apache.org/viewvc?rev=1796580&view=rev
Log:
FELIX-5619: MultiProperyFilterIndex memory consumption
FELIX-4028: Extensible filter index mechanism

Added a new integration test subproject for the above issues because filter indices are special and may mess around with org.apache.felix.dependencymanager.itest sub project.


Added:
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.classpath   (with props)
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.gitignore
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.project   (with props)
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.settings/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/bin/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/bin_test/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/bnd.bnd
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/dynamic.customindex.bnd
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/dynamiccustomindex/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/dynamiccustomindex/DynamicCustomFilterIndex.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/staticcustomindex/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/staticcustomindex/StaticCustomFilterIndex.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/DynamicCustomIndexTest.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/Ensure.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3008_FilterIndexStartupTest.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3057_EmptyServiceReferenceArray.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FilterIndexResourceAdapterTest.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/ResourceProvider.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/StaticCustomIndexTest.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/TestBase.java
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/static.customindex.bnd
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/test/
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/test/.gitignore
    felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/tests.bnd

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.classpath
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.classpath?rev=1796580&view=auto
==============================================================================
Binary file - no diff available.

Propchange: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.classpath
------------------------------------------------------------------------------
    svn:mime-type = application/xml

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.gitignore
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.gitignore?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.gitignore (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.gitignore Mon May 29 07:28:24 2017
@@ -0,0 +1,3 @@
+/bin/
+/bin_test/
+/generated/

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.project
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.project?rev=1796580&view=auto
==============================================================================
Binary file - no diff available.

Propchange: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/.project
------------------------------------------------------------------------------
    svn:mime-type = application/xml

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/bnd.bnd
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/bnd.bnd?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/bnd.bnd (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/bnd.bnd Mon May 29 07:28:24 2017
@@ -0,0 +1,56 @@
+#
+# 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.
+#
+-runbundles: \
+	org.apache.felix.metatype;version=1.0.4,\
+	org.apache.felix.gogo.runtime;version=0.10.0,\
+	org.apache.felix.log;version=1.0.1,\
+	org.apache.felix.configadmin;version=1.8.8,\
+	org.apache.felix.dependencymanager;version=latest,\
+	org.apache.felix.dependencymanager.shell;version=latest,\
+	biz.aQute.junit;version=3.0.0,\
+	org.apache.felix.gogo.command,\
+	org.apache.felix.gogo.shell,\
+	org.apache.felix.dependencymanager.index.itest.dynamic.customindex;version=latest,\
+	org.apache.felix.dependencymanager.index.itest.static.customindex;version=latest,\
+	org.apache.felix.dependencymanager.index.itest.tests;version=latest
+	
+-runee: JavaSE-1.8
+-runvm: -ea
+-runfw: org.apache.felix.framework;version='[5.2.0,5.2.0]'
+-buildpath: \
+	osgi.core;version=4.2,\
+	osgi.cmpn;version=4.2,\
+	org.apache.felix.gogo.runtime;version=0.10,\
+	org.apache.felix.dependencymanager;version=latest,\
+	org.apache.felix.dependencymanager.shell;version=latest,\
+	${junit}
+-runsystempackages: \
+	sun.reflect
+Test-Cases:  \
+	${classes;CONCRETE;EXTENDS;junit.framework.TestCase}
+-runproperties:  \
+	org.apache.felix.dependencymanager.loglevel=2,\
+	org.apache.felix.log.maxSize=100000,\
+	org.apache.felix.log.storeDebug=true,\
+	gosh.args=--noshutdown,\
+	org.apache.felix.dependencymanager.filterindex=objectClass
+	
+# we do not release this project in binary distribution.
+-releaserepo: 
+-baseline: 
+
+-sub: *.bnd
\ No newline at end of file

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/dynamic.customindex.bnd
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/dynamic.customindex.bnd?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/dynamic.customindex.bnd (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/dynamic.customindex.bnd Mon May 29 07:28:24 2017
@@ -0,0 +1,24 @@
+#
+# 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.
+#
+Export-Package: \
+	org.apache.felix.dm.index.itest.dynamiccustomindex
+Private-Package: \
+	org.apache.felix.dm.impl.index.multiproperty
+Import-Package: *
+Bundle-Category: test
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Vendor: The Apache Software Foundation

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/dynamiccustomindex/DynamicCustomFilterIndex.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/dynamiccustomindex/DynamicCustomFilterIndex.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/dynamiccustomindex/DynamicCustomFilterIndex.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/dynamiccustomindex/DynamicCustomFilterIndex.java Mon May 29 07:28:24 2017
@@ -0,0 +1,54 @@
+/*
+ * 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.itest.dynamiccustomindex;
+
+import org.apache.felix.dm.impl.index.multiproperty.MultiPropertyFilterIndex;
+import org.osgi.framework.BundleContext;
+
+/**
+ * A 
+ * @author nxuser
+ *
+ */
+@SuppressWarnings("restriction")
+public class DynamicCustomFilterIndex extends MultiPropertyFilterIndex {
+	
+	/**
+	 * System property set to true when our DynamicCustomFilterIndex has been opened
+	 */
+	private final static String OPENED = "org.apache.felix.dm.index.itest.dynamiccustomindex.CustomFilterIndex.opened";
+
+	public DynamicCustomFilterIndex(String configString) {
+		super(configString);
+	}
+
+	@Override
+    public void open(BundleContext context) {
+    	super.open(context);
+    	// indicate to our StaticCustomIndexTest that we have been used
+    	System.setProperty(OPENED, "true");
+    }
+	
+	@Override
+    public void close() {
+    	super.close();
+    	System.getProperties().remove(OPENED);
+    }
+
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/staticcustomindex/StaticCustomFilterIndex.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/staticcustomindex/StaticCustomFilterIndex.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/staticcustomindex/StaticCustomFilterIndex.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/staticcustomindex/StaticCustomFilterIndex.java Mon May 29 07:28:24 2017
@@ -0,0 +1,49 @@
+/*
+ * 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.itest.staticcustomindex;
+
+import org.apache.felix.dm.impl.index.multiproperty.MultiPropertyFilterIndex;
+import org.osgi.framework.BundleContext;
+
+@SuppressWarnings("restriction")
+public class StaticCustomFilterIndex extends MultiPropertyFilterIndex {
+	
+	/**
+	 * System property set to true when our StaticCustomFilterIndex has been opened
+	 */
+	private final static String OPENED = "org.apache.felix.dm.index.itest.staticcustomindex.StaticCustomFilterIndex.opened";
+
+	public StaticCustomFilterIndex(String configString) {
+		super(configString);
+	}
+	
+	@Override
+    public void open(BundleContext context) {
+    	super.open(context);
+    	// indicate to our StaticCustomIndexTest that we have been used
+    	System.setProperty(OPENED, "true");
+    }
+
+	@Override
+    public void close() {
+    	super.close();
+    	System.getProperties().remove(OPENED);
+    }
+
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/DynamicCustomIndexTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/DynamicCustomIndexTest.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/DynamicCustomIndexTest.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/DynamicCustomIndexTest.java Mon May 29 07:28:24 2017
@@ -0,0 +1,148 @@
+/*
+ * 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.itest.tests;
+//import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartupFor;
+//import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
+
+import java.util.function.Consumer;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.FilterIndex;
+import org.apache.felix.dm.index.itest.dynamiccustomindex.DynamicCustomFilterIndex;
+import org.junit.Assert;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceRegistration;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class DynamicCustomIndexTest extends TestBase {
+	
+	/**
+	 * This system property is set to true when the DynamicCustomFilterIndex index has been opened.
+	 */
+	private final static String OPENED = "org.apache.felix.dm.index.itest.dynamiccustomindex.CustomFilterIndex.opened";
+	
+	private ServiceRegistration m_reg;
+	
+	private String m_systemConf;
+	
+    @SuppressWarnings("unchecked")
+	public void setUp() throws Exception {
+        System.setProperty(OPENED, "false");
+        
+        // backup currently configured filter index
+        BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+    	m_systemConf = context.getProperty(DependencyManager.SERVICEREGISTRY_CACHE_INDICES);
+    	
+    	// Reset filter indices    	
+    	DependencyManager dm = new DependencyManager(context);
+    	Consumer<String> reset = (Consumer<String>) System.getProperties().get("org.apache.felix.dependencymanager.filterindex.reset");
+        reset.accept(null); // clear filter index
+        
+        // register our DynamicCustomFilterIndex service before calling super.setUp(). This will make
+        // the "getDM()" method return a DependencyManager that is using our DynamicCustomFilterIndex
+    	m_reg = context.registerService(FilterIndex.class.getName(), new DynamicCustomFilterIndex("objectClass"), null);
+    	super.setUp();   
+    }
+    
+    @SuppressWarnings("unchecked")
+	public void tearDown() throws Exception {
+        super.tearDown();
+    	try {
+    		m_reg.unregister();
+    	} catch (IllegalStateException e) { // expected, normally we have already unregistered it    		
+    	}
+        System.getProperties().remove(OPENED);
+        Consumer<String> reset = (Consumer<String>) System.getProperties().get("org.apache.felix.dependencymanager.filterindex.reset");
+        reset.accept(m_systemConf);
+    }
+	
+    public void testUsingDynamicCustomIndex() throws Exception {
+    	doTestUsingDynamicCustomIndex();
+        
+        // Make sure our static custom index has been used
+        Assert.assertTrue(Boolean.getBoolean(OPENED));
+        
+        // unregister our dynamic filter index
+    	m_reg.unregister();
+
+    	// clear the flag
+        System.setProperty(OPENED, "false");
+
+        // redo the test
+    	doTestUsingDynamicCustomIndex();
+        Assert.assertFalse(Boolean.getBoolean(OPENED));
+    }
+    
+    private void doTestUsingDynamicCustomIndex() throws Exception {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a provider
+        Provider provider = new Provider();
+        // activate it
+        Component p = m.createComponent()
+            .setInterface(Service.class.getName(), null)
+            .setImplementation(provider);
+        
+        Client consumer = new Client(e);
+        Component c = m.createComponent()
+            .setImplementation(consumer)
+            .add(m.createServiceDependency()
+                .setService(Service.class)
+                .setRequired(true)
+                );
+        
+        m.add(p);
+        m.add(c);
+        e.waitForStep(1, 5000);
+        m.remove(p);
+        e.waitForStep(2, 5000);
+        m.remove(c);
+        m.clear();
+    }
+
+    public static class Client {
+        volatile Service m_service;
+        private final Ensure m_ensure;
+        
+        public Client(Ensure e) {
+            m_ensure = e;
+        }
+
+        public void start() {
+            System.out.println("start");
+            m_ensure.step(1);
+        }
+        
+        public void stop() {
+            System.out.println("stop");
+            m_ensure.step(2);
+        }
+    }
+    
+    public static interface Service {
+    }
+    
+    public static class Provider implements Service {
+    }
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/Ensure.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/Ensure.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/Ensure.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/Ensure.java Mon May 29 07:28:24 2017
@@ -0,0 +1,174 @@
+/*
+ * 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.itest.tests;
+
+import java.io.PrintStream;
+
+import org.junit.Assert;
+
+/**
+ * Helper class to make sure that steps in a test happen in the correct order. Instantiate
+ * this class and subsequently invoke <code>step(nr)</code> with steps starting at 1. You
+ * can also have threads wait until you arrive at a certain step.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class Ensure {
+    private final boolean DEBUG;
+    private static long INSTANCE = 0;
+    private static final int RESOLUTION = 100;
+    private static PrintStream STREAM = System.out;
+    int step = 0;
+    private Throwable m_throwable;
+    
+    public Ensure() {
+        this(true);
+    }
+    
+    public Ensure(boolean debug) {
+        DEBUG = debug;
+        if (DEBUG) {
+            INSTANCE++;
+        }
+    }
+
+    public void setStream(PrintStream output) {
+        STREAM = output;
+    }
+    
+    /**
+     * Mark this point as step <code>nr</code>.
+     * 
+     * @param nr the step we are in
+     */
+    public synchronized void step(int nr) {
+        step++;
+        Assert.assertEquals(nr, step);
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] step " + step + " [" + currentThread() + "] " + info);
+        }
+        notifyAll();
+    }
+
+    private String getLineInfo(int depth) {
+        StackTraceElement[] trace = Thread.currentThread().getStackTrace();
+        String info = trace[depth].getClassName() + "." + trace[depth].getMethodName() + ":" + trace[depth].getLineNumber();
+        return info;
+    }
+    
+    /**
+     * Mark this point as the next step.
+     */
+    public synchronized void step() {
+        step++;
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] next step " + step + " [" + currentThread() + "] " + info);
+        }
+        notifyAll();
+    }
+
+    /**
+     * Wait until we arrive at least at step <code>nr</code> in the process, or fail if that
+     * takes more than <code>timeout</code> milliseconds. If you invoke wait on a thread,
+     * you are effectively assuming some other thread will invoke the <code>step(nr)</code>
+     * method.
+     * 
+     * @param nr the step to wait for
+     * @param timeout the number of milliseconds to wait
+     */
+    public synchronized void waitForStep(int nr, int timeout) {
+        final int initialTimeout = timeout;
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] waiting for step " + nr + " [" + currentThread() + "] " + info);
+        }
+        while (step < nr && timeout > 0) {
+            try {
+                wait(RESOLUTION);
+                timeout -= RESOLUTION;
+            }
+            catch (InterruptedException e) {}
+        }
+        if (step < nr) {
+            throw new IllegalStateException("Timed out waiting for " + initialTimeout + " ms for step " + nr + ", we are still at step " + step);
+        }
+        if (DEBUG) {
+            String info = getLineInfo(3);
+            STREAM.println("[Ensure " + INSTANCE + "] arrived at step " + nr + " [" + currentThread() + "] " + info);
+        }
+    }
+    
+    private String currentThread() {
+        Thread thread = Thread.currentThread();
+        return thread.getId() + " " + thread.getName();
+    }
+    
+    public static Runnable createRunnableStep(final Ensure ensure, final int nr) {
+        return new Runnable() { public void run() { ensure.step(nr); }};
+    }
+    
+    public synchronized void steps(Steps steps) {
+        steps.next(this);
+    }
+    
+    /** 
+     * Helper class for naming a list of step numbers. If used with the steps(Steps) method
+     * you can define at which steps in time this point should be passed. That means you can
+     * check methods that will get invoked multiple times during a test.
+     */
+    public static class Steps {
+        private final int[] m_steps;
+        private int m_stepIndex;
+
+        /** 
+         * Create a list of steps and initialize the step counter to zero.
+         */
+        public Steps(int... steps) {
+            m_steps = steps;
+            m_stepIndex = 0;
+        }
+
+        /**
+         * Ensure we're at the right step. Will throw an index out of bounds exception if we enter this step more often than defined.
+         */
+        public void next(Ensure ensure) {
+            ensure.step(m_steps[m_stepIndex++]);
+        }
+    }
+
+    /**
+     * Saves a thrown exception that occurred in a different thread. You can only save one exception
+     * at a time this way.
+     */
+    public synchronized void throwable(Throwable throwable) {
+        m_throwable = throwable;
+    }
+
+    /**
+     * Throws a <code>Throwable</code> if one occurred in a different thread and that thread saved it
+     * using the <code>throwable()</code> method.
+     */
+    public synchronized void ensure() throws Throwable {
+        if (m_throwable != null) {
+            throw m_throwable;
+        }
+    }
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3008_FilterIndexStartupTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3008_FilterIndexStartupTest.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3008_FilterIndexStartupTest.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3008_FilterIndexStartupTest.java Mon May 29 07:28:24 2017
@@ -0,0 +1,87 @@
+/*
+ * 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.itest.tests;
+//import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartupFor;
+//import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
+
+import org.junit.Assert;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.Bundle;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FELIX3008_FilterIndexStartupTest extends TestBase {
+		
+    public void testNormalStart() throws Exception {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a provider
+        Provider provider = new Provider();
+        // activate it
+        Component p = m.createComponent()
+            .setInterface(Service.class.getName(), null)
+            .setImplementation(provider);
+        
+        Consumer consumer = new Consumer(e);
+        Component c = m.createComponent()
+            .setImplementation(consumer)
+            .add(m.createServiceDependency()
+                .setService(Service.class)
+                .setRequired(true)
+                );
+        
+        m.add(p);
+        m.add(c);
+        e.waitForStep(1, 5000);
+        m.remove(p);
+        e.waitForStep(2, 5000);
+        m.remove(c);
+        m.clear();
+        Assert.assertEquals("Dependency manager bundle should be active.", Bundle.ACTIVE, context.getBundle().getState());
+    }
+
+    public static class Consumer {
+        volatile Service m_service;
+        private final Ensure m_ensure;
+        
+        public Consumer(Ensure e) {
+            m_ensure = e;
+        }
+
+        public void start() {
+            System.out.println("start");
+            m_ensure.step(1);
+        }
+        
+        public void stop() {
+            System.out.println("stop");
+            m_ensure.step(2);
+        }
+    }
+    
+    public static interface Service {
+    }
+    
+    public static class Provider implements Service {
+    }
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3057_EmptyServiceReferenceArray.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3057_EmptyServiceReferenceArray.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3057_EmptyServiceReferenceArray.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FELIX3057_EmptyServiceReferenceArray.java Mon May 29 07:28:24 2017
@@ -0,0 +1,68 @@
+/*
+ * 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.itest.tests;
+//import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartupFor;
+//import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
+
+import org.junit.Assert;
+
+import java.util.function.Consumer;
+
+import org.apache.felix.dm.DependencyManager;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FELIX3057_EmptyServiceReferenceArray extends TestBase {
+	
+	private String m_systemConf;
+
+    @SuppressWarnings("unchecked")
+	public void testWithoutIndex() throws Exception {
+        // backup currently configured filter index
+        BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+    	m_systemConf = context.getProperty(DependencyManager.SERVICEREGISTRY_CACHE_INDICES);
+
+    	// Reset filter indices    	
+    	Consumer<String> reset = (Consumer<String>) System.getProperties().get("org.apache.felix.dependencymanager.filterindex.reset");
+        reset.accept(null); // clear filter index
+        
+        executeTest(context); // no filter index used
+        
+        reset.accept(m_systemConf); // reset filer index configured in our bnd.bnd
+    }
+    
+    public void testWithIndex() throws Exception {
+        executeTest(context); // SERVICEREGISTRY_CACHE_INDICES system property is configured in our bnd.bnd  
+    }
+
+    private void executeTest(BundleContext context) throws InvalidSyntaxException {
+        DependencyManager m = new DependencyManager(context);
+        Assert.assertNull("Looking up a non-existing service should return null.", m.getBundleContext().getServiceReferences(Service.class.getName(), "(objectClass=*)"));
+        Assert.assertNull("Looking up a non-existing service should return null.", m.getBundleContext().getAllServiceReferences(Service.class.getName(), "(objectClass=*)"));
+        Assert.assertNull("Looking up a non-existing service should return null.", m.getBundleContext().getServiceReference(Service.class.getName()));
+        m.clear();
+    }
+
+    /** Dummy interface for lookup. */
+    public static interface Service {}
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FilterIndexResourceAdapterTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FilterIndexResourceAdapterTest.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FilterIndexResourceAdapterTest.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/FilterIndexResourceAdapterTest.java Mon May 29 07:28:24 2017
@@ -0,0 +1,85 @@
+/*
+ * 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.itest.tests;
+
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+import org.apache.felix.dm.DependencyManager;
+import org.apache.felix.dm.ResourceHandler;
+import org.junit.Assert;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class FilterIndexResourceAdapterTest extends TestBase {
+	    
+    public void testBasicResourceAdapter() throws Exception {
+      DependencyManager m = getDM(); // filter index is configured in our bnd.bnd file
+      // helper class that ensures certain steps get executed in sequence
+      Ensure e = new Ensure();
+      // create a resource provider
+      ResourceProvider provider = new ResourceProvider(context, new URL("file://localhost/path/to/file1.txt"));
+      // activate it
+      m.add(m.createComponent().setImplementation(provider).add(m.createServiceDependency().setService(ResourceHandler.class).setCallbacks("add", "remove")));
+      // create a resource adapter for our single resource
+      // note that we can provide an actual implementation instance here because there will be only one
+      // adapter, normally you'd want to specify a Class here
+      m.add(m.createResourceAdapterService("(&(path=/path/to/*.txt)(host=localhost))", false, null, "changed")
+            .setImplementation(new ResourceAdapter(e)));
+      // wait until the single resource is available
+      e.waitForStep(3, 5000);
+      // trigger a 'change' in our resource
+      provider.change();
+      // wait until the changed callback is invoked
+      e.waitForStep(4, 5000);
+      m.clear();
+   }
+  
+  static class ResourceAdapter {
+      protected URL m_resource; // injected by reflection.
+      private Ensure m_ensure;
+      
+      ResourceAdapter(Ensure e) {
+          m_ensure = e;
+      }
+      
+      public void start() {
+          m_ensure.step(1);
+          Assert.assertNotNull("resource not injected", m_resource);
+          m_ensure.step(2);
+          try {
+              @SuppressWarnings("unused")
+              InputStream in = m_resource.openStream();
+          } 
+          catch (FileNotFoundException e) {
+              m_ensure.step(3);
+          }
+          catch (IOException e) {
+              Assert.fail("We should not have gotten this exception.");
+          }
+      }
+      
+      public void changed() {
+          m_ensure.step(4);
+      }
+  }  
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/ResourceProvider.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/ResourceProvider.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/ResourceProvider.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/ResourceProvider.java Mon May 29 07:28:24 2017
@@ -0,0 +1,121 @@
+/*
+ * 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.itest.tests;
+
+import java.net.URL;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.junit.Assert;
+import org.apache.felix.dm.ResourceHandler;
+import org.apache.felix.dm.ResourceUtil;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Filter;
+import org.osgi.framework.InvalidSyntaxException;
+import org.osgi.framework.ServiceReference;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class ResourceProvider {
+	final URL[] m_resources;
+    final BundleContext m_context;
+    final Map<ResourceHandler, Filter> m_handlers = new HashMap<>();
+
+    public ResourceProvider(BundleContext ctx, URL ... resources) {
+		m_context = ctx;
+		m_resources = resources;
+	}
+	
+    public void change() {
+        for (int i = 0; i < m_resources.length; i++) {
+        	change(i);
+        }    	
+    }
+    
+    @SuppressWarnings("deprecation")
+	public void change(int resourceIndex) {
+        Map<ResourceHandler, Filter> handlers = new HashMap<>();
+        synchronized (m_handlers) {
+            handlers.putAll(m_handlers);
+        }
+        for (Map.Entry<ResourceHandler, Filter> e : handlers.entrySet()) {
+        	ResourceHandler handler = e.getKey();
+        	Filter filter = e.getValue();
+        	if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[resourceIndex]))) {
+        		handler.changed(m_resources[resourceIndex]);
+            }
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+	public void add(ServiceReference ref, ResourceHandler handler) {
+        String filterString = (String) ref.getProperty("filter");
+        Filter filter = null;
+        if (filterString != null) {
+            try {
+                filter = m_context.createFilter(filterString);
+            }
+            catch (InvalidSyntaxException e) {
+                Assert.fail("Could not create filter for resource handler: " + e);
+                return;
+            }
+        }
+        for (int i = 0; i < m_resources.length; i++) {
+            if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i]))) {
+                synchronized (m_handlers) {
+                    m_handlers.put(handler, filter);
+                }
+                handler.added(m_resources[i]);
+            }
+        }
+    }
+
+    public void remove(ServiceReference ref, ResourceHandler handler) {
+        Filter filter;
+        synchronized (m_handlers) {
+            filter = (Filter) m_handlers.remove(handler);
+        }
+        if (filter != null) {
+        	removeResources(handler, filter);
+        }
+    }
+
+    @SuppressWarnings("deprecation")
+	private void removeResources(ResourceHandler handler, Filter filter) {
+            for (int i = 0; i < m_resources.length; i++) {
+                if (filter == null || filter.match(ResourceUtil.createProperties(m_resources[i]))) {
+                    handler.removed(m_resources[i]);
+                }
+            }
+        }
+
+    public void destroy() {
+        Map<ResourceHandler, Filter> handlers = new HashMap<>();
+        synchronized (m_handlers) {
+            handlers.putAll(m_handlers);
+        }
+
+        for (Map.Entry<ResourceHandler, Filter> e : handlers.entrySet()) {
+            ResourceHandler handler = e.getKey();
+            Filter filter = e.getValue();
+            removeResources(handler, filter);
+        }
+    }
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/StaticCustomIndexTest.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/StaticCustomIndexTest.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/StaticCustomIndexTest.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/StaticCustomIndexTest.java Mon May 29 07:28:24 2017
@@ -0,0 +1,121 @@
+/*
+ * 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.itest.tests;
+//import static org.ops4j.pax.exam.CoreOptions.waitForFrameworkStartupFor;
+//import static org.ops4j.pax.exam.container.def.PaxRunnerOptions.vmOption;
+
+import java.util.function.Consumer;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
+
+/**
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public class StaticCustomIndexTest extends TestBase {
+	
+	/**
+	 * This system property is set to true when the StaticCustomFilterIndex index has been opened.
+	 */
+	private final static String OPENED = "org.apache.felix.dm.index.itest.staticcustomindex.StaticCustomFilterIndex.opened";	
+	
+	private String m_systemConf;
+
+    @SuppressWarnings("unchecked")
+	public void setUp() throws Exception {    	  
+    	System.setProperty(OPENED, "false");
+    	
+        // backup currently configured filter index
+        BundleContext context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+        m_systemConf = context.getProperty(DependencyManager.SERVICEREGISTRY_CACHE_INDICES);
+    	
+    	// configure our filter index and use the special DM backdoor in order to reinitialize filter indices
+        Consumer<String> reset = (Consumer<String>) System.getProperties().get("org.apache.felix.dependencymanager.filterindex.reset");
+        reset.accept("org.apache.felix.dm.index.itest.staticcustomindex.StaticCustomFilterIndex:objectClass");
+        
+        // now call super.setUp() method: the getDM() method will return a DependencyManager that will use the filter index.
+        super.setUp();    	
+    }
+    	
+    public void tearDown() throws Exception {
+        super.tearDown();
+        System.getProperties().remove(OPENED);
+        Consumer<String> reset = (Consumer<String>) System.getProperties().get("org.apache.felix.dependencymanager.filterindex.reset");
+        reset.accept(m_systemConf);
+    }
+
+    public void testUsingStaticCustomIndex() throws Exception {
+        DependencyManager m = getDM();
+        // helper class that ensures certain steps get executed in sequence
+        Ensure e = new Ensure();
+        // create a provider
+        Provider provider = new Provider();
+        // activate it
+        Component p = m.createComponent()
+            .setInterface(Service.class.getName(), null)
+            .setImplementation(provider);
+        
+        Client consumer = new Client(e);
+        Component c = m.createComponent()
+            .setImplementation(consumer)
+            .add(m.createServiceDependency()
+                .setService(Service.class)
+                .setRequired(true)
+                );
+        
+        m.add(p);
+        m.add(c);
+        e.waitForStep(1, 5000);
+        m.remove(p);
+        e.waitForStep(2, 5000);
+        m.remove(c);
+        m.clear();
+        
+        // Make sure our static custom index has been used
+        Assert.assertTrue(Boolean.getBoolean(OPENED));
+    }
+
+    public static class Client {
+        volatile Service m_service;
+        private final Ensure m_ensure;
+        
+        public Client(Ensure e) {
+            m_ensure = e;
+        }
+
+        public void start() {
+            System.out.println("start");
+            m_ensure.step(1);
+        }
+        
+        public void stop() {
+            System.out.println("stop");
+            m_ensure.step(2);
+        }
+    }
+    
+    public static interface Service {
+    }
+    
+    public static class Provider implements Service {
+    }
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/TestBase.java
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/TestBase.java?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/TestBase.java (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/src/org/apache/felix/dm/index/itest/tests/TestBase.java Mon May 29 07:28:24 2017
@@ -0,0 +1,365 @@
+/*
+ * 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.itest.tests;
+
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Dictionary;
+import java.util.Hashtable;
+import java.util.concurrent.Executor;
+import java.util.concurrent.ForkJoinPool;
+import java.util.concurrent.TimeUnit;
+
+import org.apache.felix.dm.Component;
+import org.apache.felix.dm.ComponentExecutorFactory;
+import org.apache.felix.dm.DependencyManager;
+import org.junit.Assert;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.Constants;
+import org.osgi.framework.FrameworkEvent;
+import org.osgi.framework.FrameworkListener;
+import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.log.LogService;
+
+import junit.framework.TestCase;
+
+/**
+ * Base class for all integration tests.
+ * 
+ * @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
+ */
+public abstract class TestBase extends TestCase implements LogService, FrameworkListener {
+    // Default OSGI log service level.
+    protected final static int LOG_LEVEL = LogService.LOG_WARNING;
+    
+    // optional thread pool used by parallel dependency managers
+    protected volatile ForkJoinPool m_threadPool;
+    
+    // flag used to check if the threadpool must be used for a given test.
+    protected volatile boolean m_parallel;
+        
+    // Flag used to check if some errors have been logged during the execution of a given test.
+    private volatile boolean m_errorsLogged;
+
+    // We implement OSGI log service.
+    protected ServiceRegistration logService;
+    
+    // Our bundle context
+    protected BundleContext context;
+
+    // Our dependency manager used to create test components.
+    protected volatile DependencyManager m_dm;
+
+    // The Registration for the DM threadpool.
+    private ServiceRegistration m_componentExecutorFactoryReg;
+
+    public TestBase() {
+    }
+       
+    protected void setParallel() {
+        m_parallel = true;
+    }
+    
+    public void setUp() throws Exception {
+    	warn("Setting up test " + getClass().getName());
+    	context = FrameworkUtil.getBundle(this.getClass()).getBundleContext();
+    	Hashtable<String, Object> props = new Hashtable<>();
+    	props.put(Constants.SERVICE_RANKING, new Integer(Integer.MAX_VALUE));
+        logService = context.registerService(LogService.class.getName(), this, props);
+        context.addFrameworkListener(this);
+        m_dm = new DependencyManager(context);
+        if (m_parallel) {
+            warn("Using threadpool ...");
+            m_threadPool = new ForkJoinPool(Runtime.getRuntime().availableProcessors());
+            m_componentExecutorFactoryReg = context.registerService(ComponentExecutorFactory.class.getName(), 
+                new ComponentExecutorFactory() {
+                    @Override
+                    public Executor getExecutorFor(Component component) {
+                        return m_threadPool;
+                    }
+                },
+                null);
+        }
+    }
+    
+    public void tearDown() throws Exception {
+    	warn("Tearing down test " + getClass().getName());
+    	logService.unregister();
+    	context.removeFrameworkListener(this);
+        clearComponents();
+
+        if (m_parallel && m_componentExecutorFactoryReg != null) {
+    	    m_componentExecutorFactoryReg.unregister();
+    	    m_threadPool.shutdown();
+            try {
+                m_threadPool.awaitTermination(60, TimeUnit.SECONDS);
+            } catch (InterruptedException e) {
+            }
+    	}
+        Assert.assertFalse(errorsLogged());
+    }
+        
+    protected DependencyManager getDM() {
+        return m_dm;
+    }
+                
+    protected void clearComponents() {
+        m_dm.clear();
+        warn("All component cleared.");
+    }
+
+    /**
+     * Creates and provides an Ensure object with a name service property into the OSGi service registry.
+     */
+    protected ServiceRegistration register(Ensure e, String name) {
+        Hashtable<String, String> props = new Hashtable<String, String>();
+        props.put("name", name);
+        return context.registerService(Ensure.class.getName(), e, props);
+    }
+
+    /**
+     * Helper method used to stop a given bundle.
+     * 
+     * @param symbolicName
+     *            the symbolic name of the bundle to be stopped.
+     */
+    protected void stopBundle(String symbolicName) {
+        // Stop the test.annotation bundle
+        boolean found = false;
+        for (Bundle b : context.getBundles()) {
+            if (b.getSymbolicName().equals(symbolicName)) {
+                try {
+                    found = true;
+                    b.stop();
+                } catch (BundleException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        if (!found) {
+            throw new IllegalStateException("bundle " + symbolicName + " not found");
+        }
+    }
+
+    /**
+     * Helper method used to start a given bundle.
+     * 
+     * @param symbolicName
+     *            the symbolic name of the bundle to be started.
+     */
+    protected void startBundle(String symbolicName) {
+        // Stop the test.annotation bundle
+        boolean found = false;
+        for (Bundle b : context.getBundles()) {
+            if (b.getSymbolicName().equals(symbolicName)) {
+                try {
+                    found = true;
+                    b.start();
+                } catch (BundleException e) {
+                    e.printStackTrace();
+                }
+            }
+        }
+        if (!found) {
+            throw new IllegalStateException("bundle " + symbolicName + " not found");
+        }
+    }
+
+    /**
+     * Helper method used to get a given bundle.
+     * 
+     * @param symbolicName
+     *            the symbolic name of the bundle to get.
+     */
+    protected Bundle getBundle(String symbolicName) {
+        for (Bundle b : context.getBundles()) {
+            if (b.getSymbolicName().equals(symbolicName)) {
+                return b;
+            }
+        }
+        throw new IllegalStateException("bundle " + symbolicName + " not found");
+    }
+    
+    /**
+     * Suspend the current thread for a while.
+     * 
+     * @param n
+     *            the number of milliseconds to wait for.
+     */
+    protected void sleep(int ms) {
+        try {
+            Thread.sleep(ms);
+        } catch (InterruptedException e) {
+        }
+    }
+    
+    /**
+     * Helper method used to convert a dictionary which with untyped keys to a dictionary having a String key.
+     * (this method is useful when converting a Properties object into a compatible Dictionary<String, Object>
+     * object that is often needed in OSGI R6 API. 
+     */
+    @SuppressWarnings("unchecked")
+	public static Dictionary<String, ?> toR6Dictionary(Dictionary<?,?> properties) {
+    	return (Dictionary<String, ?>) properties;
+    }
+
+    public void log(int level, String message) {
+        checkError(level, null);
+        if (LOG_LEVEL >= level) {
+            System.out.println(getLevel(level) + " - " + Thread.currentThread().getName() + " : " + message);
+        }
+    }
+
+    public void log(int level, String message, Throwable exception) {
+        checkError(level, exception);
+        if (LOG_LEVEL >= level) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
+            sb.append(message);
+            parse(sb, exception);
+            System.out.println(sb.toString());
+        }
+    }
+
+    public void log(ServiceReference sr, int level, String message) {
+        checkError(level, null);
+        if (LOG_LEVEL >= level) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
+            sb.append(message);
+            System.out.println(sb.toString());
+        }
+    }
+
+    public void log(ServiceReference sr, int level, String message, Throwable exception) {
+        checkError(level, exception);
+        if (LOG_LEVEL >= level) {
+            StringBuilder sb = new StringBuilder();
+            sb.append(getLevel(level) + " - " + Thread.currentThread().getName() + " : ");
+            sb.append(message);
+            parse(sb, exception);
+            System.out.println(sb.toString());
+        }
+    }
+
+    protected boolean errorsLogged() {
+        return m_errorsLogged;
+    }
+
+    private void parse(StringBuilder sb, Throwable t) {
+        if (t != null) {
+            sb.append(" - ");
+            StringWriter buffer = new StringWriter();
+            PrintWriter pw = new PrintWriter(buffer);
+            t.printStackTrace(pw);
+            sb.append(buffer.toString());
+            m_errorsLogged = true;
+        }
+    }
+
+    private String getLevel(int level) {
+        switch (level) {
+            case LogService.LOG_DEBUG :
+                return "DEBUG";
+            case LogService.LOG_ERROR :
+                return "ERROR";
+            case LogService.LOG_INFO :
+                return "INFO";
+            case LogService.LOG_WARNING :
+                return "WARN";
+            default :
+                return "";
+        }
+    }
+
+    private void checkError(int level, Throwable exception) {
+        if (level <= LOG_ERROR) {
+            m_errorsLogged = true;
+        }
+        if (exception != null) {
+            m_errorsLogged = true;
+        }
+    }
+
+    public void frameworkEvent(FrameworkEvent event) {
+        int eventType = event.getType();
+        String msg = getFrameworkEventMessage(eventType);
+        int level = (eventType == FrameworkEvent.ERROR) ? LOG_ERROR : LOG_WARNING;
+        if (msg != null) {
+            log(level, msg, event.getThrowable());
+        } else {
+            log(level, "Unknown fwk event: " + event);
+        }
+    }
+
+    private String getFrameworkEventMessage(int event) {
+        switch (event) {
+            case FrameworkEvent.ERROR :
+                return "FrameworkEvent: ERROR";
+            case FrameworkEvent.INFO :
+                return "FrameworkEvent INFO";
+            case FrameworkEvent.PACKAGES_REFRESHED :
+                return "FrameworkEvent: PACKAGE REFRESHED";
+            case FrameworkEvent.STARTED :
+                return "FrameworkEvent: STARTED";
+            case FrameworkEvent.STARTLEVEL_CHANGED :
+                return "FrameworkEvent: STARTLEVEL CHANGED";
+            case FrameworkEvent.WARNING :
+                return "FrameworkEvent: WARNING";
+            default :
+                return null;
+        }
+    }
+
+    protected void warn(String msg, Object ... params) {
+	if (LOG_LEVEL >= LogService.LOG_WARNING) {
+	    log(LogService.LOG_WARNING, params.length > 0 ? String.format(msg, params) : msg);
+	}
+    }
+
+    @SuppressWarnings("unused")
+    protected void info(String msg, Object ... params) {
+	if (LOG_LEVEL >= LogService.LOG_INFO) {
+	    log(LogService.LOG_INFO, params.length > 0 ? String.format(msg, params) : msg);
+	}
+    }
+
+    @SuppressWarnings("unused")
+    protected void debug(String msg, Object ... params) {
+	if (LOG_LEVEL >= LogService.LOG_DEBUG) {
+	    log(LogService.LOG_DEBUG, params.length > 0 ? String.format(msg, params) : msg);
+	}
+    }
+
+    protected void error(String msg, Object ... params) {
+        log(LogService.LOG_ERROR, params.length > 0 ? String.format(msg, params) : msg);
+    }
+
+    protected void error(String msg, Throwable err, Object ... params) {
+        log(LogService.LOG_ERROR, params.length > 0 ? String.format(msg, params) : msg, err);
+    }
+
+    protected void error(Throwable err) {
+        log(LogService.LOG_ERROR, "error", err);
+    }
+}

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/static.customindex.bnd
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/static.customindex.bnd?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/static.customindex.bnd (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/static.customindex.bnd Mon May 29 07:28:24 2017
@@ -0,0 +1,23 @@
+#
+# 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.
+#
+Private-Package: org.apache.felix.dm.index.itest.staticcustomindex
+Fragment-Host: org.apache.felix.dependencymanager
+Import-Package: !org.apache.felix.dm.*,*
+Bundle-Name: Apache Felix Dependency Manager integration tests Static Custom Index
+Bundle-Category: test
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Vendor: The Apache Software Foundation

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/test/.gitignore
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/test/.gitignore?rev=1796580&view=auto
==============================================================================
    (empty)

Added: felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/tests.bnd
URL: http://svn.apache.org/viewvc/felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/tests.bnd?rev=1796580&view=auto
==============================================================================
--- felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/tests.bnd (added)
+++ felix/trunk/dependencymanager/org.apache.felix.dependencymanager.index.itest/tests.bnd Mon May 29 07:28:24 2017
@@ -0,0 +1,21 @@
+#
+# 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.
+#
+Private-Package: org.apache.felix.dm.index.itest.tests
+Bundle-Name: Apache Felix Dependency Manager FilterIndex tests
+Bundle-Category: test
+Bundle-License: http://www.apache.org/licenses/LICENSE-2.0.txt
+Bundle-Vendor: The Apache Software Foundation