Newer Version Available

This content describes an older version of this product. View Latest

CMS Connector Page Code

If you use CMS Connect to render personalized content in your community, your setup process requires the following connector JSP page code.

To get your personalized content from Adobe Experience Manager working in your community, 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 community.

The connector JSP page logic includes the following sections:

  • Request parameter. The request parameter (payload) contains the data that a community 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 community 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 community. Construct the script src in this way: <your_community_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.

To ensure the connector page code gets personalization working in your community, follow these guidelines:

  • Don’t change any request parameter values.
  • Don’t take out any try/catch blocks. We need them to handle the case where something goes wrong in the connector page code.
  • Don’t change the structure of the response object in the postMessage.

Note

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 community. The path of the JS is <your community 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    %>