Welcome to CQBlueprints - A resource for your Adobe CQ 5.4, 5.5, 5.6 and AEM6 projects. Get your CQ project on the right track.

CQ Package Install Hooks

Introduction

CQ Package Install Hooks are a great way to execute code to either prepare, follow or finish the installation of packages inside CQ. For example CQ uses it when installing the CQ content to finalize the Workflow installation etc.

ATTENTION: Packages with Install Hooks cannot be replicated in CQ 5.5 because of a class loading issue but it works perfectly on CQ 5.4.

Deployment Structure

Before going ahead I want to recap the correct placement of the Install Hook to make it work. These are the elements:

  •  Create a Install Hook JAR file containing:
  •  Install Hook Code (one class has to implement the InstallHook interface)
  •  META-INF/Manifest.mf’s main-class entry that has the fully qualified class name of the Install Hook
  •  Place that Install Hook JAR file inside the /META-INF/vault/hooks directory of you CQ Package

Project Setup

Our sample project is based on Maven build system and I use the Maven Antrun Plugin to copy the Install Hook into its place within the “cqpackage” module. The Maven Vault Plugin isn’t able to handle install hooks and so it must be added manually.
Inside the “cqpackage” module I used a trick to ensure that the install hook is built before the package by adding a dependency to the install hook.

The project setup is straight forward and coding as well but there are a few gotchas to consider:

  • When the Install Hook JAR file is copied into the vault-work directory you must make sure that filtering is set to false to avoid a corrupt JAR file
  • Logging inside the InstallHook did not work for me. The only way to get some feedback is to throw a PackageException
  •  A PackageException thrown during the PREPARE phase will terminate the installation whereas anywhere else it will continue
  •  There is no way (as far as I know) to figure out the node of the package that is installed
  •  The InstallHookProcessor will log when the Hook is installed and with what class

 

The project has 3 components:

  1. Parent POM in the root
  2. installHook module that contains the Install Hook project
  3. cqpackage module that contains the content of the CQ package which is empty for this project

Please download and extract the attached ZIP file to go through the rest of this article because only important parts are highlighted below.

The parent POM file has two import parts. First the header defines the project:

<parent>
   <groupId>com.cqblueprints</groupId>
   <artifactId>parent</artifactId>
   <version>3-SNAPSHOT</version>
</parent>

<groupId>com.cqblueprints.installHook</groupId>
<artifactId>installHookParent</artifactId>
<version>1.0.0</version>
<packaging>pom</packaging>

<name>${project.groupId} - ${project.artifactId}</name>

<description>
	Install Hook Parent.
</description>

The bottom part has the module listings:

<modules>
   <module>installHook</module>
   <module>cqpackage</module>
</modules>

The installHook project POM file is a simple JAR build project but it needs to set the Manifest’s main-class to our install hook class and it must copy the JAR file into the CQ packages’s content/META-INF/vault/hooks directory:

<plugin>
   <groupId>org.apache.maven.plugins</groupId>
   <artifactId>maven-jar-plugin</artifactId>
   <configuration>
       <archive>
           <manifest>
               <mainClass>
                    com.cqblueprints.installHook.MyInstallHook
               </mainClass>
               <addClasspath>true</addClasspath>
           </manifest>
       </archive>
   </configuration>
</plugin>
<plugin>
   <artifactId>maven-antrun-plugin</artifactId>
   <executions>
      <execution>
           <id>install</id>
           <phase>install</phase>
           <configuration>
               <tasks>
                   <echo message=
   "Copying the Install Hook into the CQ Package" />
                   <copy file="${project.build.directory}/${project.artifactId}-${project.version}.jar" todir="${basedir}/../cqpackage/src/main/content/META-INF/vault/hooks"/>
               </tasks>
           </configuration>
           <goals>
               <goal>run</goal>
           </goals>
       </execution>
   </executions>
</plugin>

Finally the InstallHook class does nothing but throwing Package Exception to report the progress as logging fails to work:

package com.cqblueprints.installHook;

import com.day.jcr.vault.packaging.InstallContext;
import com.day.jcr.vault.packaging.InstallHook;
import com.day.jcr.vault.packaging.PackageException;

public class MyInstallHook implements InstallHook{

  public void execute(InstallContext ctx) throws PackageException{
   
     try {
		switch(ctx.getPhase()){
       
		case END:
          throw new PackageException(
              "Hit the END Phase, do my magic"
          );
		
		case PREPARE:
			break;
		
		default:
          throw new PackageException(
              "Reached phase: " + ctx.getPhase()
          );
      }
    }
   catch( PackageException e ) {
      throw e;
    }
   catch( Exception e ) {
      throw new IllegalStateException( e );
    }
  }
}

The “cqpackage” POM file is a pretty straight forward CQ Package Maven build project with the little trick to make sure that the install hook is built first by adding it as dependency:

<dependencies>
	<!-- This makes sure that the install hookproject is built first -->
	<dependency>
		<groupId>${project.groupId}</groupId>
		<artifactId>install-hook</artifactId>
		<version>${project.version}</version>
	</dependency>
</dependencies>

Just to recap please make sure that the resources are copied with filtering off otherwise the JAR file of the Install Hook becomes corrupt. If you need to filter then setup two resource copy plugin instructions:

<plugin>
	<groupId>org.apache.maven.plugins</groupId>
	<artifactId>maven-resources-plugin</artifactId>
	<executions>
		<execution>
			<id>copy-content-resources</id>
			<phase>process-resources</phase>
			<goals>
				<goal>copy-resources</goal>
			</goals>
			<configuration>
				<outputDirectory>
                    ${project.build.directory}/vault-work
				</outputDirectory>
				<resources>
					<resource>
						<directory>
                            ${basedir}/src/main/content
						</directory>
						<filtering>false</filtering>
					</resource>
				</resources>
			</configuration>
		</execution>
	</executions>
</plugin>

Finally to built the project just go to the parent POM and build it with:

     mvn clean install

The CQ error log should print the Package Exceptions so that you can follow the installation.{{/code}}


Do you find the information on this site useful? Do you think we should add an article on a specific subject? We'd like to hear from you. Please drop us an email @ info@headwire.com

Search CQ Related Information