All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.karaf.features.internal.service.FeaturesProcessorImpl Maven / Gradle / Ivy

/*
 * 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.features.internal.service;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import java.util.Set;

import org.apache.karaf.features.BundleInfo;
import org.apache.karaf.features.FeaturePattern;
import org.apache.karaf.features.LocationPattern;
import org.apache.karaf.features.internal.model.Bundle;
import org.apache.karaf.features.internal.model.Conditional;
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.model.processing.BundleReplacements;
import org.apache.karaf.features.internal.model.processing.FeatureReplacements;
import org.apache.karaf.features.internal.model.processing.FeaturesProcessing;
import org.apache.karaf.features.internal.model.processing.OverrideBundleDependency;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * Configurable {@link FeaturesProcessor}, controlled by several files from etc/ directory:
    *
  • etc/overrides.properties: may alter bundle versions in features
  • *
  • etc/blacklisted.properties: may filter out some features/bundles
  • *
  • etc/org.apache.karaf.features.xml (new!): incorporates two above files * and may define additional processing (changing G/A/V, adding bundles to features, changing dependency * attributes, ...)
  • *
*/ public class FeaturesProcessorImpl implements FeaturesProcessor { public static Logger LOG = LoggerFactory.getLogger(FeaturesProcessorImpl.class); private FeaturesProcessingSerializer serializer = new FeaturesProcessingSerializer(); // empty, but fully functional features processing configuration private FeaturesProcessing processing = new FeaturesProcessing(); /** * Creates instance of features processor using 1 external URI, additional {@link Blacklist} instance * and additional set of override clauses. */ public FeaturesProcessorImpl(String featureModificationsURI, String featureProcessingVersions, Blacklist blacklistDefinitions, Set overrides) { if (featureModificationsURI != null) { try { try (InputStream stream = new URL(featureModificationsURI).openStream()) { Properties versions = new Properties(); if (featureProcessingVersions != null) { File versionsProperties = new File(new URL(featureProcessingVersions).getPath()); if (versionsProperties.isFile()) { try (InputStream propsStream = new URL(featureProcessingVersions).openStream()) { versions.load(propsStream); } } } processing = serializer.read(stream, versions); } } catch (FileNotFoundException e) { LOG.debug("Can't find feature processing file (" + featureModificationsURI + "), skipping"); } catch (Exception e) { LOG.warn("Can't initialize feature processor: " + e.getMessage()); } } processing.postUnmarshall(blacklistDefinitions, overrides); } /** * Creates instance of features processor using 3 external (optional) URIs. */ public FeaturesProcessorImpl(String featureModificationsURI, String featureProcessingVersions, String blacklistedURI, String overridesURI) { this(featureModificationsURI, featureProcessingVersions, new Blacklist(blacklistedURI), Overrides.loadOverrides(overridesURI)); } /** * Creates instance of features processor using {@link FeaturesServiceConfig configuration object} where * three files may be specified: overrides.properties, blacklisted.properties and org.apache.karaf.features.xml. */ public FeaturesProcessorImpl(FeaturesServiceConfig configuration) { this(configuration.featureModifications, configuration.featureProcessingVersions, configuration.blacklisted, configuration.overrides); } /** * Writes model to output stream. */ public void writeInstructions(OutputStream output) { serializer.write(processing, output); } public FeaturesProcessing getInstructions() { return processing; } /** * For the purpose of assembly builder, we can configure additional overrides that are read from profiles. */ public void addOverrides(Set overrides) { processing.getBundleReplacements().getOverrideBundles() .addAll(FeaturesProcessing.parseOverridesClauses(overrides)); } @Override public void process(Features features) { List featureList = features.getFeature(); for (int i = 0; i < featureList.size(); i++) { Feature f = featureList.get(i); // overriding features first, so we can further override their bundles for (FeatureReplacements.OverrideFeature override : getInstructions().getFeatureReplacements().getReplacements()) { if (f.getId().equals(override.getFeature().getId())) { switch (override.getMode()) { case REPLACE: featureList.set(i, override.getFeature()); break; case MERGE: f.getBundle().addAll(override.getFeature().getBundle()); break; case REMOVE: // TODO break; } } } } for (Feature feature : features.getFeature()) { // blacklisting features boolean allBlacklisted = features.isBlacklisted(); feature.setBlacklisted(allBlacklisted || isFeatureBlacklisted(feature)); // blacklisting feature's dependencies and conditionals for (Conditional conditional : feature.getConditional()) { boolean isConditionBlacklisted = false; for (String cond : conditional.getCondition()) { isConditionBlacklisted |= isFeatureBlacklisted(new Feature(cond)); } conditional.setBlacklisted(feature.isBlacklisted() || isConditionBlacklisted); } for (Dependency dep : feature.getFeature()) { dep.setBlacklisted(feature.isBlacklisted() || isFeatureBlacklisted(new Feature(dep.getName(), dep.getVersion()))); } // override dependency flag (null - don't touch, false - change to false, true - change to true) Boolean dependency = null; for (OverrideBundleDependency.OverrideFeatureDependency overrideFeatureDependency : getInstructions().getOverrideBundleDependency().getFeatures()) { FeaturePattern pattern = new FeaturePattern(overrideFeatureDependency.getName() + "/" + overrideFeatureDependency.getVersion()); if (pattern.matches(feature.getName(), feature.getVersion())) { dependency = overrideFeatureDependency.isDependency(); } } // blacklisting bundles and processing bundles processBundles(feature.getBundle(), allBlacklisted, dependency); for (Conditional c : feature.getConditional()) { processBundles(c.getBundle(), allBlacklisted, dependency); } // TODO: think about overriding at repository level // for (OverrideBundleDependency.OverrideDependency overrideDependency : getInstructions().getOverrideBundleDependency().getRepositories()) { // } } } private void processBundles(List bundles, boolean allBlacklisted, Boolean forceDependency) { for (Bundle bundle : bundles) { boolean bundleBlacklisted = allBlacklisted || isBundleBlacklisted(bundle.getLocation()); if (bundleBlacklisted) { // blacklisting has higher priority bundle.setBlacklisted(true); } else { // if not blacklisted, it may be overriden staticOverrideBundle(bundle); // and may have dependency flag altered if (forceDependency != null) { // set at feature level bundle.setDependency(forceDependency); } else { // may have dependency overriden at bundle level for (OverrideBundleDependency.OverrideDependency overrideBundleDependency : getInstructions().getOverrideBundleDependency().getBundles()) { LocationPattern pattern = new LocationPattern(overrideBundleDependency.getUri()); if (pattern.matches(bundle.getLocation())) { bundle.setDependency(overrideBundleDependency.isDependency()); } } } } } } /** * Processes {@link Bundle bundle definition} and (according to override instructions) maybe sets different target * location and {@link BundleInfo#isOverriden()} flag. */ private void staticOverrideBundle(Bundle bundle) { bundle.setOverriden(BundleInfo.BundleOverrideMode.NONE); String originalLocation = bundle.getLocation(); Optional bestMatch = this.getInstructions().getBundleReplacements().getOverrideBundles().stream() .filter(overrideBundle -> overrideBundle.getOriginalUriPattern().strictlyMatches(originalLocation)) .max((o1, o2) -> Integer.compare(o1.getReplacement().length(), o2.getReplacement().length())); bestMatch.ifPresent(o -> doOverrideBundle(bundle, o)); } private void doOverrideBundle(Bundle bundle, BundleReplacements.OverrideBundle bestMatch) { String originalLocation = bundle.getLocation(); LOG.debug("Overriding bundle location \"" + originalLocation + "\" with \"" + bestMatch.getReplacement() + "\""); bundle.setOriginalLocation(originalLocation); if (bestMatch.getMode() == BundleReplacements.BundleOverrideMode.MAVEN) { bundle.setOverriden(BundleInfo.BundleOverrideMode.MAVEN); } else { bundle.setOverriden(BundleInfo.BundleOverrideMode.OSGI); } bundle.setLocation(bestMatch.getReplacement()); } @Override public boolean isRepositoryBlacklisted(String uri) { for (LocationPattern lp : processing.getBlacklistedRepositoryLocationPatterns()) { if (lp.matches(uri)) { return true; } } return false; } /** * Matching name and version of given feature, checks whether this feature is blacklisted. */ private boolean isFeatureBlacklisted(Feature feature) { return getInstructions().getBlacklist().isFeatureBlacklisted(feature.getName(), feature.getVersion()); } /** * Matching location of the bundle, checks whether this bundle is blacklisted. */ @Override public boolean isBundleBlacklisted(String location) { return getInstructions().getBlacklist().isBundleBlacklisted(location); } /** * Checks whether the configuration in this processor contains any instructions (for bundles, repositories, * overrides, ...). */ public boolean hasInstructions() { int count = 0; count += getInstructions().getBlacklistedRepositories().size(); count += getInstructions().getBlacklistedFeatures().size(); count += getInstructions().getBlacklistedBundles().size(); count += getInstructions().getOverrideBundleDependency().getRepositories().size(); count += getInstructions().getOverrideBundleDependency().getFeatures().size(); count += getInstructions().getOverrideBundleDependency().getBundles().size(); count += getInstructions().getBundleReplacements().getOverrideBundles().size(); count += getInstructions().getFeatureReplacements().getReplacements().size(); return count > 0; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy