Move ServiceMix Kernel trunk into Felix

git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@768912 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/karaf/main/pom.xml b/karaf/main/pom.xml
new file mode 100644
index 0000000..4166785
--- /dev/null
+++ b/karaf/main/pom.xml
@@ -0,0 +1,202 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <!--
+
+        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.
+    -->
+
+    <modelVersion>4.0.0</modelVersion>
+
+    <parent>
+        <groupId>org.apache.servicemix.kernel</groupId>
+        <artifactId>kernel</artifactId>
+        <version>1.2.0-SNAPSHOT</version>
+    </parent>
+
+    <groupId>org.apache.servicemix.kernel</groupId>
+    <artifactId>org.apache.servicemix.kernel.main</artifactId>
+    <packaging>bundle</packaging>
+    <version>1.2.0-SNAPSHOT</version>
+    <name>Apache ServiceMix Kernel :: Main</name>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.apache.felix.framework</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.felix</groupId>
+            <artifactId>org.osgi.core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.servicemix.bundles</groupId>
+            <artifactId>org.apache.servicemix.bundles.junit</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <configuration>
+                    <instructions>
+                        <_donotcopy>(CVS|.svn|config.properties)</_donotcopy>
+                        <Main-Class>org.apache.servicemix.kernel.main.Main</Main-Class>
+                        <Bundle-Name>Apache ServiceMix</Bundle-Name>
+                        <Bundle-Description>OSGi R4 framework.</Bundle-Description>
+                        <Bundle-SymbolicName>${pom.artifactId}</Bundle-SymbolicName>
+                        <Export-Package>org.apache.servicemix.kernel.main.spi.*;version=${pom.version}</Export-Package>
+                        <Private-Package>
+                            org.apache.servicemix.kernel.main;-split-package:=merge-first,
+                            org.apache.felix.moduleloader.*;-split-package:=merge-first,
+                            org.apache.felix.framework.*;-split-package:=merge-first,
+                            org.osgi.framework.launch*,
+                            org.osgi.framework.hooks*,
+                            org.osgi.framework;-split-package:=merge-first,
+                            org.osgi.service.packageadmin;-split-package:=merge-first,
+                            org.osgi.service.startlevel;-split-package:=merge-first,
+                            org.osgi.service.url;-split-package:=merge-first,
+                            org.osgi.util.tracker;-split-package:=merge-first,
+                            META-INF;-split-package:=merge-first
+                        </Private-Package>
+                        <Import-Package>!*</Import-Package>
+                    </instructions>
+                    <unpackBundle>true</unpackBundle>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-shade-plugin</artifactId>
+                <executions>
+                    <execution>
+                        <phase>package</phase>
+                        <goals>
+                            <goal>shade</goal>
+                        </goals>
+                        <configuration>
+                            <artifactSet>
+                                <includes>
+                                    <include>org.apache.felix:org.apache.felix.framework</include>
+                                    <include>org.apache.felix:org.osgi.core</include>
+                                    <include>${project.groupId}:${project.artifactId}</include>
+                                </includes>
+                            </artifactSet>
+                            <filters>
+                                <filter>
+                                    <artifact>org.apache.felix:org.apache.felix.framework</artifact>
+                                    <excludes>
+                                        <exclude>org/apache/felix/**</exclude>
+                                        <exclude>org/osgi/**</exclude>
+                                    </excludes>
+                                </filter>
+                                <filter>
+                                    <artifact>org.apache.felix:org.osgi.core</artifact>
+                                    <excludes>
+                                        <exclude>org/osgi/**</exclude>
+                                    </excludes>
+                                </filter>
+                            </filters>
+                            <createSourcesJar>${createSourcesJar}</createSourcesJar>
+                            <promoteTransitiveDependencies>true</promoteTransitiveDependencies>
+                            <createDependencyReducedPom>true</createDependencyReducedPom>
+                        </configuration>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+        <resources>
+            <resource>
+                <directory>src/main/resources</directory>
+                <filtering>true</filtering>
+            </resource>
+        </resources>
+    </build>
+
+    <profiles>
+        <profile>
+            <id>deploy</id>
+            <properties>
+                <createSourcesJar>true</createSourcesJar>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-dependency-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>unpack-sources</id>
+                                <phase>generate-sources</phase>
+                                <goals>
+                                    <goal>unpack</goal>
+                                </goals>
+                                <configuration>
+                                    <artifactItems>
+                                        <artifactItem>
+                                            <groupId>org.apache.felix</groupId>
+                                            <artifactId>org.osgi.core</artifactId>
+                                            <classifier>sources</classifier>
+                                        </artifactItem>
+                                        <artifactItem>
+                                            <groupId>org.apache.felix</groupId>
+                                            <artifactId>org.apache.felix.framework</artifactId>
+                                            <classifier>sources</classifier>
+                                        </artifactItem>
+                                    </artifactItems>
+                                    <outputDirectory>${project.build.directory}/sources</outputDirectory>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-source-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>attach-sources</id>
+                                <phase>process-classes</phase>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.apache.maven.plugins</groupId>
+                        <artifactId>maven-javadoc-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <id>package</id>
+                                <phase>package</phase>
+                                <goals>
+                                    <goal>jar</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <minmemory>128m</minmemory>
+                            <maxmemory>512m</maxmemory>
+                            <sourcepath>${project.build.directory}/sources</sourcepath>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+    </profiles>
+
+</project>
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/DefaultJDBCLock.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/DefaultJDBCLock.java
new file mode 100644
index 0000000..bf4bfba
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/DefaultJDBCLock.java
@@ -0,0 +1,194 @@
+/*
+ * 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.servicemix.kernel.main;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.Properties;
+
+/**
+ * Represents an exclusive lock on a database,
+ * used to avoid multiple SMX instances attempting
+ * to become master.
+ * 
+ * @version $Revision: $
+ */
+public class DefaultJDBCLock implements Lock {
+
+    private static final String PROPERTY_LOCK_URL               = "servicemix.lock.jdbc.url";
+    private static final String PROPERTY_LOCK_JDBC_DRIVER       = "servicemix.lock.jdbc.driver";
+    private static final String PROPERTY_LOCK_JDBC_USER         = "servicemix.lock.jdbc.user";
+    private static final String PROPERTY_LOCK_JDBC_PASSWORD     = "servicemix.lock.jdbc.password";
+    private static final String PROPERTY_LOCK_JDBC_TABLE        = "servicemix.lock.jdbc.table";
+    private static final String PROPERTY_LOCK_JDBC_CLUSTERNAME  = "servicemix.lock.jdbc.clustername";
+    private static final String PROPERTY_LOCK_JDBC_TIMEOUT      = "servicemix.lock.jdbc.timeout";
+
+    private final Statements statements;
+    private Connection lockConnection;
+    private String url;
+    private String driver;
+    private String user; 
+    private String password;
+    private String table;
+    private String clusterName;
+    private int timeout;
+
+    public DefaultJDBCLock(Properties props) {
+        this.url = props.getProperty(PROPERTY_LOCK_URL);
+        this.driver = props.getProperty(PROPERTY_LOCK_JDBC_DRIVER);
+        this.user = props.getProperty(PROPERTY_LOCK_JDBC_USER);
+        this.password = props.getProperty(PROPERTY_LOCK_JDBC_PASSWORD);
+        this.table = props.getProperty(PROPERTY_LOCK_JDBC_TABLE);
+        this.clusterName = props.getProperty(PROPERTY_LOCK_JDBC_CLUSTERNAME);
+        String time = props.getProperty(PROPERTY_LOCK_JDBC_TIMEOUT);
+        this.lockConnection = null;
+        if (table == null) { table = "SERVICEMIX_LOCK"; }
+        if ( clusterName == null) { clusterName = "smx4"; }
+        this.statements = new Statements(table, clusterName);
+        if (time != null) { 
+            this.timeout = Integer.parseInt(time) * 1000; 
+        } else {
+            this.timeout = 10000; // 10 seconds
+        }
+        if (user == null) { user = ""; }
+        if (password == null) { password = ""; }
+        try {
+            obtainLock();
+        } catch (Exception e) {
+            System.err.println("Error occured while attempting to obtain connection: " + e.getMessage());
+        }
+    }
+
+    /**
+     * obtainLock - obtain the lock connection.
+     *
+     * @throws Exception
+     */
+    private void obtainLock() throws Exception {
+        PreparedStatement statement = null;
+        while (true) {
+            try {
+                lockConnection = getConnection(driver, url, user, password);
+                lockConnection.setAutoCommit(false);
+                statements.init(lockConnection);
+                String sql = statements.testLockTableStatus();
+                statement = lockConnection.prepareStatement(sql);
+                statement.execute();
+                break;
+            } catch (Exception e) {
+                System.err.println("Could not obtain lock: " + e.getMessage());
+                Thread.sleep(this.timeout);
+            } finally {
+                if (null != statement) {
+                    try {
+                        statement.close();
+                    } catch (SQLException e1) {
+                        System.err.println("Caught while closing statement: " + e1.getMessage());
+                    }
+                    statement = null;
+                }
+            }
+            Thread.sleep(this.timeout);
+        }
+        System.out.println("Connected to data source: " + url);
+    }
+
+    /**
+     * lock - a KeepAlive function to maintain lock. 
+     *
+     * @return true if connection lock retained, false otherwise.
+     */
+    public boolean lock() {
+        PreparedStatement statement = null;
+        boolean result = false;
+        try {
+            if (lockConnection.isClosed()) { obtainLock(); } 
+            long time = System.currentTimeMillis();
+            statement = lockConnection.prepareStatement(statements.getLockUpdateStatement(time));
+            int rows = statement.executeUpdate();
+            if (rows == 1) {
+                result=true;
+            }
+        } catch (Exception e) {
+            System.err.println("Failed to acquire database lock: " + e.getMessage());
+        }finally {
+            if (statement != null) {
+                try {
+                    statement.close();
+                } catch (SQLException e) {
+                    System.err.println("Failed to close statement" + e);
+                }
+            }
+        }
+        return result;
+    }
+
+    /**
+     * release - terminate the lock connection safely.
+     */
+    public void release() throws Exception {
+        if (lockConnection != null && !lockConnection.isClosed()) {
+            lockConnection.rollback();
+            lockConnection.close();
+        }
+    }
+
+    /**
+     * isAlive - test if lock still exists.
+     */
+    public boolean isAlive() throws Exception {
+        if (lockConnection == null) { return false; }
+        PreparedStatement statement = null;
+        try { 
+            lockConnection.setAutoCommit(false);
+            statements.init(lockConnection);
+            String sql = statements.testLockTableStatus();
+            statement = lockConnection.prepareStatement(sql);
+            statement.execute();
+        } catch (Exception ex) {
+            return false;
+        }
+        return true;
+    }
+
+    /**
+     * getConnection - Obtain connection to database via jdbc driver.
+     *
+     * @throws Exception
+     * @param driver, the JDBC driver class.
+     * @param url, url to data source.
+     * @param username, user to access data source.
+     * @param password, password for specified user.
+     * @return connection, null returned if conenction fails.
+     */
+    private Connection getConnection(String driver, String url, 
+                                     String username, String password) throws Exception {
+        Connection conn = null;
+        try {
+            Class.forName(driver);
+            conn = DriverManager.getConnection(url + ";create=true", username, password);
+        } catch (Exception e) {
+            throw e; 
+        }
+        return conn;
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Lock.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Lock.java
new file mode 100644
index 0000000..f4e8ab8
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Lock.java
@@ -0,0 +1,29 @@
+/*
+ * 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.servicemix.kernel.main;
+
+public interface Lock {
+
+    boolean lock() throws Exception;
+
+    void release() throws Exception;
+
+    boolean isAlive() throws Exception;
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Main.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Main.java
new file mode 100644
index 0000000..d09a033
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Main.java
@@ -0,0 +1,1150 @@
+/*
+ * 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.servicemix.kernel.main;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.JarURLConnection;
+import java.net.MalformedURLException;
+import java.net.URI;
+import java.net.URL;
+import java.security.Provider;
+import java.security.Security;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+import java.util.concurrent.CountDownLatch;
+
+import org.apache.felix.framework.Felix;
+import org.apache.felix.framework.cache.BundleCache;
+import org.apache.felix.framework.util.FelixConstants;
+import org.apache.felix.framework.util.StringMap;
+import org.apache.servicemix.kernel.main.spi.MainService;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceReference;
+import org.osgi.framework.ServiceRegistration;
+import org.osgi.service.startlevel.StartLevel;
+
+/**
+ * <p>
+ * This class is the default way to instantiate and execute the framework. It is not
+ * intended to be the only way to instantiate and execute the framework; rather, it is
+ * one example of how to do so. When embedding the framework in a host application,
+ * this class can serve as a simple guide of how to do so. It may even be
+ * worthwhile to reuse some of its property handling capabilities. This class
+ * is completely static and is only intended to start a single instance of
+ * the framework.
+ * </p>
+ */
+public class Main implements MainService, BundleActivator {
+    /**
+     * The default name used for the system properties file.
+     */
+    public static final String SYSTEM_PROPERTIES_FILE_NAME = "system.properties";
+    /**
+     * The default name used for the configuration properties file.
+     */
+    public static final String CONFIG_PROPERTIES_FILE_NAME = "config.properties";
+    /**
+     * The default name used for the startup properties file.
+     */
+    public static final String STARTUP_PROPERTIES_FILE_NAME = "startup.properties";
+    /**
+     * The property name prefix for the launcher's auto-install property.
+     */
+    public static final String PROPERTY_AUTO_INSTALL = "felix.auto.install";
+    /**
+     * The property for auto-discovering the bundles
+     */
+    public static final String PROPERTY_AUTO_START = "felix.auto.start";
+    /**
+     * The system property for specifying the ServiceMix home directory.  The home directory
+     * hold the binary install of ServiceMix.
+     */
+    public static final String PROP_SERVICEMIX_HOME = "servicemix.home";
+    /**
+     * The environment variable for specifying the ServiceMix home directory.  The home directory
+     * hold the binary install of ServiceMix.
+     */
+    public static final String ENV_SERVICEMIX_HOME = "SERVICEMIX_HOME";
+    /**
+     * The system property for specifying the ServiceMix base directory.  The base directory
+     * holds the configuration and data for a ServiceMix instance.
+     */
+    public static final String PROP_SERVICEMIX_BASE = "servicemix.base";
+    /**
+     * The environment variable for specifying the ServiceMix base directory.  The base directory
+     * holds the configuration and data for a ServiceMix instance.
+     */
+    public static final String ENV_SERVICEMIX_BASE = "SERVICEMIX_BASE";
+
+    /**
+     * Config property which identifies directories which contain bundles to be loaded by SMX
+     */
+    public static final String BUNDLE_LOCATIONS = "bundle.locations";
+
+    /**
+     * Config property that indicates we want to convert bundles locations to maven style urls
+     */
+    public static final String PROPERTY_CONVERT_TO_MAVEN_URL = "servicemix.maven.convert";
+
+    /**
+     * If a lock should be used before starting the runtime
+     */
+    public static final String PROPERTY_USE_LOCK = "servicemix.lock";
+
+    /**
+     * The lock implementation
+     */
+    public static final String PROPERTY_LOCK_CLASS = "servicemix.lock.class";
+
+    public static final String PROPERTY_LOCK_DELAY = "servicemix.lock.delay";
+
+    public static final String PROPERTY_LOCK_LEVEL = "servicemix.lock.level";
+
+    public static final String PROPERTY_LOCK_CLASS_DEFAULT = SimpleFileLock.class.getName();
+
+
+    private File servicemixHome;
+    private File servicemixBase;
+    private static Properties m_configProps = null;
+    private static Felix m_felix = null;
+    private final String[] args;
+    private int exitCode;
+    private Lock lock;
+    private CountDownLatch shutdown = new CountDownLatch(1);
+    private int defaultStartLevel = 100;
+    private int lockStartLevel = 0;
+    private int lockDelay = 1000;
+    private boolean exiting = false;
+
+    public Main(String[] args) {
+        this.args = args;
+    }
+
+    public void launch() throws Exception {
+        servicemixHome = getServiceMixHome();
+        servicemixBase = getServiceMixBase(servicemixHome);
+
+        //System.out.println("ServiceMix Home: "+main.servicemixHome.getPath());
+        //System.out.println("ServiceMix Base: "+main.servicemixBase.getPath());
+
+        System.setProperty(PROP_SERVICEMIX_HOME, servicemixHome.getPath());
+        System.setProperty(PROP_SERVICEMIX_BASE, servicemixBase.getPath());
+
+        // Load system properties.
+        loadSystemProperties();
+
+        // Read configuration properties.
+        m_configProps = loadConfigProperties();
+
+        // Copy framework properties from the system properties.
+        Main.copySystemProperties(m_configProps);
+
+        processSecurityProperties(m_configProps);
+
+        m_configProps.setProperty(BundleCache.CACHE_ROOTDIR_PROP, servicemixBase.getPath() + "/data");
+        m_configProps.setProperty(Constants.FRAMEWORK_STORAGE, "cache");
+
+        // Register the Main class so that other bundles can inspect the command line args.
+        BundleActivator activator = new BundleActivator() {
+            private ServiceRegistration registration;
+
+            public void start(BundleContext context) {
+                registration = context.registerService(MainService.class.getName(), Main.this, null);
+            }
+
+            public void stop(BundleContext context) {
+                registration.unregister();
+                shutdown.countDown();
+            }
+        };
+        List<BundleActivator> activations = new ArrayList<BundleActivator>();
+        activations.add(this);
+        activations.add(activator);
+
+        m_configProps.put(FelixConstants.SYSTEMBUNDLE_ACTIVATORS_PROP, activations);
+
+        try {
+            defaultStartLevel = Integer.parseInt(m_configProps.getProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL));
+            lockStartLevel = Integer.parseInt(m_configProps.getProperty(PROPERTY_LOCK_LEVEL, Integer.toString(lockStartLevel)));
+            lockDelay = Integer.parseInt(m_configProps.getProperty(PROPERTY_LOCK_DELAY, Integer.toString(lockDelay)));
+            m_configProps.setProperty(Constants.FRAMEWORK_BEGINNING_STARTLEVEL, Integer.toString(lockStartLevel));
+            // Start up the OSGI framework
+            m_felix = new Felix(new StringMap(m_configProps, false));
+            m_felix.start();
+            // Start lock monitor
+            new Thread() {
+                public void run() {
+                    lock(m_configProps);
+                }
+            }.start();
+        }
+        catch (Exception ex) {
+            setExitCode(-1);
+            throw new Exception("Could not create framework", ex);
+        }
+    }
+
+    public void destroy(boolean await) throws Exception {
+        try {
+            if (await) {
+                shutdown.await();
+            }
+            exiting = true;
+            if (m_felix.getState() == Bundle.ACTIVE) {
+                m_felix.stop();
+            }
+        } finally {
+            unlock();
+        }
+    }
+
+    /**
+     * Used to instigate auto-install and auto-start configuration
+     * property processing via a custom framework activator during
+     * framework startup.
+     *
+     * @param context The system bundle context.
+     */
+    public void start(BundleContext context) {
+        Main.processAutoProperties(context);
+    }
+
+    /**
+     * Currently does nothing as part of framework shutdown.
+     *
+     * @param context The system bundle context.
+     */
+    public void stop(BundleContext context) {
+        // Do nothing.
+    }
+
+    /**
+     * <p>
+     * This method performs the main task of constructing an framework instance
+     * and starting its execution. The following functions are performed
+     * when invoked:
+     * </p>
+     * <ol>
+     *   <li><i><b>Read the system properties file.<b></i> This is a file
+     *       containing properties to be pushed into <tt>System.setProperty()</tt>
+     *       before starting the framework. This mechanism is mainly shorthand
+     *       for people starting the framework from the command line to avoid having
+     *       to specify a bunch of <tt>-D</tt> system property definitions.
+     *       The only properties defined in this file that will impact the framework's
+     *       behavior are the those concerning setting HTTP proxies, such as
+     *       <tt>http.proxyHost</tt>, <tt>http.proxyPort</tt>, and
+     *       <tt>http.proxyAuth</tt>.
+     *   </li>
+     *   <li><i><b>Perform system property variable substitution on system
+     *       properties.</b></i> Any system properties in the system property
+     *       file whose value adheres to <tt>${&lt;system-prop-name&gt;}</tt>
+     *       syntax will have their value substituted with the appropriate
+     *       system property value.
+     *   </li>
+     *   <li><i><b>Read the framework's configuration property file.</b></i> This is
+     *       a file containing properties used to configure the framework
+     *       instance and to pass configuration information into
+     *       bundles installed into the framework instance. The configuration
+     *       property file is called <tt>config.properties</tt> by default
+     *       and is located in the <tt>conf/</tt> directory of the Felix
+     *       installation directory, which is the parent directory of the
+     *       directory containing the <tt>felix.jar</tt> file. It is possible
+     *       to use a different location for the property file by specifying
+     *       the desired URL using the <tt>felix.config.properties</tt>
+     *       system property; this should be set using the <tt>-D</tt> syntax
+     *       when executing the JVM. Refer to the
+     *       <a href="Felix.html#Felix(java.util.Map, java.util.List)">
+     *       <tt>Felix</tt></a> constructor documentation for more
+     *       information on the framework configuration options.
+     *   </li>
+     *   <li><i><b>Perform system property variable substitution on configuration
+     *       properties.</b></i> Any configuration properties whose value adheres to
+     *       <tt>${&lt;system-prop-name&gt;}</tt> syntax will have their value
+     *       substituted with the appropriate system property value.
+     *   </li>
+     *   <li><i><b>Ensure the default bundle cache has sufficient information to
+     *       initialize.</b></i> The default implementation of the bundle cache
+     *       requires either a profile name or a profile directory in order to
+     *       start. The configuration properties are checked for at least one
+     *       of the <tt>felix.cache.profile</tt> or <tt>felix.cache.profiledir</tt>
+     *       properties. If neither is found, the user is asked to supply a profile
+     *       name that is added to the configuration property set. See the
+     *       <a href="cache/DefaultBundleCache.html"><tt>DefaultBundleCache</tt></a>
+     *       documentation for more details its configuration options.
+     *   </li>
+     *   <li><i><b>Creates and starts a framework instance.</b></i> A
+     *       case insensitive
+     *       <a href="util/StringMap.html"><tt>StringMap</tt></a>
+     *       is created for the configuration property file and is passed
+     *       into the framework.
+     *   </li>
+     * </ol>
+     * <p>
+     * It should be noted that simply starting an instance of the framework is not enough
+     * to create an interactive session with it. It is necessary to install
+     * and start bundles that provide an interactive impl; this is generally
+     * done by specifying an "auto-start" property in the framework configuration
+     * property file. If no interactive impl bundles are installed or if
+     * the configuration property file cannot be found, the framework will appear to
+     * be hung or deadlocked. This is not the case, it is executing correctly,
+     * there is just no way to interact with it. Refer to the
+     * <a href="Felix.html#Felix(java.util.Map, java.util.List)">
+     * <tt>Felix</tt></a> constructor documentation for more information on
+     * framework configuration options.
+     * </p>
+     * @param args An array of arguments, all of which are ignored.
+     * @throws Exception If an error occurs.
+     **/
+    public static void main(String[] args) throws Exception {
+        final Main main = new Main(args);
+        try {
+            main.launch();
+            main.destroy(true);
+        }
+        catch (Exception ex) {
+            System.err.println("Error occured shutting down framework: " + ex);
+            ex.printStackTrace();
+        } finally {
+            System.exit(main.getExitCode());
+        }
+    }
+
+    private static File getServiceMixHome() throws IOException {
+        File rc = null;
+
+        // Use the system property if specified.
+        String path = System.getProperty(PROP_SERVICEMIX_HOME);
+        if (path != null) {
+            rc = validateDirectoryExists(path, "Invalid " + PROP_SERVICEMIX_HOME + " system property");
+        }
+
+        if (rc == null) {
+            path = System.getenv(ENV_SERVICEMIX_HOME);
+            if (path != null) {
+                rc = validateDirectoryExists(path, "Invalid " + ENV_SERVICEMIX_HOME + " environment variable");
+            }
+        }
+
+        // Try to figure it out using the jar file this class was loaded from.
+        if (rc == null) {
+            // guess the home from the location of the jar
+            URL url = Main.class.getClassLoader().getResource(Main.class.getName().replace(".", "/") + ".class");
+            if (url != null) {
+                try {
+                    JarURLConnection jarConnection = (JarURLConnection) url.openConnection();
+                    url = jarConnection.getJarFileURL();
+                    rc = new File(new URI(url.toString())).getCanonicalFile().getParentFile().getParentFile();
+                } catch (Exception ignored) {
+                }
+            }
+        }
+
+        if (rc == null) {
+            // Dig into the classpath to guess the location of the jar
+            String classpath = System.getProperty("java.class.path");
+            int index = classpath.toLowerCase().indexOf("servicemix.jar");
+            int start = classpath.lastIndexOf(File.pathSeparator, index) + 1;
+            if (index >= start) {
+                String jarLocation = classpath.substring(start, index);
+                rc = new File(jarLocation).getCanonicalFile().getParentFile();
+            }
+        }
+        if (rc == null) {
+            throw new IOException("The ServiceMix install directory could not be determined.  Please set the " + PROP_SERVICEMIX_HOME + " system property or the " + ENV_SERVICEMIX_HOME + " environment variable.");
+        }
+
+        return rc;
+    }
+
+    private static File validateDirectoryExists(String path, String errPrefix) {
+        File rc;
+        try {
+            rc = new File(path).getCanonicalFile();
+        } catch (IOException e) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : " + e.getMessage());
+        }
+        if (!rc.exists()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : does not exist");
+        }
+        if (!rc.isDirectory()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : is not a directory");
+        }
+        return rc;
+    }
+
+    private static File getServiceMixBase(File defaultValue) {
+        File rc = null;
+
+        String path = System.getProperty(PROP_SERVICEMIX_BASE);
+        if (path != null) {
+            rc = validateDirectoryExists(path, "Invalid " + PROP_SERVICEMIX_BASE + " system property");
+        }
+
+        if (rc == null) {
+            path = System.getenv(ENV_SERVICEMIX_BASE);
+            if (path != null) {
+                rc = validateDirectoryExists(path, "Invalid " + ENV_SERVICEMIX_BASE + " environment variable");
+            }
+        }
+
+        if (rc == null) {
+            rc = defaultValue;
+        }
+        return rc;
+    }
+
+    private static void processSecurityProperties(Properties m_configProps) {
+        String prop = m_configProps.getProperty("org.apache.servicemix.security.providers");
+        if (prop != null) {
+            String[] providers = prop.split(",");
+            for (String provider : providers) {
+                try {
+                    Security.addProvider((Provider) Class.forName(provider).newInstance());
+                } catch (Throwable t) {
+                    System.err.println("Unable to register security provider: " + t);
+                }
+            }
+        }
+    }
+
+    /**
+     * <p/>
+     * Processes the auto-install and auto-start properties from the
+     * specified configuration properties.
+     */
+    private static void processAutoProperties(BundleContext context) {
+        // Check if we want to convert URLs to maven style
+        boolean convertToMavenUrls = Boolean.parseBoolean(m_configProps.getProperty(PROPERTY_CONVERT_TO_MAVEN_URL, "true"));
+
+        // Retrieve the Start Level service, since it will be needed
+        // to set the start level of the installed bundles.
+        StartLevel sl = (StartLevel) context.getService(
+                context.getServiceReference(org.osgi.service.startlevel.StartLevel.class.getName()));
+
+        // The auto-install property specifies a space-delimited list of
+        // bundle URLs to be automatically installed into each new profile;
+        // the start level to which the bundles are assigned is specified by
+        // appending a ".n" to the auto-install property name, where "n" is
+        // the desired start level for the list of bundles.
+        for (Iterator i = m_configProps.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+
+            // Ignore all keys that are not the auto-install property.
+            if (!key.startsWith(PROPERTY_AUTO_INSTALL)) {
+                continue;
+            }
+
+            // If the auto-install property does not have a start level,
+            // then assume it is the default bundle start level, otherwise
+            // parse the specified start level.
+            int startLevel = sl.getInitialBundleStartLevel();
+            if (!key.equals(PROPERTY_AUTO_INSTALL)) {
+                try {
+                    startLevel = Integer.parseInt(key.substring(key.lastIndexOf('.') + 1));
+                }
+                catch (NumberFormatException ex) {
+                    System.err.println("Invalid property: " + key);
+                }
+            }
+
+            StringTokenizer st = new StringTokenizer(m_configProps.getProperty(key), "\" ", true);
+            if (st.countTokens() > 0) {
+                String location = null;
+                do {
+                    location = nextLocation(st);
+                    if (location != null) {
+                        try {
+                            String[] parts = convertToMavenUrlsIfNeeded(location, convertToMavenUrls);
+                            Bundle b = context.installBundle(parts[0], new URL(parts[1]).openStream());
+                            sl.setBundleStartLevel(b, startLevel);
+                        }
+                        catch (Exception ex) {
+                            System.err.println("Auto-properties install: " + ex);
+                        }
+                    }
+                }
+                while (location != null);
+            }
+        }
+
+        // The auto-start property specifies a space-delimited list of
+        // bundle URLs to be automatically installed and started into each
+        // new profile; the start level to which the bundles are assigned
+        // is specified by appending a ".n" to the auto-start property name,
+        // where "n" is the desired start level for the list of bundles.
+        // The following code starts bundles in two passes, first it installs
+        // them, then it starts them.
+        for (Iterator i = m_configProps.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+
+            // Ignore all keys that are not the auto-start property.
+            if (!key.startsWith(PROPERTY_AUTO_START)) {
+                continue;
+            }
+
+            // If the auto-start property does not have a start level,
+            // then assume it is the default bundle start level, otherwise
+            // parse the specified start level.
+            int startLevel = sl.getInitialBundleStartLevel();
+            if (!key.equals(PROPERTY_AUTO_START)) {
+                try {
+                    startLevel = Integer.parseInt(key.substring(key.lastIndexOf('.') + 1));
+                }
+                catch (NumberFormatException ex) {
+                    System.err.println("Invalid property: " + key);
+                }
+            }
+
+            StringTokenizer st = new StringTokenizer(m_configProps.getProperty(key), "\" ", true);
+            if (st.countTokens() > 0) {
+                String location = null;
+                do {
+                    location = nextLocation(st);
+                    if (location != null) {
+                        try {
+                            String[] parts = convertToMavenUrlsIfNeeded(location, convertToMavenUrls);
+                            Bundle b = context.installBundle(parts[0], new URL(parts[1]).openStream());
+                            sl.setBundleStartLevel(b, startLevel);
+                        }
+                        catch (Exception ex) {
+                            System.err.println("Auto-properties install:" + ex);
+                        }
+                    }
+                }
+                while (location != null);
+            }
+        }
+
+        // Now loop through and start the installed bundles.
+        for (Iterator i = m_configProps.keySet().iterator(); i.hasNext();) {
+            String key = (String) i.next();
+            if (key.startsWith(PROPERTY_AUTO_START)) {
+                StringTokenizer st = new StringTokenizer(m_configProps.getProperty(key), "\" ", true);
+                if (st.countTokens() > 0) {
+                    String location = null;
+                    do {
+                        location = nextLocation(st);
+                        if (location != null) {
+                            // Installing twice just returns the same bundle.
+                            try {
+                                String[] parts = convertToMavenUrlsIfNeeded(location, convertToMavenUrls);
+                                Bundle b = context.installBundle(parts[0], new URL(parts[1]).openStream());
+                                if (b != null) {
+                                    b.start();
+                                }
+                            }
+                            catch (Exception ex) {
+                                System.err.println("Auto-properties start: " + ex);
+                            }
+                        }
+                    }
+                    while (location != null);
+                }
+            }
+        }
+    }
+
+    private static String[] convertToMavenUrlsIfNeeded(String location, boolean convertToMavenUrls) {
+        String[] parts = location.split("\\|");
+        if (convertToMavenUrls) {
+            String[] p = parts[1].split("/");
+            if (p.length >= 4 && p[p.length-1].startsWith(p[p.length-3] + "-" + p[p.length-2])) {
+                String groupId = null;
+                String artifactId = p[p.length-3];
+                String version = p[p.length-2];
+                String classifier;
+                String type;
+                String artifactIdVersion = artifactId + "-" + version;
+                StringBuffer sb = new StringBuffer();
+                if (p[p.length-1].charAt(artifactIdVersion.length()) == '-') {
+                    classifier = p[p.length-1].substring(artifactIdVersion.length() + 1, p[p.length-1].lastIndexOf('.'));
+                } else {
+                    classifier = null;
+                }
+                type = p[p.length-1].substring(p[p.length-1].lastIndexOf('.') + 1);
+                sb.append("mvn:");
+                for (int j = 0; j < p.length - 3; j++) {
+                    if (j > 0) {
+                        sb.append('.');
+                    }
+                    sb.append(p[j]);
+                }
+                sb.append('/').append(artifactId).append('/').append(version);
+                if (!"jar".equals(type) || classifier != null) {
+                    sb.append('/');
+                    if (!"jar".equals(type)) {
+                        sb.append(type);
+                    }
+                    if (classifier != null) {
+                        sb.append('/').append(classifier);
+                    }
+                }
+                parts[1] = parts[0];
+                parts[0] = sb.toString();
+            } else {
+                parts[1] = parts[0];
+            }
+        } else {
+            parts[1] = parts[0];
+        }
+        return parts;
+    }
+
+    private static String nextLocation(StringTokenizer st) {
+        String retVal = null;
+
+        if (st.countTokens() > 0) {
+            String tokenList = "\" ";
+            StringBuffer tokBuf = new StringBuffer(10);
+            String tok = null;
+            boolean inQuote = false;
+            boolean tokStarted = false;
+            boolean exit = false;
+            while ((st.hasMoreTokens()) && (!exit)) {
+                tok = st.nextToken(tokenList);
+                if (tok.equals("\"")) {
+                    inQuote = !inQuote;
+                    if (inQuote) {
+                        tokenList = "\"";
+                    } else {
+                        tokenList = "\" ";
+                    }
+
+                } else if (tok.equals(" ")) {
+                    if (tokStarted) {
+                        retVal = tokBuf.toString();
+                        tokStarted = false;
+                        tokBuf = new StringBuffer(10);
+                        exit = true;
+                    }
+                } else {
+                    tokStarted = true;
+                    tokBuf.append(tok.trim());
+                }
+            }
+
+            // Handle case where end of token stream and
+            // still got data
+            if ((!exit) && (tokStarted)) {
+                retVal = tokBuf.toString();
+            }
+        }
+
+        return retVal;
+    }
+
+    /**
+     * <p>
+     * Loads the properties in the system property file associated with the
+     * framework installation into <tt>System.setProperty()</tt>. These properties
+     * are not directly used by the framework in anyway. By default, the system
+     * property file is located in the <tt>conf/</tt> directory of the Felix
+     * installation directory and is called "<tt>system.properties</tt>". The
+     * installation directory of Felix is assumed to be the parent directory of
+     * the <tt>felix.jar</tt> file as found on the system class path property.
+     * The precise file from which to load system properties can be set by
+     * initializing the "<tt>felix.system.properties</tt>" system property to an
+     * arbitrary URL.
+     * </p>
+     */
+    private void loadSystemProperties() {
+        // The system properties file is either specified by a system
+        // property or it is in the same directory as the Felix JAR file.
+        // Try to load it from one of these places.
+
+        // See if the property URL was specified as a property.
+        URL propURL = null;
+        try {
+            File file = new File(new File(servicemixBase, "etc"), SYSTEM_PROPERTIES_FILE_NAME);
+            propURL = file.toURL();
+        }
+        catch (MalformedURLException ex) {
+            System.err.print("Main: " + ex);
+            return;
+        }
+
+        // Read the properties file.
+        Properties props = new Properties();
+        InputStream is = null;
+        try {
+            is = propURL.openConnection().getInputStream();
+            props.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex) {
+            // Ignore file not found.
+        }
+        catch (Exception ex) {
+            System.err.println(
+                    "Main: Error loading system properties from " + propURL);
+            System.err.println("Main: " + ex);
+            try {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2) {
+                // Nothing we can do.
+            }
+            return;
+        }
+
+        // Perform variable substitution on specified properties.
+        for (Enumeration e = props.propertyNames(); e.hasMoreElements();) {
+            String name = (String) e.nextElement();
+            System.setProperty(name,
+                    substVars(props.getProperty(name), name, null, null));
+        }
+    }
+
+    /**
+     * <p>
+     * Loads the configuration properties in the configuration property file
+     * associated with the framework installation; these properties
+     * are accessible to the framework and to bundles and are intended
+     * for configuration purposes. By default, the configuration property
+     * file is located in the <tt>conf/</tt> directory of the Felix
+     * installation directory and is called "<tt>config.properties</tt>".
+     * The installation directory of Felix is assumed to be the parent
+     * directory of the <tt>felix.jar</tt> file as found on the system class
+     * path property. The precise file from which to load configuration
+     * properties can be set by initializing the "<tt>felix.config.properties</tt>"
+     * system property to an arbitrary URL.
+     * </p>
+     *
+     * @return A <tt>Properties</tt> instance or <tt>null</tt> if there was an error.
+     * @throws Exception 
+     */
+    private Properties loadConfigProperties() throws Exception {
+        // The config properties file is either specified by a system
+        // property or it is in the conf/ directory of the Felix
+        // installation directory.  Try to load it from one of these
+        // places.
+
+            ArrayList<File> bundleDirs = new ArrayList<File>();
+
+        // See if the property URL was specified as a property.
+        URL configPropURL = null;
+        URL startupPropURL = null;
+
+        try {
+            File file = new File(new File(servicemixBase, "etc"), CONFIG_PROPERTIES_FILE_NAME);
+            configPropURL = file.toURL();
+
+            file = new File(new File(servicemixBase, "etc"), STARTUP_PROPERTIES_FILE_NAME);
+            startupPropURL = file.toURL();
+
+            if (servicemixBase.equals(servicemixHome)) {
+                bundleDirs.add(new File(servicemixHome, "system"));
+            } else {
+                bundleDirs.add(new File(servicemixBase, "system"));
+                bundleDirs.add(new File(servicemixHome, "system"));
+            }
+
+        }
+        catch (MalformedURLException ex) {
+            System.err.print("Main: " + ex);
+            return null;
+        }
+
+
+        Properties configProps = loadPropertiesFile(configPropURL);
+        Properties startupProps = loadPropertiesFile(startupPropURL);
+
+        String locations = configProps.getProperty(BUNDLE_LOCATIONS);
+
+        if (locations != null) {
+            StringTokenizer st = new StringTokenizer(locations, "\" ", true);
+            if (st.countTokens() > 0) {
+                String location = null;
+                do {
+                    location = nextLocation(st);
+                    if (location != null) {
+                        File f = new File(location);
+                        if (f.exists() && f.isDirectory()) {
+                            bundleDirs.add(f);
+                        } else {
+                            System.err.println("Bundle location " + location
+                                    + " does not exist or is not a directory.");
+                        }
+                    }
+                }
+
+                while (location != null);
+            }
+        }
+
+        // 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));
+        }
+
+        // Mutate properties
+        Main.processConfigurationProperties(configProps, startupProps, bundleDirs);
+
+        return configProps;
+    }
+
+    private static Properties loadPropertiesFile(URL configPropURL) throws Exception {
+        // Read the properties file.
+        Properties configProps = new Properties();
+        InputStream is = null;
+        try {
+            is = configPropURL.openConnection().getInputStream();
+            configProps.load(is);
+            is.close();
+        }
+        catch (FileNotFoundException ex) {
+        	if (configPropURL.getFile().lastIndexOf(STARTUP_PROPERTIES_FILE_NAME) != -1) {
+        		throw ex;
+        	}
+        }
+        catch (Exception ex) {
+            System.err.println(
+                    "Error loading config properties from " + configPropURL);
+            System.err.println("Main: " + ex);
+            try {
+                if (is != null) is.close();
+            }
+            catch (IOException ex2) {
+                // Nothing we can do.
+            }
+            return null;
+        }
+        return configProps;
+    }
+
+    private static void copySystemProperties(Properties configProps) {
+        for (Enumeration e = System.getProperties().propertyNames();
+             e.hasMoreElements();) {
+            String key = (String) e.nextElement();
+            if (key.startsWith("felix.") ||
+                    key.startsWith("servicemix.") ||
+                    key.equals("org.osgi.framework.system.packages") ||
+                    key.equals("org.osgi.framework.bootdelegation")) {
+                configProps.setProperty(key, System.getProperty(key));
+            }
+        }
+    }
+
+    /**
+     * Process properties to customize default felix behavior
+     *
+     * @param startupProps
+     */
+    private static void processConfigurationProperties(Properties props, Properties startupProps, ArrayList<File> bundleDirs) {
+        if (bundleDirs == null) {
+            return;
+        }
+        if ("all".equals(props.getProperty(PROPERTY_AUTO_START, "").trim())) {
+            props.remove(PROPERTY_AUTO_START);
+            ArrayList<File> jars = new ArrayList<File>();
+
+            // We should start all the bundles in the system dir.
+            for (File bundleDir : bundleDirs) {
+                findJars(bundleDir, jars);
+            }
+
+            StringBuffer sb = new StringBuffer();
+
+            for (File jar : jars) {
+                try {
+                    sb.append("\"").append(jar.toURL().toString()).append("\" ");
+                } catch (MalformedURLException e) {
+                    System.err.print("Ignoring " + jar.toString() + " (" + e + ")");
+                }
+            }
+
+            props.setProperty(PROPERTY_AUTO_START, sb.toString());
+
+        } else if (STARTUP_PROPERTIES_FILE_NAME.equals(props.getProperty(PROPERTY_AUTO_START, "").trim())) {
+            props.remove(PROPERTY_AUTO_START);
+            // We should start the bundles in the startup.properties file.
+            HashMap<Integer, StringBuffer> levels = new HashMap<Integer, StringBuffer>();
+            for (Iterator iterator = startupProps.keySet().iterator(); iterator.hasNext();) {
+                String name = (String) iterator.next();
+                File file = findFile(bundleDirs, name);
+
+                if (file != null) {
+                    Integer level;
+                    try {
+                        level = new Integer(startupProps.getProperty(name).trim());
+                    } catch (NumberFormatException e1) {
+                        System.err.print("Ignoring " + file.toString() + " (run level must be an integer)");
+                        continue;
+                    }
+                    StringBuffer sb = levels.get(level);
+                    if (sb == null) {
+                        sb = new StringBuffer(256);
+                        levels.put(level, sb);
+                    }
+                    try {
+                        sb.append("\"").append(file.toURL().toString()).append("|").append(name).append("\" ");
+                    } catch (MalformedURLException e) {
+                        System.err.print("Ignoring " + file.toString() + " (" + e + ")");
+                    }
+                } else {
+                    System.err.println("Bundle listed in " + STARTUP_PROPERTIES_FILE_NAME + " configuration not found: " + name);
+                }
+            }
+
+            for (Map.Entry<Integer, StringBuffer> entry : levels.entrySet()) {
+                props.setProperty(PROPERTY_AUTO_START + "." + entry.getKey(), entry.getValue().toString());
+            }
+        }
+
+    }
+
+    private static File findFile(ArrayList<File> bundleDirs, String name) {
+        for (File bundleDir : bundleDirs) {
+            File file = findFile(bundleDir, name);
+            if (file != null) {
+                return file;
+            }
+        }
+        return null;
+    }
+
+    private static File findFile(File dir, String name) {
+        File theFile = new File(dir, name);
+
+        if (theFile.exists() && !theFile.isDirectory()) {
+            return theFile;
+        }
+
+        for (File file : dir.listFiles()) {
+            if (file.isDirectory()) {
+                return findFile(file, name);
+            }
+        }
+
+        return null;
+    }
+
+    private static void findJars(File dir, ArrayList<File> jars) {
+        for (File file : dir.listFiles()) {
+            if (file.isDirectory()) {
+                findJars(file, jars);
+            } else {
+                if (file.toString().endsWith(".jar")) {
+                    jars.add(file);
+                }
+            }
+        }
+    }
+
+    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.
+     */
+    public 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;
+    }
+
+    /* (non-Javadoc)
+      * @see org.apache.servicemix.main.MainService#getArgs()
+      */
+    public String[] getArgs() {
+        return args;
+    }
+
+    public int getExitCode() {
+        return exitCode;
+    }
+
+    public void setExitCode(int exitCode) {
+        this.exitCode = exitCode;
+    }
+
+    public File getServicemixHome() {
+        return servicemixHome;
+    }
+
+    public File getServicemixBase() {
+        return servicemixBase;
+    }
+
+    public void lock(Properties props) {
+        try {
+            if (Boolean.parseBoolean(props.getProperty(PROPERTY_USE_LOCK, "true"))) {
+                String clz = props.getProperty(PROPERTY_LOCK_CLASS, PROPERTY_LOCK_CLASS_DEFAULT);
+                lock = (Lock) Class.forName(clz).getConstructor(Properties.class).newInstance(props);
+                boolean lockLogged = false;
+                for (;;) {
+                    if (lock.lock()) {
+                        if (lockLogged) {
+                            System.out.println("Lock acquired.");
+                        }
+                        setStartLevel(defaultStartLevel);
+                        for (;;) {
+                            if (!lock.isAlive()) {
+                                break;
+                            }
+                            Thread.sleep(lockDelay);
+                        }
+                        if (m_felix.getState() == Bundle.ACTIVE && !exiting) {
+                            System.out.println("Lost the lock, stopping this instance ...");
+                            setStartLevel(lockStartLevel);
+                        }
+                        break;
+                    } else if (!lockLogged) {
+                        System.out.println("Waiting for the lock ...");
+                        lockLogged = true;
+                    }
+                    Thread.sleep(lockDelay);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+    }
+
+    public void unlock() throws Exception {
+        if (lock != null) {
+            lock.release();
+        }
+    }
+
+    protected void setStartLevel(int level) throws Exception {
+        BundleContext ctx = m_felix.getBundleContext();
+        ServiceReference[] refs = ctx.getServiceReferences(StartLevel.class.getName(), null);
+        StartLevel sl = (StartLevel) ctx.getService(refs[0]);
+        sl.setStartLevel(level);
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/SimpleFileLock.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/SimpleFileLock.java
new file mode 100644
index 0000000..c9791fd
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/SimpleFileLock.java
@@ -0,0 +1,108 @@
+/*
+ * 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.servicemix.kernel.main;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.RandomAccessFile;
+import java.nio.channels.FileLock;
+import java.util.Properties;
+
+public class SimpleFileLock implements Lock {
+
+    private static final String PROPERTY_LOCK_DIR = "servicemix.lock.dir";
+    private static final String PROP_SERVICEMIX_BASE = "servicemix.base";
+    private RandomAccessFile lockFile;
+    private FileLock lock;
+
+    public SimpleFileLock(Properties props) {
+        try {
+            String lock = props.getProperty(PROPERTY_LOCK_DIR);
+
+            if (lock != null) {
+                File servicemixLock = getServiceMixLock(new File(lock), props);
+                props.setProperty(PROPERTY_LOCK_DIR, servicemixLock.getPath());
+            } else {
+                props.setProperty(PROPERTY_LOCK_DIR, System.getProperty(PROP_SERVICEMIX_BASE));
+            }
+
+            File base = new File(props.getProperty(PROPERTY_LOCK_DIR));
+            lockFile = new RandomAccessFile(new File(base, "lock"), "rw");
+        } catch (IOException e) {
+            throw new RuntimeException("Could not create file lock", e);
+        }
+    }
+
+    public boolean lock() throws Exception {
+        if (lock == null) {
+            lock = lockFile.getChannel().tryLock();
+        }
+        return lock != null;
+    }
+
+    public void release() throws Exception {
+        if (lock != null && lock.isValid()) {
+            lock.release();
+            lock.channel().close();
+        }
+        lock = null;
+    }
+ 
+    public boolean isAlive() throws Exception {
+        return lock != null;
+    }
+
+    private static File getServiceMixLock(File lock,Properties props) {
+        File rc = null;
+
+        String path = lock.getPath();
+        if (path != null) {
+            rc = validateDirectoryExists(path, "Invalid " + PROPERTY_LOCK_DIR + " system property");
+        }
+
+        if (rc == null) {
+            path = props.getProperty(PROP_SERVICEMIX_BASE);
+            if (path != null) {
+                rc = validateDirectoryExists(path, "Invalid " + PROP_SERVICEMIX_BASE + " property");
+            }
+        }
+
+        if (rc == null) {
+            rc = lock;
+        }
+        return rc;
+    }
+
+    private static File validateDirectoryExists(String path, String errPrefix) {
+        File rc;
+        try {
+            rc = new File(path).getCanonicalFile();
+        } catch (IOException e) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : " + e.getMessage());
+        }
+        if (!rc.exists()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : does not exist");
+        }
+        if (!rc.isDirectory()) {
+            throw new IllegalArgumentException(errPrefix + " '" + path + "' : is not a directory");
+        }
+        return rc;
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Statements.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Statements.java
new file mode 100644
index 0000000..0681792
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/Statements.java
@@ -0,0 +1,110 @@
+/*
+ * 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.servicemix.kernel.main;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+
+public class Statements {
+
+    private String lockTableName = "SERVICEMIX_LOCK";
+    private String clusterName = "smx4";
+    private String lockCreateStatement;
+    private String lockPopulateStatement;
+    private String lockUpdateStatement;
+
+    public Statements(String tableName, String clusterName) {
+        this.lockTableName = tableName; 
+        this.clusterName = clusterName;
+        this.lockCreateStatement="create table " + lockTableName + " (TIME bigint, CLUSTER varchar(20))";
+        this.lockPopulateStatement="insert into " + lockTableName + " (TIME, CLUSTER) values (1, '" + clusterName + "')";
+    }
+
+    public String testLockTableStatus() {
+        String test = "SELECT * FROM " + lockTableName + " FOR UPDATE";
+        return test;
+    }
+
+    public String getLockUpdateStatement(long timeStamp) {
+        lockUpdateStatement = "UPDATE " + lockTableName + 
+                              " SET TIME=" + timeStamp + 
+                              " WHERE CLUSTER = '" + clusterName + "'";
+        return lockUpdateStatement;
+    }
+
+    /**
+     * init - initialize db
+     */
+    public void init (Connection lockConnection) {
+        Statement s = null;
+        try {
+            // Check to see if the table already exists. If it does, then don't
+            // log warnings during startup.
+            // Need to run the scripts anyways since they may contain ALTER
+            // statements that upgrade a previous version
+            // of the table
+            boolean alreadyExists = false;
+            ResultSet rs = null;
+            try {
+                rs = lockConnection.getMetaData().getTables(null, null, lockTableName, new String[] {"TABLE"});
+                alreadyExists = rs.next();
+            } catch (Throwable ignore) {
+                System.err.println(ignore);
+            } finally {
+                close(rs);
+            }
+            if (alreadyExists) {
+                return;
+            }
+            s = lockConnection.createStatement();
+            String[] createStatments = {lockCreateStatement, lockPopulateStatement};
+            for (int i = 0; i < createStatments.length; i++) {
+                // This will fail usually since the tables will be
+                // created already.
+                try {
+                    s.execute(createStatments[i]);
+                } catch (SQLException e) {
+                    System.err.println("Could not create JDBC tables; they could already exist."
+                                 + " Failure was: " + createStatments[i] + " Message: " + e.getMessage()
+                                 + " SQLState: " + e.getSQLState() + " Vendor code: " + e.getErrorCode());
+                }
+            }
+            lockConnection.commit();
+        } catch (Exception ignore) {
+            System.err.println(ignore);
+        } finally {
+            try {
+                s.close();
+            } catch (Throwable e) {
+                // ignore
+            }
+        }
+    }
+
+    private static void close(ResultSet rs) {
+        try {
+            rs.close();
+        } catch (Throwable e) {
+            // ignore
+        }
+    }
+
+}
diff --git a/karaf/main/src/main/java/org/apache/servicemix/kernel/main/spi/MainService.java b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/spi/MainService.java
new file mode 100644
index 0000000..ab6a24b
--- /dev/null
+++ b/karaf/main/src/main/java/org/apache/servicemix/kernel/main/spi/MainService.java
@@ -0,0 +1,27 @@
+/*
+ * 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.servicemix.kernel.main.spi;
+
+public interface MainService {
+
+	public abstract String[] getArgs();
+	public int getExitCode();
+	public void setExitCode(int exitCode);
+
+}
\ No newline at end of file
diff --git a/karaf/main/src/main/resources/config.properties b/karaf/main/src/main/resources/config.properties
new file mode 100644
index 0000000..100d484
--- /dev/null
+++ b/karaf/main/src/main/resources/config.properties
@@ -0,0 +1,528 @@
+# 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.
+
+#
+# Framework config properties.
+#
+org.osgi.framework.system.packages=org.osgi.framework; version=1.4.0, \
+ org.osgi.service.packageadmin; version=1.2.0, \
+ org.osgi.service.startlevel; version=1.1.0, \
+ org.osgi.service.url; version=1.0.0, \
+ org.osgi.util.tracker; version=1.3.2 \
+ ${jre-${java.specification.version}}
+
+#org.osgi.framework.bootdelegation=sun.*,com.sun.*
+#felix.cache.profile=foo
+felix.auto.start.1= \
+ file:bundle/org.apache.felix.shell-1.0.0.jar \
+ file:bundle/org.apache.felix.shell.tui-1.0.0.jar \
+ file:bundle/org.apache.felix.bundlerepository-1.0.0.jar 
+felix.log.level=4
+felix.startlevel.framework=1
+felix.startlevel.bundle=1
+#framework.service.urlhandlers=false
+
+#
+# Bundle config properties.
+#
+org.osgi.service.http.port=8080
+osgi.shell.telnet=on
+#obr.repository.url=http://bundles.osgi.org/obr/browse?_xml=1&cmd=repository
+
+#list of directories containing bundles to be loaded by SMX
+#bundle.locations=
+
+#
+# Java platform package export properties.
+#
+jre-1.3=, \
+ javax.accessibility; \
+ javax.accessibility.resources; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.basic.resources; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.metal.resources; \
+ javax.swing.plaf.multi; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.transaction; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ version="1.3.0"
+
+jre-1.4=, \
+ javax.accessibility; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.transaction; \
+ javax.transaction.xa; \
+ javax.xml.parsers; \
+ javax.xml.transform; \
+ javax.xml.transform.dom; \
+ javax.xml.transform.sax; \
+ javax.xml.transform.stream; \
+ org.ietf.jgss; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.w3c.dom; \
+ org.w3c.dom.css; \
+ org.w3c.dom.events; \
+ org.w3c.dom.html; \
+ org.w3c.dom.stylesheets; \
+ org.w3c.dom.traversal; \
+ org.w3c.dom.views; \
+ org.xml.sax; \
+ org.xml.sax.ext; \
+ org.xml.sax.helpers; \
+ version="1.4.0"
+
+jre-1.5=, \
+ javax.accessibility; \
+ javax.activity; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.bmp; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.management; \
+ javax.management.loading; \
+ javax.management.modelmbean; \
+ javax.management.monitor; \
+ javax.management.openmbean; \
+ javax.management.relation; \
+ javax.management.remote; \
+ javax.management.remote.rmi; \
+ javax.management.timer; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.rmi.ssl; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.security.sasl; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.sql.rowset; \
+ javax.sql.rowset.serial; \
+ javax.sql.rowset.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.plaf.synth; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.transaction; \
+ javax.transaction.xa; \
+ javax.xml; \
+ javax.xml.datatype; \
+ javax.xml.namespace; \
+ javax.xml.parsers; \
+ javax.xml.transform; \
+ javax.xml.transform.dom; \
+ javax.xml.transform.sax; \
+ javax.xml.transform.stream; \
+ javax.xml.validation; \
+ javax.xml.xpath; \
+ org.ietf.jgss; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.omg.stub.javax.management.remote.rmi; \
+ org.w3c.dom; \
+ org.w3c.dom.bootstrap; \
+ org.w3c.dom.css; \
+ org.w3c.dom.events; \
+ org.w3c.dom.html; \
+ org.w3c.dom.ls; \
+ org.w3c.dom.ranges; \
+ org.w3c.dom.stylesheets; \
+ org.w3c.dom.traversal; \
+ org.w3c.dom.views; \
+ org.xml.sax; \
+ org.xml.sax.ext; \
+ org.xml.sax.helpers; \
+ version="1.5.0"
+
+jre-1.6=, \
+ java.applet; \
+ java.awt; \
+ java.awt.color; \
+ java.awt.datatransfer; \
+ java.awt.dnd; \
+ java.awt.dnd.peer; \
+ java.awt.event; \
+ java.awt.font; \
+ java.awt.geom; \
+ java.awt.im; \
+ java.awt.image; \
+ java.awt.image.renderable; \
+ java.awt.im.spi; \
+ java.awt.peer; \
+ java.awt.print; \
+ java.beans; \
+ java.beans.beancontext; \
+ java.io; \
+ java.lang; \
+ java.lang.annotation; \
+ java.lang.instrument; \
+ java.lang.management; \
+ java.lang.ref; \
+ java.lang.reflect; \
+ java.math; \
+ java.net; \
+ java.nio; \
+ java.nio.channels; \
+ java.nio.channels.spi; \
+ java.nio.charset; \
+ java.nio.charset.spi; \
+ java.rmi; \
+ java.rmi.activation; \
+ java.rmi.dgc; \
+ java.rmi.registry; \
+ java.rmi.server; \
+ java.security; \
+ java.security.acl; \
+ java.security.cert; \
+ java.security.interfaces; \
+ java.security.spec; \
+ java.sql; \
+ java.text; \
+ java.text.spi; \
+ java.util; \
+ java.util.concurrent; \
+ java.util.concurrent.atomic; \
+ java.util.concurrent.locks; \
+ java.util.jar; \
+ java.util.logging; \
+ java.util.prefs; \
+ java.util.regex; \
+ java.util.spi; \
+ java.util.zip; \
+ javax.accessibility; \
+ javax.activation; \
+ javax.activity; \
+ javax.annotation; \
+ javax.annotation.processing; \
+ javax.imageio; \
+ javax.imageio.event; \
+ javax.imageio.metadata; \
+ javax.imageio.plugins.bmp; \
+ javax.imageio.plugins.jpeg; \
+ javax.imageio.spi; \
+ javax.imageio.stream; \
+ javax.jws; \
+ javax.jws.soap; \
+ javax.lang.model; \
+ javax.lang.model.element; \
+ javax.lang.model.type; \
+ javax.lang.model.util; \
+ javax.management; \
+ javax.management.loading; \
+ javax.management.modelmbean; \
+ javax.management.monitor; \
+ javax.management.openmbean; \
+ javax.management.relation; \
+ javax.management.remote; \
+ javax.management.remote.rmi; \
+ javax.management.timer; \
+ javax.naming; \
+ javax.naming.directory; \
+ javax.naming.event; \
+ javax.naming.ldap; \
+ javax.naming.spi; \
+ javax.net; \
+ javax.net.ssl; \
+ javax.print; \
+ javax.print.attribute; \
+ javax.print.attribute.standard; \
+ javax.print.event; \
+ javax.rmi; \
+ javax.rmi.CORBA; \
+ javax.rmi.ssl; \
+ javax.script; \
+ javax.security.auth; \
+ javax.security.auth.callback; \
+ javax.security.auth.kerberos; \
+ javax.security.auth.login; \
+ javax.security.auth.spi; \
+ javax.security.auth.x500; \
+ javax.security.sasl; \
+ javax.smartcardio; \
+ javax.sound.midi; \
+ javax.sound.midi.spi; \
+ javax.sound.sampled; \
+ javax.sound.sampled.spi; \
+ javax.sql; \
+ javax.sql.rowset; \
+ javax.sql.rowset.serial; \
+ javax.sql.rowset.spi; \
+ javax.swing; \
+ javax.swing.border; \
+ javax.swing.colorchooser; \
+ javax.swing.event; \
+ javax.swing.filechooser; \
+ javax.swing.plaf; \
+ javax.swing.plaf.basic; \
+ javax.swing.plaf.metal; \
+ javax.swing.plaf.multi; \
+ javax.swing.plaf.synth; \
+ javax.swing.table; \
+ javax.swing.text; \
+ javax.swing.text.html; \
+ javax.swing.text.html.parser; \
+ javax.swing.text.rtf; \
+ javax.swing.tree; \
+ javax.swing.undo; \
+ javax.tools; \
+ javax.transaction; \
+ javax.transaction.xa; \
+ javax.xml; \
+ javax.xml.bind; \
+ javax.xml.bind.annotation; \
+ javax.xml.bind.annotation.adapters; \
+ javax.xml.bind.attachment; \
+ javax.xml.bind.helpers; \
+ javax.xml.bind.util; \
+ javax.xml.crypto; \
+ javax.xml.crypto.dom; \
+ javax.xml.crypto.dsig; \
+ javax.xml.crypto.dsig.dom; \
+ javax.xml.crypto.dsig.keyinfo; \
+ javax.xml.crypto.dsig.spec; \
+ javax.xml.datatype; \
+ javax.xml.namespace; \
+ javax.xml.parsers; \
+ javax.xml.soap; \
+ javax.xml.stream; \
+ javax.xml.stream.events; \
+ javax.xml.stream.util; \
+ javax.xml.transform; \
+ javax.xml.transform.dom; \
+ javax.xml.transform.sax; \
+ javax.xml.transform.stax; \
+ javax.xml.transform.stream; \
+ javax.xml.validation; \
+ javax.xml.ws; \
+ javax.xml.ws.handler; \
+ javax.xml.ws.handler.soap; \
+ javax.xml.ws.http; \
+ javax.xml.ws.soap; \
+ javax.xml.ws.spi; \
+ javax.xml.xpath; \
+ org.ietf.jgss; \
+ org.jcp.xml.dsig.internal; \
+ org.jcp.xml.dsig.internal.dom; \
+ org.omg.CORBA; \
+ org.omg.CORBA_2_3; \
+ org.omg.CORBA_2_3.portable; \
+ org.omg.CORBA.DynAnyPackage; \
+ org.omg.CORBA.ORBPackage; \
+ org.omg.CORBA.portable; \
+ org.omg.CORBA.TypeCodePackage; \
+ org.omg.CosNaming; \
+ org.omg.CosNaming.NamingContextExtPackage; \
+ org.omg.CosNaming.NamingContextPackage; \
+ org.omg.Dynamic; \
+ org.omg.DynamicAny; \
+ org.omg.DynamicAny.DynAnyFactoryPackage; \
+ org.omg.DynamicAny.DynAnyPackage; \
+ org.omg.IOP; \
+ org.omg.IOP.CodecFactoryPackage; \
+ org.omg.IOP.CodecPackage; \
+ org.omg.Messaging; \
+ org.omg.PortableInterceptor; \
+ org.omg.PortableInterceptor.ORBInitInfoPackage; \
+ org.omg.PortableServer; \
+ org.omg.PortableServer.CurrentPackage; \
+ org.omg.PortableServer.POAManagerPackage; \
+ org.omg.PortableServer.POAPackage; \
+ org.omg.PortableServer.portable; \
+ org.omg.PortableServer.ServantLocatorPackage; \
+ org.omg.SendingContext; \
+ org.omg.stub.java.rmi; \
+ org.omg.stub.javax.management.remote.rmi; \
+ org.w3c.dom; \
+ org.w3c.dom.bootstrap; \
+ org.w3c.dom.css; \
+ org.w3c.dom.events; \
+ org.w3c.dom.html; \
+ org.w3c.dom.ls; \
+ org.w3c.dom.ranges; \
+ org.w3c.dom.stylesheets; \
+ org.w3c.dom.traversal; \
+ org.w3c.dom.views; \
+ org.w3c.dom.xpath; \
+ org.xml.sax; \
+ org.xml.sax.ext; \
+ org.xml.sax.helpers; \
+ version=\"1.6.0\"