Making your managed package
extensible with Apex Plugins

Stephen Willcock, FinancialForce.com, Director of Product Innovation
@stephenwillcock
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
 intellectual property and other litigation, risks associated with 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-Q for the most recent fiscal quarter ended July 31, 2012. This
 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.
All about FinancialForce.com
Stephen Willcock
Director, Product Innovation
@stephenwillcock
What is an Apex Plugin?

An Apex plugin for a managed package is an external class that is
called from within the package


The package has no dependency on the class, which is
instantiated dynamically by runtime configuration
Why use a Plugin?

Plugins allow changes to the execution of packaged Apex
processes
            Managed Package
                                            Runtime Configuration:
                                            Runtime Configuration:
              Opportunity Adjuster         Use “CustomAdjuster” for
                                           Use “CustomAdjuster” for
                                           Adjusting Opportunities
                                            Adjusting Opportunities



                                          CustomAdjuster plugin
                        Call the plugin
Where to use a Plugin?
   Visualforce UIs
   Triggers
   @RemoteAction methods
   Apex APIs
   Batch Apex
   Generic plugins for common calculations
   “Apex Validation Rules”
   “Apex Workflow Rules”
Example use case

Application for adjusting Opportunity values
Visualforce UI
Customizable adjustment and validation
Implementation
 Managed Package

  public class AdjustOpportunityController


  global class Plugin                          Runtime Configuration:
                                               Runtime Configuration:
                                              Use “CustomAdjuster” for
                                              Use “CustomAdjuster” for
  public static IAdjustOpportunities          Adjusting Opportunities
                                               Adjusting Opportunities
  getInstanceIAdjustOpportunities()

                                             global class CustomAdjuster
  global interface IAdjustOpportunities      implements IAdjustOpportunities
Implementation   global class Plugin
                                               Packaged
                                               Code

global interface IAdjustOpportunities
{
    void adjust(Opportunity opportunity,
        List<OpportunityLineItem> lineItems,
        Decimal proportion);
}
Implementation   global class Plugin
                                       Packaged
                                       Code
Implementation   global class Plugin
                                             Packaged
                                             Code

public static Plugin.IAdjustOpportunities
    getInstanceIAdjustOpportunities()
{
    Object result = getInstance
        ('IAdjustOpportunities');
    return (Plugin.IAdjustOpportunities)
        (result == null
        ? new DefaultAdjustOpportunities()
        : result);
}
Implementation   global class Plugin
                                       Packaged
                                       Code
Implementation   global class Plugin
                                                  Packaged
                                                  Code

 // do the adjustment here...

 for(OpportunityLineItem item : opportunityLineItems)
   item.UnitPrice = item.UnitPrice +
       (item.UnitPrice * adjustmentProportion);

 opportunity.Amount = opportunity.Amount +
   (opportunity.Amount * adjustmentProportion);
Implementation   public with sharing class
                                                    Packaged
                   AdjustOpportunityController      Code

void adjust()
{
    Plugin.IAdjustOpportunities adjuster =
        Plugin.getInstanceIAdjustOpportunities();

    adjuster.adjust(getOpportunity(),
        getOpportunityLines(),
        getAdjustmentProportion());
}
Plugin
Implementation   global class CustomAdjuster     Code
Configuration options

Manual custom settings
Discovery by name pattern
Assisted custom settings
Plug-and-play




                Demo
Considerations

Consider the lifecycle / context of a plugin instance
    Triggers: bulk usage / before and after triggers
    Instantiation within a loop / discarding instances
    Visualforce viewstate

Interface granularity
Extend or override?
Only default plugin constructors are used
Versioning of global interfaces by name
Unplug

Resources
   Sample code and package installation URL available from
    https://github.com/financialforcedev/df12-apex-plugins
   Martin Fowler, Patterns of Enterprise Application Architecture:
      • Plugin http://martinfowler.com/eaaCatalog/plugin.html
      • Separated Interface http://martinfowler.com/eaaCatalog/separatedInterface.html
   @stephenwillcock

Questions?
Making your managed package extensible with Apex Plugins

