Using SalesForce.com REST API

I was trying to use salesforce.com REST API for getting data. So i started following the http://wiki.developerforce.com/page/Integrating_Java_Spring_Apps_on_Heroku_with_Force.com_REST_APIs document. But after i followed it i kept getting Unable to get access token exception, more details here

 at com.force.sdk.oauth.connector.ForceOAuthConnector.createTokenInternal(ForceOAuthConnector.java:196)
2013-11-28T05:58:29.294965+00:00 app[web.1]:  at org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:48)
2013-11-28T05:58:29.294965+00:00 app[web.1]: 05:58:29,267 ERROR OAuthAuthenticationProvider:82 - Unable to get access token
2013-11-28T05:58:29.294965+00:00 app[web.1]: java.io.IOException: Missing refresh token on response
2013-11-28T05:58:29.294965+00:00 app[web.1]:  at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:130)
2013-11-28T05:58:29.294965+00:00 app[web.1]:  at com.force.sdk.springsecurity.OAuthAuthenticationProvider.authenticate(OAuthAuthenticationProvider.java:78)
2013-11-28T05:58:29.300136+00:00 heroku[router]: at=info method=GET path=/_auth?code=aPrxkpHJh6tvoT6FsBbmu3.hEs0MRNTo0tj3P9AWu2oQ3aJeF7rXY._JA1wepFrePIgKkBuF4w%3D%3D&state=https%3A%2F%2Fdry-refuge-2742.herokuapp.com%2Fpeople%2F host=dry-refuge-2742.herokuapp.com fwd="206.218.52.33" dyno=web.1 connect=1ms service=446ms status=401 bytes=1083
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
2013-11-28T05:58:29.294965+00:00 app[web.1]:  at com.force.sdk.oauth.connector.ForceOAuthConnector.getAccessToken(ForceOAuthConnector.java:145)
2013-11-28T05:58:29.294965+00:00 app[web.1]:  at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java:199)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
2013-11-28T05:58:29.294965+00:00 app[web.1]:  at com.force.sdk.springsecurity.AuthenticationProcessingFilter.doFilter(AuthenticationProcessingFilter.java:109)
2013-11-28T05:58:29.294965+00:00 app[web.1]:  at com.force.sdk.springsecurity.AuthenticationProcessingFilter.attemptAuthentication(AuthenticationProcessingFilter.java:138)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilt
er(SecurityContextPersistenceFilter.java:79)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:259)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:105)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:355)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:149)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
2013-11-28T05:58:29.295172+00:00 app[web.1]:  at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
2013-11-28T05:58:29.295946+00:00 app[web.1]:  at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1146)
2013-11-28T05:58:29.295946+00:00 app[web.1]:  at java.lang.Thread.run(Thread.java:679)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1653)
2013-11-28T05:58:29.295946+00:00 app[web.1]:  at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
2013-11-28T05:58:29.295416+00:00 app[web.1]:  at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
2013-11-28T05:58:24.518283+00:00 heroku[router]: at=info method=GET path=/people/ host=dry-refuge-2742.herokuapp.com fwd="206.218.52.33" dyno=web.1 connect=1ms service=5ms status=302 bytes=0
After some googling i found the problem was that in oAuth setting i had to add 2 scopes to Selected oAuth scopes
  1. Full Access(full)
  2. Perform request on your behalf at any time (refresh_token)
Once i set up the oAUth settings properly the sample started working

Using Salesforce SOAP API from Java Code

Recently i had to develop a portlet that talks to SalesForce.com and retrieves some data. I decided to use the SalesForce SOAP API for that, i followed these steps
  1. First step is to get your salesforce.com security token, follow steps as described in Generating Security Token for SalesForce.com post for that
  2. Second step is to login into your salesforce.com account and download the Enterprise .wsdl, Follow steps 1-3 from Accessing SalesForce data using SOAP Service - SoapUi post for that
  3. You should use the Force.com web services connector (WSC) which has helper code that simplify working with Force.com SOAP service.
  4. Once you have WSC project downloaded on your machine and complied into jar copy it in a directory and then also copy your enterprise.wsdl in the same directory, then execute
    
    java -classpath target/force-wsc-29.0.0-jar-with-dependencies.jar com.sforce.ws.tools.wsdlc enterprise.wsdl enterprise.jar
    
    It will generate enterprise.jar file for you
  5. Now create a Java Project and add both enterprise.jar and force-wsc-29.0.0-jar-with-dependencies.jar in your classpath
  6. Last step is to create SFDClient.java class like this Replace userId, password and securitytoken in this file with the values you have
  7. When you run the SFDClient.java class it will display list of contacts in your salesforce.com account

Accessing SalesForce data using SOAP Service - SoapUi

