Slow initialization of apache cxf client - java

I'm using wsdl2java generated classes and this code:
MyService f = new MyService();
MyServicePortType type = f.getMyServicePortType();
Each of these calls is taking up to 30 seconds. Why is that?

After hours of googling and tinkering the problem was in how scheme files were referenced:
although WSDL and XSD were locally stored there was still some referenced to w3.org that looked like this:
<!DOCTYPE schema PUBLIC "-//W3C//DTD XMLSchema 200102//EN" "http://www.w3.org/2001/XMLSchema.dtd" [...
<import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="http://www.w3.org/TR/2002/REC-xmldsig-core-20020212/xmldsig-core-schema.xsd" />
w3.org server was resposing super-slowly hence the slow initialization of my client.
I have changed the reference to local:
<import namespace="http://www.w3.org/2000/09/xmldsig#" schemaLocation="xmldsig-core-schema.xsd" />

I owe you a great debt since I have been struggling with this for days and your answer pointed me in the right direction.
Indeed w3.org URLs take ages to respond, however there is actually no reason why a SOAP client generated from a WSDL should still need to parse the WSDL at runtime.
In fact it does not, however default generated construstors force that.
I've discovered that it's possible to skip this by instantiating the service port in a different way and specify the service endpoint via request context as follows:
// creating the service this way passes null as the wsdlLocation, preventing the runtime resolution and parsing of the wsdl
Service service = ZefixService.create(ZefixService.SERVICE);
ZefixServicePortType zefixServicePort = service.getPort(ZefixServicePortType.class);
Map<String, Object> requestContext = ((BindingProvider) zefixServicePort).getRequestContext();
// because we create the service without the wsdl location, we need to specify the service base url ourselves
requestContext.put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, Configuration.get(Constants.API_BASE_URI_PROPERTY));
requestContext.put(BindingProvider.USERNAME_PROPERTY, Configuration.get(Constants.USER_PROPERTY));
requestContext.put(BindingProvider.PASSWORD_PROPERTY, Configuration.get(Constants.PASSWORD_PROPERTY));
return zefixServicePort;
I hope this turns useful for you and others in the future.
Thanks again

Related

Create Enveloped Signature with CXF and WSS4J

I am currently creating a SOAP-Client in Java with help of Apache CXF.
I've generated the Service classes from a given WSDL and configure the client programmatically.(Just to make clear, that I'm not using Spring configuration).
The service I'm calling has the requirement that each Request I send, needs to be signed.
What I did so far is creating my client and add the WSS4JOutInterceptor in order to sign the message.
Client client = ClientProxy.getClient(soapService.getRawSoapInterface());
//Actually not sure if this is really needed?
QName signatureQName = new QName("http://www.w3.org/2000/09/xmldsig#", "Signature");
Map<String, Object> properties = new HashMap<String, Object>();
Map<QName, Object> processorMap = new HashMap<QName, Object>();
processorMap.put(WSSecurityEngine.SIGNATURE, signatureQName);
properties.put("wss4j.processor.map", processorMap);
properties.put(WSHandlerConstants.USER, "clientSignatureAlias");
properties.put(WSHandlerConstants.PW_CALLBACK_CLASS, MyPwCallback.class.getName());
properties.put(WSHandlerConstants.PASSWORD_TYPE, WSConstants.PW_TEXT);
properties.put(WSHandlerConstants.ACTION, WSHandlerConstants.SIGNATURE);
properties.put(WSHandlerConstants.SIG_PROP_FILE, "client.properties");
properties.put(WSHandlerConstants.ENC_KEY_ID, "X509KeyIdentifier");
WSS4JOutInterceptor wssOutInterceptor = new WSS4JOutInterceptor(properties);
My client.properties contains:
org.apache.wss4j.crypto.provider=org.apache.wss4j.common.crypto.Merlin
org.apache.wss4j.crypto.merlin.keystore.type=jks
org.apache.wss4j.crypto.merlin.keystore.password=secret
org.apache.wss4j.crypto.merlin.keystore.alias=cert_sig
org.apache.wss4j.crypto.merlin.keystore.file=clientCerts.jks
So far so good, and each Message is getting signed.
Lets get to the issue:
The Problem is, that The interceptor is putting these Security Headers into the Soap-Request.
<SOAP-ENV:Header xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<wsse:Security xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd"
xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" soap:mustUnderstand="1">
At first I don't them, second point is that the service I am calling doesn't know them and therefore is answering with an exception.
Currently I cannot find a way how to avoid this, any suggestions?
As far as I understood, WSS4J is not able to create an Enveloped Signature at all!
Therefore I moved into another direction. I used Apache Santuario in order to create a Signature for my message.
I used the Intercepor mechanism of CXF to create my own interceptor, an abstract class for this usecase is provided here: How To Modify The Raw XML message of an Outbound CXF Request? .
There I was able to call the Santuario STAX-API to create an valid signature, this is described very good in the following blog: http://coheigea.blogspot.ie/2014/03/apache-santuario-xml-security-for-java.html
Since I had some further modifications on the request, I was able to modify the raw String.
Thank god that SOAP is standardized protocoll and everybody is doing what he wants to...

