Usage

Converting Sling, Project Content Packages and Launch it

Note: In this sample we use Maven variables like project.groupId instead of a static value assuming that the project is within the same project that creates the content packages. Adjust that as needed. Note: Because we generate Feature Model files here the feature model files are in target/fm. We use fm instead of features to avoid confusion with the default feature source of src/main/features.

First we need to define the Content Packages that are converted

<dependencies>
...
    <dependency>
        <groupId>${project.groupId}</groupId>
        <artifactId>my-content-package</artifactId>
        <version>${project.version}</version>
        <type>zip</type>
    </dependency>

Then we need to include the JCR Package Init to deploy the packages when the project is launched:

    <dependency>
        <groupId>org.apache.sling</groupId>
        <artifactId>org.apache.sling.jcr.packageinit</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </dependency>
...
</dependencies>

Then we need to include the package init feature model file which must here is placed in the src/main/resouces/fm folder named sling_packageinit.json:

{
    "id":"${project.groupId}:${project.artifactId}:slingfeature:sling_packageinit:${project.version}",
    "variables":{
    },
    "bundles":[
        {
            "id":"org.apache.sling:org.apache.sling.jcr.packageinit:0.0.1-SNAPSHOT",
            "start-level":"10"
        }
    ]
}

We need to cpy this file into our target folder because this is not a regular JAR build and so the copy of the resources is not done automatically:

<build>
...
    <plugins>
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-resources-plugin</artifactId>
            <version>3.1.0</version>
            <configuration>
                <outputDirectory>${project.build.directory}</outputDirectory>
                <resources>
                    <resource>
                        <directory>src/main/resources</directory>
                    </resource>
                </resources>
            </configuration>
            <executions>
                <execution>
                    <id>copy-frm-resource</id>
                    <phase>process-resources</phase>
                    <goals>
                        <goal>copy-resources</goal>
                    </goals>
                </execution>
            </executions>
        </plugin>

Then we need to setup the Sling Feature Converter Maven Plugin to convert Sling into its Feature Model equivalent so that we can launch it together with the converter CP packages later:

         <plugin>
            <groupId>org.apache.sling</groupId>
            <artifactId>sling-feature-converter-maven-plugin</artifactId>
            <version>1.0.4</version>
            <extensions>true</extensions>
            <executions>
                <execution>
                    <id>convert-pm</id>
                    <phase>process-classes</phase>
                    <goals>
                        <goal>convert-pm</goal>
                    </goals>
                    <configuration>
                        <inputFolder>src/main/resources/sling/provisioning</inputFolder>
                        <outputFolder>target/fm</outputFolder>
                        <groupId>${{project.groupId}}</groupId>
                        <artifactId>${{project.artifactId}}</artifactId>
                        <version>${{project.version}}</version>
                        <frameworkProperties>
                            launchpad:felix.systempackages.substitution=true,
                            launchpad:felix.systempackages.calculate.uses=true
                        </frameworkProperties>
                        <excludeBundles>
                            org.apache.sling.launchpad.installer,
                            org.apache.sling.jcr.repoinit.impl.RepositoryInitializer
                        </excludeBundles>
                        <runModes>
                            oak_tar,
                            :standalone
                        </runModes>
                    </configuration>
                </execution>

In this scenario the Sling Provisioning Models are copied into the source folder. The Launchpad Installer and the Repository Initializer do not work together with Sling FM so they are excluded here. Then we select oak_tar and :standalone as the runmodes for this instance.

