Call SOAP service asynchronously using Spring - spring

I've to call a SOAP web service asynchronously. Currently, I'm calling it in a synchronous way using Spring webservicetemplate.
Current config is like:
<bean id="interceptedHttpClientBuilder" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="httpClientBuilder" />
<property name="targetMethod" value="addInterceptorFirst"> </property>
<property name="arguments">
<list>
<bean class="org.springframework.ws.transport.http.HttpComponentsMessageSender.RemoveSoapHeadersInterceptor"/>
</list>
</property>
</bean>
<bean id="requestConfigBuilder" class="org.apache.http.client.config.RequestConfig" factory-method="custom">
<property name="socketTimeout" value="120000" />
</bean>
<bean id="requestConfig" factory-bean="requestConfigBuilder" factory-method="build" />
<bean id="httpClient" factory-bean="httpClientBuilder" factory-method="build" />
<bean id="httpClientBuilder" class="org.apache.http.impl.client.HttpClientBuilder" factory-method="create">
<property name="defaultRequestConfig" ref="requestConfig" />
</bean>
<bean id="messageSender" class="org.springframework.ws.transport.http.HttpComponentsMessageSender">
<constructor-arg ref="httpClient"></constructor-arg>
</bean>
<bean id="jaxb2Marshaller" class="org.springframework.oxm.jaxb.Jaxb2Marshaller">
<property name="packagesToScan">
<list><value>...</value></list>
</property>
</bean>
<bean id="wsClientSecurityInterceptor"
class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="UsernameToken" />
<property name="securementUsername"><value>${username}</value></property>
<property name="securementPassword"><value>${password}</value></property>
<property name="securementPasswordType" value="PasswordText" />
</bean>
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="marshaller" ref="jaxb2Marshaller"></property>
<property name="unmarshaller" ref="jaxb2Marshaller"></property>
<property name="defaultUri"><value>${ws.url}</value></property>
<property name="interceptors">
<list>
<ref local="wsClientSecurityInterceptor"/>
</list>
</property>
<property name="messageSender" ref="messageSender"></property>
</bean>
Java call looks like:
MyResponse response = (MyResponse) webServiceTemplate.marshalSendAndReceive(req, new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) {
((SoapMessage) message).setSoapAction("test");
}
});
May I know how can I change it to call the service asynchronously? Or Do I need to use something else in spring to achieve this?

Not sure why you use spring-integration tag in your question, but if we are here, please, definitely take a look into the #MessagingGateway with the Future<> as a return type: https://docs.spring.io/spring-integration/docs/5.0.1.RELEASE/reference/html/messaging-endpoints-chapter.html#async-gateway
The SOAP WebService can be called via Spring Integration <int-ws:outbound-gateway>: https://docs.spring.io/spring-integration/docs/5.0.1.RELEASE/reference/html/ws.html
The samples are here: https://github.com/spring-projects/spring-integration-samples
To be more clear the code might looks like this:
<int:gateway id="mathService"
service-interface="org.springframework.integration.samples.async.gateway.MathServiceGateway"
default-request-channel="requestChannel"
async-executor="executor"/>
Where that MathServiceGateway is like this:
public interface MathServiceGateway {
Future<Integer> multiplyByTwo(int i);
}
The WS call is simple as well:
<int-ws:outbound-gateway request-channel="requestChannel" uri="http://www.w3schools.com/xml/tempconvert.asmx"/>

Related

How can I invoke multiple web services using JAXB in Spring?