Webservice communication between Java EE applications

I have two Java EE applications on two separate application servers. One of them already contains a working EJB. I want to be able to communicate with this EJB from the other application by using a JAX-WS webservice (the communication has to work between different application servers and different server versions, so remote EJB call is no option). It is no problem to expose the server api to the client application.
The server side is quite clear, adding #Webservice annotation seems to work quite well. But i wonder what is the best way to build the client: I don't really want to generate the client stub from the wsdl (which itself has been generated from the ejb code by the container in my case) and pack all these generated classes into the client ear - but this seems to be the only way i can make use of #WebServiceRef annotations.
The alternative to make a dynamic proxy myself with the help of the static methods of javax.xml.ws.Service (sth. like service=Service.create() and service.getPort()) is not recommended by the Spec and "container providers are not required to support managed Service Instances created using these methods".
But that is exactly sth. that I want to use:
Is there a way to get a dynamic proxy injected in my code, managed by the application server? Or is the only way to get a managed webservice client instance to be done with generated client stub classes?
Read JAX-WS 2.2 spec, Chapter 4: Client APIs.
1. Static Client Generation
Is really the simplest way to work with JAX-WS. From a web services perspective, the WSDL is the interface AND the connection properties. Even if you choose not to work with it physically, you still need to know it in a logical sense to make meaningful SOAP calls.
Note from JAX-WS spec: An Endpoint that uses the SOAP 1.1/HTTP binding MUST
make its contract available as a WSDL 1.1 document at the publishing address suffixed with ?WSDL or ?wsdl
2. Dynamic Client Programming
Is there a way to get a dynamic proxy injected in my code, managed by the application server?
This approach involves dynamic programming against the JAX-WS API to connect to a web service either with or without using WSDL. There's no way to just "inject" a dynamic proxy out of nowhere. You need to construct & configure one with the SEI's port URLs. The WSDL document is the standard place to store such configuration information, although it is possible to avoid it and to programmatically insert the info.
2A) Dynamic programming with WSDL:
javax.xml.ws.Service service = Service.create(
new URL("http://example.org/stocks.wsdl"),
new QName("http://example.org/stocks", "StockQuoteService"));
com.example.StockQuoteProvider proxy = service.getPort(portName,
com.example.StockQuoteProvider.class)
javax.xml.ws.BindingProvider bp = (javax.xml.ws.BindingProvider)proxy;
Map<String,Object> context = bp.getRequestContext();
context.setProperty("javax.xml.ws.session.maintain", Boolean.TRUE);
proxy.getLastTradePrice("ACME");
Advantages over (1): can dynamically dynamically change the WSDL doc after app is deployed, provided such changes do not affect the java interface to client.
i.e. very little benefit to you. Your WSDL is static. Whilst you could point your client to <service endpoint URL>?wsdl to dynamically lookup, this means you need to manually configure <service endpoint URL> AND that leaves little else that can change in the SEI/WSDL without impacting your client logic.
2B) Dynamic programming without WSDL:
String endpointUrl = ...;
QName serviceName = new QName("http://example.org/wssample/echo/", "EchoService");
QName portName = new QName("http://example.org/wssample/echo/", "EchoServicePort");
/** Create a service and add at least one port to it. **/
Service service = Service.create(serviceName);
service.addPort(portName, SOAPBinding.SOAP11HTTP_BINDING, endpointUrl);
/** Create a Dispatch instance from a service.**/
Dispatch<SOAPMessage> dispatch = service.createDispatch(portName,
SOAPMessage.class, Service.Mode.MESSAGE);
/** Create SOAPMessage request. **/
// compose a request message
MessageFactory mf = MessageFactory.newInstance(SOAPConstants.SOAP_1_1_PROTOCOL);
// Create a message. This example works with the SOAPPART.
SOAPMessage request = mf.createMessage();
SOAPPart part = request.getSOAPPart();
// Obtain the SOAPEnvelope and header and body elements.
SOAPEnvelope env = part.getEnvelope();
SOAPHeader header = env.getHeader();
SOAPBody body = env.getBody();
// Construct the message payload.
SOAPElement operation = body.addChildElement("invoke", "ns1",
"http://com/ibm/was/wssample/echo/");
SOAPElement value = operation.addChildElement("arg0");
value.addTextNode("ping");
request.saveChanges();
/** Invoke the service endpoint. **/
SOAPMessage response = dispatch.invoke(request);
Advantage (not really): can eventually get it to carry out same behaviour as above.
Disadvantages: Complex programming. Non-standard configuration (outside of WSDL). Need to avoid hard-coding settings. Brittle to interface changes. Manually synchronising settings between server and client - easy to omit something, extremely difficult to debug.
Answer:
Go back to (1). Generate a client stub from the WSDL. Use it as an interface contract - it should be designed well and not change.
Then spend the time you save solving real problems... ;) ;)

