blob: 295b6d2b02bb2bce7b14698311a350db51c53cf7 [file] [log] [blame]
/*
* Copyright 2005 The Apache Software Foundation
*
* Licensed 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.impl;
import java.io.PrintStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import org.apache.felix.bundlerepository.*;
import org.osgi.framework.*;
public class BundleRepositoryImpl implements BundleRepository
{
private BundleContext m_context = null;
private RepositoryState m_repo = null;
public BundleRepositoryImpl(BundleContext context)
{
m_context = context;
m_repo = new RepositoryState(m_context);
}
public String[] getRepositoryURLs()
{
return m_repo.getURLs();
}
public synchronized void setRepositoryURLs(String[] urls)
{
m_repo.setURLs(urls);
}
/**
* Get the number of bundles available in the repository.
* @return the number of available bundles.
**/
public synchronized BundleRecord[] getBundleRecords()
{
return m_repo.getRecords();
}
/**
* Get the specified bundle record from the repository.
* @param i the bundle record index to retrieve.
* @return the associated bundle record or <tt>null</tt>.
**/
public synchronized BundleRecord[] getBundleRecords(String symName)
{
return m_repo.getRecords(symName);
}
/**
* Get bundle record for the bundle with the specified name
* and version from the repository.
* @param name the bundle record name to retrieve.
* @param version three-interger array of the version associated with
* the name to retrieve.
* @return the associated bundle record or <tt>null</tt>.
**/
public synchronized BundleRecord getBundleRecord(String symName, int[] version)
{
return m_repo.getRecord(symName, version);
}
public boolean deployBundle(
PrintStream out, PrintStream err, String symName, int[] version,
boolean isResolve, boolean isStart)
{
// List to hold bundles that need to be started.
List startList = null;
// Get the bundle record of the remote bundle to be deployed.
BundleRecord targetRecord = m_repo.getRecord(symName, version);
if (targetRecord == null)
{
err.println("No such bundle in repository.");
return false;
}
// Create an editable snapshot of the current set of
// locally installed bundles.
LocalState localState = new LocalState(m_context);
// If the precise bundle is already deployed, then we are done.
if (localState.findBundle(symName, version) != null)
{
return true;
}
// Create the transitive closure all bundles that must be
// deployed as a result of deploying the target bundle;
// use a list because this will keep everything in order.
BundleRecord[] deployRecords = null;
// If the resolve flag is set, then get its imports to
// calculate the transitive closure of its dependencies.
if (isResolve)
{
// Package[] imports = (Package[])
// targetRecord.getAttribute(BundleRecord.IMPORT_PACKAGE);
Filter[] reqs = (Filter[])
targetRecord.getAttribute("requirement");
try
{
deployRecords = m_repo.resolvePackages(localState, reqs);
}
catch (ResolveException ex)
{
err.println("Resolve error: " + ex.getPackage());
return false;
}
}
// Add the target bundle since it will not be
// included in the array of records to deploy.
if (deployRecords == null)
{
deployRecords = new BundleRecord[] { targetRecord };
}
else
{
// Create a new array containing the target and put it first,
// since the array will be process in reverse order.
BundleRecord[] newRecs = new BundleRecord[deployRecords.length + 1];
newRecs[0] = targetRecord;
System.arraycopy(deployRecords, 0, newRecs, 1, deployRecords.length);
deployRecords = newRecs;
}
// Now iterate through all bundles in the deploy list
// in reverse order and deploy each; the order is not
// so important, but by reversing them at least the
// dependencies will be printed first and perhaps it
// will avoid some ordering issues when we are starting
// bundles.
for (int i = 0; i < deployRecords.length; i++)
{
LocalState.LocalBundleRecord updateRecord =
localState.findUpdatableBundle(deployRecords[i]);
if (updateRecord != null)
{
// TODO: Should check to make sure that update bundle isn't already the
// correct version.
// Modify our copy of the local state to reflect
// that the bundle is now updated.
localState.update(updateRecord, deployRecords[i]);
// Print out an "updating" message.
if (deployRecords[i] != targetRecord)
{
out.print("Updating dependency: ");
}
else
{
out.print("Updating: ");
}
out.println(Util.getBundleName(updateRecord.getBundle()));
// Actually perform the update.
try
{
URL url = new URL(
(String) deployRecords[i].getAttribute(BundleRecord.BUNDLE_URL));
updateRecord.getBundle().update(url.openStream());
// If necessary, save the updated bundle to be
// started later.
if (isStart)
{
if (startList == null)
{
startList = new ArrayList();
}
startList.add(updateRecord.getBundle());
}
}
catch (Exception ex)
{
err.println("Update error: " + Util.getBundleName(updateRecord.getBundle()));
ex.printStackTrace(err);
return false;
}
}
else
{
// Print out an "installing" message.
if (deployRecords[i] != targetRecord)
{
out.print("Installing dependency: ");
}
else
{
out.print("Installing: ");
}
out.println(deployRecords[i].getAttribute(BundleRecord.BUNDLE_NAME));
try
{
// Actually perform the install, but do not use the actual
// bundle JAR URL for the bundle location, since this will
// limit OBR's ability to manipulate bundle versions. Instead,
// use a unique timestamp as the bundle location.
URL url = new URL(
(String) deployRecords[i].getAttribute(BundleRecord.BUNDLE_URL));
Bundle bundle = m_context.installBundle(
"obr://"
+ deployRecords[i].getAttribute(BundleRecord.BUNDLE_NAME)
+ "/" + System.currentTimeMillis(),
url.openStream());
// If necessary, save the installed bundle to be
// started later.
if (isStart)
{
if (startList == null)
{
startList = new ArrayList();
}
startList.add(bundle);
}
}
catch (Exception ex)
{
err.println("Install error: "
+ deployRecords[i].getAttribute(BundleRecord.BUNDLE_NAME));
ex.printStackTrace(err);
return false;
}
}
}
// If necessary, start bundles after installing them all.
if (isStart)
{
for (int i = 0; (startList != null) && (i < startList.size()); i++)
{
Bundle bundle = (Bundle) startList.get(i);
try
{
bundle.start();
}
catch (BundleException ex)
{
err.println("Update error: " + Util.getBundleName(bundle));
ex.printStackTrace();
}
}
}
return true;
}
public BundleRecord[] resolvePackages(IPackage[] pkgs)
throws ResolveException
{
// TODO: FIX
// return m_repo.resolvePackages(new LocalState(m_context), pkgs);
return null;
}
}