April 27, 2020
Estimated Post Reading Time ~

Integration of AEM with Salesforce - Part3

This post will explain the approach to extend the basic Adobe Experience Manager(AEM) Salesforce connector to search for the Salesforce objects other than Lead/Contact.

Prerequisite - Configure the Salesforce cloud connection, refer to the above-mentioned post for more details.
Enable the Salesforce cloud configuration for the Home page of the websites.


Dependency:
Add the below Maven dependency to the project
For 6.0 and 6.1
<dependency>
<groupId>com.adobe.aem</groupId>
<artifactId>aem-api</artifactId>
<version>6.0.0.1</version>
<scope>provided</scope>
</dependency>

For 6.2
<dependency>
<groupId>com.adobe.aem</groupId>
<artifactId>uber-jar</artifactId>
<version>6.2.0</version>
<classifier>apis</classifier>
<scope>provided</scope>
</dependency>

Change the version based on your server

Create a Java Class (SalesforceSearchProcess.java) that will use the base connector to search for Salesforce objects - This code provides the support to OPPORTUNITY, change the code accordingly to enable the support for other objects.

import com.adobe.cq.mcm.salesforce.SalesforceClient;
import com.adobe.cq.mcm.salesforce.SalesforceResponse;
import com.albinsblog.samples.core.SalesforceSearchParameters;
import com.adobe.granite.crypto.CryptoException;
import com.adobe.granite.crypto.CryptoSupport;
import com.day.cq.wcm.webservicesupport.Configuration;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component
@Service({SalesforceSearchProcess.class})
public class SalesforceSearchProcess
{
private static final Logger log = LoggerFactory.getLogger(SalesforceSearchProcess.class);
@Reference
private CryptoSupport cryptoSupport;
public JSONObject search(Configuration cloudConfig, SalesforceSearchParameters parameters, ResourceResolver resolver) throws Exception
{
if (cloudConfig != null)
{
String instanceUrl = (String)cloudConfig.get("instanceurl", "");
String accessToken = (String)cloudConfig.get("accesstoken", "");
String clientId = (String)cloudConfig.get("customerkey", "");
String encryptedCustomerSecret = (String)cloudConfig.get("customersecret", "");
String encryptedRefereshToken = (String)cloudConfig.get("refreshtoken", "");
try
{
String customerSecret = encryptedCustomerSecret;
String refreshToken = encryptedRefereshToken;
if (this.cryptoSupport.isProtected(encryptedCustomerSecret)) {
customerSecret = this.cryptoSupport.unprotect(encryptedCustomerSecret);
}
if (this.cryptoSupport.isProtected(encryptedRefereshToken)) {
refreshToken = this.cryptoSupport.unprotect(encryptedRefereshToken);
}
SalesforceClient client = new SalesforceClient();
client.setAccessToken(accessToken);

client.setInstanceURL(instanceUrl);
client.setRefreshToken(refreshToken);
client.setClientId(clientId);
client.setClientSecret(customerSecret);
client.setMethod(SalesforceClient.AvailableMethods.GET);
client.setContentType("application/json");
client.setPath("/services/data/v20.0/query/");
client.addParameter("q", buildSOSL(parameters));

SalesforceResponse response = client.executeRequest();
if (response.getAccessTokenUpdated().booleanValue())
{
String configPath = cloudConfig.getPath();
Resource configResource = resolver.getResource(configPath);
Node configNode = ((Node)configResource.adaptTo(Node.class)).getNode("jcr:content");
configNode.setProperty("accesstoken", client.getAccessToken());
configNode.getSession().save();
}
return response.getBodyAsJSON();
}
catch (RepositoryException e)
{
log.error("Repository Exception in Searching SFDC Opportunity " + e.getMessage());
throw new Exception("Repository Exception in Searching SFDC Opportunity " + e.getMessage());
}
catch (CryptoException e)
{
log.error("Cryto Exception in searching SFDC Opportunity " + e.getMessage());
throw new Exception("Crypto Exception in searching SFDC Opportunity " + e.getMessage());
}
catch (JSONException e)
{
log.error("JSON Exception in searching SFDC Opportunity " + e.getMessage());
throw new Exception("JSON Exception in searching SFDC Opportunity " + e.getMessage());
}
}
return null;
}

protected String buildSOSL(SalesforceSearchParameters parameters) throws Exception
{
StringBuilder query = new StringBuilder();
query.append("SELECT ");
if ((parameters.getResultProperties() != null) && (parameters.getResultProperties().length > 0))
{
for (int i = 0; i < parameters.getResultProperties().length; i++) {
if (parameters.getResultProperties()[i] != null) {
query.append(parameters.getResultProperties()[i] + ", ");
}
}
query.deleteCharAt(query.lastIndexOf(","));
}

if (SalesforceSearchParameters.SalesforceObjectType.OPPORTUNITY.equals(parameters.getObjectType())) {//Add the support for required objects
query.append(" FROM OPPORTUNITY ");
}
if ((parameters.getSearchOperator() != null) && (parameters.getSearchType() != null) && (parameters.getSearchVal() != null)) {
query.append("WHERE " + parameters.getSearchType() + " " + parameters.getSearchOperator() + " " + getEncodedSearchVal(parameters.getSearchOperator(), parameters.getSearchVal()));
}
return query.toString();
}

private String getEncodedSearchVal(String operator, String searchVal)
{
Double searchValue = null;
try
{
searchValue = Double.valueOf(Double.parseDouble(searchVal));
return searchValue.toString();
}
catch (NumberFormatException e) {}
return "'" + searchVal + "'";
}
protected void bindCryptoSupport(CryptoSupport paramCryptoSupport)
{
this.cryptoSupport = paramCryptoSupport;
}
protected void unbindCryptoSupport(CryptoSupport paramCryptoSupport)
{
if (this.cryptoSupport == paramCryptoSupport) {
this.cryptoSupport = null;
}
}
}

