Tuesday, April 11, 2017

Integration of Adobe Experience Manager(AEM) with Salesforce - Part3

Integration of Adobe Experience Manager(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.

Refer the following post for details on integrating Salesforce with Adobe Experience Manager(AEM)
 https://www.albinsblog.com/2017/03/integrationofaemcq5withsalesforcepart1.html
https://www.albinsblog.com/2017/04/integrationofaemcq5withsalesforcepart2.html

Prerequisite  - Configure the Salesforce cloud connection, refer 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 = "=";



Integration of AEM with Salesforce - Part4


No comments:

Post a Comment