You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by ri...@apache.org on 2009/04/28 13:13:10 UTC

svn commit: r769335 - in /felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository: Activator.java ObrURLStreamHandlerService.java

Author: rickhall
Date: Tue Apr 28 11:13:09 2009
New Revision: 769335

URL: http://svn.apache.org/viewvc?rev=769335&view=rev
Log:
Apply patch (FELIX-1000) to implement a URLStreamHandler for OBR so that
OBR-installed bundles can be correctly updated.

Added:
    felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrURLStreamHandlerService.java
Modified:
    felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java

Modified: felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java?rev=769335&r1=769334&r2=769335&view=diff
==============================================================================
--- felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java (original)
+++ felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/Activator.java Tue Apr 28 11:13:09 2009
@@ -1,4 +1,4 @@
-/* 
+/*
  * 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
@@ -18,9 +18,13 @@
  */
 package org.apache.felix.bundlerepository;
 
+import java.util.Hashtable;
+
 import org.osgi.framework.BundleActivator;
 import org.osgi.framework.BundleContext;
 import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.url.URLConstants;
+import org.osgi.service.url.URLStreamHandlerService;
 
 public class Activator implements BundleActivator
 {
@@ -52,6 +56,19 @@
         {
             // Ignore.
         }
+
+        try
+        {
+			Hashtable dict = new Hashtable();
+			dict.put(URLConstants.URL_HANDLER_PROTOCOL, "obr");
+			context.registerService(URLStreamHandlerService.class.getName(),
+					new ObrURLStreamHandlerService(m_context, m_repoAdmin), dict);
+		}
+        catch (Exception e)
+		{
+			throw new RuntimeException("could not register obr url handler");
+		}
+
     }
 
     public void stop(BundleContext context)

