Friday, September 15, 2023

Leveraging 3rd Party Packages in AEM as a Cloud

 In this post, let us explore how to deploy and use third-party (external) package bundles into the AEM as a Cloud platform.

Most of the time, we must embed third-party packages into the AEM platform to enable tool-specific functionalities. In AEM versions other than AEM as a Cloud platform, the external packages can be directly installed through the package manager without any issues. But in AEM as a Cloud platform, due to the architecture change, the package that has immutable content, e.g., /apps, are not allowed to be installed through package managers and should be part of the code deployment; some of the Adobe-supported external packages like CIF add-on, Core Components, and ACS Commons packages are enabled through Cloud Manager in AEM as a Cloud platform.

Let us understand how the external packages can be enabled for AEM as a Cloud platform.

Let’s start with the package/bundle hosted through an external repository.

As a first step, add the external repository where the package is hosted to the parent pom.xml and the existing Maven repositories.

<repositories>

.............

<repository>
<id>project.local</id>
<name>project</name>
<url>https://test.repo.com/repository</url>
</repository>

</repositories>

Now add the package or bundle dependency to the all/pom.xml (the version can be managed through the parent pom property)

<dependency>
<groupId>com.test.components</groupId>
<artifactId>com-test-components.all</artifactId>
<version>1.0.0</version>
<type>zip</type>
</dependency>

Now add the embed as part of the filevault-package-maven-plugin in all/pom.xml.

<plugin>
<groupId>org.apache.jackrabbit</groupId>
<artifactId>filevault-package-maven-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<group>com.test</group>

.............

<embeddeds>

................

<embedded>
<groupId>com.test.components</groupId>
<artifactId>com-test-components.all</artifactId>
<type>zip</type>
<target>/apps/test-vendor-packages/container/install</target>
</embedded>

</embeddeds>
</configuration>
</plugin>

Now, while deploying the code, the external package will also get deployed to the AEM as a Cloud server. Ensure the external package follows the AEM as a Cloud best practice for their packages; the package may not function as expected in AEM as a Cloud.

Sometimes, you may not have the package stored in the external repository, but if the package is locally available, you need to follow some additional steps.

Create a folder with the name repository under the root of the project.

Now install the local package/bundle to the project repository

mvn install:install-file -Dfile=<Local Package path> -DgroupId=<Group ID of the external Package> -DartifactId=<Artifact ID of the external Package> -Dversion=<Version of the external Package> -Dpackaging=<Packing Type of the external Package> -DlocalRepositoryPath=<Project Repository Folder Path>
mvn install:install-file -Dfile=C:\Test\com-test-components.all-1.0.0.zip -DgroupId=com.test.components -DartifactId=com-test-components.all -Dversion=1.0.0 -Dpackaging=zip -DlocalRepositoryPath=C:\Projects\AEM\mysite\repository

Now, the package will be installed in the project repository.

Update the repository location in parent pom.xml to point to the local project repository; the remaining steps are the same.

<repositories>

.............

<repository>
<id>project.local</id>
<name>project</name>
<url>file:${maven.multiModuleProjectDirectory}/repository</url>
</repository>

</repositories>

Now, while deploying the project through the Cloud Manager pipeline, the external package also gets installed to the AEM as Cloud servers.

Friday, September 8, 2023

Support Custom Run Modes in AEM as a Cloud | Environment Specific Variables in AEM as a Cloud

 This post explores the approach to supporting current custom run modes in AEM as a Cloud using Cloud Manager environment-specific variables and OSGI configurations.

Run Modes lets you tune your AEM instance for a specific purpose: author or publish test, uat, development, intranet, or others.

You can:

  • Define collections of configuration parameters for each run mode.
  • A basic set of configuration parameters is applied for all run modes; you can then tune additional settings to the purpose of your specific environment. These are used as required.
  • Define additional bundles to be installed for a particular mode.

All settings and definitions are stored in the repository and activated by setting the Run Mode.

In AEM versions other than AEM as a Cloud (On-Prem, AMS, Hosted), apart from default run modes (Author, publish, samplecontent, nosamplecontent), we can define custom run modes such as test and uat. Let’s assume you have different AEM environments like Dev, UAT, Stage, and Prod, and each environment needs to connect to a corresponding third-party service, e.g., Dev Service, UAT Service, Stage Service, and Prod Service; this can be achieved by enabling a custom run mode to differentiate each environment then enable OSGI configurations based on the run mode(multiple run modes can be combined if required e.g. publish.uat)to enable environment specific service URL.

Create a configuration file in ui.config project— /apps/<Project Name>/osgiconfig/config.<RunModes>/<Persistent Identity>.cfg.json

The configurations that are common across all the environments can be placed under the config folder — /apps/<Project Name>/osgiconfig/config/<Persistent Identity>.cfg.json

e.g /apps/test/osgiconfig/config.uat/com.test.EndpointService.cfg.json

{
"serviceURL":"https://uat.service.com/testservice"
}

