in features/core/src/main/java/org/apache/karaf/features/internal/service/Deployer.java [1365:1509]
protected Deployment computeDeployment(
DeploymentState dstate,
DeploymentRequest request,
SubsystemResolver resolver) throws IOException {
Deployment result = new Deployment();
Map<String, Set<Resource>> bundlesPerRegions = resolver.getBundlesPerRegions();
// Gather all regions, including old ones and new ones
Set<String> regions = new HashSet<>();
regions.addAll(dstate.state.managedBundles.keySet());
regions.addAll(bundlesPerRegions.keySet());
for (String region : regions) {
Deployer.RegionDeployment deployment = new Deployer.RegionDeployment();
// Get the list of bundles currently assigned in the region
Set<Long> managed = dstate.state.managedBundles.get(region);
if (managed == null) {
managed = Collections.emptySet();
}
// Compute the list of resources to deploy in the region
Set<Resource> bundlesInRegion = bundlesPerRegions.get(region);
List<Resource> toDeploy = bundlesInRegion != null ? new ArrayList<>(bundlesInRegion) : new ArrayList<>();
// Remove the system bundle
Bundle systemBundle = dstate.bundles.get(0l);
if (systemBundle != null) {
// It may be null when unit testing, so ignore that
toDeploy.remove(systemBundle.adapt(BundleRevision.class));
}
// First pass: go through all installed bundles and mark them
// as either to ignore or delete
for (long bundleId : managed) {
// Look for the installed bundle
Bundle bundle = dstate.bundles.get(bundleId);
// Bundle has been manually uninstalled ?
if (bundle != null) {
// Look for a matching resource
Resource resource = null;
for (Resource res : toDeploy) {
if (bundle.getSymbolicName().equals(getSymbolicName(res))
&& bundle.getVersion().equals(getVersion(res))) {
resource = res;
break;
}
}
// We found a matching bundle
if (resource != null) {
// In case of snapshots, check if the snapshot is out of date
// and flag it as to update
if (isUpdateable(resource)) {
// Always update snapshots
if (FeaturesService.SnapshotUpdateBehavior.Always == request.updateSnaphots) {
LOGGER.debug("Update snapshot for " + bundle.getLocation());
deployment.toUpdate.put(bundle, resource);
} else if (FeaturesService.SnapshotUpdateBehavior.Crc == request.updateSnaphots) {
// Retrieve current bundle checksum
long oldCrc;
if (dstate.state.bundleChecksums.containsKey(bundleId)) {
oldCrc = dstate.state.bundleChecksums.get(bundleId);
} else {
// Load bundle checksums if not already done
// This is a bit hacky, but we can't get a hold on the real bundle location
// in a standard way in OSGi. Therefore, hack into Felix/Equinox to obtain the
// corresponding jar url and use that one to compute the checksum of the bundle.
oldCrc = 0l;
try {
URL url = bundle.getEntry("META-INF/MANIFEST.MF");
URLConnection con = url.openConnection();
Method method = con.getClass().getDeclaredMethod("getLocalURL");
method.setAccessible(true);
String jarUrl = ((URL) method.invoke(con)).toExternalForm();
if (jarUrl.startsWith("jar:")) {
String jar = jarUrl.substring("jar:".length(), jarUrl.indexOf("!/"));
jar = new URL(jar).getFile();
try (InputStream is = new FileInputStream(jar)) {
oldCrc = ChecksumUtils.checksum(is);
}
result.bundleChecksums.put(bundleId, oldCrc);
}
} catch (Throwable t) {
LOGGER.debug("Error calculating checksum for bundle: {}", bundle, t);
}
}
// Compute new bundle checksum
long newCrc;
try (
InputStream is = getBundleInputStream(resource, resolver.getProviders())
) {
newCrc = ChecksumUtils.checksum(is);
result.bundleChecksums.put(bundle.getBundleId(), newCrc);
}
// if the checksum are different
if (newCrc != oldCrc) {
LOGGER.debug("New snapshot available for " + bundle.getLocation());
deployment.toUpdate.put(bundle, resource);
}
}
}
// We're done for this resource
toDeploy.remove(resource);
result.resToBnd.put(resource, bundle);
// There's no matching resource
// If the bundle is managed, we need to delete it
} else if (managed.contains(bundle.getBundleId())) {
deployment.toDelete.add(bundle);
}
}
}
// Second pass on remaining resources
for (Resource resource : toDeploy) {
TreeMap<Version, Bundle> matching = new TreeMap<>();
VersionRange range = new VersionRange(Macro.transform(request.bundleUpdateRange, getVersion(resource).toString()));
for (Bundle bundle : deployment.toDelete) {
if (bundle.getSymbolicName().equals(getSymbolicName(resource)) && range.contains(bundle.getVersion())) {
matching.put(bundle.getVersion(), bundle);
}
}
if (!matching.isEmpty()) {
Bundle bundle = matching.lastEntry().getValue();
deployment.toUpdate.put(bundle, resource);
deployment.toDelete.remove(bundle);
result.resToBnd.put(resource, bundle);
} else {
deployment.toInstall.add(resource);
}
}
deployment.toInstall.sort(new ResourceComparator());
// Add this region if there is something to do
if (!deployment.toDelete.isEmpty()
|| !deployment.toUpdate.isEmpty()
|| !deployment.toInstall.isEmpty()) {
result.regions.put(region, deployment);
}
}
return result;
}