Make your CONGA-based AEM project ready for AEM Cloud Service

Overview

This article describes the required steps to make your CONGA-based AEM project compatible with AEM as a Cloud Service and deployment via Adobe Cloud Manager.

If you want to create a new CONGA-based project you do not need this article, but can create an new project straightaway with the wcm.io Maven Archetype for AEM 3.0.0 or above using “cloud” as optionAemVersion. It’s also helpful to setup an new sample project with this archetype alongside with a migration, because in this article we aim to reach the same structure as it is generated by the archetype.

Step 1: Update Dependencies

Make sure to update the following dependencies:

  • Update to latest version (1.4.8 or later) of aem-global-parent in the parent POM to get the latest versions of CONGA plugins and other updates

  • Update all other wcm.io dependencies to the latest versions - some had some small fixes for AEM Cloud compatibility

  • Check other dependencies for required updates, e.g. ACS AEM Commons or AC Tool

Step 2: Update ACS AEM Commons package references

In case you are using ACS AEM Commons in your project you have to update the package references to differentiate between the immutable and mutable content parts of ACS Commons:

  • In the parent POM, replace the reference to com.adobe.acs:acs-aem-commons-content with:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 <dependency> <groupId>com.adobe.acs</groupId> <artifactId>acs-aem-commons-ui.apps</artifactId> <version>${acs.aem.commons.version}</version> <classifier>min</classifier> <type>zip</type> </dependency> <dependency> <groupId>com.adobe.acs</groupId> <artifactId>acs-aem-commons-ui.content</artifactId> <version>${acs.aem.commons.version}</version> <classifier>min</classifier> <type>zip</type> </dependency>
  • In the config-definition POM, replace the reference to com.adobe.acs:acs-aem-commons-contentwith:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 <dependency> <groupId>com.adobe.acs</groupId> <artifactId>acs-aem-commons-ui.apps</artifactId> <classifier>min</classifier> <type>zip</type> <scope>compile</scope> </dependency> <dependency> <groupId>com.adobe.acs</groupId> <artifactId>acs-aem-commons-ui.content</artifactId> <classifier>min</classifier> <type>zip</type> <scope>compile</scope> </dependency>
  • In the CONGA role in config-definition/src/main/roles, replace the reference to com.adobe.acs:acs-aem-commons-content with:

    1 2 3 4 5 6 7 8 - url: mvn:com.adobe.acs/acs-aem-commons-ui.apps//zip/min dir: packages postProcessorOptions: contentPackage.packageType: application - url: mvn:com.adobe.acs/acs-aem-commons-ui.content//zip/min dir: packages postProcessorOptions: contentPackage.packageType: content

In this CONGA role definition excerpt an explicit packageType is defined for the ACS AEM Commons packages. This pattern may be useful for other 3rdparty packages of your project as well that have no packageType set in their properties - packages without packageType will not be deployed to AEM Cloud by CONGA.

Step 3: Enable reproducible builds in Maven

If you are using bnd-maven-plugin to build your OSGi bundles (what we recommend) there is a special edge case using Sling-Initial-Content and Sling i18n JSON files (example) and wrong ordering of files in the bundle ZIP file which may lead to deployment failures.

To solve this problem add this Maven property to your project’s parent POM to enable the “reproducible builds” feature of Maven (which is useful anyways) for your project:

1 2 3 4 <properties> <!-- Enable reproducible builds --> <project.build.outputTimestamp>${timestamp}</project.build.outputTimestamp> </properties>

The ${timestamp} variable is set by a plugin in the global-parent POM and it’s value is usually automatically replace by the Maven Release Plugin on each release.

Step 4: Remove AEM Service Packs/Hotfixes

In case you have referenced any AEM Service Pack or Hotfix content packages in the CONGA role files in

1 config-definition/src/main/roles

remove all of them - they are no longer required for AEM Cloud service.

Step 5: Remove obsolete Apache Sling bundles

Check if you have embedded Apache Sling bundles in the content-packages/complete package that are obsolete, because the same or a newer version of it is already available in the AEM Cloud version you are using. To remove them:

  • Remove the version definition from the parent POM

  • Remove the dependency definition from the complete package and the reference to it in the embeddeds section of the package definition.

  • Remove dependency definitions to them in the bundle POMs

This step is optional - it does not harm if you have included older versions of Sling Bundles in your complete packages - they will be ignored if a newer version is already present in AEM.

Step 6: Switch to AEM SDK API

Remove the reference to io.wcm.maven:io.wcm.maven.aem-dependencies in your parent POM and replace it with a new one that includes the AEM Cloud Service dependencies maintained by wcm.io:

1 2 3 4 5 6 7 8 <!-- AEM dependencies --> <dependency> <groupId>io.wcm.maven</groupId> <artifactId>io.wcm.maven.aem-cloud-dependencies</artifactId> <version>2020.04.2793.20200403T195013Z-200130.0000</version> <type>pom</type> <scope>import</scope> </dependency>

Lookup the latest version available for this dependency in Maven Central.