The run mode approach is changed in AEM as a Cloud Service; in AEM as a Cloud Service, run modes must reference RDE, development, stage, and production for the environment or author and publish for the service. A combination of <service>.<environment_type> is being supported, whereas these environments have to be used in this particular order (for example, author.dev or publish.prod)

In AEM as a Cloud service, the environment-specific configurations can be enabled using the Cloud manager environment variable and OSGI configuration. Two value types can be enabled — secret values and standard variables. The OSGI configurations can directly reference the Cloud Manager environment-specific values, replaced with actual values during the runtime.

{
"my_var1": "$[env:my_var1;default=val1]"
"my_var2": "$[secret:my_var1]"

}

As the stage and prod run modes are supported in AEM as a Cloud, the Major concern is on having multiple Dev environments(each AEM as a Cloud program by default enables one dev environment but allows the addition of additional Dev environments as required) and designating those for different purposes, e.g., UAT testing and QA testing, etc.; each Dev instance will have the run mode enabled as “Dev,” so by default, you will not be able to enable different configurations for different Dev environments by following the current approach. Still, you can do it for Stage and Prod.

You can follow two approaches.

  • Keep all the configurations under the config folder and separate any configurations that vary between authors and publisher into a config.author and config.publish run mode-specific folders and use Cloud Manager Environment variables in OSGI to enable environment-specific values.
  • Keep the configurations separated by Dev(config.dev), Stage(config.stage), and Prod(config.prod) run modes and also separated by Author and Publish run modes if required. Keep the Stage and Prod specific configurations directly on the Stage(config.stage) and Prod(config.prod) specific configurations. Then, use the Cloud Manager Environment variable to enable environment-specific configurations for Dev environments designated for different purposes.

Accessing the configuration without enabling the environment variable will display the placeholder string; the default value can be provided if required.

I am accessing the configuration value through a servlet.


@Component(service = { Servlet.class }, property = { "sling.servlet.paths=/services/endpoint",
"sling.servlet.methods"
+ "=GET" })

@Designate(ocd = EndpointService.EndpointServiceConfiguration.class)
public class EndpointService extends SlingSafeMethodsServlet {
private static final long serialVersionUID = 7699176851252742022L;

String endpoint;

@ObjectClassDefinition(name = "Endpoint Servlet")
public @interface EndpointServiceConfiguration {
@AttributeDefinition(name = "Endpoint", description = "Configure Endpoint")
String serviceURL() default "";
}

@Override
protected void doGet(SlingHttpServletRequest request,
SlingHttpServletResponse response)
throws ServletException, IOException {

response.getWriter().write("endpoint: " + endpoint);

}

@Activate
@Modified
protected void activate(EndpointServiceConfiguration config) {
this.endpoint = config.serviceURL();
}
}

You can use Cloud Manager Console or API to configure the Environment variables on Cloud Manager.

Login to Cloud Manager Console

Go to Environments and Select the View Details for the specific environment.

Click on Configuration

Add Configurations — Variable or Secret type, and also, the variable can be enabled for all the servers on the environment or specific to Author, Publish, or Preview.

Upon Save, the variable references are updated runtime; this may take some time.

Once the environment configuration update is completed, you can get the value.

You can check the OSGI configuration through the Developer Console, but this will only display the placeholder string not updated with the environment variable.

The variable can be deleted or updated if required; please note that it may take some time to reflect the changes, so plan your changes accordingly.

Also, you can enable secrets if required.

The Cloud Manager API or Command Line also can be used to manage the environment variables.

Dispatcher Configuration Per Environment:

The AMS or AEM as a Cloud uses the same configurations across all the environments and uses environment-specific server variables to support per-environment configurations.

By default, AEM as a Cloud is equipped with several environment variables. One such variable is ENVIRONMENT_TYPE, which indicates the current run mode, such as 'development', 'stage', or 'production'. This variable can be directly referenced in expressions. Additionally, there are "define" flags named ENVIRONMENT_DEVENVIRONMENT_STAGE, and ENVIRONMENT_PROD. These "define" flags can be utilized to construct logic using the <IfDefine> directive.

# Simple usage of the environment variable
ServerName ${ENVIRONMENT_TYPE}.company.com

# When more logic is required
<IfDefine ENVIRONMENT_STAGE>
# These statements are for stage
Define VIRTUALHOST stage.example.com
</IfDefine>
<IfDefine ENVIRONMENT_PROD>
# These statements are for production
Define VIRTUALHOST prod.example.com
</IfDefine>

In some cases, you may need custom variables, e.g., to separate each Dev environment for different use cases — Dev, UAT, etc.; in this case, you can use Cloud Manager environment variables, e.g., CUSTOM_VARIABLE in your httpd/dispatcher configuration, although not environment secrets. You can refer to this as a variable, e.g., ${CUSTOM_VARIABLE}, but the Define syntax defined in the earlier section will not work.

Refer to Configuring OSGi for Adobe Experience Manager as a Cloud Service | Adobe Experience Manager and Validating and Debugging using Dispatcher Tools | Adobe Experience Manager for more details on managing environment variables, including managing through API/Command lines, and also details on how local development can adopt this approach.