Hello

I want to report about my progress with
https://issues.apache.org/jira/browse/KARAF-5376 (Processor mechanism for
feature definitions (a.k.a. "better overrides")).

*Goal* - to replace (or provide more flexible alternative) of "overrides"
and "blacklisting" mechanisms

*Idea* - Karaf features come (normally) from features XML files, according
to XML Schema specified by Karaf itself. My idea was that we can
"intercept" the process of loading the repositories and alter the
definitions. Effectively we could then affect the definitions which may be
out of our influence, or use some bundles we'd rather like to replace with
others. Some feature repositories include other repositories (e.g., Camel
2.19.2 features referencing CXF 3.1.11 features) and we'd rather like to
avoid it.

*Problems with blacklisting and overrides* - blacklisting is purely static
thing - applied at distro creation time. Overrides are a bit awkward to use
("range" clause) and have some implicit behavior (requiring runtime access
to resource, to verify version and symbolic name).

*What I did*

In short words - I've created a mechanism steered by
etc/org.apache.karaf.features.xml (name matching
etc/org.apache.karaf.features.cfg PID) that looks roughly like this:

<featuresProcessing xmlns="
http://karaf.apache.org/xmlns/features-processing/v1.0.0";
        xmlns:f="http://karaf.apache.org/xmlns/features/v1.5.0";>

    <blacklistedRepositories>

<repository>mvn:org.hibernate/hibernate-validator-osgi-karaf-features/[5,*)/xml/features</repository>
        <!-- ... -->
    </blacklistedRepositories>
    <blacklistedFeatures>
        <feature>*jetty*</feature>
        <feature version="[2,3)">*jclouds*</feature>
        <!-- ... -->
    </blacklistedFeatures>
    <blacklistedBundles>
        <bundle>mvn:commons-logging/*</bundle>
    </blacklistedBundles>

    <overrideBundleDependency>
        <!-- Override "dependency" flag for all bundles of all features for
given repository URI(s) -->
        <repository
uri="mvn:org.ops4j.pax.cdi/pax-cdi-features/*/xml/features"
dependency="true" />
        <repository uri="mvn:*/xml/features" dependency="true" />
        <!-- Override "dependency" flag for all bundles of given feature(s)
-->
        <feature name="jclouds*" version="[1,3)" dependency="true" />
        <!-- Override "dependency" flag for given bundle(s) -->
        <bundle uri="mvn:javax.annotation/javax.annotation-api/*"
dependency="true" />
...
    </overrideBundleDependency>

    <bundleReplacements>
        <bundle
originalUri="mvn:commons-beanutils/commons-beanutils/[1.9,2)"
                replacement="mvn:commons-beanutils/commons-beanutils/1.9.3"
/>
        <bundle
replacement="mvn:commons-collections/commons-collections/3.2.2" />
        <bundle
originalUri="mvn:org.eclipse.jetty.orbit/javax.servlet/[3,4)"

replacement="mvn:org.apache.geronimo.specs/geronimo-servlet_3.0_spec/1.0"
mode="maven" />
        <!-- ... -->
    </bundleReplacements>

    <featureReplacements>
        <replacement mode="replace">
            <feature name="pax-jsf-resources-support" description="Provide
sharing of resources according to Servlet 3.0 for OSGi bundles and JSF"
version="6.0.7">
                <f:feature version="[6.0,6.1)">pax-jsf-support</f:feature>
                <f:bundle
dependency="true">mvn:org.ops4j.pax.web/pax-web-resources-extender/6.0.7</f:bundle>

<f:bundle>mvn:org.ops4j.pax.web/pax-web-resources-jsf/6.0.7</f:bundle>
            </feature>
        </replacement>
        <!-- ... -->
    </featureReplacements>

</featuresProcessing>

Description:

 - blacklistedRepositories, blacklistedFeatures and blacklistedBundles mean
what they mean - mark (instead of removing) given item kind from JAXB model
of loaded features XML. This information is preserved at runtime, and for
example is displayed with "features:list" command

 - overrideBundleDependency (not yet implemented) - is a method of
overriding "dependency="true|false"" flags in feature definitions

 - bundleReplacements (implemented) - is an extension of "overrides"
mechanism. In "osgi" mode, it roughly works like before - requires access
to runtime ResourceImpl, to check headers and compare versions and symbolic
names. In "maven" mode it's just static change of given bundle URI - any
feature declaring <bundle>originalUri</bundle> will be seen as declaring
<bundle>replacement</bundle>. This allows for replacement of e.g., SMX
specs bundle with javax.* bundle (or vice versa).

 - featureReplacements (not yet implemented) - is a way of changing (or
altering) any features by name (or pattern) and version simply by providing
different definition of given feature. This could be useful if we as Karaf
users know "better" than authors of original features, for whom OSGi and
Karaf were rather an afterthought.

