Thursday, April 12, 2012

How to change package install behavior in CQ / WEM

Use case: Suppose you want to move some content using CQ package, from one instance to another instance. Now you want to have a behavior where content on destination don't get deleted if it is not there in source package.
In order to better understand the problem, Consider following example,
On source you have following structure
/content/.../en
/content/.../en/p1
/content/.../en/p2
/content/.../en/p3
/content/.../en/p5
And on destination you have following structure
/content/.../en
/content/.../en/p1
/content/.../en/p2
/content/.../en/p3
/content/.../en/p4
Now when you will create package using filter root as /content/.../en on source and deploy that package on destination, You would end up deleting node /content/.../en/p4 on destination, as it is not part of source package.

On package manager through UI there is no way you can specify what behavior you want for that package on destination (You want something similar to AC handling behavior). Here is something you can do to override this behavior.

Solution
Consider your package name as testPackage.zip
Then do following
mkdir foo
cd foo
cp testPackage.zip foo/
jar xvf testPackage.zip
cd META-INF/vault
vi filter.xml
Add this to root def <filter root="/content" mode="merge">
cd ../..
jar -cvfM <New Package Name> META-INF/ jcr_root/
Now free to use <New Package> with new behavior

There are three Mode available,
1) replace: Normal behavior. Existing content is replaced completly by the imported content, i.e. is overridden or deleted accordingly.
2) merge: Existing content is not modified, i.e. only new content is added and none is deleted or modified
3) update: Existing content is only updated but never deleted

If you are using API to make changes then it is available here com.day.jcr.vault.fs.api.ImportMode

Well .. If you see you just created a package using file system content using simple Java package tool. Yes you can absolutely do that as long as you maintain directory structure of package i.e. you need to have following files in package (Take an example from any existing package created using package manager)

|-- META-INF/
| `-- vault/
| |-- config.xml
| |-- settings.xml
| |-- filter.xml
| |-- properties.xml
`-- jcr_root/
.
.

filter.xml
contains a serialization of the filters defined in the filters node of the package in a default file vault manner.
properties.xml
contains additional package properties like creation date and user.
nodetypes.cnd
contains a cnd serialization of all nodetypes and transitive ones used in the package.
config.xml
contains the file vault config that was present when exporting.

If you are using maven build, You can use Day file Vault Maven plugin to create package as part of your maven deployment. Your pom.xml will have entry like this


<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"
>
<modelVersion>4.0.0</modelVersion>

<groupId>com.day.jcr.vault</groupId>
<artifactId>vault.test</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>content-package</packaging>

<name>Sample Content Package Project</name>
<description>
Project to test the Maven Vault Plugin functionality
</description>

<build>
<plugins>
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>maven-vault-plugin</artifactId>
<version>0.0.10</version>
<extensions>true</extensions>
</plugin>
</plugins>
</build>
</project>

If you want to create package using maven plug in you have to use resource, Something like


<build>
 <resources>

<resource>
<directory>${basedir}/src/main/content/META-INF</directory>
<targetPath>../vault-work/META-INF</targetPath>
</resource>
 <resource>
 <directory>${basedir}/jcr_root</directory>
 <targetPath>.</targetPath>
 <filtering>true</filtering>
 <includes>
<include>
</include>
 </includes>
  <excludes>
       <exclude>**/.vlt</exclude>
       <exclude>**/.vltignore</exclude>
       <exclude>**/.DS_Store</exclude>
       </excludes>
 </resource>
 </resources>

And then run mvn <goal>

Note that your packaging type should be content-package. End result would be CQ/CRX package with  all filters in resource section.


Note: In this case you have to manage both filter.xml (Under META-INF) and <resource> tag under pom.xml for filter definition. <resource> tag under pom.xml is used by maven valut plugin to include resource in content package and filter.xml is used by package manager to include resource. There is already a enhancement request to merge these two and scheduled by later release of vault plugin.


Here is some more info

http://ruben42.wordpress.com/2012/03/22/maven-vault-plugin/

http://ben-peter.com/blog/generating-aggregate-content-packages-for-crx/

Vault API in CQ can be found here: http://dev.day.com/docs/en/cq/current/javadoc/overview-summary.html

Special Thanks for tobias Bocanegra from Adobe for helping to understand some of stuff

9 comments:

  1. nice - I did not know that there is a merge option in the vault file format available.

    ReplyDelete
    Replies
    1. @Bros,

      Thanks for pointing that out. Actually there are three modes which I forgot to mention. I will update Doc.

      Delete
  2. Hi Yogesh,

    So I've been playing around with this, and it does look like the merge mode works as expected. However, if I create an update package (mode="update") then it behaves exactly like replace mode, that is, the default. This is using CQ 5.4.

    Have you successfully used the update mode ?

    Thanks,

    Jon.

    ReplyDelete
  3. Hi Yogesh,

    we are trying to change package installation behavior. but its not working

    we are having the data present in as the "nt:unstructured" nodes.

    when we try to use the update policy for the package installation. It is adding but deleting the node as well. as shown below in the logs.

    - /content/data
    - /content/data/Schedule
    - /content/data/Schedule/Series_1
    D /content/data/Schedule/Series_2
    D /content/data/Schedule/Series_3
    - /content/data/Schedule/Series_1/Seasons
    - /content/data/Schedule/Series_1/Seasons/Season_2012
    - /content/data/Schedule/Series_1/Seasons/Season_2012/Events
    D /content/data/Schedule/Series_1/Seasons/Season_2012/Predictions
    - /content/data/Schedule/Series_1/Seasons/Season_2012/Events/Kobolt Tools 400
    - /content/data/Schedule/Series_1/Seasons/Season_2012/Events/Kobolt Tools 400/Predictions
    U /content/data/Schedule/Series_1/Seasons/Season_2012/Events/Kobolt Tools 400/Predictions/FinishPosition
    A /content/data/Schedule/Series_1/Seasons/Season_2012/Events/Kobolt Tools 400/Predictions/FinishPosition1
    - /content/data/Schedule/Series_1/Seasons/Season_2012/Events/Kobolt Tools 400/Predictions/OddsWinning


    I have also tried the merge policy but it is also not working.

    Do you have any context in this.

    Thanks in advance.

    TK.

    ReplyDelete
    Replies
    1. Tosheer,

      You might have to create daycare ticket for this. I will decompile and check code of http://dev.day.com/docs/en/cq/current/javadoc/com/day/jcr/vault/fs/api/ImportMode.html when get time and let you know.

      Yogesh

      Delete
  4. Hi Yogesh,
    Can we have vault filter settings to modify only a particular property.
    Like:
    /apps/sampleApp/modify_this_property --> change only this property
    /apps/sampleApp/dont_modify_this_property
    How do I design filter.xml to include only "/apps/sampleApp/modify_this_property" property?

    ReplyDelete
    Replies
    1. Hello,

      "Update" filter type should work in this case. Only property which is changed will be updated.

      Other thing you could do, is exclude this property from filter definition.






      Yogesh

      Delete
  5. Hi Yogesh,

    I want to perform some task when the package installation has completed. Is there any possible way to know whether the package installation is complete or not? Are there any events available which listen to this or I'll have to override the CQ out of the box package manager APIs to achieve it.

    ReplyDelete
    Replies
    1. I think you can use Install Hook https://github.com/Netcentric/accesscontroltool/tree/develop/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/installhook

      Delete