Get parameter from static context in axis2

While trying to move an axis2 web-app from glassfish3 to tomcat6, I can't seem to find a way to get a config parameter from a static context.
In glassfish3, a system property was defined in a far away place and read from the application using System.getProperty(String name). Not only does the web agree that this is not the way to go for a web application, this trick is just not feasible for tomcat (tomcat docs).
Reading parameters from the ServletContext is also not feasible as the app uses axis2 and I can't seem to find a way to access any kind of servlet voodoo from the static context that initializes the app's configuration.
services.xml (the file containing the service description for axis2) can contain <parameter> nodes, so that seems a nice place to configure the configuration location, but I can't seem to find a way to read these parameters from the application.
So in short: any ideas on how to get a value configured outside the application's code available from a static context?
(answer listed here as StackOverflow does not allow me to answer my own question...)
After scouring the Internet some more, a solution was found using an implementation of org.apache.axis2.engine.ServiceLifeCycle, which could read a parameter in the startUp-method as such:
Parameter param = service.getParameter("name");
if (param != null) {
saveParamValue(param.getValue().toString());
} else {
// log warning on falling back to System.getProperty()
}
The life cycle class is attached using class="fully.qualified.ClassName" on the <service> node of the services.xml file used by axis2.
This works, now the application just crashes on something else (but that has little to with this issue).
The parameters in services.xml can be accessed by getting the ServiceContext object for the service, then calling ServiceContext.getParameter(). If your service implementation class implements the Lifecycle interface, then Axis2 will call Lifecycle.init() every time it creates a new instance of the service class. The argument to Lifecycle.init() is the service's ServiceContext. Your init() implementation could save the context object or look up the parameters that you're interested in.

Invoking a web service. Need the missing link

