How to propogate an exception from tcp outbound gateway to upstream SI components - spring

I have been searching over the internet and have been trying different ways to make it work but I couldn't get it working.
Actually my system need to connect to multiple tcp server endpoints (which we call payers endpoint) as a tcp client application. The client components include the throttling and queuing components and they get initialized dynamically based on the payers configurations stored in DB as a separate application context. I have created a tcp outbound gateway for this purpose and which is being initialized in a dynamic context based on the ideas given in
https://github.com/spring-projects/spring-integration-samples/tree/master/advanced
What I want is to catch/get exceptions to the calling code at the time calling the payersGateway component in case of any error. But I am unable to receive the exceptions back.
My context file for tcp client connectivity is as follow:
dynamic-tcp-gateway-context file
<context:property-placeholder/>
<int-ip:tcp-connection-factory id="client"
type="client"
host="${host}"
port="${port}"
single-use="true"
so-timeout="${soTimeout}"
serializer="byteArrayLfSerializer"
deserializer="ediTcpSerializer"
/>
<bean id="ediTcpSerializer" class="com.abc.throttling.EdiTcpSerializer">
<property name="maxMessageSize" value="20480000"/>
</bean>
<bean id="byteArrayLfSerializer" class="org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer">
<property name="maxMessageSize" value="20480000"/>
</bean>
<int:channel id="toPayerChannel">
<int:dispatcher task-executor="producerThreadExecutor"/>
</int:channel>
<task:executor id="producerThreadExecutor" pool-size="10" queue-capacity="50" rejection-policy="ABORT"/>
<int:channel id="throttlerChannel">
<int:priority-queue capacity="${queueSize:1000}"/> <!-- for example queue size, you can increase this capacity
based on your
requirement -->
</int:channel>
<int:bridge input-channel="toPayerChannel" output-channel="throttlerChannel" />
<int-ip:tcp-outbound-gateway id="outGateway"
request-channel="throttlerChannel"
connection-factory="client"
request-timeout="10000"
reply-timeout="${replyTimeout}">
<int:poller id="tcpPoller" error-channel="errorChannel" fixed-rate="1000" max-messages-per-poll="${messageRate:20}"/>
</int-ip:tcp-outbound-gateway>
<int:transformer input-channel="errorChannel"
ref="exceptionTransformer" method="createErrorResponse"/>
<bean id="exceptionTransformer" class="com.stella.healthenet.throttling.TcpGatewayExceptionTransformer"/>
<int:object-to-string-transformer input-channel="errorChannel"/>
application context for main payers connectivity is as follow:
main-payers-gateway-context file
<context:component-scan base-package="com.abc.throttling" />
class="com.abc.throttling.DynamicTcpChannelResolverTest" id="dynamicTcpChannelResolverTest"/>-->
<int:gateway id="payersGateway"
service-interface="com.abc.gateway.PayersGateway"
default-request-channel="toDynRouter"
default-request-timeout="1000000"
default-reply-timeout="${payersGateway.defaultReplyTimout}"
/>
<int:converter ref="converter"/>
<bean class="com.abc.manager.edi.core.core4.ByteArrayToStringConverter" id="converter"/>
<int:converter ref="converter2"/>
<bean class="com.abc.manager.edi.core.core2.Core2RealTimeResponseToString" id="converter2"/>
<int:converter ref="converter3"/>
<bean class="com.abc.manager.edi.core.core4.Core4RealTimeResponseToString" id="converter3"/>
<int:channel id="toDynRouter" />
<int:router resolution-required="true" input-channel="toDynRouter"
expression="#dynamicPayerChannelResolver.resolve(headers['payer'])" >
</int:router>
The code for dynamic channel resolver is as follow:
#Component("dynamicPayerChannelResolver")
public class DynamicPayerChannelResolver {
#Value("${throttling.payersChannelQueueSize}")
private String payersChannelQueueSize;
#Value("${throttling.tcpSoTimeout}")
private String tcpSoTimeout;
#Value("${tcpOutboundGateway.replyTimeout}")
private String tcpReplyTimeout;
#Autowired
private ApplicationContext applicationContext;
public static final int MAX_CACHE_SIZE = 30;
private static final org.apache.logging.log4j.Logger LOG = LogManager.getLogger();
#Autowired
PayerRepositoryService payerRepositoryService;
private final Map<UUID, MessageChannel> channels = Collections.synchronizedMap(new LinkedHashMap<UUID,
MessageChannel>(){
private static final long serialVersionUID = 1L;
#Override
protected boolean removeEldestEntry(
Entry<UUID, MessageChannel> eldest) {
//This returning true means the least recently used
//channel and its application context will be closed and removed
boolean remove = size() > MAX_CACHE_SIZE;
if(remove) {
MessageChannel channel = eldest.getValue();
ConfigurableApplicationContext ctx = contexts.get(channel);
if(ctx != null) { //shouldn't be null ideally
ctx.close();
contexts.remove(channel);
}
}
return remove;
}
});
private final Map<MessageChannel, ConfigurableApplicationContext> contexts =
new HashMap<MessageChannel, ConfigurableApplicationContext>();
/**
* Resolve a payer to a channel, where each payer gets a private
* application context and the channel is the inbound channel to that
* application context.
*
* #param payer
* #return a channel
*/
public MessageChannel resolve(UUID payer) {
MessageChannel channel = this.channels.get(payer);
if (channel == null) {
channel = createNewPayerChannel(payerRepositoryService.findPayerByPayerId(payer));
}
return channel;
}
private synchronized MessageChannel createNewPayerChannel(PayerEntity payer) {
MessageChannel channel = this.channels.get(payer.getPayerId());
if (channel == null) {
ConfigurableApplicationContext ctx;
if(TransportType.SOAP_WSDL.getValue().equals(payer.getConnTransportType())){
ctx = new ClassPathXmlApplicationContext(
new String[] { "dynamic-soap-gateway-context.xml" },
false,applicationContext);
}
else{
ctx = new ClassPathXmlApplicationContext(
new String[] { "dynamic-tcp-gateway-context.xml" },
false,applicationContext);
}
this.setEnvironmentForPayer(ctx, payer);
ctx.refresh();
channel = ctx.getBean("toPayerChannel", MessageChannel.class);
this.channels.put(payer.getPayerId(), channel);
//Will works as the same reference is presented always
this.contexts.put(channel, ctx);
}
return channel;
}
public void updatePollerConfigs() {
Iterator it = this.channels.entrySet().iterator();
while(it.hasNext()){
Map.Entry pair = (Map.Entry)it.next();
PayerEntity payer = this.payerRepositoryService.findPayerByPayerId((UUID)pair.getKey());
final String transportType = payer.getConnTransportType();
if(TransportType.SOAP_WSDL.getValue().equals(transportType)){
MessageChannel channel= this.channels.get(payer);
ConfigurableApplicationContext ctx;
ctx=this.contexts.get(channel);
PollingConsumer pc = ctx.getBean("soapPoller",PollingConsumer.class);
//TODO: this value need to be set from payer configs in db.
pc.setMaxMessagesPerPoll(10);
}
else if (TransportType.X12_SOCKET.getValue().equals(transportType)) {
MessageChannel channel= this.channels.get(payer);
ConfigurableApplicationContext ctx;
ctx=this.contexts.get(channel);
PollingConsumer pc = ctx.getBean("outGateway",PollingConsumer.class);
//TODO: this value need to be set from payer configs in db.
pc.setMaxMessagesPerPoll(10);
}
}
}
private void setEnvironmentForPayer(ConfigurableApplicationContext ctx,
PayerEntity payer) {
final String transportType = payer.getConnTransportType();
final String endPoint = payer.getConnEndPoint();
if(payer.getMessageRate()==null){
throw new NullPointerException("MessageRate value is NULL in DB. Please specify a MessageRate value in " +
"Payers DB for PayerID: " + payer.getPayerId());
}
final String messageRate = payer.getMessageRate();
StandardEnvironment env = new StandardEnvironment();
Properties props = new Properties();
// populate properties for payer
;
if(TransportType.SOAP_WSDL.getValue().equals(transportType)){
props.setProperty("endpoint", endPoint);
props.setProperty("messageRate",messageRate);
props.setProperty("queueSize",payersChannelQueueSize);
}
else if (TransportType.X12_SOCKET.getValue().equals(transportType)) {
if (!endPoint.contains(":")) {
throw new Exception(ErrorType.UNEXPECTED, "Payer X12 Socket endpoint must include a port.");
}
final String ip;
if (endPoint.contains("/")) {
ip = endPoint.substring(endPoint.lastIndexOf('/') + 1, endPoint.lastIndexOf(":"));
} else {
ip = endPoint.substring(0, endPoint.lastIndexOf(":"));
}
final String port = endPoint.substring(endPoint.lastIndexOf(':') + 1);
props.setProperty("host", ip);
props.setProperty("port", port);
props.setProperty("messageRate",messageRate);
props.setProperty("queueSize",payersChannelQueueSize);
props.setProperty("soTimeout", tcpSoTimeout);
props.setProperty("replyTimeout",tcpReplyTimeout);
}
PropertiesPropertySource pps = new PropertiesPropertySource("payerChannelProps", props);
env.getPropertySources().addLast(pps);
ctx.setEnvironment(env);
}
I want to get the exceptions generated at the downstream components to appear at the payersGateway interface send method call i.e., shown below:
String response = payersGateway.send(
MessageBuilder.withPayload(requestMessage)
.setHeader("endpointUrl", endPoint)
.setHeader("senderId", coreSenderId)
.setHeader("receiverId", payerIdCode)
.setHeader("username", username)
.setHeader("password", password)
.setHeader("payloadType", payloadType)
.setHeader("nginxUrl", nginxUrl)
.setHeader("payer", payerId)
.setHeader("transType", transType)
.setHeader("priority", 1)
.build());
where the payersGateway is simple interface pointing to Gateway component in main context file.
public interface PayersGateway {
public String send(Message<String> message);
}
Please see the stack trace of produced exception as below:
[task-scheduler-1] ERROR org.springframework.integration.ip.tcp.TcpOutboundGateway - Tcp Gateway exception
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at java.net.Socket.<init>(Socket.java:434)
at java.net.Socket.<init>(Socket.java:211)
at javax.net.DefaultSocketFactory.createSocket(SocketFactory.java:271)
at org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.createSocket(TcpNetClientConnectionFactory.java:76)
at org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.buildNewConnection(TcpNetClientConnectionFactory.java:49)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.obtainNewConnection(AbstractClientConnectionFactory.java:116)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.obtainConnection(AbstractClientConnectionFactory.java:79)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.getConnection(AbstractClientConnectionFactory.java:69)
at org.springframework.integration.ip.tcp.TcpOutboundGateway.handleRequestMessage(TcpOutboundGateway.java:130)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
at org.springframework.integration.endpoint.PollingConsumer.handleMessage(PollingConsumer.java:129)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:272)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.access$000(AbstractPollingEndpoint.java:58)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:190)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:186)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller$1.run(AbstractPollingEndpoint.java:353)
at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:55)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:51)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:344)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
[task-scheduler-1] ERROR org.springframework.integration.handler.LoggingHandler - org.springframework.messaging.MessagingException: Failed to send or receive; nested exception is java.net.ConnectException: Connection refused (Connection refused)
at org.springframework.integration.ip.tcp.TcpOutboundGateway.handleRequestMessage(TcpOutboundGateway.java:158)
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:109)
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:127)
at org.springframework.integration.endpoint.PollingConsumer.handleMessage(PollingConsumer.java:129)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.doPoll(AbstractPollingEndpoint.java:272)
at org.springframework.integration.endpoint.AbstractPollingEndpoint.access$000(AbstractPollingEndpoint.java:58)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:190)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$1.call(AbstractPollingEndpoint.java:186)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller$1.run(AbstractPollingEndpoint.java:353)
at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:55)
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50)
at org.springframework.integration.util.ErrorHandlingTaskExecutor.execute(ErrorHandlingTaskExecutor.java:51)
at org.springframework.integration.endpoint.AbstractPollingEndpoint$Poller.run(AbstractPollingEndpoint.java:344)
at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54)
at org.springframework.scheduling.concurrent.ReschedulingRunnable.run(ReschedulingRunnable.java:81)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$201(ScheduledThreadPoolExecutor.java:180)
at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:293)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
Caused by: java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at java.net.Socket.connect(Socket.java:538)
at java.net.Socket.<init>(Socket.java:434)
at java.net.Socket.<init>(Socket.java:211)
at javax.net.DefaultSocketFactory.createSocket(SocketFactory.java:271)
at org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.createSocket(TcpNetClientConnectionFactory.java:76)
at org.springframework.integration.ip.tcp.connection.TcpNetClientConnectionFactory.buildNewConnection(TcpNetClientConnectionFactory.java:49)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.obtainNewConnection(AbstractClientConnectionFactory.java:116)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.obtainConnection(AbstractClientConnectionFactory.java:79)
at org.springframework.integration.ip.tcp.connection.AbstractClientConnectionFactory.getConnection(AbstractClientConnectionFactory.java:69)
at org.springframework.integration.ip.tcp.TcpOutboundGateway.handleRequestMessage(TcpOutboundGateway.java:130)
... 21 more

