How to Build AEM Projects using Apache Maven

How to Build AEM Projects using Apache Maven
How to Build AEM Projects using Apache
Maven
Overview / CQ / AEM How-tos / Development /
This document describes how to set up an AEM project based on Apache Maven.
Apache Maven is an open source tool for managing software projects by automating builds and providing
quality project information. It is the recommended build management tool for AEM projects.
BENEFITS
Building your AEM Project based on Maven offers you several benefits:
• An IDE-agnostic development environment
• Usage of Maven Archetypes and Artifacts provided by Adobe
• Usage of Apache Sling and Apache Felix tool sets for Maven based development setups
• Ease of import into an IDE; for example, Eclipse and/or IntelliJ
• Easy integration with Continuous Integration Systems
PREREQUISITES
To set up a development environment based on Maven (as described in this guide) the following software
must be installed before starting:
• Apache Maven 3.0.4 or higher
• Oracle Java SE 1.5.x or higher
• CQ5.5, AEM 5.6 or higher
NOTE
This guide is based on Apache Maven 3.0.4 and AEM 5.6.1
Overview
This section offers you
• a quick introduction on how to set up your first Maven based AEM project within minutes using an Adobe
provided Maven archetype in Getting started in 5 Minutes
• a more detailed discussion of the project strutcture that the archetype creates in Detailed Maven Setup
for AEM Projects
• a guideline of the most important goals and profiles in your maven project in Typical Steps in a
Development Cycle
• A set of How-Tos for Common Tasks when developing AEM projects with Maven
Getting Started in 5 Minutes
The following instructions give you a working AEM project using a Maven build in just a few minutes by using
an Adobe provided Maven Archetype.
This section assumes that
• AEM is up and running on http://localhost:4502/
• Java 1.5 or greater and Maven 3.0.4 or greater are installed
• you are connected to the internet
1.
Create the initial structure from Adobe's multimodule-content-package-archetype
In your shell, go to a directory where your project is supposed to be created.
In the following example, line breaks are only to make reading simpler. Everything goes on one line.
$ mvn archetype:generate \
-DarchetypeRepository=http://repo.adobe.com/nexus/content/groups/public/ \
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 1
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
-DarchetypeGroupId=com.day.jcr.vault \
-DarchetypeArtifactId=multimodule-content-package-archetype \
-DarchetypeVersion=1.0.2 \
-DgroupId=my-group-id \
-DartifactId=myproject \
-Dversion=1.0-SNAPSHOT \
-Dpackage=com.mycompany.myproject \
-DappsFolderName=myproject \
-DartifactName="My Project" \
-DcqVersion="5.6.1" \
-DpackageGroup="My Company"
2.
Confirm the provided values by entering "Y" and hitting Return when Maven asks.
Confirm properties configuration:
groupId: my-group-id
artifactId: myproject
version: 1.0-SNAPSHOT
package: com.mycompany.myproject
appsFolderName: myproject
artifactName: My Project
cqVersion: 5.6.1
packageGroup: My Company
Y: :
3.
Maven has created a directory for the project. Change into it:
# cd myproject
4.
Now build the project and install it into your AEM instance.
# mvn -PautoInstallPackage install
You now have a Maven managed AEM project with a bundle module for any OSGi Components and a
content module for your components, templates, design pages, etc. The sections below further explain the
setup of the project, useful goals and common tasks.
Detailed Maven Setup for AEM Projects
OVERVIEW OF THE PROJECT STRUCTURE
Developing a CQ project usually requires you to create both user interface components and OSGI services;
these are divided into two Maven projects.
You also need to create a build reactor and parent Maven project to store shared configuration information;
this makes it easier to maintain.
As a result the following hierarchy is used for the project files:
• myproject - root folder
• content - project folder holding UI resources
• bundle - project folder containing the OSGI services
• pom.xml - the Maven reactor and parent project file
CREATING THE PROJECT STRUCTURE
Adobe provide Maven Archetypes to make setup of new projects easier for you. These are documented
here.
We will use the multimodule-content-package-archetype to create an initial structure for our maven project.
In the following example, line breaks are only to make reading simpler. Everything goes on one line.
mvn -Padobe-public archetype:generate \
-DarchetypeRepository=http://repo.adobe.com/nexus/content/groups/public/ \
-DarchetypeGroupId=com.day.jcr.vault \
-DarchetypeArtifactId=multimodule-content-package-archetype \
-DarchetypeVersion=1.0.2
Maven will now ask you to fill in some variables. The examples on this page use the values shown below.
Define
Define
Define
Define
Define
Define
Define
value
value
value
value
value
value
value
for
for
for
for
for
for
for
property
property
property
property
property
property
property
© 2012 Adobe Systems Incorporated.
All rights reserved.
'groupId': : group-id
'artifactId': : myproject
'version': 1.0-SNAPSHOT: : 1.0-SNAPSHOT
'package': group-id: : com.mycompany.myproject
'appsFolderName': : myproject
'artifactName': : My Project
'cqVersion': 5.6.1: : 5.6.1
Page 2
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
Define value for property 'packageGroup': : My Company
THE REACTOR AND PARENT POM FILE
The reactor and parent POM file serves several purposes:
1. it defines common dependencies for all modules in the project
2. it provides the setup for build plugins
3. it defines common profiles to use for the build process
4. it defines properties that are used in several plugins (such as the host, port, username and password)
5. if desired, it can be used to define project specific maven repositories, such as the Adobe public
repository
6. as the build reactor, it lists out all modules that are part of the project (content and bundle in our
example)
The archetype has created the following project definition for us.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/mavenv4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ====================================================================== -->
<!-- P A R E N T P R O J E C T D E S C R I P T I O N -->
<!-- ====================================================================== -->
<groupId>my-group-id</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>pom</packaging>
<name>My Project - Reactor Project</name>
<description>Maven Multimodule project for My Project.</description>
<prerequisites>
<maven>3.0.2</maven>
</prerequisites>
<!-- ====================================================================== -->
<!-- P R O P E R T I E S -->
<!-- ====================================================================== -->
<properties>
<crx.host>localhost</crx.host>
<crx.port>4502</crx.port>
<crx.username>admin</crx.username>
<crx.password>admin</crx.password>
<publish.crx.host>localhost</publish.crx.host>
<publish.crx.port>4503</publish.crx.port>
<publish.crx.username>admin</publish.crx.username>
<publish.crx.password>admin</publish.crx.password>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
<version>4.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 3
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
<dependency>
<groupId>biz.aQute</groupId>
<artifactId>bndlib</artifactId>
<version>1.43.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.5</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
<version>2.2.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.jcr.api</artifactId>
<version>2.1.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
<!-Inclusion of repositories in POMs is controversial, to say the least.
It would be best if you proxied the Adobe repository using a Maven
Repository Manager. Once you do that, remove these sections.
-->
<repositories>
<repository>
<id>adobe</id>
<name>Adobe Public Repository</name>
<url>http://repo.adobe.com/nexus/content/groups/public/</url>
<layout>default</layout>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>adobe</id>
<name>Adobe Public Repository</name>
<url>http://repo.adobe.com/nexus/content/groups/public/</url>
<layout>default</layout>
</pluginRepository>
</pluginRepositories>
<build>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.7.4</version>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 4
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.3.7</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.6</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.7</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.4</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.14.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9</version>
</plugin>
<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-sling-plugin</artifactId>
<version>2.1.0</version>
<configuration>
<username>${crx.username}</username>
<password>${crx.password}</password>
</configuration>
</plugin>
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<version>0.0.20</version>
<extensions>true</extensions>
<configuration>
<failOnError>true</failOnError>
<username>${crx.username}</username>
<password>${crx.password}</password>
</configuration>
</plugin>
<!--This plugin's configuration is used to store Eclipse
m2e settings only. It has no influence on the Maven build itself. -->
<plugin>
<groupId>org.eclipse.m2e</groupId>
<artifactId>lifecycle-mapping</artifactId>
<version>1.0.0</version>
<configuration>
<lifecycleMappingMetadata>
<pluginExecutions>
<pluginExecution>
<pluginExecutionFilter>
<groupId>
org.apache.felix
</groupId>
<artifactId>
maven-scr-plugin
</artifactId>
<versionRange>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 5
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
[1.0.0,)
</versionRange>
<goals>
<goal>scr</goal>
</goals>
</pluginExecutionFilter>
<action>
<ignore/>
</action>
</pluginExecution>
</pluginExecutions>
</lifecycleMappingMetadata>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
<profiles>
<profile>
<id>autoInstallBundle</id>
<build>
<plugins>
<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-sling-plugin</artifactId>
<executions>
<execution>
<id>install-bundle</id>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
<modules>
<module>bundle</module>
<module>content</module>
</modules>
</project>
NOTE
A note on the archetype's statement regarding repository inclusion in the POM:
The archetype produces a self-contained setup which gets you started quickly. As you set up
the tooling for your development process, you may choose to work with only a single repository
manager which transparently proxies any required repositories (including repo.adobe.com).
THE BUNDLE MODULE
The bundle module is set up to contain OSGi Services required in your project.
Note that depending on the complexity of your project, you may want to refine this setup and create separate
modules for individual areas of your project. For example, it is common to have a separate bundle for the
project specific tag library, and to separate infrastrutural components (loggers, filters, login modules, etc)
from business components (workflow steps, live action factories, content builders and transport handlers,
etc).
The following structure has been created by the Maven archetype.
.
### pom.xml
### src
### main
#
### java
#
### com
#
### mycompany
#
### myproject
#
### HelloService.java
#
### impl
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 6
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
#
#
### HelloServiceImpl.java
#
#
### filters
#
#
### LoggingFilter.java
#
### package-info.java
### test
### java
### com
### mycompany
### myproject
### SimpleUnitTest.java
Below is the POM file generated by the Maven archetype.
It configures the following plugins:
• The maven-scr-plugin to generate SCR descriptors from Annotations (see the Apache Felix
Project's Apache Felix Maven SCR Plugin page for details of this plugin)
• The maven-bundle-plugin to define the symbolic name of the OSGi bundle created in the project (see the
Apache Felix Project's Apache Felix Bundle Plugin for Maven page for other options of this plugin)
• The maven-sling-plugin plugin to allow direct installation of the bundle into AEM using the sling:install
goal. See the Apache Sling Project's Maven Sling Plugin page for more details on this plugin.
• The maven-javadoc-plugin is configured to exclude any classes with "impl" in their package name from
the generated Documentation. This is because the maven-bundle-plugin will by default exclude any
packages that are called impl from the Export-Packages header in the Manifest.
• Note that the packaging for the module is set to "bundle". This is provided by the Apache Felix Bundle
Plugin for Maven.
The remainder of the POM defines common dependencies for AEM projects, some of which are used in the
sample classes that come with the archetype.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd
">
<modelVersion>4.0.0</modelVersion>
<!-- ====================================================================== -->
<!-- P A R E N T P R O J E C T D E S C R I P T I O N -->
<!-- ====================================================================== -->
<parent>
<groupId>my-group-id</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
</parent>
<!-- ====================================================================== -->
<!-- P R O J E C T D E S C R I P T I O N -->
<!-- ====================================================================== -->
<artifactId>myproject-bundle</artifactId>
<packaging>bundle</packaging>
<name>My Project Bundle</name>
<dependencies>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.compendium</artifactId>
</dependency>
<dependency>
<groupId>org.osgi</groupId>
<artifactId>org.osgi.core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
</dependency>
<dependency>
<groupId>biz.aQute</groupId>
<artifactId>bndlib</artifactId>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<dependency>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 7
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
</dependency>
<dependency>
<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.jcr.api</artifactId>
</dependency>
</dependencies>
<!-- ====================================================================== -->
<!-- B U I L D D E F I N I T I O N -->
<!-- ====================================================================== -->
<build>
<plugins>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<executions>
<execution>
<id>generate-scr-descriptor</id>
<goals>
<goal>scr</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<Bundle-SymbolicName>my-group-id.myproject-bundle</Bundle-SymbolicName>
</instructions>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-sling-plugin</artifactId>
<configuration>
<slingUrl>http://${crx.host}:${crx.port}/apps/myproject/install</slingUrl>
<usePut>true</usePut>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<configuration>
<excludePackageNames>
*.impl
</excludePackageNames>
</configuration>
</plugin>
</plugins>
</build>
</project>
THE CONTENT MODULE
The content module is set up to build an AEM content package which combines
• components
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 8
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
• templates
• configurations
• sample content
• the OSGi bundle that is built by the bundle module
The archetype provides the structure below. As you can see, it deviates a little from a standard Maven Java
module as there are no Java sources in the context of a content module. Accordingly, the module contains a
directory src/main/content.
NOTE
As with the bundle module, it is common to create separate modules depending on the complexity
of your project. In particular, sample content and configurations are often provided through
separate Maven module and corresponding packages, so that they can be managed and installed
separately.
.
### pom.xml
### src
### main
### content
### META-INF
#
### vault
#
### config.xml
#
### definition
#
#
### .content.xml
#
### filter.xml
#
### nodetypes.cnd
#
### properties.xml
### jcr_root
### apps
### myproject
### config
#
### put-your-configs-here.txt
### install
### .vltignore
### bundle-will-go-here.txt
The POM generated by the archetype has a couple of noteworthy points.
1. It uses a packaging of content-package (line 20), which is provided by the content-package-mavenplugin
2. The content-package-maven-plugin is configured to embed the OSGi bundle at /apps/myproject/install
(lines 59-61), (where Apache Sling's JCR Installer Provider will pick it up and install it with the OSGi
Installer)
3. It is also configured to install the package at the host and port configured in the parent pom (line 64)
4. By default, the content-package-maven-plugin uses the project's resources definition, which is set up in
lines 30-39.
Depending on your other development tools, you may want to exclude more files, such as .git, .project
etc.
5. A profile autoInstallPackage is defined, which binds the content-package-maven-plugin's install goal to
Maven's install phase. This profile allows you to automatically install the package to AEM after it has
been built.
6. A profile autoInstallPackagePublish is defined, which does the same for a publish server
NOTE
The content-package-maven-plugin is documented on the Managing Packages using Maven
page.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchemainstance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<!-- ====================================================================== -->
<!-- P A R E N T P R O J E C T D E S C R I P T I O N -->
<!-- ====================================================================== -->
<parent>
<groupId>my-group-id</groupId>
<artifactId>myproject</artifactId>
<version>1.0-SNAPSHOT</version>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 9
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
</parent>
<!-- ====================================================================== -->
<!-- P R O J E C T D E S C R I P T I O N -->
<!-- ====================================================================== -->
<artifactId>myproject-content</artifactId>
<packaging>content-package</packaging>
<name>My Project Package</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>myproject-bundle</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<resources>
<resource>
<directory>src/main/content/jcr_root</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/.vlt</exclude>
<exclude>**/.vltignore</exclude>
</excludes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<includeEmptyDirs>true</includeEmptyDirs>
</configuration>
</plugin>
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<group>My Company</group>
<filterSource>src/main/content/META-INF/vault/filter.xml</filterSource>
<embeddeds>
<embedded>
<groupId>${project.groupId}</groupId>
<artifactId>myproject-bundle</artifactId>
<target>/apps/myproject/install</target>
</embedded>
</embeddeds>
<targetURL>http://${crx.host}:${crx.port}/crx/packmgr/service.jsp</targetURL>
</configuration>
</plugin>
</plugins>
</build>
<profiles>
<profile>
<id>autoInstallPackage</id>
<build>
<plugins>
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<executions>
<execution>
<id>install-content-package</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
</execution>
</executions>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 10
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>autoInstallPackagePublish</id>
<build>
<plugins>
<plugin>
<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<executions>
<execution>
<id>install-content-package-publish</id>
<phase>install</phase>
<goals>
<goal>install</goal>
</goals>
<configuration>
<targetURL>http://${publish.crx.host}:${publish.crx.port}/crx/
packmgr/service.jsp</targetURL>
<username>${publish.crx.username}</username>
<password>${publish.crx.password}</password>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
</project>
Typical Steps in a Development Cycle
This section explains the basic AEM Development round-trip and the tasks involved.
CONTENT PACKAGE DEVELOPMENT TASKS
The typical development cycle for your content package is to
1. make changes to the project, either on the filesystem or in the repository
2. run mvn -PautoInstallPackage clean install to deploy the package to the repository
Making Changes to the Project
You can make changes to the content/ project in two ways:
1. Make changes below content/src/main/content/jcr_root and deploy them to the repository
2. Make changes in the repository and use the vlt tool to sync them back to the filesystem
See the How to use the VLT Tool page for detailed instructions on working with VLT to keep the file system
and the repository synchronized. The basic steps for setting this up are
• install the package to your repository
• cd to content/src/main/content/jcr_root
• run vlt co --force http://localhost:4502/ -- this will check out the content from the repository into your
filesystem and set up vlt to keep track
• run vlt sync install -- this will install the vlt sync service into your repository if not already available
• run vlt sync register -- this will register this project's directory with the vlt sync service
Once this initial setup has been performed, perform the following action based on the changes you made:
• changes to an nt:file in the repository (including creation and removal of files): no action required (the
vlt sync service will synchronize that change to the file system)
• changes to a file on the file system (including creation and removal of files): no action required (the vlt
sync service will synchronize that change to the repository)
• changes to other content in the repository: vlt up to update the filesystem with the changes in the
repository
• changes to .content.xml files on the filesystem: vlt ci to check the filesystem changes in to the
repository
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 11
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
mvn -PautoInstallPackage clean install
Running mvn -PautoInstallPackage clean install will
• build the content package according to the definition in myproject/content/pom.xml and save that
package to content/target/myproject-content-1.0-SNAPSHOT.zip
• install the package into your local maven repository (that is what Maven's "install" phase always does)
• activate the autoInstallPackage profile of the content module, which binds the content-package-mavenplugin:install goal to the install phase and so installs the package into AEM through the Package
Manager's HTTP API. See the documentation of the Content Package Maven Plugin for details.
NOTE
The first time you run this, you need to run it from the top level directory of the project, as the
content module requires the bundle.
After that, you can run it from either the top level directory or from the content/ directory.
NOTE
It is recommended to always clean the project before building the content package again, as
otherwise files that have since been removed will still be contained in the content package that
is built from the content/target/vault-work directory where they have been copied by the contentpackage-maven-plugin before.
NOTE
If you are using vlt sync, add the following exclusions to the resources section of your POM:
<resources>
<resource>
<directory>src/main/content/jcr_root</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/.vlt</exclude>
<exclude>**/.vltignore</exclude>
<exclude>**/.vlt-sync.log</exclude>
<exclude>**/.vlt-sync-config.properties</exclude>
</excludes>
</resource>
</resources>
BUNDLE DEVELOPMENT TASKS
The bundle module follows a standard Java setup, and so does the process:
1. make changes to your Java sources
2. run mvn -PautoInstallBundle install in the bundle/ directory to compile and deploy the bundle
NOTE
mvn -PautoInstallBundle install only succeeds after the package has been installed at least once,
as it requires the path /apps/myproject/install to exist.
Common Tasks
HOW-TO ADD DEPENDENCIES
As your project evolves, you will be working with more dependencies than are included in the dependencies
that the archetype adds to your project initially.
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 12
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
Adding new dependencies involves the following steps
1. determine the Maven coordinates for the classes that you want to work with
2. add the corresponding dependency to the parent POM
3. reference the dependency in the correct Maven module
The following example shows how to add a dependency to the bundle module so that you can work with the
class com.day.cq.wcm.msm.api.LiveActionFactory
1.
Determine Maven Coordinates
To find the Maven coordinates for a class or package, you can use the Web Console's "Packages"
screen at http://<host>:<port>/system/console/depfinder.
Enter com.day.cq.wcm.msm.api into the "Packages / Classes" input field and click "Find". The Web
Console will provide an XML fragment that can be used with Maven as shown in the screen below.
2.
Add the Dependency to the Parent POM
Use the XML fragment from the Web Console and add it to the <dependencies> list in the
<dependenyManagement> section of the parent POM (i.e. in myproject/pom.xml).
<dependencyManagement>
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-msm-api</artifactId>
<version>5.6.2</version>
<scope>provided</scope>
</dependency>
<!-- ... -->
</dependencies>
</dependencyManagement>
3.
Reference the Dependency in the bundle Module
Now you can add the dependency to the bundle module's <dependencies> list. You do not need to
repeat <version> and <scope>, as these are derived from the definition in the parent POM.
After that, you can use LiveActionFactory in your code.
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-msm-api</artifactId>
</dependency>
<!-- ... -->
</dependencies>
Importing AEM Product Dependencies
If you are working with CQ 5.5 or AEM 5.6, you can also use Maven's dependency import to add all AEM
product dependencies to your project.
This saves you the step of adding the full Maven coordinates for all dependencies to the parent POM, and
you only need to add dependencies to the modules stating their groupId and artifactId.
1.
Add the following XML fragment to the parent POM's <dependencies> list in the
<dependencyManagement> section.
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 13
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
The <scope>import</scope> in line 10 will import the dependencies listed in the
<dependencyManagement> section of com.day.cq:cq-quickstart-product-dependencies:5.6.1 to the
parent POM, so that you no longer need to add each individual dependency yourself.
<dependencyManagement>
<dependencies>
<!-- ... -->
<dependency>
<!-- use com.day.cq.wcm as groupId if you are using an AEM version previous to 5.5
-->
<groupId>com.day.cq</groupId>
<artifactId>cq-quickstart-product-dependencies</artifactId>
<version>5.6.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- ... -->
</dependencies>
</dependencyManagement>
2.
3.
Adjust the AEM version you are working with (lines 6, 7 and 8 in the example above). The following
table shows the Apache Maven GAV coordinates to use for each CQ / AEM version.
Version
GAV
AEM 5.6.1
com.day.cq:cq-quickstart-productdependencies:5.6.1
AEM 5.6
com.day.cq:cq-quickstart-productdependencies:5.6.0
CQ 5.5
com.day.cq:cq-quickstart-productdependencies:5.5.0
CQ 5.4
com.day.cq.wcm:cq-quickstart-productdependencies:5.4.0
CQ 5.3
com.day.cq.wcm:cq-quickstart-productdependencies:5.3.0
You still need to add the dependency to module you are using it in as described above:
<dependencies>
<!-- ... -->
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-msm-api</artifactId>
</dependency>
<!-- ... -->
</dependencies>
HOW-TO ADD PATHS TO THE CONTENT MODULE
The content module contains a file src/main/content/META-INF/vault/filter.xml which defines the filters for the
AEM package that is built by Maven. The file that is created by the Maven archetype looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/apps/myproject"/>
</workspaceFilter>
This file is used in a number of different ways:
• by the content-package-maven-plugin to determine which content to include in the package
• by the VLT tool to determine which paths to consider
• if the package is re-built in AEM Package Manager, this also defines which paths to include
Depending on your application's requirements, you may want to add to these paths to include more content,
such as:
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 14
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
• Rollout Configurations
• Blueprints
• Workflow Models
• Design Pages
• Sample Content
To add to the paths, add more <filter> elements:
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/apps/myproject"/>
<filter root="/etc/msm/rolloutconfigs/myrolloutconfig"/>
<filter root="/etc/blueprints/mysite/globalsite"/>
<filter root="/etc/workflow/models/myproject"/>
<filter root="/etc/designs/myproject"/>
<filter root="/content/myproject/sample-content"/>
</workspaceFilter>
Adding Paths to the Package Without Syncing Them
If you have files that should be added to the package that is built by the content-package-maven-plugin but
that should not be synchronized between the file system and the repository, you can use .vltignore files.
These files have the same syntax as .gitignore files.
For example, the archetype uses a .vltignore file to prevent the JAR file that is installed as part of the bundle
from being synced back to the file system:
*.jar
Syncing Paths Without Adding Them to the Package
In some cases, you may want to keep particular paths synchronized between the file system and the
repository, but not have them included in the package that is built to be installed into AEM.
A typical case is the /libs/foundation path. For development purposes, you may want to have the contents of
this path available in your file system, so that e.g. your IDE can resolve JSP inclusions that include JSPs in /
libs. However, you don't want to include that part in the package you build, as the /libs part contains product
code that must not be modified by custom implementations.
To achieve this, you can provide a file src/main/content/META-INF/vault/filter-vlt.xml. If this file exists, it will
be used by the VLT tool, e.g. when you perform vlt up and vlt ci, or when you have set vlt sync set up. The
content-package-maven-plugin will continue to use the file src/main/content/META-INF/vault/filter.xml when
creating the package.
For example, to make /libs/foundation available locally for development, but only include /apps/myproject in
the package, use the following two files.
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/apps/myproject"/>
</workspaceFilter>
<?xml version="1.0" encoding="UTF-8"?>
<workspaceFilter version="1.0">
<filter root="/libs/foundation"/>
<filter root="/apps/myproject"/>
</workspaceFilter>
You will also need to reconfigure the maven-resources-plugin to not include these files in the package: the
filter.xml file is not applied when the package is installed but only when the package is built again using
package manager.
Change the <resources> section in the content pom accoringly:
<!-- ... -->
<resources>
<resource>
<directory>src/main/content/jcr_root</directory>
<filtering>false</filtering>
<excludes>
<exclude>**/.vlt</exclude>
<exclude>**/.vltignore</exclude>
<exclude>libs/</exclude>
</excludes>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 15
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
</resource>
</resources>
<!-- ... -->
HOW-TO WORK WITH JSPS
The Maven setup described so far creates a content package that can also include components and their
corresponding JSPs. However, Maven treats them as any other file that is part of the content package and
does not even recognize them as JSPs.
The resulting components work in AEM all the same, but making Maven aware of the JSPs has two major
benefits
• it allows Maven to fail if the JSPs contain errors, so that these are surfaced at build time and not when
they are first compiled in AEM
• For IDEs that can import Maven projects, this also enables code completion and tag library support in
the JSPs
Two things are required to enable this setup:
1. add tag library dependencies
2. compile the JSPs as part of the Maven compile process
Adding Tag Library Dependencies
Below dependencies need to be added to the content modules's POM.
NOTE
Unless you are importing the product dependencies as described in Importing AEM Product
Dependencies above, they also need to be added to the parent POM along with the version
matching your AEM setup as described in Adding Dependencies above. The comments in each
entry below show the package to search for in the Dependency Finder.
NOTE
The com.adobe.granite.xssprotection artifact is not included in the cq-quickstart-productdependencies POM and requires full Maven coordinates as obtained from the Dependency
Finder.
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.jcr.jcr-wrapper</artifactId>
<!-- javax.jcr -->
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.api</artifactId>
</dependency>
<dependency>
<groupId>com.day.cq</groupId>
<artifactId>cq-commons</artifactId>
<!-- com.day.cq.commons -->
</dependency>
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-wcm-commons</artifactId>
<!-- com.day.cq.wcm.commons -->
</dependency>
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-wcm-api</artifactId>
<!-- com.day.cq.wcm.api -->
</dependency>
<dependency>
<groupId>com.day.commons</groupId>
<artifactId>day-commons-jstl</artifactId>
<!-- javax.servlet.jsp.jstl.core -->
</dependency>
<dependency>
<groupId>com.day.cq.wcm</groupId>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 16
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
<artifactId>cq-wcm-taglib</artifactId>
<!-- com.day.cq.wcm.tags -->
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.scripting.jsp.taglib</artifactId>
<!-- org.apache.sling.scripting.jsp.taglib -->
</dependency>
<dependency>
<groupId>com.adobe.granite</groupId>
<artifactId>com.adobe.granite.xssprotection</artifactId>
<!-- com.adobe.granite.xss -->
</dependency>
<dependency>
<groupId>com.day.cq.wcm</groupId>
<artifactId>cq-wcm-core</artifactId>
<!-- com.day.cq.wcm.core.components -->
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<!-- org.apache.commons.lang3 -->
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
Compiling JSPs as part of the Maven Compile Phase
To compile JSPs in Maven's compile phase, we use Apache Sling's Maven JspC Plugin as shown below:
• we set up an execution for the jspc goal (which by default binds to the compile phase, so we don't need
to specify the phase explicitly)
• we tell it to compile any JSPs in ${project.build.directory}/jsps-to-compile
• and output the result to ${project.build.directory}/ignoredjspc (which translates to myproject/content/
target/ignoredjspc)
• we set up maven-resources-plugin to copy the JSPs to ${project.build.directory}/jsps-to-compile in the
generate-sources phase and configure it to not copy the libs/ folder (because that is AEM product code
and we neither want to incur the dependencies for compilation for our project, nor do we need to validate
that it compiles.
Our primary goal, as stated above, is to validate the JSPs and make sure that the build process fails if they
contain errors. This is why we compile them to a separate directory that is ignored (and in fact immediately
deleted afterwards, as you will see in a minute).
The result of the Maven JspC Plugin can also be bundled and deployed as part of an OSGi Bundle, but this
has other implications and side effects and goes beyond our goal of validating the JSPs.
To achieve deletion of the classes compiled from the JSPs, we set up the Maven Clean Plugin as shown
below. If you want to inspect the result of the Maven JspC Plugin, run mvn compile in myproject/content -after that, you will find the result in myproject/content/target/ignoredjspc).
<build>
<!-- ... -->
<plugins>
<!-- ... -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>generate-sources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/jsps-to-compile</outputDirectory>
<resources>
<resource>
<directory>src/main/content/jcr_root</directory>
<excludes>
<exclude>libs/**</exclude>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 17
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
</excludes>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.sling</groupId>
<artifactId>maven-jspc-plugin</artifactId>
<version>2.0.6</version>
<executions>
<execution>
<id>compile-jsp</id>
<goals>
<goal>jspc</goal>
</goals>
<configuration>
<jasperClassDebugInfo>false</jasperClassDebugInfo>
<sourceDirectory>${project.build.directory}/jsps-to-compile</sourceDirectory>
<outputDirectory>${project.build.directory}/ignoredjspc</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-clean-plugin</artifactId>
<executions>
<execution>
<id>remove-compiled-jsps</id>
<goals>
<goal>clean</goal>
</goals>
<phase>process-classes</phase>
<configuration>
<excludeDefaultDirectories>true</excludeDefaultDirectories>
<filesets>
<fileset>
<directory>${project.build.directory}/jsps-to-compile</directory>
<directory>${project.build.directory}/ignoredjspc</directory>
</fileset>
</filesets>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
NOTE
Depending on whether you actually make use of JSP code in /libs (i.e. include JSPs from there),
you will need to refine which JSPs are copied for compilation.
E.g. if you include /libs/foundation/global.jsp, you can use the following configuration for the
maven-resources-plugin instead of the configuration above which completely skips over /libs.
<resource> <directory>src/main/content/jcr_root</directory> <includes>
<include>apps/
**</include>
<include>libs/foundation/global.jsp</include> </includes> </resource>
HOW-TO WORK WITH SCM SYSTEMS
When working with Source Configuration Management (SCM), you want to make sure that
• The VCS ignores non-source artifacts in the file system
• VLT ignores artifacts of the VCS and does not check them in to the repository
NOTE
This description does not cover how to configure Maven to work with your SCM, which
is described exhaustively in the Maven POM reference and the Maven SCM Plugin's
documentation.
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 18
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
Patterns to Exclude from SCM
The following is a typical list of patterns to include from SCM. E.g., if you are using git, you can add these to
your project's .gitignore file.
# Ignore VLT files
.vlt
.vlt-sync.log
.vlt-sync-config.properties
# Ignore Quickstart launches in the source tree
license.properties
crx-quickstart
# Ignore compilation results
target
# Ignore IDE and Operating System artifacts
.idea
.classpath
.metadata
.project
.settings
maven-eclipse.xml
*.iml
*.ipr
*.iws
.DS_Store
Ignoring SCM control files in VLT
In some cases, you may have SCM control files in the content source tree that you do not want to be
checked in to the repository.
Think of the following situation:
The archetype already created a .vltignore file to prevent the installed bundle jar file from being synced back
to the file system:
*.jar
Obviously, you do not want this file in your SCM either, so if e.g. you are using git, you would add a
corresponding .gitignore file:
*.jar
As the .gitignore file should not go into the repository either, the .vltignore file needs to be extended to
include the .gitignore file:
*.jar
.gitignore
HOW-TO WORK WITH DEPLOYMENT PROFILES
If your build process is part of a larger development lifecycle management setup, such as a continous
integration process, you often need to deploy to other machines than just the developer's local instance.
For such scenarios, you can easily add new Maven Build Profiles to the project's POM.
The example below adds a profile integrationServer, which redefines the host names and ports for the author
and publish instances. You can deploy to these servers by running maven from the project root as shown
below.
# install on integration test author
$ mvn -PautoInstallPackage -PintegrationServer install
# install on integration test publisher
$ mvn -PautoInstallPackagePublish -PintegrationServer install
<profiles>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 19
Created on 2014-09-05
How to Build AEM Projects using Apache Maven
<!-- ... -->
<profile>
<id>integrationServer</id>
<properties>
<crx.host>dev-author.intranet</crx.host>
<crx.port>5502</crx.port>
<publish.crx.host>dev-publish.intranet</publish.crx.host>
<publish.crx.port>5503</publish.crx.port>
</properties>
</profile>
</profiles>
© 2012 Adobe Systems Incorporated.
All rights reserved.
Page 20
Created on 2014-09-05