Apache Camel + spring remoting + jax-ws + multiple parameters - spring

I have following camel route:
<route id="myRoute">
<from uri="cxf:bean:TestEndpoint />
<process ref="TestProcessor" />
<to uri="bean:TestWS?method=doSomething" />
</route>
where TestWS:
<bean id="TestWS" class="org.springframework.remoting.jaxws.JaxWsPortProxyFactoryBean">
<property name="serviceInterface" value="org.example.TestWS />
<property name="wsdlDocumentUrl" value="http://localhost:8080/TestWSImplService/TestWSImpl?wsdl" />
<property name="namespaceUri" value="http://org.example" />
<property name="serviceName" value="TestWSImplService" />
<property name="portName" value="TestWSImplPort" />
</bean>
and TestWS:
#WebService(targetNamespace = "http://org.example")
public interface TestWS {
public String doSomething(Object param1, Object param2);
}
Could you tell me what TestProcessor should return in order to proper call TestWS with multiple parameters?
Thanks

You need to add multiParameterArray=true option to the endpoint to the bean [1] URI.
<to uri="bean:TestWS?method=doSomething&multiParameterArray=true" />
Then your processor should set body as an array of parameters you want to pass to the service:
exchange.getIn().setBody(new Object[]{"param1", "param2"});
[1] https://camel.apache.org/bean.html

Related

How to provide reference bean to XmlViewResolver

i am generating Excel Sheet using Spring MVC , for this reason i have the following in my appcontext.xml file
appcontext.xml
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/views.xml"/>
</bean>
views.xml
<bean id="excelView" class="com.xxxx.xx.util.MyListExcelView" />
​
Instead of having the bean reference excelView in a separate views.xml file .can we mention the below in the same appcontext.xml
<bean id="excelView" class="com.xxxx.xx.util.MyListExcelView" />
Sure, you can.
Just add BeanNameViewResolver to your ViewResolver chain.
Of course, you should remove excelView from views.xml in this case.
Here is an example:
appcontext.xml:
<bean class="org.springframework.web.servlet.view.BeanNameViewResolver">
<property name="order" value="0"/>
</bean>
<bean class="org.springframework.web.servlet.view.XmlViewResolver">
<property name="order" value="1"/>
<property name="location" value="/WEB-INF/views.xml"/>
</bean>
<bean id="excelView" class="com.xxxx.xx.util.MyListExcelView" />
YourController.java
#Controller
public class YourController {
// ...
#RequestMapping(value = "/test")
public String test() {
// populate your model here
return "excelView";
}
// ...
}

Spring integration RabbitMQ - Listener with retry

Below is my declarative configuration inside xml file for rabbitmq listener. Retry with advic chain doesnot seem to be happening.DLQMessageRecoverer class is throwing RabbitmqRejectAndDontRequeue exception. It doesnot seem to be calling it either.
<bean id="retryAdvice" class="org.springframework.amqp.rabbit.config.StatefulRetryOperationsInterceptorFactoryBean">
<property name="messageRecoverer" ref="dlqMessageRecoverer"/>
<!--<property name="messageRecoverer" ref="errorMessageRecoverer"/>-->
<property name="retryOperations" ref="retryTemplate" />
</bean>
<bean id="dlqMessageRecoverer" class="com.prosper.phlconsumer.service.error.DLQMessageRecoverer" />
<bean id="retryTemplate" class="org.springframework.retry.support.RetryTemplate">
<property name="backOffPolicy">
<bean class="org.springframework.retry.backoff.ExponentialBackOffPolicy">
<property name="initialInterval" value="500000" />
<property name="maxInterval" value="12000000" />
<property name="multiplier" value="2" />
</bean>
</property>
<property name="retryPolicy">
<bean class="org.springframework.retry.policy.SimpleRetryPolicy">
<property name="maxAttempts" value="2" />
</bean>
</property>
</bean>
<rabbit:listener-container id="messageListenerContainer"
connection-factory="connectionFactory" concurrency="1" acknowledge="auto" advice-chain="retryAdvice" >
<rabbit:listener ref="listingsMessageListener" queue-names="${prosper.listing.phl.queue}" />
<rabbit:listener ref="prospectsMessageListener" queue-names="${prosper.prospect.phl.queue}" />
</rabbit:listener-container>
public class DLQMessageRecoverer implements MessageRecoverer {
#Override public void recover(Message message, Throwable cause) {
message.getMessageProperties()
.setHeader("error",cause.getMessage());
throw new AmqpRejectAndDontRequeueException(cause);
}
}
I think you should set spring.rabbitmq.listener.retry.enabled property true. By default RabbitMQ doesn't retry a failed message (assuming fail is on the consumer side).
Also AmqpRejectAndDontRequeueException is preventing your message from being requeued.

