Search in sources :

Example 6 with FeatureUpdate

use of org.jboss.fuse.patch.management.FeatureUpdate in project fuse-karaf by jboss-fuse.

the class PatchServiceImpl method featureUpdatesInPatch.

/**
 * Returns a list of {@link FeatureUpdate} for single patch, taking into account already discovered updates
 * @param patch
 * @param updatesForFeatureKeys
 * @param kind
 * @return
 */
private List<FeatureUpdate> featureUpdatesInPatch(Patch patch, Map<String, FeatureUpdate> updatesForFeatureKeys, PatchKind kind) throws Exception {
    Set<String> addedRepositoryNames = new HashSet<>();
    HashMap<String, Repository> after = null;
    try {
        List<FeatureUpdate> updatesInThisPatch = new LinkedList<>();
        /*
             * Two pairs of features makes feature names not enough to be a key:
             * <feature name="openjpa" description="Apache OpenJPA 2.2.x persistent engine support" version="2.2.2" resolver="(obr)">
             * <feature name="openjpa" description="Apache OpenJPA 2.3.x persistence engine support" version="2.3.0" resolver="(obr)">
             * and
             * <feature name="activemq-camel" version="5.11.0.redhat-621039" resolver="(obr)" start-level="50">
             * <feature name="activemq-camel" version="1.2.0.redhat-621039" resolver="(obr)">
             */
        // install the new feature repos, tracking the set the were
        // installed before and after
        // (e.g, "karaf-enterprise-2.4.0.redhat-620133" -> Repository)
        Map<String, Repository> before = new HashMap<>(getAvailableFeatureRepositories());
        for (String url : patch.getPatchData().getFeatureFiles()) {
            featuresService.addRepository(new URI(url));
        }
        after = getAvailableFeatureRepositories();
        // track which old repos provide which features to find out if we have new repositories for those features
        // key is name|version (don't expect '|' to be part of name...)
        // assume that [feature-name, feature-version{major,minor,0,0}] is defined only in single repository
        Map<String, String> featuresInOldRepositories = new HashMap<>();
        // key is only name, without version - used when there's single feature in old and in new repositories
        MultiMap<String, String> singleFeaturesInOldRepositories = new MultiMap<>();
        Map<String, Version> actualOldFeatureVersions = new HashMap<>();
        for (Repository existingRepository : before.values()) {
            for (Feature feature : existingRepository.getFeatures()) {
                Version v = Utils.getOsgiVersion(feature.getVersion());
                Version lowestUpdateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
                // assume that we can update feature XXX-2.2.3 to XXX-2.2.142, but not to XXX-2.3.0.alpha-1
                String key = String.format("%s|%s", feature.getName(), lowestUpdateableVersion.toString());
                featuresInOldRepositories.put(key, existingRepository.getURI().toString());
                singleFeaturesInOldRepositories.put(feature.getName(), existingRepository.getURI().toString());
                actualOldFeatureVersions.put(key, v);
            }
        }
        // Use the before and after set to figure out which repos were added.
        addedRepositoryNames = new HashSet<>(after.keySet());
        addedRepositoryNames.removeAll(before.keySet());
        // track the new repositories where we can find old features
        Map<String, String> featuresInNewRepositories = new HashMap<>();
        MultiMap<String, String> singleFeaturesInNewRepositories = new MultiMap<>();
        Map<String, String> actualNewFeatureVersions = new HashMap<>();
        MultiMap<String, String> singleActualNewFeatureVersions = new MultiMap<>();
        // Figure out which old repos were updated:  Do they have feature
        // with the same name as one contained in a repo being added?
        // and do they have update'able version? (just like with bundles)
        Set<String> oldRepositoryNames = new HashSet<String>();
        for (String addedRepositoryName : addedRepositoryNames) {
            Repository added = after.get(addedRepositoryName);
            for (Feature feature : added.getFeatures()) {
                Version v = Utils.getOsgiVersion(feature.getVersion());
                Version lowestUpdateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
                String key = String.format("%s|%s", feature.getName(), lowestUpdateableVersion.toString());
                featuresInNewRepositories.put(key, addedRepositoryName);
                singleFeaturesInNewRepositories.put(feature.getName(), addedRepositoryName);
                actualNewFeatureVersions.put(key, v.toString());
                singleActualNewFeatureVersions.put(feature.getName(), v.toString());
                String oldRepositoryWithUpdateableFeature = featuresInOldRepositories.get(key);
                if (oldRepositoryWithUpdateableFeature == null && singleFeaturesInOldRepositories.get(feature.getName()) != null && singleFeaturesInOldRepositories.get(feature.getName()).size() == 1) {
                    oldRepositoryWithUpdateableFeature = singleFeaturesInOldRepositories.get(feature.getName()).get(0);
                }
                if (oldRepositoryWithUpdateableFeature != null) {
                    // track the old repository to be removed
                    oldRepositoryNames.add(oldRepositoryWithUpdateableFeature);
                }
            }
        }
        // We need to uninstall them. Before we uninstall, track which features were installed.
        for (String oldRepositoryName : oldRepositoryNames) {
            Repository repository = before.get(oldRepositoryName);
            for (Feature feature : repository.getFeatures()) {
                if (featuresService.isInstalled(feature)) {
                    Version v = Utils.getOsgiVersion(feature.getVersion());
                    Version lowestUpdateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
                    String key = String.format("%s|%s", feature.getName(), lowestUpdateableVersion.toString());
                    String newRepositoryName = featuresInNewRepositories.get(key);
                    String newVersion = actualNewFeatureVersions.get(key);
                    if (newRepositoryName == null) {
                        // feature from 1.1.1 to 1.3.0
                        if (singleFeaturesInOldRepositories.get(feature.getName()) != null && singleFeaturesInOldRepositories.get(feature.getName()).size() == 1 && singleFeaturesInNewRepositories.get(feature.getName()) != null && singleFeaturesInNewRepositories.get(feature.getName()).size() == 1) {
                            newRepositoryName = singleFeaturesInNewRepositories.get(feature.getName()).get(0);
                        }
                    }
                    if (newVersion == null) {
                        if (singleActualNewFeatureVersions.get(feature.getName()) != null && singleActualNewFeatureVersions.get(feature.getName()).size() == 1) {
                            newVersion = singleActualNewFeatureVersions.get(feature.getName()).get(0);
                        }
                    }
                    FeatureUpdate featureUpdate = null;
                    if (newVersion != null && newRepositoryName != null) {
                        featureUpdate = new FeatureUpdate(feature.getName(), after.get(oldRepositoryName).getURI().toString(), feature.getVersion(), after.get(newRepositoryName).getURI().toString(), newVersion);
                    } else {
                        // we didn't find an update for installed features among feature repositories from patch
                        // which means we have to preserve both the feature and the repository - this may
                        // be user's feature
                        featureUpdate = new FeatureUpdate(feature.getName(), after.get(oldRepositoryName).getURI().toString(), feature.getVersion(), null, null);
                    }
                    updatesInThisPatch.add(featureUpdate);
                    // Merge result
                    FeatureUpdate oldUpdate = updatesForFeatureKeys.get(key);
                    if (oldUpdate != null) {
                        Version upv = null;
                        Version newV = null;
                        if (oldUpdate.getNewVersion() != null) {
                            upv = VersionTable.getVersion(oldUpdate.getNewVersion());
                        }
                        if (newVersion != null) {
                            newV = VersionTable.getVersion(newVersion);
                        }
                        if (upv == null && newV == null) {
                        // weird...
                        } else {
                            if (upv == null || (newV != null && upv.compareTo(newV) < 0)) {
                                // other patch contains newer update for the feature
                                updatesForFeatureKeys.put(key, featureUpdate);
                            }
                        }
                    } else {
                        // this is the first update of the bundle
                        updatesForFeatureKeys.put(key, featureUpdate);
                    }
                }
            }
        }
        // now let's see if there are repositories that are NOT updated (either they're not available in patch
        // (like user feature repositories) or simply didn't change (like jclouds 1.8.1 between Fuse 6.2 and 6.2.1)
        Set<String> unchangedRepositoryNames = new HashSet<>(before.keySet());
        unchangedRepositoryNames.removeAll(oldRepositoryNames);
        for (String unchangedRepositoryName : unchangedRepositoryNames) {
            Repository repository = before.get(unchangedRepositoryName);
            boolean hasInstalledFeatures = false;
            for (Feature feature : repository.getFeatures()) {
                if (featuresService.isInstalled(feature)) {
                    FeatureUpdate featureUpdate = new FeatureUpdate(feature.getName(), after.get(unchangedRepositoryName).getURI().toString(), feature.getVersion(), null, null);
                    hasInstalledFeatures = true;
                    // preserve unchanged/user feature - install after restart
                    updatesInThisPatch.add(featureUpdate);
                    // the key doesn't matter
                    updatesForFeatureKeys.put(String.format("%s|%s", feature.getName(), feature.getVersion()), featureUpdate);
                }
            }
            if (!hasInstalledFeatures) {
                // we have to preserve unchanged/user feature repository - even if it had no installed features
                // this featureUpdate means - "restore feature repository only"
                FeatureUpdate featureUpdate = new FeatureUpdate(null, after.get(unchangedRepositoryName).getURI().toString(), null, null, null);
                updatesInThisPatch.add(featureUpdate);
                updatesForFeatureKeys.put(String.format("REPOSITORY_TO_ADD:%s", after.get(unchangedRepositoryName).getURI().toString()), featureUpdate);
            }
        }
        return updatesInThisPatch;
    } catch (Exception e) {
        throw new PatchException(e.getMessage(), e);
    } finally {
        // we'll add new feature repositories again later. here we've added them only to track the updates
        if (after != null) {
            for (String repo : addedRepositoryNames) {
                if (after.get(repo) != null) {
                    featuresService.removeRepository(after.get(repo).getURI(), false);
                }
            }
        }
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) URI(java.net.URI) Feature(org.apache.karaf.features.Feature) LinkedList(java.util.LinkedList) URISyntaxException(java.net.URISyntaxException) PatchException(org.jboss.fuse.patch.management.PatchException) BundleException(org.osgi.framework.BundleException) IOException(java.io.IOException) Repository(org.apache.karaf.features.Repository) Version(org.osgi.framework.Version) PatchException(org.jboss.fuse.patch.management.PatchException) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) FeatureUpdate(org.jboss.fuse.patch.management.FeatureUpdate)

Aggregations

FeatureUpdate (org.jboss.fuse.patch.management.FeatureUpdate)6 File (java.io.File)4 HashMap (java.util.HashMap)4 LinkedHashSet (java.util.LinkedHashSet)4 LinkedList (java.util.LinkedList)4 IOException (java.io.IOException)3 URISyntaxException (java.net.URISyntaxException)3 LinkedHashMap (java.util.LinkedHashMap)3 BundleUpdate (org.jboss.fuse.patch.management.BundleUpdate)3 PatchException (org.jboss.fuse.patch.management.PatchException)3 Bundle (org.osgi.framework.Bundle)3 BundleException (org.osgi.framework.BundleException)3 FileInputStream (java.io.FileInputStream)2 URI (java.net.URI)2 URL (java.net.URL)2 HashSet (java.util.HashSet)2 Feature (org.apache.karaf.features.Feature)2 FeaturesService (org.apache.karaf.features.FeaturesService)2 Patch (org.jboss.fuse.patch.management.Patch)2 PatchReport (org.jboss.fuse.patch.management.PatchReport)2