Adobe Campaign yields solutions that let you personalize and deliver campaigns across all of your online and offline channels. Adobe Experience Manager leading digital experience management solution that helps the business deliver compelling content across experiences. Adobe provides integration points among these tools to provide a very specific targetted experience that typically includes managing content (email or web) in AEM and synchronizing them to AC where the email content is personalized and delivered to target audience at the desired time. Check AEM to Campaign v6 for related details. This blog post, however, provides some insight into another use case where User Accounts are created on AEM hosted web page which in turn triggers simultaneous Recipient profile creation in AC in real time using dynamic javascript templates, in short, JSSP.
[ls_content_block id=”1828″]
The solution involves making a POST request to JSSP web service hosted on AC from AEM environment with data being passed as Request parameters or JSON and using AEM cloud configuration for authenticating the request.
Thus, the solution implementation involves following steps:
- Creating JSSP web service to handle POST request
- Configuring AEM environment using Cloud configuration
- Calling the web service from AEM
Creating JSSP web service to handle POST request
Adobe Campaign provides functionality to host JSSP scripts within AC where one can directly perform CRUD operations on AC database and render response in the desired format which could be a string or rich text or even a complex JSON. The JSSP hosted on the server can be accessed using its public URL which is automatically generated whenever we create a JSSP page within AC.
For example, assume we create a jssp page as mentioned in below screenshot with “cus” is the namespace and JSSP named as “acCreateCustomer.jssp”. We can access this web service using below URL:
https://[AC Domain Name]/cus/acCreateCustomer.jssp
Below code that can help you create recipient record once POST request is received from AEM:
<%@ page import="/nl/core/shared/nl.js" %> <% loadLibrary("xtk:common.js"); loadLibrary("xtk:shared/json2.js"); NL.require('/nl/core/shared/xtk.js'); NL.require("/nl/core/api.js") .require('/nl/core/jsspcontext.js'); NL.API.init(request, response, { jsonOutput: true }, function(jsspContext) { var responseCode = 0; var responseMessage = ''; // Setting headers to disable cache response.addHeader("Pragma", "no-cache") response.addHeader("Cache-Control", "no-cache"); response.addHeader("Expires", new Date().toGMTString()); // Handle only if POST requests if( request.method.toLowerCase() !== "post" ) { responseCode = 401; responseMessage = "Service called with usupported method"; logWarning("Service called with usupported method"); response.sendError(401); } else { //Default variables for recipients var FolderName = 'recipient_folder'; var Origin = "AEM"; //Setting variables from HTTP request var p_firstName = String(request.getParameter("firstName")); var p_lastName = String(request.getParameter("lastName")); var p_mobile = String(request.getParameter("mobile")); var p_email = String(request.getParameter("email")).toLowerCase(); var app = { entryData: {}, requestIsValid: function() { return (app.util.isNotEmpty(p_firstName) && app.util.isNotEmpty(p_lastName) && app.util.isNotEmpty(p_mobile) && app.util.isNotEmpty(p_email)); }, util: { isEmpty: function (value) { return typeof value == 'string' && !value.trim() || typeof value == 'undefined' || value === null; }, isNotEmpty: function (value) { return (!app.util.isEmpty(value)); } }, data: { get: { recipientByTaId: function( email ) { var where = '@email="' + email + '" and [folder/@name]="' + FolderName + '"'; var query = xtk.queryDef.create( <queryDef schema="nms:recipient" operation="getIfExists"> <select> <node expr="@id" /> </select> <where> <condition expr={where}/> </where> </queryDef> ).ExecuteQuery(); return query; } }, set: { entryData: function(){ app.entryData = { firstName: p_firstName, lastName: p_lastName, mobile: p_mobile, email: p_email } }, newRecipient: function( data ) { var xml = <recipient xtkschema="nms:recipient" firstName={data.firstName} lastName={data.lastName} mobilePhone={data.mobile} email={data.email} origin= {Origin} _operation="insert"> <folder name={data.folderName} _operation="none"/> </recipient>; //Inserts recipient record xtk.session.Write( xml ); } } } }; //Check if requst to JSSP is valid if ( app.requestIsValid() ) { app.data.set.entryData(); //Getting recipient for recieved TA_ID for verification var recipient = app.data.get.recipientByTaId( email ); //Verify if recipient already exists for recieved TA_ID if ( recipient.@id > 1 ) { //Return since recipient already exists responseCode = 405; responseMessage = "Recipient with same TA ID already exists in AC."; } else { //Inserts new recipient record app.data.set.newRecipient( app.entryData ); responseCode = 200; responseMessage = "Recipient record successfully inserted in AC."; } } else{ //Invalid request responseCode = 500; responseMessage = "Invalid request. Check request parameters."; } } document.write('{\"responseCode\": \"'+responseCode+'\", \"message\": \"'+responseMessage+'\"}'); }); %>
One must add safeguards to avoid anonymous access to JSSP service otherwise it will open vulnerabilities. If you carefully look at above code there are statements that can:
- Validate user (avoid anonymous access)
- Only POST calls as permitted
- Validating recipient parameters prior inserting the record
- Restricting recipient records with same email address
- Specifying valid recipient’s folder
Configuring AEM environment using Cloud configuration
Once we set up our JSSP service, we must establish the link between both solutions so that they can communicate. This is possible by configuring AEM Cloud services which can be accessed through
AEM logo> Tools icon > Deployment > Cloud Services
Check out Connecting AEM to Adobe Campaign for more details.
Apart from this, make sure your AEM environment IP addresses (both author and publish instances) are whitelisted in adobe campaign.
Calling the web service from AEM
Once we are able to setup cloud configuration, the last piece is calling our JSSP from AEM environment. For this, a simple servlet is required that using GenericCampaignConnector to connect AC environment followed by calling postGeneric() method to send POST request from AEM to AC.
@Reference private GenericCampaignConnector campaignConnector; ... Configuration config = campaignConnector.getWebserviceConfig(page.getContentResource().getParent()); CampaignCredentials credentials = campaignConnector.retrieveCredentials(config); ... Map<String, String> params = new HashMap<String, String>(); params.put("origin", "AEM"); CallResults results = campaignConnector.postGeneric("/cus/acCreateCustomer.jssp", params, credentials); return results.bodyAsString();
This is one use case where we utilize AC’s dynamic javascript pages as used to integrate AC and AEM for creating recipients.
We can think to use this solution for sending GET and POST requests to AC using other web technologies 🙂