Tuesday, July 11, 2017

Trigger and it's handler class example with design pattern.

Please check my previous post (Trigger and it's handler class structure for your organisation.), where I mentioned the architectural structure to design or handle trigger for your organisation.

For the same you should have the below apex classes and trigger,

1. TriggerHandlerException class [Handled exception].
2. TriggerHandler class [An abstract class where all trigger related operations have been structured as a template].
3. TriggerFactory class [Factory of Concrete Trigger Handler classes].
4. TriggerWorker class [This is the worker class for trigger. Each and every trigger just call "executeTrigger()" method of this worker class].
5. ConcreteTriggerHandler class [This is the main handler class, where the actual logic will be define and this class extend TriggerHandler abstract class and defined all abstract method].
6. Trigger for an SObject [From here only call the "executeTrigger()" method of this TriggerWorker class with string parameter as "ConcreteTriggerHandler class name"].


Suppose we want to create a trigger of Account object, then the source code will be as follows,

1. TriggerHandlerException
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2017
 *
 * Description : This is custom exception calss and fire while trying to create an
 * handler instance which is not registered.
 *.
 */
public class TriggerHandlerException extends Exception {}

2. TriggerHandler
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2016
 *
 * Description : This abstract class is responsible to create a template to handle trigger operations.
 *               All Trigger Handlers must implement to enforce best practice.
 */
public abstract class TriggerHandler{
    //Template method
    public void doExecute(){
        // Before Trigger
        if (Trigger.isBefore){
            // Iterate through the records to be deleted passing them to the handler.
            if (Trigger.isDelete)
            {
                beforeDelete(Trigger.old, Trigger.oldMap);
            }
            // Iterate through the records to be inserted passing them to the handler.
            else if (Trigger.isInsert)
            {
                beforeInsert(Trigger.new);
            }
            // Iterate through the records to be updated passing them to the handler.
            else if (Trigger.isUpdate)
            {
                List<SObject> lstOfNewSo = new List<SObject>();
                for (SObject so : Trigger.old)
                {
                    lstOfNewSo.add(Trigger.newMap.get(so.Id));                        
                }
                beforeUpdate(Trigger.old, lstOfNewSo, Trigger.oldMap, Trigger.newMap);
            }

        } else { // After Trigger
            // Iterate through the records deleted passing them to the handler.
            if (Trigger.isDelete)
            {
                afterDelete(Trigger.old, Trigger.oldMap);
            }
            // Iterate through the records inserted passing them to the handler.
            else if (Trigger.isInsert)
            {
                afterInsert(Trigger.new, Trigger.newMap);
            }
            // Iterate through the records updated passing them to the handler.
            else if (Trigger.isUpdate)
            {
                List<SObject> lstOfNewSo = new List<SObject>();
                for (SObject so : Trigger.old)
                {
                    lstOfNewSo.add(Trigger.newMap.get(so.Id));
                }
                afterUpdate(Trigger.old, lstOfNewSo, Trigger.oldMap, Trigger.newMap);
            }
    
        }
    }
    //############################### After operations ###############################
    /*
     * This method is called iteratively for each record inserted during an AFTER trigger.
     */
    
    //@TestVisible
    abstract void afterInsert(List<SObject> lstOfNewSo, map<id,SObject> mapOfNewSo);
    /*
     * This method is called iteratively for each record updated during an AFTER trigger.
     */
    
    
    abstract void afterUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo);
    /*
     * This method is called iteratively for each record deleted during an AFTER trigger.
     */
    
    
    abstract void afterDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo);
    //############################### Before operations ###############################
    /*
     * This method is called iteratively for each record inserted during an BEFORE trigger.
     */
    
    
    abstract void beforeInsert(List<SObject> lstOfNewSo);
    /*
     * This method is called iteratively for each record updated during an BEFORE trigger.
     */
    
    
    abstract void beforeUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo);
    /*
     * This method is called iteratively for each record deleted during an BEFORE trigger.
     */
    
    
    abstract void beforeDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo);
}

