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 - userNameemailrecipientId, 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']}

Integrate AEM with Docusign - Part 1

Integrate AEM with Docusign to get Docusign account information

What is Docusign?

DocuSign® is The Global Standard for Digital Transaction Management. Accessible anytime, anywhere on any device, global enterprises, business departments, individual professionals, and consumers in all industries solve their paper problems by replacing manual, paper-based methods with DocuSign. The result is accelerated transactions that increase speed to results, reduce costs, improve visibility and control, and delight customers. DocuSign helps you keep business digital with the easiest, fastest, most secure way to send, sign, manage and store documents in the cloud.

Why Docusign?



Thursday, 20 April 2017

Different ways to get AEM admin session

Method 1:

AEM admin session can be obtained using below method but this is deprecated


@Reference
private SlingRepository repository;
adminSession = repository.loginAdministrative(null);


Method 2:

Another way to get the session (not the recommended way)
Session session = repository.login(new SimpleCredentials("admin",
      "admin".toCharArray()),"crx.default");

Method 3:

@Reference
 public ResourceResolverFactory rrFactory;

ResourceResolver adminResolver = rrFactory.getAdministrativeResourceResolver(null);        
Session adminSession = adminResolver.adaptTo(Session.class);

Method 4:

Map<String, Object> param = new HashMap<String, Object>();
param.put(ResourceResolverFactory.SUBSERVICE, "jqom");
ResourceResolver resolver = null;          
        try {                     
            //Invoke the getServiceResourceResolver method to create a Session instance
            resolver = resolverFactory.getServiceResourceResolver(param);
            session = resolver.adaptTo(Session.class);
           }

See Community Article

Method 5:

You can create a user and assign it to the administrative group and use it's credentials rather than the default admin user.
You may also want to take a look at this article which goes over using the correct resource resolver in AEM 6.

Tuesday, 18 April 2017

Deploy AEM bundles and packages using Maven

Setup Maven

You can use Maven to build an OSGi bundle that uses the QueryBuilder API and is deployed to Experiene Manager. Maven manages required JAR files that a Java project needs in its class path. Instead of searching the Internet trying to find and download third-party JAR files to include in your project’s class path, Maven manages these dependencies for you.
You can download Maven 3 from the following URL:
After you download and extract Maven, create an environment variable named M3_HOME. Assign the Maven install location to this environment variable. For example:
C:\Programs\Apache\apache-maven-3.0.4
Set up a system environment variable to reference Maven. To test whether you properly setup Maven, enter the following Maven command into a command prompt:
%M3_HOME%\bin\mvn -version
This command provides Maven and Java install details and resembles the following message:
OS name: "windows 7", version: "6.1", arch: "amd64", family: "windows"

Monday, 17 April 2017

Cannot create maven project

When trying to create maven project using multi module content package archetype we may get exception

Maven command to create project:

mvn archetype:generate -DarchetypeRepository=https://repo.adobe.com/nexus/content/groups/public/ -DarchetypeGroupId=com.day.jcr.vault -DarchetypeArtifactId=multimodule-content-package-archetype -DarchetypeVersion=1.0.2 -DgroupId=com.mycompany.myproject.htl -DartifactId=htl -Dversion=1.0-SNAPSHOT -Dpackage=com.mycompany.myproject.htl -DappsFolderName=myproject -DartifactName="My Project" -DcqVersion="5.6.1" -DpackageGroup="My Company"

Exception:

