Wednesday, February 25, 2015

Filled Under: , , ,

Code and Visualforce Optimization using Custom Component and Abstraction


This post aims at minimizing Apex code and reusing visual force construct using custom components.

Let us start with a straight forward implementation, forgetting about any optimization. My requirement is I want to display an Account's Annual revenue only on a button click via a custom page.
I want do the same on the Contact page as well, here showing the associated Account's annual revenue.
I create two separate visualforce pages and two separate apex controllers to support them.
I added the visual force pages as inline to the Account layout and the Contact layout respectively.
Page 1: GetAccountAnnualRevenue
<apex:page standardController="Account" extensions="AnnualRevenueController">
<apex:form >
    <apex:pageBlock >
        <apex:pageBlockButtons location="top">
            <apex:commandButton value="Click Here" action="{!fetchAnnualRevenue}"/><br/><br/>
            <apex:outputText value="Annual Revenue   " />
            <apex:outputText value="{!annualRevenue}" label="Annual Revenue"></apex:outputText><br/>
        </apex:pageBlockButtons>
    </apex:pageBlock>
</apex:form>
</apex:page>


Controller 1: AnnualRevenueController 
public with sharing class AnnualRevenueController {

  public String annualRevenue {get;set;}
  public Id objectId {get;set;}
  public Account account {get;set;}
  
  public AnnualRevenueController(ApexPages.StandardController stdController){
    account = [SELECT Id,Name,AnnualRevenue
                  FROM Account WHERE Id =: ApexPages.currentPage().getParameters().get('id')];
  }
  
  public void fetchAnnualRevenue(){
    annualRevenue = account.AnnualRevenue.toPlainString();
  }
}

Page 2: GetContactAnnualRevenue
<apex:page standardController="Contact" extensions="ContactAnnualRevenueController">
<apex:form >
    <apex:pageBlock >
        <apex:pageBlockButtons location="top">
            <apex:commandButton value="Click Here" action="{!fetchAnnualRevenue}"/><br/><br/>
            <apex:outputText value="Annual Revenue   " />
            <apex:outputText value="{!annualRevenue}" label="Annual Revenue"></apex:outputText><br/>
        </apex:pageBlockButtons>
    </apex:pageBlock>
</apex:form>
</apex:page>

Controller 1: ContactAnnualRevenueController
public with sharing class ContactAnnualRevenueController {
  public String annualRevenue {get;set;}
  public Id objectId {get;set;}
  public Contact contact {get;set;}
  
  public ContactAnnualRevenueController(ApexPages.StandardController stdController){
    
    contact = [SELECT Id,Name,Account.AnnualRevenue
                  FROM Contact WHERE Id =: ApexPages.currentPage().getParameters().get('id')];
  }
  
  public void fetchAnnualRevenue(){
    annualRevenue = contact.Account.AnnualRevenue.toPlainString();
  }
}

The Account Page shows the Annual revenue something like this:
And on click


Now, we are doing the same thing for two different pages, the only difference is the way we pull in the Annual Revenue data. Once from an Account record and the second time from a Contact record.
We display the exact same thing, but have ended up putting in the same lines for the two different pages. If we tomorrow decide to show the same for an Opportunity record, we will mimic all the lines of code in another page. Unnecessary.
Now, let us collate these together for a more precise solution.
First, what we show in both the pages, and perhaps multiple other pages in future, come into a component as below:
<apex:component >
<apex:attribute name="revenueController" description="This is the Controller" type="AnnualRevenueController" required="true"/>
<apex:form >
    <apex:pageBlock >
        <apex:pageBlockButtons location="top">
            <apex:commandButton value="Click Here" action="{!revenueController.fetchAnnualRevenue}"/><br/><br/>
            <apex:outputText value="Annual Revenue   " />
            <apex:outputText value="{!revenueController.annualRevenue}" label="Annual Revenue"></apex:outputText><br/>
        </apex:pageBlockButtons>
    </apex:pageBlock>
</apex:form>
</apex:component>

Now, the Visualforce page can be concised to as :
<apex:page standardController="Account" extensions="AnnualRevenueController">
<c:commonannualrevenuedisplay revenueController="{!this}"></c:commonannualrevenuedisplay>
</apex:page>

Ok, let's see what we did. The Visualforce component does all the work. From the page we just assign the instance of the AnnualRevenueController class to the revenueController attribute of the component. Using the revenueController the component can fetch and display the revenue.
The actual Annual Revenue is fetched from database by the AnnualRevenueController.
To make this work, add the below lines to your AnnualRevenueController 
//returns the instance of this class
    public AnnualRevenueController getThis(){
      return this;
    }

