FELIX-2033: Provide an easy to use layer for writing pax-exam test for Karaf

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@906084 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/tooling/testing/pom.xml b/karaf/tooling/testing/pom.xml
index 4008c9b..7f29aba 100644
--- a/karaf/tooling/testing/pom.xml
+++ b/karaf/tooling/testing/pom.xml
@@ -39,6 +39,13 @@
     </properties>
 
     <dependencies>
+        <!-- The assembly and all the dependencies -->
+        <dependency>
+            <groupId>org.apache.felix.karaf</groupId>
+            <artifactId>apache-felix-karaf</artifactId>
+            <type>xml</type>
+            <classifier>features</classifier>
+        </dependency>
         <!-- Pax EXAM -->
         <dependency>
             <groupId>org.ops4j.pax.exam</groupId>
@@ -57,9 +64,8 @@
             <artifactId>pax-exam-junit-extender-impl</artifactId>
         </dependency>
         <dependency>
-            <groupId>junit</groupId>
-            <artifactId>junit</artifactId>
-            <version>4.5</version>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
         </dependency>
     </dependencies>
 
diff --git a/karaf/tooling/testing/src/main/java/org/apache/felix/karaf/testing/Helper.java b/karaf/tooling/testing/src/main/java/org/apache/felix/karaf/testing/Helper.java
index f41a716..1243eb9 100644
--- a/karaf/tooling/testing/src/main/java/org/apache/felix/karaf/testing/Helper.java
+++ b/karaf/tooling/testing/src/main/java/org/apache/felix/karaf/testing/Helper.java
@@ -16,31 +16,20 @@
  */
 package org.apache.felix.karaf.testing;
 
+import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
 import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
-import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 
 import org.ops4j.pax.exam.CoreOptions;
-import org.ops4j.pax.exam.Inject;
 import org.ops4j.pax.exam.Option;
 import org.ops4j.pax.exam.options.MavenArtifactProvisionOption;
 import org.ops4j.pax.exam.options.SystemPropertyOption;
-import org.osgi.framework.Bundle;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.Constants;
-import org.osgi.framework.Filter;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
-import org.osgi.util.tracker.ServiceTracker;
 
 import static org.ops4j.pax.exam.CoreOptions.bootClasspathLibrary;
 import static org.ops4j.pax.exam.CoreOptions.frameworkStartLevel;
@@ -48,42 +37,222 @@
 import static org.ops4j.pax.exam.CoreOptions.wrappedBundle;
 import static org.ops4j.pax.exam.OptionUtils.combine;
 
