I have some EJBs as JAX-WS Web Service:
@WebService
@Stateless
@Remote(MobileFacade.class)
public class MobileFacadeBean implements MobileFacade {
...
@Resource
WebServiceContext wsc;
...
}
Within this Web Service class, a WebServiceContext is injected via @Resource. I use this WebServiceContext to get the principal in the implementation. This works quite well, but now I wonder how to (Unit-)test this class!
So far, I was using OpenEJB to test my EJBs. Since the Web Service class also is an Stateless Session Bean, I would really like to use the same approach here. However, it does not work that easy - of course, it complains that there is no WebServiceContext when not called as a Web Service.
So the first question is: are there any ways to mock the WebServiceContext in OpenEJB?
And if no, what approach would you favour to test this kind of Web Service classes?
Cheers,
Frank
There are a handful of @WebService
unit test examples in the OpenEJB examples zip file. Everything you want should work fine.
- simple-webservice
- webservice-attachments
- webservice-security
- webservice-ws-security
The webservice-security example sounds exactly like what you want. The version online uses @RolesAllowed
to make the container do the security check rather than doing it in code, but it is possible to check the principle in code. Here's a slightly modified version of that example that worked for me with no issues.
The bean
@DeclareRoles(value = {"Administrator"})
@Stateless
@WebService(
portName = "CalculatorPort",
serviceName = "CalculatorWsService",
targetNamespace = "http://superbiz.org/wsdl",
endpointInterface = "org.superbiz.calculator.CalculatorWs")
public class CalculatorImpl implements CalculatorWs, CalculatorRemote {
@Resource
private WebServiceContext webServiceContext;
@RolesAllowed(value = {"Administrator"})
public int sum(int add1, int add2) {
// maybe log the principal or something -- prints "jane" in the test
System.out.print(webServiceContext.getUserPrincipal());
return add1 + add2;
}
@RolesAllowed(value = {"Administrator"})
public int multiply(int mul1, int mul2) {
return mul1 * mul2;
}
}
The Test
public class CalculatorTest extends TestCase {
private InitialContext initialContext;
protected void setUp() throws Exception {
Properties properties = new Properties();
properties.setProperty(Context.INITIAL_CONTEXT_FACTORY, "org.apache.openejb.client.LocalInitialContextFactory");
properties.setProperty("openejb.embedded.remotable", "true");
initialContext = new InitialContext(properties);
}
/**
* Create a webservice client using wsdl url
*
* @throws Exception
*/
public void testCalculatorViaWsInterface() throws Exception {
URL url = new URL("http://127.0.0.1:4204/CalculatorImpl?wsdl");
QName calcServiceQName = new QName("http://superbiz.org/wsdl", "CalculatorWsService");
Service calcService = Service.create(url, calcServiceQName);
assertNotNull(calcService);
CalculatorWs calc = calcService.getPort(CalculatorWs.class);
((BindingProvider) calc).getRequestContext().put(BindingProvider.USERNAME_PROPERTY, "jane");
((BindingProvider) calc).getRequestContext().put(BindingProvider.PASSWORD_PROPERTY, "waterfall");
assertEquals(10, calc.sum(4, 6));
assertEquals(12, calc.multiply(3, 4));
}
}
Libraries
If using maven, switch your normal openejb-core
dependency to openejb-cxf
like so. This will add Apache CXF and the OpenEJB/CXF integration code to your classpath.
<dependency>
<groupId>org.apache.openejb</groupId>
<artifactId>openejb-cxf</artifactId>
<version>3.1.4</version>
<scope>test</scope>
</dependency>
If not using maven, simplest approach is to just add all the jars from the lib/
directory of the OpenEJB zip file.
David,In your answer in CalculatorTest you have used CalculatorWs.class, Is it same interface as it is used in webservice side implementation. Do we have to create web service client?
Also in David's example Instead of
QName calcServiceQName = new QName("http://superbiz.org/wsdl", "CalculatorWsService");
use
QName calcServiceQName = new QName("http://superbiz.org/wsdl", "CalculatorPort");