In some scenarios it is useful to invoke the rule engine directly from your custom APEX code. 


Applying a business policy involves a callout to our server. Due to Salesforce restrictions, it is not possible to make a callout synchronously in all contexts (such as from a trigger) -- but the policy can still be applied asynchronously. 


Contexts for invoking a business policy include:

  • Synchronous invocation
    Typically from a Visualforce or Lightning controller, or from a future method
  • Trigger
  • Scheduled APEX
  • Batch APEX


Each is described in more detail below

Apply a policy synchronously (from a Visualforce or Lightning controller, or future method)

To apply a business policy to a single record, your code would look like this:

sObjectType objType =...; // Object to which your policy applies
String policyName = .... ;// Name of your policy

DecsOnD.PolicyInvocationContext ctxt = new DecsOnD.PolicyInvocationContext(objType, policyName);

ID recordId = ...; // ID of the record to process
DecsOnD.ApplyPolicyHelper helper = DecsOnD.ApplyPolicyHelper.createHelper(ctxt, recordId);

// Alternatively, if you already have the record loaded, use: 
// sObject rec = ...; 
// DecsOnD.ApplyPolicyHelper helper = DecsOnD.ApplyPolicyHelper.createHelper(ctxt, rec);
// NOTE: in this scenario the record must be loaded with all fields accessed by the policy

// Prepare and send request to the Decisions on Demand server
DecsOnD.DecisionRequest req = helper.prepareDecisionRequest();        
DecsOnD.DecisionResponse response = helper.executeDecisionRequest(req);
if (response.status != 'OK') {  
  List<String> errors = response.getErrorMessages();
  // Handle error or return messages.
} else {
  List<DecsOnD.PolicyActionRecord> actionRecs = helper.prepareActions(response);
  List<String> msgs = helper.applyActions(actionRecs);      
  // Optionally, create an execution record 
  helper.createExecutionRecord(response, actionRecs);
}


To apply a business policy to multiple records in one operation, use the following:

sObjectType objType =...; // Object to which your policy applies
String policyName = .... ;// Name of your policy

DecsOnD.PolicyInvocationContext ctxt = new DecsOnD.PolicyInvocationContext(objType, policyName);

List<sObject> records = ....; // List of records -- must be loaded with all fields accessed by the policy

List<DecsOnD.ApplyPolicyHelper> helpers = DecsOnD.ApplyPolicyHelper.applyPolicyBatch(ctxt, records);

// Optionally, create execution records
DecsOnD.ApplyPolicyHelper.createBatchExecutionRecords(helpers);


Note that this code will make a callout, so:

Apply a policy from a trigger

The following methods are used to apply a policy from a trigger:

  • On insert
    Map<String, String> DecsOnD.TriggerExecutionHandler.executePolicySObjectInsert(Map<Id, SObject> scope, String triggerEvent);
  • On update
    Map<String, String> DecsOnD.TriggerExecutionHandler.executePolicySObjectUpdate(Map<Id, SObject> scopeNew, Map<Id, SObject> scopeOld, String triggerEvent);
  • On delete
    Map<String, String> DecsOnD.TriggerExecutionHandler.executePolicySObjectDelete(Map<Id, SObject> scope, String triggerEvent);


Notes:

  • In all cases, the API should called in the after event
  • The triggerEvent parameter is used to distinguish the trigger in logs -- it is optional
  • The return value will be null on successful invocation. If there are errors, it will contain a map of record IDs to the error messages returned for those records
  • Even if the above API is called, the rules will only be invoked if the corresponding trigger is activated on the Business Policy detail page

See the Administrator Guide for more details, including a complete code example.

Apply a policy from a scheduled job or Batch APEX

This code shows the execute method of a simple scheduled job to apply a policy to a set of records defined by an (optional) SOQL where clause.


public void execute(SchedulableContext sc) {
    sObjectType objType =...; // Object to which your policy applies
    String policyName = .... ;// Name of your policy
    String whereClause = ....; // SOQL where clause selecting records to be processed 
    boolean createExecutionRecord = ....; // whether or not to create an execution record

    DecsOnD.PolicyInvocationContext ctxt = new DecsOnD.PolicyInvocationContext(objType, policyName);

    DecsOnD.BatchExecutePolicy bep = new DecsOnD.BatchExecutePolicy(ctxt, whereClause);
    bep.createExecutionRecord = createExecutionRecord;
    ID batchId = Database.executebatch(bep);             
}


Notes:

  • DecsOnD.BatchExecutePolicy will throw an exception if there is any failure during execution of the business rules, but some records may still have been processed successfully.
    The exception message will contain details.
  • You can create a batch for a specific set of records using the following constructor
    List<sObject> scope = ...;
    DecsOnD.BatchExecutePolicy bep = new DecsOnD.BatchExecutePolicy(ctxt, scope);


Batch APEX

If you are updating records in a batch, and then wish to apply a business policy to these same records, you will need to start a second batch, because it is not possible to directly apply the policy to records that have been modified in the same APEX transaction. See this Salesforce Knowledge Article for details.


To create a nested batch, use the same code as that shown above for a scheduled job, but place it in the finish method of the first batch.