Can someone fill in the missing link in the code below?
First way:
The web service interface file is HappyService.
JaxWSProxyFactoryBean factory = new JaxWsProxyFactoryBean();
factory.getInterceptors().add(new LoggingInInterceptor());
factory.getInterceptors().add(new LoggingOutInterceptor());
//MISSING LINK. Where does HappyService.class come from? I don't have it
factory.setServiceClass(HappyService.class);
factory.setAddress("http://......../happyService");
//Again how do I get HappyService?
HappyService client = (HappyService) factory.create();
Second way:
String UrlString = "Your WSDL URL";
String nameSpaceUri = "urn:Foo";
String serviceName = "MyHelloService";
String portName = "HelloIFPort";
URL helloWsdlUrl = new URL(UrlString);
ServiceFactory serviceFactory = ServiceFactory.newInstance();
Service helloService =
serviceFactory.createService(helloWsdlUrl,
new QName(nameSpaceUri, serviceName));
//Where did dynamicproxy.HelloIF come from? This code won't compile as that file does not exist anywhere
dynamicproxy.HelloIF myProxy =
(dynamicproxy.HelloIF)
helloService.getPort(
new QName(nameSpaceUri, portName),
dynamicproxy.HelloIF.class);
System.out.println(myProxy.sayHello("Buzz"));
Anyone that has a clue as to where these interface classes come from and how they are generated please let me know. It looks like the only way I can do an web service invocation is by writing the SOAP request by hand and I really don't want to do that as it can get very large and error prone.
There are many tools that generate webservices Java classes from WSDL definition files.
You could try JAXB, which is the standard Java tool for this task.
An other possibility is Axis, which a level higher.
You need a SOAP library such as Apache Axis2. The library will include tools for generating Java classes from WSDLs. You would use that generated code to make the web service calls.
Based on your first sample I think you use the CXF framework.
This framework provides a task named wsdl2java that allows to generate classes from a WSDL file.
Once your classes are generated you can use them in your code to call the Web Service in an easy way without having to build the SOAP message by hand. It's CXF's job to do this.
I think it helps if you refer few basics of web-services in java
http://www.oracle.com/technetwork/java/index-jsp-137004.html
http://metro.java.net/

Servlet Testing

I am using the ServletTester class provided by Jetty to test one of my servlets.
The servlet reads the the body of the request using InputStream.read() to construct a byte[] which is the decoded and acted on by the servlet.
The ServletTest class provides a method getResponses(ByteArrayBuffer) but I'm unsure how to create one of these in the correct format since it would also need to contain things like headers (e.g. "Content-Type: application/octet-stream).
Can anyone show me an easy way to construct this, preferably using an existing library so that I can use it in a similar way to the HttpTester class.
If there is a "better" way to test servlets (ideally using a local connector rather than via the tcp stack) I'd like to hear that also.
Many thanks,
Why use a mock at all? Why not test the servlet by running it in jetty?
Servlet servlet = new MyServlet();
String mapping = "/foo";
Server server = new Server(0);
Context servletContext = new Context(server, contextPath, Context.SESSIONS);
servletContext.addServlet(new ServletHolder(servlet), mapping);
server.start();
URL url = new URL("http", "localhost", server.getConnectors()[0].getLocalPort(), "/foo?bar");
//get the url...assert what you want
//finally server.stop();
Edit: Just wanting to reassure people that this is very fast. Its also a very reliable indicator of what your code will actually do, because it is in fact doing it.
Spring MVC provides a small set of "mock" classes for the various javax.servlet interfaces, such as HttpServletRequest, HttpSession, and so on. This makes it easy to unit test the likes of a servlet, you just inject mocks into the e.g. doGet() method.
Even if you don't use Spring itself on the server, you can still use the mock from the library, just for your tests.
You can use HttpClient to simplify testing somewhat. Take a look at the following article:
http://roberthanson.blogspot.com/2007/12/testing-servlets-with-junit.html
That in combination with servlet tester should give you what you want unit test wise.

Categories