First, here are a couple of usage examples. These can be run in an "Execute Anonymous" window in the developer console or Force.com IDE.
// 1. schedule a process to delete old accounts and email myself when complete
System.schedule('Account Cleanup', '0 0 0 1 * *', new SF_Batch('Delete old accounts',
SF_Batch.OP.OP_DELETE, 'SELECT Id FROM Account WHERE CreatedDate != THIS_YEAR',
new String[] {'scox67@gmail.com'}));
// 2. mark all my cases as 'TEST'
class AccountNameUpdater implements SF_Batch.Handler {
public void handle(SObject[] scope) {
for (Case c : (Case[])scope) {
c.Name += ' TEST';
}
}
}
Database.executeBatch(new SF_Batch('Mark Test Cases', SF_Batch.OP.OP_UPDATE,
'SELECT Name FROM Case WHERE Owner.Name = \'Steve Cox\'',
new AccountNameUpdater(), null);
If several scheduled cleanup tasks are needed in your org, you can create a custom setting and use a simple function like scheduleAllJobs (below) to load them all up at once. Here's the complete code listing. Enjoy!
public class SF_Batch implements Database.Batchable<SObject>, Schedulable {
//--------------------------------------------------------------------------
// Constants
public enum OP { OP_UPDATE, OP_DELETE, OP_UNDELETE }
private final static String ALL_ROWS = ' ALL ROWS ';
// {0} = process name, {1} = status
private final static String NOTIFY_SUBJECT = 'Salesforce Batch Process: {0} - {1}';
// {0} = total batches processed, {1} = number of failures
private final static String NOTIFY_BODY = '{0} batch(es) processed, with {1} failure(s).';
//--------------------------------------------------------------------------
// Properties
private String name;
private String query;
private OP operation;
private Handler handler;
private String[] notify;
//--------------------------------------------------------------------------
// Constructor
/**
* Create a batch process
* @param name optional name of the process. This will be reported in the
* notification email.
* @param operation the operation to perform
* @param query the query used to select records
* @param handler an optional handler. If specified, h.handle() will be called
* and passed the array of objects before the operation is performed.
* @param notify optional email addresses for finish or error notifications
*/
public SF_Batch(String name, OP operation, String query, Handler handler, String[] notify) {
SF.preCondition(null != operation, 'SF_Batch.SF_Batch() - missing operation');
SF.preCondition(!SF.isEmpty(query), 'SF_Batch.SF_Batch() - missing query');
this.name = name;
this.operation = operation;
this.handler = handler;
this.notify = notify;
if ((OP.OP_UNDELETE == operation) && !query.contains(ALL_ROWS)) {
this.query = query + ALL_ROWS;
} else {
this.query = query;
}
// validate that the query is valid
SObject[] o = Database.query(this.query);
}
public interface Handler {
void handle(SObject[] scope);
}
/** Database.Batchable method */
public Database.QueryLocator start(Database.BatchableContext context) {
return Database.getQueryLocator(query);
}
/** Database.Batchable method */
public void execute(Database.BatchableContext context, SObject[] scope) {
if (null != handler) {
handler.handle(scope);
}
if (OP.OP_UPDATE == operation) {
update scope;
} else if (OP.OP_DELETE == operation) {
delete scope;
} else if (OP.OP_UNDELETE == operation) {
undelete scope;
}
}
/** Database.Batchable method */
public void finish(Database.BatchableContext context) {
if (null != notify) {
AsyncApexJob a = [SELECT Status, NumberOfErrors, JobItemsProcessed, TotalJobItems,
CreatedBy.Name FROM AsyncApexJob WHERE Id = :context.getJobId()];
final String subject = String.format(NOTIFY_SUBJECT, new String[]{
String.valueOf(name), String.valueOf(a.Status)});
final String body = String.format(NOTIFY_BODY, new String[]{
String.valueOf(a.TotalJobItems), String.valueOf(a.NumberOfErrors)});
new SF.Email(notify, null, null, subject, body).send();
}
}
/** Schedulable method */
public void execute(SchedulableContext SC) {
Database.executeBatch(new SF_Batch(name, operation, query, handler, notify));
}
//--------------------------------------------------------------------------
// Schedule/abort processes from custom settings
/**
* Schedule all active jobs specified in the SF Job custom setting.
*/
public static void scheduleAllJobs() {
final Map<String, Batch.OP> opMap = new Map<String, Batch.OP> {
'update' => SF_Batch.OP.OP_UPDATE,
'delete' => SF_Batch.OP.OP_DELETE,
'undelete' => SF_Batch.OP.OP_UNDELETE
};
SF_Job__c[] jobs = new SF_Job__c[]{};
for (SF_Job__c j : [SELECT Name, Schedule__c, Operation__c, Query__c,
Email_Recipients__c FROM SF_Job__c WHERE Active__c = true]) {
final SF_Batch b = new SF_Batch(j.Name, opMap.get(j.Operation__c.toLowerCase()),
j.Query__c, null, (null != j.Email_Recipients__c)? j.Email_Recipients__c.split(',') : null);
final Id cronId = System.schedule(j.Name, j.Schedule__c, b);
jobs.add(new SF_Job__c(Id = j.Id, Job_Id__c = cronId));
}
update jobs;
}
/**
* Abort all active jobs launched with scheduleAllJobs
*/
public static void abortAllJobs() {
SF_Job__c[] jobs = new SF_Job__c[]{};
for (SF_Job__c j : [SELECT Job_Id__c FROM SF_Job__c WHERE Job_Id__c != null]) {
System.abortJob(j.Job_Id__c);
jobs.add(new SF_Job__c(Id = j.Id, Job_Id__c = null));
}
update jobs;
}
}
No comments:
Post a Comment