3. TriggerFactory
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2016
 *
 * Description : This is a factoy class of all triggers, existes in this ORG. This factory is responsible for
 *               creating factory of trigger handler class.
 */
public with sharing class TriggerFactory{
    /*
     * This method return instance of TriggerHandler.
     * Arguments:   String className - Name of handler class in string format.
     * Return triggerHandler : Instance of trigger handler class.
     *  
     */
    public static TriggerHandler getHandlerInstance(String className){
        TriggerHandler handler = getHandler(className);
        // Make sure we have a handler registered, new handlers must be registered in the getHandler method.
        if (handler == null){
            throw new TriggerHandlerException('No Trigger Handler registered of name : ' + className);
        }        
        return handler;
    }
    
    /*
     * private static method to get the appropriate handler for the object type.
     * Modify this method to add any additional handlers.
     * Arguments:   String className - Name of handler class in string format.
     * Returns:     A trigger handler if one exists or null.
     */
    private static TriggerHandler getHandler(String className){
        if (className != null && className.trim().length() > 0){
            Type t = Type.forName(className);
            return (TriggerHandler) t.newInstance();
        }        
        return null;
    }
}

4. TriggerWorker
/*
 * Author : Arun Kumar Hazra
 * Date : 16-NOV-2016
 *
 * Description : This is the first entry point for each trigger.
 *.
 */
global with sharing class TriggerWorker{
    /*
     * This static method is responsible to execute trigger logic with help of handler class.
     * Arguments:   String className - Name of handler class in string format.
     *  
     */
    global static void executeTrigger(String className){
        TriggerHandler handler = TriggerFactory.getHandlerInstance(className);
        handler.doExecute();
    }
}


5. AccountTriggerHandler  (ConcreteTriggerHandler class)
/**
* Trigger Handler class for Expense Detail Objcet.
*
**/
public class AccountTriggerHandler extends TriggerHandler{
    // ########### Start of defining abstract methods of Trigger Handler abstract class ###########
    public void afterInsert(List<SObject> lstOfNewSo, map<id,SObject> mapOfNewSo){
        sampleMethod(lstOfNewSo);
    }
    
    public void afterUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo){
        
    }
    
    public void afterDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo){
        
    }
    
    public void beforeInsert(List<SObject> lstOfNewSo){
        
    }
    
    public void beforeUpdate(List<SObject> lstOfOldSo, List<SObject> lstOfNewSo, map<id,SObject> mapOfOldSo, map<id,SObject> mapOfNewSo){
        
    }
    
    public void beforeDelete(List<SObject> lstOfOldSo, map<id,SObject> mapOfOldSo){
        
    }
    // ########### End of defining abstract methods of Trigger Handler abstract class ###########
    
    /* here create private method(s) to perform your operation and call that method(s) 
     * from above template method based on the scenario. Suppose we need perform an 
     * operation after a record insertion, so create a private method say sampleMethod() and 
     * call it from above afterInsert() method. */

   private void sampleMethod(lstOfNewSo){
        //Perform your logic.
   }
       
}

6. AccountTrigger

trigger AccountTrigger on Account(after insert, after update, after delete, before insert, before update, before delete) {
   // Method parameter as concrete trigger handler class name.
   TriggerWorker.executeTrigger('AccountTriggerHandler');
}

Thursday, June 29, 2017

Trigger and it's handler class structure for your organisation.

This is a sample structure to make your organization's triggers and their's handler class in a maintainable way. Check the coding example in next post.


Scheduler class example for batch apex.

Assume that our ORG has a custom object API named as "Product_Complaint__c".
Our aim is to schedule a batch apex which will responsible for make a select query on Product_Complaint__c object.

/**
 * This is a batch class.
 * https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_batch_interface.htm
 **/