I'm building an application with Spring MVC (3.2). This application need to invoke to 2 web services. It's ok when I invoke each service separately. However, it's not work when I call both. My application config file:
<bean id="soapMessageFactory" class="org.springframework.ws.soap.saaj.SaajSoapMessageFactory">
<property name="soapVersion">
<util:constant static-field="org.springframework.ws.soap.SoapVersion.SOAP_11" />
</property>
</bean>
<!-- The first service-->
<bean id="local" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
p:contextPath="com.ws" />
<bean id="webServiceTemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<property name="marshaller" ref="local" />
<property name="unmarshaller" ref="local" />
<property name="defaultUri"
value="http://localhost:9999/ws/ProcessService" />
</bean>
<!-- The second service-->
<bean id="preconvert" class="org.springframework.oxm.jaxb.Jaxb2Marshaller"
p:contextPath="com.ws.preprocess" />
<bean id="wstemplate" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="soapMessageFactory" />
<property name="marshaller" ref="preconvert" />
<property name="unmarshaller" ref="preconvert" />
<property name="defaultUri"
value="http://localhost:9999/jod/PreProcessService" />
</bean>
Help me please! Thanks.
Hi chicky I solved the problem
Beans XML
<bean id="webServiceTemplate1" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="soapMessageFactory"/>
<property name="marshaller" ref="marshaller1"/>
<property name="unmarshaller" ref="marshaller1"/>
<property name="defaultUri" value="http://www.webservicex.net/CurrencyConvertor.asmx?WSDL"/>
</bean>
<bean id="webServiceTemplate2" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="soapMessageFactory"/>
<property name="marshaller" ref="marshaller2"/>
<property name="unmarshaller" ref="marshaller2"/>
<property name="defaultUri" value="http://www.w3schools.com/webservices/tempconvert.asmx?WSDL"/>
</bean>
webServiceTemplate1 service
#Autowired
private WebServiceTemplate webServiceTemplate1;
#Override
public double obtenerCambio(String from, String to) {
ConversionRate conversionRate = new ObjectFactory().createConversionRate();
conversionRate.setFromCurrency(Currency.fromValue(from));
conversionRate.setToCurrency(Currency.fromValue(to));
ConversionRateResponse conversionRateResponse = (ConversionRateResponse) webServiceTemplate1.marshalSendAndReceive(conversionRate);
return conversionRateResponse.getConversionRateResult();
}
And webServiceTemplate2
#Autowired
private WebServiceTemplate webServiceTemplate2;
#Override
public String obtenerConversion(String celcius) {
CelsiusToFahrenheit celsiusToFahrenheit = new ObjectFactory().createCelsiusToFahrenheit();
celsiusToFahrenheit.setCelsius(celcius);
CelsiusToFahrenheitResponse response = (CelsiusToFahrenheitResponse) webServiceTemplate2.marshalSendAndReceive(celsiusToFahrenheit);
return response.getCelsiusToFahrenheitResult();
}

Spring MDP not Consuming Message

I am implementing Spring MDP + JMSTemplate to send and receive the message. The message send mechanism is working fine, however the MDP is not getting invoked. I tried testing the via plain receiver, and was able to retrieve the message, but not via MDP. What could be the problem? I can see the messages getting accumulated in the request queue, but somehow the MDP is not getting trigger. Am I missing anything here in configurations or something else needs to be taken care of?
Here's the Spring Config. The Java class to send and received are pretty much standard ones.
<bean id="cookieRequestListener" class="com.text.jms.mq.mdp.RequestQueueMDP">
<property name="logger" ref="mqLogger" />
<property name="scoringEngine" ref="scoringEngine" />
<property name="mqSender" ref="jmsMQSender" />
</bean>
<bean id="CookieRequestContainer" class="org.springframework.jms.listener.DefaultMessageListenerContainer">
<property name="connectionFactory" ref="cachedConnectionFactory" />
<property name="destination" ref="jmsRequestQueue" />
<property name="messageListener" ref="cookieRequestListener" />
</bean>
<bean id="jmsConnectionFactory" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>java:/jms/queueCF</value>
</property>
</bean>
<!-- A cached connection to wrap the Queue connection -->
<bean id="cachedConnectionFactory" class="org.springframework.jms.connection.CachingConnectionFactory">
<property name="targetConnectionFactory" ref="jmsConnectionFactory"/>
<property name="sessionCacheSize" value="10" />
</bean>
<!-- jms Request Queue Configuration -->
<bean id="jmsRequestQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>java:/jms/cookieReqQ</value>
</property>
</bean>
<!-- jms Response Queue Configuration -->
<bean id="jmsResponseQueue" class="org.springframework.jndi.JndiObjectFactoryBean">
<property name="jndiTemplate">
<ref bean="jndiTemplate" />
</property>
<property name="jndiName">
<value>java:/jms/cookieResQ</value>
</property>
</bean>
<bean id="jmsJMSTemplate" class="org.springframework.jms.core.JmsTemplate" >
<property name="connectionFactory" ref="cachedConnectionFactory" />
</bean>
<!-- jms MQ Utility -->
<bean id="jmsMQSender" class="com.text.jms.util.MQSender">
<property name="jmsTemplate">
<ref bean="jmsJMSTemplate"></ref>
</property>
<property name="defaultDestination">
<ref bean="jmsRequestQueue" />
</property>
<property name="logger" ref="mqLogger" />
</bean>

How do I add a jackson objectmapper dateformat config into spring mvc config?