It should work as you need; exceptions before the throttlerChannel will be thrown directly to the caller; exceptions after that channel will be sent to the gateway by the poller's error handler.
Perhaps your gateway timeout is too short?
Turning on DEBUG logging and following the message flow should help you debug it.
EDIT
You can fix the missing failedMessage by adding a bean of this type to the Tcp outbound gateway's <int-ip:request-handler-advice-chain />...
public class FailedMessagePopulator extends AbstractRequestHandlerAdvice {
#Override
protected Object doInvoke(ExecutionCallback callback, Object target, Message<?> message) throws Exception {
try {
return callback.execute();
}
catch (MessagingException e) {
if (e.getFailedMessage() == null) {
throw new MessageHandlingException(message, e.getMessage(), e);
}
else {
throw e;
}
}
catch (Exception e) {
throw new MessageHandlingException(message, e.getMessage(), e);
}
}
}
Note that you will need to add the error channel to the <gateway/> since the poller will now see the failed message and send the exception back to the gateway for error handling.

Related

Spring integration / GCP PubSub : channel subscriber lost

Everything is mostly in the title.
I have a specific channel to send data to PubSub, using Spring integration and this information about GCP PubSub
I don't have any problem locally, or on the QA env.
But, in the prod, I have the following error :
org.springframework.messaging.MessageDeliveryException: failed to send Message to channel
'pubSubFlow.channel#1'; nested exception is java.lang.IllegalStateException: The [bean
'pubSubFlow.channel#1'; defined in: 'class path resource [fr/auchan/lark/tracking/api/v1
/pubsub/PubSubRequestIntegration.class]'; from source: 'bean method pubSubFlow'] doesn't
have subscribers to accept messages
org.springframework.integration.support.utils.IntegrationUtils.wrapInDeliveryExceptionIfNecessary(IntegrationUtils.java:167) ~[spring-integration-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:600) ~[spring-integration-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:520) ~[spring-integration-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
org.springframework.integration.channel.FluxMessageChannel.lambda$subscribeTo$2(FluxMessageChannel.java:83) ~[spring-integration-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
reactor.core.publisher.FluxPeekFuseable$PeekFuseableSubscriber.onNext(FluxPeekFuseable.java:189) ~[reactor-core-3.3.13.RELEASE.jar:3.3.13.RELEASE]
reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.runAsync(FluxPublishOn.java:439) ~[reactor-core-3.3.13.RELEASE.jar:3.3.13.RELEASE]
reactor.core.publisher.FluxPublishOn$PublishOnSubscriber.run(FluxPublishOn.java:526) ~[reactor-core-3.3.13.RELEASE.jar:3.3.13.RELEASE]
reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84) ~[reactor-core-3.3.13.RELEASE.jar:3.3.13.RELEASE]
reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37) ~[reactor-core-3.3.13.RELEASE.jar:3.3.13.RELEASE]
java.base/java.util.concurrent.FutureTask.run(Unknown Source) ~[na:na]
java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(Unknown Source) ~[na:na]
java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source) ~[na:na]
java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source) ~[na:na]
java.base/java.lang.Thread.run(Unknown Source) ~[na:na]
Caused by: java.lang.IllegalStateException: The [bean 'pubSubFlow.channel#1'; defined in: 'class path resource [PubSubRequestIntegration.class]'; from source: 'bean method pubSubFlow'] doesn't have subscribers to accept messages
org.springframework.util.Assert.state(Assert.java:97) ~[spring-core-5.2.12.RELEASE.jar:5.2.12.RELEASE]
org.springframework.integration.channel.FluxMessageChannel.doSend(FluxMessageChannel.java:61) ~[spring-integration-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
org.springframework.integration.channel.AbstractMessageChannel.send(AbstractMessageChannel.java:570) ~[spring-integration-core-5.3.5.RELEASE.jar:5.3.5.RELEASE]
12 common frames omitted
Below is my channel declaration, and the use of ServiceActivator as written is the PubSub Guidelines (see the link above).
#Bean
public MessageChannel dataChannel() {
return MessageChannels.publishSubscribe(Executors.newCachedThreadPool()).get();
}
#Bean
public MessageChannel pubSubChannel() {
return MessageChannels.publishSubscribe(Executors.newCachedThreadPool()).get();
}
#Bean
public IntegrationFlow pubSubFlow(
MessageChannel dataChannel,
MessageChannel pubSubChannel) {
return IntegrationFlows
.from(dataChannel)
.fluxTransform(this::toPubSubFormat)
.channel(pubSubChannel)
.get();
}
#Bean
#ServiceActivator(inputChannel = "pubSubChannel")
public PubSubMessageHandler sendToPubSub(PubSubTemplate pubSubTemplate) {
PubSubMessageHandler adapter = new PubSubMessageHandler(pubSubTemplate,
pubSubIntegrationProperties.getTopic());
adapter.setPublishCallback(
new ListenableFutureCallback<>() {
#Override
public void onFailure(Throwable throwable) {
log.warn("There was the following error sending the message. " + throwable);
}
#Override
public void onSuccess(String result) {
log.debug("Message was sent via the outbound channel adapter to {} : {}", pubSubIntegrationProperties.getTopic(), result);
}
});
return adapter;
}
Did I miss something? Why is the pubSubChannel marked as having no subscribers?
Thanks for the help

Spring Integration Headers are not getting injected to Service Activator POJO

Spring Integration Headers are not getting injected to Service Activator POJO.This happens only at the time of load testing (with less than 10 tps).
Normal flow its is working as expected.
Spring integration flow is
Splitter -> executor channel -> service activator -> aggregator.
SI version 4.1.2.RELEASE
Spring Version 4.1.2.RELEASE
Java version 1.8.0_60
//service activator -Method
public ProductDetail getProductDetails(final String productID,
#Header(STATS) final Stats statsType,
#Header(SKU) final String sku,
#Header(PRODUCT_LIST) final Collection<String> productList,
#Header(NO_OF_PRODUCTS) final String size)
final MessageBuilder<Map<String, Object>> msgBuilder = MessageBuilder
.withPayload(payload);//Map<String, Object> payload
this.addMessageHeaders(msgBuilder, httpHeadersMap, statsType);
private final boolean addMessageHeaders(MessageBuilder<?> msgBuilder,
final Map<String, String> httpHeadersMap, final Stats statsType) {
if ((httpHeadersMap != null) && (httpHeadersMap.size() > 0)) {
for (Map.Entry<String, String> entry : httpHeadersMap.entrySet()) {
msgBuilder.setHeader(entry.getKey(), entry.getValue());
}
}
if (statsType != null) {
msgBuilder.setHeader(STATS, statsType);
}
return true;
}
org.springframework.messaging.MessageHandlingException: nested exception is java.lang.IllegalArgumentException: required header not available: STATS
at org.springframework.integration.handler.MethodInvokingMessageProcessor.processMessage(MethodInvokingMessageProcessor.java:78) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.handler.ServiceActivatingHandler.handleRequestMessage(ServiceActivatingHandler.java:71) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.handler.AbstractReplyProducingMessageHandler.handleMessageInternal(AbstractReplyProducingMessageHandler.java:99) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.handler.AbstractMessageHandler.handleMessage(AbstractMessageHandler.java:78) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.dispatcher.AbstractDispatcher.tryOptimizedDispatch(AbstractDispatcher.java:116) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.dispatcher.UnicastingDispatcher.doDispatch(UnicastingDispatcher.java:101) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.dispatcher.UnicastingDispatcher.access$000(UnicastingDispatcher.java:48) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.dispatcher.UnicastingDispatcher$1.run(UnicastingDispatcher.java:92) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at org.springframework.integration.util.ErrorHandlingTaskExecutor$1.run(ErrorHandlingTaskExecutor.java:52) ~[spring-integration-core-4.1.2.RELEASE.jar:na]
at xx.run(DelegatingContextRunnable.java:40) ~[xx-core-3.xx.jar:3.24.0.52]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) ~[na:1.8.0_60]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) ~[na:1.8.0_60]
at java.lang.Thread.run(Thread.java:745) ~[na:1.8.0_60]
Caused by: java.lang.IllegalArgumentException: required header not available: STATS
at org.springframework.util.Assert.isTrue(Assert.java:68) ~[spring-core-4.2.2.RELEASE.jar:4.2.2.RELEASE]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_60]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_60]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_60]
at java.lang.reflect.Method.invoke(Method.java:497) ~[na:1.8.0_60]
<int:channel id="retrieve-product.in" />
<int:channel id="retrieve-product.out" />
<int:channel id="retrieve-product.err" />
<int:channel id="retrieve-product.splitter.in"/>
<int:channel id="retrieve-product.sa.in">
<int:dispatcher task-executor="testExecutor" failover="false"/>
</int:channel>
<int:channel id="retrieve-product.aggregator.in"/>
<int:channel id="retrieve-product.transformer.in"/>
<bean id="retrieveProductsServiceActivatorSupport" class="com.test.eip.serviceactivator.support.RetrieveProductsServiceActivatorSupport" />
<bean id="retrieveProductsServiceActivator" class="com.test.eip.serviceactivator.RetrieveProductsServiceActivator" />
<bean id="retrieveProductsAggregator" class="com.test.eip.aggregator.RetrieveProductsAggregator" />
<bean id="retrieveProductResponseTransformer" class="com.test.eip.transformer.RetrieveProductsResponseTransformer" />
<bean id="productGroupsConfig" class="com.test.support.ProductGroupsConfig" >
<constructor-arg index="0" value="ProductMapping.xml" />
</bean>
<bean id="payloadSizeBasedReleaseStrategy" class="com.test.eip.aggregator.support.PayloadSizeBasedReleaseStrategy" />
<oxm:jaxb2-marshaller id="productConfigJaxbMarshaller" context-path="com.test.product.config.types" />
<int:gateway id="retrieveProductsGateway" service-interface="com.test.eip.gateway.IProductGateway" error-channel ="retrieve-product.err">
<int:method name="getProductsResponse" request-channel="retrieve-product.in" reply-channel="retrieve-product.out" />
</int:gateway>
<int:header-enricher input-channel="retrieve-product.in" output-channel="retrieve-product.splitter.in">
<int:header name="API_NAME" value="retrieve-product" />
</int:header-enricher>
<!-- Input List<String> contain product numbers -->
<int:splitter id="productListSplitter" input-channel="retrieve-product.splitter.in"
output-channel="retrieve-product.sa.in"></int:splitter>
<!-- Retrieve Product Features from USING API -->
<int:service-activator input-channel="retrieve-product.sa.in"
ref="retrieveProductsServiceActivator" method="getProductDetails"
output-channel="retrieve-product.aggregator.in"
id="retrieve-product-service-activator" />
<!-- Aggregate result from Parallel Call -->
<int:aggregator input-channel="retrieve-product.aggregator.in"
output-channel="retrieve-product.transformer.in"
method="aggregateProductDetails" ref="retrieveProductsAggregator"
release-strategy="payloadSizeBasedReleaseStrategy"
release-strategy-method="canRelease">
</int:aggregator>
<!-- Generate Service Response-->
<int:transformer id="retrieve-product-ResponseTransformer" method="transform"
ref="retrieveProductResponseTransformer" input-channel="retrieve-product.transformer.in" output-channel="retrieve-product.out" />
<!--
Listen for error and generate response
-->
<int:service-activator input-channel="retrieve-product.err"
ref="testErrorHandler" method="handleExceptions"
output-channel="retrieve-product.out"
id="retrieve-product-err-handler" />
public interface IProductGateway {
public RetrieveProductsResponse getProductsResponse(Message<?> inputMessage);
}
//Service
#Service
public class ProductsService implements IProductsService {
#Autowired
private IProductGateway retrieveProductsGateway;
#Override
public RetrieveProductsResponse getProductsResponse(
final RetrieveProductsRequest retrieveProductsRequest,
final Map<String, String> httpHeadersMap, final Stats statsType) {
final ProductsReqType products = retrieveProductsRequest.getProducts();
//populate productList From products
final Collection<String> productList = new HashSet<>();
httpHeadersMap.put(SKU, retrieveProductsRequest.getSKU());
httpHeadersMap.put(NO_OF_PRODUCTS,
String.valueOf(productList.size()));
final MessageBuilder<Collection<String>> msgBuilder = MessageBuilder
.withPayload(productList)
.setHeader(PRODUCT_LIST, new HashSet<>(productList));
this.addMessageHeaders(msgBuilder, httpHeadersMap, statsType);
final Message<Collection<String>> inMsg = msgBuilder.build();
LOG.debug("retrieveProductsGateway:: {}", this.retrieveProductsGateway);
final RetrieveProductsResponse retrieveProductsResponse = this.retrieveProductsGateway
.getProductsResponse(inMsg);
return retrieveProductsResponse;
}
}
//Jersey Filter is creating Stats setting it to requestContext( javax.ws.rs.container.ContainerRequestFilter)
/* Request Filter Creating and setting statsType
*/
#Override
public void filter(final ContainerRequestContext requestContext) throws IOException {
LOG.debug("filter(requestContext)::Entry");
final Stats statsType = STATS_OBJ_FACTORY.createStats();
final MultivaluedMap<String, String> headers = requestContext.getHeaders();
statsType.setBegin(DT_FACTORY.newXMLGregorianCalendar(new GregorianCalendar()));
requestContext.setProperty(STATS, statsType);
LOG.debug("filter(requestContext)::Exit");
}
//Resource Method taking statsType and passing to ProductsService
/*javax.ws.rs.core.Context*/
#POST
#Path("retrieve-product")
#Produces(MyMediaType.PD_XML_MEDIA_TYPE)
#Consumes(MyMediaType.PD_XML_MEDIA_TYPE)
public Response getProducts(RetrieveProductsRequest retrieveProductsRequest,
#Context final ContainerRequestContext containerRequestContext,
#Context final HttpHeaders headers) {
LOG.debug("getProducts::Entry");
final Stats statsType = (Stats) containerRequestContext
.getProperty(STATS);
final Map<String, String> httpHeadersMap = ResourceHelper
.getHttpHeadersAsMap(headers);
final RetrieveProductsResponse retrieveProductsResponse = this.productsService
.getProductsResponse(retrieveProductsRequest, httpHeadersMap, statsType);
LOG.debug("getProducts::Exit");
return Response.ok(retrieveProductsResponse).build();
}
Thanks,
required header not available: STATS
Simply means that whatever is upstream that creates the message is not populating the headers; you need to show all your configuration (and possibly code). DEBUG logging and following the messages will generally help debugging such conditions.
A common mistake is a lack of thread-safety - such as in your splitter.

