Sunday, August 16, 2020

Sling Content Distribution in AEM (Part 3) — Sync Distribution | Sync Content between Publishers in AEM as a Cloud Service

This tutorial is the continuation of earlier tutorials on Sling Content Distribution in AEM, refer the following URL for part 1 and part 2 tutorials.

This tutorial is created based on AEM as Cloud Service Local Author and Publish instances. The social user sync module is removed from AEM as Cloud due to that some additional configurations required to enable the sync distribution between publishers.

I am using the OSGi system console to enable the required configurations for the demo, use run mode specific OGGI configurations while implementing content distribution in the project.

In this tutorial let us see the details on Sling Sync Distribution on AEM.

Sync Distribution — Definition

  • Sync distribution allows modifications made on one publish instance to be synchronized with other publish instances in the farm of publish instances via author instance
  • The modifications automatically synchronized across the publish instances in the farm and are not created on the author.
  • That is done by the author pulling the content from source instance(publish) and distribute it to the other publish instances on the farm.
  • Sling distribution only sends the modification data to non-originating publish instances, eliminating unnecessary traffic
  • The author pulls resources from n publish instances and push them to n-1 publish instances in the farm.
sling-sync-distribution-aem

This will helps us to sync the data generated in n publish instances to (n-1) publish instances other than the source publish instance in a farm through Author instance as a coordinator but without creating the content in Author.

Sync Distribution — Configurations

sling-sync-distribution-aem

Configure a local importer, agent-based exporter and a “queue” agent on all the publish instances

org.apache.sling.distribution.packaging.impl.importer.LocalDistributionPackageImporterFactory-sync.json

name=“sync”

org.apache.sling.distribution.agent.impl.QueueDistributionAgentFactory-pubsync.json

name=”pubsync

org.apache.sling.distribution.packaging.impl.exporter.AgentDistributionPackageExporterFactory-pubsync.json

name=”pubsync”

Configure a “sync distribution” agent on the author(coordinator instance)

org.apache.sling.distribution.agent.impl.SyncDistributionAgentFactory

name=“distribution-sync”

packageExporter.endpoints — pointing to the URL of the exporter on publish instance, configure the endpoints of all the publishers in the farm

packageImporter.endpoints — pointing to the URL of the importer on publish instance, configure the endpoints of all the publishers in the farm

Sync Distribution — Demo

  • Configure Authorized User
  • Adobe Granite Distribution — Encrypted Password Transport Secret Provider
  • Configure Queue agent and importer on Publisher
  • Configure Sync Distribution Agent on Author
  • Enable Triggers — Scheduled/JCREvent
  • Test — CURL/Triggers

Let us now see how to use the sync distribution to sync the content modifications between publish instances through Author instance(Coordinator) without creating the modifications in Author instance. The sync distribution can be used to sync any data between the farm of publishers.

Configure Authorized User

Create a new user with name — “usersync-admin” and add this user to the administrator group

Follow the amove steps in all the publish instances

Adobe Granite Distribution — Encrypted Password Transport Secret Provider

Once the authorized user is configured in all the publishers, enable Encrypted Password Transport Secret Provider in Author instance, this user will be used to sync the content between Author and Publish instances.

Access http://localhost:4502/system/console/configMgr

Create new configuration for factory “Adobe Granite Distribution — Encrypted Password Transport Secret Provider

name=”distributionsync-publishuser”

username=”usersync-admin”

encryptedPassword= <encryptedPassword for usersync-admin> — Encrypt the password through http://localhost:4502/system/console/crypto

Follow the below steps before encrypting the password to sync the hmac and master files from Author to all the publish instances.

  • Find the bundle Id in Author for com.adobe.granite.crypto.file, for example, 36 by navigating to /system/console/bundles/com.adobe.granite.crypto.file to see the Id.
  • Navigate to /crx-quickstart/launchpad/felix/bundle<Id>/data in the Author file system.
  • Copy the two files: hmac and master from the Author instance to the publish instances.
  • Restart the com.adobe.granite.crypto bundle or the complete Publish instances.

Configure importer, exporter and Queue agent on Publishers

Configure a queue agent that places the changes into the queues, an exporter that exports packages from the queue agent and importer that imports packages from the queue agent.

Access http://localhost:4503/system/console/configMgr

Create new configuration for factory “Apache Sling Distribution Agent — Queue Agents Factory”

Enter a name =“pubsync”
Title=“pubsync”
Check=“Enabled”
Service Name=Service name is optional, if required create a service user with the required permission
Change the log level if required
Allowed Roots=Add the root paths the agent is responsible for distribution e.g required multiple root paths can be configured ) e.g. [/content/we-retail/us]

