Still new to spring and spring integration so please bear with me. =)
I have set up a client to connect to a remote server using TCP. The server sends a message as soon as a connection is established. Using ngrep I have verified that the connection is up and that the message is sent from the server.
By using the gateway interface "gw" I can successfully receive the message. However what I would like to do is to trigger the com.example.Client.onMessage method when a message is received. My understanding is that this should be possible using a ServiceActivator as shown below. Is this true or do I have to use my own dedicated thread doing a blocking receive? Thanks.
Configuration
<bean id="javaDeserializer"
class="org.springframework.integration.ip.tcp.serializer.ByteArrayLfSerializer" />
<int-ip:tcp-connection-factory id="client"
type="client" host="localhost" port="12000"
single-use="false" so-timeout="10000" so-keep-alive="true" deserializer="javaDeserializer"
serializer="javaSerializer"/>
<int:gateway id="gw" service-interface="com.example.Interface"
default-request-channel="input" default-reply-channel="replies" />
<int:channel id="input" />
<int:channel id="replies">
<int:queue />
</int:channel>
<int-ip:tcp-outbound-channel-adapter
id="outboundClient" channel="input" connection-factory="client" />
<int-ip:tcp-inbound-channel-adapter
id="inboundClient" channel="replies" connection-factory="client"
client-mode="true" retry-interval="10000" auto-startup="true" />
<int:service-activator input-channel="input" output-channel="replies" ref="com.example.Client" method="onMessage" />
ServiceActivator
#EnableIntegration
#IntegrationComponentScan
#MessageEndpoint
public class Client {
#ServiceActivator
public void onMessage(byte[] received) {
//Not called
}
}
#EnableIntegration and #IntegrationComponentScan must be configured on the #Configuration. The general Spring annotations configuration principles: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-java. Although having an XML config you don't need those annotations at all.
If you want to receive messages from TCP to the <service-activator>, you have to configure its input-channel to the replies.
Right now you have a mess in your config: several subscribers for the input channel. In this case they receive incoming messages via round-robin manner.
If I understand correctly you should remove all the <int:gateway> staff and just perform step #2. Although it isn't clear how you are going to send messages to the input channel...
Related
What i'm trying to do is create a proof-of-concept Camel route, that exposes a cxfrs service endpoint. Requests to this endpoint are routed to another service on a different server using cxf client. After i get the xml response, i need to do some stuff with it, lets say save the response body to a DB for example. And of course the original requestor needs to receive the response as well.
If i don't do any post-processing of the response, then i get the response xml in the browser as expected. But any time i try to add another step to my route for processing the response, the browser gets a response that is empty. As you can see in the commented out lines, it doesn't matter which camel component i use the call the bean. I tried bean, process, and to. Even if i comment out all the code from the bean so it does nothing, the result is the same.
Here's my route:
<cxf:rsServer address="{{base.url}}/employeeservicecxf" id="restServiceCxf">
<cxf:serviceBeans>
<bean class="com.kf.camel.sample.EmployeeServiceResource"/>
</cxf:serviceBeans>
</cxf:rsServer>
<cxf:rsClient
address="http://{{remote.server}}/adminrest/jaxrs/projects/10475/products"
id="rsClient" loggingFeatureEnabled="true" />
<bean class="com.kf.camel.sample.CamelProcessor" id="processor"/>
<bean class="com.kf.camel.sample.CamelResponseProcessor" id="responseProcessor"/>
<camelContext id="_camelContext1" trace="true" xmlns="http://camel.apache.org/schema/spring">
<propertyPlaceholder id="properties" location="app.properties"/>
<route id="_route1">
<from id="_from1" uri="cxfrs://bean://restServiceCxf"/>
<process id="_process1" ref="processor"/>
<setHeader headerName="CamelHttpMethod" id="_setHeader1">
<constant>GET</constant>
</setHeader>
<to id="_to1" uri="cxfrs://bean://rsClient"/>
<!-- to id="_to3" uri="bean://com.kf.camel.sample.CamelResponseProcessor?method=process"/-->
<bean id="_bean1" ref="responseProcessor" method="process"/>
<!-- process id="_process2" ref="responseProcessor"/-->
</route>
</camelContext>
</beans>
Response Headers
Response Body with content length mismatch error
Have you tried to enable stream caching?
Sounds like any first operation you do on the response is consuming the stream and any further attempt to read the stream again gets an empty result.
When you want to read a stream multiple times in Camel you have to enable stream caching.
I am using Spring JMS with ActiveMQ as the broker and running the application on Tomcat.
I have one queue, let's say queue.a. In my web app, I already have a MessageListener running whenever I start my web app. The only thing is, I want to add some kind of queue consumer but synchronously. I already try using JmsTemplate etc. But when both of my consumer (listener async & consumer synchronous) is up and I trigger the .receive() method, the message sent to the queue always sucked up to the message listener that have been always online since the web app started. After the end of the timeout,the synchronous receiver did not consume any message at all.
But,when I comment out the messageListener, the synchronous customer run well.
I'm still a newbie,do any of you have any way to make what I want possible? Thanks! Sorry for my bad english :(
<bean id="someQueue" class="org.apache.activemq.command.ActiveMQQueue">
<constructor-arg index="0" value="TEST.QUEUE?consumer.priority=10" />
</bean>
and then, set it to your listener/receiver bean:
<bean id="someReceiver" class="blah.blah.SomeReceiver">
<property name="destination" ref="someQueue" />
<property name="jmsTemplate" ref="jmsTemplate" />
</bean>
Does this solve your problem?
I'm trying to publish a message to a queue and then have certain consumers consume it only if it contains a certain header and another consumer consume it if it contains another header.
What I've done so far is to setup a headers-exchange that routes messages to a certain queue only if it contains that header.
This is the config I'm using to setup the exchange and the queue and the listener:
<!-- Register Queue Listener Beans -->
<bean id="ActionMessageListener" class="com.mycee.Action" />
<!-- Register RabbitMQ Connections -->
<rabbit:connection-factory
id="connectionFactory"
port="${rabbit.port}"
virtual-host="${rabbit.virtual}"
host="${rabbit.host}"
username="${rabbit.username}"
password="${rabbit.password}"
connection-factory="nativeConnectionFactory" />
<!-- Register RabbitMQ Listeners -->
<rabbit:listener-container
connection-factory="connectionFactory"
channel-transacted="true"
requeue-rejected="true"
concurrency="${rabbit.consumers}">
<rabbit:listener queues="${queue.myqueue}" ref="ActionMessageListener" method="handle"/>
</rabbit:listener-container>
<!-- Setup RabbitMQ headers exchange -->
<rabbit:headers-exchange id="${exchange.myexchange}" name="${exchange.myexchange}">
<rabbit:bindings>
<rabbit:binding queue="${queue.myqueue}" key="action" value="action3" />
</rabbit:bindings>
</rabbit:headers-exchange>
<rabbit:admin connection-factory="connectionFactory"/>
<rabbit:queue name="${queue.myqueue}" />
So I'm binding myqueue to myexchange using key of action and value of action3.
Now when I publish on the exchange:
the ChannelAwareMessageListener is consuming it even though the action was set to action1 instead of action3
public class Action implements ChannelAwareMessageListener {
#Override
public void onMessage(Message message, Channel channel) throws Exception {
System.out.println(message.toString());
}
}
Either I'm not using a headers-exchange correctly or I'm not configuring it correctly - any advice ?
It doesn't work that way; you need a separate queue for each consumer. See the tutorial.
When multiple consumers consume from the same queue they compete for all messages; you can't select messages on the consumer side; the "selection" is done by the exchange by routing messages to specific queue(s).
I'm using Spring Integration & SI AMQP 3.0.0-RELEASE.
I have a fairly simple Request-Response over AMQP between two SI instances.
I'm finding that when the response arrives back on the requesting server, that SI is attempting to deserialize the response using the the Request object's type, not the Response object.
ie., Given the gateway interface of:
public AnalyticsReponse getAnalyticsReport(EntityMessage objectUri);
I find that even though the correct JSON of an AnalyticsResponse arrives on the server, SI is attempting to deserialize it as an EntityMessage, which is failing.
I've debugged it through, and I suspect that the cause is that the Responding side is copying the inbound json__TypeId__ header, rather than supplying it's own. However, I can't see where I've misconfigured this.
Here's my config -- what have I done wrong?
Requesting side:
<int:channel id="analytics.reports.requests.channel" />
<int:channel id="analytics.reports.responses.channel" />
<int:gateway service-interface="com.project.analytics.gateway.AnalyticsReportingGateway">
<int:method name="getAnalyticsReport" request-channel="analytics.reports.requests.channel" reply-channel="analytics.reports.responses.channel"/>
</int:gateway>
<int-amqp:outbound-gateway
request-channel="analytics.reports.requests.channel"
reply-channel="analytics.reports.responses.channel"
exchange-name="analytics.reports.exchange" amqp-template="amqpTemplate" />
Responding side:
<int:channel id="analytics.reports.requests.channel" />
<int:channel id="analytics.reports.responses.channel" />
<int-amqp:inbound-gateway request-channel="analytics.reports.requests.channel" reply-channel="analytics.reports.responses.channel"
queue-names="analytics.reports.queue" connection-factory="rabbitConnectionFactory" message-converter="jsonMessageConverter"/>
<int:service-activator input-channel="analytics.reports.requests.channel" output-channel="analytics.reports.responses.channel"
ref="analyticsReporter" method="getAnalytics"/>
<bean class="com.project.analytics.reporters.SimpleAnalyticsReporter" id="analyticsReporter"/>
public class SimpleAnalyticsReporter {
#SneakyThrows
public AnalyticsReponse getAnalytics(EntityMessage message) {
return new AnalyticsReponse("Hello");
}
As far as you aren't interested in org.springframework.integration.mapping.support.JsonHeaders, because you use jsonMessageConverter, you should filter them (<header-filter>) or fully ignore all AMQP headers (mapped-request-headers="-" or mapped-reply-headers="-").
However I see that I wasn't right yesterday (https://jira.springsource.org/browse/INT-3285) and reopen the issue to revise how can we get deal with standard headers by default to allow to work similar scenarios.
Thank you!
Does any method of camel's consumer exist which is able to process >20 http requests per second? I try to work with restlet and jetty components, but failed with both.
For example, I set this config for a jetty component:
<bean id="jetty" class="org.apache.camel.component.jetty.JettyHttpComponent">
<property name="httpClientMinThreads" value="10"/>
<property name="httpClientMaxThreads" value="254" />
<property name="minThreads" value="10"/>
<property name="maxThreads" value="254" />
</bean>
and hoped that everything will be OK, but nothing.
My route config:
from("jetty:http://0.0.0.0:8888" + linkRequest+"?matchOnUriPrefix=true")
.onException(Exception.class)
.log(LoggingLevel.ERROR, "${exception.stacktrace}")
.useOriginalMessage()
.handled(true)
.setBody(simple("Something went wrong"))
.end()
.process(new MyFirstProcessor())//here I get httpHeaders,create entity A
.to("jpa:RequestEntity")
.process(new MySecondProcessor())//set some filed in entity A and send it
.to("bean:service?method=process")//here I recieve entity A and create entity B
.to("jpa:ResponseEntity")
.process(new MyThirdProcessor())//here response is created;
Please explain to me how I can configurate parameters of camel (I glance at the threading model configuration), jetty-component or restlet component - so that my router can handle all incoming requests.
UPDATE
These problems were caused by the settings of the connection pool to the database.