Webservices in XPages - AXIS vs. CXF
I wrote about using Apache AXIS to connect to a web service before. It worked like a charm when you import the AXIS library into the NSF. In the past few days I tried to move this code into an extension library and I had initially very little success. Here is what I tried and what finally worked:- The AXIS libraries are provided as a plug-in in the Domino server, so my first take was to declare a dependency in my plug-in to that plug-in. To successfully create a Extension Library I had to declare dependencies to
com.ibm.commonsandcom.ibm.xsp.coreto be able to extendcom.ibm.commons.Extension. Unfortunately the plug-ins expose Java commons logging, so the classloader complaint and didn't load the AXIS classes - Second attempt was to split the code into two plug-ins: one that depended on the AXIS plug-in and another one that depended on the former and
com.ibm.commonsandcom.ibm.xsp.core. This didn't yield any better result - 3rd test was to import the AXIS jars into a plug-in and only depend on
com.ibm.commonsandcom.ibm.xsp.corebut not the AXIS plug-in. Didn't work either - Finally I tried to switch from AXIS to the newer and more flexible Apache CXF. CXF is able to provide transport over many protocols, not only SOAP and REST but JMS and others too. Initially I felt it was too complex for my little requirement, especially since the list of jar dependencies is quite long.
Turns out CXF is the optimal solution. I used CXF 2.5.2 and the provided wsdl2java utility. The command line I used is[path-to-cxf-install]/bin/wsdl2java -frontend jaxws21 -client your.wsdl. The-clientparameter is optional, but generates a nice sample client that shows the call parameters for all web service methods.
I found I either need to include the WSDL file in the jar or point to the URL where the WSDL file is available online to get CXF to run. Now for the best part: All dependencies including CXF are available in Domino (I tested on 8.5.3), so other than the Java code generated I didn't had to import, depend etc. on anything (it actually might work even in a Java agent). So CXF is the way to go.
grant {
permission java.lang.RuntimePermission "setContextClassLoader";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
For testing I used a dictionary service that returns the definitions found for a given word. My class (the part I had to write myself) is rather short:
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.List;
import javax.xml.namespace.QName;
import com.aonaware.services.webservices.Definition;
import com.aonaware.services.webservices.DictService;
import com.aonaware.services.webservices.DictServiceSoap;
import com.aonaware.services.webservices.WordDefinition;
public class Dict2Test {
public final static String WORD_TO_LOOK_FOR = "Trust";
public final static String WSDL_URL = "http://services.aonaware.com/DictService/DictService.asmx?WSDL";
public static final QName SERVICE_NAME = new QName("http://services.aonaware.com/webservices/", "DictService");
public static void main(String[] args) throws IOException {
Dict2Test dt = new Dict2Test();
ByteArrayOutputStream out = new ByteArrayOutputStream();
dt.getWordInfo(out, WORD_TO_LOOK_FOR);
System.out.println(out.toString());
}
public void getWordInfo(OutputStream out, String theWord) {
OutputStreamWriter w;
DictService ds;
DictServiceSoap dss;
w = new OutputStreamWriter(out);
try {
ds = new DictService(new URL(WSDL_URL),SERVICE_NAME);
dss = ds.getDictServiceSoap();
WordDefinition wd = dss.define(theWord);
List<Definition> allDef = wd.getDefinitions().getDefinition();
if (allDef.isEmpty()) {
w.append("<h1>No definition found for ");
w.append(theWord);
w.append("</h1>\n");
} else {
w.append("<h1>You were looking for: ");
w.append(theWord);
w.append("</h1>\n<ul>");
for (Definition oneD : allDef) {
w.append("\n<li>");
w.append(oneD.getWordDefinition());
w.append("</li>");
}
w.append("\n</ul>");
}
} catch (Exception e) {
try {
w.append("<h1>" + e.getMessage() + "</h1>");
} catch (IOException e1) {
e1.printStackTrace();
} finally {
try {
w.close();
} catch (IOException ex) {
ex.printStackTrace();
}
}
}
}
}
faces-config.xml:
<managed-bean-name>dictionary</managed-bean-name>
<managed-bean-class>demo.Dict2Test</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
var x = context.getUrlParameter("word");
if (x == null || x == "") {
x = "Parameter [word] missing, use ..XAgentDemo4?word=somevalue";
proceedWithBeanCall = false;
}
// The external context and the response object
var exCon = facesContext.getExternalContext();
var response = exCon.getResponse();
// Deliver uncached result
response.setContentType("text/html");
response.setHeader("Cache-Control", "no-cache");
// The Output Stream for Binary Output
var out = response.getOutputStream();
if (proceedWithBeanCall) {
try {
dictionary.getWordInfo(out, x);
} catch (innerErr) {
x = innerErr.message;
proceedWithBeanCall = false;
}
}
if(!proceedWithBeanCall) {
var w = new java.io.OutputStreamWriter(out);
w.write("<h1>Didn't work the way we wanted!</h1>\n");
w.write("<h2>");
w.write(x);
w.write("</h2>\n");
w.close();
}
// Done
facesContext.responseComplete();
out.close();
As usual: YMMV






Comments
Thank you for the hint using a jar-File instead of adding the generated code to WebContent/WEB-INF/src folder.
After adding the following lines to the [Notes program directroy]/jvm/lib/security/java.policy file it worked.
grant {
permission java.lang.RuntimePermission "setContextClassLoader";
permission java.lang.reflect.ReflectPermission "suppressAccessChecks";
};
Bernd
Posted by Bernd Hort At 20:30:54 On 07/31/2012 | - Website - |
What do you think about jax-ws method ?
I used and its working but i amnot sure its best way or not about performance issue etc. we have http crash problem about my app and dont know what is the reason. Maybe web service integration or another thing, opened pmr and still searching for the reason.
I used this method to execute webservice from xpages : { Link }
I just want to know your ideas about webservice execution ?
Posted by Ferhat Bulut At 23:59:17 On 06/12/2012 | - Website - |
I get an exception
javax.xml.ws.WebServiceException: class com.aonaware.services.webservices.DictionaryListExtendedResponse do not have a property of the name {http ://services.aonaware.com/webservices/}DictionaryListExtendedResult
Caused by: javax.xml.bind.JAXBException: {http ://services.aonaware.com/webservices/}DictionaryListExtendedResult is not a valid property on class com.aonaware.services.webservices.DictionaryListExtendedResponse
using the code in a XPage.
If I ran the code directly from Eclipse everything works fine.
Is there any magic trick?
Thanx
Bernd
Posted by Bernd Hort At 18:10:36 On 07/17/2012 | - Website - |
I also added "-exsh true" to the wsdl2java command when I needed to generate the client code to set soap header values.
Posted by Steve Lapthorn At 02:25:29 On 09/18/2012 | - Website - |
Posted by Rickard Tauson At 21:25:45 On 12/10/2012 | - Website - |
Thank you for pointing me to CXF! I'm not a Java specialist, so it took me a while to get things rolling... I have some questions:
1) Am I right that you're saying that we only have to create a jar with the classes generated by CXF, and import it and that we don't have to add anything else? To me it seems I have to add all CXF related jars into the lib\ext-directory...?
2) Even then, it still doesn't work. I can get it to work in Eclipse, with the Notes jvm as JRE and CXF classes added, but in Domino, I get:
WARNING: Interceptor for http://arcelormittal.com/documentum/objectservices Objectservice #http://arcelormittal.com/documentum/objectservices Create has thrown exception, unwinding now
Throwable occurred: java.lang.NullPointerException: NullPointerException invokinghttp://svsim045.sidmar.be/documentum.service/objectservice.asmx null at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
Any idea what I could have forgotten? I think it's strange sun classes are used. Like they get in the way of the apache classes or so...?
Posted by Martin Vereecken At 23:45:42 On 01/22/2013 | - Website - |
Posted by Martin Vereecken At 23:49:19 On 01/22/2013 | - Website - |
Posted by Stephan H. Wissel At 02:00:20 On 01/23/2013 | - Website - |
Anyway: thanks a lot for this great article, it helped me in getting this to work tremendously! I'll post my findings in an article on my site too.
Kind regards,
Martin
Posted by Martin Vereecken At 19:19:48 On 01/23/2013 | - Website - |
Regards,
Martin
Posted by Martin Vereecken At 00:51:31 On 01/24/2013 | - Website - |
thanks for this post (reminded via Martin Vereecken to it)!
we want to connect with a REST API (webservice) that supports both JSON and XML and we need to authenticatie via OAuth2.0.
Now I previously thought that we needed to use the new Extension Library for this but now I'm not sure anymore.
Is Apache CXF a good alternative for this?
Posted by don van zijtveld At 19:51:41 On 01/24/2013 | - Website - |
Cristian
Posted by Cristian D'Aloisio At 04:43:48 On 01/26/2013 | - Website - |
A question for you, your article doesn't mention updating the java.policy file as suggested by Bernd in the first comment. Is that because you did something different which meant the permissions didn't require updating or was it because your policy file had already been updated previously?
Cheers,
Lee
Posted by Lee McMullen At 19:44:03 On 01/31/2013 | - Website - |