Monday, 18 February 2019

Connect Dropbox with Salesforce as IdP


An identity provider is a system entity that creates, maintains, and manages identity information for principals while providing authentication services to relying applications. An identity provider is “a trusted provider that lets you use single sign-on (SSO) to access other websites".
When you log into trailhead by clicking 'Log in with Facebook', 'Log in with Google+' or 'Log in with Linkedin' then that's the example of Google, Facebook, Linkedin acting as trusted identity provider, and authenticating you on behalf of trailhead.




Identity provider saves your time spent in creating and maintaining your credentials and helping third party websites from storing and protecting your information.

Salesforce supports 
  • Identity provided-initiated login - when Salesforce logs in to a server provider at the initiation of the end user.
  • Service provider-initiated login - when the service provider requests Salesforce to authenticate a user, at the initiation of the user.


Salesforce as Identity provider: Salesforce can act as identity provider to service providers, allowing end users to easily and securely access many web and mobile applications with one login. When using SAML for federated authentication, enable Salesforce as an identity provider and then set up connected apps.

Steps to enable Salesforce as Identity Provider with DropBox:

Prerequisite
DropBox account: if you already have dropbox account then verify if it is personal? if yes then enable Dropbox for Business from bottom left corner,it is free for 30 days. Once Dropbox for Business is enabled follow the steps below. Make sure you select DropBox Business Advance option.


1. From setup, enter Identity provider in the quick find box and click 'Enable Identity Provider' (if not enabled).

2. Go to Dropbox and click Admin Console.

3. Click Setting.

4. Under Authentication settings, click Single sign-on.


5. Choose whether SSO is optional or required.

6. Dropbox displays information about SSO setup, including a URL for service provider–initiated SSO, for example, https://www.dropbox.com/sso/11272027. Save this URL to use later when you test the configuration.

7. For Identity provider sign-in URL, enter the HttpRedirect endpoint, for example, https://yourdomain.my.salesforce.com/idp/endpoint/HttpRedirect, where yourdomain is your My Domain subdomain.

8. Optionally, for Identity provider sign-out URL, enter the URL to which the user is redirected after logout.

9. For X.509 certificate, upload your Salesforce certificate. You can download your certificate from Setup -> Identity Provider -> Click on Download certificate button.




Create a Connected App in Salesforce:
1. In Lightning goto App Manager, click New Connected App and in classic goto Apps under Connected Apps and click New.

2. Enter Connected App basic information.
2.a. Enter Connected App name as Dropbox and Contact Email.

3. Configure Web App Settings
3.a. Select Enable SAML.
3.b. Entity Id: Dropbox
3.c. ACS: https://www.dropbox.com/saml_login
3.d. Subject type: Federation Id.
3.d. For Name ID, Issuer, Idp Certificate keep the default.

4. Save the Settings.

5. Configure profiles and permission sets for Connected Apps.
5.a. From Setup enter Apps, in the Quick Find box.
   - Lightning: select Manage Connected Apps.
   - Classic:   select Connected Apps.

5.b. Click on the name of your connected App (Dropbox) to open detail    page.
5.c. Click Manage Profiles or Manage Permission Sets and add profile and permission sets for those users who can access this app.

6. In Salesforce, enter the start URL for connected App.
6.a. On the connected app detail page, under SAML Login Information, copy the IdP-initiated login URL.
6.b. On the connected app detail page, click Edit Policies.
6.c. For Start URL, paste the IdP-initiated login URL.
6.d. Save the settings.

Testing
1. From App Launcher choose Dropbox application, you will see a screen like the one below.




2. Clicking on continue button will log you in to your Dropbox account.



Special Thanks to Krishna and Harleen.


Sunday, 17 February 2019

Apex Service Layer : Separation of Concerns


Separation of Concerns (SoC) (modularity,information hiding)

The most important principle of Software is Separation of Concerns(SoC).Software system must be decomposed into parts that overlap in functionality.

Separation of Concerns is a design principle for separating a program into different sections so that each section addresses a separate concern (information). A program which implements SoC is consider as modular program. Modularity is achieved by encapsulation. Encapsulating means information hiding. SoC results in simplified and easy maintenance of code which later help reusing the code and easy to upgrade, i.e. one can modify one piece of code without knowing the details of other section of code.

