How to Build AEM Projects using Apache Maven
Transcription
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