Both bundle/feature/repository blacklisting and bundle/feature override use
two new classes to "match" candidate to replace/override:
 - org.apache.karaf.features.LocationPattern - matches URI (of bundle or
repository) in two modes - for non mvn: URI, it just uses a string with
possible "*" glob. For mvn: URI, it splits the URI into well known
components (groupId, artifactId, version, type and classifier). For version
it can use version range (e.g, "[2.1,2.2)") and for other components it can
use "*" glob.
 - org.apache.karaf.features.FeaturePattern - matches feature by name
(possibly containing "*" glob) and version range
(org.apache.felix.utils.version.VersionRange)

Universally applicable:

FeaturesProcessor generally postprocesses
org.apache.karaf.features.internal.model.Features instance(s) and marks
items as blacklisted if they match given pattern and changes the model
(according to overrides/replacements).

The behavior after processing JAXB model of features is exactly the same
both when using FeaturesServiceImpl at runtime and when using profile
Builder during custom assembly creation. For example changed flow of
karaf-maven-plugin:asembly invocation looks like this:

[INFO] --- karaf-maven-plugin:4.2.0-SNAPSHOT:assembly (default-assembly) @
test-karaf-plugins ---
[INFO] Using repositories:
[INFO]    https://repo.maven.apache.org/maven2@id=central
...
[INFO]    Custom startup KAR found:
mvn:grgr.test.karaf.plugins/my-kar/0.1.0.BUILD-SNAPSHOT/kar
...
[INFO] Unzipping kars
[INFO]    processing KAR:
mvn:grgr.test.karaf.plugins/my-kar/0.1.0.BUILD-SNAPSHOT/kar
[INFO]       found repository:
mvn:grgr.test.karaf.plugins/my-kar/0.1.0.BUILD-SNAPSHOT/xml/features
[INFO] Found features processor configuration:
../classes/etc/org.apache.karaf.features.xml
...
[INFO] Loading profiles from:
[INFO]
file:///home/ggrzybek/sources/_testing/grgr-test-karaf-plugins/src/main/profiles/1
[INFO]    jar:mvn:test/profiles/42!/profiles/2
[INFO]    Found profiles: p1a, p1b-another, p2b, p2c-two, p2c-one-two, p2a
...
[INFO] Generating features processor configuration:
etc/org.apache.karaf.features.xml
[INFO] Startup stage
[INFO]    Loading startup repositories
[INFO]    Resolving startup features and bundles
[INFO]       Features: undertow, my-startup-feature
...
[INFO]       skipping blacklisted maven bundle:
mvn:org.ops4j.pax.tipi/org.ops4j.pax.tipi.undertow.websocket-jsr/1.3.25.1
...
[INFO] Boot stage
[INFO]    Loading boot repositories
[INFO]       adding feature repository:
mvn:org.ops4j.pax.web/pax-web-features/6.0.7/xml/features
[INFO]       adding feature repository:
mvn:grgr.test.karaf.plugins/my-kar/0.1.0.BUILD-SNAPSHOT/xml/features
[INFO]    Feature undertow/1.3.25.1 is defined as a boot feature
...
[INFO]       adding overriden maven artifact:
mvn:org.jboss.logging/jboss-logging/3.3.1.Final (original location:
mvn:org.jboss.logging/jboss-logging/3.3.0.Final)
...
[INFO]       skipping blacklisted maven artifact:
mvn:org.ops4j.pax.tipi/org.ops4j.pax.tipi.undertow.websocket-jsr/1.3.25.1
[INFO]       adding overriden maven artifact:
mvn:javax.servlet/javax.servlet-api/3.1-b09 (original location:
mvn:javax.servlet/javax.servlet-api/3.1.0)
...
[INFO] Install stage
[INFO]    Loading installed repositories

overrides and blacklisting information may come from karaf-maven-plugin
configuration (in POM), from externally provided
org.apache.karaf.features.xml (e.g., in resource KAR or in POM:
<configuration>/<featuresProcessing>) or from profiles.

There are still few things to polish, but I'll appreciate any feedback to
check if I misunderstood something or there were other plans related to
these mechanisms. The changes are in
https://github.com/apache/karaf/commits/KARAF-5376-overrides_v2 branch.

best regards
Grzegorz Grzybek

Reply via email to