I have a problem about jackson 2.1.
My pojo have some date properties, I want turn it to string, I setted it in spring-servlet.xml but it's not usefull.
I don't like use #JsonSerialize(using = JsonDateSerializer.class) on the setter.
this is my configuration:
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
</bean>
</property>
</bean>
</property>
</bean>
Assuming you are using Spring 3.1, you should customize your mvc-annotation driven tag properties,
as is shown in
Configuring ObjectMapper in Spring
Assuming that your bean declaration is correct I think it should be something like
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
<property name="objectMapper">
<bean class="com.fasterxml.jackson.databind.ObjectMapper">
<property name="dateFormat">
<bean class="java.text.SimpleDateFormat">
<constructor-arg type="java.lang.String" value="yyyy-MM-dd"></constructor-arg>
</bean>
</property>
</bean>
</property>
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
My setup is:
<!-- Date Format -->
<bean id="dateFormatter" class="java.text.SimpleDateFormat">
<constructor-arg value="yyyy-MM-dd"/>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="dateFormatter" />
<property name="targetMethod" value="setTimeZone" />
<property name="arguments">
<list>
<ref bean="timeZone"/>
</list>
</property>
</bean>
<!-- End Date Format -->
<!-- Jackson Object Mapper -->
<bean id="jacksonObjectMapper" class="org.codehaus.jackson.map.ObjectMapper"/>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="jacksonObjectMapper" />
<property name="targetMethod" value="configure" />
<property name="arguments">
<list>
<value type="org.codehaus.jackson.map.DeserializationConfig.Feature">FAIL_ON_UNKNOWN_PROPERTIES</value>
<value>false</value>
</list>
</property>
</bean>
<bean id="jacksonDeserializationConfig" class="org.codehaus.jackson.map.DeserializationConfig" factory-bean="jacksonObjectMapper" factory-method="getDeserializationConfig" />
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="jacksonDeserializationConfig" />
<property name="targetMethod" value="setDateFormat" />
<property name="arguments">
<list>
<ref bean="dateFormatter"/>
</list>
</property>
</bean>
<bean class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="jacksonObjectMapper" />
<property name="targetMethod" value="setDeserializationConfig" />
<property name="arguments">
<list>
<ref bean="jacksonDeserializationConfig"/>
</list>
</property>
</bean>
<!-- End Jackson Object Mapper -->
<!-- JSON provider -->
<bean id="jsonRestProvider" class="org.codehaus.jackson.jaxrs.JacksonJsonProvider">
<property name="mapper" ref="jacksonObjectMapper"/>
</bean>

Jackson+Spring3.0.5 custom object mapper

I am having a hard time configuring Jackson on my Spring application. I can get it to work, but it does not seem to accept any kind of configurations. Basically what i'm trying to achieve is have an ObjectMapper that scans for Spring format annotations.
What i am trying is this:
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<bean
class="org.springframework.http.converter.json.MappingJacksonHttpMessageConverter">
<property name="objectMapper" ref="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
<bean id="jacksonObjectMapper" class="ro.softwin.cnfp.ConversionServiceAwareObjectMapper" />
<bean
class="org.springframework.web.servlet.view.ContentNegotiatingViewResolver">
<property name="mediaTypes">
<map>
<entry key="json" value="application/json" />
<entry key="html" value="text/html" />
</map>
</property>
<property name="viewResolvers">
<list>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
</list>
</property>
<property name="defaultViews">
<list>
<bean
class="org.springframework.web.servlet.view.json.MappingJacksonJsonView">
<property name="prefixJson" value="false" />
<property name="objectMapper" value="jacksonObjectMapper" />
</bean>
</list>
</property>
</bean>
The code for the mapper is :
public class ConversionServiceAwareObjectMapper extends ObjectMapper {
#Autowired
public ConversionServiceAwareObjectMapper(
ConversionService conversionService) {
AnnotationIntrospector introspector = AnnotationIntrospector.pair(
new FormatAnnotationIntrospector(conversionService),
DEFAULT_ANNOTATION_INTROSPECTOR);
this.setDeserializationConfig(this.getDeserializationConfig()
.withAnnotationIntrospector(introspector));
this.setSerializationConfig(this.getSerializationConfig()
.withAnnotationIntrospector(introspector).withSerializationInclusion(JsonSerialize.Inclusion.NON_NULL));
}
}
When initializing the server the following error occurs:
java.lang.IllegalStateException: Cannot convert value of type [java.lang.String] to required type [org.codehaus.jackson.map.ObjectMapper] for property 'objectMapper': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:241)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:470)
... 55 more
I tried switching to a normal view resolver and just having the object mapper in the AnnotationMethodHandler, and that works regarding server start-up, but it just completely ignores any configuration.
I am completely at a loss as to what to do next.
Thanks for any help.
Update :
<property name="objectMapper" value="jacksonObjectMapper" />
with:
<property name="objectMapper" ref="jacksonObjectMapper" />
ref not value.

