You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by fm...@apache.org on 2007/12/18 11:25:29 UTC

svn commit: r605168 - in /incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app: BootstrapInstaller.java Sling.java

Author: fmeschbe
Date: Tue Dec 18 02:25:25 2007
New Revision: 605168

URL: http://svn.apache.org/viewvc?rev=605168&view=rev
Log:
SLING-138 Implement bootstrap bundle installation not done by the
Felix framework anymore.

Added:
    incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/BootstrapInstaller.java
Modified:
    incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/Sling.java

Added: incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/BootstrapInstaller.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/BootstrapInstaller.java?rev=605168&view=auto
==============================================================================
--- incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/BootstrapInstaller.java (added)
+++ incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/BootstrapInstaller.java Tue Dec 18 02:25:25 2007
@@ -0,0 +1,200 @@
+/*
+ * 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.sling.launcher.app;
+
+import java.io.InputStream;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.BundleException;
+import org.osgi.framework.ServiceReference;
+import org.osgi.service.startlevel.StartLevel;
+
+/**
+ * The <code>BootstrapInstaller</code> class is installed into the OSGi
+ * framework as an activator to be called when the framework is starting up.
+ * Upon startup all bundles from the {@link #PATH_CORE_BUNDLES} and the
+ * {@link #PATH_BUNDLES} location are checked whether they are already installed
+ * or not. If they are not installed, they are installed, their start level set
+ * to 1 and started. Any bundle already installed is not installed again and
+ * will also not be started here.
+ */
+class BootstrapInstaller implements BundleActivator {
+
+    /**
+     * The Bundle location scheme (protocol) used for bundles installed by this
+     * activator (value is "slinginstall:"). The path part of the Bundle
+     * location of Bundles installed by this class is the name (without the
+     * path) of the resource from which the Bundle was installed.
+     */
+    public static final String SCHEME = "slinginstall:";
+
+    /**
+     * The location the core Bundles (value is "resources/corebundles"). These
+     * bundles are installed first.
+     */
+    public static final String PATH_CORE_BUNDLES = "resources/corebundles";
+
+    /**
+     * The location the additional Bundles (value is "resources/bundles"). These
+     * Bundles are installed after the {@link #PATH_CORE_BUNDLES core Bundles}.
+     */
+    public static final String PATH_BUNDLES = "resources/bundles";
+
+    /**
+     * The {@link Logger} use for logging messages during installation and
+     * startup.
+     */
+    private final Logger logger;
+
+    /**
+     * The {@link ResourceProvider} used to access the Bundle jar files to
+     * install.
+     */
+    private final ResourceProvider resourceProvider;
+
+    BootstrapInstaller(Logger logger, ResourceProvider resourceProvider) {
+        this.logger = logger;
+        this.resourceProvider = resourceProvider;
+    }
+
+    /**
+     * Installs any Bundles missing in the current framework instance. The
+     * Bundles are verified by the Bundle location string. All missing Bundles
+     * are first installed and then started in the order of installation.
+     */
+    public void start(BundleContext context) throws Exception {
+
+        // list all existing bundles
+        Bundle[] bundles = context.getBundles();
+        Map<String, Bundle> byLocation = new HashMap<String, Bundle>();
+        for (int i = 0; i < bundles.length; i++) {
+            byLocation.put(bundles[i].getLocation(), bundles[i]);
+        }
+
+        // install bundles
+        List<Bundle> installed = new LinkedList<Bundle>();
+        installBundles(context, byLocation, PATH_CORE_BUNDLES, installed);
+        installBundles(context, byLocation, PATH_BUNDLES, installed);
+
+        // set start levels on the bundles and start them
+        startBundles(context, installed);
+    }
+
+    /** Nothing to be done on stop */
+    public void stop(BundleContext context) {
+    }
+
+    /**
+     * Install the Bundles from JAR files found in the given <code>parent</code>
+     * path.
+     * 
+     * @param context The <code>BundleContext</code> used to install the new
+     *            Bundles.
+     * @param currentBundles The currently installed Bundles indexed by their
+     *            Bundle location.
+     * @param parent The path to the location in which to look for JAR files to
+     *            install. Only resources whose name ends with <em>.jar</em>
+     *            are considered for installation.
+     * @param installed The list of Bundles installed by this method. Each
+     *            Bundle successfully installed is added to this list.
+     */
+    private void installBundles(BundleContext context,
+            Map<String, Bundle> currentBundles, String parent,
+            List<Bundle> installed) {
+        
+        Iterator<String> res = resourceProvider.getChildren(parent);
+        while (res.hasNext()) {
+            
+            String path = res.next();
+            
+            if (path.endsWith(".jar")) {
+
+                // check for an already installed Bundle with the given location
+                String location = SCHEME
+                    + path.substring(path.lastIndexOf('/') + 1);
+                if (currentBundles.containsKey(location)) {
+                    continue;
+                }
+
+                // try to access the JAR file, ignore if not possible
+                InputStream ins = resourceProvider.getResourceAsStream(path);
+                if (ins == null) {
+                    continue;
+                }
+
+                // install the JAR file as a bundle
+                Bundle newBundle;
+                try {
+                    newBundle = context.installBundle(location, ins);
+                    logger.log("Bundle " + newBundle.getSymbolicName()
+                        + " installed from " + location);
+                } catch (BundleException be) {
+                    logger.log("Bundle installation from " + location
+                        + " failed", be);
+                    continue;
+                }
+
+                // finally add the bundle to the list for later start
+                installed.add(newBundle);
+            }
+        }
+    }
+
+    /**
+     * Starts the Bundles in the <code>bundles</code> list. If the framework
+     * provides an active <code>StartLevel</code> service, the start levels of
+     * the Bundles is first set to <em>1</em>.
+     */
+    private void startBundles(BundleContext context, List<Bundle> bundles) {
+
+        // the start level service to set the initial start level
+        ServiceReference ref = context.getServiceReference(StartLevel.class.getName());
+        StartLevel startLevel = (ref != null)
+                ? (StartLevel) context.getService(ref)
+                : null;
+
+        // start all bundles
+        for (Bundle bundle : bundles) {
+
+            if (startLevel != null) {
+                startLevel.setBundleStartLevel(bundle, 1);
+            }
+
+            try {
+                bundle.start();
+            } catch (BundleException be) {
+                logger.log("Bundle " + bundle.getSymbolicName()
+                    + " could not be started", be);
+            }
+        }
+
+        // release the start level service
+        if (ref != null) {
+            context.ungetService(ref);
+        }
+    }
+
+}

