SalesForce.com JAX-WS & Netbeans
The process for using SalesForce.com (SFDC) webservices in Netbeans isn’t as intuitive as you would think. Most of the SFDC documentation examples are built using Apache Axis vis-a-vis JAX-WS. The good news is that it’s possible to get Netbeans (and therefore JAX-WS) to properly build a WS client for SFDC.
Once you’ve downloaded your organizations enterprise or partner WSDL, in Netbeans, right-click on the project and select New -> Web Service Client (if it’s not there then New -> Other -> Web Services Category, and then Web Service Client). Select Local File and Browse to the location of your downloaded WSDL. Specify your package and leave the Client Style as JAX-WS and “Generate Dispatch Code” unselected.
Netbeans will attempt to do it’s thing and fail with an error – however, it’s not the only thing standing between you and a working web service client in Netbeans. Below is the error that I received.
In this case, it’s complaining about a ComplexType and element that share the same name. There are two different ways to solve the problem and really only one that works with Netbeans. To properly fix the issue (and have Netbeans “see” the fix) you need to create a JAX-WS binding document to prevent the naming collision from occurring. To do this create a new file and cut and paste this into it. You may have to adjust the @targetNamespace='urn:enterprise.soap.sforce.com' to whichever version (enterprise or partner) your using.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <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" wsdlLocation="../wsdl/enterprise.wsdl"> <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> |
But we’re not done quite yet. Even though the first attempt failed, Netbeans created a new “Web Service References” node in the Projects tree. If you expand that node, you’ll see your webservice. Right-click on the service and select “Edit Web Service Attributes”. Select the “WSDL Customization” tab and scroll all the way to the bottom section named “External Binding Files”. Expand it, and click “Add”. Answer “Yes” to the dialog and then find the xml file you created earlier that contained the binding changes.
Once you select “OK”, a dialog will appear indicating that a refresh of the client is underway. At that point, Netbeans will attempt to re-create the client. If all goes well you should have a working SFDC client in Netbeans.
[UPDATE 1]
The security model in the SFDC API is interesting. In order to properly utilize the service, you must do two things after logging in. One, re-point to a URL that actually contains your organization, and two, make all subsequent calls to that new URL with a session ID that is provided as a result of the login process. The good thing is it’s documented. The bad thing is it’s not documented well at all for JAXWS. What follows is a condensed version of what it took to make it really work.
Repoint to the correct URL
You log into one URL and as part of the LoginResponse you get the real URL of your organization. All subsequent calls made after logging in must use this new URL. It’s in the documentation and described well. However, the redirection of subsequent calls requires the user (caller) to change the ENDPOINT_ADDRESS_PROPERTY to the new URL. The SFDC documentation that uses Axis, shows that with Axis the ability to manipulate a SOAP binding property is relatively straightforward. Unfortunately it’s not quite so simple with JAXWS.
All of the documentation regarding using JAXWS in SFDC focuses on the use of the non-standard com.sun.xml.internal.ws.developer.WSBindingProvider to get access to the SOAP binding properties to insert the new endpoint URL once the login has successfully completed. For some reason, if you attempt to use this from glassfish, the downcast of the port to WSBindingProvider causes an exception preventing it from working properly and successfully getting the port to re-point to the proper endpoint URL. However, I was able to figure a way around the WSBindingProvider to get access to the SOAP header to set the proper endpoint address. I’ll detail that step in another post.
Provide the proper session ID
This workaround was somewhat simpler even though the reasons are just a complex. The short answer is that the SOAP headers are not implicitly defined in the Salesforce.com WSDL. Because the SOAP headers are defined in the WSDL binding section instead of the portType section, they don’t become available and you won’t be able to get set the proper session ID wihout getting really creative. The solution is very straightforward. In the WSImport Options tab where you set the jaxb options, set one more WSImport Option as well. Add in xadditionalHeaders and true.
When done successfully, the method signatures will now include a parameter for the SessionHeader (where you set the sessionID).
I’m going to show a full working example of all of this in a subsequent post for those who want/need more information.
[UPDATE 2]
Upon further testing it appears that wsimport will disregard the -XautoNameResolution if you also provide a mapping file because they’re actually attempting to do the same thing. Furthermore, if you just use -XautoNameResolution without the mapping, wsimport will work properly however Netbeans doesn’t “see” the fix and still complains even though you can compile and run. Removing the references for -XautoNameResolution for now.
Enjoy.