Good code benefits from careful design and foresight and complex code gets out of hand if you don't partition it properly. When code is heavily intermixed, it become error prone, difficult to maintain and hard to learn.

Benefits of SoC
At higher level, applications have three things: storage, logic and means to interact with them.  When you separate these things, you can start to define layers within your application, each with its own set of concerns and responsibilities to other layers and the application as a whole.


  • Evolution: over the time technical and functional requirements evolve, a layer might need to be extended, reworked, or even dropped.
  • Impact management: Modifying or dropping one or more layers should not impact other layers, unless this is the intention due to requirements.
  • Roles and Responsibility: Each layer has its own responsibility and must not drop below or over-extend that responsibility. If the lines of responsibility get blurred, the purpose and value of SOC are eroded and that's not good.
The Force.com platform has two distinct approaches to development, declarative (point-and-click) and traditional coding. You can use either method on its own or in conjunction. The two approaches fit into the standard SOC layers as outlined below.

Presentation:
  • Declarative: Layouts, Flow, Record Types, Formulas, Reports, Dashboards
  • Coding: Apex Controllers, Visualforce, Lightning Components

Business Logic:
  • Declarative: Formula, Validation, Workflow, Process Builder, Sharing Rules
  • Coding: Apex Services, Apex Custom Actions

Data Access Layer:
  • Declarative: Data Loaders
  • Coding: SOQL, SOSL, Salesforce APIs

Database Layer:
  • Declarative: Custom Objects, Fields, Relationships, Rollups
  • Coding: Apex Triggers


When some business requirement cannot be acheived via declarative way and you have to write code to achieve complex logic than we ends up using SoC using Apex, triggers etc.



Service Layer, "Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation." Martin Fowler / Randy Stafford, EAA Patterns

Service layer is a middle layer between presentation and data store. It abstract business logic and data access. A good Service layer:

1. Centralizes external access to data and functions
2. Hides (abstracts) internal implementation and changes.
3. Allows for versioning of the services.

The Service layer helps you form a clear and strict encapsulation of code implementing business tasks, calculations and processes. It’s important to ensure that the Service layer is ready for use in different contexts, such as mobile applications, UI forms, rich web UIs, and numerous APIs. It must remain pure and abstract to endure the changing times and demands ahead of it.


Design Consideration:

  • Naming conventions: Ensure that class, methods, and parameters names are expressed in general terms of the application or task rather than relating to a specific client caller.
  • Platform/Caller sympathy: Design methods signatures must support platform's best practices especially Bulkification.
  • SoC consideration: Service layer code encapsulates task or process logic typically utilizing multiple objects in your application. Think of this as an orchestrator. In contrast, code relating specifically to validation, field values or calculations, which occur during record inserts, updates, and deletes, is the concern of the related object. Such code is typically written in Apex triggers and can remain there.
  • Security: Service layer code and the code it calls should by default run with user security applied. To ensure that this is the case, utilize the with sharing modifier on your Apex Service classes.
  • Marshalling: Visualforce uses <apex:pagemessages>, and Schedule jobs will likely use emails, Chatter posts, or logs to communicate errors. So in this case, it is typically best to leverage the default error-handling semantics of Apex by throwing exceptions. Alternatively, your service can provide partial database update feedback to the caller. In this case, devise an appropriate Apex class and return a list of that type. The system Database.insert method is a good example of this type of method signature.
  • Compound services: Although clients can execute multiple service calls one after another, doing so can be inefficient and cause database transactional issues. It’s better to create compound services that internally group multiple service calls together in one service call. It is also important to ensure that the service layer is as optimized as possible in respect to SOQL and DML usage.
  • Transaction management and statelessness: Make the service stateless to give calling contexts the flexibility to employ their own state management solutions. The scope of a transaction with the database should also be contained within each service method so that the caller does not have to consider this with its own SavePoints. It’s best to encapsulate database operations and service state within the method call to the service layer.
  • Configuration: You might have common configuration or behavioral overrides in a service layer, such as providing control to allow the client to instruct the server layer not to commit changes or send emails. This scenario might be useful in cases where the client is implementing preview or what-if type functionality.
In below code method in controller represents the service operations, which access the information they needed through environment and parameters passed. The logic in the method updates the database or returns information in the method’s return type using custom Apex exceptions to indicate failure. The following example shows a service to apply a given discount to a set of Opportunities (and lines items, if present).

