The Silver Lining

A developer's view of Cloud Computing platforms & technologies.

Archive for the ‘Apex’ Category

Salesforce: Universal Batch Scheduling Class

with one comment

Mark David Josue. All Rights Reserved.I’d like to propose a new way of working with scheduled batch classes. I’ve worked on several hundred Salesforce projects in the past few years and often see batch scheduling classes being created per scheduling requirement and it grinds my OCD – not in a good way. In most cases you should only need one “Batch Scheduler” per Org, let me demonstrate how and why.

The Universal Batch Scheduler™

Requirements

Let’s assuming you have a batch class that you need to run on a repeated schedule*, such a class signature is given below. That class will have to obey some conventions such as implementing the Batchable interface as shown in the standard documentation.

global class MyBatch implements Database.Batchable<SObject> {

// …

}

* For one off, schedule execution of batch classes you can use the System.ScheduleBatch() method.

The Scheduler

Now you might be tempted to created a scheduled Apex class specifically for this batch class, but by using the principle of polymorphism you could create a universal scheduler instead.

First of all you’ll need to implement the required interface for scheduled Apex classes as shown below.

global class BatchScheduler implements Schedulable {

// …

}

Next assign global, class-level variables which will be used to access the parameter values required when executing a batch class. Note that we’re creating a variable called “batchClass” whose type is the interface Database.Batchable. This means that any class that implements this interface can be assigned to this variable, this behaviour is called polymorphism.

  global Database.Batchable<SObject> batchClass{get;set;}
  global Integer batchSize{get;set;} {batchSize = 200;}

And finally implement the method required by the Scheduleable interface and use the variables to kick off the execution of a batch class.

  global void execute(SchedulableContext sc) {
   database.executebatch(batchClass, batchSize);
  }

Et voila! You now have a class that can be used to schedule any batch class in your Org. The final code being:

global class BatchScheduler implements Schedulable {
  global Database.Batchable<SObject> batchClass{get;set;}
  global Integer batchSize{get;set;} {batchSize = 200;}

  global void execute(SchedulableContext sc) {
   database.executebatch(batchClass, batchSize);
  }
}

In order to use it you would have to initiate the schedule from an anonymous block (Developer Console, Eclipse, Mavensmate etc.). For example I would schedule my batch class using something like this:

// Instantiate the batch class
MyBatch myBatch = new MyBatch();

// Instantiate the scheduler
BatchScheduler scheduler = new BatchScheduler();

// Assign the batch class to the variable within the scheduler
scheduler.batchClass = myBatch;

// Run every day at 1pm
String sch = '0 0 13 * * ?';

System.schedule('MyBatch - Everyday at 1pm', sch, scheduler);

There may be cases where the universal batch scheduler is not appropriate i.e. special pre-work has to be done in the scheduling class, but in most cases I’ve seen it’ll do the job. Hopefully this’ll help you make your Orgs a little neater too.

Written by Wes

February 2, 2014 at 12:34 pm

Salesforce JavaScript Remoting: Using Apex and JavaScript objects to pass data from client- to server-side and vice versa

with 13 comments

I’ve spoken about how to do this at a high-level during Cloudstock London and there are hints at how it can be done but no formal documentation that I’ve found, so here we are :)

Quite simply JavaScript Remoting will transform Apex objects and classes (or collections of these types) into JavaScript objects for you. The opposite is true too but there are some rules you need to observe.

Apex Types to JavaScript Equivalents

This is the easier of the type conversions in that you don’t have to really do anything to make it happen. The code below uses a custom class that I’ve defined but you can do the same with any sObject too. Let’s have a look at the code.

The Controller

public with sharing class RemotingObjectsController {

    /* The remoting method simply instantiates a two custom types, puts
       them into a list and then returns them. */
    @RemoteAction
    public static List<CustomClass> getClassInstances(){
        List<CustomClass> classes = new List<CustomClass>();

        CustomClass me = new CustomClass('Wes');
        CustomClass you = new CustomClass('Champ');

        classes.add(me);
        classes.add(you);

        return classes;
    }

    /* My custom type */
    public class CustomClass{
        public String firstName{get;set;}

        CustomClass(String firstName){
            this.firstName = firstName;
        }
    }
}

