July 14, 2010

How Tolerado improves the Salesforce Web Service Client code !

This post explains how Tolerado improves the Java client code for using Salesforce web services.

Why Client Code improvement is required ?

Developers are always too concerned about many things, like making the Web Service call work right for them and implementing the biz requirements. So handling exceptions and giving them proper treatment is mostly not a priority. Developers usually check the API docs/samples and production ready product usually evolves from the foundation laid by those sample codes.

So, Tolerado jumps in here to touch the areas often ignored in web service programming.

Code Samples

Here we will try touching areas of common programming issues and how Tolerado would fix them.

Sample 1 : Making Partner/Metadata/Apex Calls

When working Salesforce Axis client stubs, following are 2 very common scenarios/exceptions, where its possible to recover from errors but the code crashed :

  • Exception 1: Connection timeout or Unknownhost Error: This error might temporarily come in your internet connection because of some DNS/internet issues.
  • Exception 2: Service temporarily down: Again on getting this error, we are failing fast in above code samples.
  // Code sample that shows, the web service exception 
  // being caught and eaten
  
  QueryResult qr = null;
  try {
    // All your code to create the binding and set the correct headers 
    // .... 
    // ...
    binding = (SoapBindingStub) new SforceServiceLocator().getSoap();  
    // ...
    LoginResult loginResult = binding.login(userName, password);
    binding._setProperty(SoapBindingStub.ENDPOINT_ADDRESS_PROPERTY,
                                loginResult.getServerUrl());
    SessionHeader sh = new SessionHeader();
    sh.setSessionId(loginResult.getSessionId());
    binding.setHeader(new SforceServiceLocator().getServiceName()
                                .getNamespaceURI(), "SessionHeader", sh);
    qr = binding.query("select FirstName, LastName from Contact");
    // ... 
    // process the results within QueryResult 
    // ...
  }catch (Exception ex) {
    // No recovery, just log the message.
    System.out.println(
           "\nFailed to execute query successfully, error message was: \n" 
           + ex.getMessage());
  }

After using Tolerado stub, you will get something very similar. But many other stuff transparently. Check the code sample below.

    // NOTE: No try catch block, a RunTimeException ToleradoException is thrown if the failure // is not recoverable

    // All the hassle of doing login and setting headers encapsulated in this single call
    // ToleradoStub is a ready to use stub, with no changes required
    ToleradoPartnerStub pStub = new ToleradoPartnerStub(new Credential("userName@user.com", "password"));
    //Binding created transparently from the given salesforce user name
    //password.
    //You transparently got the
    //1. Fault recovery mechanism
    //2. Cached stub (if its second call via the same login)
    //3. QueryResult is same class as before, so no change on your rest of the
    // logic.
    QueryResult qr = pStub.query("select FirstName, LastName from Contact");
    // ... 
    // process the results within QueryResult 
    // ...
Sample 2 : Making Partner queryMore Calls

Using queryMore requires some setting of headers to stubs for batch size and using a string query locator handle correctly.

First we will show the normal code without Tolerado framework

  QueryResult qr = null;
  _QueryOptions qo = new _QueryOptions();
  qo.setBatchSize(250);
  binding.setHeader(new SforceServiceLocator().getServiceName().getNamespaceURI(), 
                     "QueryOptions", qo);
  try {
    qr = binding.query("Select name From lead");
    boolean done = false;
    if (qr.getSize() > 0){      
      while (!done) {
        for(sObject lead : qr.getRecords()) {
            System.out.println(lead.get_any()[0].getValue());
        }
        if (qr.isDone()) {
          done = true;
        } else {
          qr = binding.queryMore(qr.getQueryLocator());
        }
      }
    }
    else {
      System.out.println("No records found.");
    }
    System.out.println("\nQuery succesfully executed.");
  }
  catch (RemoteException ex) {
    // No recovery from remote errors
    System.out.println("\nFailed to execute query successfully, error message was: \n" + 
                       ex.getMessage());
  }

Now we will show the Tolerado simplified code sample

  
    // Cached, Recoverable Stub
    ToleradoPartnerStub pStub = new ToleradoPartnerStub(new Credential("username", "password"));
    // Wrapper class for making queryMore calls super easy
    // Just pass the SOQL and batch size here, it will take care of the rest
    ToleradoQuery q = new ToleradoQuery(pStub, "Select name From lead",
                                250);    
    // Do Java style iteration over the ToleradoQuery
    while (q.hasMoreRecords()) {
        // Correct query locator used internally 
        SObject[] records = q.getRecords();
        if (records == null || records.length == 0)  break;
        for(sObject lead : records) {
            System.out.println(lead.get_any()[0].getValue());
        }            
                log.debug("Fetched next " + records.length + " records !");
        }
    // No try catch block as run time exception is thrown, if the stub can't recover
    // the error. 
Sample 3: Working with SObject – Creating new Contact record

Developers need to deal with MessageElement and Sobjects while creating new Sobjects. As shown below

  SObject[] cons = new SObject[1];
  MessageElement[] contact = new MessageElement[5];
  contact[0] = new MessageElement(new QName("FirstName"),"Joe");
  contact[1] = new MessageElement(new QName("LastName"),"Blow");
  contact[2] = new MessageElement(new QName("Salutation"),"Mr.");
  contact[3] = new MessageElement(new QName("Phone"),"999.999.9999");
  contact[4] = new MessageElement(new QName("Title"),"Purchasing Director");
  cons[0] = new SObject();
  cons[0].setType("Contact");
  cons[0].set_any(contact);
  SaveResult[] sr = null;
  try {
    sr = binding.create(cons);
  } catch (Exception ex) {
    System.out.println("An unexpected error has occurred." + ex.getMessage());
    return;
  }

The Tolerado code, is much simpler and more readable

    ToleradoSobject sobj = new ToleradoSobject("Contact");
    sobj.setAttribute("FirstName", "Joe");
    sobj.setAttribute("LastName", "Blow");
    sobj.setAttribute("Salutation", "Mr.");
    sobj.setAttribute("Phone", "999.999.9999");
    sobj.setAttribute("Title", "Purchasing Director");
    // Get the updated Sobejct
    SObject updatedSObject = sobj.getUpdatedSObject();
    SaveResult[] saveResults = partnerStub.create(new SObject[] { updatedSObject });
What advantage you get is clearly visible

References

For more info on “Tolerado”, please follow these pointers