This above snippet of code, basically, returns the current instance of the AnnualRevenueController class to the visualforce page and in turn the component.

So, we slimmed down the visualforce page. However, we still have a problem here.

We arrived at a station but not our destination. What happens to our Contact page? I have passed the Account related controller to the component, and hence it would work only for the Account page.
Here, we do another trick - one of the strongest tool OOPs provides - "ABSTRACTION"
We create an abstract class to fetch and initialize the Annual revenue from the page. See below:
public abstract class AbstractAnnualRevenueController{
    abstract String getAnnualRevenue();
    public String annualRevenue{get;set;};
    
    public void fetchAnnualRevenue(){
        annualRevenue = getAnnualRevenue();
    }
}

Now, abstract class is a class which cannot be initialized. Simply put, this class is incomplete. We have declared a method getAnnualRevenue, but never defined what is does.
Here,is where, abstraction starts, as we mark this method as abtract, we need not define it, but we enforce other classes (child) who extend this class to define this method.
The individual classes can decide what to do inside and what final value to return. 
So, the trick is let the page get the details from the same attribute/methos. Internally, you channel your method to fetch the actual relevant data.

Now,let us see what changed in our controller classes


public with sharing class AnnualRevenueController extends AbstractAnnualRevenueController{

   public Account account {get;set;}
        
    public AnnualRevenueController(ApexPages.StandardController stdController){
        account = [SELECT Id,Name,AnnualRevenue
                                  FROM Account WHERE Id =: ApexPages.currentPage().getParameters().get('id')];
    }            
    //returns the instance of this class
    public AnnualRevenueController getThis(){
      return this;
    }
    
    public String getAnnualRevenue(){
        return account.AnnualRevenue.toPlainString();
    }
}



public with sharing class ContactAnnualRevenueController  extends AbstractAnnualRevenueController {
    
    public Contact contact {get;set;}    
    public ContactAnnualRevenueController(ApexPages.StandardController stdController){
        
        contact = [SELECT Id,Name,Account.AnnualRevenue
                                  FROM Contact WHERE Id =: ApexPages.currentPage().getParameters().get('id')];
    }    
    //returns the instance of this class
    public ContactAnnualRevenueController getThis(){
      return this;
    }
    
    public String getAnnualRevenue(){
        return contact.Account.AnnualRevenue.toPlainString();
    }
}

As simple as that, and now we make a very small change in our component


<apex:attribute name="revenueController" description="This is the Controller" type="AbstractAnnualRevenueController" required="true"/>

Our contact page can also be concise now:


<apex:page standardController="Contact" extensions="ContactAnnualRevenueController">
<c:commonannualrevenuedisplay revenueController="{!this}"></c:commonannualrevenuedisplay>
</apex:page>

And that completes our goal. Our Account and Contact page successfully renders the Annual Revenue : 


We reused a single component and an abstract class to create a custom page displaying the Annual revenue for an Account, a Contact and in future can plug in any object to show its Annual revenue. 
All we need to do is extend the class AbstractAnnualRevenueController and override the method getAnnualRevenue. Voila!!
Try doing this for an Opportunity record. It will be a cake walk.

Hope all of you enjoyed this, do post your comments and any queries.