public class OpportunitiesService {
public static void applyDiscounts(Set<Id> opportunityIds, Decimal discountPercentage) {
if(opportunityIds == null || opportunityIds.size()==0)
throw new OpportunityServiceException(' Opportunities not specified');
if(discountPercentage<0 || discountPercentage>100)
throw new OpportunityServiceException('Invalid discount to apply.');
List<Opportunity> opportunities = [SELECT Amount, (SELECT UnitPrice from OpportunityLineItems)
FROM Opportunity WHERE Id in :opportunityIds];
// Update Opportunities and Lines (if present)
List<Opportunity> oppsToUpdate = new List<Opportunity>();
List<OpportunityLineItem> oppLinesToUpdate = new List<OpportunityLineItem>();
Decimal factor = 1 - (discountPercentage==null ? 0 : discountPercentage / 100);
for(Opportunity opportunity : opportunities) {
// Apply to Opportunity Amount
if(opportunity.OpportunityLineItems!=null && opportunity.OpportunityLineItems.size()>0) {
for(OpportunityLineItem oppLineItem : opportunity.OpportunityLineItems) {
oppLineItem.UnitPrice = oppLineItem.UnitPrice * factor;
oppLinesToUpdate.add(oppLineItem);
}
} else {
opportunity.Amount = opportunity.Amount * factor;
oppsToUpdate.add(opportunity);
}
}
// Update the database
SavePoint sp = Database.setSavePoint();
try {
update oppLinesToUpdate;
update oppsToUpdate;
} catch (Exception e) {
// Rollback
Database.rollback(sp);
// Throw exception on to caller
throw e;
}
}
public class OpportunityServiceException extends Exception {}
}
If you wanted to expose your service to external parties through an API, then simplest way to expose it to Apex developers is to modify the class and method modifiers from public to global. It's worth considering exposing your API for off-platform callers, such as mobile or IoT is via REST protocol.

Below code closes the Case and set reason for one or more given case records. Below CaseService class contains a static method which takes two parameters, set of Case Ids and a string parameter for close reason.

public class CaseService {
public static void closeCases(Set<Id> caseIds, String caseReason) {
if(caseReason == '')
new CaseServiceException(' Case Reason is not mentioned');
if(caseIds.isEmpty() || caseIds == null)
new CaseServiceException(' Cases not specified');
List<Case> caseList = new List<Case>();
List<Case> casesToUpdate = new List<Case>();
caseList = [SELECT Id, reason FROM Case WHERE Id In: caseIds];
for(Case c: caseList) {
c.reason = caseReason;
c.Status = 'Closed';
casesToUpdate.add(c);
}
SavePoint sp = Database.setSavepoint();
try {
update casesToUpdate;
} catch (exception e) {
// Rollback
Database.rollback(sp);
// Throw exception on to caller
throw e;
}
}
public class CaseServiceException extends Exception {}
}
view raw CaseService.cls hosted with ❤ by GitHub
Below REST Apex class called CaseCloseReason with URI mapping /case/*/close (where * will be the Id) implements a HTTPPost method closecase which accepts a reason of type string and calls CaseService.closecases service method passing Id and reason.
@RestResource(urlMapping='/case/*/close')
global class CaseCloseResource {
@HttpPost
global static void closeCase(String reason) {
RestRequest req = RestContext.request;
String[] uriParts = req.requestURI.split('/');
Id caseIds = uriParts[2];
CaseService.closeCases(new Set<Id>{caseIds}, reason);
}
}

Unit of Work Principles

When you're pulling data in and out of a database, it's important to keep track of what you've changed; otherwise, that data won't be written back into the database. Unit of work keeps track of everything you do during a business transaction that can affect the database. "A Unit of Work keeps track of everything you do during a business transaction that can affect the database. When you're done,
it figures out everything that needs to be done to alter the database as a result of your work."

The Unit of Work is a design pattern that reduces repetitive code when implementing transaction management and the coding overheads of adhering to DML bulkification through extensive use of maps and lists. It’s not a requirement for implementing a service layer, but it can help.

On Force.com platform this translates to the pattern handling the following use cases:
  • Recording record updates, inserts, and deletes to implement a specific business requirement
  • Recording record relationships to make inserting child or related records easier with less coding
  • When asked to write (or commit) to the database, bulkifies all records captured
  • Wrapping DML performed in SavePoint, freeing the developer from implementing this each time for every service method that is written
In OpportunitiesService we use Savepoint to encapsulate and wrap the database operations within a Service method. As per the design considerations, the SavePoint is used to avoid the caller catching exceptions (perhaps resulting from the second DML statement). That would then result in the Apex runtime committing updates to the opportunity lines (first DML statement), causing a partial update to the database.

Please refer Unit of Work  Principles of Apex on Trailhead for details and example.


References: Apex Enterprise Patterns: Service Layer, www.martinfowler.com


Saturday, 16 February 2019

Reset Password button missing for Community Users


If you are created a community user and you don't see 'Reset Password' button on user detail record then one of the reason of missing button is that you might not have added that user to community as member.

Steps to add the Community User:

1. Go to Setup.
2. Search 'All Communities' in Quick Find.
3. Click on workspaces link next to community.


4. Click on Administration.


5. Select Members from left panel
6. Select the user's profile and click on Add.




Thursday, 14 February 2019

Lightning Tooltip


A lightning:helptext component displays an icon with a popover containing a small amount of text describing an element on screen. The popover is displayed when you hover or focus on the icon that's attached to it.

By default, the tooltip uses the utility:info icon but you can specify a different icon with the iconName attribute. 

Visit
 https://lightningdesignsystem.com/icons/#utility to view the utility icons.


Let's create tooltip component and will try to make it reusable.
LightningToolTipcmp
<aura:component implements="flexipage:availableForRecordHome,force:hasRecordId,force:appHostable" access="global" >
<aura:attribute name="helpText" default="Help Text here" required="true" type="String"
description="stores the help text send, value can be controlled dynamically"/>
<lightning:helptext content="{!v.helpText}" />
</aura:component>

Above Lightning tooltip component can be reused by passing the help text as a attribute.



Reference: 
Lightning Web Components

Sunday, 10 February 2019

CAPTCHA in Lightning

Use below code to implement captcha in your lightning component.





Lightning_CAPTCH.cmp
<aura:component >
<aura:attribute name="captchaError" type="Boolean" default="false" />
<aura:attribute name="captchaSuccess" type="Boolean" default="false" />
<aura:attribute name="char1" type="String" />
<aura:attribute name="char2" type="String" />
<aura:attribute name="char3" type="String" />
<aura:attribute name="char4" type="String" />
<aura:attribute name="char5" type="String" />
<aura:attribute name="char6" type="String" />
<aura:attribute name="captchaData" type="String" />
<aura:attribute name="Msg" type="String"/>
<aura:handler name="init" value="{!this}" action="{!c.init}" />
<div class="col-md-12 col-sm-12 col-xs-12 slds-align_absolute-center">
<div class="form-group">
<h5 class="font14">CAPTCHA</h5>
<hr/>
<aura:if isTrue="{!v.captchaError}" >
<div class="error" style = "background-color: white;color:red;">
Please enter black characters only.
</div>
</aura:if>
<aura:if isTrue="{!v.captchaSuccess}" >
<div class="error" style = "background-color: white;color:green;">
Captcha Matched.
</div>
</aura:if>
<div>
<span class="slds-text-heading_large">{!v.char1 }<span style="color: lightgray;">{!v.char2 }</span>
{!v.char3 } <span style="color:lightgray;">{!v.char4 }</span> {!v.char5 }
<span style="color: lightgray;">{!v.char6 }</span></span>
<a href="javascript:void(0);" class="reset-form color-red" onclick="{!c.resetCaptcha}">Reset Captcha</a>
</div>
<div class="form-group">
<lightning:input type="text" label="Enter" value="{!v.captchaData }"/>
</div>
<lightning:button label="Validate" title="Validate Captcha" onclick="{!c.validate }"/>
</div>
</div>
</aura:component>
Lightning_CAPTCHController.js
({
init : function(component, event, helper) {
helper.initialiseCaptcha(component, event);
},
/* Reset captcha */
resetCaptcha: function(component, event, helper){
helper.initialiseCaptcha(component, event);
component.set("v.captchaData", "");
},
validate : function(component, event, helper) {
var returntype = helper.validateEnteredCaptcha(component, event);
console.log(returntype);
if(!returntype) {
component.set("v.captchaError", "true");
component.set("v.captchaSuccess", "false");
component.set("v.captchaData", "");
} else {
component.set("v.captchaError", "false");
component.set("v.captchaSuccess", "true");
}
}
})
Lightning_CAPTCHHelper.js
({
initialiseCaptcha: function(component,event, helper) {
component.set("v.char1", this.randomNumber());
component.set("v.char2", this.randomNumber());
component.set("v.char3", this.randomNumber());
component.set("v.char4", this.randomNumber());
component.set("v.char5", this.randomNumber());
component.set("v.char6", this.randomNumber());
},
/* Generate ramdom number for captcha */
randomNumber: function(){
var possible = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var random = possible.charAt(Math.floor(Math.random() * possible.length))
return random;
},
validateEnteredCaptcha: function(component,event) {
var char1 = component.get("v.char1");
var char3 = component.get("v.char3");
var char5 = component.get("v.char5");
var captchaData = component.get("v.captchaData");
if(captchaData == undefined || captchaData == null){
this.initialiseCaptcha(component,event);
return false;
}else if(captchaData.length != 3){
this.initialiseCaptcha(component,event);
return false;
}else if(captchaData[0].localeCompare(char1) != 0){
this.initialiseCaptcha(component,event);
return false;
}else if(captchaData[1].localeCompare(char3) != 0){
this.initialiseCaptcha(component,event);
return false;
}else if(captchaData[2].localeCompare(char5) != 0){
return false;
}else{
return true;
}
}
})