+/**
+ * Helper class for setting up a pax-exam test environment for karaf.
+ *
+ * A simple configuration for pax-exam can be create using the following
+ * code:
+ * <pre>
+ *   @Configuration
+ *   public static Option[] configuration() throws Exception{
+ *       return combine(
+ *           // Default karaf environment
+ *           Helper.getDefaultOptions(),
+ *           // Test on both equinox and felix
+ *           equinox(), felix()
+ *       );
+ *   }
+ * </pre>
+ *
+ */
 public final class Helper {
 
     private Helper() {
     }
 
+    /**
+     *  Create an provisioning option for the specified maven artifact
+     * (groupId and artifactId), using the version found in the list
+     * of dependencies of this maven project.
+     *
+     * @param groupId the groupId of the maven bundle
+     * @param artifactId the artifactId of the maven bundle
+     * @return the provisioning option for the given bundle
+     */
     public static MavenArtifactProvisionOption mavenBundle(String groupId, String artifactId) {
-        return CoreOptions.mavenBundle().groupId(groupId).artifactId(artifactId).versionAsInProject();
+        return CoreOptions.mavenBundle(groupId, artifactId).versionAsInProject();
     }
 
-    /*
-     * Explode the dictionary into a ,-delimited list of key=value pairs
+    /**
+     * Return a map of system properties for karaf.
+     * The default karaf home directory is "target/karaf.home".
+     *
+     * @return a list of system properties for karaf
      */
-    private static String explode(Dictionary dictionary) {
-        Enumeration keys = dictionary.keys();
-        StringBuffer result = new StringBuffer();
-        while (keys.hasMoreElements()) {
-            Object key = keys.nextElement();
-            result.append(String.format("%s=%s", key, dictionary.get(key)));
-            if (keys.hasMoreElements()) {
-                result.append(", ");
-            }
-        }
-        return result.toString();
+    public static Properties getDefaultSystemOptions() {
+        return getDefaultSystemOptions("target/karaf.home");
     }
 
-    /*
-     * Provides an iterable collection of references, even if the original array is null
+    /**
+     * Return a map of system properties for karaf,
+     * using the specified folder for the karaf home directory.
+     *
+     * @param karafHome the karaf home directory
+     * @return a list of system properties for karaf
      */
-    private static final Collection<ServiceReference> asCollection(ServiceReference[] references) {
-        List<ServiceReference> result = new LinkedList<ServiceReference>();
-        if (references != null) {
-            for (ServiceReference reference : references) {
-                result.add(reference);
+    public static Properties getDefaultSystemOptions(String karafHome) {
+        Properties sysProps = new Properties();
+        sysProps.setProperty("karaf.name", "root");
+        sysProps.setProperty("karaf.home", karafHome);
+        sysProps.setProperty("karaf.base", karafHome);
+        sysProps.setProperty("karaf.startLocalConsole", "false");
+        sysProps.setProperty("karaf.startRemoteShell", "false");
+        sysProps.setProperty("org.osgi.framework.startlevel.beginning", "100");
+        return sysProps;
+    }
+
+    /**
+     * Return an array of pax-exam options to correctly configure the osgi
+     * framework for karaf.
+     *
+     * @return default pax-exam options for karaf osgi framework
+     */
+    public static Option[] getDefaultConfigOptions() {
+        return getDefaultConfigOptions(getDefaultSystemOptions(),
+                                       getResource("/org/apache/felix/karaf/testing/config.properties"));
+    }
+
+    /**
+     * Return an array of pax-exam options to configure the osgi
+     * framework for karaf, given the system properties and the
+     * location of the osgi framework properties file.
+     *
+     * @param sysProps karaf system properties
+     * @param configProperties the URL to load the osgi framework properties from
+     * @return pax-exam options for karaf osgi framework
+     */
+    public static Option[] getDefaultConfigOptions(Properties sysProps, URL configProperties) {
+        // Load props
+        Properties configProps = loadProperties(configProperties);
+        // Set system props
+        for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements();) {
+            String key = (String) e.nextElement();
+            configProps.setProperty(key, sysProps.getProperty(key));
+        }
+        // Perform variable substitution for system properties.
+        for (Enumeration e = configProps.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            configProps.setProperty(name, substVars(configProps.getProperty(name), name, null, configProps));
+        }
+        // Transform to sys props options
+        List<Option> options = new ArrayList<Option>();
+        for (Enumeration e = configProps.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            String value = configProps.getProperty(name);
+            value = value.replaceAll("\r", "").replaceAll("\n", "").replaceAll(" ", "");
+            options.add(new SystemPropertyOption(name).value(value));
+        }
+        if (configProps.getProperty("org.osgi.framework.startlevel.beginning") != null) {
+            options.add(frameworkStartLevel(Integer.parseInt(configProps.getProperty("org.osgi.framework.startlevel.beginning"))));
+        }
+        return options.toArray(new Option[options.size()]);
+    }
+
+    /**
+     * Return an array of pax-exam options for the provisioning of karaf system bundles.
+     *
+     * @return an array of pax-exam options for provisioning karaf system bundles
+     */
+    public static Option[] getDefaultProvisioningOptions() {
+        return getDefaultProvisioningOptions(getDefaultSystemOptions(),
+                                            getResource("/org/apache/felix/karaf/testing/startup.properties"));
+    }
+
+    /**
+     * Return an array of pax-exam options for the provisioning of karaf system bundles,
+     * given the karaf system properties and the location of the startup bundles config file.
+     *
+     * @param sysProps karaf system properties
+     * @param startupProperties the URL to load the system bundles from
+     * @return an array of pax-exam options for provisioning karaf system bundles
+     */
+    public static Option[] getDefaultProvisioningOptions(Properties sysProps, URL startupProperties) {
+        Properties startupProps = loadProperties(startupProperties);
+        // Perform variable substitution for system properties.
+        for (Enumeration e = startupProps.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            startupProps.setProperty(name, substVars(startupProps.getProperty(name), name, null, sysProps));
+        }
+        // Transform to sys props options
+        List<Option> options = new ArrayList<Option>();
+        options.add(bootClasspathLibrary(mavenBundle("org.apache.felix.karaf.jaas", "org.apache.felix.karaf.jaas.boot")).afterFramework());
+        options.add(bootClasspathLibrary(mavenBundle("org.apache.felix.karaf", "org.apache.felix.karaf.main")).afterFramework());
+        for (Enumeration e = startupProps.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            String value = startupProps.getProperty(name);
+            MavenArtifactProvisionOption opt = convertToMaven(name);
+            if (opt.getURL().contains("org.apache.felix.karaf.features")) {
+                opt.noStart();
+            }
+            opt.startLevel(Integer.parseInt(value));
+            options.add(opt);
+        }
+        options.add(mavenBundle("org.apache.felix.karaf.tooling", "org.apache.felix.karaf.tooling.testing"));
+        // We need to add pax-exam-junit here when running with the ibm
+        // jdk to avoid the following exception during the test run:
+        // ClassNotFoundException: org.ops4j.pax.exam.junit.Configuration
+        if ("IBM Corporation".equals(System.getProperty("java.vendor"))) {
+            options.add(wrappedBundle(maven("org.ops4j.pax.exam", "pax-exam-junit")));
+        }
+        return options.toArray(new Option[options.size()]);
+    }
+
+    /**
+     * Return an array of options for setting up a pax-exam test environment for karaf.
+     *
+     * @return an array of pax-exam options
+     */
+    public static Option[] getDefaultOptions() {
+        return combine(getDefaultConfigOptions(), getDefaultProvisioningOptions());
+    }
+
+    /**
+     * Retrieve the pax-exam option for provisioning the given maven bundle.
+     *
+     * @param options the list of pax-exam options
+     * @param groupId the maven group id
+     * @param artifactId the maven artifact id
+     * @return the pax-exam provisioning option for the bundle or <code>null</code> if not found
+     */
+    public static MavenArtifactProvisionOption findMaven(Option[] options, String groupId, String artifactId) {
+        for (Option option : options) {
+            if (option instanceof MavenArtifactProvisionOption) {
+                MavenArtifactProvisionOption mvn = (MavenArtifactProvisionOption) option;
+                if (mvn.getURL().startsWith("mvn:" + groupId + "/" + artifactId + "/")) {
+                    return mvn;
+                }
             }
         }
-        return result;
+        return null;
+    }
+
+    private static Properties loadProperties(URL location) {
+        try {
+            Properties props = new Properties();
+            InputStream is = location.openStream();
+            try {
+                props.load(is);
+            } finally {
+                is.close();
+            }
+            return props;
+        } catch (IOException e) {
+            throw new RuntimeException("Unable to load properties from " + location, e);
+        }
+    }
+
+    private static URL getResource(String location) {
+        URL url = null;
+        if (Thread.currentThread().getContextClassLoader() != null) {
+            url = Thread.currentThread().getContextClassLoader().getResource(location);
+        }
+        if (url == null) {
+            url = Helper.class.getResource(location);
+        }
+        if (url == null) {
+            throw new RuntimeException("Unable to find resource " + location);
+        }
+        return url;
     }
 
     private static final String DELIM_START = "${";
@@ -226,481 +395,4 @@
         }
     }
 
-    public static Properties getDefaultSystemOptions() {
-        return getDefaultSystemOptions("target/karaf.home");
-    }
-
-    public static Properties getDefaultSystemOptions(String karafHome) {
-        Properties sysProps = new Properties();
-        sysProps.setProperty("karaf.name", "root");
-        sysProps.setProperty("karaf.home", karafHome);
-        sysProps.setProperty("karaf.base", karafHome);
-        sysProps.setProperty("karaf.startLocalConsole", "false");
-        sysProps.setProperty("karaf.startRemoteShell", "false");
-        sysProps.setProperty("org.osgi.framework.startlevel.beginning", "100");
-        return sysProps;
-    }
-
-    public static Option[] getDefaultConfigOptions() throws Exception {
-        return getDefaultConfigOptions(getDefaultSystemOptions(),
-                                       getResource("/org/apache/felix/karaf/testing/config.properties"));
-    }
-
-    public static Option[] getDefaultConfigOptions(Properties sysProps, URL configProperties) throws Exception {
-        // Load props
-        Properties configProps = new Properties();
-        InputStream is = configProperties.openStream();
-        try {
-            configProps.load(is);
-        } finally {
-            is.close();
-        }
-        // Set system props
-        for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements();) {
-            String key = (String) e.nextElement();
-            configProps.setProperty(key, sysProps.getProperty(key));
-        }
-        // Perform variable substitution for system properties.
-        for (Enumeration e = configProps.propertyNames(); e.hasMoreElements();) {
-            String name = (String) e.nextElement();
-            configProps.setProperty(name, substVars(configProps.getProperty(name), name, null, configProps));
-        }
-        // Transform to sys props options
-        List<Option> options = new ArrayList<Option>();
-        for (Enumeration e = configProps.propertyNames(); e.hasMoreElements();) {
-            String name = (String) e.nextElement();
-            String value = configProps.getProperty(name);
-            value = value.replaceAll("\r", "").replaceAll("\n", "").replaceAll(" ", "");
-            options.add(new SystemPropertyOption(name).value(value));
-            System.err.println("sysprop: " + name + " = " + value);
-        }
-        if (configProps.getProperty("org.osgi.framework.startlevel.beginning") != null) {
-            options.add(frameworkStartLevel(Integer.parseInt(configProps.getProperty("org.osgi.framework.startlevel.beginning"))));
-        }
-        return options.toArray(new Option[options.size()]);
-    }
-
-    public static Option[] getDefaultProvisioningOptions() throws Exception {
-        return getDefaultProvisioningOptions(getDefaultSystemOptions(),
-                                            getResource("/org/apache/felix/karaf/testing/startup.properties"));
-    }
-
-    private static URL getResource(String location) throws Exception {
-        URL url = null;
-        if (Thread.currentThread().getContextClassLoader() != null) {
-            url = Thread.currentThread().getContextClassLoader().getResource(location);
-        }
-        if (url == null) {
-            url = Helper.class.getResource(location);
-        }
-        System.err.println("Trying to load resource: " + location + ". Found: " + url);
-        return url;
-    }
-
-    public static Option[] getDefaultProvisioningOptions(Properties sysProps, URL configProperties) throws Exception {
-        Properties startupProps = new Properties();
-        InputStream is = configProperties.openStream();
-        try {
-            startupProps.load(is);
-        } finally {
-            is.close();
-        }
-        // Perform variable substitution for system properties.
-        for (Enumeration e = startupProps.propertyNames(); e.hasMoreElements();) {
-            String name = (String) e.nextElement();
-            startupProps.setProperty(name, substVars(startupProps.getProperty(name), name, null, sysProps));
-        }
-        // Transform to sys props options
-        List<Option> options = new ArrayList<Option>();
-        options.add(bootClasspathLibrary(mavenBundle("org.apache.felix.karaf.jaas", "org.apache.felix.karaf.jaas.boot")).afterFramework());
-        options.add(bootClasspathLibrary(mavenBundle("org.apache.felix.karaf", "org.apache.felix.karaf.main")).afterFramework());
-        for (Enumeration e = startupProps.propertyNames(); e.hasMoreElements();) {
-            String name = (String) e.nextElement();
-            String value = startupProps.getProperty(name);
-            MavenArtifactProvisionOption opt = convertToMaven(name);
-            if (opt.getURL().contains("org.apache.felix.karaf.features")) {
-                opt.noStart();
-            }
-            opt.startLevel(Integer.parseInt(value));
-            options.add(opt);
-        }
-        options.add(mavenBundle("org.apache.felix.karaf.tooling", "org.apache.felix.karaf.tooling.testing"));
-        // We need to add pax-exam-junit here when running with the ibm
-        // jdk to avoid the following exception during the test run:
-        // ClassNotFoundException: org.ops4j.pax.exam.junit.Configuration
-        if ("IBM Corporation".equals(System.getProperty("java.vendor"))) {
-            options.add(wrappedBundle(maven("org.ops4j.pax.exam", "pax-exam-junit")));
-        }
-        return options.toArray(new Option[options.size()]);
-    }
-
-    public static Option[] getDefaultOptions() throws Exception {
-        return combine(getDefaultConfigOptions(), getDefaultProvisioningOptions());
-    }
-
-    public static MavenArtifactProvisionOption findMaven(Option[] options, String groupId, String artifactId) {
-        for (Option option : options) {
-            if (option instanceof MavenArtifactProvisionOption) {
-                MavenArtifactProvisionOption mvn = (MavenArtifactProvisionOption) option;
-                if (mvn.getURL().startsWith("mvn:" + groupId + "/" + artifactId + "/")) {
-                    return mvn;
-                }
-            }
-        }
-        return null;
-    }
-
-    public abstract static class AbstractIntegrationTest {
-
-        public static final long DEFAULT_TIMEOUT = 30000;
-
-        @Inject
-        protected BundleContext bundleContext;
-
-        protected <T> T getOsgiService(Class<T> type, long timeout) {
-            return getOsgiService(type, null, timeout);
-        }
-
-        protected <T> T getOsgiService(Class<T> type) {
-            return getOsgiService(type, null, DEFAULT_TIMEOUT);
-        }
-
-        protected <T> T getOsgiService(Class<T> type, String filter, long timeout) {
-            ServiceTracker tracker = null;
-            try {
-                String flt;
-                if (filter != null) {
-                    if (filter.startsWith("(")) {
-                        flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")" + filter + ")";
-                    } else {
-                        flt = "(&(" + Constants.OBJECTCLASS + "=" + type.getName() + ")(" + filter + "))";
-                    }
-                } else {
-                    flt = "(" + Constants.OBJECTCLASS + "=" + type.getName() + ")";
-                }
-                Filter osgiFilter = FrameworkUtil.createFilter(flt);
-                tracker = new ServiceTracker(bundleContext, osgiFilter, null);
-                tracker.open(true);
-                // Note that the tracker is not closed to keep the reference
-                // This is buggy, as the service reference may change i think
-                Object svc = type.cast(tracker.waitForService(timeout));
-                if (svc == null) {
-                    Dictionary dic = bundleContext.getBundle().getHeaders();
-                    System.err.println("Test bundle headers: " + explode(dic));
-
-                    for (ServiceReference ref : asCollection(bundleContext.getAllServiceReferences(null, null))) {
-                        System.err.println("ServiceReference: " + ref);
-                    }
-
-                    for (ServiceReference ref : asCollection(bundleContext.getAllServiceReferences(null, flt))) {
-                        System.err.println("Filtered ServiceReference: " + ref);
-                    }
-
-                    throw new RuntimeException("Gave up waiting for service " + flt);
-                }
-                return type.cast(svc);
-            } catch (InvalidSyntaxException e) {
-                throw new IllegalArgumentException("Invalid filter", e);
-            } catch (InterruptedException e) {
-                throw new RuntimeException(e);
-            }
-        }
-
-        protected Bundle installBundle(String groupId, String artifactId) throws Exception {
-            MavenArtifactProvisionOption mvnUrl = mavenBundle(groupId, artifactId);
-            return bundleContext.installBundle(mvnUrl.getURL());
-        }
-
-        protected Bundle getInstalledBundle(String symbolicName) {
-            for (Bundle b : bundleContext.getBundles()) {
-                if (b.getSymbolicName().equals(symbolicName)) {
-                    return b;
-                }
-            }
-            return null;
-        }
-
-        public static MavenArtifactProvisionOption mavenBundle(String groupId, String artifactId) {
-            return CoreOptions.mavenBundle().groupId(groupId).artifactId(artifactId).versionAsInProject();
-        }
-
-        /*
-         * Explode the dictionary into a ,-delimited list of key=value pairs
-         */
-        private static String explode(Dictionary dictionary) {
-            Enumeration keys = dictionary.keys();
-            StringBuffer result = new StringBuffer();
-            while (keys.hasMoreElements()) {
-                Object key = keys.nextElement();
-                result.append(String.format("%s=%s", key, dictionary.get(key)));
-                if (keys.hasMoreElements()) {
-                    result.append(", ");
-                }
-            }
-            return result.toString();
-        }
-
-        /*
-         * Provides an iterable collection of references, even if the original array is null
-         */
-        private static final Collection<ServiceReference> asCollection(ServiceReference[] references) {
-            List<ServiceReference> result = new LinkedList<ServiceReference>();
-            if (references != null) {
-                for (ServiceReference reference : references) {
-                    result.add(reference);
-                }
-            }
-            return result;
-        }
-
-        private static final String DELIM_START = "${";
-        private static final String DELIM_STOP = "}";
-
-        /**
-         * <p>
-         * This method performs property variable substitution on the
-         * specified value. If the specified value contains the syntax
-         * <tt>${&lt;prop-name&gt;}</tt>, where <tt>&lt;prop-name&gt;</tt>
-         * refers to either a configuration property or a system property,
-         * then the corresponding property value is substituted for the variable
-         * placeholder. Multiple variable placeholders may exist in the
-         * specified value as well as nested variable placeholders, which
-         * are substituted from inner most to outer most. Configuration
-         * properties override system properties.
-         * </p>
-         *
-         * @param val         The string on which to perform property substitution.
-         * @param currentKey  The key of the property being evaluated used to
-         *                    detect cycles.
-         * @param cycleMap    Map of variable references used to detect nested cycles.
-         * @param configProps Set of configuration properties.
-         * @return The value of the specified string after system property substitution.
-         * @throws IllegalArgumentException If there was a syntax error in the
-         *                                  property placeholder syntax or a recursive variable reference.
-         */
-        private static String substVars(String val, String currentKey,
-                                        Map<String, String> cycleMap, Properties configProps)
-                throws IllegalArgumentException {
-            // If there is currently no cycle map, then create
-            // one for detecting cycles for this invocation.
-            if (cycleMap == null) {
-                cycleMap = new HashMap<String, String>();
-            }
-
-            // Put the current key in the cycle map.
-            cycleMap.put(currentKey, currentKey);
-
-            // Assume we have a value that is something like:
-            // "leading ${foo.${bar}} middle ${baz} trailing"
-
-            // Find the first ending '}' variable delimiter, which
-            // will correspond to the first deepest nested variable
-            // placeholder.
-            int stopDelim = val.indexOf(DELIM_STOP);
-
-            // Find the matching starting "${" variable delimiter
-            // by looping until we find a start delimiter that is
-            // greater than the stop delimiter we have found.
-            int startDelim = val.indexOf(DELIM_START);
-            while (stopDelim >= 0) {
-                int idx = val.indexOf(DELIM_START, startDelim + DELIM_START.length());
-                if ((idx < 0) || (idx > stopDelim)) {
-                    break;
-                } else if (idx < stopDelim) {
-                    startDelim = idx;
-                }
-            }
-
-            // If we do not have a start or stop delimiter, then just
-            // return the existing value.
-            if ((startDelim < 0) && (stopDelim < 0)) {
-                return val;
-            }
-            // At this point, we found a stop delimiter without a start,
-            // so throw an exception.
-            else if (((startDelim < 0) || (startDelim > stopDelim))
-                    && (stopDelim >= 0)) {
-                throw new IllegalArgumentException(
-                        "stop delimiter with no start delimiter: "
-                                + val);
-            }
-
-            // At this point, we have found a variable placeholder so
-            // we must perform a variable substitution on it.
-            // Using the start and stop delimiter indices, extract
-            // the first, deepest nested variable placeholder.
-            String variable =
-                    val.substring(startDelim + DELIM_START.length(), stopDelim);
-
-            // Verify that this is not a recursive variable reference.
-            if (cycleMap.get(variable) != null) {
-                throw new IllegalArgumentException(
-                        "recursive variable reference: " + variable);
-            }
-
-            // Get the value of the deepest nested variable placeholder.
-            // Try to configuration properties first.
-            String substValue = (configProps != null)
-                    ? configProps.getProperty(variable, null)
-                    : null;
-            if (substValue == null) {
-                // Ignore unknown property values.
-                substValue = System.getProperty(variable, "");
-            }
-
-            // Remove the found variable from the cycle map, since
-            // it may appear more than once in the value and we don't
-            // want such situations to appear as a recursive reference.
-            cycleMap.remove(variable);
-
-            // Append the leading characters, the substituted value of
-            // the variable, and the trailing characters to get the new
-            // value.
-            val = val.substring(0, startDelim)
-                    + substValue
-                    + val.substring(stopDelim + DELIM_STOP.length(), val.length());
-
-            // Now perform substitution again, since there could still
-            // be substitutions to make.
-            val = substVars(val, currentKey, cycleMap, configProps);
-
-            // Return the value.
-            return val;
-        }
-
-        private static MavenArtifactProvisionOption convertToMaven(String location) {
-            String[] p = location.split("/");
-            if (p.length >= 4 && p[p.length-1].startsWith(p[p.length-3] + "-" + p[p.length-2])) {
-                MavenArtifactProvisionOption opt = new MavenArtifactProvisionOption();
-                int artifactIdVersionLength = p[p.length-3].length() + 1 + p[p.length-2].length(); // (artifactId + "-" + version).length
-                if (p[p.length-1].charAt(artifactIdVersionLength) == '-') {
-                    opt.classifier((p[p.length-1].substring(artifactIdVersionLength + 1, p[p.length-1].lastIndexOf('.'))));
-                }
-                StringBuffer sb = new StringBuffer();
-                for (int j = 0; j < p.length - 3; j++) {
-                    if (j > 0) {
-                        sb.append('.');
-                    }
-                    sb.append(p[j]);
-                }
-                opt.groupId(sb.toString());
-                opt.artifactId(p[p.length-3]);
-                opt.version(p[p.length-2]);
-                opt.type(p[p.length-1].substring(p[p.length-1].lastIndexOf('.') + 1));
-                return opt;
-            } else {
-                throw new IllegalArgumentException("Unable to extract maven information from " + location);
-            }
-        }
-
-        public static Properties getDefaultSystemOptions() {
-            return getDefaultSystemOptions("target/karaf.home");
-        }
-
-        public static Properties getDefaultSystemOptions(String karafHome) {
-            Properties sysProps = new Properties();
-            sysProps.setProperty("karaf.name", "root");
-            sysProps.setProperty("karaf.home", karafHome);
-            sysProps.setProperty("karaf.base", karafHome);
-            sysProps.setProperty("karaf.startLocalConsole", "false");
-            sysProps.setProperty("karaf.startRemoteShell", "false");
-            sysProps.setProperty("org.osgi.framework.startlevel.beginning", "100");
-            return sysProps;
-        }
-
-        public static Option[] getDefaultConfigOptions() throws Exception {
-            return getDefaultConfigOptions(getDefaultSystemOptions(),
-                                           Helper.class.getResource("/config.properties"));
-        }
-
-        public static Option[] getDefaultConfigOptions(Properties sysProps, URL configProperties) throws Exception {
-            // Load props
-            Properties configProps = new Properties();
-            InputStream is = configProperties.openStream();
-            try {
-                configProps.load(is);
-            } finally {
-                is.close();
-            }
-            // Set system props
-            for (Enumeration e = sysProps.propertyNames(); e.hasMoreElements();) {
-                String key = (String) e.nextElement();
-                configProps.setProperty(key, sysProps.getProperty(key));
-            }
-            // Perform variable substitution for system properties.
-            for (Enumeration e = configProps.propertyNames(); e.hasMoreElements();) {
-                String name = (String) e.nextElement();
-                configProps.setProperty(name, substVars(configProps.getProperty(name), name, null, configProps));
-            }
-            // Transform to sys props options
-            List<Option> options = new ArrayList<Option>();
-            for (Enumeration e = configProps.propertyNames(); e.hasMoreElements();) {
-                String name = (String) e.nextElement();
-                String value = configProps.getProperty(name);
-                value = value.replaceAll("\r", "").replaceAll("\n", "").replaceAll(" ", "");
-                options.add(new SystemPropertyOption(name).value(value));
-            }
-            if (configProps.getProperty("org.osgi.framework.startlevel.beginning") != null) {
-                options.add(frameworkStartLevel(Integer.parseInt(configProps.getProperty("org.osgi.framework.startlevel.beginning"))));
-            }
-            return options.toArray(new Option[options.size()]);
-        }
-
-        public static Option[] getDefaultProvisioningOptions() throws Exception {
-            return getDefaultProvisioningOptions(getDefaultSystemOptions(),
-                                                 Helper.class.getResource("/startup.properties"));
-        }
-
-        public static Option[] getDefaultProvisioningOptions(Properties sysProps, URL configProperties) throws Exception {
-            Properties startupProps = new Properties();
-            InputStream is = configProperties.openStream();
-            try {
-                startupProps.load(is);
-            } finally {
-                is.close();
-            }
-            // Perform variable substitution for system properties.
-            for (Enumeration e = startupProps.propertyNames(); e.hasMoreElements();) {
-                String name = (String) e.nextElement();
-                startupProps.setProperty(name, substVars(startupProps.getProperty(name), name, null, sysProps));
-            }
-            // Transform to sys props options
-            List<Option> options = new ArrayList<Option>();
-            options.add(bootClasspathLibrary(mavenBundle("org.apache.felix.karaf.jaas", "org.apache.felix.karaf.jaas.boot")).afterFramework());
-            options.add(bootClasspathLibrary(mavenBundle("org.apache.felix.karaf", "org.apache.felix.karaf.main")).afterFramework());
-            for (Enumeration e = startupProps.propertyNames(); e.hasMoreElements();) {
-                String name = (String) e.nextElement();
-                String value = startupProps.getProperty(name);
-                MavenArtifactProvisionOption opt = convertToMaven(name);
-                if (opt.getURL().contains("org.apache.felix.karaf.features")) {
-                    opt.noStart();
-                }
-                opt.startLevel(Integer.parseInt(value));
-                options.add(opt);
-            }
-            // We need to add pax-exam-junit here when running with the ibm
-            // jdk to avoid the following exception during the test run:
-            // ClassNotFoundException: org.ops4j.pax.exam.junit.Configuration
-            if ("IBM Corporation".equals(System.getProperty("java.vendor"))) {
-                options.add(wrappedBundle(maven("org.ops4j.pax.exam", "pax-exam-junit")));
-            }
-            return options.toArray(new Option[options.size()]);
-        }
-
-        public static Option[] getDefaultOptions() throws Exception {
-            return combine(getDefaultConfigOptions(), getDefaultProvisioningOptions());
-        }
-
-        public static MavenArtifactProvisionOption findMaven(Option[] options, String groupId, String artifactId) {
-            for (Option option : options) {
-                if (option instanceof MavenArtifactProvisionOption) {
-                    MavenArtifactProvisionOption mvn = (MavenArtifactProvisionOption) option;
-                    if (mvn.getURL().startsWith("mvn:" + groupId + "/" + artifactId + "/")) {
-                        return mvn;
-                    }
-                }
-            }
-            return null;
-        }
-    }
 }
\ No newline at end of file