May 13, 2020
Estimated Post Reading Time ~

Building an Application

The Basics
For the most basic application in AEM, there are 2 main pieces of code, the jcr:repository and the java code. To keep things clean we do create a few more projects so that each one has it's own distinct purpose.
The following code examples won't actually do much but I will try to discuss what they are meant to be doing and why I have built them the way I have. This will be far from an extensive and in-depth view of what can and can't be built with AEM.
Maven
While you can use any build tool to create and build an aem project, maven comes with plugins for deploying to AEM as well as setting up your packages with the right information. To create a project from scratch I tend to copy an existing one, however, you can create one with the maven archetype
Project Structure
The default structure from the archetype is slightly different from what I use and I will explain.
Maven project structure
As you can see there are not that many changes. The archetype creates it. launcher project with some basic sling base test classes which I have never used.
I also add a sling project for sling mappings, with a sub-project for each of the environments. While in normal practice you would just put the sling mappings in the ui.app project, if you are using reverse mappings in the sling then it will take the first mapping that matches the folder structure and return the address as that of the server defined. I also find it quite messy having an environment that has all of the sling mappings for all possible environments.
I also have an all project that allows me to package the entire application into a single deployment within AEM.
You will notice in the structure of the pages that I don't have a section to discuss the sling and all projects, as these are variations of the ui.apps project they will be discussed in the appropriate sections of the pages on ui.apps
I know using a project for configuration is probably a bit of overkill, but it leaves your servers in a cleaner state and only code that is really needed is unpacked.
pom.xml
Most of the pom.xml files are pretty standard, having a parent pom means you can put dependency management in for the entire project which is much tidier.
There are 2 main types of package types use in aem
  • jar
    • The code bundle that will be installed
  • content-package
    • The content and application configuration files
For building AEM apps there are a few plugins that are very useful.
org.apache.felix:maven-bundle-plugin
This plugin creates the maven bundles' information in the manifest. For more information visit the documentation page
This is mainly for creating your code project and is not really required in the other projects.
The following instructions are part of the configuration
  • Export-Package
    • Defines the packages to be declared as part of the project for AEM
  • Private-Package
    • Defines a list of packages that should not be exported
  • Include-Resource
    • Adds resources to the bundle in the root of the bundle
  • Import-Package
    • Defines a list of packages that are required by this bundle
  • Embed-Dependency
    • Defines which dependencies should be installed inside the bundle
  • Embed-StripVersion
    • Removes the version from the files
  • Embed-StripGroup
    • Removes the group as a subdirectory
  • Embed-Directory
    • Defines the directory to add artifacts to
  • Embed-Transitive
    • Check for transitive dependencies
  • obrRepository
    • The path to the OBR Repository

com.day.jcr.vault:content-package-maven-plugin
The maven vault plugin is used to create a deployable AEM package. For more information visit the documentation page
This will be used for your ui.app project, but will also be used in the ui.content and all projects.
The following instructions are some of the more important parts of the configuration
  • failOnError
    • Specifies if the build should fail if the plugin detects an error during installation of the package
  • name
    • The name of the package to act on
  • password
    • The password used for authentication with crx
  • serverid
    • The server id from which to retrieve the username and password
  • targetURL
    • The url to the crx server
  • timeout
    • The time to wait before failing the build
  • useProxy
    • Determines if the plugin should use a proxy
  • userId
    • The user id for the crx server
  • verbose
    • How the plugin logs
    • The version of the artefact to install
  • embeddeds
    • The way of adding additional content to the project
      • Use this to add the java code package to the deploy
    • A list of embeded items (must be in the dependencies of the project)
      • groupId
        • The group of the embedded item
      • artifactId
        • The artifact of the embedded item
      • target
        • The location in the jcr:repository to install the artefact
  • properties
    • acHandling
      • clear
        • Clears all ACL's
      • ignore
        • Ignores ACL's in the package
      • merge
        • Merges the ACL's in the package with those already on the system by replacing entries of corresponding principals
      • merge_preserve
        • Merges the ACL's in the package with those already on the system by adding for principals not already there
      • overwrite
        • Overwrite any ACL's already in place

The following is an example base pom.xml
<?xml version="1.0" encoding="UTF-8"?> <project
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.sample</groupId>
<artifactId>base</artifactId> <name>Base</name>
<description>Sample base</description>
<packaging>pom</packaging>
<version>1.0.0-SNAPSHOT</version>
<modules>

<module>core</module>
<module>ui.apps</module>
<module>ui.content</module>
<module>sling</module>
<module>all</module>
</modules>
<properties>

<crx.user>admin</author.user>
<crx.password>admin</author.password>
<author.url>localhost:4502</author.url>
<publisher.url>localhost:4503</publisher.url>
</properties>
<build>

<plugins>
<!-- Maven Release Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.1</version>
<configuration>