Add caption



Pagination in Lightning




In this blog we will implement pagination in Lightning. 




PaginationController.cls

public class PaginationController {
@AuraEnabled
public static List<Opportunity> getOpportunities() {
return [SELECT Id, Name, StageName, CloseDate, Amount, AccountId, Account.Name
FROM Opportunity Limit 10000];
}
}

LightningPagination.cmp
<aura:component controller="PaginationController"
implements="force:appHostable,flexipage:availableForAllPageTypes">
<aura:handler name="init" value="{!this}" action="{!c.doInit}" />
<aura:attribute name="opportunityList" type="List"
description="opportunitList attribute stores the total number of records returned from Server"/>
<aura:attribute name="pageOpportunityList" type="List"
description="attribute stores list of opportunity to be diaplayed on the basis of pageSize"/>
<aura:attribute name="totalRecSize" type="integer"/>
<aura:attribute name="defaultSize" type="integer" default="5"
description="attribute stores the number of records to be displayed"/>
<aura:attribute name="pageNumber" type="integer" default="1" description="stores current page number"/>
<aura:attribute name="totalPages" type="integer" default="1" description="stores total page number"/>
<table class="slds-table slds-table_cell-buffer slds-table_bordered">
<thead>
<tr class="slds-text-title--caps">
<th class="" scope="col">
<div class="slds-truncate" title="Opportunity Name">Opportunity Name</div>
</th>
<th class="" scope="col">
<div class="slds-truncate" title="Account Name">Account Name</div>
</th>
<th class="" scope="col">
<div class="slds-truncate" title="Close Date">Close Date</div>
</th>
<th class="" scope="col">
<div class="slds-truncate" title="Stage">Stage</div>
</th>
<th class="" scope="col">
<div class="slds-truncate" title="Amount">Amount</div>
</th>
</tr>
</thead>
<tbody>
<aura:iteration items="{!v.pageOpportunityList}" var="item">
<tr class="slds-hint-parent">
<td data-label="Opportunity Name">
<div class="slds-truncate" title="{!item.Name}">{!item.Name}
</div>
</td>
<td data-label="Account Name">
<div class="slds-truncate" title="{!item.Account.Name}">{!item.Account.Name}</div>
</td>
<td data-label="Close Date">
<div class="slds-truncate" title="{!item.CloseDate}">{!item.CloseDate}</div>
</td>
<td data-label="Stage">
<div class="slds-truncate" title="{!item.StageName}">{!item.StageName}</div>
</td>
<td data-label="Amount">
<div class="slds-truncate" title="{!item.Amount}">{!item.Amount}</div>
</td>
</tr>
</aura:iteration>
</tbody>
</table>
<div class="slds-align_absolute-center" style="height: 5rem;">
<lightning:button label="First" disabled="{!v.pageNumber == 1}" onclick="{!c.first}"/>
<lightning:button label="Previous" disabled="{!v.pageNumber == 1}" onclick="{!c.previous}"/>
<lightning:button label="Next" disabled="{!v.pageNumber == v.totalPages}" onclick="{!c.next}"/>
<lightning:button label="Last" disabled="{!v.pageNumber == v.totalPages}" onclick="{!c.last}"/>
<span class="slds-p-horizontal_x-small">Page {!v.pageNumber} of {!v.totalPages}</span>
</div>
</aura:component>



