Saturday, August 31, 2013

Samples on how to use "CloudChoir - Salesforce integration-as-a-service"

Note: all credentials used in following DEMO videos are removed.

1. SF vs. Windows or Windows Azure or Linux - SSH (with password, without SSH cert)
Demo video:
http://youtu.be/KzCPjqHKnk4

Command:
SSH (old name "SSHBridge")

Sample Input XML:
<SSHBridge>
<host>cloudchoir2.cloudapp.net</host>
<port>22</port>
<user>azureuser</user>
<password>ThisIs1Password</password>
<timeout>20000</timeout>
<commandline>ls -l</
commandline>
</
SSHBridge>

Sample (Account) Trigger code:
(see below #2 as reference.) 


2. SF vs. Amazon EC2 VM or others - SSH (without password, with SSH cert in ".pem")
Demo videos:

Command:
SSH

Sample Input XML:

1st sample(XML - no base64. for easy demo.):
<SSHBridge>
    <host>ec2-54-213-54-199.us-west-2.compute.amazonaws.com</host>
    <port>22</port>
    <certfilename >CloudChoirEC2demo.pem</certfilename >
    <user>ubuntu</user>
    <password>-password-not-used</password>
    <timeout>20000</timeout>
    <commandline>ps -ef | grep tty</commandline>
</SSHBridge>
 


  1st sample, partial Trigger code:



            String s_Cred_SSH_Cert = 'CloudChoirEC2demo.pem';
                //Blob tempBlobCertNM = Blob.valueOf(s_Cred_SSH_Cert);
               // s_Cred_SSH_Cert = EncodingUtil.base64Encode(tempBlobCertNM);
            String s_Cred_Name = 'ubuntu';
                //Blob tempBlobCredNM = Blob.valueOf(s_Cred_Name);
                //s_Cred_Name = EncodingUtil.base64Encode(tempBlobCredNM);
            String s_Cred_Password = 'whatever, not used';
                //Blob tempBlobPWD = Blob.valueOf(s_Cred_Password);
                //s_Cred_Password = EncodingUtil.base64Encode(tempBlobPWD);
            String s_Cmd_Timeout = '8000';
            String s_Cmd_Input = 'ps -ef | grep tty';

            String sTemplate = '' +
                '<SSHBridge>' +
                    '<host>{0}</host>' +
                    '<port>{1}</port>'  +
                    '<certfilename>{2}</certfilename>' +
                    '<user>{3}</user>' +
                    '<password>{4}</password>' +
                    '<timeout>{5}</timeout>' +
                    '<commandline>{6}</commandline>' +
                '</SSHBridge>';     





2nd sample (XML - base64 version)
<SSHBridge>
    <host>ec2-54-213-54-199.us-west-2.compute.amazonaws.com</host>
    <port>22</port>
    <certfilename_base64>Q2xvdWRDaG9pckVDMmRlbW8ucGVt</certfilename_base64>
    <user_base64>dWJ1bnR1</user_base64>
    <password_base64>cGFzc3dvcmQtbm90LXVzZWQ=</password_base64>
    <timeout>20000</timeout>
    <commandline>ps -ef</commandline>
</SSHBridge>


2nd sample (Apex Trigger - base64 version)
2nd Sample (Account) full Trigger code:

  trigger AccountOutboundMessageTrigger on Account (after insert, after update) {     if (Trigger.isInsert)     {         for (Account acct : Trigger.new)         {             //following variables' values will be provided by either customer fields in Account or from some other related record in this Trigger,             //for DEMO purpose, I hard coded most of them             String s_AcctName = Trigger.new[0].Name;                        String sTableName = 'account';             String sColumnName = 'Description';              String sRecordID = Trigger.new[0].Id;             String sCommand = 'SSH';                          String s_Node_Address = 'ec2-54-213-54-199.us-west-2.compute.amazonaws.com';              String s_Node_Port = '22';             String s_Cred_SSH_Cert = 'CloudChoirEC2demo.pem';                                  Blob tempBlobCertNM = Blob.valueOf(s_Cred_SSH_Cert);                 s_Cred_SSH_Cert = EncodingUtil.base64Encode(tempBlobCertNM);                               String s_Cred_Name = 'ubuntu';                 Blob tempBlobCredNM = Blob.valueOf(s_Cred_Name);                 s_Cred_Name = EncodingUtil.base64Encode(tempBlobCredNM);                         String s_Cred_Password = 'whatever, not used';                 Blob tempBlobPWD = Blob.valueOf(s_Cred_Password);                 s_Cred_Password = EncodingUtil.base64Encode(tempBlobPWD);              String s_Cmd_Timeout = '8000';             String s_Cmd_Input = 'ps -ef | grep tty';                          String sTemplate = '' +                 '<SSHBridge>' +                     '<host>{0}</host>' +                         '<port>{1}</port>'  +                        '<certfilename_base64>{2}</certfilename_base64>' +                        '<user_base64>{3}</user_base64>' +                        '<password_base64>{4}</password_base64>' +                       '<timeout>{5}</timeout>' +                       '<commandline>{6}</commandline>' +                   '</SSHBridge>';                  String[] arguments = new String[] {s_Node_Address, s_Node_Port, s_Cred_SSH_Cert, s_Cred_Name, s_Cred_Password, s_Cmd_Timeout, s_Cmd_Input};             String sInputString = String.format(sTemplate, arguments);                          String sCreatedRecordID= '';             try             {                      cloudchoir__Integration__c aIntegration  = new cloudchoir__Integration__c();                    //name                   aIntegration.Name = s_AcctName;                    //callback                   aIntegration.cloudchoir__Callback_Table_Name__c = sTableName;                   aIntegration.cloudchoir__Callback_Column_Name__c = sColumnName;                    aIntegration.cloudchoir__Callback_Record_ID__c = sRecordID;                                    //input                   aIntegration.cloudchoir__Security__c = 'n/a';                   aIntegration.cloudchoir__Command__c = sCommand;                                     aIntegration.cloudchoir__Param__c = sInputString;                                  insert aIntegration;                   //keep relationship here                                   sCreatedRecordID = aIntegration.Id;             }catch (DmlException e) {                 sCreatedRecordID = 'N/A';             }                         break;         }     }     else if (Trigger.isUpdate)     {         if (Trigger.new[0].Description != Trigger.old[0].Description)  //thus no infinite loop         {             String sCurrentRecordID = Trigger.new[0].Id;             List<cloudchoir__Integration__c> l_child = [SELECT Id FROM cloudchoir__Integration__c WHERE cloudchoir__Callback_Record_ID__c =: sCurrentRecordID];             if (null != l_child && l_child.size()>0)             {                 delete l_child; //remove the 'temp' Integration record. (no need this delete, if you choose to keep it.)             }         }             } }



3. SF vs. Windows Batch
Demo video:
http://youtu.be/s3WO2-dXeqY

Command:
SSH

Sample Input XML:
<root>
<host>74.61.134.120</host>
<port>2222</port>
<user>DemoUser1</user>
<password>TempPa$$w0rd</password>
<timeout>20000</timeout>
<commandline>cmd /c c:\temp\list.bat</
commandline>
</root>


The content in "c:\temp\list.bat", it has only one line:
cmd /c dir c:\temp

Sample Trigger code:
(see above #2 as reference.) 

4. SF vs. Windows PowerShell
Demo video:
http://youtu.be/QhMhFvATPJI

Command:
POWERSHELL

Sample Input XML:
<root>
<host>74.61.134.120</host>
<port>2222</port>
<user>DemoUser1</user>
<password>TempPa$$w0rd</password>
<timeout>20000</timeout>
<powershell>Get-Service</powershell>
</root>


Sample Trigger code:
(see above #2 as reference.) 

5. SF vs. any external Java framework or library (Jar)
Anyone can test run this with his/hers existing Facebook token. (the sample input one is a valid one but expired.)

Demo video:
http://youtu.be/VItGaFwoEaE

Java framework for Facebook:
http://restfb.com/

Java/Groovy source code deployed:
import java.util.List;
import com.restfb.Connection;
import com.restfb.DefaultFacebookClient;
import com.restfb.FacebookClient;
import com.restfb.types.User;
import groovy.util.XmlSlurper
//Integration Pack - parent class
class RestFB {
    static String IntegrationCall(String jInput) throws Exception{
        return RestFBJava.ListFBFriends(jInput)
    }

}
class RestFBJava
{
    public static String ListFBFriends(String MY_ACCESS_TOKEN)
    {
        FacebookClient facebookClient = new DefaultFacebookClient(MY_ACCESS_TOKEN);
        Connection<User> myFriends = facebookClient.fetchConnection("me/friends", User.class);
        List<User> lUser = myFriends.getData();
        String sRet = "Friend count(" + myFriends.getData().size() + "):";
        for(int i=0; i< lUser.size(); i++)
        {
            sRet += lUser.get(i).getName() + ";";
        }
        return sRet;
    }
}


Command:  
RestFB

Sample Input: CAACSazocXasBAHW7fZA9tz7lVbhHmJIiPTN7SfQf5bCrxaspnRoAtJhqV57WoHFMLAfgMuJfLRze3QLKjF5CEZAckyeqzRm9UaYuKhgH2p4UZBxvMu8ZA5WLic1s5rl6ZBGliMkUEKtnXFOhcoDMPIleAIEL7T68A1oIbDfITgBKd14KIyZBSR5itiQ1ZAhs6ZADqCU83LiolwZDZD

Sample Trigger code:
trigger AccountCloudchoirRestFB on Account (after insert, after update) {
    if (Trigger.isInsert)
    {
        for (Account acct : Trigger.new)
        {
            String s_AcctName = Trigger.new[0].Name;          
            String sTableName = 'account';
            String sColumnName = 'Description';
            String sRecordID = Trigger.new[0].Id;
            String sCommand = 'RestFB';        
            String sInputString = Trigger.new[0].Description; 
           
            String sCreatedRecordID= '';
            try
            {  
                  cloudchoir__Integration__c aIntegration  = new cloudchoir__Integration__c();
                  //name
                  aIntegration.Name = s_AcctName;
                  //callback
                  aIntegration.cloudchoir__Callback_Table_Name__c = sTableName;
                  aIntegration.cloudchoir__Callback_Column_Name__c = sColumnName;
                  aIntegration.cloudchoir__Callback_Record_ID__c = sRecordID;                
                  //input
                  aIntegration.cloudchoir__Security__c = 'n/a';
                  aIntegration.cloudchoir__Command__c = sCommand;                 
                  aIntegration.cloudchoir__Param__c = sInputString;              
                  insert aIntegration;
                  //keep relationship here               
                  sCreatedRecordID = aIntegration.Id;
            }catch (DmlException e) {
                sCreatedRecordID = 'N/A';
            }           
            break;
        }
    }
    else if (Trigger.isUpdate)
    {
        if (Trigger.new[0].Description != Trigger.old[0].Description)  //thus no infinite loop
        {
            String sCurrentRecordID = Trigger.new[0].Id;
            List<cloudchoir__Integration__c> l_child = [SELECT Id FROM cloudchoir__Integration__c WHERE cloudchoir__Callback_Record_ID__c =: sCurrentRecordID];
            if (null != l_child && l_child.size()>0)
            {
                delete l_child; //remove the 'temp' Integration record. (no need this delete, if you choose to keep it.)
            }
        }       
    }
}



6. SF query Emails (demo)
Demo video:
http://youtu.be/QYL-g2I4Yuc

Command:

Sample Input XML:

Sample Trigger code:
(see above #1 and #2) 
7. SF query Linkedin (demo)
Demo video:
http://youtu.be/QYL-g2I4Yuc

Command:

Sample Input XML:

Sample Trigger code:
(see above #1 and #2) 
8. SF query Facebook (demo)
Demo video:
http://youtu.be/bafj6rof_BM

Command:

Sample Input XML:

Sample Trigger code:
(see above #1 and #2)

Sunday, August 18, 2013

CRM Integration: Salesforce vs. Facebook using "RestFB" framework in Java

YouTube DEMO video:
http://youtu.be/bafj6rof_BM
How to develop (utilizing the full power of  Java/Groovy) and deploy (into cloud) a Salesforce external extension and integration in 3 minutes 

(Part 2: consume the Integration Pack, from Account trigger.)


YouTube DEMO video:
http://youtu.be/KaubGkES6eY

Tech Notes
"CloudChoir - Integration Foundation" created a Customer Object called "Integration", it servers as "Outbound Message" hub, thus all your integrations will go through it. Thus you DO NOT need to create Outbound Message and related trigger workflow for each Standard Object and Customer Object individually, in order to get them integrated... our "Integration Foundation" did them all for your easy use.

In this DEMO, I will show you how easy it is, to develop a simple Account APEX trigger, to utilize our integration framework... it could be calling Customer Java code, or SSH call (JSch in our server), or even SOAP call (Axis2 in our server) or REST call (Restlet in our server),  all through Outbound Message, thus no worry about "Callout governor and limit".

Email: admin@konafornia.com
(I am currently looking for Salesforce dev job and/or sub contracts. thx!)

__________________________________________________
Reference: APEX trigger source code (used in above DEMO):
trigger AccountOutboundMessageTrigger on Account (after insert, after update) {
    if (Trigger.isInsert)
    {
        for (Account acct : Trigger.new)
        {
            String sInput = '<root><title>' + Trigger.new[0].Name + '</title><fullname>' + Trigger.new[0].Phone + '</fullname></root>';
            Trigger2Cloudchoir cc = new Trigger2Cloudchoir();
            String sChildRecordID = cc.CreateCloudChoir(acct.Name + '(temp)', 'account', 'Description', acct.Id, '-security-', 'HelloWorld', sInput);  
            break;
        }
    }
    else if (Trigger.isUpdate)
    {
        if (Trigger.new[0].Description != Trigger.old[0].Description)  //thus no infinite loop
        {
            String sCurrentRecordID = Trigger.new[0].Id;
            List<cloudchoir__Integration__c> l_child = [SELECT Id FROM cloudchoir__Integration__c WHERE cloudchoir__Callback_Record_ID__c =: sCurrentRecordID];
            if (null != l_child && l_child.size()>0)
            {
                delete l_child; //remove the 'temp' Integration record. (no need this delete, if you choose to keep it.)
            }
        }       
    }
}


Monday, August 05, 2013

How to develop (utilizing the full power of  Java/Groovy) and deploy (into cloud) a Salesforce external extension and integration in 3 minutes

(Part 1: develop and debug an Integration Pack)

- "NO Callout Execution Governors and Limits"(right! because it is based on Outbound Message.)

YouTube demo:
http://youtu.be/Z5YTqa0bm6M

Tech notes:
1. Outbound Message based solution, thus no worry about "Apex Callout Execution Governors and Limits " or "Apex Trigger Execution Governors and Limits".
2. Full Java (Groovy) power, including debugging Groovy/Java using IDEs such as Eclipse/Netbeans.
3. Utilizing existing Java (Groovy) framework/library such as Apache Commons, Restlet, Axis2, Jsch, JDBC, BigData, UnboundID, ... etc. And... utilizing your Java developers.
4. If you prefer, Java debug can be done 100% inside Salesforce.
5. HTTPs and SSH based security.

Use cases and value:
1. "NO Execution Governors and Limits" (the same as "NO Software") - for example, if some piece of Apex code is blocked by your instance's "Execution Governors and Limits", ... you could pack that logic into Java/Groovy code and deploy it into CloudChoir's "Integration server" (hosted in Amazon EC2 cloud or Windows Azure cloud).
2. Develop external customer integration logic( "Integration Pack") specifically for your org or instance, callable from such as Trigger.
3. Your Extensions or Integrations can serve for your own use, or to be published and marketed($$$) to other Salesforce users.

Dependency:
1. Free AppExchange app: CloudChoir - Saleforce Integration Foundation (submitted to AppExchange for review. developed also by Konafornia LLC.)
2. Java/Groovy runtime.
3. Optional: the ".jar" library your code used; the SSH cert in ".pem" format.

Tool:
Groovy IDE of your choice: such as Eclipse or NetBeans

Email: admin@konafornia.com
(I am currently looking for Salesforce dev job and/or sub contracts. thx!)

______________________________________________
Reference: Java/Groovy source code used in this DEMO:
 import groovy.util.XmlSlurper
//Integration Pack - parent class
class HelloWorld {
    static String IntegrationCall(String jInput) throws Exception{
        def gInput = new XmlSlurper().parseText(jInput)
        def title = gInput."title".text()
        def fullname = gInput."fullname".text()
        return myJavaClass.sGreet(title, fullname)
    }
    public static void main(String[] args) {
        String sInput =    "<root><title>Mr</title><fullname>Stanley He</fullname></root>";
        String sReturn = this.IntegrationCall(sInput);
        System.out.println(sReturn); //see the result
    }
}

//Java class, to consume whatever Java Jar
class myJavaClass
{
    public static String sGreet(String sTitle, String sName)
    {
        return "Hello(v1): " + sTitle + " " + sName;
    }
}
CRM Integration: Salesforce.com vs. Windows PowerShell

YouTube DEMO:
http://youtu.be/SYNQqf_o_MQ

Key design:
1. Salesforce trigger -> Cutomer Object -> Outbound Message -> "CloudChoir" -> SSH ->... whatever behind SSH.
2. NOT using Salesforce Apex callout, so the Callout "runtime governor limit" is not an issue.

Use cases:
1. Any Private cloud and local corp network Apps (such as Windows Server, or SharePoint, or Exchange,  Database, SCOM, ...etc) with SSH as gateway. Either VMs or physical boxes.
2. Any Public cloud VMs, such as Windows Azure VM, Amazon EC2 VM, ... etc. (same, any App accessible from Windows Batch or PowerShell.)

Dependency:
1. Free AppExchange app: CloudChoir - Saleforce Integration Foundation (under AppExchange review. developed also by Konafornia LLC.)
2. A web facing SSH/PowerShell endpoint: Power Shell Server (recommended) or OpenSSH Server (free)

Email: admin@konafornia.com
(I am currently looking for Salesforce dev job and/or sub contracts. thx!)
CRM Integration: Salesforce.com vs. Amazon EC2

YouTube DEMO:


Dependency:
1. Free AppExchange app: CloudChoir - Saleforce Integration Foundation (under AppExchange review. developed also by Konafornia LLC.)
2. Amazon EC2 account with OpenSSH Server installed. (optional SSH cert in ".pem" format.)

Email: admin@konafornia.com
(I am currently looking for Salesforce dev job and/or sub contracts. thx!)
CRM Integration: Salesforce.com vs. Oracle VirtualBox

YouTube DEMO:
http://youtu.be/1chMx9foh1M

Dependency:
1. Free AppExchange app: CloudChoir - Saleforce Integration Foundation (under AppExchange review. developed also by Konafornia LLC.)
2. VirtualBox server, of course.

Email: admin@konafornia.com
(I am currently looking for Salesforce dev job and/or sub contracts. thx!)
CRM Integration: Salesforce.com vs. Windows Azure VM

YouTube DEMO:
http://youtu.be/KzCPjqHKnk4

Dependency:
1. Free AppExchange app: CloudChoir - Saleforce Integration Foundation (under AppExchange review. developed also by Konafornia LLC.)
2. Windows Azure VM, with SSH Server installed and its port open. (optional SSH cert in ".pem" format.)

Email: admin@konafornia.com
(I am currently looking for Salesforce dev job and/or sub contracts. thx!)

Konafornia

Konafornia LLC is a Seattle/Bellevue USA based, software developing and consulting company.
Email: admin@konafornia.com
Skype: konafornia
Phone: 425-562-5196