Modified: incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/Sling.java
URL: http://svn.apache.org/viewvc/incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/Sling.java?rev=605168&r1=605167&r2=605168&view=diff
==============================================================================
--- incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/Sling.java (original)
+++ incubator/sling/trunk/launcher/app/src/main/java/org/apache/sling/launcher/app/Sling.java Tue Dec 18 02:25:25 2007
@@ -16,13 +16,14 @@
  */
 package org.apache.sling.launcher.app;
 
+import static org.apache.felix.framework.util.FelixConstants.EMBEDDED_EXECUTION_PROP;
+
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
-import java.net.URL;
 import java.util.ArrayList;
 import java.util.HashMap;
 import java.util.Hashtable;
@@ -181,12 +182,6 @@
     public static final String CONFIG_PROPERTIES = "sling.properties";
 
     /**
-     * The property name prefix for the launcher's auto-start property.
-     * FIXME - This is just a temporary solution to get this module compilable.
-     **/
-    public static final String AUTO_START_PROP = "felix.auto.start";
-
-    /**
      * The simple logger to log messages during startup and shutdown to
      */
     protected final Logger logger;
@@ -227,7 +222,6 @@
 
         // check for auto-start bundles
         this.setInstallBundles(props);
-        this.setAutoStartBundles(props);
 
         // ensure execution environment
         this.setExecutionEnvironment(props);
@@ -236,11 +230,12 @@
         props.put(SLING_ID, getInstanceId(props));
 
         // make sure Felix does not exit the VM when terminating ...
-        props.put("felix.embedded.execution", "true");
+        props.put(EMBEDDED_EXECUTION_PROP, "true");
 
         // the custom activator list just contains this servlet
         List<BundleActivator> activators = new ArrayList<BundleActivator>();
         activators.add(this);
+        activators.add(new BootstrapInstaller(logger, resourceProvider));
 
         // create the framework and start it
         Felix tmpFelix = new Felix(props, activators);
@@ -566,36 +561,6 @@
         props.put(prefix + "bundles", buf.toString());
     }
 
-    private void setAutoStartBundles(Map<String, String> props) {
-
-        String propName = AUTO_START_PROP + ".1";
-        StringBuffer buf = new StringBuffer();
-
-        // take over the current value
-        String autostart = props.get(propName);
-        if (autostart != null) {
-            buf.append(autostart);
-        }
-
-        this.listBundles(buf, "resources/corebundles");
-        this.listBundles(buf, "resources/bundles");
-
-        props.put(propName, buf.toString());
-    }
-
-    private void listBundles(StringBuffer list, String path) {
-        Iterator<String> res = this.resourceProvider.getChildren(path);
-        while (res.hasNext()) {
-            String name = res.next();
-            if (name.endsWith(".jar")) {
-                URL url = this.resourceProvider.getResource(name);
-                if (url != null) {
-                    list.append(" ").append(this.toString(url));
-                }
-            }
-        }
-    }
-
     /**
      * Ensures sensible Execution Environment setting. If the
      * <code>org.osgi.framework.executionenvironment</code> property is set in
@@ -699,41 +664,6 @@
         }
 
         return slingId;
-    }
-
-    /**
-     * Convert the URL into a string. If the URL string contains blank spaces,
-     * which may happen if the <code>File.toURL()</code> method is used on
-     * files whose path contains blank spaces, this method replaces the blank
-     * spaces with their URL encoding <code>%20</code>. No other encoding
-     * takes place.
-     * <p>
-     * Note: This is a quick solution to a problem with the CQSE servlet
-     * container which uses the File.toURL() method to return an URL for a web
-     * application contained resource.
-     *
-     * @param url The <code>URL</code> to convert into a string
-     * @return The URL string with any blanks replaced by "%20"
-     */
-    private String toString(URL url) {
-        String urlS = url.toExternalForm();
-
-        // return unmodified, if there is no blank
-        if (urlS.indexOf(' ') < 0) {
-            return urlS;
-        }
-
-        // otherwise replace all blanks with "%20"
-        StringBuffer buf = new StringBuffer();
-        for (int i = 0; i < urlS.length(); i++) {
-            char c = urlS.charAt(i);
-            if (c == ' ') {
-                buf.append("%20");
-            } else {
-                buf.append(c);
-            }
-        }
-        return buf.toString();
     }
 
     // ---------- Extension support --------------------------------------------