Then we convert the Content Package:

                <execution>
                    <id>convert-cp</id>
                    <phase>process-classes</phase>
                    <goals>
                        <goal>convert-cp</goal>
                    </goals>
                    <configuration>
                        <!-- NOTE: ${{ / }} is a way to encode placeholders that should not be interpolated in Maven in this call
                                   and ${{{ / }}} is used to make it a CP Conversion Placeholder -->
                        <artifactIdOverride>${{project.groupId}}:${{project.artifactId}}:slingosgifeature:${{{filename}}}:${{project.version}}</artifactIdOverride>
                        <installConvertedCP>true</installConvertedCP>
                        <!-- Attention: because of the hack to deal with the overrides in the local Repo the generated files must be placed locally and not in the local Maven repo -->
                        <convertedCPOutput>${project.build.directory}/fm.out</convertedCPOutput>
                        <fmOutput>${project.build.directory}/fm</fmOutput>
                        <fmPrefix>test-ui-apps-</fmPrefix>
                        <contentPackages>
                            <contentPackage>
                                <groupId>org.apache.sling.test</groupId>
                                <artifactId>ui.apps</artifactId>
                            </contentPackage>
                        </contentPackages>
                    </configuration>
                </execution>
            </executions>
        </plugin>

Here we override the Feature Id to a more generic version, mark that we want to intall the converted files into our local Maven repo and that we prefix the converted FM file with test-ui-apps-.

Now we setup this Plugin and set the features folder to target/fm (keep in mind this path has to be relative to the basedir and cannot be absolute):

        <plugin>
            <groupId>org.apache.sling</groupId>
            <artifactId>slingfeature-maven-plugin</artifactId>
            <version>1.1.12</version>
            <extensions>true</extensions>
            <configuration>
                <features>target/fm</features>
            </configuration>

