You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@karaf.apache.org by gg...@apache.org on 2017/12/09 18:46:52 UTC

[karaf] 09/19: [KARAF-5376] Generate/merge features processor configuration from external and Maven config, improve logging in karaf-maven-plugin:assembly

This is an automated email from the ASF dual-hosted git repository.

ggrzybek pushed a commit to branch KARAF-5376-overrides_v2
in repository https://gitbox.apache.org/repos/asf/karaf.git

commit f245b4ee418c81627e72ac8ddd941250d891121a
Author: Grzegorz Grzybek <gr...@gmail.com>
AuthorDate: Wed Nov 22 15:09:01 2017 +0100

    [KARAF-5376] Generate/merge features processor configuration from external and Maven config, improve logging in karaf-maven-plugin:assembly
---
 .../org/apache/karaf/features/FeaturePattern.java  | 12 +++
 .../org/apache/karaf/features/LocationPattern.java |  4 +
 .../model/processing/FeaturesProcessing.java       | 58 +++++++------
 .../karaf/features/internal/service/Blacklist.java | 12 +++
 .../karaf/profile/assembly/ArtifactInstaller.java  | 28 ++++++
 .../org/apache/karaf/profile/assembly/Builder.java | 99 ++++++++++++++--------
 .../org/apache/karaf/tooling/AssemblyMojo.java     | 10 +++
 7 files changed, 164 insertions(+), 59 deletions(-)

diff --git a/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java b/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java
index 107993b..a77c4df 100644
--- a/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java
+++ b/features/core/src/main/java/org/apache/karaf/features/FeaturePattern.java
@@ -80,6 +80,18 @@ public class FeaturePattern {
         }
     }
 