LightningPaginationController.js
({
doInit : function(component, event, helper) {
helper.getData(component, helper);
},
next : function(component, event,helper) {
var recList = component.get("v.opportunityList");
var pageNumber = component.get("v.pageNumber");
var defaultSize = component.get("v.defaultSize");
var nextPageNumber = pageNumber+1;
var start = pageNumber * defaultSize;
var nextPageRecs = [];
for(; start < (nextPageNumber*defaultSize); start++) {
if(recList[start]) {
nextPageRecs.push(recList[start]);
}
}
component.set("v.pageOpportunityList", nextPageRecs);
component.set("v.pageNumber", pageNumber+1);
},
first : function(component, event, helper) {
var recList = component.get("v.opportunityList");
var rec = [];
var defaultSize = component.get("v.defaultSize");
for(var i =0; i <defaultSize; i++) {
if(recList[i])
rec.push(recList[i]);
}
component.set("v.pageOpportunityList", rec);
component.set("v.pageNumber", 1);
},
last : function(component, event, helper) {
var totalRecSize = component.get("v.totalRecSize");
var recList = component.get("v.opportunityList");
var defaultSize = component.get("v.defaultSize");
var totalPages = component.get("v.totalPages");
var lastPageRecs = [];
var i = ((totalPages*defaultSize)-defaultSize);
for(; i < (totalPages*defaultSize); i++ ) {
if(recList[i])
lastPageRecs.push(recList[i]);
}
component.set("v.pageOpportunityList", lastPageRecs);
component.set("v.pageNumber", Math.ceil(totalRecSize/defaultSize));
},
previous : function(component, event, helper) {
var recList = component.get("v.opportunityList");
var pageNumber = component.get("v.pageNumber");
var defaultSize = component.get("v.defaultSize");
var curPageNumber = pageNumber-1;
var start;
if(curPageNumber == 0)
start = 0;
else
start = (curPageNumber-1) * defaultSize;
var nextPageRecs = [];
for(; start < (pageNumber*defaultSize)-defaultSize; start++) {
if(recList[start]) {
nextPageRecs.push(recList[start]);
}
}
component.set("v.pageOpportunityList", nextPageRecs);
component.set("v.pageNumber", pageNumber-1);
}
})



LightningPaginationHelper.js
({
getData : function(component, helper) {
var action = component.get("c.getOpportunities");
action.setCallback(this, function(response) {
var state = response.getState();
if(component.isValid() && state == 'SUCCESS') {
var records = response.getReturnValue();
component.set("v.opportunityList", records);
var totalRecSize = component.get("v.opportunityList").length;
component.set("v.totalRecSize", totalRecSize);
var pageRecSize = component.get("v.defaultSize");
var firstPageRecs = [];
for(var i =0; i < pageRecSize; i++){
if(i < records.length && i < pageRecSize) {
firstPageRecs.push(records[i]);
}
}
component.set("v.pageOpportunityList", firstPageRecs);
component.set("v.totalPages", Math.ceil(totalRecSize/pageRecSize) );
}
});
$A.enqueueAction(action);
},
})

Monday, 4 February 2019

instanceof in Apex


If we need to verify at runtime whether an object is actually an instance of a particular class use instanceof keyword. The instanceof keyword can only be used to verify if the target type in the expression on the right of the keyword is a viable alternative for the declared type of the expression on the left.

You could have something which is passed as Object type and using instanceof you can determine if it is an instance of your class or other data types

below code will help understand the use instanceof keyword.