Spring: How to inject a property with a non-setter method?

Is it possible to inject a property bean through a method with a signature doesn't start with set?
Specifically, I'm trying to use Spring to configure an embedded Jetty instance and I need to be able to inject a servlet bean via an addServlet() method.
I am looking at Jetty/Tutorial/Embedding Jetty documentation. I guess you mean calling ServletContextHandler.addServlet(). You have few choices:
#Configuration (since 3.0)
My favourite approach. You can configure everything using Java!
#Configuration
public class Jetty {
#Bean(initMethod = "start")
public Server server() {
Server server = new Server(8080);
server.setHandler(context());
return server;
}
#Bean
public ServletContextHandler context() {
ServletContextHandler context = new ServletContextHandler(ServletContextHandler.SESSIONS);
context.setContextPath("/");
context.addServlet(servlet(), "/*");
return context;
}
#Bean
public ServletHolder servletHolder() {
return new ServletHolder(helloServlet());
}
#Bean
public HelloServlet helloServlet() {
return new HelloServlet();
}
}
Inheritance/decorating
You can inherit from or wrap original ServletContextHandler class to follow Java bean naming conventions. Of course it requires an extra class, but makes Jetty class Spring-friendly. You can even publish such wrapper or maybe someone already did that?
MethodInvokingFactoryBean
I don't like this approach as it seems too low level. Basically you create a bean that calls arbitrary method with arbitrary arguments:
<bean id="javaVersion" class="org.springframework.beans.factory.config.MethodInvokingFactoryBean">
<property name="targetObject" ref="servletContextHandler"/>
<property name="targetMethod" value="addServlet"/>
<property name="arguments">
<list>
<ref bean="yourServlet"/>
</list>
</property>
</bean>
just the spring file adapted to Jetty 7. It's possible to add yours contextHandlers...
<bean id="contexts"
class="org.eclipse.jetty.server.handler.ContextHandlerCollection" />
<context:property-placeholder location="src/main/resources/ws.properties" />
<!-- Manually start server after setting parent context. (init-method="start") -->
<bean id="jettyServer" class="org.eclipse.jetty.server.Server"
destroy-method="stop">
<property name="threadPool">
<bean id="ThreadPool" class="org.eclipse.jetty.util.thread.QueuedThreadPool">
<property name="minThreads" value="10" />
<property name="maxThreads" value="50" />
</bean>
</property>
<property name="connectors">
<list>
<bean id="Connector" class="org.eclipse.jetty.server.nio.SelectChannelConnector">
<property name="port" value="8181" />
</bean>
</list>
</property>
<property name="handler">
<bean id="handlers" class="org.eclipse.jetty.server.handler.HandlerCollection">
<property name="handlers">
<list>
<ref bean="contexts" />
<bean id="defaultHandler" class="org.eclipse.jetty.server.handler.DefaultHandler" />
<bean class="org.eclipse.jetty.servlet.ServletContextHandler"
p:contextPath="/${ws.context.path}">
<property name="sessionHandler">
<bean class="org.eclipse.jetty.server.session.SessionHandler" />
</property>
<property name="servletHandler">
<bean class="org.eclipse.jetty.servlet.ServletHandler">
<property name="servlets">
<list>
<bean class="org.eclipse.jetty.servlet.ServletHolder"
p:name="spring-ws">
<property name="servlet">
<bean
class="org.springframework.ws.transport.http.MessageDispatcherServlet" />
</property>
<property name="initParameters">
<map>
<entry key="contextConfigLocation" value="classpath:/spring-ws-context.xml" />
</map>
</property>
</bean>
</list>
</property>
<property name="servletMappings">
<list>
<bean class="org.eclipse.jetty.servlet.ServletMapping"
p:servletName="spring-ws" p:pathSpec="/*" />
</list>
</property>
</bean>
</property>
</bean>
<bean class="org.eclipse.jetty.server.handler.RequestLogHandler" />
</list>
</property>
</bean>
</property>
</bean>

Resources