+    public String getOriginalFeatureId() {
+        return originalId;
+    }
+
+    public String getName() {
+        return nameString;
+    }
+
+    public String getVersion() {
+        return versionString;
+    }
+
     /**
      * Returns <code>true</code> if this feature pattern matches given feature/version
      * @param featureName
diff --git a/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java b/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java
index 428746f..e5c96eb 100644
--- a/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java
+++ b/features/core/src/main/java/org/apache/karaf/features/LocationPattern.java
@@ -108,6 +108,10 @@ public class LocationPattern {
         }
     }
 
+    public String getOriginalUri() {
+        return originalUri;
+    }
+
     /**
      * Converts a String with one special character (<code>*</code>) into working {@link Pattern}
      * @param value
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java b/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java
index 8a3c7b6..3f5050b 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/model/processing/FeaturesProcessing.java
@@ -142,22 +142,49 @@ public class FeaturesProcessing {
     }
 
     /**
-     * Perform <em>compilation</em> of rules declared in feature processing XML file.
+     * <p>Perform <em>compilation</em> of rules declared in feature processing XML file.</p>
+     * <p>Additional blacklist and overrides definitions will be added to this model</p>
+     *
      * @param blacklist additional {@link Blacklist} definition with lower priority
      * @param overrides additional overrides definition with lower priority
      */
     public void postUnmarshall(Blacklist blacklist, Set<String> overrides) {
-        // compile blacklisted repository URIs
-        for (String repositoryURI : this.getBlacklistedRepositories()) {
+        // configure Blacklist tool
+        List<String> blacklisted = new LinkedList<>();
+
+        // compile blacklisted repository URIs (from XML and additional blacklist)
+        blacklist.getRepositoryBlacklist().stream()
+                .map(LocationPattern::getOriginalUri)
+                .forEach(uri -> getBlacklistedRepositories().add(uri));
+        for (String repositoryURI : getBlacklistedRepositories()) {
             try {
                 blacklistedRepositoryLocationPatterns.add(new LocationPattern(repositoryURI));
+                blacklisted.add(repositoryURI + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_REPOSITORY);
             } catch (MalformedURLException e) {
                 LOG.warn("Can't parse blacklisted repository location pattern: " + repositoryURI + ". Ignoring.");
             }
         }
 
-        // verify bundle override definitions
-        for (Iterator<BundleReplacements.OverrideBundle> iterator = this.bundleReplacements.getOverrideBundles().iterator(); iterator.hasNext(); ) {
+        // add external blacklisted features to this model
+        blacklist.getFeatureBlacklist()
+                .forEach(fb -> getBlacklistedFeatures().add(new BlacklistedFeature(fb.getName(), fb.getVersion())));
+        blacklisted.addAll(getBlacklistedFeatures().stream()
+                .map(bf -> bf.getName() + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_FEATURE + (bf.getVersion() == null ? "" : ";" + FeaturePattern.RANGE + "=\"" + bf.getVersion() + "\""))
+                .collect(Collectors.toList()));
+
+        // add external blacklisted bundle URIs to this model
+        blacklist.getBundleBlacklist().stream()
+                .map(LocationPattern::getOriginalUri)
+                .forEach(uri -> getBlacklistedBundles().add(uri));
+        blacklisted.addAll(getBlacklistedBundles().stream()
+                .map(bl -> bl + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_BUNDLE)
+                .collect(Collectors.toList()));
+
+        this.blacklist = new Blacklist(blacklisted);
+
+        // verify bundle override definitions (from XML and additional overrides)
+        bundleReplacements.getOverrideBundles().addAll(parseOverridesClauses(overrides));
+        for (Iterator<BundleReplacements.OverrideBundle> iterator = bundleReplacements.getOverrideBundles().iterator(); iterator.hasNext(); ) {
             BundleReplacements.OverrideBundle overrideBundle = iterator.next();
             if (overrideBundle.getOriginalUri() == null) {
                 // we have to derive it from replacement - as with etc/overrides.properties entry
@@ -180,27 +207,6 @@ public class FeaturesProcessing {
                 iterator.remove();
             }
         }
-
-        // etc/blacklisted.properties
-        // blacklisted bundle from XML to instruction for Blacklist class
-        List<String> blacklisted = new LinkedList<>();
-        for (String bl : this.getBlacklistedBundles()) {
-            blacklisted.add(bl + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_BUNDLE);
-        }
-        // blacklisted features - XML type to String instruction for Blacklist class
-        blacklisted.addAll(this.getBlacklistedFeatures().stream()
-                .map(bf -> bf.getName() + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_FEATURE + (bf.getVersion() == null ? "" : ";" + FeaturePattern.RANGE + "=\"" + bf.getVersion() + "\""))
-                .collect(Collectors.toList()));
-        // blacklisted repositories
-        for (String bl : this.getBlacklistedRepositories()) {
-            blacklisted.add(bl + ";" + Blacklist.BLACKLIST_TYPE + "=" + Blacklist.TYPE_REPOSITORY);
-        }
-
-        this.blacklist = new Blacklist(blacklisted);
-        this.blacklist.merge(blacklist);
-
-        // etc/overrides.properties (mvn: URIs)
-        bundleReplacements.getOverrideBundles().addAll(parseOverridesClauses(overrides));
     }
 
     /**
diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java
index dcc1a20..9792afa 100644
--- a/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java
+++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/Blacklist.java
@@ -243,4 +243,16 @@ public class Blacklist {
         bundleBlacklist.add(locationPattern);
     }
 
+    public List<LocationPattern> getRepositoryBlacklist() {
+        return repositoryBlacklist;
+    }
+
+    public List<FeaturePattern> getFeatureBlacklist() {
+        return featureBlacklist;
+    }
+
+    public List<LocationPattern> getBundleBlacklist() {
+        return bundleBlacklist;
+    }
+
 }
diff --git a/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java b/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java
index 967a979..f068f5e 100644
--- a/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java
+++ b/profile/src/main/java/org/apache/karaf/profile/assembly/ArtifactInstaller.java
@@ -23,6 +23,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.nio.file.StandardCopyOption;
 
+import org.apache.karaf.features.BundleInfo;
 import org.apache.karaf.features.internal.download.Downloader;
 import org.apache.karaf.features.internal.service.Blacklist;
 import org.apache.karaf.util.maven.Parser;
@@ -48,6 +49,33 @@ public class ArtifactInstaller {
         this.blacklist = blacklist;
     }
     
+    public void installArtifact(BundleInfo bundle) throws Exception {
+        if (bundle.isBlacklisted()) {
+            LOGGER.info("      skipping blacklisted maven artifact: " + bundle.getLocation());
+            return;
+        }
+        if (bundle.isOverriden()) {
+            LOGGER.info("      adding overriden maven artifact: " + bundle.getLocation() + " (original location: " + bundle.getOriginalLocation() + ")");
+        } else {
+            LOGGER.info("      adding maven artifact: " + bundle.getLocation());
+        }
+        String location = bundle.getLocation().trim();
+        location = removeTrailingSlash(stripUrl(location));
+        if (!location.startsWith("mvn:")) {
+            LOGGER.warn("Ignoring non maven artifact " + location);
+            return;
+        }
+        final String finalLocation = location;
+        downloader.download(location, provider -> {
+            String uri = provider.getUrl();
+            Path path = pathFromProviderUrl(systemDirectory, finalLocation);
+            synchronized (provider) {
+                Files.createDirectories(path.getParent());
+                Files.copy(provider.getFile().toPath(), path, StandardCopyOption.REPLACE_EXISTING);
+            }
+        });
+    }
+
     public void installArtifact(String location) throws Exception {
         LOGGER.info("      adding maven artifact: " + location);
         location = removeTrailingSlash(stripUrl(location));
diff --git a/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java b/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java
index 960a067..aedc8eb 100644
--- a/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java
+++ b/profile/src/main/java/org/apache/karaf/profile/assembly/Builder.java
@@ -62,6 +62,7 @@ import java.util.zip.ZipInputStream;
 import org.apache.felix.resolver.ResolverImpl;
 import org.apache.felix.utils.manifest.Clause;
 import org.apache.felix.utils.properties.Properties;
+import org.apache.karaf.features.BundleInfo;
 import org.apache.karaf.features.FeaturePattern;
 import org.apache.karaf.features.FeaturesService;
 import org.apache.karaf.features.Library;
@@ -286,6 +287,7 @@ public class Builder {
     boolean ignoreDependencyFlag;
     int defaultStartLevel = 50;
     Path homeDirectory;
+    Path featuresProcessingLocation;
     boolean offline;
     String localRepository;
     String mavenRepositories;
@@ -575,6 +577,20 @@ public class Builder {
     }
 
     /**
+     * <p>Configures custom location for a file with features processing instructions. Normally this file is generated
+     * by the builder if any of blacklisted options are configured.</p>
+     * <p>If custom location is provided and it's not <code>etc/org.apache.karaf.features.xml</code>, it is copied</p>
+     * <p>If custom location is provided and it's <code>etc/org.apache.karaf.features.xml</code>, it's left as is</p>
+     * <p>Any additional blacklisting/overrides configuration via Maven configuration causes overwrite of original
+     * content.</p>
+     * @param featuresProcessing
+     */
+    public Builder setFeaturesProcessing(Path featuresProcessing) {
+        this.featuresProcessingLocation = featuresProcessing;
+        return this;
+    }
+
+    /**
      * Ignore the dependency attribute (dependency="[true|false]") on bundles, effectively forcing their
      * installation.
      */
@@ -860,11 +876,26 @@ public class Builder {
         // profiles are generated after reading features from repositories
         // so for now, we can only configure blacklisting features processor
 
-        Path existingProcessorDefinition = etcDirectory.resolve("org.apache.karaf.features.xml");
+        boolean needFeaturesProcessorFileCopy = false;
         String existingProcessorDefinitionURI = null;
+        Path existingProcessorDefinition = etcDirectory.resolve("org.apache.karaf.features.xml");
         if (existingProcessorDefinition.toFile().isFile()) {
             existingProcessorDefinitionURI = existingProcessorDefinition.toFile().toURI().toString();
+            LOGGER.info("Found existing features processor configuration: {}", homeDirectory.relativize(existingProcessorDefinition));
+        }
+        if (featuresProcessingLocation != null && featuresProcessingLocation.toFile().isFile()
+                && !featuresProcessingLocation.equals(existingProcessorDefinition)) {
+            if (existingProcessorDefinitionURI != null) {
+                LOGGER.warn("Explicitly configured {} will be used for features processor configuration.", homeDirectory.relativize(featuresProcessingLocation));
+            } else {
+                LOGGER.info("Found features processor configuration: {}", homeDirectory.relativize(featuresProcessingLocation));
+            }
+            existingProcessorDefinitionURI = featuresProcessingLocation.toFile().toURI().toString();
+            // when there are no other (configured via Maven for example) processing instructions (e.g., blacklisting)
+            // we don't have to generate this file and may take original content
+            needFeaturesProcessorFileCopy = true;
         }
+
         // now we can configure blacklisting features processor which may have already defined (in XML)
         // configuration for bundle replacements or feature overrides.
         // we'll add overrides from profiles later.
@@ -1014,30 +1045,18 @@ public class Builder {
             editor.run();
         }
 
-//        if (!blacklistedFeatures.isEmpty() || !blacklistedBundles.isEmpty()) {
-//            List<String> lines = new ArrayList<>();
-//            lines.add("#");
-//            lines.add("# Generated by the karaf assembly builder");
-//            lines.add("#");
-//            if (!blacklistedFeatures.isEmpty()) {
-//                lines.add("");
-//                lines.add("# Features");
-//                lines.addAll(blacklistedFeatures);
-//            }
-//            if (!blacklistedBundles.isEmpty()) {
-//                lines.add("");
-//                lines.add("# Bundles");
-//                lines.addAll(blacklistedBundles);
-//            }
-//            LOGGER.info("Generating {}", homeDirectory.relativize(blacklist));
-//            Files.write(blacklist, lines, StandardCharsets.UTF_8, StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING);
-//        }
-
-        // TODO: download overrides, implement fuller override clauses (original->replacement)
         if (processor.hasInstructions()) {
             Path featuresProcessingXml = etcDirectory.resolve("org.apache.karaf.features.xml");
-            try (FileOutputStream fos = new FileOutputStream(featuresProcessingXml.toFile())) {
-                processor.writeInstructions(fos);
+            if (hasOwnInstructions() || overrides.size() > 0) {
+                // just generate new etc/org.apache.karaf.features.xml file (with external config + builder config)
+                try (FileOutputStream fos = new FileOutputStream(featuresProcessingXml.toFile())) {
+                    LOGGER.info("Generating features processor configuration: {}", homeDirectory.relativize(featuresProcessingXml));
+                    processor.writeInstructions(fos);
+                }
+            } else if (needFeaturesProcessorFileCopy) {
+                // we may simply copy configured features processor XML configuration
+                LOGGER.info("Copying features processor configuration: {} -> {}", homeDirectory.relativize(featuresProcessingLocation), homeDirectory.relativize(featuresProcessingXml));
+                Files.copy(featuresProcessingLocation, featuresProcessingXml, StandardCopyOption.REPLACE_EXISTING);
             }
         }
 
@@ -1058,6 +1077,20 @@ public class Builder {
     }
 
     /**
+     * Similar to {@link FeaturesProcessorImpl#hasInstructions()}, we check if there are any builder configuration
+     * options for blacklisted repos/features/bundles or overwrites.
+     * @return
+     */
+    private boolean hasOwnInstructions() {
+        int count = 0;
+        count += blacklistedRepositoryURIs.size();
+        count += blacklistedFeatureIdentifiers.size();
+        count += blacklistedBundleURIs.size();
+
+        return count > 0;
+    }
+
+    /**
      * Checks existing (etc/overrides.properties) and configured (in profiles) overrides definitions
      * @param profileOverrides
      * @return
@@ -1091,7 +1124,7 @@ public class Builder {
             try {
                 blacklist.blacklistRepository(new LocationPattern(br));
             } catch (MalformedURLException e) {
-                LOGGER.warn("Blacklisted features XML repository URI is invalid {}, ignoring", br);
+                LOGGER.warn("Blacklisted features XML repository URI is invalid: {}, ignoring", br);
             }
         }
         for (String bf : blacklistedFeatureIdentifiers) {
@@ -1101,7 +1134,7 @@ public class Builder {
             try {
                 blacklist.blacklistBundle(new LocationPattern(bb));
             } catch (MalformedURLException e) {
-                LOGGER.warn("Blacklisted bundle URI is invalid {}, ignoring", bb);
+                LOGGER.warn("Blacklisted bundle URI is invalid: {}, ignoring", bb);
             }
         }
         if (existingBlacklist != null) {
@@ -1320,7 +1353,7 @@ public class Builder {
             LOGGER.info("   Feature {} is defined as an installed feature", feature.getId());
             for (Bundle bundle : feature.getBundle()) {
                 if (!ignoreDependencyFlag || !bundle.isDependency()) {
-                    installer.installArtifact(bundle.getLocation().trim());
+                    installer.installArtifact(bundle);
                 }
             }
             // Install config files
@@ -1330,7 +1363,7 @@ public class Builder {
             for (Conditional cond : feature.getConditional()) {
                 for (Bundle bundle : cond.getBundle()) {
                     if (!ignoreDependencyFlag || !bundle.isDependency()) {
-                        installer.installArtifact(bundle.getLocation().trim());
+                        installer.installArtifact(bundle);
                     }
                 }
             }
@@ -1392,16 +1425,16 @@ public class Builder {
             // the feature is a startup feature, updating startup.properties file
             LOGGER.info("   Feature " + feature.getId() + " is defined as a boot feature");
             // add the feature in the system folder
-            Set<String> locations = new HashSet<>();
+            Set<BundleInfo> bundleInfos = new HashSet<>();
             for (Bundle bundle : feature.getBundle()) {
                 if (!ignoreDependencyFlag || !bundle.isDependency()) {
-                    locations.add(bundle.getLocation().trim());
+                    bundleInfos.add(bundle);
                 }
             }
             for (Conditional cond : feature.getConditional()) {
                 for (Bundle bundle : cond.getBundle()) {
                     if (!ignoreDependencyFlag || !bundle.isDependency()) {
-                        locations.add(bundle.getLocation().trim());
+                        bundleInfos.add(bundle);
                     }
                 }
             }
@@ -1413,10 +1446,10 @@ public class Builder {
             prereqs.put("wrap:", Collections.singletonList("wrap"));
             prereqs.put("war:", Collections.singletonList("war"));
             ArtifactInstaller installer = new ArtifactInstaller(systemDirectory, downloader, blacklist);
-            for (String location : locations) {
-                installer.installArtifact(location);
+            for (BundleInfo bundleInfo : bundleInfos) {
+                installer.installArtifact(bundleInfo);
                 for (Map.Entry<String, List<String>> entry : prereqs.entrySet()) {
-                    if (location.startsWith(entry.getKey())) {
+                    if (bundleInfo.getLocation().trim().startsWith(entry.getKey())) {
                         for (String prereq : entry.getValue()) {
                             Dependency dep = generatedDep.get(prereq);
                             if (dep == null) {
diff --git a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java
index 08f41cb..2830306 100644
--- a/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java
+++ b/tooling/karaf-maven-plugin/src/main/java/org/apache/karaf/tooling/AssemblyMojo.java
@@ -88,6 +88,13 @@ public class AssemblyMojo extends MojoSupport {
     @Parameter(defaultValue = "${project.build.directory}/assembly")
     protected File workDirectory;
 
+    /**
+     * Optional location for custom features processing XML configuration
+     * (<code>etc/org.apache.karaf.features.cfg</code>)
+     */
+    @Parameter
+    protected File featuresProcessing;
+
     /*
      * There are three builder stages related to maven dependency scopes:
      *  - Stage.Startup : scope=compile
@@ -462,6 +469,9 @@ public class AssemblyMojo extends MojoSupport {
         builder.writeProfiles(writeProfiles);
         builder.environment(environment);
         builder.defaultStartLevel(defaultStartLevel);
+        if (featuresProcessing != null) {
+            builder.setFeaturesProcessing(featuresProcessing.toPath());
+        }
 
         // Set up remote repositories from Maven build, to be used by pax-url-aether resolver
         String remoteRepositories = MavenUtil.remoteRepositoryList(project.getRemoteProjectRepositories());

-- 
To stop receiving notification emails like this one, please contact
"commits@karaf.apache.org" <co...@karaf.apache.org>.