Accessing API exposed via wsdl in spring REST based client - java

How can we access a wsdl of a soap project whose war is deployed on the same server, by a Rest based project using spring maven. Basically , I have to access an API that is exposed via wsdl and I have to access this API, the response than needs to be returned as json from a rest POST method. It will be like a REST post method, accepting the inputs and invoking this API (from wsdl) and manipulating the response as JSON,
I have to jump into the WebServices and Spring framework, without through knowledge. So, any help or directions to learn these things fast would be appreciated.

You will need to do the following:
Create the client code from the WSDL
This can be acomplished in Spring with the following technique:Spring - Consuming a SOAP service. It will generate the Java classes that you will need to call the service from your REST API code. In this case that you are calling another service in the same server, all you have to do it set the endpoint url to your server.
Create your REST API
You can use Spring MVC to design your REST API and call the SOAP service.You will need to develop a Controller class with the different endpoints and the proper request and response objects. Spring MVC will automatically convert those request and response objects to JSON using the Jackson framework. Use this guide: Building a RESTful Web Service
That is a generic way of consuming a SOAP service from a Java REST API. If the goal is to simply expose the SOAP service as a REST service then you can just return the response object that was generated from the WSDL. If it is an option, I would seriosly consider refactoring the SOAP service code and expose the it as a REST API.
Note: In the good old days consuming a SOAP was acomplished by using JAX-WS directly and exposing JSON objects was done through Jackson.

