FELIX-1756: allow fileinstall to override (i.e. update) bundles that have not been deployed by fileinstall initially
Also fixes FELIX-1386: updating fileinstall bundle in watched directory causes IllegalStateException
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@825454 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
index c838ad4..a3d8951 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/DirectoryWatcher.java
@@ -18,6 +18,7 @@
*/
package org.apache.felix.fileinstall.internal;
+import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FilenameFilter;
@@ -36,6 +37,8 @@
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;
@@ -47,6 +50,7 @@
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;
/**
@@ -197,6 +201,15 @@
}
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);
}
}
@@ -599,10 +612,6 @@
Map /*<File, Long>*/ checksums = new HashMap/*<File, Long>*/();
for (int i = 0; i < bundles.length; i++)
{
- Artifact artifact = new Artifact();
- artifact.setBundleId(bundles[i].getBundleId());
- artifact.setChecksum(Util.loadChecksum(bundles[i], context));
- artifact.setListener(null);
// 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.
@@ -633,10 +642,14 @@
// We can't do any meaningful processing for this bundle.
continue;
}
- artifact.setPath(new File(path));
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()));
}
@@ -659,7 +672,6 @@
if (bundle != null)
{
bundles.add(bundle);
- Util.storeChecksum(bundle, artifact.getChecksum(), context);
}
}
return bundles;
@@ -701,7 +713,6 @@
if (bundle != null)
{
bundles.add(bundle);
- Util.storeChecksum(bundle, artifact.getChecksum(), context);
}
}
return bundles;
@@ -722,10 +733,10 @@
*/
private Bundle install(Artifact artifact)
{
+ File path = artifact.getPath();
Bundle bundle = null;
try
{
- File path = artifact.getPath();
// If the listener is an installer, ask for an update
if (artifact.getListener() instanceof ArtifactInstaller)
{
@@ -734,30 +745,38 @@
// 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();
- Artifact badArtifact = (Artifact) installationFailures.get(artifact.getPath());
- if (badArtifact != null && badArtifact.getChecksum() == artifact.getChecksum())
- {
- return null; // Don't attempt to install it; nothing has changed.
- }
- bundle = context.installBundle(transformed.toString());
- artifact.setBundleId(bundle.getBundleId());
- }
- // else we need to ask for an update on the bundle
- else if (artifact.getListener() instanceof ArtifactTransformer)
- {
- File transformed = artifact.getTransformed();
- Artifact badArtifact = (Artifact) installationFailures.get(artifact.getPath());
- if (badArtifact != null && badArtifact.getChecksum() == artifact.getChecksum())
- {
- return null; // Don't attempt to install it; nothing has changed.
- }
- InputStream in = new FileInputStream(transformed != null ? transformed : path);
+ String location = transformed.toString();
+ BufferedInputStream in = new BufferedInputStream(transformed.openStream());
try
{
- // Some users wanted the location to be a URI (See FELIX-1269)
- final String location = path.toURI().normalize().toString();
- bundle = context.installBundle(location, in);
+ 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
{
@@ -771,16 +790,46 @@
}
catch (Exception e)
{
- log("Failed to install artifact: " + artifact.getPath(), 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(artifact.getPath(), artifact);
+ 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.
*/
@@ -851,6 +900,7 @@
+ ". The bundle has been uninstalled", null);
return null;
}
+ Util.storeChecksum(bundle, artifact.getChecksum(), context);
bundle.update();
}
// else we need to ask for an update on the bundle
@@ -866,6 +916,7 @@
+ ". The bundle has been uninstalled", null);
return null;
}
+ Util.storeChecksum(bundle, artifact.getChecksum(), context);
InputStream in = new FileInputStream(transformed != null ? transformed : path);
try
{
diff --git a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java
index 7192922..bfa03c0 100644
--- a/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java
+++ b/fileinstall/src/main/java/org/apache/felix/fileinstall/internal/Util.java
@@ -39,7 +39,9 @@
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
import org.osgi.framework.ServiceReference;
+import org.osgi.framework.Version;
import org.osgi.service.log.LogService;
public class Util
@@ -47,6 +49,8 @@
private static final String DELIM_START = "${";
private static final String DELIM_STOP = "}";
+ private static final String CHECKSUM_SUFFIX = ".checksum";
+
/**
* Perform substitution on a property set
*
@@ -184,12 +188,13 @@
private static Logger getLogger(BundleContext context)
{
- if (logger != null && logger.isValidLogger(context))
- {
- return logger;
- }
try
{
+ context.getBundle();
+ if (logger != null && logger.isValidLogger(context))
+ {
+ return logger;
+ }
logger = new OsgiLogger(context);
}
catch (Throwable t)
@@ -383,7 +388,7 @@
public static void storeChecksum( Bundle b, long checksum, BundleContext bc )
{
String key = getBundleKey(b);
- File f = bc.getDataFile( key + ".checksum" );
+ File f = bc.getDataFile( key + CHECKSUM_SUFFIX );
DataOutputStream dout = null;
try
{
@@ -418,7 +423,7 @@
public static long loadChecksum( Bundle b, BundleContext bc )
{
String key = getBundleKey(b);
- File f = bc.getDataFile( key + ".checksum" );
+ File f = bc.getDataFile( key + CHECKSUM_SUFFIX );
DataInputStream in = null;
try
{
@@ -448,8 +453,8 @@
{
StringBuffer sb = new StringBuffer();
sb.append(b.getSymbolicName()).append("_");
- String version = (String) b.getHeaders().get( "Bundle-Version" );
- sb.append(version != null ? version : "0.0.0");
+ String version = (String) b.getHeaders().get(Constants.BUNDLE_VERSION);
+ sb.append(version != null ? version : Version.emptyVersion.toString());
return sb.toString();
}