global class BatchClassExample implements Database.Batchable<sObject>{
  global String query;

  global Database.QueryLocator start(Database.BatchableContext BC){
      return Database.getQueryLocator(query);
    }

    global void execute(Database.BatchableContext BC, List<sObject> scope){
       List<Product_Complaint__c> lstOfPC = (List<Product_Complaint__c>)scope;

       // Call any helper calss to do the logic.
       System.debug('Test PC Size ::::::::::::: ');
       System.debug('PC Size ::::::::::::: '+ lstOfPC.size());
   }


    global void finish(Database.BatchableContext BC){
    }
}


/**
 * This is a scheduler class example for batch apex.
 * This class implements the Schedulable interface for a class called AffectedScheculeClassExample.
 * 
 * Link: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm
 **/
global class ScheduledBatchClassExample implements Schedulable {
  //This is implemented method and it must be declared as global or public.
  global void execute(SchedulableContext sc) {
    BatchClassExample batchInst = new BatchClassExample();
    batchInst.query = 'SELECT Id FROM Product_Complaint__c';
    database.executebatch(batchInst, 1);
  }
}


/**
 * This class is responsible for calling ScheduledBatchClassExample class to run the scheduler.
 * Call this class constractor from anonymous window.
 *
 **/
public class CallScheduledBatchClassExample
{
  //Constructor need to be call from annonymous window to run the schedule job.
  public CallScheduledBatchClassExample(){
    ScheduledBatchClassExample schBatchClsExmpl = new ScheduledBatchClassExample();
    /**
      *  Schedule structure:
      *  <Seconds> <Minutes> <Hours> <Day_of_month> <Month> <Day_of_week> <Optional_year>
      *
      * For below example it will schedulw the job @ 08:23 AM every day.
    */
    String sch = '0 23 8 * * ?';
    String schJobID = system.schedule('Scheduler Batch Example', sch, schBatchClsExmpl);
  }
}

To test this example instantiate CallScheduledBatchClassExample() 
from anonymous window as,
CallScheduledBatchClassExample inst = new CallScheduledBatchClassExample
();

Apex Scheduler Example.

Check the class descriptions .....


/**
 * This is a simple class called from scheduler class.
 *
 **/
public class AffectedScheculeClassExample {
  public AffectedScheculeClassExample() {
    System.debug('Calling from scheduler class for testing ...... ');
  }
}


/**
 * This is a scheduler class example.
 * This class implements the Schedulable interface for a class called AffectedScheculeClassExample.
 * 
 * Link: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_scheduler.htm
 **/
global class ScheduledClassExample implements Schedulable {
  //This is implemented method and it must be declared as global or public.
  global void execute(SchedulableContext sc) {
    AffectedScheculeClassExample affectedSchClassExmpl = new AffectedScheculeClassExample();
  }
}


/**
 * This class is responsible for calling scheduler class named as ScheduledClassExample to run at schedule time.
 * Call this class constractor from anonymous window.
 **/
public class CallScheduledClassExample {
  //Constructor need to be call from annonymous window to run the schedule job.
  public CallScheduledClassExample(){
    ScheduledClassExample schClsExmpl = new ScheduledClassExample();
    /**
      *  Schedule structure:
      *  <Seconds> <Minutes> <Hours> <Day_of_month> <Month> <Day_of_week> <Optional_year>
      *
      * For below example it will schedulw the job @ 02:28 AM every day.
    */
    String sch = '0 28 2 * * ?';
    String schJobID = system.schedule('Scheduler Example', sch, schClsExmpl);
  }
}

To test this example instantiate CallScheduledClassExample() 
from anonymous window as,
CallScheduledClassExample inst = new CallScheduledClassExample();

Friday, June 16, 2017

apex:actionSupport with apex:param example.

1. Create apex class as below example.


/**
 * Controller class for actionSupport with passing parameter example.
 *
 **/
public with sharing class ActionSupportExamCtrl
{
 //Variable responsible for holding param value assigned in from VF.
 public String param1{get;set;}

 //action method called from actionFunction.
 public void method1(){
  System.debug('Parameter passed is '+ param1);
 }
}