Create a Java class(SalesforceSearchParameters.java) that will provide the support for required Salesforce objects - - This code provides the support to OPPORTUNITY, change the code accordingly to enable the support for other objects.

import java.util.HashMap;
public class SalesforceSearchParameters
{
private String searchOperator;
private String searchVal;
private String searchType;
private String[] resultProperties;
private HashMap<String,String> inputData;
private SalesforceObjectType objectType;

public static enum SalesforceObjectType
{
OPPORTUNITY;//Add the required objects
private SalesforceObjectType() {}
}
public SalesforceObjectType getObjectType()
{
return this.objectType;
}
public void setObjectType(SalesforceObjectType objectType)
{
this.objectType = objectType;
}
public void setObjectType(String objectType)
{
if (SalesforceObjectType.OPPORTUNITY.name().equalsIgnoreCase(objectType)) {// Add the support required objects
this.objectType = SalesforceObjectType.OPPORTUNITY;
}
}
public String getSearchOperator()
{
return this.searchOperator;
}
public void setSearchOperator(String searchOperator)
{
this.searchOperator = searchOperator;
}
public String getSearchVal()
{
return this.searchVal;
}
public void setSearchVal(String searchVal)
{
this.searchVal = searchVal;

}
public String getSearchType()
{
return this.searchType;
}
public void setSearchType(String searchType)
{
this.searchType = searchType;
}
public String[] getResultProperties()
{
return this.resultProperties;
}
public void setResultProperties(String[] resultProperties)
{
this.resultProperties = resultProperties;
}
public HashMap<String,String> getInputData()
{
return this.inputData;
}
public void setInputData(HashMap<String,String> inputData)
{
this.inputData = inputData;
}
}

Create a components that will invoke SalesforceSearchProcess.search to get the data by providing required parameters.

<%@include file="/libs/foundation/global.jsp"%><%
%><cq:defineObjects />
<%@page session="false"
import="com.albinsblog.samples.core.SalesforceSearchProcess,
com.day.cq.wcm.webservicesupport.Configuration,
com.day.cq.wcm.webservicesupport.ConfigurationManager" %>
<%@page import="com.albinsblog.samples.core.SalesforceSearchParameters" %>
<%@page import="com.day.cq.i18n.I18n" %>
<%@page import="org.apache.sling.commons.json.JSONObject" %>
<%@page import="org.apache.sling.commons.json.JSONArray" %>
<%@ page import="org.apache.sling.commons.json.JSONException" %>
<%
final String searchType = "";
final String searchVal = "";
final String searchOperator = "=";
I18n i18n = new I18n(slingRequest.getResourceBundle(currentPage.getLanguage(false)));
boolean cloudConfigFound = false;
boolean opportunityFound = false;
boolean errorsInSearch = false;
try{
SalesforceSearchProcess searchClient = sling.getService(SalesforceSearchProcess.class);
SalesforceSearchParameters searchParameters = new SalesforceSearchParameters(); searchParameters.setObjectType(SalesforceSearchParameters.SalesforceObjectType.OPPORTUNITY); //Configure the required object
if(!searchVal.equals(""))
{
searchParameters.setSearchVal(searchVal);
}
if(!searchType.equals(""))
{
searchParameters.setSearchType(searchType);
}
if(!searchOperator.equals(""))
{
searchParameters.setSearchOperator(searchOperator);
}

searchParameters.setResultProperties(new String[]{"Name","StageName","Probability"});// Configured the required fields
String[] cloudConfigs = pageProperties.getInherited("cq:cloudserviceconfigs", new String[]{});
ConfigurationManager configurationManager = resourceResolver.adaptTo(ConfigurationManager.class);
if(cloudConfigs.length>0){
Configuration salesforceConfig = configurationManager.getConfiguration("salesforce",cloudConfigs);
if(salesforceConfig!=null){
cloudConfigFound = true;
JSONObject opportunityJSON = searchClient.search(salesforceConfig, searchParameters, resource.getResourceResolver());
if(opportunityJSON!=null){
log.info("OpportunityJSON "+opportunityJSON.toString());
if(!hasErrors(opportunityJSON)){
Integer totalOpportunity = Integer.parseInt(opportunityJSON.getString("totalSize"));
log.info("Total Opportunity searched ----> "+totalOpportunity);
if(totalOpportunity > 0 ){
opportunityFound = true;
JSONArray opportunity = opportunityJSON.getJSONArray("records"); %>
<div id="opportunity-grid">
<table>
<thead>
<tr>
<td width="150"> <%= i18n.get("Name") %> </td>
<td width="150"> <%= i18n.get("Probability") %> </td>

<td width="150"> <%= i18n.get("StageName") %> </td>
</tr>
</thead>
<%
for(int i=0; i<opportunity.length(); i++){
JSONObject opr = opportunity.getJSONObject(i);
%>
<tr>
<td> <%= xssAPI.encodeForHTML( (String)opr.get("Name") ) %> </td>
<td> <%= opr.get("Probability") %> </td>
<td> <%= xssAPI.encodeForHTML( (String)opr.get("StageName") ) %> </td>
</tr>
<%
}
%>
</table>
</div>
<%
}
}
else {
errorsInSearch = true;
}
}
}
}
if(!cloudConfigFound){
%>
<div id="emptyOpportunity">
<%= i18n.get("Salesforce Cloud Service Configuration could not be found for this page.")%>
</div>
<%
}
else if(errorsInSearch){
%>
<div id="emptyOpportunity">
<%= i18n.get("Errors in Search Criteria. Search Again !")%>
</div>
<%
}
else if(!opportunityFound){
%>
<div id="emptyOpportunity">
<%= i18n.get("No Results Found for given Search Criteria. Search Again !")%>
</div>
<%
}
}catch (Exception se){
%>
<div id="emptyOpportunity">
<%= i18n.get("Exception occurred while Searching. Please contact Administrator. ")%>
</div>
<%
log.error("Exception in Searching Opportunity: "+se.getMessage());
} %>
<%!
boolean hasErrors(JSONObject opportunity){
boolean hasErrors = false;
try {
if(opportunity.get("errorCode")!=null)
hasErrors = true;
} catch (JSONException e) {
hasErrors = false;
}
return hasErrors;
}
%>

This will display all the available OPPORTUNITIES in the system


Provide values to searchType,searchVal and searchOperator to restrict the search - make this fields configureable via dialog
e.g
searchType = "Name";
searchVal = "TestPost";
searchOperator = "=";



By aem4beginner

No comments:

Post a Comment

If you have any doubts or questions, please let us know.