Writing java based JMS Client for WildFly10

I writing java based JMS Client for WildFly10 and I had problem
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
props.put(Context.PROVIDER_URL, WILDFLY_REMOTING_URL); // NOTICE: "http- remoting" and port "8080"
props.put(Context.SECURITY_PRINCIPAL, JMS_USERNAME);
props.put(Context.SECURITY_CREDENTIALS, JMS_PASSWORD);
//props.put("jboss.naming.client.ejb.context", true);
context = new InitialContext(props);
i run your client code and i got this error:
Got initial Context: javax.naming.InitialContext#5442a311
Exception in thread “main” org.jboss.naming.remote.protocol.NamingIOException: Failed to lookup [Root exception is java.io.IOException: java.lang.ClassNotFoundException: org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory]
at org.jboss.naming.remote.client.ClientUtil.namingException(ClientUtil.java:49)
at org.jboss.naming.remote.protocol.v1.Protocol$1.execute(Protocol.java:104)
at org.jboss.naming.remote.protocol.v1.RemoteNamingStoreV1.lookup(RemoteNamingStoreV1.java:95)
at org.jboss.naming.remote.client.HaRemoteNamingStore$1.operation(HaRemoteNamingStore.java:276)
at org.jboss.naming.remote.client.HaRemoteNamingStore.namingOperation(HaRemoteNamingStore.java:137)
at org.jboss.naming.remote.client.HaRemoteNamingStore.lookup(HaRemoteNamingStore.java:272)
at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:87)
at org.jboss.naming.remote.client.RemoteContext.lookup(RemoteContext.java:129)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at com.almasprocess.model.bl.WildFlyJmsQueueSender.init(WildFlyJmsQueueSender.java:49)
at com.almasprocess.model.bl.WildFlyJmsQueueSender.main(WildFlyJmsQueueSender.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.io.IOException: java.lang.ClassNotFoundException: org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory
at org.jboss.naming.remote.protocol.v1.Protocol$1$3.read(Protocol.java:159)
at org.jboss.naming.remote.protocol.v1.Protocol$1$3.read(Protocol.java:149)
at org.jboss.naming.remote.protocol.v1.BaseProtocolCommand.readResult(BaseProtocolCommand.java:59)
at org.jboss.naming.remote.protocol.v1.Protocol$1.handleClientMessage(Protocol.java:149)
at org.jboss.naming.remote.protocol.v1.RemoteNamingStoreV1$MessageReceiver$1.run(RemoteNamingStoreV1.java:232)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.ClassNotFoundException: org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory
at java.net.URLClassLoader$1.run(URLClassLoader.java:372)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:360)
at java.lang.ClassLoader.loadClass(ClassLoader.java:424)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:357)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:340)
at org.jboss.marshalling.AbstractClassResolver.loadClass(AbstractClassResolver.java:131)
at org.jboss.marshalling.AbstractClassResolver.resolveClass(AbstractClassResolver.java:112)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadClassDescriptor(RiverUnmarshaller.java:1002)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadNewObject(RiverUnmarshaller.java:1256)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:276)
at org.jboss.marshalling.river.RiverUnmarshaller.doReadObject(RiverUnmarshaller.java:209)
at org.jboss.marshalling.AbstractObjectInput.readObject(AbstractObjectInput.java:41)
at org.jboss.naming.remote.protocol.v1.Protocol$1$3.read(Protocol.java:156)
… 7 more
Process finished with exit code 1
And I changed code like this and add activemq lib in my project:
Properties props = new Properties();
props.put(Context.INITIAL_CONTEXT_FACTORY,"org.apache.activemq.jndi.ActiveMQInitialContextFactory");
props.put(Context.PROVIDER_URL, WILDFLY_REMOTING_URL); // NOTICE: "http-remoting" and port "8080"
props.put(Context.SECURITY_PRINCIPAL, JMS_USERNAME);
props.put(Context.SECURITY_CREDENTIALS, JMS_PASSWORD);
and i got this error :
Got initial Context: javax.naming.InitialContext#6842775d
Exception in thread "main" javax.naming.NameNotFoundException: jms/RemoteConnectionFactory
at org.apache.activemq.jndi.ReadOnlyContext.lookup(ReadOnlyContext.java:225)
at javax.naming.InitialContext.lookup(InitialContext.java:417)
at com.almasprocess.model.bl.WildFlyJmsQueueSender.init(WildFlyJmsQueueSender.java:49)
at com.almasprocess.model.bl.WildFlyJmsQueueSender.main(WildFlyJmsQueueSender.java:43)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
and standalone-full.xml config file like this :
<subsystem xmlns="urn:jboss:domain:messaging-activemq:1.0">
<server name="default">
<security-setting name="#">
<role name="guest" send="true" consume="true" create-non-durable-queue="true" delete-non-durable-queue="true"/>
</security-setting>
<address-setting name="#" dead-letter-address="jms.queue.DLQ" expiry-address="jms.queue.ExpiryQueue" max-size-bytes="10485760" page-size-bytes="2097152" message-counter-history-day-limit="10"/>
<http-connector name="http-connector" socket-binding="http" endpoint="http-acceptor"/>
<http-connector name="http-connector-throughput" socket-binding="http" endpoint="http-acceptor-throughput">
<param name="batch-delay" value="50"/>
</http-connector>
<in-vm-connector name="in-vm" server-id="0"/>
<http-acceptor name="http-acceptor" http-listener="default"/>
<http-acceptor name="http-acceptor-throughput" http-listener="default">
<param name="batch-delay" value="50"/>
<param name="direct-deliver" value="false"/>
</http-acceptor>
<in-vm-acceptor name="in-vm" server-id="0"/>
<jms-queue name="ExpiryQueue" entries="java:/jms/queue/ExpiryQueue"/>
<jms-queue name="DLQ" entries="java:/jms/queue/DLQ"/>
<jms-queue name="clickQueue" entries="java:/jms/queue/clickQueue java:/jboss/exported/jms/queue/clickQueue"/>
<jms-queue name="emailQueue" entries="java:/jms/queue/EmailQueue java:/jboss/exported/jms/queue/EmailQueue"/>
<jms-queue name="emailSendQueue" entries="java:/jboss/exported/jms/queue/EmailSendQueue"/>
<connection-factory name="InVmConnectionFactory" entries="java:/ConnectionFactory" connectors="in-vm"/>
<connection-factory name="RemoteConnectionFactory" entries="java:jboss/exported/jms/RemoteConnectionFactory" connectors="http-connector"/>
<pooled-connection-factory name="activemq-ra" entries="java:/JmsXA java:jboss/DefaultJMSConnectionFactory" connectors="in-vm" transaction="xa"/>
</server>
</subsystem>
can you help me about error???
thanks.
Working example:
public class JMSClient {
private static final String INITIAL_CONTEXT_FACTORY = "org.jboss.naming.remote.client.InitialContextFactory";
private static final String PROVIDER_URL = "http-remoting://127.0.0.1:8080";
private static final String CONNECTION_FACTORY = "jms/RemoteConnectionFactory";
private static final String DESTINATION = "topic/irisWebBroadcaster";
private static final String USERNAME = "jmsuser";
private static final String PASSWORD = "qqq";
public static void main(String[] args) {
Context namingContext = null;
JMSContext context = null;
try {
final Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, INITIAL_CONTEXT_FACTORY);
env.put(Context.PROVIDER_URL, PROVIDER_URL);
env.put(Context.SECURITY_PRINCIPAL, USERNAME);
env.put(Context.SECURITY_CREDENTIALS, PASSWORD);
namingContext = new InitialContext(env);
ConnectionFactory connectionFactory = (ConnectionFactory) namingContext.lookup(CONNECTION_FACTORY);
Destination destination = (Destination) namingContext.lookup(DESTINATION);
context = connectionFactory.createContext(USERNAME, PASSWORD);
JMSProducer producer = context.createProducer();
producer.send(destination, "TEST");
} catch (Exception e) {
// print error messge
} finally {
if (namingContext != null) {
try {
namingContext.close();
} catch (NamingException e) {
// print error messge
}
}
if (context != null) {
context.close();
}
}
}
}
Corresponding classpath (maybe excessive):
[WILDFLY10_DIR]/modules/system/layers/base/javax/annotation/api/main/jboss-annotations-api_1.2_spec-1.0.0.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/javax/servlet/api/main/jboss-servlet-api_3.1_spec-1.0.0.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/javax/ejb/api/main/jboss-ejb-api_3.2_spec-1.0.0.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/javax/enterprise/api/main/cdi-api-1.2.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/log4j/logmanager/main/log4j-jboss-logmanager-1.1.2.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/javax/inject/api/main/javax.inject-1.jar
[WILDFLY10_DIR]/modules/system/layers/base/javax/ws/rs/api/main/jboss-jaxrs-api_2.0_spec-1.0.0.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/javax/jms/api/main/jboss-jms-api_2.0_spec-1.0.0.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/codehaus/jackson/jackson-core-asl/main/jackson-core-asl-1.9.13.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/codehaus/jackson/jackson-mapper-asl/main/jackson-mapper-asl-1.9.13.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/logging/main/jboss-logging-3.3.0.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/logmanager/main/jboss-logmanager-2.0.3.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/remote-naming/main/jboss-remote-naming-2.0.4.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/xnio/main/xnio-api-3.3.4.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/xnio/nio/main/xnio-nio-3.3.4.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/remoting/main/jboss-remoting-4.0.18.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/marshalling/main/jboss-marshalling-1.4.10.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/marshalling/river/main/jboss-marshalling-river-1.4.10.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/apache/activemq/artemis/main/artemis-jms-client-1.1.0.wildfly-011.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/apache/activemq/artemis/main/artemis-core-client-1.1.0.wildfly-011.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/apache/activemq/artemis/main/artemis-commons-1.1.0.wildfly-011.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/apache/activemq/artemis/main/artemis-selector-1.1.0.wildfly-011.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/apache/commons/beanutils/main/commons-beanutils-1.9.2.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/apache/commons/collections/main/commons-collections-3.2.2.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/slf4j/jcl-over-slf4j/main/jcl-over-slf4j-1.7.7.jbossorg-1.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/slf4j/main/slf4j-api-1.7.7.jbossorg-1.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/slf4j/impl/main/slf4j-jboss-logmanager-1.0.3.GA.jar
[WILDFLY10_DIR]/modules/system/layers/base/org/jboss/ejb-client/main/jboss-ejb-client-2.1.4.Final.jar
[WILDFLY10_DIR]/modules/system/layers/base/io/netty/main/netty-all-4.0.32.Final.jar
You can add something like this if you have problems with logging:
InternalLoggerFactory.setDefaultFactory(new Log4JLoggerFactory());
PropertyConfigurator.configure("conf/log4j.properties");
I see that Answer given by Rudik is not yet accepted , hence posting my take on this problem.
Test case
#Test
public void sendMessagesToWildfly10() throws IOException, NamingException {
String Message = "Hello, World!";
String connectionFactoryJNDIName = "jms/RemoteConnectionFactory";
String queueName = "jms/queue/TestQueue";
Context namingContext = null;
JMSContext context = null;
try {
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY,"org.jboss.naming.remote.client.InitialContextFactory");
env.put(Context.PROVIDER_URL, "http-remoting://localhost:8470");
// Below May Not be needed if you have turned off the security for Messaging
env.put(Context.SECURITY_PRINCIPAL, "guest");
env.put(Context.SECURITY_CREDENTIALS, "guest");
namingContext = new InitialContext(env);
ConnectionFactory connectionFactory = (ConnectionFactory) namingContext.lookup(connectionFactoryJNDIName);
Destination destination = (Destination) namingContext.lookup(queueName);
context = connectionFactory.createContext("userName", "password");
JMSProducer producer = context.createProducer();
for (int i = 0; i < 10; i++) {
producer.send(destination, Message+" - "+i);
}
JMSConsumer consumer = context.createConsumer(destination);
for (int i = 0; i < 10; i++) {
String text = consumer.receiveBody(String.class, 5000);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
if (namingContext != null) {
namingContext.close();
}
if (context != null) {
context.close();
}
}
}
You will require below mentioned Jars/dependencies added to your classpath. Most of them you can find in Wildfly/modules
If a JMS client is running within a WildFly application then the org.apache.activemq.artemis module must be added as a dependency on your deployment to avoid the java.lang.ClassNotFoundException: org.apache.activemq.artemis.jms.client.ActiveMQJMSConnectionFactory, e.g. as answered here.
Otherwise ( standalone java application) - the jboss-client.jar needs to be included into class-path.
Note: take the jboss-client.jar based on your target WildFly version because it differs between WildFLy 8 and 10.

