Groovy as a SalesForce API client

We needed a quick way of performing data cleansing and bulk updates to data within SalesForce. As SalesForce is a hosted Software-as-a-Service offering it’s not as simple as resorting to SQL statements – or is it?
Using the Web Services API from Groovy made it quite easy once the foundations were in place.

API access
To use the SalesForce API you’ll need an account level that includes API access and your user account will require a SalesForce API key. If you meet these criteria, go to the Setup screen and click on ‘Reset My Security Token’ under ‘Personal Setup’ > ‘My Personal Information’ – this will email you your new security token.

Building the Web Services client stubs
Firstly get hold of the Web Services Definition Language (WSDL) file from SalesForce – this is also available via the Setup screen.
Under ‘App Setup’, click on ‘Develop’ and then ‘API’.
For this use case we’ll choose the Enterprise WSDL – so click on ‘Generate Enterprise WSDL’.
This will give you a file called enterprise.wsdl.xml

Grabbing GroovyWS wouldn’t seem to play as it tried to download the entire known universe – so resorted to using Apache Axis as I had an old copy of 1.4 to hand. With Axis it’s just a matter of running WSDL2Java and pointing it at the WSDL file…

Assuming you’ve got the Axis dependencies in lib and the WSDL file in wsdl:

java -cp lib/activation.jar;lib/axis.jar;lib/commons-discovery-0.2.jar;lib/commons-logging-1.0.4.jar;lib/jaxrpc.jar;lib/logj-1.2.8.jar;lib/mail.jar;lib/saaj.jar;lib/wsdl4j-1.5.1.jar org.apache.axis.wsdl.WSDL2Java -a wsdl/enterprise.wsdl.xml

This will generate the Java source for the client stubs. Compile these, jar it up as e.g. sfdc_axis_binding.jar and drop that plus the Axis dependencies into ~/.groovy/lib
(or you can figure out all the Groovy Grape-Grab dependency names – mvnrepository.com now helpfully includes these).

Getting Groovy
It’s time to break out the Groovy Console…

Firstly import the following:

import com.sforce.soap.enterprise.*
import com.sforce.soap.enterprise.fault.*
import com.sforce.soap.enterprise.sobject.*
import com.sforce.soap.enterprise.Soap
import javax.xml.rpc.*;

Then we’ll set up some variables to hold configuration information:

def username = 'someuser@example.com'
def password = 'password_goes_here'
def securityToken = 'security_token_goes_here'

Now we’ll login to the API and bind the session to a header for subsequent API requests:

Soap port = (SoapBindingStub) new SforceServiceLocator().getSoap()

// login
def loginResult = port.login(username, "${password}${securityToken}")

// set-up the session
def session = loginResult.getSessionId()
def url = loginResult.getServerUrl()
port._setProperty(SoapBindingStub.ENDPOINT_ADDRESS_PROPERTY, url)

// create session header
def sessionHeader = new SessionHeader()
sessionHeader.setSessionId(session)

// bind session header
def sforceURI = new SforceServiceLocator().getServiceName().getNamespaceURI()
port.setHeader(sforceURI, "SessionHeader", sessionHeader)

Querying SalesForce Objects
SalesForce provides a sql-like object query language (SOQL) which is intuitive if you’ve used SQL before. It also allows you to query standard and custom fields on an object (you’ll need to use the API names – which can be viewed via the Fields screen under App Setup > Customize > ‘Object’. Standard fields are also well documented e.g. Leads).

In the following example we’re querying for legacy leads (imported from SugarCRM) that have the Disqualified status and then printing these out:

def qo = new QueryOptions()
qo.batchSize = 200

// add query options to the header
port.setHeader(sforceURI, "QueryOptions", qo)

// perform a query
def qr = port.query("select id, Email, FirstName, LastName, LeadSource from Lead where legacy_Id__c null and status = 'Disqualified'")
println qr.getSize() // overall number of records - could be > 200
def recs = qr.getRecords()
if (recs) {
 println recs.length // number of records to process
 recs.each {
  println "${it.id}, ${it.email}, ${it.firstName}, ${it.lastName}, ${it.leadSource}"
 }
}

Working with SalesForce Objects
Once you have a set of records, you can e.g. bulk update their status (and print out any errors):

def list = recs.collect {
 def lead = new Lead()
 lead.id = it.id
 lead.status = 'Dead'
 return lead
}
def saveResults = port.update(list as SObject[])
saveResults.each { saveResult ->
 if (!saveResult.success) {
  saveResult.errors.each { err -> err.properties.each { println it } }
 }
}

Logging out
port.logout()
Naturally this was in a finally block.

Parallelisation
Some of the data migration activities we were performing could benefit from parallel execution.
GPars was chosen for the elegant simplicity of implementing this:

import groovyx.gpars.GParsPool

Once a GParsPool is in place, we can then parallel process a collection using eachParallel:

GParsPool.withPool {
 // query the database
 def rows = sql.rows(query)
 rows.eachParallel { note ->
  ...

Note: Tomas Lin wrote a good introductory post to GPars on his blog.

Summary
In conclusion, querying SalesForce data is almost as simple as using SQL thanks to SOQL. Using the object API from Groovy (thanks to the powerful collection handling and more concise syntax) for data updates is also pretty easy.

About these ads

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s