Added: felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrURLStreamHandlerService.java
URL: http://svn.apache.org/viewvc/felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrURLStreamHandlerService.java?rev=769335&view=auto
==============================================================================
--- felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrURLStreamHandlerService.java (added)
+++ felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository/ObrURLStreamHandlerService.java Tue Apr 28 11:13:09 2009
@@ -0,0 +1,246 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.bundlerepository;
+
+import java.io.IOException;
+import java.net.URL;
+import java.net.URLConnection;
+import java.net.URLStreamHandler;
+import java.util.Iterator;
+import java.util.Set;
+import java.util.SortedMap;
+import java.util.TreeMap;
+
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.Version;
+import org.osgi.service.obr.RepositoryAdmin;
+import org.osgi.service.obr.Resource;
+import org.osgi.service.url.AbstractURLStreamHandlerService;
+
+/**
+ * Simple {@link URLStreamHandler} which is able to handle
+ * obr urls. The urls must be conform the following schema:
+ *
+ *  obr://<symbolicName>/<timeStamp>
+ *
+ * Example:
+ *
+ *  obr://org.apache.felix.javax.servlet/1240305961998
+ *
+ *
+ * Update to the bundle is done
+ *
+ */
+public class ObrURLStreamHandlerService extends AbstractURLStreamHandlerService
+{
+    /**
+     * The BundleContext to search for the bundles.
+     */
+    private final BundleContext m_bundleContext;
+    /**
+     * The RepositoryAdmin to query for the actual url
+     * for a bundle.
+     */
+    private final RepositoryAdmin m_reRepositoryAdmin;
+    /**
+     * Logger to use.
+     */
+    private final Logger m_logger;
+    /**
+     * The update strategy to use.
+     * Default: newest
+     */
+    private String m_updateStrategy = "newest";
+    /**
+     * Property defining the obr update strategy
+     */
+    public static final String OBR_UPDATE_STRATEGY = "obr.update.strategy";
+
+    /**
+     * Constructor
+     *
+     * @param context context to use
+     * @param admin admin to use
+     */
+    public ObrURLStreamHandlerService(BundleContext context, RepositoryAdmin admin)
+    {
+        m_bundleContext = context;
+        m_reRepositoryAdmin = admin;
+        m_logger = new Logger(context);
+        if (m_bundleContext.getProperty(OBR_UPDATE_STRATEGY) != null)
+        {
+            this.m_updateStrategy = m_bundleContext.getProperty(OBR_UPDATE_STRATEGY);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * This implementation looks up the bundle with the given
+     * url set as location String within the current {@link BundleContext}.
+     * The real url for this bundle is determined afterwards via the
+     * {@link RepositoryAdmin}.
+     */
+    public URLConnection openConnection(URL u) throws IOException
+    {
+        String url = u.toExternalForm();
+
+        URL remoteURL = null;
+
+        Bundle[] bundles = m_bundleContext.getBundles();
+
+        int i = 0;
+        while ((remoteURL == null) && (i < bundles.length))
+        {
+            if (url.equals(bundles[i].getLocation()))
+            {
+                remoteURL = getRemoteUrlForBundle(bundles[i]);
+            }
+            i++;
+        }
+
+        if (remoteURL == null)
+        {
+            throw new IOException("could not resolve obr url to remote url! " + u);
+        }
+
+        return remoteURL.openConnection();
+
+    }
+
+    /**
+     * Determines the remote url for the given bundle according to
+     * the configured {@link ResourceSelectionStrategy}.
+     *
+     * @param bundle bundle
+     * @return remote url
+     * @throws IOException if something went wrong
+     */
+    private URL getRemoteUrlForBundle(Bundle bundle) throws IOException
+    {
+        String bundleVersion =
+            (String) bundle.getHeaders().get(Constants.BUNDLE_VERSION);
+        StringBuffer buffer = new StringBuffer();
+        buffer.append("(symbolicname=");
+        buffer.append(bundle.getSymbolicName());
+        buffer.append(")");
+
+        Resource[] discoverResources =
+            m_reRepositoryAdmin.discoverResources(buffer.toString());
+
+        ResourceSelectionStrategy strategy = getStrategy(m_updateStrategy);
+        Resource selected = strategy.selectOne(
+            Version.parseVersion(bundleVersion), discoverResources);
+
+        return selected.getURL();
+    }
+
+    private ResourceSelectionStrategy getStrategy(String strategy)
+    {
+        m_logger.log(Logger.LOG_DEBUG, "Using ResourceSelectionStrategy: " + strategy);
+
+        if ("same".equals(strategy))
+        {
+            return new SameSelectionStrategy(m_logger);
+        }
+        else if ("newest".equals(strategy))
+        {
+            return new NewestSelectionStrategy(m_logger);
+        }
+
+        throw new RuntimeException("Could not determine obr update strategy : " + strategy);
+    }
+
+    /**
+     * Abstract class for Resource Selection Strategies
+     */
+    private static abstract class ResourceSelectionStrategy
+    {
+        private final Logger m_logger;
+
+        ResourceSelectionStrategy(Logger logger)
+        {
+            m_logger = logger;
+        }
+
+        Logger getLogger()
+        {
+            return m_logger;
+        }
+
+        final Resource selectOne(Version currentVersion, Resource[] resources)
+        {
+            SortedMap sortedResources = new TreeMap();
+            for (int i = 0; i < resources.length; i++)
+            {
+                sortedResources.put(resources[i].getVersion(), resources[i]);
+            }
+
+            Version versionToUse = determineVersion(currentVersion, sortedResources);
+
+            m_logger.log(Logger.LOG_DEBUG,
+                "Using Version " + versionToUse + " for bundle "
+                + resources[0].getSymbolicName());
+
+            return (Resource) sortedResources.get(versionToUse);
+        }
+
+        abstract Version determineVersion(Version currentVersion, SortedMap sortedResources);
+    }
+
+    /**
+     * Strategy returning the current version.
+     */
+    static class SameSelectionStrategy extends ResourceSelectionStrategy
+    {
+        SameSelectionStrategy(Logger logger)
+        {
+            super(logger);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        Version determineVersion(Version currentVersion, SortedMap sortedResources)
+        {
+            return currentVersion;
+        }
+    }
+
+    /**
+     * Strategy returning the newest entry.
+     */
+    static class NewestSelectionStrategy extends ResourceSelectionStrategy
+    {
+        NewestSelectionStrategy(Logger logger)
+        {
+            super(logger);
+        }
+
+        /**
+         * {@inheritDoc}
+         */
+        Version determineVersion(Version currentVersion, SortedMap sortedResources)
+        {
+            return (Version) sortedResources.lastKey();
+        }
+    }
+}
\ No newline at end of file