Recently i was trying to figure out how to access SalesForce data from outside. I had two options either to use REST or use SOAP API for accessing the data. I tried both and these are my notes for accessing SalesForce Soap API using Soap client such as SoapUi.
  1. First thing that you would want to do is generate security token for salesforce. Follow these steps for generating security token
  2. Once you have security token, login into the SalesForce console to download the WSDL, Click on Develop -< API and you will see page where you can download all the WSDL's, Download the Enterprise WSDL
  3. Now create new SOAP Ui project using the Enterprise WSDL you just downloaded
    You will notice that it generates bunch of SOAP operations
  4. In order to use the SOAP API you will have to first send a login request to SalesForce and get sessionid once you have it you can use that for making subsequent calls. First call the Login service like this
    
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:enterprise.soap.sforce.com">
       <soapenv:Header>
       </soapenv:Header>
       <soapenv:Body>
          <urn:login>
             <urn:username>replacerwitheuserid</urn:username>
             <urn:password>replacewithpasswordreplacewithsecuritytoken</urn:password>
          </urn:login>
       </soapenv:Body>
    </soapenv:Envelope>
    
    You should replace replacerwitheuserid with your userId (email id that you use for login) and also replace replacewithpassword with your password and use the security token that you got in email to replace replacewithsecuritytoken. Make a request and you will get a response which looks like this
    
    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns="urn:enterprise.soap.sforce.com" 
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
       <soapenv:Body>
          <loginResponse>
             <result>
                <metadataServerUrl>https://na15.salesforce.com/services/Soap/m/29.0/00Di0000000iKns</metadataServerUrl>
                <passwordExpired>false</passwordExpired>
                <sandbox>false</sandbox>
                <serverUrl>https://na15.salesforce.com/services/Soap/c/29.0/00Di0000000iKns</serverUrl>
                <sessionId>sessionId</sessionId> 
                <userId>userId</userId>
                <userInfo>
                   <accessibilityMode>false</accessibilityMode>
                   <currencySymbol>$</currencySymbol>
                   <orgAttachmentFileSizeLimit>5242880</orgAttachmentFileSizeLimit>
                   <orgDefaultCurrencyIsoCode>USD</orgDefaultCurrencyIsoCode>
                   <orgDisallowHtmlAttachments>false</orgDisallowHtmlAttachments>
                   <orgHasPersonAccounts>false</orgHasPersonAccounts>
                   <organizationId>xxxx</organizationId>
                   <organizationMultiCurrency>false</organizationMultiCurrency>
                   <organizationName>Self</organizationName>
                   <profileId>xxxx</profileId>
                   <roleId xsi:nil="true"/>
                   <sessionSecondsValid>7200</sessionSecondsValid>
                   <userDefaultCurrencyIsoCode xsi:nil="true"/>
                   <userEmail>xxxxx</userEmail>
                   <userFullName>Sunil Patil</userFullName>
                   <userId>xxxxx</userId>
                   <userLanguage>en_US</userLanguage>
                   <userLocale>en_US</userLocale>
                   <userName>sxxxxxx</userName>
                   <userTimeZone>America/Los_Angeles</userTimeZone>
                   <userType>Standard</userType>
                   <userUiSkin>Theme3</userUiSkin>
                </userInfo>
             </result>
          </loginResponse>
       </soapenv:Body>
    </soapenv:Envelope>
    
    You will need the value of sessionId element and value of serverUrl in subsequent requests. so note it down
  5. Next assume that you want to execute query request that will give you list of all the contacts using SELECT Id, FirstName, LastName From Contact query, so use XML that looks like this for the soap request. Replace the replacewithyoursessionid with the sessionId that you got from the login request and also change the URL where SOAP request is made to value of serverUrl
    
    <soapenv:Envelope 
    xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
    xmlns:urn="urn:enterprise.soap.sforce.com">
    
       <soapenv:Header>
          <urn:SessionHeader>
    <urn:sessionId>replacewithyoursessionid</urn:sessionId>
          </urn:SessionHeader>
       </soapenv:Header>
       <soapenv:Body>
          <urn:query>
             <urn:queryString>
    SELECT Id, FirstName, LastName  From Contact<
    /urn:queryString>
          </urn:query>
       </soapenv:Body>
    </soapenv:Envelo
    
    You will get response with list of contacts

Generating Security Token for SalesForce.com

If you want to use SalesForce SOAP API then you will need security token. If you dont have the security token SalesForce will generate Soap fault like this

<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" 
xmlns:sf="urn:fault.enterprise.soap.sforce.com" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
   <soapenv:Body>
      <soapenv:Fault>
         <faultcode>sf:LOGIN_MUST_USE_SECURITY_TOKEN</faultcode>
         <faultstring>LOGIN_MUST_USE_SECURITY_TOKEN: Invalid username, password, security token; or user locked out. Are you at a new location? When accessing Salesforce--either via a desktop client or the API--from outside of your company’s trusted networks, you must add a security token to your password to log in. To receive a new security token, log in to salesforce.com at http://login.salesforce.com and click Setup | My Personal Information | Reset Security Token.</faultstring>
         <detail>
            <sf:LoginFault xsi:type="sf:LoginFault">
               <sf:exceptionCode>LOGIN_MUST_USE_SECURITY_TOKEN</sf:exceptionCode>
               <sf:exceptionMessage>Invalid username, password, security token; or user locked out. Are you at a new location? When accessing Salesforce--either via a desktop client or the API--from outside of your company’s trusted networks, you must add a security token to your password to log in. To receive a new security token, log in to salesforce.com at http://login.salesforce.com and click Setup | My Personal Information | Reset Security Token.</sf:exceptionMessage>
            </sf:LoginFault>
         </detail>
      </soapenv:Fault>
   </soapenv:Body>