The Visualforce

<apex:page controller="RemotingObjectsController">
  <script>
      // Will hold our converted Apex data structures
      var classInstances;

      Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.RemotingObjectsController.getClassInstances}',
        function(result, event) {
          // Put the results into a var for pedantries sake
          classInstances = result;

          console.log(classInstances);

          // Assign the first element of the array to a local var
          var me = classInstances[0];

          // And now we can use the var in the "normal" JS way
          var myName = me.firstName;
          console.log(myName);
        });
  </script>
</apex:page>

The Output

Console output from the JS code.

JavaScript Types to Apex Equivalents

This is a little tricker, especially when it comes to sObjects. Note that the approach below works for classes and sObjects too.

The Visualforce Page

<apex:page controller="RemotingObjectsController">
  <script>
      /* Define a JavaScript Object that looks like an Account */
      /* If you were using custom objects the name must include the "__c" */
      function Account(){
          /* Note the field names are case-sensitive! */
          this.Id = null; /* set a value here if you need to update or delete */
          this.Name = null;
          this.Active__c = null; /* the field names must match the API names */
      }

      var acc1 = new Account();
      acc1.Name = 'Tquila';
      acc1.Active__c = 'Yes';

      var acc2 = new Account();
      acc2.Name = 'Apple';
      acc2.Active__c = 'Yes';

      var accounts = new Array(acc1, acc2);

      Visualforce.remoting.Manager.invokeAction(
        '{!$RemoteAction.RemotingObjectsController.insertAccounts}',
        accounts,
        function(result, event) {
          console.log(result);
        });
  </script>
</apex:page>

The Controller

There not much to the controller in this case.

public with sharing class RemotingObjectsController {

    @RemoteAction
    public static void insertAccounts(List<Account> accounts){
        insert accounts;
    }

}

Why is this cool?

Good question. If the Force.com Platform didn’t do this for you then we – the developer – would need to convert ours types explicitly on both the server-side and the client-side, and man-oh-man is that boring, error-prone work. Yet again the guys at salesforce.com have built in a convenience that saves us time and let’s us get on with the work of building cool apps.

Written by Wes

June 22, 2012 at 11:06 am

Salesforce: JavaScript Remoting – a different way of thinking

with 6 comments

 

Remoting is awesome.

JavaScript Remoting for Apex operates in a very different paradigm from what you might be used to i.e. Visualforce pages have controllers and the two interact through action methods – where this might be a full form submission or some neat AJAX functionality. Remoting also calls controller methods but there is a gaping maw in terms of how the two work under the hood.

I’ve seen a few great articles on the syntax and example usage of JavaScript Remoting for Apex but when I started using it I came across a number domain differences that weren’t documented anywhere. Hopefully my list here will help you in the learning process. The best way to describe the new way of thinking is to examine the features set in contrast to “normal” Apex and Visualforce.

How JavaScript Remoting Differs

  • Pass parameters naturally i.e. the call matches the method signature syntactically instead of requiring <apex:param/>.
  • Action methods when called in “normal” Visualforce can only return NULL or a PageReference. Remoting allows you to return a wider range of data types, even objects and collections.
  • Remoting methods have no access to the view state e.g. if a static variable is initialised to some value (outside the remoting method) a remoting method will see this as NULL unless it is re-initialised in that method! Conversely if a remoting method sets a state variable value the scope of that value is only within that method.
  • It’s much faster. I’m building an application at the moment that is 95% backed by JS Remoting and when I show it to other developers they are struck dumb for at least 3 hours because of the speed.
  • Neater debugging info in the browser console. Salesforce has done a great job of providing feedback directly to the browser’s console log.
  • Each method call gets its own executional/transactional context i.e. fresh governor limits per call!

