Creating Portlets for Integration With Salesforce.com

Part 1: Consuming the Force.com Enterprise WSDL

Integration with the Salesforce.com API is a feature that is highly desirable for any organization which uses that platform to track opportunities in the sales pipeline; as a proof of concept, we recently went through the process of developing several portlets for deployment on Liferay which integrate with the Salesforce.com Web Services. This is a multi-part blog post detailing the challenges that we faced in completing this task; the first entry will deal solely with the task of integration with the Salesforce.com enterprise WSDL. Note that for the purposes of this example, Maven was used to handle code generation, dependency management, and compilation. It should be simple enough to perform the following using Ant or another build tool, but this example will only cover Maven.

Retrieve the enterprise.wsdl for your organization

The enterprise.wsdl file describes the contracts provided by the Salesforce.com enterprise web services API. To retrieve this API for your organization, navigate to the organization’s salesforce.com site and log in. Once authenticated, navigate to the “App Setup” -> “Develop” -> “API” section of the Setup area. Click on the “Generate Enterprise WSDL” link to retrieve the enterprise WSDL for your organization. Save this file locally; there is no way to remotely reference the WSDL, so you will need to include it in your project, and in all resulting JAR or WAR files.

Integrate CXF into Maven

Create the following directory structure for Maven:

${PROJECT_ROOT}/src
${PROJECT_ROOT}/src/main
${PROJECT_ROOT}/src/main/java
${PROJECT_ROOT}/src/main/resources
${PROJECT_ROOT}/src/main/resources/wsdl

Place the enterprise.wsdl file that was saved earlier in the ${PROJECT_ROOT}/src/main/resources/wsdl directory.

Create a JAXB bindings file named enterprise.wsdl.bindings.xml in ${PROJECT_ROOT}/src/main/resources/wsdl. The contents of the file should be as follows:

<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
  xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc" xmlns:xs="http://www.w3.org/2001/XMLSchema">
  <jaxb:globalBindings mapSimpleTypeDef="true">
    <xjc:generateElementProperty>false</xjc:generateElementProperty>
  </jaxb:globalBindings>
</jaxb:bindings>

The mapSimpleTypeDef attribute of the jaxb:globalBindings element instructs the code generator to generate classes for globally defined simple types; for the Force.com enterprise API, this includes all ID instances. This attribute can safely be omitted if you wish to use simple String representations of ID attributes; for our purposes, a distinct ID class was required.

The xjc:generateElementProperty element instructs the code generator to account for aspects of the enterprise.wsdl which would normally generate JAXBElement<T> typed methods in the resulting Java code; instead, the generator will correctly generate Java-typed methods in the code.

Add the following snippet to the section of your POM in order to enable the cxf code generation plugin:

<plugin>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-codegen-plugin</artifactId>
  <version>2.4.0</version>
  <executions>
    <execution>
      <id>generate-sources</id>
      <configuration>
        <wsdlOptions>
          <wsdlOption>
            <wsdl>${basedir}/src/main/resources/wsdl/enterprise.wsdl</wsdl>
            <bindingFiles>
              <bindingFile>${basedir}/src/main/resources/wsdl/enterprise.wsdl.bindings.xml</bindingFile>
            </bindingFiles>
            <extraargs>
              <extraarg>-autoNameResolution</extraarg>
              <extraarg>-exsh</extraarg>
              <extraarg>true</extraarg>
              <extraarg>-wsdlLocation</extraarg>
              <extraarg>wsdl/enterprise.wsdl</extraarg>
            </extraargs>
          </wsdlOption>
        </wsdlOptions>
      </configuration>
      <goals>
        <goal>wsdl2java</goal>
      </goals>
    </execution>
  </executions>
</plugin>

The -autoNameResolution argument instructs the code generator to automatically resolve naming conflicts in the generated source without requiring the use of complex bindings; this is absolutely necessary for the Salesforce.com API.

The -exsh true arguments instruct the generator to enable the processing of implicit SOAP headers in the WSDL; this is also necessary for the Salesforce.com API in order to correctly handle the login process for web services endpoint.

The -wsdlLocation wsdl/enterprise.wsdl arguments tell the generator how to reference the WSDL in generated code. We place the WSDL in this location in order to correctly bundle it with the generated JAR file for the project; this is necessary in this case in order to avoid having to deploy the enterprise.wsdl file seperately from the jar itself.

Add the following Maven dependencies for CXF:

<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-frontend-jaxws</artifactId>
  <version>2.4.0</version>
</dependency>
<dependency>
  <groupId>org.apache.cxf</groupId>
  <artifactId>cxf-rt-transports-http</artifactId>
  <version>2.4.0</version>
</dependency>

At this point, you should be able to run mvn compile in ${PROJECT_ROOT} and see the resulting generated source in ${PROJECT_ROOT}targetgenerated-sourcescxf.

That’s it for the first entry in this series; in the next entry, I’ll address the process of logging in to the web services and running a basic query.

Share This