/**
* controller using instanceof keyword to identify the type
*/
public class InstanceofController {
public static void getType(Object o) {
if(o instanceof SObject) {
system.debug(' #type# SObject ');
} else if(o instanceof Boolean) {
system.debug(' #type# Boolean ');
} else if(o instanceof Id) {
system.debug(' #type# Id ');
} else if(o instanceof String) {
system.debug(' #type# String ');
} else if(o instanceof Blob) {
system.debug(' #type# Blob ');
} else if(o instanceof Date) {
system.debug(' #type Date ');
} else if(o instanceof Datetime) {
system.debug(' #type# Datetime ');
} else if(o instanceof Time) {
system.debug(' #type# Time ');
} else if(o instanceof String) {
system.debug(' #type# String ');
} else if(o instanceof Integer) {
system.debug(' #type# Integer ');
} else if(o instanceof Long) {
system.debug(' #type# Long ');
} else if(o instanceof Decimal) {
system.debug(' #type# Decimal ');
} else if(o instanceof Double) {
system.debug(' #type# Double ');
} else if(o instanceof List<object>) {
system.debug(' #type# List ');
} else if(o instanceof InstanceofController) {
InstanceofController classInst=(InstanceofController) o;
system.debug(' InstanceofController ');
}
}
}

Open developer console and run below code and observe the logs

InstanceofController.getType(new Account());
INstanceofController.getType(true);
INstanceofController.getType(Id.valueOf('001xa000003DIlo'));
InstanceofController.getType(Date.newInstance(2020, 12, 31));
InstanceofController.getType(DateTime.newInstance(2020, 12, 31,0,0,0));
InstanceofController.getType('Clever Fox');
InstanceofController.getType(Blob.valueof('Clever Fox'));
InstanceofController.getType(12345);
Long myLong = 4271990;
InstanceofController.getType(myLong);
InstanceofController.getType(new InstanceofController());

Debug logs:





Reference:
Iterative Logic (must read)
Salesforce Developer Guide, Salesforce-System Namespace


Virtual Class in Apex


A class that extends another class inherits all the methods and properties of the extended class. In addition extending class can override the existing virtual methods by using override keyword in the method definition. Overriding a virtual method allows you to provide a different implementation for an existing method. This means that the behavior of a particular method is different based on the object you're calling it. This is referred as polymorphism.


  • just like abstract class, it is not mandatory to override virtual methods.
  • virtual and abstract classes can extends virtual class.

Check below code
/**
* Virtual Class with virtual methods
*
*/
public virtual class Marker {
public virtual void write() {
system.debug(' MARKER: writing some text');
}
public virtual integer price() {
return 10;
}
}
view raw Marker.cls hosted with ❤ by GitHub

/**
* Child class extending Virtual Class
*/
public class BlueMarker extends Marker{
// overriding write method
public override void write() {
System.debug('BLUEMARKER: writing some text using BlueMarker');
}
}
view raw BlueMarker.cls hosted with ❤ by GitHub

Now open developer console and run below code snippet and observe the logs

Marker obj1, obj2;
obj1 = new Marker();
// This outputs 'MARKER: writing some text'
obj1.write();

obj2 = new BlueMarker();
// This outputs 'BLUEMARKER: writing some text using BlueMarker'
obj2.write();
// We get the price of marker
// and can call it from the BlueMarker instance.
Integer i = obj2.price();
system.debug(' price: ' + i);
Debug logs:


  • Abstract class can also extends virtual class
defining a abstract class which extends a virtual class

/**
* Declaring and defining Abstract class extending Virtual class
*/
public abstract class AbstractMarker extends Marker {
public override void write(){
system.debug(' ABSTRACTMARKER: writing text with permanent Marker.');
}
// Declaring abstract method
public abstract decimal discount(Integer markerCount);
}

Defining a child class which extends a Abstract class which is extending a virtual class
/**
* Child class extending Abstract class which extended Virtual class
*/
public class ExtendController extends AbstractMarker{
public override decimal discount(Integer markerCount) {
if(markerCount > 10) {
return 1.5;
} else {
return 0.5;
}
}
}


Open developer console and run below code and observe the logs


Marker obj1, obj2, obj3;
obj1 = new Marker(); 
// this will output : 'MARKER: writing some text'
obj1.write(); 


obj2 = new ExtendController();
//below will output: 'ABSTRACTMARKER: writing text with permanent Marker.'
obj2.write(); 

// below code will give an error 'Abstract classes cannot be constructed: AbstractMarker'
obj3 = new AbstractMarker();
obj3.write();


Reference:

Sunday, 3 February 2019