Additionally you have to replace all references to com.adobe.aem:uber-jar in your bundle POMs with this dependency:

1 2 3 4 5 <dependency> <groupId>com.adobe.aem</groupId> <artifactId>aem-sdk-api</artifactId> <scope>provided</scope> </dependency>

Step 7: Remove AEM Core Components dependency/packages

The latest version of AEM Core Components is already included in the AEM SDK API and AEM Cloud Service, it’s not longer required to reference it as explicit dependency or deploy the packages together with your project:

  1. Remove all references to com.adobe.cq:core.wcm.components.core and com.adobe.cq:core.wcm.components.all from your parent POM.

  2. Remove all references to com.adobe.cq:core.wcm.components.core from your bundle POMs.

  3. Remove all references to com.adobe.cq:core.wcm.components.all from the config-definition POM, and remove the reference to it from the CONGA Roles at config-definition/src/main/roles.

Step 8: Create service users via repoinit

Some wcm.io bundles requires service users to set up appropriate permissions, and this was done in the past using CONGA-generated bundles with a file definition in the CONGA role like this wcm-io-samples-aem-cms-author-systemusers with this JSON template .

Remove this file definition {project}-aem-cms-author-systemusers.json from the CONGA role and the HBS template it references and replace it with an addition to the {project}-aem-cms-config.provisioning.hbs template which defines the OSGi configurations of your project using Sling RepoInit syntax:

1 2 3 4 5 6 [:repoinit runModes=author] # Create service user for wcm.io Media Handler create service user wcmioDamSystemUser set ACL on /content/dam allow jcr:read,rep:write for wcmioDamSystemUser end

Replace the user names accordingly. If you have created more system users or more “initialization” packages like this, convert them to repoinit as well. Additional benefit: this repoinit syntax us much more compact and better readable.

Step 9: Remove longCacheKey definitions

It’s not longer required to set longCacheKey properties for client libraries - this feature is enabled by default in AEM Cloud Service generating a hash based on the content of the client library.

Please note that this is only the case in the cloud environment, not when using the local quickstart JAR of AEM Cloud SDK. If you want to activate the feature for the local AEM instance as well, set the “Long term client side cache key” in the “Adobe Granite HTML Library Manager” OSGi configuration to /.*;hash.

Step 10: Make content package modules compatible with AEM Cloud

The Project Structure documentation of AEM Cloud Service explains the new requirements for content packages (immutable and mutable, that means application packages and config/sample content packages).

If you’ve not done it already, make sure you have switched all your content package projects to the Apache Jackrabbit FileVault Package Maven Plugin (see migration guide).

The latest wcm.io aem-global-parent also includes the latest version of the FileVault Package Maven Plugin which has built-in additional validation steps, you may have to adapt your packages, see this guide .

Check/adapt all your content package module POMs:

  1. Make sure the appropriate packageType property is set for each content package. “application” and “container” are immutable content packages, “content” are mutable content packages. It’s not allowed to use the “mixed” type. Example:

    1 <packageType>content</packageType>
  2. If you have packages that mix immutable and mutable content (the validation rules of the FileVault Package Maven Plugin will tell you that), you have to split up your packages.

  3. Make sure that all packages have a new package property cloudManagerTarget set to none. This instructs the Cloud Manager to ignore this package - it will be handed over to the Cloud Manager as part of an “all” package generated by CONGA in a later step. Example:

    1 2 3 4 <!-- Do not deploy directly via AEM cloud manager, only as part of CONGA-generated "all" package --> <properties> <cloudManagerTarget>none</cloudManagerTarget> </properties>
  4. You do not have to declare dependencies between your packages. This is done by CONGA automatically based on the order of the files defined in the CONGA role.

  5. It is recommended (but not mandatory) to create a “repository structure” package module that defines all application folders that are already present OOTB in AEM Cloud Service and which should not fail the validation of the other packages if application content is deployed to them. In the Adobe documentation this module is referenced as repository-structure, in the latest Adobe AEM project archetypes it’s named ui.apps.structure.

    • For CONGA-bases projects the recommendation is to create it at

      1 content-packages/apps-repository-structure/pom.xml
    • Example package definition (full example):

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 <plugin> <groupId>org.apache.jackrabbit</groupId> <artifactId>filevault-package-maven-plugin</artifactId> <extensions>true</extensions> <configuration> <!-- Do not deploy directly via AEM cloud manager, only as part of CONGA-generated "all" package --> <properties> <cloudManagerTarget>none</cloudManagerTarget> </properties> <filters> <!-- /apps root --> <filter><root>/apps</root></filter> <!-- Common overlay roots --> <filter><root>/apps/sling</root></filter> <filter><root>/apps/cq</root></filter> <filter><root>/apps/dam</root></filter> <filter><root>/apps/wcm</root></filter> <filter><root>/apps/msm</root></filter> <!-- Immutable context-aware configurations --> <filter><root>/apps/settings</root></filter> </filters> </configuration> </plugin>
    • Once this is defined it can be referenced from the other content package modules containing immutable application content of the project. Example:

      1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 <dependencies> <dependency> <groupId>YOUR_GROUP_ID</groupId> <artifactId>YOUR_GROUP_ID.apps-repository-structure</artifactId> <version>YOUR_VERSION</version> <type>zip</type> <scope>provided</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.apache.jackrabbit</groupId> <artifactId>filevault-package-maven-plugin</artifactId> <extensions>true</extensions> <configuration> ... <repositoryStructurePackages> <repositoryStructurePackage> <groupId>YOUR_GROUP_ID</groupId> <artifactId>YOUR_GROUP_ID.apps-repository-structure</artifactId> </repositoryStructurePackage> </repositoryStructurePackages> </configuration> </plugin> </plugins> </build>
    • Make sure this package gets never deployed to any AEM instance! It’s only a tool for supporting the package validation during build time.