2.Create VF as below example.

<apex:page  controller="ActionSupportExamCtrl">
<apex:form id="formId">
<!-- apex:actionSupport with apex:param -->
<apex:inputCheckbox>
   <apex:actionSupport action="{!method1}" event="onclick" rerender="formId">
<apex:param assignTo="{!param1}" name="prmNm" value="[ Your param value ]"/>
</apex:actionsupport>
</apex:inputCheckbox>
Click on checkbox to pass parameter from action support.
    </apex:form>
</apex:page>

apex:actionFunction with apex:param example.

1. Create an apex class as below example.
/**
 * Controller class for actionFunction with passing parameter example.
 *
 **/
public with sharing class ActionFunctionExmpCtrl
{
 //Variable for input text used in VF.
 public String firstName{get;set;}
 //Variable responsible for holding param value assigned in from VF.
 public String param1{get;set;}

 //action method called from actionFunction.
 public void method1(){
  System.debug('Parameter passed is '+ param1);
 }
}

2. Create a page like below example.

<apex:page controller="ActionFunctionExmpCtrl">
<script>
/**
 * JS method call from onClick operation.
 */
function doJSMethod(fst_name) {
//Varibale to fetch the valuse passed as a parameter on onClick event.
var fstNm = document.getElementById(fst_name).value;
//actionFunction name with parameter.
callMethod1(fstNm);
}
</script>

<apex:form id="formId">
First Name: <apex:inputText id = "f_Nm" value="{!firstName}"/><br/>
<apex:inputCheckbox onclick="doJSMethod('{!$Component.f_Nm}')"/>Click on checkbox to pass First Nmae as parameter

<!-- apex:actionFunction with apex:param -->
<apex:actionFunction action="{!method1}" name="callMethod1" rerender="formId" >
       <apex:param assignTo="{!param1}" name="prmNm" value=""/>
   </apex:actionFunction>

    </apex:form>

</apex:page>

Wednesday, May 10, 2017

Sample example for consuming Rest Web Service (RestWSSampleWithParam) containing web method with parameters from same Salesforce ORG.

Scenario: Suppose we have a rest web service in ORG1 (As posted in previous post named as "RestWSSampleWithParam"). This service has a web method (getRestSampleResponse) which contains 2 parameters. Now our aim is to call the web service from same ORG (ORF1).

Solution: Below is the apex code example for consuming rest web service from same Org.
Pre-step: Before copy paste the below code base, do the remote site setting for the endPoint URL.


/**
 * Consuming Rest Web Service (RestWSSampleWithParam) from same ORG with parameters.
 **/
public class RestWSWithParamsConsumeFromSameOrg
{
  public static void callingRestWS(){
    try {
      // Setup remote site setting for the below URL.
          String url = 'https://ap5.salesforce.com/services/apexrest/RestWSSampleParamExmpl';
          system.debug('Response URL'  +url);   
          
          HttpRequest req = new HttpRequest();
          req.setMethod('POST');
          //req.setHeader('content-type', 'application/json');
          req.setHeader('Content-Type', 'application/xml; charset=utf-8');
          req.setEndpoint(url);   
          req.setHeader('Authorization', 'OAuth '+UserInfo.getSessionId());
          req.setBody('<?xml version="1.0" encoding="UTF-8" ?><request><firstName>Arun</firstName><lastName>Hazra</lastName></request>');
    
          Http http = new Http();
          
          HTTPResponse resp = http.send(req);
          
          system.debug('Response body'  +resp.getBody()); 
          system.debug('STATUS: '+ resp.getStatus());
          system.debug('STATUS_CODE:'+ resp.getStatusCode());    
    } catch(System.CalloutException e){
      System.debug('Sorry, You have an error ' + e.getMessage());
    }
  }
}

Data Cloud Part 6: Practical (Ingest Physical Store's Customer details and Sales details)

Hope you have already created your Data Cloud Org and also downloaded the Customer's details and Sales details from previous posts.  Now...