Saturday, 13 May 2017

AEM - Salesforce lightning component - Access-Control-Allow-Origin

When I try to access salesforce lightning components in AEM, I was not able to access the lightning script from AEM server, I got below error in browser console.

Issue:

XMLHttpRequest cannot load https://AAAAAA.lightning.force.com/lightning/lightning.out.js. 
Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' 
header is present on the requested resource. Origin 'https://localhost:5544' is therefore not allowed access.

Solution:

We need to whitelist the origin i.e. our aem server in salesforce. 
  • Goto salesforce.com site, click on Setup -> search for CORS
  • Goto CORS console, give the AEM server url pattern, in my case it is https://localhost:5544



Tuesday, 2 May 2017

Create AEM porject structure using Lazybones

Lazybones is a command line tool to create AEM project structure. Adobe is recommending its customers to create AEM project structure using Lazybones instead of traditional Maven archetype 10. As when we create a aem project using Maven archetype it is not easy to customize, it provides lots of sample content and packages like test, launcher. Which might not be required for your project, on contrary lazybones bones is very interactive , flexible and easy to customize according to your project need. Adobe consulting Services (ACS) provides a aem multi module template using which you can create AEM projects, which includes lot of default config options and also provides an option to include the ACS commons package as a sub package.
The aim of this tutorial is to learn what is lazybones and how we can use it to create an aem skeleton project structure, as Adobe consulting Services (ACS) has updated the template version and provided the support for AEM 6.3 also i am going to create project structure for AEM 6.3, for learning i am using windows machine so we are going to install lazybones on windows, but you can install it on linux and other operating systems also.
Lazybones Overview:- Lazybones is a command line tool and is build in two parts. First lazybones command line tool and second project templates. This command line tool allows you to create a new project structure for any framework or library for which the tool has a template. Currently ACS has contributed one template for creating AEM multi module project, which we are going to use in this tutorial. You can also contribute templates by sending pull requests to this GitHub project or publishing the packages to the relevant Bintray repository.


Saturday, 29 April 2017

AEM 6.3 - Things to know

Adobe expanded the capabilities of Adobe Experience Manager with the announcement of the new Adobe Experience Cloud at Adobe Summit in March 2017. Adobe Experience Manager’s latest release became generally available on the 26th of April 2017.


Online Revision Cleanup Support

This new release ships with a brand new Tar file format: Oak Segment Tar. It claims to perform better than the previous TarMK format and also fully supports online revision cleanups. This last point should be music to the ears of anyone who has worked on cloud automation with AEM. There will no longer be a need to shutdown an instance to perform a repository compaction and it is now scheduled to run frequently as part of the maintenance tasks.

It’s worth noting that AEM 6.3 does not support the previous TarMK format, which means a repository migration is necessary. Thankfully, Adobe claims to have made the upgrade process more resilient.

Livefyre Integration

Adobe acquired Livefyre back in May 2016 and has now integrated it within Adobe Experience Manager as a set of components along with a user-generated content ingestion & moderation console. Once a Livefyre cloud service configuration is setup, it allows content authors to add components (located under “/libs/social/integrations/livefyre/components“) on a page to surface user generated content from social media like Twitter and Instagram. The combination of traditional branded experiences and social media content will prove to be an effective way to drive engagement with customers. The use of Livefyre does require a separate Assets and Livefyre license but doesn’t require a Communities license.

Monday, 24 April 2017

AEM OSGI component is not visible

When new AEM project is created we may find OSGI components are not displayed in /system/console/components or in manifest.mf or in bundle.

To avoid this add the below plugin in the parent pom.xml and rebuild the project

<plugin>
  <groupId>org.apache.felix</groupId>
  <artifactId>maven-bundle-plugin</artifactId>
  <version>2.3.7</version>
  <configuration>
         <instructions>
                <Embed-Dependency>*;scope=compile|runtime</Embed-Dependency>
                <Embed-Directory>OSGI-INF/lib</Embed-Directory>
                <Embed-Transitive>true</Embed-Transitive>
         </instructions>
  </configuration>
</plugin>

Sunday, 23 April 2017

Get docusign recipient link in AEM

To generate the recipient signing URL call the EnvelopeViews: createRecipientmethod, using the same identifying recipient information - including the clientUserId - that was sent with envelope. To do this make an http POST request to the following endpoint:


POST /accounts/{accountId}/envelopes/{envelopeId}/views/recipient
With the following request body:
{
    "userName": "Kishore Polsani",
    "email": "kishore.polsani@gmail.com",
    "recipientId": "1",
    "clientUserId": "1111",
    "authenticationMethod": "email",
    "returnUrl": "https://www.docusign.com/devcenter"
}