</soapenv:Envelope>
Follow these steps to generate a security token
  1. Login into your Salesforce account
  2. Click on your use name and you will get drop down like this, click on My Settings sub menu
  3. On the next page you will get submenu on the side click on Personal side menu, once its expanded click on Reset my security token link
  4. Once your on the Reset My Security Token button and it will trigger security token generation process
  5. In few minutes it will send email to your address with security token, use that for the subsequent SOAP calls

Customizing the JSON output generated by Jackson

Recently i was using Jackson JSON Processor for converting java object into JSON. When i did that i noticed JackSon was storing date in the long format i.e. it was converting date.getTime() and using that long value in JSON instead of formatted date. This is how my Contact object looks like Note: please ignore line 32 @JsonSerialize(using = CustomDateSerializer.class) for now. I had following code to create object of Contact and converting and then using Jackson to convert it to String and write it on console This was the output that got generated

{"firstName":"Sachin","lastName":"Tendulkar","dateOfBirth":60065349443063}
Now i wanted to customize how the date so that it got generated in dd-MMM-yyyy format. In order to do that i started by creating CustomDateSerializer class like this Then i had to change the Contact.java class to add @JsonSerialize(using = CustomDateSerializer.class) annotation to getDateOfBirth() field, i could attach it to any other date field that i want. Now when i run JSONTester this the output that it generates

{"firstName":"Sachin","lastName":"Tendulkar","dateOfBirth":"24-Apr-1973"}
You can download the source code for this program from here

Using Mule to get Geo Code for address

For last few days i am playing around with Mule, its really cool integration framework. You can use it to build integration applications by using small amount of code. I had this requirement where given address i wanted to get the Geo Coding information for that address, I wanted to use Google Maps API for getting GeoCode information for the address. The way Google Maps API works is it has a REST API, it takes address as query string and it returns JSON structure. Ex. If you copy paste this URL in the browser http://maps.googleapis.com/maps/api/geocode/json?address=3055 Oak Road,Walnut Creek,CA,94597&sensor=false You will get a JSON structure with longitude and latitude embedded in lot of other information

{
   "results" : [
      {
         "address_components" : [
            {
               "long_name" : "3055",
               "short_name" : "3055",
               "types" : [ "street_number" ]
            },
            {
               "long_name" : "Oak Road",
               "short_name" : "Oak Rd",
               "types" : [ "route" ]
            },
            {
               "long_name" : "Walnut Creek",
               "short_name" : "Walnut Creek",
               "types" : [ "locality", "political" ]
            },
            {
               "long_name" : "Contra Costa County",
               "short_name" : "Contra Costa County",
               "types" : [ "administrative_area_level_2", "political" ]
            },
            {
               "long_name" : "California",
               "short_name" : "CA",
               "types" : [ "administrative_area_level_1", "political" ]
            },
            {
               "long_name" : "United States",
               "short_name" : "US",
               "types" : [ "country", "political" ]
            },
            {
               "long_name" : "94597",
               "short_name" : "94597",
               "types" : [ "postal_code" ]
            }
         ],
         "formatted_address" : "3055 Oak Road, Walnut Creek, CA 94597, USA",
         "geometry" : {
            "bounds" : {
               "northeast" : {
                  "lat" : 37.9302338,
                  "lng" : -122.0582288
               },
               "southwest" : {
                  "lat" : 37.9302299,
                  "lng" : -122.0582466
               }
            },
            "location" : {
               "lat" : 37.9302299,
               "lng" : -122.0582466
            },
            "location_type" : "RANGE_INTERPOLATED",
            "viewport" : {
               "northeast" : {
                  "lat" : 37.93158083029149,
                  "lng" : -122.0568887197085
               },
               "southwest" : {
                  "lat" : 37.9288828697085,
                  "lng" : -122.0595866802915
               }
            }
         },
         "types" : [ "street_address" ]
      }
   ],
   "status" : "OK"
}
Out of all the data returned by Google MAPS api i am only interested in the Lat and Long and i want to return it in GeoJSON format like this

 [
 -122.0582466,
 37.9302299
 ]
Which is [lng,lat] format, some open source JavaScript Mapping frameworks understand the GeoJSON format. I built a simple Mule integration application which takes STREETLINE1, CITY, STATE, ZIPCODE as argument and returns geo location in GeoJSON format like this [lng,lat]. I followed these steps to build the application
  1. First i built a Mule Flow which looks like this
    In this flow i have a composite input source that could take input on either VM transport or HTTP transport and then uses the values submitted by user to make a request to Google Maps API. Once the response is returned it uses DataMapper to convert the big response that Google Maps API returns into simple GeoJSON response.
  2. This is how the Data Mapping file looks like
    If you look at the script of this file it looks like this
After deploying this application i can make the POST call to http://localhost:9081/geocode URL and see the location in geojson format like this