| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.karaf.profile.assembly; |
| |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.HashMap; |
| import java.util.HashSet; |
| import java.util.LinkedList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.stream.Collectors; |
| |
| import org.apache.felix.utils.version.VersionTable; |
| import org.apache.karaf.features.FeaturePattern; |
| import org.apache.karaf.features.internal.model.Dependency; |
| import org.apache.karaf.features.internal.model.Feature; |
| import org.apache.karaf.features.internal.model.Features; |
| import org.apache.karaf.features.internal.service.FeatureReq; |
| |
| public class FeatureSelector { |
| |
| private final Set<Feature> allFeatures; |
| Map<String, Set<Feature>> featuresCache; |
| |
| public FeatureSelector(Set<Feature> features) { |
| allFeatures = features; |
| featuresCache = new HashMap<>(); |
| for (Feature feature : features) { |
| featuresCache.computeIfAbsent(feature.getName(), fn -> new HashSet<>()) |
| .add(feature); |
| } |
| } |
| |
| /** |
| * Assuming <code>idOrPattern</code> may be a pattern (with glob and version range), get all matching features |
| * @param idOrPattern |
| * @param repositories |
| * @return |
| */ |
| public static Collection<String> getMatchingFeatures(String idOrPattern, Collection<Features> repositories) { |
| List<String> result = new LinkedList<>(); |
| FeaturePattern pattern = new FeaturePattern(idOrPattern); |
| for (Features features : repositories) { |
| for (Feature feature : features.getFeature()) { |
| // blacklisting will be applied anyway, so no need to do it here |
| if (/*!feature.isBlacklisted() && */pattern.matches(feature.getName(), feature.getVersion())) { |
| result.add(feature.getId()); |
| } |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Get all matching features |
| * @param idOrPattern |
| * @param features |
| * @return |
| */ |
| public static Collection<String> getMatchingFeatures(FeaturePattern idOrPattern, Collection<Feature> features) { |
| List<String> result = new LinkedList<>(); |
| for (Feature feature : features) { |
| // blacklisting will be applied anyway, so no need to do it here |
| if (/*!feature.isBlacklisted() && */idOrPattern.matches(feature.getName(), feature.getVersion())) { |
| result.add(feature.getId()); |
| } |
| } |
| return result; |
| } |
| |
| /** |
| * Features matching the given feature selectors including dependent features |
| * |
| * @param features feature selector name, name/version, name/version-range |
| * |
| * @return matching features |
| */ |
| public Set<Feature> getMatching(List<String> features) { |
| Set<Feature> selected = new HashSet<>(); |
| for (String feature : features) { |
| for (String featureId : getMatchingFeatures(new FeaturePattern(feature), allFeatures)) { |
| addFeatures(featureId, selected, true); |
| } |
| } |
| return selected; |
| } |
| |
| private void addFeatures(String feature, Set<Feature> features, boolean mandatory) { |
| Set<Feature> set = getMatching(feature); |
| if (mandatory && set.isEmpty()) { |
| throw new IllegalStateException("Could not find matching feature for " + feature); |
| } |
| for (Feature f : set) { |
| if (features.add(f)) { |
| for (Dependency dep : f.getFeature()) { |
| if (!dep.isBlacklisted()) { |
| addFeatures(dep.toString(), features, isMandatory(dep)); |
| } |
| } |
| } |
| } |
| } |
| |
| private boolean isMandatory(Dependency dep) { |
| return !dep.isDependency() && !dep.isPrerequisite(); |
| } |
| |
| private Set<Feature> getMatching(String nameAndVersion) { |
| FeatureReq req = new FeatureReq(nameAndVersion); |
| Set<Feature> versionToFeatures = featuresCache.get(req.getName()); |
| if (versionToFeatures == null) { |
| return Collections.emptySet(); |
| } |
| return versionToFeatures.stream() |
| .filter(f -> f.getName().equals(req.getName()) && req.getVersionRange().contains(VersionTable.getVersion(f.getVersion()))) |
| .collect(Collectors.toSet()); |
| } |
| } |