Monday, June 10, 2013

Saleforce HTTP callouts limit workaround

I need to do tons of requests to an external service that, unfortunately, doesn't allow me to put multiple action requests within one single HTTP request, so that each action I want to send to this external service I have to do an HTTP request. Problem: Salesforce allows you to do only ten HTTP requests per execution. I could use Batch Jobs to schedule all the requests I need, but Batch Jobs are executed when resources are free, and I want to have the requests to be sent almost in real time, not "when Salesforce has time to do it".

So, here's the workaround. The key is that the limit is "per execution", and an AJAX call (done through a standard Visualforce <apex:actionFunction>) is actually a single execution. I can "loop" in Javascript to do requests as long as I need it.

Let's have a look at the code.

The controller:
public with sharing class testJavascript {
 public String requestStatus { get; set; }
 public String requestMore { get; set; }
 public Integer requestNumber { get; set; }
 public Integer requestCurrent { get; set; }
 public testJavascript () {
  requestStatus = '';
  requestMore = '';
  requestNumber = 10000;
  requestCurrent = 0;  
 }
 public void doRequest () {
  if (requestCurrent <= requestNumber) {
   Http http = new Http();
   for (Integer startPoint = requestCurrent; (requestCurrent <= requestNumber) && ((requestCurrent - startPoint) < 10); requestCurrent++) {
    HttpRequest req = new HttpRequest();
    req.setEndpoint('http://www.google.com');
        req.setMethod('GET');
    HTTPResponse res = http.send(req);
   }
   requestStatus = requestCurrent + ' out of ' + requestNumber + ' processed';
  }
  if (requestCurrent >= requestNumber)
   requestMore = 'false';
  else requestMore = 'true';
 }
}

The page:
<apex:page controller="testJavascript">
<apex:form>
 <apex:outputpanel id="status">
  Status:

  {!requestStatus}
  <script>requestContinue = {!requestMore};</script>
 </apex:outputpanel>
 <script>
  function requestMore() {
   if (requestContinue)
    doRequest();
  } 
 </script>
 <button onclick="if (doRequest()) return false; else return false;">Start</button>
 <apex:actionfunction action="{!doRequest}" name="doRequest" oncomplete="requestMore()" rerender="status">
</apex:actionfunction></apex:form>

Some explication:

  1. In the controller I have a request counter (requestCurrent, set to 0 at beginning) and a request amount (requestNumber, set to 10000 at beginning) and a method, doRequest(), that, given those two variables, executes the next 10 HTTP requests (increasing the counter) and updates the status String (requestStatus) and the requestMore String/Boolean, setting it to true if other requests are needed (if the counter is lower than the request amount we need) or false if not.
  2. In the page I have an <apex:actionFunction> pointing to this method, that rerenders the status panel. In the panel I show the status string and I update a Javascript global variable (requestContinue) with the String/Boolean given in requestMore by the doRequest() APEX method.
  3. The actionFunction has an oncomplete attribute that calls another Javascript function, requestMore(), that is in the page code. This function checks for requestContinue value (updated after each rerender): if true calls again the doRequest() actionFunction and 10 more requests are executed, if false it does nothing.
The user has just to push the <button> (that does the first actionFunction call) to start the loop.

Nice, isn't it? :-)

Thursday, May 16, 2013

APEX Map sorting

I am programming in APEX from less than a month and I've already written those lines several times... so I think this may be useful for someone else coming to this point for the first time.

We have a map, whose key may be Integer, String or whatever else is a Primitive type. We want to sort it, in ascending or descending order.

Here's a quick method:

public Map<Key_object, Value_object> sortMap (Map<Key_object, Value_object> theMap, String theOrder) {
    //create the return map
    Map<Key_object, Value_object> returnMap = new Map<Key_object, Value_object>();
    //get the set of the keys of the map we want to sort
    Set<Key_object> keySet = theMap.keySet();
    //create a list and add all the keys from the set
    //a small workaround needed because we can't sort a set
    List<Key_object> keyList = new List<Key_object>();
    keyList.addAll(keySet);
    //sort the list ascending (predefined behaviour)
    keyList.sort();
    if (theOrder == 'DESC')
        //iterate from the last to the first key over the ascending ordered key list
        for (Integer i = (keyList.size() - 1); i >= 0; i--)
            returnMap.put(keyList[i], theMap.get(keyList[i]));
    else
        //iterate from the first to the last key over the ascending ordered key list
        for (Integer i = 0; i < keyList.size(); i++)
            returnMap.put(keyList[i], theMap.get(keyList[i]));
    //return the sorted map
    return returnMap;
}

Of course we can omit the part regarding the order (if we want only ascending or descending order) or create two different methods for this.

APEX class getter for attributes by attribute name

A colleague came up the other day with this question:
Usually when you create an Apex class you access data using getters and setters with this direct attribute access syntax (dot-notation):
class MyClass {
    String name { get; set }
}
myC = new MyClass();
String theName = myC.name;  // <== dot-notation
I would now like to use this syntax for my class:
myC = new MyClass();
String theName = myC.get('name'); // <== generic attribute getter syntax
How do I achieve that for my Apex class? Observe that get(String attributeName) must be able to return different types since the attributes may be strings, integers, boolean etc.
Any ideas?

One solution is to use a Map for attributes. It's an easy solution (you don't need to write that much code) that requires small modification on setters of the attributes we want to "track", so that the map is populated with the current value at any time.
class MyClass {
    String name { get; set {
                             this.attributesMap.put('name', value);
                             name = value;
                       } }
    Map<String,Object> attributesMap { get; set; }
    public MyClass () {
        this.attributesMap = new Map<String,Object>();
    }
    public Object getter(String attrName) {
        return this.attributesMap.get(attrName);
    }
}

Object type must be used as the getter return type, since we can't overload methods on return type. Then, a forced casting is required for getting things working:

MyClass c = new MyClass();
c.name = 'Matt';
String a = (String) c.getter('name');

We can also create different getter methods for each type (getInt, getString, getDouble, etc.) to avoid writing casting on any assignment, but I think this is faster.

But, what if we don't want to modify the class at all? Here comes the dirty solution: we can use JSON functions to build an on-the-run getter on any instance attribute:

public class MyClass {
//(...)
    public Object getter(String attrName) {
        Map<String, Object> m = (Map<String, Object>) JSON.deserializeUntyped(JSON.serialize(this));
        return (Object) m.get(attrName);
    }
}

This will instantly create a Map of class instance attributes, returned as Object type, so that casting is still needed on assignment.
The JSON serialize-deserialize may cause some data type losing, for example Date and Datetime types will be translated as String, so that a little workaround is needed to get original data back
Date myDate = Date.valueOf((String) c.get('myDateAttribute');


Hello World

...how can a programming-related blog first post be different?

I'm a Salesforce Developer - still not certified. I'd like to share here whatever I think that could be useful for other people out there. So, let's get it started and... happy coding! :-)