The recipient information - userName, email, recipientId, and clientUserId - must match the values that were provided when the recipient was first added to the envelope, otherwise an error will be returned. Also note we use the userNameproperty to reference the recipient's name instead of just name.
The authenticationMethod is an enumerated value that indicates the convention used to authenticate the signer. Since, with Embedding, you are telling Docusign that you are handling authentication this is your way of telling the platform how you authenticated the recipient. This information will also be included in the Certificate of Completion, a PDF that is automatically generated for every completed envelope. Lastly, the returnUrl is where the recipient will be re-directed to once signing is complete.
A successful response looks like:
{
    "uri": "https://demo.docusign.net/Signing/startinsession.aspx?t=fd6b9e60-e6f6-4260-a9fc-1f4d2e1973d1&pei=d1cf4bea-1b78-47ea-b372-746678e3679f"
}

Sample Code:

package com.kishore.docusign;

/**
 * Docusign integration
 * Author: Kishore Polsani
 */
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.Serializable;
import java.util.Dictionary;

import javax.servlet.ServletException;

import org.apache.commons.lang.StringUtils;
import org.apache.felix.scr.annotations.Activate;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.http.HttpEntity;
import org.apache.http.HttpHost;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.params.ConnRoutePNames;
import org.apache.http.entity.ByteArrayEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.sling.api.SlingHttpServletRequest;
import org.apache.sling.api.SlingHttpServletResponse;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.commons.json.JSONArray;
import org.apache.sling.commons.json.JSONException;
import org.apache.sling.commons.json.JSONObject;
import org.osgi.service.component.ComponentContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

@Component(name = "com.kishore.docusign.DocusignViewRecipientLink", label = "AEM Docusign - Integration", immediate = true, metatype = true)
@Service
@Properties({ @Property(name = "service.description", value = "AEM Docusign - Integration"),
        @Property(name = "service.vendor", value = "AEM Quickstart"),
        @Property(name = "docuservicebaseurl", value = "https://demo.docusign.net"),
        @Property(name = "docusignLoginUrl", value = "https://demo.docusign.net/restapi/v2/login_information"),
        @Property(name = "docuusername", value = "XXXX@XXXX"),
        @Property(name = "docupassword", value = "XXXXX"), 
        @Property(name = "sling.servlet.paths", value = "/services/docusign/DocusignViewRecipientLink", propertyPrivate = true),
        @Property(name = "sling.servlet.methods", value = "POST"),
        @Property(name = "proxyurl", value = "xxxxxxxxxx"),
        @Property(name = "proxyport", value = "80"),
        @Property(name = "integratorkey", value = "XXXXX-XXXXX-XXXXX-XXXXX-XXXX") })
        
public class DocusignViewRecipientLink extends SlingAllMethodsServlet implements Serializable{
    /** The log. */
    private Logger log = LoggerFactory.getLogger(DocusignViewRecipientLink.class);

    private static final long serialVersionUID = 1L;

    private String loginServiceUrl;
    private String serviceBaseUrl;
    private String userName;
    private String password;
    private String integratorkey;
    private String proxyurl;
    private String proxyport;
    private String accountid;

    protected void doGet(SlingHttpServletRequest request,
               SlingHttpServletResponse response) throws ServletException
                {
              doPost(request, response);
             }
    