Hi I have used the following approach to implement the above requirement:
http://myshittycode.com/2013/10/01/using-spring-web-services-and-jaxb-to-invoke-web-service-based-on-wsdl/
1. changed the pom to add spring-ws dependency and plugin.
2. build the classes and it generated the classes from the wsdl.
3. changed the application xml :
<!--Generating web sources-->
<!-- Define the SOAP version used by the WSDL -->
<bean id="soapMessageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
<property name="soapVersion">
<util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_12"/>
</property>
</bean>
<!-- The location of the generated Java files -->
<oxm:jaxb2-marshaller id="marshaller" contextPath="com.pb.pims.generatedsources"/>
<!-- Configure Spring Web Services -->
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="soapMessageFactory"/>
<property name="marshaller" ref="marshaller"/>
<property name="unmarshaller" ref="marshaller"/>
<property name="defaultUri" value="http://localhost/HSWS/services/HSService?wsdl"/>
</bean>
4. Created the Service class;
#Service
public class HSService {
#Autowired
private WebServiceTemplate webServiceTemplate;
public List<HSChild> getHSChildren(String hscode, String country,String limit) {
GetHSChildren getHSChildren= new ObjectFactory().createGetHSChildren();
getHSChildren.setCountry(country);
getHSChildren.setHsCode(hscode);
getHSChildren.setLimit(Integer.parseInt(limit));
GetHSChildrenResponse response = (GetHSChildrenResponse) webServiceTemplate.marshalSendAndReceive(getHSChildren);
return response.getGetHSChildrenReturn();
}
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HSService hsService = context.getBean(HSService.class);
}
}
So, I am able to call this aPI from the wsdl via my client. But I am always getting the values of the getGetHSChildrenReturn. hscode and getGetHSChildrenReturn.description as null.
Please find below the getGetHSChildrenReturn.class generated in the Step1 :
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"getHSChildrenReturn"
})
#XmlRootElement(name = "getHSChildrenResponse")
public class GetHSChildrenResponse {
#XmlElement(required = true)
protected List<HSChild> getHSChildrenReturn;
public List<HSChild> getGetHSChildrenReturn() {
if (getHSChildrenReturn == null) {
getHSChildrenReturn = new ArrayList<HSChild>();
}
return this.getHSChildrenReturn;
}
Also, I verified in the service code , which we are invoking via this wsdl by putting logging, that the correct request is going and it is returning the expected response at service end. But while coming to the client, the values are set as null.
Please help, what's wrong here in the client side.
Thanks in advance.

Related

How to run two mock web services with different URL on the same port with citrus?

I am investigating Citrus Framework in order to use it in test automation of my project. I want to run two web services, lets name it:
http://localhost:port/service1
http://localhosr:port/sercice2
and then call my SUT (system under test). SUT will synchronously call both of above mock services (service1 & service2) and return the answer.
I've managed to do it, BUT on different ports:
<citrus-ws:server id="helloMockService1"
port="${server.port1}"
servlet-mapping-path="/service1"
auto-start="true"
timeout="10000"
endpoint-adapter="genericResponseAdapter1" />
<citrus-ws:server id="helloMockService2"
port="${server.port2}"
servlet-mapping-path="/service2"
auto-start="true"
timeout="10000" />
I need it on the same port. I've also tried to write my custom DispatchingEndpointAdapter and somehow extract the context path from the request Message, but didn't succeed..
<citrus:dispatching-endpoint-adapter id="dispatchingEndpointAdapter"
mapping-key-extractor="mappingKeyExtractor"
mapping-strategy="mappingStrategy"/>
<bean id="mappingStrategy"
class="com.consol.citrus.endpoint.adapter.mapping.SimpleMappingStrategy">
<property name="adapterMappings">
<map>
<entry key="service1" value-ref="genericResponseAdapter1"/>
<entry key="service2" value-ref="genericResponseAdapter2"/>
</map>
</property>
</bean>
<bean id="mappingKeyExtractor"
class="com.mycompany.citrus.CustomExtractor">
</bean>
I cant find URL in request parameter of type com.citrus.message.Message..
package com.mycompany.citrus;
import com.consol.citrus.endpoint.adapter.mapping.MappingKeyExtractor;
import com.consol.citrus.message.Message;
public class CustomExtractor implements MappingKeyExtractor{
#Override
public String extractMappingKey(Message request) {
// ther is no URL information in Message object!!!!!!!!!!!!
return "service1";
}
}
How do you run two mock services in Citrus Framework on the same port? I want to differentiate them by URL, not a payload itself... (by peyload it would be easy using above custom MappingKeyExtractor, since Message object contains payload)
Please help! I cant belive that Citrus Framework could be so badly designed that missed such a basic test requirement.
You are almost there. Remove the servlet-mapping-path setting and use this mapping key extractor:
<bean id="mappingKeyExtractor" class="com.consol.citrus.endpoint.adapter.mapping.HeaderMappingKeyExtractor">
<property name="headerName" value="#{T(com.consol.citrus.http.message.HttpMessageHeaders).HTTP_REQUEST_URI}"/>
</bean>
That will map incoming requests based on the request path. So you can add mappings with the keys /service1 and /service2 in the simple mapping strategy.

Camel CXF Soap Client calling web service with multiple input parameters

I'm using Camel and have generated code from a WSDL using CXF. I generated a client stub and the implementation appears like this:
SetDeviceDetailsv4 port = ss.getSetDeviceDetailsv4Port();
com.vodafone.gdsp.ws.SetDeviceDetailsv4_Type _setDeviceDetailsv4_parameters = null;
com.vodafone.gdsp.ws.GdspHeader _setDeviceDetailsv4_gdspHeader = null;
com.vodafone.gdsp.ws.SetDeviceDetailsv4Response _setDeviceDetailsv4__return = port.setDeviceDetailsv4(_setDeviceDetailsv4_parameters, _setDeviceDetailsv4_gdspHeader);
System.out.println("setDeviceDetailsv4.result=" + _setDeviceDetailsv4__return);
As you one can see, the port takes two parameters and returns the response, which I want to delegate back to my Camel Route. What's the best way to implement this in Camel? I already have my CXF Enpoint defined, I'm just struggling with the DSL Routing part of it. Should I add a processor like what is found in this link? Apache Camel and web services
Thanks
You can use jax-ws client (implement as bean) and use it in camel DSL. JAX-WS client bean definition takes service class/interface and allow you configure additional properties like SSL config & etc. In route, we can use it as bean. It takes JAXB generated Request object (WSDL request object) as input and returns the JAXB generated Response Object (WSDL response object). To convert you pojo to JAXB classes, Dozer framework can be used or custom mapping can be also used.
Jax-WS client is also flexible to take XML as request and response. In that case, properties need to be set as DATAFORMAT as PAYLOAD.
I'm not sure if this is the correct way to do it but I added both of my "input" objects as a Camel Header, then I wrote a processor that grabbed what I needed and put the two objects that the service call needed as parameters.
public void process(Exchange exchange) throws Exception {
Message inMessage = exchange.getIn();
gdspHeader = inMessage.getHeader(GDSP_HEADER, com.vodafone.gdsp.ws.GdspHeader.class);
commModule = inMessage.getHeader(COMM_MODULE_HEADER, resmed.hi.ngcs.datastore.model.CommModule.class);
SetDeviceDetailsv4_Type deviceDetails = createSetDeviceDetailsv4(commModule);
List<Object> params = new ArrayList<>();
params.add(deviceDetails);
params.add(gdspHeader);
inMessage.setBody(params);
}
`

Get SOAP request as XML in Spring MVC

I need to get the XML Soap request coming to a url on my server. I wrote something like
#RequestMapping("/SomeService")
#ResponseBody
public String index(#RequestBody String request) {
mailService.sendMail("someone#gmail.com", "Subject", request);
return "";
}
But the request body is coming as blank. I'm using spring 3.2. I just need the XML SOAP content. How do I proceed in this case. Thanks in advance.
Let me suggest a few ways of doing this #Akhil:
If you want to expose a robust SOAP based endpoint, then the best approach would be to use one of the full-fledged JAX-WS implementations(say Apache CXF or Axis2).
If you want to be a little more lightweight and want to be completely under the Spring umbrella of projects, I would highly recommend using Spring-WS as the endpoint to consume the SOAP request and serve out a response - Spring WS is here: http://static.springsource.org/spring-ws/sites/2.0/reference/html/index.html
If this is an ad-hoc endpoint that you are using not for real business reasons but say just for capturing info and do not really care for other features that SOAP brings - say security, validation etc, marshalling, unmarshalling support etc, then an option would be to use Spring's HttpRequestHandlingServlet, this way you can implement a HttpRequestHandler which takes HttpServletRequest as a parameter and grab the POSTed content from it.
These as you have probably noted is all outside of Spring MVC, the reason is the framework tends to consume the raw http request and provides the parameters once it has pre-processed them, so even if you write a #RequestMapped method expecting a raw string, you will not get it cleanly.
Try below code. I think you have to define this method as a POST. And define the headers as well. It will support to define this as GET but in the server side it will not identify the Body contents in the #RequestBody .
#RequestMapping(value = "/SomeService", method = RequestMethod.POST, headers = "Accept=application/xml, application/json")
#ResponseBody
public String index(#RequestBody String request) {
mailService.sendMail("someone#gmail.com", "Subject", request);
return "";
}
Add the following bean definition in your beans definition file. My bean definition has beans prefix.
<beans:bean name="handlerAdapter"
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter">
<beans:property name="messageConverters">
<util:list>
<beans:bean
class="org.springframework.http.converter.StringHttpMessageConverter" />
</util:list>
</beans:property>
</beans:bean>

REQ: Spring configured CXF ws client -- replacing hardcoded variables like 'address'

I have to contact a Web Service (WS). I'm using JDK 1.6, maven 3.04, Spring 3.20 and apache's CXF 2.7.2. Using maven I created stubs for the WS by feeding it the wsdl file. I have a spring config for the WS client and it looks something like
servlet-context.xml
<jaxws:client id="paymentClient" serviceClass="com.xxx.payment.Payment"
address="http://127.0.0:8088/mockPaymentBinding" <!-- SOAPUI mock -->
username="username"
password="secret" />
<!- username and password are for wsdl basic authentication -->
In the Java code it looks something like
#Autowired
com.xxx.payment.Payment client;
..
// Set all needed parameters.
PaymentGetBalanceResponse response = null;
PaymentGetBalance getBalance = new PaymentGetBalance();
RequestGetBalance value = new RequestGetBalance();
value.setTransactionId("transActionId");
getBalance.setRequest(value );
// Now call the WS and get the response
response = client.getBalance(getBalance); // generated by the cxf -client argument.
The "response" line is generated as an example by CXF. Then Eclipse tells me something is missing (getbalance) and optionally creates it for me above the line. Then something else is (value) missing and so on. In the end all parameters are correctly filled in. All the missing stuff/variables/objects are in the generated stubs code.
This works like a charm BUT the address is atm hardcoded in the spring config. The configuarion parameters for the application are stored in a simple database. The contents is accesible using a spring bean so I can get at the variables in the end in the code using something like config.getValue(URL);
I hoped to being able to change the 'address' (url WS) in the code above but haven't found a way to do that. Can't find setters in the generated stub code. An alternative would be to use variables in the spring servlet-context.xml file BUT those variables have to come from the database. Second alternative. I probably/hopefully get away with starting at the bottom and using the Objectfactorys (in the stubs) to create objects. Then setting the correct parameter (either in the 'new' or a setter) and then work my way to the top. A colleguee has done this (not for 'address') and this seems to work but the code is suboptimal/'messy' at best. ALSO I would like to able to have the username and password configurable, NOT static. Did quite a bit of RTM at the CXF sites but to no avail.
Read something about JaxWsProxyFactoryBean but can't figure out how to apply it here as I use Springs #autowire functionality.
I've been breaking my brains about this issue but it seems my neurons are running in circles. ANY help/pointers is really appreciated.
From CXF User Guide: How to override the service address?.
If I've inferred the spring config correctly, I think this will do:
#Autowired
com.xxx.payment.Payment client;
// ...
BindingProvider provider = (BindingProvider)client.getServicePort();
// You can set the address per request here
provider.getRequestContext().put(
BindingProvider.ENDPOINT_ADDRESS_PROPERTY,
"http://my/new/url/to/the/service");

Spring-WS: how to use WebserviceTemplate with pre-generated SOAP-envelope

Can you use a Spring-WS WebserviceTemplate for calling a webservice and avoid that it generates a SOAP-envelope? That is, the message already contains an SOAP-Envelope and I don't want that the WebserviceTemplate wraps another one around it. :-)
The reason I want this is that I'd like to call a webservice that uses ws-security and do not want to put the ws-security stuff into the WebserviceTemplate, but just want to feed it a message with pre-generated ws-security information in the SOAP-envelope. I tried calling the method sendSourceAndReceiveToResult with a Source already contains a Soap-Envelope with the WS-Security stuff and the webservice template wraps around another Soap-Envelope and thus destroys the message.
You're using ws-security in a strange way... I guess that you're trying to avoid ws-security dependancy by using pre-generated messages - for simple client might make sense, although it's definitely not by-the-book.
You can configure WebServiceTemplate to use plain XML without SOAP by setting messageFactory on WebServiceTemplate to this bean:
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="messageFactory" ref="poxMessageFactory" />
</bean>
<bean id="poxMessageFactory" class="org.springframework.ws.pox.dom.DomPoxMessageFactory" />
Interceptors can come in handy for the sort of thing you are trying to do. Take a look at the Interceptor hierarchy here: http://static.springframework.org/spring-ws/docs/1.0-m1/api/org/springframework/ws/EndpointInterceptor.html
You can register an EndpointInterceptor with spring-ws and manipulate the response to your liking.

Categories

Resources