protected Deployment computeDeployment()

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;
    }