Interface Class in Apex

Interface is similar to class, it can have methods and variables and methods are default abstract (method with abstract keyword, only declaration not body).

Interface is been used for total abstraction.

Difference between interface and abstract class.


Abstract Class Interface Class
Use abstract keyword to declare abstract class. Use interface keyword to declare interface
An abstract class can be extended using keyword "extends". As interface class can be implemented using keyword "implements".
You can define constructors in abstract class. Interface cannot have any constructors.
Abstract class can have methods with implementations. Interface provides absolute abstraction i.e. methods do not have any implementation or body.
A child/sub-class can only extends one abstract class. A child/sub-class can implements multiple interface
In abstract class, you can call methods in the abstract's child and abstract class methods. In interface all methods are already implemented in child (mandatory), so can directly refer child class.
example:
public abstract class Shape{
public abstract void draw();
}
example:
public interface class Shape{
void shape(string param);
}
You need to use keyword override to implement abstract class method.
public override integer methodName(params..){}
use of keyword override is not required to implement interface class method.
public integer methodName(params..){}

Below is Interface class:
/**
* Interface class, all method declared in interface are abstract methods
* its mandatory to implement these methods in child class
* interface do not include constructor
* their is no need to use abstract keyword as interface are implicitly abstract
* interface method do not include access modifiers only their prototype is available
*/
public interface Mammal {
Boolean eat(string name);
Boolean canfly(string name);
}
view raw Mammal.cls hosted with ❤ by GitHub

below child class implements the interface
/**
* Child class which implements the interface Mammal
* child class will use implements keyword
* will implements all methods declared in Mammal class
* it will not use override keyword override to use the method declared in interface
*/
public class Human implements Mammal{
public Boolean eat(string name) {
if(name == 'human') {
return true;
} else {
return false;
}
}
public Boolean canfly(string name) {
if(name == 'human') {
return false;
} else {
return true;
}
}
}
view raw Human.cls hosted with ❤ by GitHub


run below code snippet in developer console, you will get an error "type cannot be constructor:Mammal".

Mammal mam = new Mammal();


now run below code and observe the outcome

Human mam = new Human();
system.debug(' ##### => ' + mam.eat('human')) ;

system.debug(' ##### => ' + mam.canfly('human')) ;



Notes:
1. You cannot instantiate interface.
2. An interface does not contains any constructor.
3. All methods declared in interface are abstract.
4. An interface is implemented by class.
5. An interface can extends multiple interface.


Please click on below link for more references: 
Rajat Mahajan, guru99geeksforgeeks, tutorialspoint.com

Saturday, 2 February 2019

Abstract Class Use in Apex

abstract keyword is used to create a abstract class and method. Abstract class cannot be instantiated. An abstract class is mostly used to provide a base for sub-classes to extend and implements the abstract methods and override or use the implemented methods in abstract class.

Abstract classes are classes which have at-least one method declared as abstract(method with keyword abstract).

When you instantiate a class extending abstract class, first abstract class constructor is called then constructor of child get called.

Lets create Abstract class and extends it


/**
* Abstract Controller, contains instance variable, constructor.
* Abstract class cannot be instantiated and contains one abstract method.
*/
public abstract class AbstractController {
public Integer result;
public Integer getresult() {
if(result != null) {
return result;
} else {
return null;
}
}
public void setResult(Integer result) {
this.result = result;
}
public AbstractController() {
system.debug(' Abstract constructor called ');
}
// this method needs to be implemented by all class extending this
public abstract Integer calculate(Integer val1, Integer val2);
}

/**
* this class extends AbstractController and implements abstract method
*/
public class Calculator extends AbstractController {
public Calculator() {
System.debug(' Calculator class extends AbstractController');
}
public override Integer calculate(Integer val1, Integer val2) {
Integer result = val1 + val2;
system.debug(' Calculated value : ' + result);
return result;
}
}
view raw Calculator.cls hosted with ❤ by GitHub


Now go to Developer console and run below code and observe the output in debug logs.

Calculator cal = new Calculator();
cal.Calculate(10,20);

below is the output:



Note: 
1. You cannot directly call the abstract class constructor i.e. if you tried to run below code you will get an error.

AbstractController abst = new AbstractController();


2. A child class must implment the abstract method of its extended class but at the same time can also use other methods and variable defined in abstract class.