Newer Version Available
CMS Connector Page Code
If you use CMS Connect to render personalized content in your Experience Builder site,
your setup process requires the following connector JSP page code.
To get your personalized content from Adobe Experience Manager working in your site, create a JSP connector page that contains the following code. You can add to this code as needed. See Personalize Your CMS Content for full instructions on setting up personalization in your site.
The connector JSP page logic includes the following sections:
- Request parameter. The request parameter (payload) contains the data that a site passes to the connector page. It contains componentUrls (an array of component path URLs for which personalization must be run), asset (a JavaScript asset specified in the Asset Path field in the CMS connection that is injected when the JSP page loads), clientContext (IP address, language, country, state, city, latitude, and longitude), requestId (a token that is returned as part of the postMessage to validate the authenticity of the response), and domain (the domain of the site requesting personalized content).
- Personalization JSP logic. We provide you with the basic logic, below. You can add logic as needed.
- JavaScript. In your JSP, include Salesforce-provided JavaScript that sends a postMessage to your site. Construct the script src in this way: <your_site_domain/_sfdc/cms-connect/aem_personalization/salesforceConnector.js>. Any asset specified in the Asset Path field in the CMS connection is included in your JSP.
- Response. The final section constructs the response object and does the postMessage. The JavaScript that you include in the previous section does this.
1<!-- Salesforce connector to run AEM personalization-->
2<%@include file="/libs/foundation/global.jsp"%><%
3%><%@page import="
4 java.io.StringWriter,
5 java.net.URL,
6 com.day.cq.wcm.api.WCMMode,
7 com.day.cq.wcm.core.stats.PageViewStatistics,
8 com.day.text.Text,
9 java.util.ResourceBundle,
10 com.day.cq.i18n.I18n,
11 com.day.cq.personalization.TargetedContentManager,
12 com.day.cq.personalization.ClientContextUtil,
13 org.apache.sling.commons.json.JSONObject,
14 org.apache.sling.commons.json.JSONArray,
15 com.day.cq.commons.JS,
16 org.apache.sling.engine.*,
17 org.apache.sling.api.SlingHttpServletRequest,
18 org.apache.sling.api.resource.ResourceResolver,
19 java.util.*,
20 com.day.cq.*" %><%
21
22 %><cq:includeClientLib categories="personalization.kernel"/><%
23 if(request.getParameter("payload") != null) {
24 // For every component URL, get the Teasers object and strategy.
25 JSONObject payload = new JSONObject(request.getParameter("payload"));
26 JSONArray compUrls = payload.getJSONArray("componentUrls");
27 String asset = payload.getString("asset");
28 HashMap<String, JSONArray> teaserMap = new HashMap<>();
29 HashMap<String, String> strategyMap = new HashMap<>();
30 ResourceBundle resourceBundle = slingRequest.getResourceBundle(null);
31 I18n i18n = new I18n(resourceBundle);
32 final TargetedContentManager targetedContentManager = sling.getService(TargetedContentManager.class);
33 SlingRequestProcessor requestProcessor = sling.getService(SlingRequestProcessor.class);
34 ResourceResolver resolver = slingRequest.getResourceResolver();
35 for(int j=0; j<compUrls.length(); j++) {
36
37 JSONArray allTeasers = new JSONArray();
38 String strategy = "";
39
40 try {
41 String requestPath = new URL(compUrls.getString(j)).getPath().replaceAll(".html", "");
42
43 Resource resourceObject = resolver.getResource(requestPath);
44
45 Node rootNode = resourceObject.adaptTo(Node.class);
46 ValueMap prop = resourceObject.adaptTo(ValueMap.class);
47
48 // Get the strategy path
49 String strategyPath = prop.get("strategyPath", (String) null);
50 if (strategyPath != null) {
51 strategy = Text.getName(strategyPath);
52 strategy = strategy.replaceAll(".js", "");
53 }
54
55 // Get the campaign path
56 String campaignPath = prop.get("campaignpath", (String) null);
57 String campaignClass = "";
58 if (campaignPath != null) {
59 Page campaignPage = pageManager.getPage(campaignPath);
60 if (campaignPage != null) {
61 campaignClass = "campaign-" + campaignPage.getName();
62 }
63 }
64
65 JSONObject teaserInfo = targetedContentManager.getTeaserInfo(resourceResolver, campaignPath, requestPath);
66 allTeasers = teaserInfo.getJSONArray("allTeasers");
67
68 // Add selectors from the current page for the mobile case, e.g. "smart", "feature" etc.
69 String selectors = slingRequest.getRequestPathInfo().getSelectorString();
70 selectors = selectors != null ? "." + selectors : "";
71
72 for (int i = 0; i < allTeasers.length(); i++) {
73 JSONObject t = (JSONObject) allTeasers.get(i);
74 t.put("url", t.get("path") + "/_jcr_content/par" + selectors + ".html");
75 }
76
77 // Use "default" child node as default teaser and add at the end of the teaser list
78 JSONObject defaultTeaser = new JSONObject();
79 defaultTeaser.put("path", resourceObject.getPath() + "/default");
80 defaultTeaser.put("url", resourceObject.getPath()+ ".default" + selectors + ".html");
81 defaultTeaser.put("name", "default");
82 defaultTeaser.put("title", i18n.get("Default"));
83 defaultTeaser.put("campainName", "");
84 defaultTeaser.put("thumbnail", resourceObject.getPath() + ".thumb.png");
85 allTeasers.put(defaultTeaser);
86 } catch (Exception e) {
87 // If an exception occurs for any of the component URLs, we will put default values in teaserMap and strategyMap
88 }
89
90 teaserMap.put(compUrls.getString(j), allTeasers);
91 strategyMap.put(compUrls.getString(j), strategy);
92
93 }
94
95 String requestId = payload.getString("requestId");
96 String domain = payload.getString("domain");
97 JSONObject teaserJson = new JSONObject(teaserMap);
98 JSONObject strategyJson = new JSONObject(strategyMap);
99
100 %>
101
102 <html>
103 <head>
104 <script type="text/javascript" src="/etc/clientlibs/granite/jquery.js"></script>
105 <script type="text/javascript" src="/etc/clientlibs/granite/utils.js"></script>
106 <script type="text/javascript" src="/etc/clientlibs/granite/jquery/granite.js"></script>
107 <script type="text/javascript" src="/etc/clientlibs/foundation/jquery.js"></script>
108 <script type="text/javascript" src="/etc/clientlibs/foundation/shared.js"></script>
109 <script type="text/javascript" src="/etc/clientlibs/granite/lodash/modern.js"></script>
110 <script type="text/javascript" src="/etc/clientlibs/foundation/personalization/kernel.js"></script>
111 <!--TODO: Include the script that will send a postMessage to your site. The path of the JS is <your site domain/_sfdc/cms-connect/aem_personalization/salesforceConnector.js> -->
112 <!--The below line injects a script that is passed in the request -->
113 <script type="text/javascript" src="<%= asset %>"></script>
114 </head>
115
116 <body>
117 <script>
118 var teaserMap = <%= teaserJson %>;
119 var strategyMap = <%= strategyJson %>;
120 var requestId = "<%= requestId %>";
121 var domain = "<%= domain %>";
122 setClientContext();
123 var resolvedTeasers = getResolvedTeasers(teaserMap, strategyMap);
124 CMS_CONNECT_PERSONALIZATION_AEM.responsePersonalization(resolvedTeasers, requestId, domain);
125
126
127 // This is a sample client-context that can be used.
128 // Salesforce provides the client-context object which can be used to build the json
129 /**
130 * @typedef {object} payload.clientContext
131 * @property {String} ipAddress User's ipAddress
132 * @property {String} language User language
133 * @property {String} country User's country
134 * @property {String} state User's state
135 * @property {String} city User's city
136 * @property {String} latitude User's latitude
137 * @property {String} longitude User's longitude
138 */
139 function setClientContext() {
140 var payload = <%= payload %>;
141 var clientContext = payload.clientContext;
142 // Set client-context
143 var clientContextJson = {};
144 clientContextJson.surferinfo = {
145 'IP': clientContext.ipAddress
146 };
147 clientContextJson.profile = {
148 'language': clientContext.language,
149 'country': clientContext.country,
150 'state': clientContext.state,
151 'city': clientContext.city
152 };
153 clientContextJson.geolocation = {
154 'latitude': clientContext.latitude,
155 'longitude': clientContext.longitude
156 };
157 CQ_Analytics.ClientContextMgr.clientcontext = clientContextJson;
158 }
159
160 /**
161 * Runs personalization logic for all the component URLs requested
162 * @param {teaserMap} Map of componentUrl as key and teasers object for the component
163 * @param {strategyMap} Map of componentUrl as key and strategy for the component
164 */
165 function getResolvedTeasers(teaserMap, strategyMap) {
166 var resolvedTeasers = {};
167 for (var key in teaserMap) {
168 try {
169 if (teaserMap.hasOwnProperty(key)) {
170 var resolvedTeaser = CQ_Analytics.Engine.resolveTeaser(teaserMap[key], strategyMap[key], null);
171 resolvedTeasers[key] = resolvedTeaser.url.substring(1);
172 }
173 } catch (err) {
174 // If any error occurs in calculating resolved teaser for a component url, we save it as error
175 resolvedTeasers[key] = "error";
176 }
177 }
178
179 return resolvedTeasers;
180 }
181 </script>
182 </body>
183 </html>
184 <%
185 }
186 %>