If I’ve missed anything please let me know and I’ll add it. Viva la knowledge crowdsourcing!

Written by Wes

February 5, 2012 at 4:05 pm

Salesforce: Dynamically determining the field type of a dynamically determined sObject

with 2 comments

This solution is quite difficult to find.

Call me crazy but I need to do this from time to time, and every time I do I can’t remember how I did it before! So I then trudge through the API and the Apex docs until I find the answer and that’s no mean feat in this specific case. Well, no more my friends because I’m putting it right here on this very blog!

In short the code below will return (as a String) the type of field that we’re working with. Neither the name of the object or the name of the field need to be known in advance.

    public static String getFieldType(String fieldName){
    	// Assume that "sObjectName" is populated elsewhere
	Schema.SObjectType t = Schema.getGlobalDescribe().get(sObjectName);

	Schema.DescribeSObjectResult r = t.getDescribe();
	Schema.DescribeFieldResult f = r.fields.getMap().get(fieldName).getDescribe();

	if (f.getType() == Schema.DisplayType.String){
		return 'String';
	} // .... else if

	return null;
    }

Written by Wes

February 1, 2012 at 9:33 pm

Salesforce: Different percentage unit test code coverage in different environments

with 3 comments

Spot the difference.

Many people are finding that their tests are reporting different degrees of test-coverage in different environments. There are a few things to check if you are getting inconsistent results but there’s a new bug in the wild. Before you assume you have the bug make sure that you’ve:

  1. ‘Run All Tests’ in each environment. This will tell you a few things viz.
    • Perhaps there are tests failing that are bringing coverage in that environment down.
    • There are some tests that only fail when run in the browser e.g. MIXED_DML_EXCEPTION will not rear it’s head through the IDE.
  2. Click the ‘Compile all classes’ link above the Setup > Develop > Apex Classes view. I’m not sure when this lil’ bugger first appeared but it’s darn useful. Essentially it makes sure that all the dependencies in your code are fulfilled e.g. if page A uses controller B that in turn refers to utility class C it’ll make sure each of those pieces exist and work (as far as compilation goes at least).
  3. Double-check your test classes to make sure they’re not data dependent. If they are and you have different types/amounts of data in your respective environments it’s 100% feasible that the test coverage will be different.

Now if you’ve checked all of the above you might have been afflicted by a new bug which, for some reason, counts braces, whitespace (and more!) as being uncovered by your tests. This is preposterous of course and to fix it simply remove all test history from the deranged environment. Re-running the test and/or deploying them should now be back to normal!

Written by Wes

November 30, 2011 at 11:01 pm

Salesforce: Stop email being sent on user creation or password reset or …

leave a comment »

I’ve had to do this a few times but infrequently enough for me to forget how to do it each time. Forgetting things isn’t usually an issue because of our Google Overlords and their mighty The Google but it’s quite a journey down the rabbit hole to find this specific information.

The reasons it’s tricky to find is because the setting that controls whether an email is sent to the user on creation is not directly associated with users but with DML. Long story short you need to set a particular Database.DMLOption e.g.


User u = new User();
// Add some details here ...

// Set the DML options
Database.DMLOptions dlo = new Database.DMLOptions();
dlo.EmailHeader.triggerUserEmail = false;

Database.insert(u,dlo);

Hopefully this information will now be easier to find next time I forget :)

Written by Wes

October 30, 2011 at 1:12 pm

Posted in Apex, SalesForce

Tagged with , , , , ,

Salesforce & LinkedIn Developer API: 401 – Unauthorized

with 3 comments

Image representing LinkedIn as depicted in Cru...

Image via CrunchBase

I’m not going to get into the boilerplate code you’ll need in order to get OAuth up and running as it’s pretty straight forward, but I did run into a peculiar issue which took me some time to narrow down. To reproduce these steps you’ll need to:

  1. Correctly setup OAuth between the Force.com Platform and LinkedIn
  2. Authorise access to your LinkedIn account
  3. Attempt to fetch a resource using an API endpoint such as: http://api.linkedin.com/v1/people/~/network/updates?scope=self

