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 5b5a0e8ed6dfa43209da6d4586de8caae88f03d1 Author: Grzegorz Grzybek <[email protected]> AuthorDate: Wed Dec 6 10:37:43 2017 +0100 [KARAF-5376] Use etc/versions.properties (configurable) to resolve placeholders in etc/org.apache.karaf.features.xml --- .../resources/etc/org.apache.karaf.features.cfg | 9 ++ features/core/pom.xml | 16 ++ .../model/processing/FeaturesProcessing.java | 2 +- .../karaf/features/internal/osgi/Activator.java | 2 + .../service/FeaturesProcessingSerializer.java | 171 ++++++++++++++++++++- .../internal/service/FeaturesProcessorImpl.java | 27 +++- .../internal/service/FeaturesServiceConfig.java | 27 +++- .../features/internal/service/BlacklistTest.java | 2 +- .../internal/service/FeaturesProcessorTest.java | 32 +++- .../karaf/features/internal/service/fpi03.xml | 30 ++++ pom.xml | 16 ++ .../org/apache/karaf/profile/assembly/Builder.java | 2 +- 12 files changed, 310 insertions(+), 26 deletions(-) diff --git a/assemblies/features/base/src/main/filtered-resources/resources/etc/org.apache.karaf.features.cfg b/assemblies/features/base/src/main/filtered-resources/resources/etc/org.apache.karaf.features.cfg index 57b92b4..c0c6594 100644 --- a/assemblies/features/base/src/main/filtered-resources/resources/etc/org.apache.karaf.features.cfg +++ b/assemblies/features/base/src/main/filtered-resources/resources/etc/org.apache.karaf.features.cfg @@ -62,3 +62,12 @@ featuresBootAsynchronous=false # Store cfg file for config element in feature # #configCfgStore=true + +# +# Configuration of features processing mechanism (overrides, blacklisting, modification of features) +# XML file defines instructions related to features processing +# versions.properties may declare properties to resolve placeholders in XML file +# both files are relative to ${karaf.etc} +# +#featureProcessing=org.apache.karaf.features.xml +#featureProcessingVersions=versions.properties diff --git a/features/core/pom.xml b/features/core/pom.xml index e5eaa85..a2e9729 100644 --- a/features/core/pom.xml +++ b/features/core/pom.xml @@ -88,6 +88,19 @@ </dependency> <dependency> + <groupId>org.ops4j.base</groupId> + <artifactId>ops4j-base-util-property</artifactId> + </dependency> + <dependency> + <groupId>org.ops4j.base</groupId> + <artifactId>ops4j-base-util-collections</artifactId> + </dependency> + <dependency> + <groupId>org.ops4j.pax.swissbox</groupId> + <artifactId>pax-swissbox-property</artifactId> + </dependency> + + <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-log4j12</artifactId> <scope>test</scope> @@ -159,6 +172,9 @@ org.apache.karaf.util.xml, org.eclipse.equinox.internal.region.*;-split-package:=merge-first, org.apache.felix.resolver.*, + org.ops4j.pax.swissbox.*, + org.ops4j.util.*, + org.ops4j.lang.* </Private-Package> <Embed-Dependency> org.apache.karaf.util;inline="org/apache/karaf/util/XmlUtils*.class" 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 3f5050b..537057e 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 @@ -280,7 +280,7 @@ public class FeaturesProcessing { return null; } Version vfloor = new Version(v.getMajor(), v.getMinor(), 0, null); - parser.setVersion(new VersionRange(false, vfloor, v, true).toString()); + parser.setVersion(new VersionRange(false, vfloor, v, v.compareTo(vfloor) > 0).toString()); } return parser.toMvnURI(); } catch (MalformedURLException e) { diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java b/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java index a950f90..5ef8870 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/osgi/Activator.java @@ -92,6 +92,7 @@ public class Activator extends BaseActivator { public static final String FEATURES_SERVICE_CONFIG_FILE = "org.apache.karaf.features.cfg"; public static final String FEATURES_SERVICE_PROCESSING_FILE = "org.apache.karaf.features.xml"; + public static final String FEATURES_SERVICE_PROCESSING_VERSIONS_FILE = "versions.properties"; private static final String STATE_FILE = "state.json"; @@ -238,6 +239,7 @@ public class Activator extends BaseActivator { getInt("scheduleMaxRun", FeaturesService.DEFAULT_SCHEDULE_MAX_RUN), getString("blacklisted", new File(karafEtc, "blacklisted.properties").toURI().toString()), getString("featureProcessing", new File(karafEtc, FEATURES_SERVICE_PROCESSING_FILE).toURI().toString()), + getString("featureProcessingVersions", new File(karafEtc, FEATURES_SERVICE_PROCESSING_VERSIONS_FILE).toURI().toString()), getString("serviceRequirements", FeaturesService.ServiceRequirementsBehavior.Default.getValue())); } diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessingSerializer.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessingSerializer.java index 4a72fe3..6fcbbcb 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessingSerializer.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessingSerializer.java @@ -24,13 +24,15 @@ import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; +import java.io.StringWriter; import java.util.HashMap; import java.util.Map; import java.util.Properties; import javax.xml.bind.JAXBContext; -import javax.xml.bind.JAXBException; import javax.xml.bind.Marshaller; import javax.xml.bind.Unmarshaller; +import javax.xml.bind.UnmarshallerHandler; +import javax.xml.parsers.SAXParserFactory; import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventReader; import javax.xml.stream.XMLEventWriter; @@ -42,8 +44,21 @@ import javax.xml.transform.stream.StreamResult; import org.apache.karaf.features.internal.model.processing.FeaturesProcessing; import org.apache.karaf.features.internal.model.processing.ObjectFactory; import org.apache.karaf.util.xml.IndentingXMLEventWriter; +import org.ops4j.pax.swissbox.property.BundleContextPropertyResolver; +import org.ops4j.util.property.DictionaryPropertyResolver; +import org.ops4j.util.property.PropertyResolver; +import org.osgi.framework.Bundle; +import org.osgi.framework.BundleContext; +import org.osgi.framework.FrameworkUtil; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.xml.sax.Attributes; +import org.xml.sax.ContentHandler; +import org.xml.sax.InputSource; +import org.xml.sax.Locator; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.helpers.AttributesImpl; /** * A class to help serialize {@link org.apache.karaf.features.internal.model.processing.FeaturesProcessing} model @@ -53,12 +68,15 @@ public class FeaturesProcessingSerializer { public static Logger LOG = LoggerFactory.getLogger(FeaturesProcessingSerializer.class); + private final BundleContext bundleContext; private JAXBContext FEATURES_PROCESSING_CONTEXT; public FeaturesProcessingSerializer() { + Bundle bundle = FrameworkUtil.getBundle(this.getClass()); + this.bundleContext = bundle == null ? null : bundle.getBundleContext(); try { FEATURES_PROCESSING_CONTEXT = JAXBContext.newInstance(ObjectFactory.class); - } catch (JAXBException e) { + } catch (Exception e) { throw new RuntimeException(e); } } @@ -68,9 +86,43 @@ public class FeaturesProcessingSerializer { * @param stream * @return */ - public FeaturesProcessing read(InputStream stream) throws JAXBException { + public FeaturesProcessing read(InputStream stream) throws Exception { + return this.read(stream, null); + } + + /** + * Reads {@link FeaturesProcessing features processing model} from input stream + * @param stream + * @param versions additional properties to resolve placeholders in features processing XML + * @return + */ + public FeaturesProcessing read(InputStream stream, Properties versions) throws Exception { Unmarshaller unmarshaller = FEATURES_PROCESSING_CONTEXT.createUnmarshaller(); - return (FeaturesProcessing) unmarshaller.unmarshal(stream); + UnmarshallerHandler handler = unmarshaller.getUnmarshallerHandler(); + + // BundleContextPropertyResolver gives access to e.g., ${karaf.base} + final PropertyResolver resolver = bundleContext == null ? new DictionaryPropertyResolver(versions) + : new DictionaryPropertyResolver(versions, new BundleContextPropertyResolver(bundleContext)); + + // indirect unmarshaling with property resolution inside XML attribute values and CDATA + SAXParserFactory spf = SAXParserFactory.newInstance(); + spf.setNamespaceAware(true); + XMLReader xmlReader = spf.newSAXParser().getXMLReader(); + xmlReader.setContentHandler(new ResolvingContentHandler(new Properties() { + @Override + public String getProperty(String key) { + return resolver.get(key); + } + + @Override + public String getProperty(String key, String defaultValue) { + String value = resolver.get(key); + return value == null ? defaultValue : value; + } + }, handler)); + xmlReader.parse(new InputSource(stream)); + + return (FeaturesProcessing) handler.getResult(); } /** @@ -156,4 +208,115 @@ public class FeaturesProcessingSerializer { } } + private static class ResolvingContentHandler implements ContentHandler { + + public static Logger LOG = LoggerFactory.getLogger(ResolvingContentHandler.class); + + private Properties properties; + private ContentHandler target; + + private boolean inElement = false; + private StringWriter sw = new StringWriter(); + + public ResolvingContentHandler(Properties properties, ContentHandler target) { + this.properties = properties; + this.target = target; + } + + @Override + public void setDocumentLocator(Locator locator) { + target.setDocumentLocator(locator); + } + + @Override + public void startDocument() throws SAXException { + target.startDocument(); + } + + @Override + public void endDocument() throws SAXException { + target.endDocument(); + } + + @Override + public void startPrefixMapping(String prefix, String uri) throws SAXException { + target.startPrefixMapping(prefix, uri); + } + + @Override + public void endPrefixMapping(String prefix) throws SAXException { + target.endPrefixMapping(prefix); + } + + @Override + public void startElement(String uri, String localName, String qName, Attributes atts) throws SAXException { + AttributesImpl resolvedAttributes = new AttributesImpl(atts); + for (int i = 0; i < atts.getLength(); i++) { + resolvedAttributes.setAttribute(i, atts.getURI(i), atts.getLocalName(i), atts.getQName(i), + atts.getType(i), resolve(atts.getValue(i))); + } + if (inElement) { + flushBuffer(false); + } + inElement = true; + target.startElement(uri, localName, qName, resolvedAttributes); + } + + @Override + public void endElement(String uri, String localName, String qName) throws SAXException { + if (inElement) { + flushBuffer(true); + inElement = false; + } + target.endElement(uri, localName, qName); + } + + @Override + public void characters(char[] ch, int start, int length) throws SAXException { + if (inElement) { + sw.append(new String(ch, start, length)); + } else { + target.characters(ch, start, length); + } + } + + @Override + public void ignorableWhitespace(char[] ch, int start, int length) throws SAXException { + // only elements without PCDATA in DTD have whitespace passed to this method. so ignore + target.ignorableWhitespace(ch, start, length); + } + + @Override + public void processingInstruction(String target, String data) throws SAXException { + this.target.processingInstruction(target, data); + } + + @Override + public void skippedEntity(String name) throws SAXException { + target.skippedEntity(name); + } + + /** + * Pass collected characters to target {@link ContentHandler} + * @param resolve whether to expect placeholders in collected text + */ + private void flushBuffer(boolean resolve) throws SAXException { + String value = sw.toString(); + String resolved = resolve ? resolve(value) : value; + + target.characters(resolved.toCharArray(), 0, resolved.length()); + sw = new StringWriter(); + } + + private String resolve(String value) { + String resolved = org.ops4j.util.collections.PropertyResolver.resolve(properties, value); + if (resolved.contains("${")) { + // there are still unresolved properties - just log warning + LOG.warn("Value {} has unresolved properties, please check configuration.", value); + } + return resolved; + } + + } + } diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessorImpl.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessorImpl.java index 4e3fa04..87d26e6 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessorImpl.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesProcessorImpl.java @@ -18,11 +18,13 @@ */ 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.Properties; import java.util.Set; import org.apache.karaf.features.BundleInfo; @@ -49,7 +51,7 @@ public class FeaturesProcessorImpl implements FeaturesProcessor { public static Logger LOG = LoggerFactory.getLogger(FeaturesProcessorImpl.class); - private static FeaturesProcessingSerializer serializer = new FeaturesProcessingSerializer(); + private FeaturesProcessingSerializer serializer = new FeaturesProcessingSerializer(); // empty, but fully functional features processing configuration private FeaturesProcessing processing = new FeaturesProcessing(); @@ -58,14 +60,25 @@ public class FeaturesProcessorImpl implements FeaturesProcessor { * <p>Creates instance of features processor using 1 external URI, additional {@link Blacklist} instance * and additional set of override clauses.</p> * @param featureModificationsURI + * @param featureProcessingVersions * @param blacklistDefinitions * @param overrides */ - public FeaturesProcessorImpl(String featureModificationsURI, Blacklist blacklistDefinitions, Set<String> overrides) { + public FeaturesProcessorImpl(String featureModificationsURI, String featureProcessingVersions, + Blacklist blacklistDefinitions, Set<String> overrides) { if (featureModificationsURI != null) { try { try (InputStream stream = new URL(featureModificationsURI).openStream()) { - processing = serializer.read(stream); + 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"); @@ -80,11 +93,13 @@ public class FeaturesProcessorImpl implements FeaturesProcessor { /** * <p>Creates instance of features processor using 3 external (optional) URIs.</p> * @param featureModificationsURI + * @param featureProcessingVersions * @param blacklistedURI * @param overridesURI */ - public FeaturesProcessorImpl(String featureModificationsURI, String blacklistedURI, String overridesURI) { - this(featureModificationsURI, new Blacklist(blacklistedURI), Overrides.loadOverrides(overridesURI)); + public FeaturesProcessorImpl(String featureModificationsURI, String featureProcessingVersions, + String blacklistedURI, String overridesURI) { + this(featureModificationsURI, featureProcessingVersions, new Blacklist(blacklistedURI), Overrides.loadOverrides(overridesURI)); } /** @@ -93,7 +108,7 @@ public class FeaturesProcessorImpl implements FeaturesProcessor { * @param configuration */ public FeaturesProcessorImpl(FeaturesServiceConfig configuration) { - this(configuration.featureModifications, configuration.blacklisted, configuration.overrides); + this(configuration.featureModifications, configuration.featureProcessingVersions, configuration.blacklisted, configuration.overrides); } /** diff --git a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceConfig.java b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceConfig.java index 7fb0f26..5ea4fea 100644 --- a/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceConfig.java +++ b/features/core/src/main/java/org/apache/karaf/features/internal/service/FeaturesServiceConfig.java @@ -65,25 +65,32 @@ public class FeaturesServiceConfig { public final String featureModifications; /** + * Location of <code>etc/versions.properties</code> to read properties to resolve placeholders in + * {@link #featureModifications} + */ + public final String featureProcessingVersions; + + /** * Location of <code>etc/overrides.properties</code> */ @Deprecated public final String overrides; public FeaturesServiceConfig() { - this(null, null, null); + this(null, null, null, null); } - public FeaturesServiceConfig(String featureModifications) { - this(null, FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE, FeaturesService.DEFAULT_BUNDLE_UPDATE_RANGE, null, 1, 0, 0, null, featureModifications, null); + public FeaturesServiceConfig(String featureModifications, String featureProcessingVersions) { + this(null, FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE, FeaturesService.DEFAULT_BUNDLE_UPDATE_RANGE, null, 1, 0, 0, null, featureModifications, featureProcessingVersions, null); } @Deprecated - public FeaturesServiceConfig(String overrides, String blacklisted, String featureModifications) { - this(overrides, FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE, FeaturesService.DEFAULT_BUNDLE_UPDATE_RANGE, null, 1, 0, 0, blacklisted, featureModifications, null); + public FeaturesServiceConfig(String overrides, String blacklisted, String featureModifications, String featureProcessingVersions) { + this(overrides, FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE, FeaturesService.DEFAULT_BUNDLE_UPDATE_RANGE, null, 1, 0, 0, blacklisted, featureModifications, featureProcessingVersions, null); } - public FeaturesServiceConfig(String featureResolutionRange, String bundleUpdateRange, String updateSnapshots, int downloadThreads, long scheduleDelay, int scheduleMaxRun, String featureModifications, String serviceRequirements) { + public FeaturesServiceConfig(String featureResolutionRange, String bundleUpdateRange, String updateSnapshots, int downloadThreads, long scheduleDelay, int scheduleMaxRun, + String featureModifications, String featureProcessingVersions, String serviceRequirements) { this.overrides = null; this.featureResolutionRange = featureResolutionRange; this.bundleUpdateRange = bundleUpdateRange; @@ -93,11 +100,16 @@ public class FeaturesServiceConfig { this.scheduleMaxRun = scheduleMaxRun; this.blacklisted = null; this.featureModifications = featureModifications; + this.featureProcessingVersions = featureProcessingVersions; this.serviceRequirements = serviceRequirements; } @Deprecated - public FeaturesServiceConfig(String overrides, String featureResolutionRange, String bundleUpdateRange, String updateSnapshots, int downloadThreads, long scheduleDelay, int scheduleMaxRun, String blacklisted, String featureModifications, String serviceRequirements) { + public FeaturesServiceConfig(String overrides, String featureResolutionRange, String bundleUpdateRange, + String updateSnapshots, int downloadThreads, long scheduleDelay, int scheduleMaxRun, + String blacklisted, + String featureModifications, String featureProcessingVersions, + String serviceRequirements) { this.overrides = overrides; this.featureResolutionRange = featureResolutionRange; this.bundleUpdateRange = bundleUpdateRange; @@ -107,6 +119,7 @@ public class FeaturesServiceConfig { this.scheduleMaxRun = scheduleMaxRun; this.blacklisted = blacklisted; this.featureModifications = featureModifications; + this.featureProcessingVersions = featureProcessingVersions; this.serviceRequirements = serviceRequirements; } diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/BlacklistTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/BlacklistTest.java index 6c5d7e2..34fc55f 100644 --- a/features/core/src/test/java/org/apache/karaf/features/internal/service/BlacklistTest.java +++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/BlacklistTest.java @@ -83,7 +83,7 @@ public class BlacklistTest { fos.write(blacklistClause.getBytes("UTF-8")); } RepositoryImpl features = new RepositoryImpl(uri, true); - FeaturesServiceConfig config = new FeaturesServiceConfig(null, FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE, FeaturesService.DEFAULT_BUNDLE_UPDATE_RANGE, null, 1, 0, 0, blacklistedProperties.toURI().toString(), null, null); + FeaturesServiceConfig config = new FeaturesServiceConfig(null, FeaturesService.DEFAULT_FEATURE_RESOLUTION_RANGE, FeaturesService.DEFAULT_BUNDLE_UPDATE_RANGE, null, 1, 0, 0, blacklistedProperties.toURI().toString(), null, null, null); features.processFeatures(new FeaturesProcessorImpl(config)); return Arrays.stream(features.getFeatures()); } diff --git a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesProcessorTest.java b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesProcessorTest.java index e73e7d1..45955b2 100644 --- a/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesProcessorTest.java +++ b/features/core/src/test/java/org/apache/karaf/features/internal/service/FeaturesProcessorTest.java @@ -18,7 +18,9 @@ */ package org.apache.karaf.features.internal.service; +import java.io.FileWriter; import java.net.URI; +import java.util.Properties; import javax.xml.bind.JAXBContext; import javax.xml.bind.Marshaller; @@ -89,7 +91,7 @@ public class FeaturesProcessorTest { public void readingLegacyOverrides() { FeaturesProcessorImpl processor = new FeaturesProcessorImpl(new FeaturesServiceConfig( "file:src/test/resources/org/apache/karaf/features/internal/service/overrides2.properties", - null, null)); + null, null, null)); FeaturesProcessing instructions = processor.getInstructions(); BundleReplacements bundleReplacements = instructions.getBundleReplacements(); @@ -116,7 +118,7 @@ public class FeaturesProcessorTest { FeaturesProcessorImpl processor = new FeaturesProcessorImpl(new FeaturesServiceConfig( null, "file:src/test/resources/org/apache/karaf/features/internal/service/blacklisted2.properties", - null)); + null, null)); FeaturesProcessing instructions = processor.getInstructions(); Blacklist blacklist = instructions.getBlacklist(); @@ -136,7 +138,7 @@ public class FeaturesProcessorTest { public void blacklistingRepositories() { FeaturesProcessorImpl processor = new FeaturesProcessorImpl(new FeaturesServiceConfig( null, null, - "file:src/test/resources/org/apache/karaf/features/internal/service/fpi01.xml")); + "file:src/test/resources/org/apache/karaf/features/internal/service/fpi01.xml", null)); URI uri = URI.create("file:src/test/resources/org/apache/karaf/features/internal/service/fp01.xml"); RepositoryImpl repo = (RepositoryImpl) new RepositoryCacheImpl(processor).create(uri, true); assertThat(repo.getRepositories().length, equalTo(3)); @@ -150,7 +152,7 @@ public class FeaturesProcessorTest { public void blacklistingFeatures() { FeaturesProcessorImpl processor = new FeaturesProcessorImpl(new FeaturesServiceConfig( null, null, - "file:src/test/resources/org/apache/karaf/features/internal/service/fpi01.xml")); + "file:src/test/resources/org/apache/karaf/features/internal/service/fpi01.xml", null)); URI uri = URI.create("file:src/test/resources/org/apache/karaf/features/internal/service/fp02.xml"); RepositoryImpl repo = (RepositoryImpl) new RepositoryCacheImpl(processor).create(uri, true); @@ -166,7 +168,7 @@ public class FeaturesProcessorTest { public void blacklistingBundles() { FeaturesProcessorImpl processor = new FeaturesProcessorImpl(new FeaturesServiceConfig( null, null, - "file:src/test/resources/org/apache/karaf/features/internal/service/fpi01.xml")); + "file:src/test/resources/org/apache/karaf/features/internal/service/fpi01.xml", null)); URI uri = URI.create("file:src/test/resources/org/apache/karaf/features/internal/service/fp03.xml"); RepositoryImpl repo = (RepositoryImpl) new RepositoryCacheImpl(processor).create(uri, true); @@ -182,7 +184,7 @@ public class FeaturesProcessorTest { public void overridingBundles() { FeaturesProcessorImpl processor = new FeaturesProcessorImpl(new FeaturesServiceConfig( null, null, - "file:src/test/resources/org/apache/karaf/features/internal/service/fpi02.xml")); + "file:src/test/resources/org/apache/karaf/features/internal/service/fpi02.xml", null)); URI uri = URI.create("file:src/test/resources/org/apache/karaf/features/internal/service/fp03.xml"); RepositoryImpl repo = (RepositoryImpl) new RepositoryCacheImpl(processor).create(uri, true); @@ -202,6 +204,24 @@ public class FeaturesProcessorTest { } @Test + public void resolvePlaceholders() throws Exception { + Properties props = new Properties(); + props.put("version.jclouds", "1.9"); + props.put("version.commons-io", "2.5"); + props.store(new FileWriter("target/versions.properties"), null); + + FeaturesProcessorImpl processor = new FeaturesProcessorImpl(new FeaturesServiceConfig( + null, null, + "file:src/test/resources/org/apache/karaf/features/internal/service/fpi03.xml", + "file:target/versions.properties")); + + assertThat(processor.getInstructions().getBlacklistedRepositories().get(0), + equalTo("mvn:org.jclouds/jclouds-features/1.9/xml/features")); + assertThat(processor.getInstructions().getBundleReplacements().getOverrideBundles().get(0).getReplacement(), + equalTo("mvn:commons-io/commons-io/2.5")); + } + + @Test public void serializeWithComments() { FeaturesProcessingSerializer serializer = new FeaturesProcessingSerializer(); FeaturesProcessing featuresProcessing = new FeaturesProcessing(); diff --git a/features/core/src/test/resources/org/apache/karaf/features/internal/service/fpi03.xml b/features/core/src/test/resources/org/apache/karaf/features/internal/service/fpi03.xml new file mode 100644 index 0000000..4528fbd --- /dev/null +++ b/features/core/src/test/resources/org/apache/karaf/features/internal/service/fpi03.xml @@ -0,0 +1,30 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + 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. +--> +<featuresProcessing xmlns="http://karaf.apache.org/xmlns/features-processing/v1.0.0"> + + <blacklistedRepositories> + <repository>mvn:org.jclouds/jclouds-features/${version.jclouds}/xml/features</repository> + </blacklistedRepositories> + + <bundleReplacements> + <bundle replacement="mvn:commons-io/commons-io/${version.commons-io}" /> + </bundleReplacements> + +</featuresProcessing> diff --git a/pom.xml b/pom.xml index 4f218d5..81106e9 100644 --- a/pom.xml +++ b/pom.xml @@ -273,6 +273,7 @@ <pax.exam.version>4.11.0</pax.exam.version> <pax.logging.version>1.10.1</pax.logging.version> <pax.base.version>1.5.0</pax.base.version> + <pax.swissbox.version>1.8.2</pax.swissbox.version> <pax.url.version>2.5.3</pax.url.version> <pax.web.version>6.1.0-SNAPSHOT</pax.web.version> <pax.tinybundle.version>2.1.1</pax.tinybundle.version> @@ -1246,6 +1247,16 @@ <version>${pax.base.version}</version> </dependency> <dependency> + <groupId>org.ops4j.base</groupId> + <artifactId>ops4j-base-util-property</artifactId> + <version>${pax.base.version}</version> + </dependency> + <dependency> + <groupId>org.ops4j.base</groupId> + <artifactId>ops4j-base-util-collections</artifactId> + <version>${pax.base.version}</version> + </dependency> + <dependency> <groupId>org.ops4j.pax.url</groupId> <artifactId>pax-url-aether</artifactId> <version>${pax.url.version}</version> @@ -1305,6 +1316,11 @@ </exclusions> </dependency> <dependency> + <groupId>org.ops4j.pax.swissbox</groupId> + <artifactId>pax-swissbox-property</artifactId> + <version>${pax.swissbox.version}</version> + </dependency> + <dependency> <groupId>org.ops4j.pax.url</groupId> <artifactId>pax-url-wrap</artifactId> <version>${pax.url.version}</version> 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 274d535..4a5603c 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 @@ -906,7 +906,7 @@ public class Builder { // 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. - FeaturesProcessorImpl processor = new FeaturesProcessorImpl(existingProcessorDefinitionURI, blacklist, new HashSet<>()); + FeaturesProcessorImpl processor = new FeaturesProcessorImpl(existingProcessorDefinitionURI, null, blacklist, new HashSet<>()); // // Propagate feature installation from repositories -- To stop receiving notification emails like this one, please contact "[email protected]" <[email protected]>.
