blob: 90b4e27cf103bfbc0263283072aafa858b654337 [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.fileinstall.internal;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.SecureRandom;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import org.apache.felix.fileinstall.ArtifactInstaller;
import org.apache.felix.fileinstall.ArtifactListener;
import org.apache.felix.fileinstall.ArtifactTransformer;
import org.apache.felix.fileinstall.ArtifactUrlTransformer;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleEvent;
import org.osgi.framework.BundleException;
import org.osgi.framework.BundleListener;
import org.osgi.framework.Constants;
import org.osgi.framework.Version;
import org.osgi.service.packageadmin.PackageAdmin;
/**
* -DirectoryWatcher-
*
* This class runs a background task that checks a directory for new files or
* removed files. These files can be configuration files or jars.
* For jar files, its behavior is defined below:
* - If there are new jar files, it installs them and optionally starts them.
* - If it fails to install a jar, it does not try to install it again until
* the jar has been modified.
* - If it fail to start a bundle, it attempts to start it in following
* iterations until it succeeds or the corresponding jar is uninstalled.
* - If some jar files have been deleted, it uninstalls them.
* - If some jar files have been updated, it updates them.
* - If it fails to update a bundle, it tries to update it in following
* iterations until it is successful.
* - If any bundle gets updated or uninstalled, it refreshes the framework
* for the changes to take effect.
* - If it detects any new installations, uninstallations or updations,
* it tries to start all the managed bundle unless it has been configured
* to only install bundles.
*
* @author <a href="mailto:dev@felix.apache.org">Felix Project Team</a>
*/
public class DirectoryWatcher extends Thread implements BundleListener
{
public final static String FILENAME = "felix.fileinstall.filename";
public final static String POLL = "felix.fileinstall.poll";
public final static String DIR = "felix.fileinstall.dir";
public final static String DEBUG = "felix.fileinstall.debug";
public final static String TMPDIR = "felix.fileinstall.tmpdir";
public final static String FILTER = "felix.fileinstall.filter";
public final static String START_NEW_BUNDLES = "felix.fileinstall.bundles.new.start";
public final static String NO_INITIAL_DELAY = "felix.fileinstall.noInitialDelay";
static final SecureRandom random = new SecureRandom();
static final File javaIoTmpdir = new File(System.getProperty("java.io.tmpdir"));
Dictionary properties;
File watchedDirectory;
File tmpDir;
long poll;
long debug;
boolean startBundles;
String filter;
BundleContext context;
String originatingFileName;
boolean noInitialDelay;
// Map of all installed artifacts
Map/* <File, Artifact> */ currentManagedArtifacts = new HashMap/* <File, Artifact> */();
// The scanner to report files changes
Scanner scanner;
// Represents files that could not be processed because of a missing artifact listener
Set/* <File> */ processingFailures = new HashSet/* <File> */();
// Represents artifacts that could not be installed
Map/* <File, Artifact> */ installationFailures = new HashMap/* <File, Artifact> */();
public DirectoryWatcher(Dictionary properties, BundleContext context)
{
super(properties.toString());
this.properties = properties;
this.context = context;
poll = getLong(properties, POLL, 2000);
debug = getLong(properties, DEBUG, -1);
originatingFileName = (String) properties.get(FILENAME);
watchedDirectory = getFile(properties, DIR, new File("./load"));
prepareDir(watchedDirectory);
tmpDir = getFile(properties, TMPDIR, null);
prepareTempDir();
startBundles = getBoolean(properties, START_NEW_BUNDLES, true); // by default, we start bundles.
filter = (String) properties.get(FILTER);
noInitialDelay = getBoolean(properties, NO_INITIAL_DELAY, false);
this.context.addBundleListener(this);
FilenameFilter flt;
if (filter != null && filter.length() > 0)
{
flt = new FilenameFilter()
{
public boolean accept(File dir, String name) {
return name.matches(filter);
}
};
}
else
{
flt = null;
}
scanner = new Scanner(watchedDirectory, flt);
}
public Dictionary getProperties() {
return properties;
}
public void start() {
if (noInitialDelay)
{
log("Starting initial scan", null);
initializeCurrentManagedBundles();
Set/*<File>*/ files = scanner.scan(true);
if (files != null)
{
process(files);
}
}
super.start();
}
/**
* Main run loop, will traverse the directory, and then handle the delta
* between installed and newly found/lost bundles and configurations.
*
*/
public void run()
{
log("{" + POLL + " (ms) = " + poll + ", "
+ DIR + " = " + watchedDirectory.getAbsolutePath() + ", "
+ DEBUG + " = " + debug + ", "
+ START_NEW_BUNDLES + " = " + startBundles + ", "
+ TMPDIR + " = " + tmpDir + ", "
+ FILTER + " = " + filter + "}", null);
if (!noInitialDelay)
{
initializeCurrentManagedBundles();
}
while (!interrupted())
{
try
{
Set/*<File>*/ files = scanner.scan(false);
// Check that there is a result. If not, this means that the directory can not be listed,
// so it's presumably not a valid directory (it may have been deleted by someone).
// In such case, just sleep
if (files == null)
{
synchronized (this)
{
wait(poll);
}
continue;
}
process(files);
synchronized (this)
{
wait(poll);
}
}
catch (InterruptedException e)
{
return;
}
catch (Throwable e)
{
try
{
context.getBundle();
}
catch (IllegalStateException t)
{
// FileInstall bundle has been uninstalled, exiting loop
return;
}
log("In main loop, we have serious trouble", e);
}
}
}
public void bundleChanged(BundleEvent bundleEvent)
{
if (bundleEvent.getType() == BundleEvent.UNINSTALLED)
{
for (Iterator it = currentManagedArtifacts.entrySet().iterator(); it.hasNext();)
{
Map.Entry entry = (Map.Entry) it.next();
Artifact artifact = (Artifact) entry.getValue();
if (artifact.getBundleId() == bundleEvent.getBundle().getBundleId())
{
log("Bundle " + bundleEvent.getBundle().getBundleId() + " has been uninstalled", null);
currentManagedArtifacts.remove(entry.getKey());
break;
}
}
}
}
private void process(Set files)
{
List/*<ArtifactListener>*/ listeners = FileInstall.getListeners();
List/*<Artifact>*/ deleted = new ArrayList/*<Artifact>*/();
List/*<Artifact>*/ modified = new ArrayList/*<Artifact>*/();
List/*<Artifact>*/ created = new ArrayList/*<Artifact>*/();
// Try to process again files that could not be processed
files.addAll(processingFailures);
processingFailures.clear();
for (Iterator it = files.iterator(); it.hasNext();)
{
File file = (File) it.next();
boolean exists = file.exists();
Artifact artifact = (Artifact) currentManagedArtifacts.get(file);
// File has been deleted
if (!exists)
{
if (artifact != null) {
deleteJaredDirectory(artifact);
deleteTransformedFile(artifact);
deleted.add(artifact);
}
}
// File exists
else
{
File jar = file;
URL jaredUrl = null;
try
{
jaredUrl = file.toURI().toURL();
}
catch (MalformedURLException e)
{
// Ignore, can't happen
}
// Jar up the directory if needed
if (file.isDirectory())
{
prepareTempDir();
try
{
jar = new File(tmpDir, file.getName() + ".jar");
Util.jarDir(file, jar);
jaredUrl = new URL(JarDirUrlHandler.PROTOCOL, null, file.getPath());
}
catch (IOException e)
{
log("Unable to create jar for: " + file.getAbsolutePath(), e);
continue;
}
}
// File has been modified
if (artifact != null)
{
artifact.setChecksum(scanner.getChecksum(file));
// If there's no listener, this is because this artifact has been installed before
// fileinstall has been restarted. In this case, try to find a listener.
if (artifact.getListener() == null)
{
ArtifactListener listener = findListener(jar, listeners);
// If no listener can handle this artifact, we need to defer the
// processing for this artifact until one is found
if (listener == null)
{
processingFailures.add(file);
continue;
}
artifact.setListener(listener);
}
// If the listener can not handle this file anymore,
// uninstall the artifact and try as if is was new
if (!listeners.contains(artifact.getListener()) || !artifact.getListener().canHandle(jar))
{
deleted.add(artifact);
artifact = null;
}
// The listener is still ok
else
{
deleteTransformedFile(artifact);
artifact.setJaredDirectory(jar);
artifact.setJaredUrl(jaredUrl);
if (transformArtifact(artifact))
{
modified.add(artifact);
}
else
{
deleteJaredDirectory(artifact);
deleted.add(artifact);
}
continue;
}
}
// File has been added
else
{
// Find the listener
ArtifactListener listener = findListener(jar, listeners);
// If no listener can handle this artifact, we need to defer the
// processing for this artifact until one is found
if (listener == null)
{
processingFailures.add(file);
continue;
}
// Create the artifact
artifact = new Artifact();
artifact.setPath(file);
artifact.setJaredDirectory(jar);
artifact.setJaredUrl(jaredUrl);
artifact.setListener(listener);
artifact.setChecksum(scanner.getChecksum(file));
if (transformArtifact(artifact))
{
created.add(artifact);
}
else
{
deleteJaredDirectory(artifact);
}
}
}
}
// Handle deleted artifacts
// We do the operations in the following order:
// uninstall, update, install, refresh & start.
Collection uninstalledBundles = uninstall(deleted);
Collection updatedBundles = update(modified);
Collection installedBundles = install(created);
if (uninstalledBundles.size() > 0 || updatedBundles.size() > 0)
{
// Refresh if any bundle got uninstalled or updated.
// This can lead to restart of recently updated bundles, but
// don't worry about that at this point of time.
refresh();
}
if (startBundles)
{
// Try to start all the bundles that are not persistently stopped
startAllBundles();
// Try to start newly installed bundles
start(installedBundles);
}
}
ArtifactListener findListener(File artifact, List/* <ArtifactListener> */ listeners)
{
for (Iterator itL = listeners.iterator(); itL.hasNext();)
{
ArtifactListener listener = (ArtifactListener) itL.next();
if (listener.canHandle(artifact))
{
return listener;
}
}
return null;
}
boolean transformArtifact(Artifact artifact)
{
if (artifact.getListener() instanceof ArtifactTransformer)
{
prepareTempDir();
try
{
File transformed = ((ArtifactTransformer) artifact.getListener()).transform(artifact.getJaredDirectory(), tmpDir);
if (transformed != null)
{
artifact.setTransformed(transformed);
return true;
}
}
catch (Exception e)
{
log("Unable to transform artifact: " + artifact.getPath().getAbsolutePath(), e);
}
return false;
}
else if (artifact.getListener() instanceof ArtifactUrlTransformer)
{
try
{
URL url = artifact.getJaredUrl();
URL transformed = ((ArtifactUrlTransformer) artifact.getListener()).transform(url);
if (transformed != null)
{
artifact.setTransformedUrl(transformed);
return true;
}
}
catch (Exception e)
{
log("Unable to transform artifact: " + artifact.getPath().getAbsolutePath(), e);
}
return false;
}
return true;
}
private void deleteTransformedFile(Artifact artifact)
{
if (artifact.getTransformed() != null
&& !artifact.getTransformed().equals(artifact.getPath())
&& !artifact.getTransformed().delete())
{
log("Unable to delete transformed artifact: " + artifact.getTransformed().getAbsolutePath(), null);
}
}
private void deleteJaredDirectory(Artifact artifact)
{
if (artifact.getJaredDirectory() != null
&& !artifact.getJaredDirectory().equals(artifact.getPath())
&& !artifact.getJaredDirectory().delete())
{
log("Unable to delete jared artifact: " + artifact.getJaredDirectory().getAbsolutePath(), null);
}
}
private void prepareTempDir()
{
if (tmpDir == null)
{
for (;;)
{
File f = new File(javaIoTmpdir, "fileinstall-" + Long.toString(random.nextLong()));
if (!f.exists() && f.mkdirs())
{
tmpDir = f;
break;
}
}
}
else
{
prepareDir(tmpDir);
}
}
/**
* Create the watched directory, if not existing.
* Throws a runtime exception if the directory cannot be created,
* or if the provided File parameter does not refer to a directory.
*
* @param dir
* The directory File Install will monitor
*/
private void prepareDir(File dir)
{
if (!dir.exists() && !dir.mkdirs())
{
log("Cannot create folder "
+ dir
+ ". Is the folder write-protected?", null);
throw new RuntimeException("Cannot create folder: " + dir);
}
if (!dir.isDirectory())
{
log("Cannot use "
+ dir
+ " because it's not a directory", null);
throw new RuntimeException(
"Cannot start FileInstall using something that is not a directory");
}
}
/**
* Log a message and optional throwable. If there is a log service we use
* it, otherwise we log to the console
*
* @param message
* The message to log
* @param e
* The throwable to log
*/
void log(String message, Throwable e)
{
Util.log(context, debug, message, e);
}
/**
* Check if a bundle is a fragment.
*
* @param bundle
* @return
*/
boolean isFragment(Bundle bundle)
{
PackageAdmin padmin = FileInstall.getPackageAdmin();
if (padmin != null)
{
return padmin.getBundleType(bundle) == PackageAdmin.BUNDLE_TYPE_FRAGMENT;
}
return false;
}
/**
* Convenience to refresh the packages
*/
void refresh()
{
PackageAdmin padmin = FileInstall.getPackageAdmin();
if (padmin != null)
{
padmin.refreshPackages(null);
}
}
/**
* Retrieve a property as a long.
*
* @param properties the properties to retrieve the value from
* @param property the name of the property to retrieve
* @param dflt the default value
* @return the property as a long or the default value
*/
long getLong(Dictionary properties, String property, long dflt)
{
String value = (String) properties.get(property);
if (value != null)
{
try
{
return Long.parseLong(value);
}
catch (Exception e)
{
log(property + " set, but not a long: " + value, null);
}
}
return dflt;
}
/**
* Retrieve a property as a File.
*
* @param properties the properties to retrieve the value from
* @param property the name of the property to retrieve
* @param dflt the default value
* @return the property as a File or the default value
*/
File getFile(Dictionary properties, String property, File dflt)
{
String value = (String) properties.get(property);
if (value != null)
{
return new File(value);
}
return dflt;
}
/**
* Retrieve a property as a boolan.
*
* @param properties the properties to retrieve the value from
* @param property the name of the property to retrieve
* @param dflt the default value
* @return the property as a boolean or the default value
*/
boolean getBoolean(Dictionary properties, String property, boolean dflt)
{
String value = (String) properties.get(property);
if (value != null)
{
return Boolean.valueOf(value).booleanValue();
}
return dflt;
}
public void close()
{
this.context.removeBundleListener(this);
interrupt();
try
{
join(10000);
}
catch (InterruptedException ie)
{
// Ignore
}
}
/**
* This method goes through all the currently installed bundles
* and returns information about those bundles whose location
* refers to a file in our {@link #watchedDirectory}.
*/
private void initializeCurrentManagedBundles()
{
Bundle[] bundles = this.context.getBundles();
String watchedDirPath = watchedDirectory.toURI().normalize().getPath();
Map /*<File, Long>*/ checksums = new HashMap/*<File, Long>*/();
for (int i = 0; i < bundles.length; i++)
{
// Convert to a URI because the location of a bundle
// is typically a URI. At least, that's the case for
// autostart bundles and bundles installed by fileinstall.
// Normalisation is needed to ensure that we don't treat (e.g.)
// /tmp/foo and /tmp//foo differently.
String location = bundles[i].getLocation();
String path = null;
if (location != null &&
!location.equals(Constants.SYSTEM_BUNDLE_LOCATION))
{
URI uri;
try
{
uri = new URI(bundles[i].getLocation()).normalize();
}
catch (URISyntaxException e)
{
// Let's try to interpret the location as a file path
uri = new File(location).toURI().normalize();
}
path = uri.getPath();
}
if (path == null)
{
// jar.getPath is null means we could not parse the location
// as a meaningful URI or file path. e.g., location
// represented an Opaque URI.
// We can't do any meaningful processing for this bundle.
continue;
}
final int index = path.lastIndexOf('/');
if (index != -1 && path.startsWith(watchedDirPath))
{
Artifact artifact = new Artifact();
artifact.setBundleId(bundles[i].getBundleId());
artifact.setChecksum(Util.loadChecksum(bundles[i], context));
artifact.setListener(null);
artifact.setPath(new File(path));
currentManagedArtifacts.put(new File(path), artifact);
checksums.put(new File(path), new Long(artifact.getChecksum()));
}
}
scanner.initialize(checksums);
}
/**
* This method installs a collection of artifacts.
* @param artifacts Collection of {@link Artifact}s to be installed
* @return List of Bundles just installed
*/
private Collection/* <Bundle> */ install(Collection/* <Artifact> */ artifacts)
{
List bundles = new ArrayList();
for (Iterator iter = artifacts.iterator(); iter.hasNext();)
{
Artifact artifact = (Artifact) iter.next();
Bundle bundle = install(artifact);
if (bundle != null)
{
bundles.add(bundle);
}
}
return bundles;
}
/**
* This method uninstalls a collection of artifacts.
* @param artifacts Collection of {@link Artifact}s to be uninstalled
* @return Collection of Bundles that got uninstalled
*/
private Collection/* <Bundle> */ uninstall(Collection/* <Artifact> */ artifacts)
{
List bundles = new ArrayList();
for (Iterator iter = artifacts.iterator(); iter.hasNext();)
{
Artifact artifact = (Artifact) iter.next();
Bundle bundle = uninstall(artifact);
if (bundle != null)
{
bundles.add(bundle);
}
}
return bundles;
}
/**
* This method updates a collection of artifacts.
*
* @param artifacts Collection of {@link Artifact}s to be updated.
* @return Collection of bundles that got updated
*/
private Collection/* <Bundle> */ update(Collection/* <Artifact> */ artifacts)
{
List bundles = new ArrayList();
for (Iterator iter = artifacts.iterator(); iter.hasNext(); )
{
Artifact artifact = (Artifact) iter.next();
Bundle bundle = update(artifact);
if (bundle != null)
{
bundles.add(bundle);
}
}
return bundles;
}
/**
* Install an artifact and return the bundle object.
* It uses {@link Artifact#getPath()} as location
* of the new bundle. Before installing a file,
* it sees if the file has been identified as a bad file in
* earlier run. If yes, then it compares to see if the file has changed
* since then. It installs the file if the file has changed.
* If the file has not been identified as a bad file in earlier run,
* then it always installs it.
*
* @param artifact the artifact to be installed
* @return Bundle object that was installed
*/
private Bundle install(Artifact artifact)
{
File path = artifact.getPath();
Bundle bundle = null;
try
{
// If the listener is an installer, ask for an update
if (artifact.getListener() instanceof ArtifactInstaller)
{
((ArtifactInstaller) artifact.getListener()).install(path);
}
// if the listener is an url transformer
else if (artifact.getListener() instanceof ArtifactUrlTransformer)
{
Artifact badArtifact = (Artifact) installationFailures.get(path);
if (badArtifact != null && badArtifact.getChecksum() == artifact.getChecksum())
{
return null; // Don't attempt to install it; nothing has changed.
}
URL transformed = artifact.getTransformedUrl();
String location = transformed.toString();
BufferedInputStream in = new BufferedInputStream(transformed.openStream());
try
{
bundle = installOrUpdateBundle(location, in, artifact.getChecksum());
}
finally
{
in.close();
}
artifact.setBundleId(bundle.getBundleId());
}
// if the listener is an artifact transformer
else if (artifact.getListener() instanceof ArtifactTransformer)
{
Artifact badArtifact = (Artifact) installationFailures.get(path);
if (badArtifact != null && badArtifact.getChecksum() == artifact.getChecksum())
{
return null; // Don't attempt to install it; nothing has changed.
}
File transformed = artifact.getTransformed();
String location = path.toURI().normalize().toString();
BufferedInputStream in = new BufferedInputStream(new FileInputStream(transformed != null ? transformed : path));
try
{
bundle = installOrUpdateBundle(location, in, artifact.getChecksum());
}
finally
{
in.close();
}
artifact.setBundleId(bundle.getBundleId());
}
installationFailures.remove(path);
currentManagedArtifacts.put(path, artifact);
log("Installed " + path, null);
}
catch (Exception e)
{
log("Failed to install artifact: " + path, e);
// Add it our bad jars list, so that we don't
// attempt to install it again and again until the underlying
// jar has been modified.
installationFailures.put(path, artifact);
}
return bundle;
}
private Bundle installOrUpdateBundle(String bundleLocation, BufferedInputStream is, long checksum) throws IOException, BundleException {
is.mark(256 * 1024);
JarInputStream jar = new JarInputStream(is);
Manifest m = jar.getManifest();
String sn = m.getMainAttributes().getValue(Constants.BUNDLE_SYMBOLICNAME);
String vStr = m.getMainAttributes().getValue(Constants.BUNDLE_VERSION);
Version v = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
Bundle[] bundles = context.getBundles();
for (int i = 0; i < bundles.length; i++) {
Bundle b = bundles[i];
if (b.getSymbolicName() != null && b.getSymbolicName().equals(sn)) {
vStr = (String) b.getHeaders().get(Constants.BUNDLE_VERSION);
Version bv = vStr == null ? Version.emptyVersion : Version.parseVersion(vStr);
if (v.equals(bv)) {
is.reset();
if (Util.loadChecksum(b, context) != checksum) {
log("A bundle with the same symbolic name (" + sn + ") and version (" + vStr + ") is already installed. Updating this bundle instead.", null);
Util.storeChecksum(b, checksum, context);
b.update(is);
}
return b;
}
}
}
is.reset();
Bundle b = context.installBundle(bundleLocation, is);
Util.storeChecksum(b, checksum, context);
return b;
}
/**
* Uninstall a jar file.
*/
private Bundle uninstall(Artifact artifact)
{
Bundle bundle = null;
try
{
File path = artifact.getPath();
// Find a listener for this artifact if needed
if (artifact.getListener() == null) {
artifact.setListener(findListener(path, FileInstall.getListeners()));
}
// Forget this artifact
currentManagedArtifacts.remove(path);
// Delete transformed file
deleteTransformedFile(artifact);
// if the listener is an installer, uninstall the artifact
if (artifact.getListener() instanceof ArtifactInstaller)
{
((ArtifactInstaller) artifact.getListener()).uninstall(path);
}
// else we need uninstall the bundle
else if (artifact.getBundleId() != 0)
{
// old can't be null because of the way we calculate deleted list.
bundle = context.getBundle(artifact.getBundleId());
if (bundle == null)
{
log("Failed to uninstall bundle: "
+ path + " with id: "
+ artifact.getBundleId()
+ ". The bundle has already been uninstalled", null);
return null;
}
log("Uninstalling bundle " + bundle.getBundleId() + " (" + bundle.getSymbolicName() + ")", null);
bundle.uninstall();
}
log("Uninstalled " + path, null);
}
catch (Exception e)
{
log("Failed to uninstall artifact: " + artifact.getPath(), e);
}
return bundle;
}
private Bundle update(Artifact artifact)
{
Bundle bundle = null;
try
{
File path = artifact.getPath();
// If the listener is an installer, ask for an update
if (artifact.getListener() instanceof ArtifactInstaller)
{
((ArtifactInstaller) artifact.getListener()).update(path);
}
// if the listener is an url transformer
else if (artifact.getListener() instanceof ArtifactUrlTransformer)
{
URL transformed = artifact.getTransformedUrl();
bundle = context.getBundle(artifact.getBundleId());
if (bundle == null)
{
log("Failed to update bundle: "
+ path + " with ID "
+ artifact.getBundleId()
+ ". The bundle has been uninstalled", null);
return null;
}
Util.storeChecksum(bundle, artifact.getChecksum(), context);
InputStream in = (transformed != null) ? transformed.openStream() : new FileInputStream(path);
try
{
bundle.update(in);
}
finally
{
in.close();
}
}
// else we need to ask for an update on the bundle
else if (artifact.getListener() instanceof ArtifactTransformer)
{
File transformed = artifact.getTransformed();
bundle = context.getBundle(artifact.getBundleId());
if (bundle == null)
{
log("Failed to update bundle: "
+ path + " with ID "
+ artifact.getBundleId()
+ ". The bundle has been uninstalled", null);
return null;
}
Util.storeChecksum(bundle, artifact.getChecksum(), context);
InputStream in = new FileInputStream(transformed != null ? transformed : path);
try
{
bundle.update(in);
}
finally
{
in.close();
}
}
log("Updated " + path, null);
}
catch (Throwable t)
{
log("Failed to update artifact " + artifact.getPath(), t);
}
return bundle;
}
private void startAllBundles()
{
List bundles = new ArrayList();
for (Iterator it = currentManagedArtifacts.values().iterator(); it.hasNext();)
{
Artifact artifact = (Artifact) it.next();
if (artifact.getBundleId() > 0)
{
Bundle bundle = context.getBundle(artifact.getBundleId());
if (bundle != null)
{
if (bundle.getState() != Bundle.STARTING && bundle.getState() != Bundle.ACTIVE
&& FileInstall.getStartLevel().isBundlePersistentlyStarted(bundle))
{
bundles.add(bundle);
}
}
}
}
start(bundles);
}
private void start(Collection/* <Bundle> */ bundles)
{
for (Iterator b = bundles.iterator(); b.hasNext(); )
{
start((Bundle) b.next());
}
}
private void start(Bundle bundle)
{
// Fragments can not be started.
// No need to check status of bundles
// before starting, because OSGi treats this
// as a noop when the bundle is already started
if (!isFragment(bundle))
{
try
{
bundle.start();
log("Started bundle: " + bundle.getLocation(), null);
}
catch (BundleException e)
{
log("Error while starting bundle: " + bundle.getLocation(), e);
}
}
}
}