sling-sync-distribution-aem

Now the Queue Agent factory is enabled, the agent can be managed through Tools — Deployments — Distribution

Image for post

Let us now configure a local importer

Access http://localhost:4503/system/console/configMgr

Create new configuration for factory “Apache Sling Distribution Importer — Local Package Importer Factory”

name=”sync”

sling-sync-distribution-aem

Let us now configure an agent-based exporter

Access http://localhost:4503/system/console/configMgr

Create new configuration for factory “Apache Sling Distribution Exporter — Agent Based Package Exporter

name=”pubsync”
agent.target=”(name=pubsync)”

sling-sync-distribution-aem

Repeat the above(configuring Queue agent, importer, and exporter)steps on other publishers in the farm

Configure Sync Distribution Agent on Author

Configure a Sync Distribution Agent in Author that will PULL the content from publishers(exporters) endpoints based on the configuration and distribute the content to the publishers other than the source.

Access http://localhost:4502/system/console/configMgr

Create new configuration for factory “Apache Sling Distribution Agent — Sync Agents Factory”

Enter a name=“distribution-sync”
Title =“distribution-sync”
Check “Enabled”
Service Name=Service name is optional, if required create a service user with the required permission
Change the log level if required
packageExporter.endpoints=[“http://localhost:4503/libs/sling/distribution/services/exporters/pubsync","http://localhost:4505/libs/sling/distribution/services/exporters/pubsync"]
packageImporter.endpoints=[“http://localhost:4503/libs/sling/distribution/services/importers/sync","http://localhost:4505/libs/sling/distribution/services/importers/sync"]
transportSecretProvider.target = (name=distributionsync-publishuser)

sling-sync-distribution-aem
sling-sync-distribution-aem

Now the Distribution Agent factory is enabled, the agent can be managed through Tools — Deployments — Distribution

sling-sync-distribution-aem

Now the initial configurations are ready, let us test the sync distribution scenario through curl commands

Modify some content under /content/wknd/us node in publish1

Image for post

Execute the below curl commands

On Publish1 — the publisher where the content is modified

curl -u admin:admin http://localhost:4503/libs/sling/distribution/services/agents/pubsync -d “action=ADD” -d “path=/content/wknd/us/en/jcr:content”

Now the content is queued to the publish1 distribution queue

On Author

curl -u admin:admin http://localhost:4502/libs/sling/distribution/services/agents/distribution-sync -d “action=PULL”

Now the content is pulled by Author and distributed to the publishers other than source, the content modifications are not created in Author.

Image for post

Let us now see how to automate the sync distribution through triggers

Configure a JCR Event Trigger in Publishers

Configure a JCR Event Trigger in Publishers — repeat the below steps to all the publishers, to add the JCR changes under the configured path to the Distribution queue

Access http://localhost:4502/system/console/configMgr

Create new configuration for factory “Apache Sling Distribution Trigger — Jcr Event Triggers Factory”

Enter name =“pubsync-trigger”
The path for which the changes are distributed=“/content/wknd/us”
serviceName=service name to access the content e.g distributionservice
Use deep distribution =Enable this if want to distribute the subtree of the configured node on any events

sling-sync-distribution-aem

Create a system user with name distributionservice and provide the required privileges to access the content, I am providing full access for the demo

Register a Server User Mapping for “Apache Sling Service User Mapper Service Amendment”

org.apache.sling.distribution.core:distributionservice=distributionservice

sling-sync-distribution-aem

Now link the trigger to the “Apache Sling Distribution Agent — Queue Agents Factory” configured with the name “pubsync” in the earlier step, Triggers — (name=pubsync-trigger)

sling-sync-distribution-aem

Configure a Scheduled Event Trigger in Author

Configure a Scheduled Event Trigger in Author to pull the content from publishers Queue and distribute the content to the publishers other than the source.

Access http://localhost:4502/system/console/configMgr

Create new configuration for factory “Apache Sling Distribution Trigger — Scheduled Triggers Factory”

Enter name =“pubsync-trigger”
Distribution Type=“PULL”
Distributed Path= the path to be distributed periodically e.g. “/content/wknd/us”
serviceName = service name to access the content e.g distributionservice
Interval in Seconds =the number of seconds between distribution requests. Default 30 seconds

sling-sync-distribution-aem

Create a system user with name distributionservice and provide the required privileges to access the content, I am providing full access for the demo

Register a Server User Mapping for “Apache Sling Service User Mapper Service Amendment”

org.apache.sling.distribution.core:distributionservice=distributionservice

sling-sync-distribution-aem

Now link the trigger to the “Apache Sling Distribution Agent — Sync Agents Factory” configured with the name “distribution-sync” in the earlier step, Triggers — (name=pubsync-trigger)

sling-sync-distribution-aem

Now the content modification from the publisher1 under /content/wknd/us node will be synced to the publishers other than the source(publisher1)on every 30 second

This concludes the sync distribution configuration between publishers through the author instance as a coordinator, the content changes from the publishers are pulled by the author and distributed to all the publishers other than the source. We can configure multiple publisher endpoints in the Author sync agent to pull and distribute the content changes. The triggers can be configured in Author and Publishers to completely automate the sync distribution of the contents.

Friday, August 7, 2020

Sling Feature Flags for continuous integration in Adobe Experience Manager(AEM)| Feature Toggles in AEM

Sling Feature Flags for continuous integration in Adobe Experience Manager(AEM)| Feature Toggles in AEM


This tutorial explains the details of Sling Feature Flags in AEM.

Feature Flags

Feature Flags are used to select whether a particular feature is enabled or not. This allows us to continuously deploy new features of an application without making them globally available yet.

apache-sling-feature-flags

Feature flag support consists of two parts:

The feature flag itself represented by the Feature interface and the application providing a feature guarded by a feature flag.

A feature flag is simply a boolean condition that modifies the behavior of a component, module, or function in your application.

Features may be enabled based on various contextual data:

  • Time of Day
  • Segmentation Data (gender, age, etc.), if available
  • Request Parameter
  • Request Header
  • Cookie Value
  • Static Configuration

Configure Feature Flags

Feature flags can be provided by registering org.apache.sling.featureflags.Feature services. Alternatively feature flags can be provided by factory configuration with factory PID org.apache.sling.featureflags.impl.ConfiguredFeature

Enable through Feature service

Enable a Feature service as shown below, the feature service should implement org.apache.sling.featureflags.Feature. Add the logic to enable/disable the feature into the isEnabled(ExecutionContext ec) method, the method returns boolean true(feature enabled) or false(feature disabled) based on the implementation logic. The ExecutionContext interface provides access to the context for evaluating whether a feature is enabled or not. Enable a name and description for the feature, this will help us to identify the features through feature console.

import org.apache.sling.featureflags.Feature;@Component(service = Feature.class, immediate = true)
public class SampleFeature implements Feature {
@Override
public String getDescription() {
return "Sample Feature";
}
@Override
public String getName() {
return "sample-feature";
}
@Override
public boolean isEnabled(ExecutionContext ec) {

// Write a logic to evaluate the feature flag to true or false

return false;

}

}

This is a dynamic configuration, the logic is evaluated to identify the flag value.

As an example I am creating a feature — CalculateTotal, based on the request parameter(newTotal=true/false) the corresponding calculation logic is enabled, implement the required logic to enable or disable the features.

import org.apache.sling.featureflags.ExecutionContext;
import org.apache.sling.featureflags.Feature;
import org.osgi.service.component.annotations.Component;
@Component(service = Feature.class, immediate = true)
public class CalculateNewTotalFeature implements Feature {

@Override
public String getDescription() {
return "Calculate New Total Feature";
}
@Override
public String getName() {
return "CalculateNewTotalFeature";
}
@Override
public boolean isEnabled(ExecutionContext ec) {
// Feature Flag to enable new total calculation based on the request parameter
if(ec.getRequest()!=null)
{
return Boolean.valueOf(ec.getRequest().getParameter("newTotal"));
}

return false;
}
}

Sample Servlet guarded by the feature flag

import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingSafeMethodsServlet;
import org.apache.sling.featureflags.Features;
import org.osgi.framework.Constants;
import org.apache.sling.api.servlets.HttpConstants;
@Component(service=Servlet.class,immediate = true,
property={
Constants.SERVICE_DESCRIPTION + "=Simple Demo Servlet",
"sling.servlet.methods=" + HttpConstants.METHOD_GET,
"sling.servlet.paths="+ "/services/calculateTotalServlet",
})
public class CalculateTotalServlet extends SlingSafeMethodsServlet {

@Reference
private Features features;
private static final long serialVersionUID = 1L;@Override
protected void doGet(final SlingHttpServletRequest req,
final SlingHttpServletResponse resp) throws ServletException, IOException {
int total=0;
if(features.isEnabled("CalculateNewTotalFeature"))
{
total=Integer.valueOf(req.getParameter("qty"))*Integer.valueOf(req.getParameter("val"))*Integer.valueOf(req.getParameter("tax"));
}else
{
total=Integer.valueOf(req.getParameter("qty"))*Integer.valueOf(req.getParameter("val"));
}
resp.setContentType("text/plain");
resp.getWriter().write("Total = " +total) ;
}
}

Different calculation logic is used based on the newTotal flag value in the request parameter

http://localhost:4502/services/calculateTotalServlet?qty=2&val=3&tax=10&newTotal=true — new logic is used and the outcome is 60

http://localhost:4502/services/calculateTotalServlet?qty=2&val=3&tax=10&newTotal=false — Old logic is used and the outcome is 6

Enable through factory PID org.apache.sling.featureflags.Feature

The feature can also be enabled through factory PID org.apache.sling.featureflags.impl.ConfiguredFeature (Apache Sling Configured Feature)

Enable the run mode-specific configuration — org.apache.sling.featureflags.impl.ConfiguredFeature-sample-feature.xml

Sample configure details are

<?xml version="1.0" encoding="UTF-8"?>
<jcr:root xmlns:sling="http://sling.apache.org/jcr/sling/1.0"
xmlns:jcr="http://www.jcp.org/jcr/1.0" jcr:primaryType="sling:OsgiConfig"
name="sample-feature"
description="Sample Feature"
enabled="{Boolean}true"/>
apache-sling-feature-flags

name — Short name of this feature. This name is used to refer to this feature when checking for it to be enabled or not. This property is required and defaults to a name derived from the feature’s class name and object identity. It is strongly recommended to define a useful and unique for the feature

description — Description of the feature. The intent is to describe the behavior of the application if this feature would be enabled. It is recommended to define this property. The default value is the value of the name property.

enabled — Boolean flag indicating whether the feature is enabled or not by this configuration

This is going to be a static configuration, the flag value is set in the configuration. The static features flags can be used in the application as same as the dynamic feature flags to guard the features.

The configurations can be created/modified(not recommended) and verified through OSGI Console

Image for post
apache-sling-feature-flags

The registered feature flags(default and custom) status can be viewed from OSGI console — http://localhost:4502/system/console/features(displays both dynamic and static flags)

apache-sling-feature-flags

In my case, the feature flag(sample-feature) is disabled by default as the logic is based on the request parameter, enabled when the request parameter contains “newTotal=true”

The static flag — sample-feature

Image for post

Feature Flags for Render Condition in Granite UI Fields

Render condition is a mechanic to indicate if the component should be rendered or not. A typical example would be to render a submit button based on whether the current user has a privilege to create or modify a resource.

The actual decision making logic itself is pluggable, where a rendercondition component can be created as needed.

/libs/granite/ui/components/coral/foundation/renderconditions/feature — A condition that decides based on Sling’s Feature Flag. The UI fields can be enabled or disabled based on the Feature Flag configuration.

I want to display the “Additional Comments” dialog field based on the feature flag -”sample-feature”, display the filed if the feature flag is enabled, and hide if disabled.

Let us now enable the render condition for the specific dialog field

Create a node of type “nt:unstructured” with the name “granite:rendercondition” under the dialog field

Add the following properties to the “granite:rendercondition” node

“sling:resourceType” — granite/ui/components/coral/foundation/renderconditions/feature

feature- feature name(sample-feature), the feature can be of the type dynamic or static type.

apache-sling-feature-flags-aem

The dialog field “Additional Comments” is displayed based on the status(enabled or disabled) of the “simple-feature” flag.

The field is displayed when the flag is enabled

apache-sling-feature-flags
apache-sling-feature-flags

The field is hidden when the flag is disabled

apache-sling-feature-flags
apache-sling-feature-flags

Feature Flags in Workflow Launcher

The feature flags can be used to trigger the workflow launchers along with the other conditions.

Features — Add the list of features that must be enabled to trigger the launcher

Disabled Features — Add the list of features that must be disabled to trigger the launcher.

apache-sling-feature-flags

The sling feature flags can be used in AEM to manage(enable/disable) the features externally from the application code, the flags can be dynamic based on the implementation logic or static. The features can be enabled based on different context data e.g request parameters, cookies, resource properties, etc. The feature flags help us to continuously deliver features without impacting the end-users also helps to dry run the new features without enabling to public users.

References

https://sling.apache.org/documentation/the-sling-engine/featureflags.html

https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/granite-ui/api/jcr_root/libs/granite/ui/components/coral/foundation/renderconditions/feature/index.html

https://helpx.adobe.com/experience-manager/6-5/sites/developing/using/reference-materials/javadoc/org/apache/sling/featureflags/package-summary.html