crm science - dreamforce '14: generic package extension architecture for appexchange partners
DESCRIPTION
Salesforce partners often have to dodge complexities that relate to the multi-tenancy nature of the Salesforce platform. Many of these complexities can be handled by dynamic handling of SOQL and object; however, sometimes more drastic measures need to be taken. Join us as we cover the required steps to writing a completely generic interface architecture that can call any external class, as well as other tips and tricks that make AppExchange package development a snap! You will learn how to use an extension architecture that implements an interface to generically call external packages or even methods in a target org that are unknown during base package build.TRANSCRIPT
Generic Package Extension Architecturefor AppExchange PartnersAmi Assayag
Chief Architect
CRM Science
@amiassayag
Kirk Steffke
Senior Developer
CRM Science
@kirkevonphilly
Safe Harbor
Safe harbor statement under the Private Securities Litigation Reform Act of 1995:
This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of
the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking
statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service
availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future
operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of
our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service,
new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions or
delays in our Web hosting, breach of our security measures, the outcome of any litigation, risks associated with completed and any possible mergers and
acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and
manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization
and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our
annual report on Form 10-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most recent fiscal quarter. These documents and
others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site.
Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not be
delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available.
Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
Place
Customer or
Partner logo in
white area of
slide, centered
Ami AssayagChief Architect
CRM Science
Place
Customer or
Partner logo in
white area of
slide, centered
Kirk SteffkeSenior Developer
CRM Science
Managed Package ChallengesFlexibility of platform creates (un)expected variability
• Access and permissions issues
Edition specific features
• Person accounts, record types, etc.
Optional standard features
• Org specific user access
Unknown sharing models
• Pre-existing or a-typical business logic
Varying target org business logic
“...in our org, we do
<process x> this
way.”
Customer Wants… Customer Gets…
“…your package
does <x>, can it
do <y>?”
“…we use <custom object> instead
of <standard object>“
Extension Package Flow
Salesforce Org
Optional Native Extension PackageBase Package
Trigger Trigger
Trigger Handler
Business logicBusiness logic Business logic
Callout Handler
External Application
Generic Extension Package Architecture Advantages
Completely generic
Can handle any org-specific complexity
Flexible and reusable
Extends to separate packages
or target orgs
Use to
introduce a
demo, video,
Q&A, etc. Technologies UsedThe right tools for the job…
Custom Settings
• Very similar to Custom Objects
Familiar
• Can be exposed to or hidden from end-users
Visibility
• Won’t count against SOQL limits
Efficient
• Apex
• Visualforce
• Formula Fields
• Web Services API
Readily Available
Interfaces
// A new global class w/in the Base Package
global with sharing class <className> {
}
// Define an interface with method blueprints
global interface <interfaceName>{
}
// Define a generic class with generic params
<returnType> <methodName(<parameters>);
Dynamic Instantiation of Classes
// get the type of the class outside the package that impl. the generic interface
Type t = Type.forName(<namespace>, <className>);
// use a concrete type of the intf. To create a new inst. of the ext. impl.
Extension ExtensionClass = (Extension)t.newInstance();
Use to
introduce a
demo, video,
Q&A, etc. Code Examples - Outbound3 Steps to Implement this Design Pattern
Step 1: Create Interface in the Base Package
// A new global class w/in the Base Package
global with sharing class BasePackage {
}
// Define an interface with method blueprints
global interface Extension {
}
// Define a generic class with generic params
object GenericMethod(list<object> params);
// anything inside this class can be custom
// in this example the business logic needs to make a callout to a different API
@future(callout = true)
public static void ProcessFutureCallout(set<id> RecordIds, string somestring) {
}
// in this case there is no need to return anything so return null;
return null;
// use the concrete type variables to call the class that does all the work
ProcessFutureCallout(RecordIds, somestring);
// replace input params with variables that have concrete types.
set<id> RecordIds = (set<id>)params[0];
string somestring = (string)params[1];
// define a the generic class that is present in the interface
public static object GenericMethod(list<object> params) {
}
public with sharing class MyExtension implements BasePackageNameSpace.BasePackage.Extension {
}
Step 2: Create External Class
// Use ExtensionClass to call the generic method with any relevant variable
list<object> retList = ExtensionClass.GenericMethod(
new list<object>{someRecordIds, someString}
);
// Using a concrete type of the int., create a new instance of the ext. implementation
BasePackage.Extension ExtensionClass = (BasePackage.Extension)t.newInstance();
// Get the type of the class outside the package that implements the generic interface
Type t = Type.forName(ext.Namespace__c, ext.ClassName__c);
else {
}
// Process normal business logic
if (ext == null) {
}
// Get the external class name from a custom setting
PackageExtension__c ext = PackageExtension__c.getInstance('extensionName');
Step 3: Call External Class from Within the Base Package
Use to
introduce a
demo, video,
Q&A, etc. Code Examples - InboundRe-using Common Code from the Base Package
// Instantiate a generic object to return
object retValue;
// Using a Base Package Class' internal public static method with parameters
else if (classDotMethod == 'BasePackageClass2.Method1')
BasePackageClass2.Method1(
(set<Id>)params[0],
(string)params[1],
(string)params[2]
);
// Return methods results to caller as an object
return retValue;
// Define a global entry point to the package that can be called from outside the package
global object CallMethod(string classDotMethod, list<object> params) {
}
Utilize Base Package Code from the Extension
// Using a Base Package Class' internal public static method
if (classDotMethod == 'BasePackageClass1.Method1')
retValue = BasePackageClass1.Method1();
Generic Package Extension Architecturefor AppExchange PartnersAmi Assayag
Chief Architect
CRM Science
@amiassayag
Kirk Steffke
Senior Developer
CRM Science
@kirkevonphilly