Spring WebServiceTemplate Interceptor for adding security header

I am trying to add a SOAP:Header with wss4j authentication for my outbound SOAP service.
Below is my WebServiceTemplate and interceptor configuration
<bean id="securityHeader"
class="org.springframework.ws.soap.security.wss4j.Wss4jSecurityInterceptor">
<property name="securementActions" value="UsernameToken" />
<property name="securementUsername" value="uname" />
<property name="securementPassword" value="password#123" />
<property name="securementPasswordType" value="PasswordText" />
<property name="securementUsernameTokenElements" value="Nonce Created" />
</bean>`
<bean id="webService" class="org.springframework.ws.client.core.WebServiceTemplate">
<constructor-arg ref="messageFactory" />
<property name="messageSender">
<bean
class="org.springframework.ws.transport.http.CommonsHttpMessageSender">
<!-- <property name="credentials" ref="credentials" /> -->
</bean>
</property>
<property name="interceptors">
<list>
<ref bean="securityHeader" />
</list>
</property>
<property name="defaultUri"
value="https://test.test.com/ws/service/test" />
<property name="marshaller" ref="fmarshaller" />
<property name="unmarshaller" ref="forwardunmarshaller" />
</bean>
But when the outbound call happens, its not adding the SOAP security header.webService.marshalSendAndReceive("http://localhost:8088/mockBinding",request);
Below changes did the trick for me.
Changing the SOAP version to 1.1
Defining the bean declaration inside interceptor instead of referencing it.
Use a web service message callback.

Retry mechanism using Camel and ActiveMq - Retry Policy gets ignored

I am working on a retry mechanism using camel and activeMq. What I want to do is to start a retry mechanism if one of the servers I am calling is down, add the request into my queue and from hour to hour resend it to the server. Everything works fine except my Retry Policy that seems to be ignored (my requests are resent when they get into my queue and they are never added into the DLQ after the number of retries is reached)
My configuration looks as follows (Values are readed from a .cfg file):
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">
<bean id="jmsConnectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="${activemq.broker.url}"/>
<property name="userName" value="${activemq.broker.username}"/>
<property name="password" value="${activemq.broker.password}"/>
<property name="redeliveryPolicy" ref="policy"/>
</bean>
<bean id="policy" class="org.apache.activemq.RedeliveryPolicy">
<property name="queue" value="*"/>
<property name="initialRedeliveryDelay" value="${activemq.redelivery.delay}"/>
<property name="redeliveryDelay" value="${activemq.redelivery.delay}"/>
<property name="useExponentialBackOff" value="false"/>
<property name="maximumRedeliveries" value="${activemq.number.of.redeliveries}"/>
</bean>
<bean id="pooledConnectionFactory" class="org.apache.activemq.pool.PooledConnectionFactory">
<property name="maxConnections" value="8"/>
<property name="connectionFactory" ref="jmsConnectionFactory"/>
</bean>
<bean id="jmsTransactionManager" class="org.springframework.jms.connection.JmsTransactionManager">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
</bean>
<bean id="jmsConfig" class="org.apache.camel.component.jms.JmsConfiguration">
<property name="connectionFactory" ref="pooledConnectionFactory"/>
<property name="transactionManager" ref="jmsTransactionManager"/>
<property name="transacted" value="true"/>
<property name="cacheLevelName" value="CACHE_CONSUMER"/>
<property name="concurrentConsumers" value="8"/>
</bean>
<bean id="activemq" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="configuration" ref="jmsConfig"/>
</bean>
Camel route that calls my service:
<route id="addRegistrationRoute">
<from uri="direct:addRegistrationRoute"/>
<to uri="cxf:bean:addRegistrationEndpoint"/>
<onException>
<exception>java.net.ConnectException</exception>
<onWhen>
<el>${in.headers['previousRoute'] != 'registrationRetryRoute'}</el>
</onWhen>
<handled>
<constant>true</constant>
</handled>
<setBody>
<simple>${headers.request}</simple>
</setBody>
<removeHeaders pattern="*"/>
<to uri="activemq:queue:registrationRetryQueue"/>
<stop/>
</onException>
<onException>
<exception>org.apache.cxf.interceptor.Fault</exception>
<onWhen>
<el>${in.headers['previousRoute'] != 'registrationRetryRoute'}</el>
</onWhen>
<handled>
<constant>true</constant>
</handled>
<setBody>
<simple>${headers.request}</simple>
</setBody>
<removeHeaders pattern="*"/>
<to uri="activemq:queue:registrationRetryQueue"/>
<stop/>
</onException>
<onException>
<exception>javax.xml.soap.SOAPFault</exception>
<handled>
<constant>true</constant>
</handled>
</onException>
</route>
<route id="registrationRetryRoute">
<from uri="activemq:queue:registrationRetryQueue"/>
<setHeader headerName="previousRoute">
<simple>registrationRetryRoute</simple>
</setHeader>
<to uri="direct:addRegistrationRoute"/> <!-- Back to the initial flow. -->
</route>
If somebody can please tell me what I have did wrong in configuring activeMq I will be really thankful!
Regards,
Roxana
ActiveMQ pushes messages into DLQ only if you are throwing an error from your consumers (or message listeners). So try to catch your exception and throw it back so that retry policy will be enabled accordingly.

PayloadValidatingInterceptor - validate only concrete wsdl

I have one Spring WS servlet with two endpoints and two wsdl files. Requests/responses are being validated with PayloadValidatingInterceptor. Content of spring-ws-servlet.xml:
<context:component-scan base-package="cz.legend.mzv.spi.ws.ei.endpoints" />
<context:component-scan base-package="cz.legend.mzv.spi.ws.de.endpoints" />
<sws:annotation-driven />
<sws:static-wsdl id="entityImport" location="classpath:/wsdl/entityImport.wsdl" />
<sws:static-wsdl id="documentEvidence"
location="classpath:/wsdl/documentEvidence.wsdl" />
<oxm:jaxb2-marshaller id="jaxb2Marshaller"
contextPath="cz.legend.mzv.spi.ws.jaxb.generated" />
<bean id="endpointAdapter" class="org.springframework.ws.server.endpoint.adapter.MarshallingMethodEndpointAdapter">
<constructor-arg ref="jaxb2Marshaller" />
</bean>
<sws:interceptors>
<bean
class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">
<property name="schema" value="classpath:/xsd/vums_spi_de.xsd" />
<property name="validateRequest" value="true" />
<property name="validateResponse" value="true" />
</bean>
</sws:interceptors>
Interceptor is applied on both services. I need the interceptor to be applied only on service described by documentEvidence.wsdl. One option is to make two separate spring servlets. But I want to use only one servlet.
Solution:
Alternatively, you can use or
elements to specify for which payload root name or SOAP action the
interceptor should apply:
<sws:interceptors>
<bean class="samples.MyGlobalInterceptor"/>
<sws:payloadRoot namespaceUri="http://www.example.com">
<bean class="samples.MyPayloadRootInterceptor"/>
</sws:payloadRoot>
<sws:soapAction value="http://www.example.com/SoapAction">
<bean class="samples.MySoapActionInterceptor1"/>
<ref bean="mySoapActionInterceptor2"/>
</sws:soapAction>
</sws:interceptors>

Resources