Now we can aggregate, collect them into a single FM file (attach) and verify all the generated Feature Model files:

                <execution>
                    <id>aggregate-base-feature</id>
                    <phase>generate-test-sources</phase>
                    <goals>
                        <goal>aggregate-features</goal>
                        <generatedFeatures>${basedir}/target/fm</generatedFeatures>
                    </goals>
                    <configuration>
                        <aggregates>
                            <aggregate>
                                <classifier>example-runtime</classifier>
                                <filesInclude>**/*.json</filesInclude>
                            </aggregate>
                        </aggregates>
                    </configuration>
                </execution>
                <execution>
                    <id>attach-base-feature</id>
                    <phase>process-test-sources</phase>
                    <goals>
                        <goal>attach-features</goal>
                    </goals>
                </execution>
                <execution>
                    <id>verify-analyze</id>
                    <phase>generate-test-resources</phase>
                    <goals>
                        <goal>analyse-features</goal>
                    </goals>
                    <configuration>
                        <framework>
                            <groupId>org.apache.felix</groupId>
                            <artifactId>org.apache.felix.framework</artifactId>
                            <version>6.0.1</version>
                        </framework>
                        <scans>
                            <scan>
                                <includeClassifier>example-runtime</includeClassifier>
                                <includeTasks>
                                    <includeTask>bundle-packages</includeTask>
                                </includeTasks>
                            </scan>
                        </scans>
                    </configuration>
                </execution>
            </executions>
        </plugin>
...
    </plugins>
</build>

Finally we can define a profile to launch the Feature Model based project. With that the launch is only done if the project is buil with goal install and profile launch (mvn install -P launch):

<profiles>
    <profile>
        <id>launch</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.sling</groupId>
                    <artifactId>slingfeature-maven-plugin</artifactId>
                    <version>1.1.12</version>
                    <extensions>true</extensions>
                        <dependencies>
                            <!-- For now the Extension Content has to be placed ahead of the launcher to make CP
                                 deployment work (see SLING-8483) -->
                            <dependency>
                                <groupId>org.apache.sling</groupId>
                                <artifactId>org.apache.sling.feature.extension.content</artifactId>
                                <version>1.0.5-SNAPSHOT</version>
                            </dependency>
                            <dependency>
                                <groupId>org.apache.sling</groupId>
                                <artifactId>org.apache.sling.feature.launcher</artifactId>
                                <version>1.1.0</version>
                            </dependency>
                        </dependencies>
                        <executions>
                            <execution>
                                <id>launch-it</id>
                                <phase>install</phase>
                                <goals>
                                    <goal>launch-features</goal>
                                </goals>
                                <configuration>
                                    <selection>
                                        <includeClassifier>example-runtime</includeClassifier>
                                    </selection>
                                </configuration>
                            </execution>
                        </executions>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

The execution of a conversion and launch would look like this:

mvn \
    clean \
    install \
    -P launch

Converting a Content Package and Install its Feature Model Descriptor

Instead of building everything local in a dedicated Maven module now each Content Project Module can install their generated Feature Module descriptor into the local Maven repository so that it can be included as artifact when the FM project is assembled.

First in each Content Package module add this plugin configuration to your POM in the build section:

<plugin>
    <groupId>org.apache.sling</groupId>
    <artifactId>sling-feature-converter-maven-plugin</artifactId>
    <version>${sling-feature-converter-maven-plugin.version}</version>
    <extensions>true</extensions>
    <executions>
        <execution>
            <id>convert-cp</id>
            <phase>verify</phase>
            <goals>
                <goal>convert-cp</goal>
            </goals>
            <configuration>
                <artifactIdOverride>${project.groupId}:${project.artifactId}:slingosgifeature:${{{filename}}}:${project.version}</artifactIdOverride>
                <installConvertedCP>true</installConvertedCP>
                <convertedCPOutput>${project.build.directory}/fm.out</convertedCPOutput>
                <fmOutput>${project.build.directory}/fm</fmOutput>
                <fmPrefix>peregrine-</fmPrefix>
                <isContentPackage>true</isContentPackage>
                <contentPackages>
                    <contentPackage>
                        <groupId>${project.groupId}</groupId>
                        <artifactId>${project.artifactId}</artifactId>
                    </contentPackage>
                </contentPackages>
            </configuration>
        </execution>
    </executions>
</plugin>
  • sling-feature-converter-maven-plugin.version: is a property with the version of this plugin to be used (1.0.2 for now)
  • artifactIdOverride: This should match the Maven Id with this pattern: ‘groupId’:‘artifactId’:‘type fixed to slingosgifeature’:‘classifier’:‘version’
  • installConvertedCP: must be set to true otherwise I cannot be assembled later
  • convertedCPOutput/fmOutput/fmPrefix: adjust to your preferences
  • isContentPackage: must be set to true
  • contentPackage: must match the module’s properties (later we might remove this)

After a successful build one can check the installation by going to your local Maven repository, got to the location of you artifact and check if there is a file with the extension slingosgifeature.

Now we can go to the Assembly part and add the FM installed locally as artifact:

<plugin>
    <groupId>org.apache.sling</groupId>
    <artifactId>slingfeature-maven-plugin</artifactId>
    <version>${slingfeature-maven-plugin.version}</version>
    <extensions>true</extensions>
    <configuration>
        <features>target/fm</features>
        <generatedFeatures>${basedir}/target/fm</generatedFeatures>
    </configuration>
    <executions>
        <execution>
            <id>aggregate-base-feature</id>
            <phase>generate-test-sources</phase>
            <goals>
                <goal>aggregate-features</goal>
            </goals>
            <configuration>
                <aggregates>
                    <aggregate>
                        <classifier>example-runtime</classifier>
                        <filesInclude>**/*.json</filesInclude>
                        <configurationOverrides>*=USE_LATEST</configurationOverrides>
                        <includeArtifact>
                            <groupId>org.apache.sling</groupId>
                            <artifactId>base.ui.apps</artifactId>
                            <version>1.0.4</version>
                            <classifier>base.ui.apps</classifier>
                            <type>slingosgifeature</type>
                        </includeArtifact>
                        ...
                    </aggregate>
                </aggregates>
            </configuration>
        </execution>
    </executions>
</plugin>
  • slingfeature-maven-plugin.version: version of the sling feature maven plugin to be used
  • features/generatedFeatures: add/set depending on your project
  • classifier/filesInclude/configurationOverrides: set depending on your project
  • includeArtifact: one entry per Content Package FM. The groupId, artifactId, version and classifier must match your FM descriptor