Step 11: Make CONGA-generated content packages compatible with AEM Cloud

Check the CONGA roles defined at config-definition/src/main/roles if you have custom packages defined using JSON templates and the aem-contentpackage post processor:

  • Set a package type for each content package. Example:

    1 2 3 4 5 postProcessors: - aem-contentpackage postProcessorOptions: contentPackage: packageType: content
  • Split packages that mix immutable with mutable content, or check if the package can be replaced with repoinit statements.

This applies not to OSGi configuration packages generated with the aem-contentpackage-osgiconfig post processor - they are automatically generated as immutable container packages.

Step 12: Add new CONGA Environments for AEM Cloud

The way recommended by Adobe is to put the AEM application code directly in the GIT repository provided by the Cloud Manager. In this case no separate “configuration-management” GIT repository is used, so we need to define an additional CONGA Environment for the AEM cloud dev/stage/prod environments. Create a CONGA environment directly in the application GIT repository at config-definition/src/main/dev-environments:

  1. Define a new “cloud” environment:

  2. Rename the predefined “development” environment to “local” to avoid confusion with the cloud “dev” environment. For this you have to:

    • Rename the file development.yaml to local.yaml

    • Change the references to the “development” CONGA_ENVIRONMENT in the configuration/definition/packages-upload.sh and build-deploy.sh scripts to “local”

  3. Mark this “local” environment to be ignored by the Cloud Manager (it’s only used for local AEM deployment) by adding to the config: section:

    1 2 3 # Not used for AEM cloud cloudManager.target: - none

The rationale behind this:

  • We define a single “cloud” CONGA environment instead of three for dev/stage/prod cloud environments because the Adobe Cloud Manager has currently limitations and does not support deploying packages on some and environments and not on others (e.g. sample content not on prod). Therefore we currently have to live with a single “cloud” environment. It’s still possible to define different host names for each environment, and OSGi configuration can also be defined individually using the environment names as run modes.

  • CONGA will build a separate “all” package for author and publish instances containing the selected packages with dependencies automatically defined following the order of the files in the role definitions

  • An additional ZIP file is generated containing the dispatcher configuration which is used for all cloud environments as well.

Step 13: Build “all” and “dispatcher config” packages for Cloud Manager

Add two new plugin executions to the POM at config-definition/pom.xml:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 <plugin> <groupId>io.wcm.devops.conga.plugins</groupId> <artifactId>conga-aem-maven-plugin</artifactId> <executions> <!-- Generate "all" packages including all packages from CONGA configuration for deployment via Adobe Cloud Manager --> <execution> <id>cloudmanager-all-package</id> <phase>generate-resources</phase> <goals> <goal>cloudmanager-all-package</goal> </goals> <configuration> <group>epsiloncloudProject</group> <!-- Workaround because Cloud Manager does not properly support dependencies for mutable content packages yet --> <autoDependenciesMode>IMMUTABLE_ONLY</autoDependenciesMode> </configuration> </execution> <!-- Generate Dispatcher configuration ZIP file for deployment via Adobe Cloud Manager --> <execution> <id>cloudmanager-dispatcher-config</id> <phase>generate-resources</phase> <goals> <goal>cloudmanager-dispatcher-config</goal> </goals> </execution> </executions> </plugin>

Replace ${packageGroupName} with the group name of packages you use in this project.

This will generate the ZIP files that will be picked up by Adobe Cloud Manager to deploy the content packages and dispatcher configuration to AEM Cloud Service.

Step 14 - Workarounds for Issues

This section lists workarounds for issues that are currently present in AEM Cloud 2020.4. They may be fixed in more recent releases and no longer required.

Do not configure Sling Log Manager

Check if you have a configuration present for the PID org.apache.sling.commons.log.LogManager in any of the provisioning file templates at

1 config-definition/src/main/templates

If you find such a configuration, remove it completely. It will fail the image build in Adobe Cloud Manager.

NodeJS Maven Plugin

If you encounter problems with building your frontend code by Adobe Cloud Manager consider switching from wcm.io NodeJS Plugin to frontend-maven-plugin. See configuration example.

Last Remarks

Use a Sandbox in AEM Cloud to test your migrated project thoroughly. Do not deploy to a stage/prod environment before all is running as expected on a dev environment (it’s easy to delete a dev environment and start from scratch).