Features I Like About CQ5 - Content Packages

In this blog series, I will point out some not so well known features of CQ5 and how to put them to use in your projects. This article is a longer one, but well worth reading.

Agreed, the content packages aren't really 'not so well known'. At least I hope. But they definitely are great, although sometimes tricky. I put a small article together for our internal training and knowledge base material, and I'll just republish it. Thanks a lot to Konrad Windszus and Santiago Pimentel for correcting and extending! Here we go.

What is a CRX package?

A CRX package is used to package up arbitrary content from a CRX repository. 'Packaging up' in this case means that you can select branches inside the content repositories which is then added to a file downloadable from the repository. That file can be uploaded to any instance and the content contained therein can be installed.

By this, you can easily backup content and copy it to any instance. And as CQ5 goes: Everything is content, therefore you can put users, configurations, code, binaries, content and anything else into those packages.

The file itself is a zip file, so you can even unpack it and review the content offline.

CRX Package Manager

The CRX Package Manager is the interface provided by CRX / CQ5 to manage and upload your packages. It is available at http://localhost:4502/crx/packmgr/index.jsp (given your instance is running at localhost port 4502).

The interface should be pretty intuitive; with the search options to the left and the packages mapping to those settings to the right. If you click on a package, you get some information and can perform actions:

The most important actions are:

Package definitions

The main part of a package definition are the filter definitions:

Using the filter definitions it is possible to define which parts of the repository are included into the package.

Each filter consists of one path, which makes the package include all the content below that path, and a list of rules. A rule allows to define that some content below the path should be excluded or included; which content that is is defined by a globbing, i.e. you can define for example to exclude certain nodes which have some name by using an exclude globbing like .*/name(/.*)? It is important to know that this globbing is always mapped against the entire path, not starting from the path defined. If you start with an include rule, you define a white-listing approach, i.e. everything else is explicitly excluded. If you use an exclude as first rule, a black-listing approach is used, i.e. everything is added in but the excluded parts. It is very tricky to mix those two types of rules up, so better don't do it.

To further complicate things with the rules: They actually change the traversal behaviour. The typical pitfall is to have include rules for pages deeper down in the hierarchy only. This implicitly defines an exclude for all, and as no page is traversed if it is excluded, the included pages are not even considered. Enjoy your empty package.

Most of the other information is beautification, like title, description, thumbnail and so on.

Within the advanced tab of the package there are some functional settings, though:

How packages are used

The packages definitely are a developer’s tool, but a very powerful one.

Obviously, packages are pretty handy to manually copy some example content from one instance to another, or to create a backup if you want to play around with the content a bit.

But there's more to packages, but let's first highlight two more features of packages:

Using packages with maven

These two capabilities enable us to use packages for code deployment: An hierarchical structure reflecting the project setup is available via contained packages, and code implemented as bundles gets deployed in the install folder. That's what happens if you execute your maven build targets: The packaging 'bundle' generates an OSGi bundle, and the packaging 'war' list the content-package-maven-plugin as used plugin, therefore with the build two different artifacts get generated: the WAR file (only there to make Eclipse happy, as Eclipse does not know anything about content-packages) and the content-package itself.

Now it should be pretty obvious what the 'package.root' property in the pom.xml represents: It's the definition of the filter for the package. But a property is single value, while a list of filters may be required. These additional filters can be set up in the plugin configuration:

<configuration>
<filters combine.children="append">
<filter>
<root>/a/second/path</root>
</filter>
</filters>
</configuration>

More information regarding the content-package-maven-plugin can be found in http://dev.day.com/docs/en/cq/current/core/how\\_to/how\\_to\\_use\\_the\\_vlttool/vlt-mavenplugin.html

Whenever you change something about the filter rules in your pom (either implicitly by adapting the package.* properties or by setting something within the plugin configuration, you have to do a maven clean, otherwise the changes will not be applied!

Dependencies to bundle projects can be embedded into the install folder of the final package by adding an <embeddeds> configuration. To this end, the target location (i.e. the path to the install folder) has to be defined as a <target> in the configuration of the content-package-maven-plugin. You also need to define the group-id, and you may define artifact-ids. The nice thing about it is the maven inheritance: The configuration of the embeddeds is inherited, and the group-id is automatically updated to the current group-id. So, you set the embeddeds definition up only once in your parent project pointing to the parent group-id; and then all bundles with the same group-id get embedded automatically into the folder defined in the parent package. To see how it works, just have a short look at the Effective POM of your local pom.xml. If you need to add multiple embeddeds configurations, be sure to give them unique names though.

Short example:

<configuration>
<embeddeds>
<embedded1>
<groupId>your-groupid-1</groupId>
<artifactId>your.artifact.id.1</artifactId>
<target>/apps/project/install</target>
</embedded1>
<embedded2>
<groupId>your-groupid-2</groupId>
<artifactId>your.artifact.id.2</artifactId>
<target>/apps/project/install</target>
</embedded2>
</embeddeds>
</configuration>

How content gets merged

By default during installation of a package, the content existing in the corresponding paths in the content repository is removed first. As a second step, new content contained in the package and allowed by the filter is added. That installation mode is called "replace". You can use this mode to remove things with a package, by including an appropriate filter but not adding any actual content to the package.

You can influence the merge behaviour of new content and old content within the maven-content-package-plugin with the help of the element mode (sibling of element root within a filter) which can be either "replace", "merge" or "update". "replace" is the default as described above (unfortunately there is a bug in CQ 5.5 before Update 1, which made "merge" the default merging behaviour). Using "merge", the installation will never touch existing nodes, and only add new nodes. The "update" updates but doesn't remove existing nodes.

If some of the content is not covered by the filter rules but part of the project code (e.g. because you forget an additional filter rule), this content also will be installed in the "merge" mode. So if you come upon strange duplications of nodes in the repository upon installing you project via maven, make sure all the paths of the code are actuall

Package share

Finally, there is the package share. The package share is like an apps store for packages, provided by Adobe. Actually, it is not used by many, as CQ5 is not as wide spread as music or casual games. Not many companies have identified business models around the package share (e.g. by providing the integration to a webservice like translations.com for free, but having a fee on the actual usage of that service). And there are also some hotfixes, feature packs (hybris integration, language packs) and patches available for download from the package share.

Aside from that, there is no real community around the package share yet.