<scmCommentPrefix>[maven-scm] :</scmCommentPrefix>
<preparationGoals>clean install</preparationGoals>
<goals>install</goals>
<releaseProfiles>release</releaseProfiles>
</configuration>
</plugin>
<!-- Maven Source Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<inherited>true</inherited>
</plugin>
<!-- Maven Resources Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>

<encoding>UTF-8</encoding>
</configuration>
</plugin>
<!-- Maven Jar Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.5</version>
</plugin>
<!-- Maven Enforcer Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<executions>

<execution>
<id>enforce-maven</id>
<goals>

<goal>enforce</goal>
</goals>
<configuration>

<rules>
<requireMavenVersion>
<version>[2.2.1,)</version>
</requireMavenVersion>
<requireJavaVersion>

<message>Project must be compiled with Java 8 or higher</message>
<version>1.8.0</version>
</requireJavaVersion>
</rules>
</configuration>
</execution>
</executions>
</plugin>
<!-- Maven Compiler Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>

<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
</plugins>
<pluginManagement>

<plugins>
<!-- Maven Clean Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-clean-plugin</artifactId>
<version>2.6.1</version>
</plugin>
<!-- Maven Resources Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
</plugin>
<!-- Maven Compiler Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.2</version>
</plugin> <!-- Apache Felix SCR Plugin --> <plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-scr-plugin</artifactId>
<version>1.20.0</version>
<executions>

<execution>
<id>generate-scr-scrdescriptor</id>
<goals>

<goal>scr</goal>
</goals> <configuration>
<!-- Private service properties for all services. -->
<properties>

<service.vendor>Adobe</service.vendor>
</properties>
</configuration>
</execution>
</executions>
<configuration>

<outputDirectory>${project.build.directory}/classes</outputDirectory>
</configuration>
<dependencies>

<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>1.5.11</version>
</dependency>
</dependencies>
</plugin>
<!-- Maven Installer Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-install-plugin</artifactId>
<version>2.5.2</version>
</plugin>
<!-- Maven Surefire Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.18.1</version>
</plugin>
<!-- Maven Failsafe Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.18.1</version>
</plugin>
<!-- Maven Deploy Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
</plugin>
<!-- Content Package Plugin -->
<plugin>

<groupId>com.day.jcr.vault</groupId>
<artifactId>content-package-maven-plugin</artifactId>
<version>0.0.24</version>
<configuration>

<targetURL>http://${aem.host}:${aem.port}/crx/packmgr/service.jsp</targetURL>
<failOnError>true</failOnError>
<failOnMissingEmbed>true</failOnMissingEmbed>
</configuration>
</plugin>
<!-- Apache Felix Bundle Plugin -->
<plugin>

<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<version>2.5.3</version>
<inherited>true</inherited>
</plugin>
<!-- Maven Enforcer Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-enforcer-plugin</artifactId>
<version>1.4</version>
</plugin>
<!-- Maven Dependency Plugin -->
<plugin>

<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
</plugin>
<!-- Build Helper Maven Plugin -->
<plugin>

<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.9.1</version>
</plugin>
</plugins>
</pluginManagement>
</build>
<!-- ====================================================================== -->
<!-- D E P E N D E N C I E S -->
<!-- ====================================================================== -->
<dependencyManagement>

<dependencies>
<!-- AEM Dependencies -->
<dependency>

<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr</artifactId>
<version>1.6.0</version>
<scope>provided</scope>
</dependency> <dependency>
<groupId>org.apache.felix</groupId>
<artifactId>org.apache.felix.scr.annotations</artifactId>
<version>1.9.6</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>javax.jcr</groupId>
<artifactId>jcr</artifactId>
<version>2.0</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>com.adobe.aem</groupId>
<artifactId>uber-jar</artifactId>
<version>6.2.0</version>
<classifier>apis</classifier>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.api</artifactId>
<version>1.2.2</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.impl</artifactId>
<version>1.2.2</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-atinject_1.0_spec</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
<!-- Web Dependencies -->
<dependency>

<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<!-- Logging Dependencies -->
<dependency>

<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>1.5.11</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.5.2</version>
</dependency>
<!-- Commons Dependencies -->
<dependency>

<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.4</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.0</version>
</dependency>
<dependency>

<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.6</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
<scope>provided</scope>
</dependency>
<dependency>

<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.2.4</version>
<scope>compile</scope>
</dependency>
<dependency>

<groupId>org.apache.commons</groupId>
<artifactId>commons-email</artifactId>
<version>1.2</version>
</dependency>
<!-- Test Dependencies -->
<dependency>

<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>

<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<version>1.9.5</version>
<scope>test</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>

It isn't much unusual in the base pom, it defines all of the dependencies for libraries and plugins that the child projects will use
One thing you will notice in the dependencies is that I am using the AEM uber jar with a classifier of apis instead of obfuscated. You will need to contact adobe to get access to this file, however, it will be worthwhile as you will be able to write unit tests for all of your classes that use some of the more low-level adobe libraries. The obfuscated version doesn't include the constructors for a lot of the items which means you won't be able to mock them in your unit tests. 


By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.