Return-Path: Delivered-To: apmail-felix-commits-archive@www.apache.org Received: (qmail 10640 invoked from network); 28 Apr 2009 11:13:32 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (140.211.11.3) by minotaur.apache.org with SMTP; 28 Apr 2009 11:13:32 -0000 Received: (qmail 85699 invoked by uid 500); 28 Apr 2009 11:13:31 -0000 Delivered-To: apmail-felix-commits-archive@felix.apache.org Received: (qmail 85625 invoked by uid 500); 28 Apr 2009 11:13:31 -0000 Mailing-List: contact commits-help@felix.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@felix.apache.org Delivered-To: mailing list commits@felix.apache.org Received: (qmail 85616 invoked by uid 99); 28 Apr 2009 11:13:31 -0000 Received: from athena.apache.org (HELO athena.apache.org) (140.211.11.136) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 Apr 2009 11:13:31 +0000 X-ASF-Spam-Status: No, hits=-2000.0 required=10.0 tests=ALL_TRUSTED X-Spam-Check-By: apache.org Received: from [140.211.11.4] (HELO eris.apache.org) (140.211.11.4) by apache.org (qpsmtpd/0.29) with ESMTP; Tue, 28 Apr 2009 11:13:31 +0000 Received: by eris.apache.org (Postfix, from userid 65534) id B6C03238896C; Tue, 28 Apr 2009 11:13:10 +0000 (UTC) Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Subject: svn commit: r769335 - in /felix/trunk/bundlerepository/src/main/java/org/apache/felix/bundlerepository: Activator.java ObrURLStreamHandlerService.java Date: Tue, 28 Apr 2009 11:13:10 -0000 To: commits@felix.apache.org From: rickhall@apache.org X-Mailer: svnmailer-1.0.8 Message-Id: <20090428111310.B6C03238896C@eris.apache.org> X-Virus-Checked: Checked by ClamAV on apache.org 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:/// + * + * 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