When attempting to make the call out in step 3 you’ll get a “401 – Unauthorized” error. So to be clear OAuth is working perfectly but a call like this one will still result in the error.

After some troubleshooting I noticed that some API endpoints didn’t result in the error e.g. http://api.linkedin.com/v1/people/id=abcdefg/network/updates?scope=self. At this point I realised the issue was probably the tilde (‘~’) character in the URI.

Grasping at straws I manually replaced the tilde with it’s URL friendly equivalent ‘%7E’ and the callout worked perfectly. Now this is strange because I am, in the course of making the callout, URL encoding all parts of the endpoint URL. It seems that for some reason the LinkedIn OAuth services needs to have the tilde encoded twice when signing the request :/

Salesforce: Programmatically Populating Sample Data Post-Deployment

with 12 comments

I’m not sure if this concept is obvious when reading my previous post, so I thought I’d run through it with a specific example.

Rule one of packaging - Finish your bolognese first!

Let’s say that you’ve created what can only be described as an exemplary application in the form of a Managed Package. Although your user interface is beyond compare, you’d also like to populate some of your core objects with example data. Some options that immediately spring to mind are:

  1. Get the person that installs the package to call you, and you can do it post-installation.
  2. Get the person that installs the package to create sample data manually post-installation.
  3. Give the user a “Start Here” page with a call-to-action – such as a commandButton – that fetches the data from some API and parses into object data.

Option 3 is pretty excellent, especially now that you can package Remote Site Settings but I think we can do one better. And when I say better I mean simpler and with fewer potential points of failure. Read the rest of this entry »

Written by Wes

January 28, 2011 at 6:45 pm

Salesforce: Instantiating an SObject Dynamically at Run-time

with 13 comments

I’m sure a lot of you have this documented somewhere but I’ve recently discovered that it’s quite difficult to find an obvious reference to this knowledge on the interwobbles. So how would you create a Generic SObject at run-time? It’s rather easy thankfully:

String sObjectName = 'MyObject__c';
Schema.SObjectType t = Schema.getGlobalDescribe().get(sObjectName);
SObject s = t.newSObject();

If you require this type of functionality quite often I’d suggest putting it in a utility class.

Written by Wes

January 25, 2011 at 8:54 pm

Salesforce: Enhanced Custom Settings

with 14 comments

Okay book’s done, now where were we? Oh yes software development, right? Programming software engineering application development h4x0R-ing. Oh how I’ve missed getting my mitts dirty so without further ado…

Now this one goes right about... here!

Some time back Custom Settings were introduced on the Force.com Platform and we all star-jumped in the air, w00ting to anyone who would listen. Up till this point – if you’re anything like me – you were using custom objects to hold configuration data, whether this be lists of language-codes, or operational settings such at outbound web service endpoints, usernames, passwords etc. With Custom Settings you finally had a place to put this information – a home if you will – for your lonely, orphaned Control Data.

Quite quickly however I realised there was still a gaping hole that could be filled with Custom Settings but just didn’t feel right. Lists of data (such as currency codes and descriptions) fit really well into this structure but more serious Control Data that you only need to be listed once-off (such as important URLs, flags to active/deactive modules in your application, usernames and passwords) just don’t seem like they really belong with this other crowd. A quick list of reasons highlights this:

  • Control Data is typically entered once off and creating an entire Custom Setting for a single line of data feels like a waste.
  • Custom Settings are data so they can’t be deployed with code, they must be created after the fact. Control Data should be a little more important than regular data, it needs a smarter vehicle than plain-old data entry.
  • If you’re creating packages you want as much autonomy for your clients as possible. If you use custom settings there will have to be that “Create data in Custom Setting X__c” step in each and every deployment. Read the rest of this entry »

Written by Wes

December 30, 2010 at 4:49 pm

Follow

Get every new post delivered to your Inbox.

Join 1,849 other followers

%d bloggers like this: