Modify launcher to automatically install and start bundles in the
auto-deploy directory without need for configuration. (FELIX-1446)


git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@800486 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/main/pom.xml b/main/pom.xml
index 7eb0d86..c62375a 100644
--- a/main/pom.xml
+++ b/main/pom.xml
@@ -68,6 +68,10 @@
           <groupId>${pom.groupId}</groupId>
           <artifactId>org.osgi.core</artifactId>
         </exclusion>
+        <exclusion>
+          <groupId>${pom.groupId}</groupId>
+          <artifactId>org.osgi.compendium</artifactId>
+        </exclusion>
       </exclusions>
     </dependency>
     <dependency>
@@ -81,6 +85,10 @@
         </exclusion>
         <exclusion>
           <groupId>${pom.groupId}</groupId>
+          <artifactId>org.osgi.compendium</artifactId>
+        </exclusion>
+        <exclusion>
+          <groupId>${pom.groupId}</groupId>
           <artifactId>org.osgi.service.obr</artifactId>
         </exclusion>
         <exclusion>
diff --git a/main/src/main/java/org/apache/felix/main/AutoActivator.java b/main/src/main/java/org/apache/felix/main/AutoActivator.java
index c234fd8..f639c2c 100644
--- a/main/src/main/java/org/apache/felix/main/AutoActivator.java
+++ b/main/src/main/java/org/apache/felix/main/AutoActivator.java
@@ -18,17 +18,35 @@
  */
 package org.apache.felix.main;
 
+import java.io.File;
+import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 import java.util.StringTokenizer;
+import org.osgi.framework.Constants;
 import org.osgi.framework.Bundle;
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
 import org.osgi.service.startlevel.StartLevel;
 
 public class AutoActivator implements BundleActivator
 {
     /**
+     * The property name used for the bundle directory.
+    **/
+    public static final String AUTO_DEPLOY_DIR_PROPERY = "felix.auto.deploy.dir";
+    /**
+     * The default name used for the bundle directory.
+    **/
+    public static final String AUTO_DEPLOY_DIR_VALUE = "bundle";
+    /**
+     * The property name used to enable/disable automatic bundle deployment.
+    **/
+    public static final String AUTO_DEPLOY_PROP = "felix.auto.deploy";
+    /**
      * The property name prefix for the launcher's auto-install property.
     **/
     public static final String AUTO_INSTALL_PROP = "felix.auto.install";
@@ -37,7 +55,7 @@
     **/
     public static final String AUTO_START_PROP = "felix.auto.start";
 
-    private Map m_configMap;
+    private final Map m_configMap;
 
     public AutoActivator(Map configMap)
     {
@@ -52,6 +70,7 @@
     **/
     public void start(BundleContext context)
     {
+        processAutoDeploy(context);
         processAutoProperties(context);
     }
 
@@ -64,6 +83,68 @@
         // Do nothing.
     }
 
+    private void processAutoDeploy(BundleContext context)
+    {
+        // Determine if auto deploy is enabled; default is enabled.
+        String enabled = (String) m_configMap.get(AUTO_DEPLOY_PROP);
+        enabled = (enabled == null) ? Boolean.TRUE.toString() : enabled;
+        if (Boolean.valueOf(enabled).booleanValue())
+        {
+            // Get the auto deploy directory.
+            String autoDir = (String) m_configMap.get(AUTO_DEPLOY_DIR_PROPERY);
+            autoDir = (autoDir == null) ? AUTO_DEPLOY_DIR_VALUE : autoDir;
+            // Look in the specified bundle directory to create a list
+            // of all JAR files to install.
+            File[] files = new File(autoDir).listFiles();
+            if (files != null)
+            {
+                Arrays.sort(files);
+                List bundleList = new ArrayList();
+                for (int i = 0; i < files.length; i++)
+                {
+                    if (files[i].getName().endsWith(".jar"))
+                    {
+                        bundleList.add(files[i]);
+                    }
+                }
+
+                // Install bundle JAR files and remember the bundle objects.
+                final List installedList = new ArrayList();
+                for (int i = 0; i < bundleList.size(); i++)
+                {
+                    try
+                    {
+                        Bundle b = context.installBundle(
+                            ((File) bundleList.get(i)).toURI().toString());
+                        installedList.add(b);
+                    }
+                    catch (BundleException ex)
+                    {
+                        System.err.println("Auto-deploy install: "
+                            + ex + ((ex.getCause() != null) ? " - " + ex.getCause() : ""));
+                    }
+                }
+
+                // Start all installed bundles.
+                for (int i = 0; i < installedList.size(); i++)
+                {
+                    try
+                    {
+                        if (!isFragment((Bundle) installedList.get(i)))
+                        {
+                            ((Bundle) installedList.get(i)).start();
+                        }
+                    }
+                    catch (BundleException ex)
+                    {
+                        System.err.println("Auto-deploy start: "
+                            + ex + ((ex.getCause() != null) ? " - " + ex.getCause() : ""));
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * <p>
      * Processes the auto-install and auto-start properties from the
@@ -212,4 +293,9 @@
 
         return retVal;
     }
+
+    private static boolean isFragment(Bundle bundle)
+    {
+        return bundle.getHeaders().get(Constants.FRAGMENT_HOST) != null;
+    }
 }
\ No newline at end of file
diff --git a/main/src/main/java/org/apache/felix/main/Main.java b/main/src/main/java/org/apache/felix/main/Main.java
index 57d8d61..6cfa7b7 100644
--- a/main/src/main/java/org/apache/felix/main/Main.java
+++ b/main/src/main/java/org/apache/felix/main/Main.java
@@ -40,6 +40,11 @@
 public class Main
 {
     /**
+     * Switch for specifying bundle directory.
+    **/
+    public static final String BUNDLE_DIR_SWITCH = "-b";
+
+    /**
      * The property name used to specify an URL to the system
      * property file.
     **/
@@ -163,11 +168,34 @@
     **/
     public static void main(String[] args) throws Exception
     {
+// TODO: MAIN - SHOULD WE ADD A SHUTDOWN HOOK?
+
+        // Look for bundle directory and/or cache directory.
         // We support at most one argument, which is the bundle
         // cache directory.
-        if (args.length > 1)
+        String bundleDir = null;
+        String cacheDir = null;
+        boolean expectBundleDir = false;
+        for (int i = 0; i < args.length; i++)
         {
-            System.out.println("Usage: [<bundle-cache-dir>]");
+            if (args[i].equals(BUNDLE_DIR_SWITCH))
+            {
+                expectBundleDir = true;
+            }
+            else if (expectBundleDir)
+            {
+                bundleDir = args[i];
+                expectBundleDir = false;
+            }
+            else
+            {
+                cacheDir = args[i];
+            }
+        }
+
+        if ((args.length > 3) || (expectBundleDir && bundleDir == null))
+        {
+            System.out.println("Usage: [-b <bundle-deploy-dir>] [<bundle-cache-dir>]");
             System.exit(0);
         }
 
@@ -187,11 +215,18 @@
         // Copy framework properties from the system properties.
         Main.copySystemProperties(configProps);
 
+        // If there is a passed in bundle auto-deploy directory, then
+        // that overwrites anything in the config file.
+        if (bundleDir != null)
+        {
+            configProps.setProperty(AutoActivator.AUTO_DEPLOY_DIR_PROPERY, bundleDir);
+        }
+
         // If there is a passed in bundle cache directory, then
         // that overwrites anything in the config file.
-        if (args.length > 0)
+        if (cacheDir != null)
         {
-            configProps.setProperty(Constants.FRAMEWORK_STORAGE, args[0]);
+            configProps.setProperty(Constants.FRAMEWORK_STORAGE, cacheDir);
         }
 
         // Create a list for custom framework activators and
diff --git a/main/src/main/resources/config.properties b/main/src/main/resources/config.properties
index c1e0a64..9d8f509 100644
--- a/main/src/main/resources/config.properties
+++ b/main/src/main/resources/config.properties
@@ -48,10 +48,27 @@
 # "none" and "onFirstInit"; the default is "none".
 #org.osgi.framework.storage.clean=onFirstInit
 
-felix.auto.start.1= \
- file:bundle/org.apache.felix.shell-1.3.0-SNAPSHOT.jar \
- file:bundle/org.apache.felix.shell.tui-1.3.0-SNAPSHOT.jar \
- file:bundle/org.apache.felix.bundlerepository-1.5.0-SNAPSHOT.jar 
+# The following properties determines whether bundles in the bundle
+# auto-deploy directory are automatically installed and started when
+# the framework starts. The value is either true or false; the
+# default is true.
+#felix.auto.deploy=true
+
+# The following property specifies the directory to use as the bundle
+# auto-deploy directory; the default is 'bundle' in the working directory.
+felix.auto.deploy.dir=bundle
+
+# The following property is a space-delimited list of bundle URLs
+# to install when the framework starts. The ending numerical component
+# is the target start level. Any number of these properties may be
+# specified for different start levels.
+#felix.auto.install.1=
+
+# The following property is a space-delimited list of bundle URLs
+# to install and start when the framework starts. The ending numerical
+# component is the target start level. Any number of these properties
+# may be specified for different start levels.
+#felix.auto.start.1=
 
 felix.log.level=${log.level}