Making your managed package extensible with Apex Plugins

  • 1.
    Making your managedpackage extensible with Apex Plugins Stephen Willcock, FinancialForce.com, Director of Product Innovation @stephenwillcock
  • 2.
    Safe harbor Safeharbor 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 intellectual property and other litigation, risks associated with 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-Q for the most recent fiscal quarter ended July 31, 2012. This 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.
  • 3.
  • 4.
    Stephen Willcock Director, ProductInnovation @stephenwillcock
  • 5.
    What is anApex Plugin? An Apex plugin for a managed package is an external class that is called from within the package The package has no dependency on the class, which is instantiated dynamically by runtime configuration
  • 6.
    Why use aPlugin? Plugins allow changes to the execution of packaged Apex processes Managed Package Runtime Configuration: Runtime Configuration: Opportunity Adjuster Use “CustomAdjuster” for Use “CustomAdjuster” for Adjusting Opportunities Adjusting Opportunities CustomAdjuster plugin Call the plugin
  • 7.
    Where to usea Plugin?  Visualforce UIs  Triggers  @RemoteAction methods  Apex APIs  Batch Apex  Generic plugins for common calculations  “Apex Validation Rules”  “Apex Workflow Rules”
  • 8.
    Example use case Applicationfor adjusting Opportunity values Visualforce UI Customizable adjustment and validation
  • 9.
    Implementation Managed Package public class AdjustOpportunityController global class Plugin Runtime Configuration: Runtime Configuration: Use “CustomAdjuster” for Use “CustomAdjuster” for public static IAdjustOpportunities Adjusting Opportunities Adjusting Opportunities getInstanceIAdjustOpportunities() global class CustomAdjuster global interface IAdjustOpportunities implements IAdjustOpportunities
  • 10.
    Implementation global class Plugin Packaged Code global interface IAdjustOpportunities { void adjust(Opportunity opportunity, List<OpportunityLineItem> lineItems, Decimal proportion); }
  • 11.
    Implementation global class Plugin Packaged Code
  • 12.
    Implementation global class Plugin Packaged Code public static Plugin.IAdjustOpportunities getInstanceIAdjustOpportunities() { Object result = getInstance ('IAdjustOpportunities'); return (Plugin.IAdjustOpportunities) (result == null ? new DefaultAdjustOpportunities() : result); }
  • 13.
    Implementation global class Plugin Packaged Code
  • 14.
    Implementation global class Plugin Packaged Code // do the adjustment here... for(OpportunityLineItem item : opportunityLineItems) item.UnitPrice = item.UnitPrice + (item.UnitPrice * adjustmentProportion); opportunity.Amount = opportunity.Amount + (opportunity.Amount * adjustmentProportion);
  • 15.
    Implementation public with sharing class Packaged AdjustOpportunityController Code void adjust() { Plugin.IAdjustOpportunities adjuster = Plugin.getInstanceIAdjustOpportunities(); adjuster.adjust(getOpportunity(), getOpportunityLines(), getAdjustmentProportion()); }
  • 16.
    Plugin Implementation global class CustomAdjuster Code
  • 17.
    Configuration options Manual customsettings Discovery by name pattern Assisted custom settings
  • 18.
  • 19.
    Considerations Consider the lifecycle/ context of a plugin instance  Triggers: bulk usage / before and after triggers  Instantiation within a loop / discarding instances  Visualforce viewstate Interface granularity Extend or override? Only default plugin constructors are used Versioning of global interfaces by name
  • 20.
    Unplug Resources Sample code and package installation URL available from https://github.com/financialforcedev/df12-apex-plugins  Martin Fowler, Patterns of Enterprise Application Architecture: • Plugin http://martinfowler.com/eaaCatalog/plugin.html • Separated Interface http://martinfowler.com/eaaCatalog/separatedInterface.html  @stephenwillcock Questions?

Editor's Notes

  • #6 Plugin is an established design pattern FinancialForce.com uses a number of design patterns published in Martin Fowler, Patterns of Enterprise Application Architecture Andy’ Fawcett’s session: Applying Enterprise Application Design Patterns on Force.com
  • #8 Visualforce UIs - +fieldsets
  • #12 Update December 2013: Implement fix for Salesforce Winter 13 change in behaviour. Issue: https://sites.secure.force.com/success/issues_view?id=a1p30000000SVY3AAO
  • #17 In Winter ‘13 we will not need to make this class global
  • #18 Assisted: discover candidates from which a user selects and persists in cust setting
  • #20 Extend / override - responsibility of package or plugin?
  • #21 Chatter wall for this session