Tuesday, September 7, 2010

Generating Salesforce Enterprise WS client stubs using JAX-WS

I've seen a lot of posts online but found few direct hits that address our technical need to consume Salesforce Enterprise wsdl into our JBoss 5 server. And since JBoss 4.2 (and above) runs JBossWS under the hood, which natively supports JAX-RPC and JAX-WS web service stack, I think it is such a good idea to post the steps I've done to accomplish this as reference for others (and myself the next time I have the need to refresh my application with the updated Salesforce Enterprise wsdl from our org).

I'll be generating the client stubs using the command line approach but on my next blog I'll show how using SoapUI. BTW, I'm using Linux Fedora 12 but you can easily follow and execute these steps on Windows DOS command line.

1) Download JAX-WS from here, if you don't have it yet. I extracted the zip file in /home/gio/Downloads/JAXWS2.2.1-20100617/jaxws-ri

2) Login to Salesforce with your credentials. Go to Setup, App Setup, Develop, API then click Generate Enterprise WSDL. Save your "Salesforce Enterprise wsdl" on the same jaxws-ri directory extracted from above. I named the wsdl file SF_Enterprise.wsdl.

3) Create the JAXWS-JAXB binding xml file in same jaxws-ri directory cotaining the code below (this is to bind XMLSchema to Java). I saved this JAXB binding file sf-jaxws-bindings-enterprise.xml. Change the targetNamespace accordingly based on the version you're using (look at the Salesforce wsdl).

<bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns="http://java.sun.com/xml/ns/jaxws">
<bindings node="//xsd:schema[@targetNamespace='urn:enterprise.soap.sforce.com']">
<jaxb:globalBindings underscoreBinding="asCharInWord" />
<jaxb:schemaBindings>
<jaxb:nameXmlTransform>
<jaxb:typeName suffix="Type" />
</jaxb:nameXmlTransform>
</jaxb:schemaBindings>
</bindings>
<enableWrapperStyle>false</enableWrapperStyle>
<enableAsyncMapping>false</enableAsyncMapping>
</bindings>

4) Create "gen-src" target directory for your generated client stubs in same jaxws-ri directory.

5) You should endup with the file structure similar to this image.

6) Optionally, change the java heap size to at least 512m so you have a buffer and hopefully never run into heap size error (just in case you have lots of custom objects in Salesforce, which we do in our org). Find the wsimport.sh/wsimport.bat and add -Xmx512m accordingly.
a) On Linux, ../bin/wsimport.sh --> exec "$JAVA" -Xmx512m $WSIMPORT_OPTS -jar "$JAXWS_HOME/lib/jaxws-tools.jar" "$@"

b) On Windows, ../bin/wsimport.bat --> %JAVA% -Xmx512m %WSIMPORT_OPTS% -jar "%JAXWS_HOME%\lib\jaxws-tools.jar" %*

7) Open up command line and type-in the following
bin/wsimport.sh -verbose -keep -p com.company.myapp.ws.sf.client -b sf-jaxws-bindings-enterprise.xml -s gen-src SF_Enterprise.wsdl -XadditionalHeaders -Xnocompile -Xendorsed

You might asked, what? Ok, here's what these parameters are for
-verbose - so that I see the output from the compiler as it runs
-keep - to keep the generated files
-p - the target package of generated java source codes (will be under package com.company.myapp.ws.sf.client)
-b - jaxws/jaxb binding files for binding XML schema to java representation (step #3)
-s - target directory where the compiler will dump all generated java source codes (step #4)
-XadditionalHeaders - map headers not bound to request/response message to java method parameters
-Xnocompile - don't compile the generated java codes into classes.
-Xendorsed - I'm running JDK6 on my Fedora 12 and the JAXWS 2.2.1 I downloaded requires the latest version JAXWS 2.2 API therefore I have to use the "endorsed" API from JAXWS 2.2 rather than from my own JDK6. See this site for more details.

8) Voila, you now have java client stubs you can inject into your JBoss application project.