[KARAF-5300] Reuse and extract feature matching code
Project: http://git-wip-us.apache.org/repos/asf/karaf/repo Commit: http://git-wip-us.apache.org/repos/asf/karaf/commit/6576f476 Tree: http://git-wip-us.apache.org/repos/asf/karaf/tree/6576f476 Diff: http://git-wip-us.apache.org/repos/asf/karaf/diff/6576f476 Branch: refs/heads/model_features Commit: 6576f476581367a83e7c42ac0e516bb710d3d7db Parents: 69fcb36 Author: Christian Schneider <ch...@die-schneider.net> Authored: Thu Aug 10 15:30:59 2017 +0200 Committer: Christian Schneider <ch...@die-schneider.net> Committed: Thu Aug 17 16:29:30 2017 +0200 ---------------------------------------------------------------------- .../internal/service/FeaturesServiceImpl.java | 79 +++++++++++--------- 1 file changed, 43 insertions(+), 36 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/karaf/blob/6576f476/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java ---------------------------------------------------------------------- diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java index 2767bc8..574998a 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceImpl.java @@ -520,15 +520,15 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall @Override public Feature[] getFeatures(String nameOrId) throws Exception { - return getFeatures(new FeatureReq(nameOrId)); + return toArray(getFeatures(new FeatureReq(nameOrId))); } @Override public Feature[] getFeatures(String name, String version) throws Exception { - return getFeatures(new FeatureReq(name, version)); + return toArray(getFeatures(new FeatureReq(name, version))); } - private Feature[] getFeatures(FeatureReq featureReq) throws Exception { + private Collection<Feature> getFeatures(FeatureReq featureReq) throws Exception { List<Feature> features = new ArrayList<>(); Pattern pattern = Pattern.compile(featureReq.getName()); Map<String, Map<String, Feature>> allFeatures = getFeatureCache(); @@ -541,6 +541,10 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall } } } + return features; + } + + private Feature[] toArray(Collection<Feature> features) { return features.toArray(new Feature[features.size()]); } @@ -819,33 +823,33 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall private Set<FeatureReq> computeFeaturesToAdd(EnumSet<Option> options, Set<FeatureReq> toInstall) throws Exception { Feature[] installedFeatures = listInstalledFeatures(); - Map<String, Map<String, Feature>> allFeatures = getFeatureCache(); Set<FeatureReq> toAdd = new HashSet<>(); - for (FeatureReq feature : toInstall) { - Pattern pattern = Pattern.compile(feature.getName()); - boolean matched = false; - for (String fKey : allFeatures.keySet()) { - Matcher matcher = pattern.matcher(fKey); - if (matcher.matches()) { - Feature f = getFeatureMatching(fKey, feature.getVersionRange()); - if (f != null) { - toAdd.add(new FeatureReq(f)); - for (Feature installedFeature : installedFeatures) { - if (installedFeature.getName().equals(f.getName()) && installedFeature.getVersion().equals(f.getVersion())) { - LOGGER.info("The specified feature: '{}' version '{}' {}",f.getName(),f.getVersion(),f.getVersion().endsWith("SNAPSHOT") ? "has been upgraded": "is already installed"); - } - } - matched = true; + for (FeatureReq featureReq : toInstall) { + Collection<Feature> matching = getFeatures(featureReq); + for (Feature f: matching) { + toAdd.add(new FeatureReq(f)); + for (Feature installedFeature : installedFeatures) { + if (isSameFeature(f, installedFeature)) { + logInstalledOrUpdated(f); } } } - if (!matched && !options.contains(Option.NoFailOnFeatureNotFound)) { - throw new IllegalArgumentException("No matching features for " + feature); + if (matching.isEmpty() && !options.contains(Option.NoFailOnFeatureNotFound)) { + throw new IllegalArgumentException("No matching features for " + featureReq); } } return toAdd; } + private void logInstalledOrUpdated(Feature f) { + String msg = f.getVersion().endsWith("SNAPSHOT") ? "has been upgraded": "is already installed"; + LOGGER.info("The specified feature: '{}' version '{}' {}", f.getName(), f.getVersion(), msg); + } + + private boolean isSameFeature(Feature a, Feature b) { + return b.getName().equals(a.getName()) && b.getVersion().equals(a.getVersion()); + } + private Set<FeatureReq> computeFeaturesToRemoveOnUpdate(Set<FeatureReq> featuresToAdd, Set<FeatureReq> existingFeatures) throws Exception { Set<String> namesToAdd = featuresToAdd.stream().map(f -> f.getName()).collect(toSet()); @@ -869,34 +873,37 @@ public class FeaturesServiceImpl implements FeaturesService, Deployer.DeployCall if (region == null || region.isEmpty()) { region = ROOT_REGION; } - Set<String> requiredForRegion = required.computeIfAbsent(region, k -> new HashSet<>()); + Set<String> requirements = required.computeIfAbsent(region, k -> new HashSet<>()); + Set<FeatureReq> existingFeatures = requirements.stream().map(r -> toFeatureReq(r)).collect(toSet()); Set<FeatureReq> featuresToRemove = new HashSet<>(); for (FeatureReq feature : featureReqs) { - Pattern pattern = Pattern.compile(feature.getName()); - List<FeatureReq> toRemove = new ArrayList<>(); - for (String existingFeature : requiredForRegion) { - FeatureReq existingFeatureReq = toFeatureReq(existingFeature); - if (existingFeatureReq != null) { - Matcher matcher = pattern.matcher(existingFeatureReq.getName()); - if (matcher.matches() && feature.getVersionRange().includes(existingFeatureReq.getVersionRange().getLeft())) { - toRemove.add(existingFeatureReq); - } - } - } - + List<FeatureReq> toRemove = getMatching(existingFeatures, feature); if (toRemove.isEmpty()) { throw new IllegalArgumentException("Feature named '" + feature + "' is not installed"); } featuresToRemove.addAll(toRemove); } print("Removing features: " + join(featuresToRemove), options.contains(Option.Verbose)); - featuresToRemove.stream().forEach(f->requiredForRegion.remove(toRequirement(f))); - if (requiredForRegion.isEmpty()) { + featuresToRemove.stream().forEach(f -> requirements.remove(toRequirement(f))); + if (requirements.isEmpty()) { required.remove(region); } doProvisionInThread(required, emptyMap(), state, getFeaturesById(), options); } + private List<FeatureReq> getMatching(Set<FeatureReq> existingFeatures, FeatureReq feature) { + Pattern pattern = Pattern.compile(feature.getName()); + List<FeatureReq> matching = new ArrayList<>(); + for (FeatureReq existingFeatureReq : existingFeatures) { + Matcher matcher = pattern.matcher(existingFeatureReq.getName()); + Version existingVersion = existingFeatureReq.getVersionRange().getLeft(); + if (matcher.matches() && feature.getVersionRange().includes(existingVersion)) { + matching.add(existingFeatureReq); + } + } + return matching; + } + private FeatureReq toFeatureReq(String featureReq) { if (!featureReq.startsWith(FEATURE_OSGI_REQUIREMENT_PREFIX)) { return null;