How to develop/deploy CQ5 components/bundles using JUST an OSGi bundle

For those that develop CQ5 components, most people will be familiar with CRXDE or Eclipse to develop CQ5 components and OSGi bundles. The usual unit of deployment is a CRX package either created using the Package Manager or some build script offline using the vault format. The CQ5 package will contain inside it one or more OSGi bundles which are then picked up by the JCR Installer and deploy it to Apache Felix.

There is one other way of deploying code to CQ5 and that is using OSGi bundles with the JCR content bundled as resources inside the bundle itself. This mechanism is used by the applications developed on Apache Sling. Since CQ5 components are essentially Sling applications, I thought I’d describe how to go about doing offline development and deployment of an example CQ5 component using maven.

Let’s start with the pre-requisites:

  1. A local CQ5 instance
  2. Maven
  3. A maven repository with the OSGi bundles OR Install the Archiva Servlet (link) on CQ5

Let’s assume you have these ready.

The first thing you need is a project structure and a pom file.

In my app, I created a project structure as follows:
sample-sling-app/

pom.xml

src/main/java/

com/technomaven/samples/

SomeService.java

com/technomaven/samples/impl

SomeServiceImpl.java

src/main/resources/SLING-CONTENT/

apps/technomaven/components/

testcomponent/

testcomponent.jsp

testcomponent.json

apps/technomaven/templates/

apps/technomaven/config/

etc/designs/my-sling-app/

my-sling-app.json

This source structure will produce the jar file which includes the java classes (contained in src/main/java) and the JCR nodes, properties, and files that constitute the CQ5 components (contained in src/main/resources/SLING-CONTENT).  You’ll notice the CQ5 folders for apps and etc/designs/ are there.  You can add any other folders there too.

First a look at the pom.xml

<?xml version=”1.0″ encoding=”UTF-8″?>
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.apache.sling</groupId>
        <artifactId>sling</artifactId>
        <version>11</version>
    </parent>
    <groupId>com.technomaven.sling.samples</groupId>
    <artifactId>sample-sling-app</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>bundle</packaging>
    <name>Technomaven Sample Sling App</name>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-scr-plugin</artifactId>
            </plugin>
            <plugin>
                <groupId>org.apache.felix</groupId>
                <artifactId>maven-bundle-plugin</artifactId>
                <extensions>true</extensions>
                <executions>
                <execution>
                <id>install-bundle</id>
                <goals>
                <goal>install</goal>
                </goals>
                </execution>
                </executions>
                <configuration>
                    <instructions>
                        <Export-Package>com.technomaven.sling.samples.*</Export-Package>
                        <Private-Package>
                        </Private-Package>
                        <Sling-Initial-Content>
                        SLING-CONTENT/apps/technomaven;overwrite:=true;uninstall:=true;path:=/apps/technomaven,
                        SLING-CONTENT/content/technomaven;overwrite:=true;uninstall:=true;path:=/content/technomaven,
SLING-CONTENT/etc/designs/my-sling-app.json;overwrite:=true;uninstall:=true;path:=/etc/designs/,
SLING-CONTENT/etc/designs/my-sling-app/;overwrite:=true;uninstall:=true;path:=/etc/designs/my-sling-app
                        </Sling-Initial-Content>
                    </instructions>
                </configuration>
            </plugin>
            <plugin>
                        <groupId>org.apache.sling</groupId>
                        <artifactId>maven-sling-plugin</artifactId>
                        <version>2.0.4-incubator</version>
                        <executions>
                            <execution>
                                <id>install-bundle</id>
                                <goals>
                                    <goal>install</goal>
                                </goals>
                            </execution>
                        </executions>
                        <configuration>
                            <slingUrl>http://localhost:4502/system/console</slingUrl&gt;
                            <user>admin</user>
                            <password>admin</password>
                        </configuration>
                    </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.osgi</groupId>
            <artifactId>org.osgi.core</artifactId>
        </dependency>
        …
    </dependencies>
</project>

Most of this is your usual maven configuration of the dependent libraries.  If we concentrate on the plugins section, there are three plugins:

  1. maven-scr-plugin
  2. maven-bundle-plugin
  3. maven-sling-plugin

maven-scr-plugin is used to use the scr annotations in the java classes to register or wire the OSGi services.

maven-bundle-plugin uses BND to produce the OSGi bundle with the correct MANIFEST.MF contents.  Note the entries in the configuration element.  These include the Export-Package, Import-Package, Private-Package headers found in your typical OSGi bundle.  The extra element here is the Sling-Initial-Content element which includes declarations of what parts of the bundle should be used to initialise content in the JCR (CRX in our case).

If we look closely, we have several entries delimited by commas:

<Sling-Initial-Content>
                        SLING-CONTENT/apps/technomaven;overwrite:=true;uninstall:=true;path:=/apps/technomaven,
                        SLING-CONTENT/content/technomaven;overwrite:=true;uninstall:=true;path:=/content/technomaven,
SLING-CONTENT/etc/designs/my-sling-app.json;overwrite:=true;uninstall:=true;path:=/etc/designs/,
SLING-CONTENT/etc/designs/my-sling-app/;overwrite:=true;uninstall:=true;path:=/etc/designs/my-sling-app
</Sling-Initial-Content>

Each entry contains the location in the bundle, a flag to overwrite in the repository, a flag to install the content on uninstall of the bundle, and the path in the repository that the contents should be written.

The actual contents of SLING-CONTENT can be specified according to the Sling Content Loader mechanism (more detail here)

Each folder represents a folder in CRX.  Each node and its children and properties can be defined in a json file.

In the Sling-Initial-Content above, you will notice two entries for /etc/designs/my-sling-app.  One for the the /etc/designs/my-sling-app node itself (which is of type cq:Page) and another for the its child (jcr:content) and child nodes and properties of jcr:content.

The third plugin (maven-sling-plugin) is used to install the bundle to Apache Felix in the install phase of mvn execution.

That’s it.  Run mvn clean install from commandline and this will be installed on your local CQ5 instance and overwrite your OSGi bundle,  /apps/technomaven, and /etc/designs/my-sling-app folders in CRX.

The full package of the code above can be found here.  Enjoy.

– Sarwar Bhuiyan

Advertisements
How to develop/deploy CQ5 components/bundles using JUST an OSGi bundle

One thought on “How to develop/deploy CQ5 components/bundles using JUST an OSGi bundle

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s