    public void doPost(SlingHttpServletRequest request, SlingHttpServletResponse response) throws ServletException {
        log.info("loginServiceUrl :" + loginServiceUrl);
        log.info("userName" + userName);
        log.info("password " + password);
        log.info("integratorkey:" + integratorkey);
        log.info("serviceBaseUrl: "+serviceBaseUrl);
        JSONObject obj = new JSONObject();
        String recipientLink=null;
        try {
            obj.put("Username", userName);
            obj.put("Password", password);
            obj.put("IntegratorKey", integratorkey);
            HttpClient httpClient = new DefaultHttpClient();
            HttpGet getRequest = new HttpGet(loginServiceUrl);
            //If proxy is required, else avoid the below  two lines
            HttpHost proxy = new HttpHost(proxyurl, Integer.parseInt(proxyport));
            httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
            
            getRequest.addHeader("X-DocuSign-Authentication", obj.toString());
            HttpResponse responseHttp = httpClient.execute(getRequest);
            BufferedReader rd = new BufferedReader(new InputStreamReader(responseHttp.getEntity().getContent()));
            StringBuffer result = new StringBuffer();
            String line = "";
            int status = responseHttp.getStatusLine().getStatusCode();
            log.info("Base Url Status :"+result);
            JSONObject resJsonObj = new JSONObject();
            if (status == 200) {
                while ((line = rd.readLine()) != null) {
                    result.append(line);
                }
                log.info("result :"+result);
                if (!StringUtils.isEmpty(result.toString())) {
                    JSONObject resObj = new JSONObject(result.toString());
                    JSONArray quote = resObj.getJSONArray("loginAccounts");                 
                    String baseUrl = (String)quote.getJSONObject(0).get("baseUrl");
                    log.info("baseUrl :"+baseUrl);
                    String accountId = (String)quote.getJSONObject(0).get("accountId");
                    log.info("Account Id :"+accountId);
                    String envIdParam = request.getParameter("envelopeId");
                    log.info("userNameParam :"+envIdParam);
                    StringBuffer sb = new StringBuffer();
                    sb.append(serviceBaseUrl+"/restapi/v2/accounts/"+accountId+"");
                    sb.append("/envelopes/"+envIdParam+"");
                    sb.append("/views/recipient");
                    log.info("Envelope Url :"+sb.toString());
                    httpClient = new DefaultHttpClient();
                    HttpPost postReq = new HttpPost(sb.toString());
                    httpClient.getParams().setParameter(ConnRoutePNames.DEFAULT_PROXY, proxy);
                    postReq.addHeader("X-DocuSign-Authentication", obj.toString());
                    postReq.addHeader("Content-Type", "application/json");
                    postReq.addHeader("Accept", "application/json");
                    String userNameParam = request.getParameter("userName");
                    String emailParam = request.getParameter("email");
                    String clientUserIdParam = request.getParameter("clientUserId");
                    String docuSignReturnUrl = request.getParameter("docuSignReturnUrl");
                    log.info("userNameParam :"+userNameParam);
                    log.info("emailParam :"+emailParam);
                    log.info("clientUserIdParam :"+clientUserIdParam);
                    log.info("docuSignReturnUrl :"+docuSignReturnUrl);
                    JSONObject envJson = new JSONObject();
                    envJson.put("userName", userNameParam);
                    envJson.put("email", emailParam);
                    envJson.put("recipientId", 1);
                    envJson.put("routingOrder", 1);
                    envJson.put("clientUserId", clientUserIdParam);
                    envJson.put("authenticationMethod", "email");
                    envJson.put("returnUrl", docuSignReturnUrl);
                    HttpEntity entity = new ByteArrayEntity(envJson.toString().getBytes("UTF-8"));
                    postReq.setEntity(entity);
                    HttpResponse envResponse = httpClient.execute(postReq);
                    log.info("Response Code" + envResponse.getStatusLine().getStatusCode());
                    int envStatus = envResponse.getStatusLine().getStatusCode();
                     log.info("Status :"+envStatus);
                     
                    if(envStatus >= 200 &&  envStatus < 300) {
                     rd = new BufferedReader(new InputStreamReader(envResponse.getEntity().getContent()));
                      StringBuffer result1 = new StringBuffer();
                        String line1 = "";
                        while ((line1 = rd.readLine()) != null) {
                        result1.append(line1);
                    }
                    JSONObject finalJsonObj = new JSONObject(result1.toString());
                     recipientLink = (String) finalJsonObj.get("url");  
                    if(!StringUtils.isEmpty(recipientLink)) {
                        resJsonObj.put("url", recipientLink);
                        log.info("recipientLink: "+recipientLink);
                    }
                    
                  }
                    else{
                        throw new Exception("Docusing status is "+envStatus);
                    }
                } 
            } else {
                resJsonObj.put("status", String.valueOf(status));
            }
            response.setContentType("text/html");
            response.getWriter().write(recipientLink);

        } catch (JSONException e) {
            log.error("Json Exception details :"+ e.toString());
        } catch (Exception e) {
            log.error("Exception details :"+ e.toString());
        }
        log.info("doPost Ended");

    }

    /**
     * default activate method.
     * 
     * @param context
     *            the context
     * @throws Exception
     *             the exception
     */
    @Activate
    protected void activate(ComponentContext context) throws Exception {
        @SuppressWarnings("rawtypes")
        Dictionary properties = context.getProperties();
        loginServiceUrl = (String) properties.get("docusignLoginUrl");
        serviceBaseUrl = (String) properties.get("docuservicebaseurl");     
        userName = (String) properties.get("docuusername");
        password = (String) properties.get("docupassword");
        integratorkey = (String) properties.get("integratorkey");
        proxyurl = (String) properties.get("proxyurl");
        proxyport = (String) properties.get("proxyport");
    }
}

Sample Ajax Call

var signerName = "Kishore Polsani";
var  signerEmail= "kishore.polsani@gmail.com";
var envelopeId = "xxxxxxxxxxxxxxxxxxxxxxxx";
var clientUserId = "xxxxxxxxx";
var docuSignReturnUrl = "https://localhost:5433/content/kishore/docusign.html";
$.ajax({
        type: "GET",
        async: true,
        url: "/services/salesforce/docusignViewRecipientLink ",
        data: {
        userName:signerName,
        email :signerEmail,
        envelopeId :envelopeId,
        clientUserId:clientUserId,
        docuSignReturnUrl:docuSignReturnUrl
        },
        success: function(result) {
        console.log("result" +result);
        window.location.href = result;
        },
        error: function(result) {
        console.log("Docusign Recipient Link" +result);        
        }
     });
Test this API

Saturday, 22 April 2017

Hashmap in Sightly / HTL

Use hashmap in sightly / HTL

WCMUsePojo code
package com.kishore.sightly;

public class GetMap extends WCMUsePojo {
    Map<String, String> myMap = null; 
    @Override
    public void activate() throws Exception {
        myMap = new HashMap<String, String>();
        myMap.put("name", "Kishore");
    }

    public Map<String, String> getmyMap() {
            return myMap;
    }
}

HTL code

<sly data-sly-use.model="com.kishore.sightly.GetMap" />

Name: ${model.myMap['name']}