Thank you so much for this solution!!! You are the man! I just started a project to convert a C# program to Java using the Salesforce WSDL and was looking for a solution that would allow me to integrate the WSDL. As a matter of fact, the program was written originally in C# due to the fact that the WSDL integration is much easier in C# than Java. You just made my life a lot easier.
Hi, could you add also an example on how change the ENDPOINT_ADDRESS_PROPERTY ? I’m using NetBeans 6.8 but I can’t find the right method.
Oops — I posted 2 comments in reply to Giovanni, but I don’t think I clicked “REPLY” to do it. Here’s my actual reply, to make sure Giovanni gets notified.
This is regarding the question of how to change the ENDPOINT_ADDRESS_PROPERTY property.
Regarding ENDPOINT_ADDRESS_PROPERTY, I’m in the process of trying to transliterate the code from quickstart.java into something that works with NetBeans, and here’s what I’ve come up with. I’m not sure if it actually works yet, because I have not yet written the subsequent code to actually do something with it.
LoginResponse response = port.login(parameters, scopeHdr);
LoginResultType result = response.getResult();
((BindingProvider) port).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
result.getServerUrl() );
I have now verified that the code in my previous post works. Here (below) is a working example of code that logs in with a Customer Portal user’s credentials, and then asks for the server time.
Of course, you’ll need to supply constants for your organization ID, portal ID, an user credentials. If you’re logging in as a regular organization user, leave the organization & portal IDs unset, and append your security token to the password string instead.
BTW: Thanks very much to Jason for this article. I was completely stuck trying to make this work without knowing about the
xadditionalHeadersoption.public static void main(String[] args) {
LoginScopeHeader scopeHdr = new LoginScopeHeader();
scopeHdr.setOrganizationId( STEVEJ_DEV_ORG_ID );
scopeHdr.setPortalId( STEVEJ_DEV_PORTAL_ID );
try {
SforceService service = new SforceService();
Soap port = service.getSoap();
Login parameters = new Login();
parameters.setUsername( MEGACORP_ADMIN_USERNAME );
parameters.setPassword( MEGACORP_ADMIN_PASSWORD );
LoginResponse response = port.login(parameters, scopeHdr);
LoginResultType result = response.getResult();
System.out.println("Login was successfull.");
System.out.print("The returned session id is: ");
System.out.println(result.getSessionId());
System.out.print("Your logged in user id is: ");
System.out.println(result.getUserId() + " \n\n");
((BindingProvider) port).getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
result.getServerUrl() );
SessionHeader sessionHdr = new SessionHeader();
sessionHdr.setSessionId(result.getSessionId());
GetServerTimestamp tsParam = new GetServerTimestamp();
GetServerTimestampResponse tsResponse =
port.getServerTimestamp(tsParam, sessionHdr);
GetServerTimestampResultType tsResult = tsResponse.getResult();
System.out.println(
"Server time is:" + tsResult.getTimestamp().toString() );
} catch (Exception ex) {
throw new RuntimeException(ex);
}
}
Hi,
I am using partner.wsdl which points to “https://test.salesforce.com/services/Soap/u/18.0″. But to use it in production I need to change it to “https://login.salesforce.com/services/Soap/u/18.0″.
I am putting partner.wsdl in jar file and reading it
URL wsdlLocation = this.getClass().getClassLoader().getResource(“META-INF/partner.wsdl”);
If i try to put it in some hard drive physical location, I am not able to read wsdlLocation.
Could you please tell me how can i change end point url dynamically?
Thank You
Hi , I am using Netbeans 6.9.1 . My web service client
successfully login to salesforce using enterprise wsdl. But if i
try any API call it gives an exception
“Enterprise.UnexpectedErrorFault_Exception: INVALID_SESSION_ID:
Invalid Session ID found in SessionHeader: Illegal Session ” Please
Give me a solution
UPDATE How to use the Session Header? My code for Session
Header. SessionHeader sh = new SessionHeader();
sh.setSessionId(result.getSessionId()); But I dont know how to use
this code..
Hi After parsing the enterprise.wsdl file the
“soapBindingStub.java” class is not created… What will be the
problem?
I’m using Netbeans 7.1 and “WSDL Customization” tab doesn’t offer a “External Bindings File” option. What can I do to add the jaxb binding file?
I haven’t tried with 7.1 yet. I’ll have to take a look.
I am not getting the “External Binding Files” option in the “WSDL Customization” tab in the dialog in Netbeans 7.1 any ideas how I can add the binding via the pom or something?