javax.management.InstanceAlreadyExistsException while deploying spring application

<int:poller fixed-delay="${fixedDelay}" default="true">
<int:advice-chain>
<ref bean="pollAdvise"/>
</int:advice-chain>
</int:poller>
<bean id="pollAdvise" class="org.springframework.integration.scheduling.PollSkipAdvice">
<constructor-arg ref="healthCheckStrategy"/>
</bean>
<bean id="healthCheckStrategy" class="test.main.ServiceHealthCheckPollSkipStrategy">
<property name="url" value="${url}"/>
<property name="doHealthCheck" value="${doHealthCheck}"/>
<property name="restTemplate" ref="restTemplate"/>
</bean>
<bean id="restTemplate"
class="org.springframework.web.client.RestTemplate">
<constructor-arg ref="requestFactory"/>
</bean>
<bean id="requestFactory"
class="test.BatchClientHttpRequestFactory">
<constructor-arg ref="verifier"/>
</bean>
and my health check strategy looks like below
#ManagedResource
public class ServiceHealthCheckPollSkipStrategy implements PollSkipStrategy {
private volatile boolean skip=false;
private String url;
private static String doHealthCheck;
private RestTemplate restTemplate;
public RestTemplate getRestTemplate() {
return restTemplate;
}
public void setRestTemplate(RestTemplate restTemplate) {
this.restTemplate = restTemplate;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public String getDoHealthCheck() {
return doHealthCheck;
}
public void setDoHealthCheck(String doHealthCheck) {
ServiceHealthCheckPollSkipStrategy.doHealthCheck= doHealthCheck;
}
#Override
public boolean skipPoll() {
if(doHealthCheck.equals("false")){
return this.skip;
}
else if(doHealthCheck.equals("true")){
List<String> urlList =getUrlfromEncodedString(url);
for (String url : urlList) {
boolean status =performHealthCheck(url);
if(status==false){
return this.skip = true;
}
}
return this.skip;
}
else {
throw new IllegalArgumentException("do health check can be either true or false");
}
}
/**
* Skip future polls.
*/
#ManagedOperation
public void skipPolls() {
this.skip = true;
}
/**
* Resume polling at the next {#code Trigger} event.
*/
#ManagedOperation
public void reset() {
this.skip = false;
}
private List<String> getUrlfromEncodedString(String urls) throws IllegalArgumentException
{
if(urls==null){
throw new IllegalArgumentException("urls passed is null");
}
List<String> urlList = Arrays.asList(urls.split("\\s*,\\s*"));
return urlList;
}
private boolean performHealthCheck(String url){
if(url==null){
throw new IllegalArgumentException("url passed is null");
}
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.setContentType(MediaType.APPLICATION_JSON);
headers.set("API-Key", "RTM");
HttpEntity<String> request = new HttpEntity<String>("parameters", headers);
ResponseEntity<String> response = restTemplate.
exchange(url, HttpMethod.OPTIONS, request, String.class);
if (response.getStatusCode().toString().equals("200")){
return true;
}
return false;
}
}
I get below exception
Unable to register MBean [test.main.ServiceHealthCheckPollSkipStrategy#73d4b814] with key 'healthCheckStrategy'; nested exception is javax.management.InstanceAlreadyExistsException: test.main:name=healthCheckStrategy,type=ServiceHealthCheckPollSkipStrategy
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:625)
at org.springframework.jmx.export.MBeanExporter.registerBeans(MBeanExporter.java:550)
at org.springframework.jmx.export.MBeanExporter.afterSingletonsInstantiated(MBeanExporter.java:432)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:775)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:757)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:480)
at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:686)
at org.springframework.boot.SpringApplication.run(SpringApplication.java:320)
at org.springframework.boot.builder.SpringApplicationBuilder.run(SpringApplicationBuilder.java:139)
at org.springframework.xd.module.core.SimpleModule.initialize(SimpleModule.java:213)
at org.springframework.xd.dirt.module.ModuleDeployer.doDeploy(ModuleDeployer.java:217)
at org.springframework.xd.dirt.module.ModuleDeployer.deploy(ModuleDeployer.java:200)
at org.springframework.xd.dirt.server.container.DeploymentListener.deployModule(DeploymentListener.java:365)
at org.springframework.xd.dirt.server.container.DeploymentListener.deployStreamModule(DeploymentListener.java:334)
at org.springframework.xd.dirt.server.container.DeploymentListener.onChildAdded(DeploymentListener.java:181)
at org.springframework.xd.dirt.server.container.DeploymentListener.childEvent(DeploymentListener.java:149)
at org.apache.curator.framework.recipes.cache.PathChildrenCache$5.apply(PathChildrenCache.java:509)
at org.apache.curator.framework.recipes.cache.PathChildrenCache$5.apply(PathChildrenCache.java:503)
at org.apache.curator.framework.listen.ListenerContainer$1.run(ListenerContainer.java:92)
at com.google.common.util.concurrent.MoreExecutors$SameThreadExecutorService.execute(MoreExecutors.java:297)
at org.apache.curator.framework.listen.ListenerContainer.forEach(ListenerContainer.java:83)
at org.apache.curator.framework.recipes.cache.PathChildrenCache.callListeners(PathChildrenCache.java:500)
at org.apache.curator.framework.recipes.cache.EventOperation.invoke(EventOperation.java:35)
at org.apache.curator.framework.recipes.cache.PathChildrenCache$10.run(PathChildrenCache.java:762)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
Caused by: javax.management.InstanceAlreadyExistsException: test.main:name=healthCheckStrategy,type=ServiceHealthCheckPollSkipStrategy
at com.sun.jmx.mbeanserver.Repository.addMBean(Repository.java:437)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerWithRepository(DefaultMBeanServerInterceptor.java:1898)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerDynamicMBean(DefaultMBeanServerInterceptor.java:966)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerObject(DefaultMBeanServerInterceptor.java:900)
at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.registerMBean(DefaultMBeanServerInterceptor.java:324)
at com.sun.jmx.mbeanserver.JmxMBeanServer.registerMBean(JmxMBeanServer.java:522)
at org.springframework.jmx.support.MBeanRegistrationSupport.doRegister(MBeanRegistrationSupport.java:195)
at org.springframework.jmx.export.MBeanExporter.registerBeanInstance(MBeanExporter.java:678)
at org.springframework.jmx.export.MBeanExporter.registerBeanNameOrInstance(MBeanExporter.java:615)
... 30 m
I got the javax.management.InstanceAlreadyExistsException as part of the stacktrace, however the leading error was java.lang.IllegalStateException:
javax.management.InstanceAlreadyExistsException: jboss.deployment:id="jboss.web.deployment:war=/my_application", type=Component already registered.
Caused by: java.lang.IllegalStateException: jboss.web.deployment:war=/my_application is already installed.
The reason was that I accidentally kept two .ear files in the /deploy folder of my JBOSS server - both the previous and the current .ear of my application.
As it was stated here: https://www.theserverside.com/discussions/thread/22674.html
I'm not sure there is a way to deploy two ear files with the same
classes inside and not have problems.
Since the two .ears had classes in common, that lead to InstanceAlreadyExistsException.
What has worked for me is:
Delete the war file from /webapps
Copy war file from /target and paste into /webapps
Hope it will work for you too.
It's because you also declare another bean with the same id as 'healthCheckStrategy' in another spring application. You probably put these two spring applications in the same server.
Solution 1:
change the bean id either in this spring application or the other one will solve your problem.
Solution 2:
add EnableMBeanExport annotation and set different defaultDomain for each spring application
#Configuration
#EnableMBeanExport(defaultDomain="first")
public class BeanGenerator {...}
#Configuration
#EnableMBeanExport(defaultDomain="second")
public class BeanGenerator {...}