Caused by: org.apache.maven.plugin.MojoFailureException: The desired archetype does not exist (com.day.jcr.vault:multimodule-content-package-archetype

Resolution:

Check the settings.xml under .m2 folder.

Sunday, 16 April 2017

Adobe Salesforce Connector - INVALID_SESSION_ID

Issue:

I have integrated AEM with Salesforce using salesforce cloud config. I am able to connect to salesforce successfully and able to pull data from salesforce. After sometime when I access aem page am getting error below
[{"message":"Session expired or invalid","errorCode":"INVALID_SESSION_ID"}]  
I have also checked below settings in salesforce
  • Session timeout after 4 hours of inactivity
  • Selecte OAuth scopes
    •  Perform requests on your behalf at any time (refresh_token, offline_access)
    • Access and manage your data (api)
    • Full Access (Full)

Resolution:

In sales force we need to remove Full Access (Full) OAuth Scopes, if we use this then refresh token will not be effective.

Friday, 14 April 2017

AEM: design and preview mode toolbar not visible

Issue
If you are using the sidekick on an author instance of CQ, you may notice that the toolbar at the bottom which includes the design and preview mode buttons, is not visible or available.
Reason
The functionality in the sidekick is determined by the ACLs (Access-Control-Lists) defined in the CQ server.  If you do not have the appropriate privileges then functionality may be hidden in your sidekick.  Sometimes the sidekick may become unstable if you add faulty components to the page, or after you have installed some packages that may have overwritten required objects in your application, breaking some dependencies.

Solution
You should first try to clear your browser cache, and then reload the page from WCM console to refresh the sidekick.
You should also ensure you have the correct privileges to access the appropriate design in /etc/designs.  This can be changed by an administrator on the Users tab in the siteadmin console.  If the privileges appear to be correct, then try to disable them, save, and then re-enable them and save.  The sidekick should now display the toolbar again as expected.

To display the design button on the sidekick enable Modify permission for etc path.

Thursday, 13 April 2017

Lazybones - Project Creation Tool

Lazybones was born out of frustration that Ratpack does not and will not have a command line tool that will bootstrap a project. It's a good decision for Ratpack, but I'm lazy and want tools to do the boring stuff for me.
The tool is very simple: it allows you to create a new project structure for any framework or library for which the tool has a template. You can even contribute templates by sending pull requests to this GitHub project or publishing the packages to the relevant Bintray repository (more info available below).
The concept of Lazybones is very similar to Maven archetypes, and what Yeoman does for web applications. Lazybones also includes a sub templates feature that resembles the behaviour of Yeoman's sub-generators, allowing you to generate optional extras (controllers, scaffolding etc.) inside a project.

Encrypting and Decrypting String in Java

The Advanced Encryption Standard (AES), also known by its original name Rijndael (Dutch pronunciation: [ˈrɛindaːl]),[5][6] is a specification for the encryption of electronic data established by the U.S. National Institute of Standards and Technology (NIST) in 2001.[7]

Below is sample java code to encrypt and decrypt a string.


package com.kishore;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

import org.apache.commons.codec.binary.Base64;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class Encrypt {

    protected final Logger LOGGER = LoggerFactory.getLogger(this.getClass());
    
    public static void main(String[] args) {
        String encryptString = "45634634";
        final String KEY = "kishore";
        Encrypt obj = new Encrypt();
        String encryptedString = obj.encrypt(encryptString, obj.encryptSecretKey(KEY));
        System.out.println("encryptedString: "+encryptedString);        
        String decyptedString = obj.decrypt(encryptedString, obj.encryptSecretKey(KEY));
        System.out.println("decyptedString: "+decyptedString);
    }
    public SecretKeySpec encryptSecretKey(final String secretKey) {
        MessageDigest sha = null;
        SecretKeySpec encryptApiSecret = null;
        try {
            byte[] key = secretKey.getBytes("UTF-8");
            sha = MessageDigest.getInstance("SHA-1");
            key = sha.digest(key);
            key = Arrays.copyOf(key, 16);
            encryptApiSecret = new SecretKeySpec(key, "AES");
        } catch (final NoSuchAlgorithmException e) {
            LOGGER.error("Exception occurred in encryptApiSecret",e);
        } catch (final UnsupportedEncodingException e) {
            LOGGER.error("Exception occurred in encryptApiSecret",e);
        }
        return encryptApiSecret;
    }
    
    public String decrypt(final String strToDecrypt, final SecretKeySpec secretKey) {
        String decryptedApiKey = "";
        try {
            final Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            cipher.init(Cipher.DECRYPT_MODE, secretKey);
            byte[] c = Base64.decodeBase64(strToDecrypt.getBytes("UTF-8"));
            decryptedApiKey = new String(cipher.doFinal(c));
        } catch (final Exception e) {
            LOGGER.error("Exception occurred in decrypt",e);
        }
        return decryptedApiKey;
    }

    public String encrypt(final String strToDecrypt, final SecretKeySpec secretKey) {
        String encryptedApiKey = "";
        try {
            final Cipher cipher = Cipher.getInstance("AES/ECB/PKCS5PADDING");
            cipher.init(Cipher.ENCRYPT_MODE, secretKey);
            byte[] c = cipher.doFinal(strToDecrypt.getBytes());
            encryptedApiKey = new String(Base64.encodeBase64(c));
        } catch (final Exception e) {
            LOGGER.error("Exception occurred in encrypt",e);
        }
        return encryptedApiKey;
    }

}


Tuesday, 11 April 2017

AEM Component is in satisfied state, not in active

Some times we face OSGI component is in active state when the component is installed for the first time. When we modify the component from configMgr, component state changes to satisfied.

To avoid this and make the component in active state add the annotation @Activate to the activate method. This helps in changing the component state to Active whenever the component is modified.

Saturday, 8 April 2017

Salesforce REST API implementation - JAVA

This post demonstrates the following basic use cases for the REST API:
- authentication with OAuth 2.0 (This is for development purposes only. Not a real implementation.)
- querying (using account records)
- inserting (using a contact record related to one of the retrieved account records)
- updating (updates contact record added in previous step)

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.IOException;
import java.io.UnsupportedEncodingException;

import org.apache.http.Header;
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.entity.StringEntity;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.message.BasicHeader;
import org.apache.http.util.EntityUtils;

import org.json.JSONException;
import org.json.JSONObject;