28 comments:

  1. Nowadays, most of the businesses rely on cloud based CRM tool to power their business process. They want to access the business from anywhere and anytime. In such scenarios, salesforce CRM will ensure massive advantage to the business owners. Salesforce Training in Chennai

    ReplyDelete
  2. Oracle DBA Training in Chennai
    Thanks for sharing this informative blog. I did Oracle DBA Certification in Greens Technology at Adyar. This is really useful for me to make a bright career..

    ReplyDelete
  3. Whatever we gathered information from the blogs, we should implement that in practically then only we can understand that exact thing clearly, but it’s no need to do it, because you have explained the concepts very well. It was crystal clear, keep sharing..
    Websphere Training in Chennai

    ReplyDelete
  4. Data warehousing Training in Chennai
    I am reading your post from the beginning, it was so interesting to read & I feel thanks to you for posting such a good blog, keep updates regularly..

    ReplyDelete
  5. Selenium Training in Chennai
    Wonderful blog.. Thanks for sharing informative blog.. its very useful to me..

    ReplyDelete
  6. Oracle Training in chennai
    Thanks for sharing such a great information..Its really nice and informative..

    ReplyDelete
  7. I have read your blog and i got a very useful and knowledgeable information from your blog.You have done a great job.
    SAP Training in Chennai

    ReplyDelete
  8. This information is impressive..I am inspired with your post writing style & how continuously you describe this topic. After reading your post,thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic
    Android Training In Chennai In Chennai

    ReplyDelete
  9. Pretty article! I found some useful information in your blog, it was awesome to read,thanks for sharing this great content to my vision, keep sharing..
    Unix Training In Chennai

    ReplyDelete
  10. I found some useful information in your blog, it was awesome to read, thanks for sharing this great content to my vision, keep sharing..
    SalesForce Training in Chennai

    ReplyDelete
  11. There are lots of information about latest technology and how to get trained in them, like Best Hadoop Training In Chennai have spread around the web, but this is a unique one according to me. The strategy you have updated here will make me to get trained in future technologies Hadoop Training in Chennai By the way you are running a great blog. Thanks for sharing this blogs..

    ReplyDelete
  12. Oracle Training in chennai | Oracle D2K Training In chennai
    This information is impressive; I am inspired with your post writing style & how continuously you describe this topic. After reading your post, thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic..

    ReplyDelete
  13. Thanks for Information Oracle Apps Technical is a collection of a bunch of collected applications like accounts payables, purchasing, inventory, accounts receivables, human resources, order management, general ledger and fixed assets, etc which have its own functionality for serving the business
    Oracle Apps Training In Chennai

    ReplyDelete
  14. This information is impressive; I am inspired with your post writing style & how continuously you describe this topic. After reading your post, thanks for taking the time to discuss this, I feel happy about it and I love learning more about this topic..
    Selenium Training in Chennai | QTP Training in Chennai

    ReplyDelete
  15. Excellent post!!! The future of cloud computing is on positive side. With most of the companies integrate Salesforce CRM to power their business; there is massive demand for Salesforce developers and administrators across the world. Salesforce Training in Chennai

    ReplyDelete
  16. Best iOS Training Institute In Chennai It’s too informative blog and I am getting conglomerations of info’s about Oracle interview questions and answer .Thanks for sharing, I would like to see your updates regularly so keep blogging.

    ReplyDelete
  17. I have read your blog and I gathered some needful information from your blog. Keep update your blog. Awaiting for your next update.

    salesforce training in hyderabad

    ReplyDelete
  18. Nice information thank you,if you want more information please visit our link salesforce Online course

    ReplyDelete
  19. Greetings. I know this is somewhat off-topic, but I was wondering if you knew where I could get a captcha plugin for my comment form? I’m using the same blog platform like yours, and I’m having difficulty finding one? Thanks a lot.
    Big data training in tambaram

    Big data training in tambaram

    ReplyDelete
  20. Your good knowledge and kindness in playing with all the pieces were very useful. I don’t know what I would have done if I had not encountered such a step like this.
    Devops Training in pune

    Devops Training in Chennai

    Devops Training in Bangalore

    AWS Training in chennai

    AWS Training in bangalore

    ReplyDelete
  21. Your good knowledge and kindness in playing with all the pieces were very useful. I don’t know what I would have done if I had not encountered such a step like this.

    rpa training in Chennai | rpa training in pune

    rpa training in tambaram | rpa training in sholinganallur

    rpa training in Chennai | rpa training in velachery

    rpa online training | rpa training in bangalore

    ReplyDelete
  22. I have been meaning to write something like this on my website and you have given me an idea. Cheers.
    python training in tambaram
    python training in annanagar
    python training in OMR

    ReplyDelete
  23. I would like to thank you for your nicely written post, its informative and your writing style encouraged me to read it till end. Thanks
    java training in chennai | java training in bangalore

    java online training | java training in pune

    ReplyDelete
  24. Thank you for sharing such valuable information and tips. This can give insights and inspirations for us; very helpful and informative! Would love to see more updates from you in the future.
    Selenium Training in Chennai
    Selenium Training
    JAVA Training in Chennai
    JAVA Training Institutes in Chennai
    iOS Training in Chennai
    iOS Training Institutes in Chennai
    iOS Training in Velachery

    ReplyDelete
  25. Awwsome informative blog ,Very good information thanks for sharing such wonderful blog with us ,after long time came across such knowlegeble blog. keep sharing such informative blog with us.
    Aviation Academy in Chennai | Aviation Courses in Chennai | Best Aviation Academy in Chennai | Aviation Institute in Chennai | Aviation Training in Chennai

    ReplyDelete