blob: c9616a4dd66cbf83f5d07224f3e4e272029a7b89 [file] [log] [blame]
/*
* 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.webconsole.internal.core;
import java.io.File;
import java.io.InputStream;
import org.apache.felix.bundlerepository.Reason;
import org.apache.felix.webconsole.SimpleWebConsolePlugin;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleException;
import org.osgi.framework.Constants;
import org.osgi.service.log.LogService;
import org.osgi.service.obr.RepositoryAdmin;
import org.osgi.service.obr.Requirement;
import org.osgi.service.obr.Resolver;
import org.osgi.service.obr.Resource;
class UpdateHelper extends BaseUpdateInstallHelper
{
private final Bundle bundle;
UpdateHelper( final SimpleWebConsolePlugin plugin, final Bundle bundle, boolean refreshPackages )
{
this( plugin, bundle, null, refreshPackages );
}
UpdateHelper( final SimpleWebConsolePlugin plugin, final Bundle bundle, final File bundleFile,
boolean refreshPackages )
{
super( plugin, "Background Update " + bundle.getSymbolicName() + " (" + bundle.getBundleId() + ")",
bundleFile, refreshPackages );
this.bundle = bundle;
}
protected Bundle doRun( final InputStream bundleStream ) throws BundleException
{
bundle.update( bundleStream );
return bundle;
}
protected Bundle getTargetBundle()
{
return bundle;
}
protected Bundle doRun() throws Exception
{
// update the bundle from the file if defined
if ( getBundleFile() != null )
{
return super.doRun();
}
// try updating from the bundle location
if ( updateFromBundleLocation() )
{
return bundle;
}
// ensure we have a symbolic name for the OBR update to follow
if ( bundle.getSymbolicName() == null )
{
throw new BundleException( "Cannot update bundle: Symbolic Name is required for OBR update" );
}
// try updating from Apache Felix OBR
if ( updateFromFelixOBR() )
{
return bundle;
}
// try updating from OSGi OBR
if ( updateFromOsgiOBR() )
{
return bundle;
}
// bundle was not updated, return nothing
return null;
}
private boolean updateFromBundleLocation()
{
getLog().log( LogService.LOG_DEBUG, "Trying to update with Bundle.update()" );
try
{
bundle.update();
getLog().log( LogService.LOG_INFO, "Bundle updated from bundle provided (update) location" );
return true;
}
catch ( Throwable ioe )
{
// BundleException, IllegalStateException or SecurityException? lets use OBR then
getLog().log( LogService.LOG_DEBUG, "Update failure using Bundle.update()", ioe );
}
// not installed from the bundle location
return false;
}
private boolean updateFromFelixOBR()
{
org.apache.felix.bundlerepository.RepositoryAdmin ra = ( org.apache.felix.bundlerepository.RepositoryAdmin ) getService( "org.apache.felix.bundlerepository.RepositoryAdmin" );
if ( ra != null )
{
getLog().log( LogService.LOG_DEBUG, "Trying to update from OSGi Bundle Repository (Apache Felix API)" );
final org.apache.felix.bundlerepository.Resolver resolver = ra.resolver();
String version = ( String ) bundle.getHeaders().get( Constants.BUNDLE_VERSION );
if ( version == null )
{
version = "0.0.0";
}
final String filter = "(&(symbolicname=" + bundle.getSymbolicName() + ")(!(version=" + version
+ "))(version>=" + version + "))";
final org.apache.felix.bundlerepository.Requirement req = ra.getHelper().requirement(
bundle.getSymbolicName(), filter );
final org.apache.felix.bundlerepository.Resource[] resources = ra
.discoverResources( new org.apache.felix.bundlerepository.Requirement[]
{ req } );
final org.apache.felix.bundlerepository.Resource resource = selectHighestVersion( resources );
if ( resource != null )
{
resolver.add( resource );
if ( !resolver.resolve() )
{
logRequirements( "Cannot updated bundle from OBR due to unsatisfied requirements", resolver
.getUnsatisfiedRequirements() );
}
else
{
logResource( "Installing Requested Resources", resolver.getAddedResources() );
logResource( "Installing Required Resources", resolver.getRequiredResources() );
logResource( "Installing Optional Resources", resolver.getOptionalResources() );
// deploy the resolved bundles and ensure they are started
resolver.deploy( org.apache.felix.bundlerepository.Resolver.START );
getLog().log( LogService.LOG_INFO, "Bundle updated from OSGi Bundle Repository" );
return true;
}
}
else
{
getLog().log( LogService.LOG_INFO,
"Nothing to update, OSGi Bundle Repository does not provide more recent version" );
}
}
else
{
getLog().log( LogService.LOG_DEBUG, "Cannot updated from OSGi Bundle Repository: Service not available" );
}
// fallback to false, nothing done
return false;
}
private boolean updateFromOsgiOBR()
{
RepositoryAdmin ra = ( RepositoryAdmin ) getService( "org.osgi.service.obr.RepositoryAdmin" );
if ( ra != null )
{
getLog().log( LogService.LOG_DEBUG, "Trying to update from OSGi Bundle Repository (OSGi API)" );
final Resolver resolver = ra.resolver();
String version = ( String ) bundle.getHeaders().get( Constants.BUNDLE_VERSION );
if ( version == null )
{
version = "0.0.0";
}
final String filter = "(&(symbolicname=" + bundle.getSymbolicName() + ")(!(version=" + version
+ "))(version>=" + version + "))";
final Resource[] resources = ra.discoverResources( filter );
final Resource resource = selectHighestVersion( resources );
if ( resource != null )
{
resolver.add( resource );
if ( !resolver.resolve() )
{
logRequirements( "Cannot updated bundle from OBR due to unsatisfied requirements", resolver
.getUnsatisfiedRequirements() );
}
else
{
logResource( "Installing Requested Resources", resolver.getAddedResources() );
logResource( "Installing Required Resources", resolver.getRequiredResources() );
logResource( "Installing Optional Resources", resolver.getOptionalResources() );
// deploy the resolved bundles and ensure they are started
resolver.deploy( true );
getLog().log( LogService.LOG_INFO, "Bundle updated from OSGi Bundle Repository" );
return true;
}
}
else
{
getLog().log( LogService.LOG_INFO,
"Nothing to update, OSGi Bundle Repository does not provide more recent version" );
}
}
else
{
getLog().log( LogService.LOG_DEBUG, "Cannot updated from OSGi Bundle Repository: Service not available" );
}
// fallback to false, nothing done
return false;
}
//---------- Apache Felix OBR API helper
private org.apache.felix.bundlerepository.Resource selectHighestVersion(
final org.apache.felix.bundlerepository.Resource[] candidates )
{
if ( candidates == null || candidates.length == 0 )
{
// nothing to do if there are none
return null;
}
else if ( candidates.length == 1 )
{
// simple choice if there is a single one
return candidates[0];
}
// now go on looking for the highest version
org.apache.felix.bundlerepository.Resource best = candidates[0];
for ( int i = 1; i < candidates.length; i++ )
{
if ( best.getVersion().compareTo( candidates[i].getVersion() ) < 0 )
{
best = candidates[i];
}
}
return best;
}
private void logResource( String message, org.apache.felix.bundlerepository.Resource[] res )
{
if ( res != null && res.length > 0 )
{
getLog().log( LogService.LOG_INFO, message );
for ( int i = 0; i < res.length; i++ )
{
getLog().log( LogService.LOG_INFO,
" " + i + ": " + res[i].getSymbolicName() + ", " + res[i].getVersion() );
}
}
}
private void logRequirements( String message, Reason[] reasons )
{
getLog().log( LogService.LOG_ERROR, message );
for ( int i = 0; reasons != null && i < reasons.length; i++ )
{
String moreInfo = reasons[i].getRequirement().getComment();
if ( moreInfo == null )
{
moreInfo = reasons[i].getRequirement().getFilter().toString();
}
getLog().log( LogService.LOG_ERROR,
" " + i + ": " + reasons[i].getRequirement().getName() + " (" + moreInfo + ")" );
}
}
//---------- OSGi OBR API helper
private Resource selectHighestVersion( final Resource[] candidates )
{
if ( candidates == null || candidates.length == 0 )
{
// nothing to do if there are none
return null;
}
else if ( candidates.length == 1 )
{
// simple choice if there is a single one
return candidates[0];
}
// now go on looking for the highest version
Resource best = candidates[0];
for ( int i = 1; i < candidates.length; i++ )
{
if ( best.getVersion().compareTo( candidates[i].getVersion() ) < 0)
{
best = candidates[i];
}
}
return best;
}
private void logResource( String message, Resource[] res )
{
if ( res != null && res.length > 0 )
{
getLog().log( LogService.LOG_INFO, message );
for ( int i = 0; i < res.length; i++ )
{
getLog().log( LogService.LOG_INFO,
" " + i + ": " + res[i].getSymbolicName() + ", " + res[i].getVersion() );
}
}
}
private void logRequirements( String message, Requirement[] reasons )
{
getLog().log( LogService.LOG_ERROR, message );
for ( int i = 0; reasons != null && i < reasons.length; i++ )
{
String moreInfo = reasons[i].getComment();
if ( moreInfo == null )
{
moreInfo = reasons[i].getFilter().toString();
}
getLog().log( LogService.LOG_ERROR, " " + i + ": " + reasons[i].getName() + " (" + moreInfo + ")" );
}
}
}