August 5, 2010

Salesforce WSC ApacheAxis Session Sharing

Yesterday’s blog post explained how to best use Apache Axis and WSC stubs in parallel on same JVM or Project. This post reveals another small trick for developers using both WSC and Apache Axis WSDL2Java stubs together in a project/jvm. The trick focuses on reducing the number of login() call via Partner or Enterprise Stubs. This post might be of interest for those developers also, who have generated WSDL2Java stubs using other options like Apache CXF etc.

Secret sauce behind SFDC Session sharing

In general, the basic trick to reduce login calls, share sfdc session and use that session in prolonged way is to keep hold of two key SFDC artifacts i.e.

  • SESSION ID
  • SERVER URL

Both these are returned in “LoginResult” when you successfully complete a login() call via Partner or Enterprise stubs. It doesn’t matters using which tool you have compiled the salesforce wsdls, the key is to keep reusing these two artifacts.

These two artifacts are real beauty of salesforce web services too, I love the way you can share these artifacts across stubs, platforms and languages. For ex.

  • You have a PHP page that creates a SFDC session via login() call.
  • This PHP page delegates the complex processing stuff to some Java process.
  • Now, the PHP guy can safely share the same sessionid/server-url with Java process for re-use. Java process can start making web service calls without requiring a new login.

So, this is beauty because PHP guy, didn’t passed username/password to Java process.

OK, enough talking on basics. Now time for action and some code

Code Snippet - Reusing Apache Axis Session in WSC

NOTE: If you haven’t changed the java packaging during WSC WSDL compilation as suggested in this blog post, the sample below will not work because of package conflicts/ClassCast. I am also assuming you have included the WSDL2Java classes and required other jar’s in classpath. Didn’t included this intentionally to keep this post focused on the core topic.

First, the usual Apace Axis login() call using Partner.

// LoginResult from Apache Axis WSDL 2 JAVA stubs
SforceServiceLocator servLocator = new SforceServiceLocator();
SoapBindingStub axisStub = (SoapBindingStub) servLocator.getSoap();
// LoginResult is WSDL2Java class from Apache Axis.
LoginResult loginResult = axisStub.login(userName, password);

Now how to re-use the Apache Axis LoginResult created above in WSC

// Fetch the Server URL and Session from the Apache Axis login results
// Create new WSC Partner Connection
ConnectorConfig config = new ConnectorConfig();
config.setManualLogin(true);
// NOTE: We got server url from Apache Axis LoginResult
config.setServiceEndpoint(loginResult.getServerUrl());
// NOTE: We got sessionId from Apache Axis LoginResult
config.setSessionId(loginResult.getSessionId());
PartnerConnection partnerConn = Connector.newConnection(config);

Now putting all code snippets together, a complete fully functional sample code, that creates a Contact using WSC based on SFDC session created by Apache Axis. Please notice the import statements.

import com.sforce.soap.partner.LoginResult;
import com.sforce.soap.partner.SforceServiceLocator;
import com.sforce.soap.partner.SoapBindingStub;
import com.sforce.soap.partner.sobject.wsc.SObject;
import com.sforce.soap.partner.wsc.Connector;
import com.sforce.soap.partner.wsc.PartnerConnection;
import com.sforce.soap.partner.wsc.SaveResult;
import com.sforce.ws.ConnectorConfig;

public class AxisWSCTest {

public static void main(String[] args) throws Exception {
	// Set your user/pass here
	String userName = "";
	String password = "";

	// LoginResult from Apache Axis WSDL 2 JAVA stubs
	SforceServiceLocator servLocator = new SforceServiceLocator();
	SoapBindingStub axisStub = (SoapBindingStub) servLocator.getSoap();
	// LoginResult is WSDL2Java class from Apache Axis.
	LoginResult loginResult = axisStub.login(userName, password);

	// Fetch the Server URL and Session from the Apache Axis login results
	// Create new WSC Partner Connection
	ConnectorConfig config = new ConnectorConfig();
	config.setManualLogin(true);
	// NOTE: We got server url from Apache Axis LoginResult
	config.setServiceEndpoint(loginResult.getServerUrl());
	// NOTE: We got sessionId from Apache Axis LoginResult
	config.setSessionId(loginResult.getSessionId());
	PartnerConnection partnerConn = Connector.newConnection(config);

	// Create a new Contact
	SObject contact = new SObject();
	contact.setType("Contact");
	contact.setField("FirstName", "Abhinav");
	contact.setField("LastName", "Gupta");
	SaveResult[] create = partnerConn.create(new SObject[] { contact });
	for (SaveResult saveResult : create) {
		if (!saveResult.isSuccess()) {
			throw new RuntimeException(
					"Failed to save contact via Partner WSDL");
		}
	}
	System.out.println("Partner-WSDL : Save successfully done using WSC");

}

}

Thats it guys, any ideas/issues on using this. Please share !