How to send Emails via Spring

In my JavaFx project I inject my controllers like so, which works fine:
#Configuration
public class AppFactory {
#Bean
public HomeController homeController() throws IOException {
return (HomeController) loadController("/wakiliproject/Home.fxml");
}
FXMLLoader loader = null;
protected Object loadController(String url) throws IOException {
loader = new FXMLLoader(getClass().getResource(url));
loader.load();
return loader.getController();
}
}
However, for non-controller classes, I get a null pointer exception, probably because the class never gets injected. Say, for example, I try to call a method in a non-controller class from another non-controller class like so:
Sending email via Spring, for example:
public class HomeController extends Application {
#Autowired
MailMail mailMail;
// Send email here
public void sendEmailMethod() {
System.out.println("Here ----------------------------------------------------------------");
mailMail.sendMail("olireylikesyou#gmail.com", "tryrevilo#yahoo.com", "Hello", "Subjecto");
}
// The other class methods
The other classes:
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="smtp.gmail.com" />
<property name="username" value="mygmailusername#gmail.com" />
<property name="password" value="gmailpassword" />
<property name="javaMailProperties">
<props>
<prop key="mail.smtp.auth">true</prop>
</props>
</property>
</bean>
<bean id="mailMail" class="wakiliproject.ServerSide.EMail.MailMail">
<property name="mailSender" ref="mailSender" />
</bean>
--
public class MailMail {
private MailSender mailSender;
public void setMailSender(MailSender mailSender) {
this.mailSender = mailSender;
}
public void sendMail(String from, String to, String subject, String msg) {
//creating message
SimpleMailMessage message = new SimpleMailMessage();
message.setFrom(from);
message.setTo(to);
message.setSubject(subject);
message.setText(msg);
//sending message
mailSender.send(message);
}
}
The stacktrace:
Exception in Application start method
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:367)
at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:305)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:894)
at com.sun.javafx.application.LauncherImpl.access$000(LauncherImpl.java:56)
at com.sun.javafx.application.LauncherImpl$1.run(LauncherImpl.java:158)
at java.lang.Thread.run(Thread.java:745)
Caused by: org.springframework.mail.MailSendException: Failed messages: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first. k10sm2188955lae.42 - gsmtp
; message exceptions (1) are:
Failed message 1: com.sun.mail.smtp.SMTPSendFailedException: 530 5.7.0 Must issue a STARTTLS command first. k10sm2188955lae.42 - gsmtp
at org.springframework.mail.javamail.JavaMailSenderImpl.doSend(JavaMailSenderImpl.java:448)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:308)
at org.springframework.mail.javamail.JavaMailSenderImpl.send(JavaMailSenderImpl.java:297)
at wakiliproject.ServerSide.EMail.MailMail.sendMail(MailMail.java:22)
at wakiliproject.HomeController$HomeInit.homeInit(HomeController.java:618)
at wakiliproject.HomeController$HomeInit.access$100(HomeController.java:613)
at wakiliproject.HomeController.initHomeController(HomeController.java:319)
at wakiliproject.WakiliProject.start(WakiliProject.java:34)
at com.sun.javafx.application.LauncherImpl$8.run(LauncherImpl.java:837)
at com.sun.javafx.application.PlatformImpl$7.run(PlatformImpl.java:335)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:301)
at com.sun.javafx.application.PlatformImpl$6$1.run(PlatformImpl.java:298)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.application.PlatformImpl$6.run(PlatformImpl.java:298)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
... 1 more
Exception running application wakiliproject.WakiliProject
Java Result: 1
had a similar problem... got me some attempts to configure it right in my application.properties (I'm injecting JavaMailSender using spring)
spring.mail.properties.mail.smtp.starttls.enable=true
spring.mail.properties.mail.smtp.starttls.required=true
spring.mail.properties.mail.smtp.auth = true;
spring.mail.properties.mail.socketFactory.port=587
spring.mail.properties.mail.socketFactory.class=javax.net.ssl.SSLSocketFactory
spring.mail.properties.mail.socketFactory.fallback=false
later i was required to enable looser security to my account during the test:
"change your settings at https://www.google.com/settings/security/lesssecureapps so that your account is no longer protected by modern security standards"
or i got an authentication error.
I hope that helps
According to Mladen Uzelac You need to set some properties for your SMTP connection.
Link related:
http://forum.spring.io/forum/spring-projects/web/68425-javax-mail-messagingexception-530-5-7-0-must-issue-a-starttls-command-first-5sm505

Resources