High Efficient MDB using spring jms or ntegration - spring

I have requirement where I need receive message from MQ every seconds , the message will be in XML format , so i need to write a high effecient MDB. Problem here is I am new to MQ,JMS,Spring JMS and Spring Integration but not spring tough.
Based on google search so far I am able to write below code
MDB
import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;
public class MyMessageListener implements MessageListener{
#Override
public void onMessage(Message m) {
TextMessage message=(TextMessage)m;
try{
System.out.println(message.getText());
}catch (Exception e) {e.printStackTrace(); }
}
}
XMl config
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:jms="http://www.springframework.org/schema/jms"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/jms
http://www.springframework.org/schema/jms/spring-jms.xsd">
<bean id="connectionFactory" class="org.apache.activemq.ActiveMQConnectionFactory"
p:brokerURL="tcp://localhost:61616" />
<bean id="listener" class="com.springexample.MyMessageListener"></bean>
<jms:listener-container container-type="default" connection-factory="connectionFactory"
acknowledge="auto">
<jms:listener destination="myfirstqueue" ref="listener" method="onMessage"></jms:listener>
</jms:listener-container>
</beans>
I know what i have written is very basic one but i dont know what is the efficient one , how to provide transaction support and how to handle such load where i am going to recieve message every seconds.
Should i use Spring JMS or Spring Integration any help is much appreciated.

The question you asked is which to use: definitely go Spring JMS

Related

Spring #Transaction not rolling back

I have a very strange problem and looking for the solution here. I spent significant amount of time by reading articles and other questions on SO however no luck.
I am using #Transactional annotation in my sample application of Spring 3 and hibernate 3 as shown below. In the last line of method I am explicitly throwing NullPointerException as shown below.
package com.mkyong.common;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.mkyong.stock.bo.StockBo;
import com.mkyong.stock.model.Stock;
#Service("stockService")
public class StockServiceImpl {
final static Logger logger = Logger.getLogger(StockServiceImpl.class);
#Transactional(rollbackFor ={ NullPointerException.class} )
public void createNewStock(StockBo stockBo) {
/** insert **/
Stock stock = new Stock();
String code = "xee";
stock.setStockCode(code);
stock.setStockName(code);
stockBo.save(stock);
logger.debug("#################### After Save ##########################");
throw new NullPointerException();
}
}
However this transaction is not rolling back and always commiting to database even though NullPointerException is thrown.
Below is my application context file
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
<!-- Database Configuration -->
<import resource="../database/DataSource.xml" />
<import resource="../database/Hibernate.xml" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<!-- Auto scan the components -->
<context:component-scan base-package="com.mkyong.stock" />
<bean
class="org.springframework.jdbc.datasource.DataSourceTransactionManager"
id="transactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
</beans>
Judging from your configuration you are using Hibernate, however you are using the transaction manager that is solely for plain JDBC usage.
To have proper transaction management you must use the PlatformTransactionManager which belongs to your persistence technology. In your case you should use the HibernateTransactionManager instead of the DataSourceTransactionManager.
<bean id="transactionManager" class="org.springframework.hibernate5.HibernateTransactionManager>
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Note: This is for Hibernate5 (see the package name) use the one that fits your version of hibernate.
Make sure that the class that contains the method is in the application context not in the web application context (simple: the parent class of the method should be a service, repository etc. not a controller).
Also check that you import the #Transactional annotation from the right spring package.
Using only #Transactional annotation is enough. You dont require rollbackFor attribute to rollback on NullPointerException. Transactions with #Transactional annotation are defaulted to RuntimeException.
You should add rollbackFor only if you want to rollback on Checked Exceptions.

Configuring JMS connectionfactory in mule

Could anyone suggest me how to configure connectionfactory in mule using connectionFactory-ref
I am trying to configure connectionfactory in mule using connectionFactory-ref[this is the url I am following ::: http://www.mulesoft.org/documentation-3.2/display/32X/JMS+Transport+Reference].
In the above mentioned documentation - mentioned -
Configuring the ConnectionFactory
One of the most important attributes is connectionFactory-ref. This is a reference to the ConnectionFactory object which creates new connections for your JMS provider. The object must implement the interface javax.jms.ConnectionFactory.
ConnectionFactory
So to implement the above below is my mule configuraion xml
<?xml version="1.0" encoding="UTF-8"?>
<mule xmlns:smtps="http://www.mulesoft.org/schema/mule/smtps"
xmlns:scripting="http://www.mulesoft.org/schema/mule/scripting" xmlns:https="http://www.mulesoft.org/schema/mule/https"
xmlns:http="http://www.mulesoft.org/schema/mule/http" xmlns:jms="http://www.mulesoft.org/schema/mule/jms" xmlns="http://www.mulesoft.org/schema/mule/core" xmlns:doc="http://www.mulesoft.org/schema/mule/documentation"
xmlns:spring="http://www.springframework.org/schema/beans" version="EE-3.5.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.mulesoft.org/schema/mule/smtps http://www.mulesoft.org/schema/mule/smtps/current/mule-smtps.xsd
http://www.mulesoft.org/schema/mule/https http://www.mulesoft.org/schema/mule/https/current/mule-https.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-current.xsd
http://www.mulesoft.org/schema/mule/core http://www.mulesoft.org/schema/mule/core/current/mule.xsd
http://www.mulesoft.org/schema/mule/http http://www.mulesoft.org/schema/mule/http/current/mule-http.xsd
http://www.mulesoft.org/schema/mule/jms http://www.mulesoft.org/schema/mule/jms/current/mule-jms.xsd
http://www.mulesoft.org/schema/mule/scripting http://www.mulesoft.org/schema/mule/scripting/current/mule-scripting.xsd">
<spring:bean name="connectionFactory" class="com.ers.connections.ConnectionFactoryImpl"/>
<jms:activemq-connector name="Active_MQForApex" connectionFactory-ref="connectionFactory" validateConnections="true" doc:name="Active MQ"/>
<flow name="apexwritequeueFlow1" doc:name="apexwritequeueFlow1">
<http:inbound-endpoint exchange-pattern="request-response" host="localhost" port="8081" path="niviTest" doc:name="HTTP"/>
<logger message="Payload ::: #[payload]" level="INFO" doc:name="Logger"/>
<jms:outbound-endpoint queue="ANS.RecOps.Incoming" connector-ref="Active_MQForApex" doc:name="JMS"/>
</flow>
</mule>
Below java class
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;
import org.apache.activemq.ActiveMQConnectionFactory;
public class ConnectionFactoryImpl implements javax.jms.ConnectionFactory {
#Override
public Connection createConnection() throws JMSException {
// Create a ConnectionFactory
ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("21233", "123", "ssl://xxxx.autonet-yyy.com:443");
return connectionFactory.createConnection();
}
#Override
public Connection createConnection(String arg0, String arg1)
throws JMSException {
// TODO Auto-generated method stub
return null;
}
}
However I am getting this error
. Root Exception was: Unsupported ConnectionFactory type: com.ers.connections.ConnectionFactoryImpl. Type: class java.lang.IllegalArgumentException
ERROR 2014-12-28 11:53:26,141 [main] org.mule.module.launcher.application.DefaultMuleApplication: null
java.lang.IllegalArgumentException: Unsupported ConnectionFactory type: com.ers.connections.ConnectionFactoryImpl
Thank you in advance.
Any suggestions most appreciated.
Thank you and regards
Nivi
If you don't have any really good reason, that you do not show in the post, to write your own ConenctionFactory implementation you should use the one provided by the JMS provider directly.
So you should use a bean definition like this
<spring:bean id="connectionFactory"
class="org.apache.activemq.ActiveMQConnectionFactory">
<property name="brokerURL" value="tcp://localhost:61616"/>
</spring:bean>
You are using the ActiveMQ connector and it is expecting a factory class of type org.apache.activemq.ActiveMQConnectionFactory. If you really need a custom factory, your ConnectionFactoryImpl class should extend the activemq factory:
import org.apache.activemq.ActiveMQConnectionFactory;
public class ConnectionFactoryImpl extends ActiveMQConnectionFactory {
// Override the methods you need
}
Then you can reference it in connectionFactory-ref attribute of the connector.
Your implementation probably does not provide any special feature, if this is the case please just use the default connector:
<jms:activemq-connector name="JmsConnector" specification="1.1" />
However if you have some special behaviour that you want to use, with the activemq connector, you just need a connection factory that implements org.apache.activemq.ActiveMQConnectionFactory, this is because these two lines. Then just use something like the following:
<spring:beans>
<spring:bean name="myActiveMqConnectionFactory"
class="org.apache.activemq.spring.MyActiveMQConnectionFactory"
p:brokerURL="vm://esb-amq-broker" <--- Just some example property />
</spring:beans>
<jms:activemq-connector name="myJmsConnector"
specification="1.1"
connectionFactory-ref="AmqConnectionFactory"
persistentDelivery="true" />
However please twink twice about the need of doing this, the original activemq connector probably provides almost anything you need with the exeption of connection caching. If that is what you need please consider using this.

Camel, Netty, MINA: Two Way Asynchronous Communications Between Server and Client

From my limited understanding of Camel's MINA2 and Netty Components I see that I can do one way communications and request-reply communications but I want to be able to send messages from the client to the server and from the server to the client asynchronously.
For example, I would like to write a simple server to echo back to any connected clients what was submitted. In addition, for any connected client I want to send the current time every thirty seconds. Is there a good way to do this? Below is a sample of what I have but don't know how to setup the part that allows the server to send messages to the connected client.
The netcat portion of the code snippets below work, and printing the current time to the server's console (via logging) works, but want to send it back to the connected client. I should note that the client is legacy software and I don't have the ability to change it. Only the server portions.
TL;DR: I want the server to send asynchronous messages to connected legacy clients that I have to support as is. Is there a built in way to do this in Camel without writing custom code? Or if not, what I would have to write?
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:camel="http://camel.apache.org/schema/spring" xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="echo" class="netcat.Echo" />
<camel:errorHandler id="camelErrorHandler" type="DefaultErrorHandler" />
<camelContext id="camelContext" errorHandlerRef="camelErrorHandler" xmlns="http://camel.apache.org/schema/spring">
<route>
<from uri="quartz2://sendTime?cron=0/5+*+*+*+*+?" />
<to uri="bean:netcat.CurrentTime?method=getCurrentTime()" />
</route>
<route>
<from uri="netty:tcp://localhost:5555?textline=true" />
<to uri="bean:echo" />
</route>
</camelContext>
</beans>
log4j.properties
log4j.rootLogger=INFO, A1
# A1 is set to be a ConsoleAppender.
log4j.appender.A1=org.apache.log4j.ConsoleAppender
# A1 uses PatternLayout.
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%-4r %d [%t] %-5p %c %x - %m%n
CurrentTime.java
package netcat;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CurrentTime {
private static final Logger LOG = LoggerFactory.getLogger(CurrentTime.class);
private CurrentTime() {
}
public static String getCurrentTime() {
String currentTime = DateTime.now().toString();
LOG.info("Current Time is {}.", currentTime);
return currentTime;
}
}
Echo.java
package netcat;
import org.apache.commons.lang3.StringUtils;
public class Echo {
public String echo(String message) {
return StringUtils.join(new Object[] { "Echoing: ", message });
}
}

ActiveMQ JMS Broker and Spring configuration

I'm pretty new to using Camel and ActiveMQ. I'm trying to run a simple code from Eclipse, without using Maven. But, it fails during Bean initialization. From the error, it seems its due to the JAR version differences, but i m failing to locate it. Kindly help me resolve this .
import org.apache.camel.CamelContext;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestingBroker {
private TestingBroker() {
// Helper class
}
public static void main(final String[] args) throws Exception {
AbstractApplicationContext aContext = new ClassPathXmlApplicationContext(
"classpath:META-INF/spring/camel-config-client.xml");
CamelContext ctx = (CamelContext) aContext.getBean("mycamelTemplate", CamelContext.class);
ctx.addRoutes(new BuildTwitterComponent());
ctx.start();
}
}
Here's the camel-config-client.xml file contents-
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:camel="http://camel.apache.org/schema/spring"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.11.1.xsd">
<camel:camelContext id="my-camel-client">
<camel:template id="mycamelTemplate"/>
</camel:camelContext>
<bean id="jms" class="org.apache.activemq.camel.component.ActiveMQComponent">
<property name="brokerURL" value="tcp://135.207.178.237:61616" />
</bean>
</beans>
------------------------------
I have spring.jar.2.5.6 and camel-spring-2.11.1 JAR in the classpath. Pls suggest what am i missing here.
Thanks!
GR
Camel 2.11.1 uses Spring 3.2.3.RELEASE
Also, you'll need to have ActiveMQ 5.8.0 jars (activemq-camel, etc) in your path as well to find the org.apache.activemq.camel.component.ActiveMQComponent class

Use of Spring Framework for RabbitMQ is reducing the performance

I have created a producer, which was using com.rabbitmq.client.connectionFactory and was sending 1,000,000 messages (40 Bytes) in 100 seconds.
But now I want an spring abstraction. I was unable to use com.rabbitmq.client.connectionFactory rather I had to use org.springframework.amqp.rabbit.connection.SingleConnectionFactory. Using this connection factory only 100,000 messages (40 Bytes) are send to the broker in 100 seconds.
Does anybody have experience why the performance is reduced so much (around 90%).
The code using "import com.rabbitmq.client.ConnectionFactory;" is ->
package Multiple_queues_multiple_consumers;
import java.io.IOException;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
public class Producer {
private static Connection myConnection;
private static Channel myChannel;
public static String myQueueName;
public static void main(String[] args) throws IOException {
long startTime=0;
int count=0;
ConnectionFactory myFactory=new ConnectionFactory();
myFactory.setHost("localhost");
try {
myConnection = myFactory.newConnection();
myChannel = myConnection.createChannel();
String myExchange = "wxyzabc";
String myBody = "This is a message : message numberxxxxxx";
String myRoutingKey = "RoutingKey";
myQueueName = "new_Queue";
myChannel.exchangeDeclare(myExchange, "direct", true, false, null);
myChannel.queueDeclare(myQueueName, true, false, false, null);
myChannel.queueBind(myQueueName, myExchange, myRoutingKey);
startTime=System.currentTimeMillis();
AMQP.BasicProperties properties = new AMQP.BasicProperties();
properties.setDeliveryMode(2);
startTime=System.currentTimeMillis();
while(count++<=10000){
myChannel.basicPublish(myExchange, myRoutingKey, true, true, properties, myBody.getBytes() );
}
System.out.println(System.currentTimeMillis()-startTime);
} catch (Exception e){
System.exit(0);
}
}
}
The code using SpringFramework is :->
Producer1.java
import org.springframework.amqp.core.AmqpAdmin;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Producer1 {
public static void main(String[] args) {
ConfigurableApplicationContext context = new ClassPathXmlApplicationContext("Producer1.xml");
AmqpAdmin amqpAdmin = context.getBean(RabbitAdmin.class);
Queue queue = new Queue("sampleQueue");
DirectExchange exchange = new DirectExchange("myExchange");
Binding binding = new Binding(queue, exchange, "");
amqpAdmin.declareQueue(queue);
amqpAdmin.declareExchange(exchange);
amqpAdmin.declareBinding(binding);
RabbitTemplate rabbitTemplate = context.getBean(RabbitTemplate.class);
String routingKey = "";
String myBody = "This is a message : message numberxxxxxx";
Message Msg = new Message(myBody.getBytes(), null);
int count=0;
long CurrTime = System.currentTimeMillis();
while(count++<=10000){
rabbitTemplate.send(routingKey, Msg);
//System.out.println("Message Sent");
}
System.out.println(System.currentTimeMillis()-CurrTime);
}
}
Producer1.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd">
<!-- Define a connectionFactory -->
<bean id="rabbitConnectionFactory" class="com.rabbitmq.client.ConnectionFactory">
<property name="host" value="localhost" />
</bean>
<bean id="connectionFactory" class="org.springframework.amqp.rabbit.connection.SingleConnectionFactory">
<constructor-arg ref="rabbitConnectionFactory"/>
</bean>
<!-- Tell the Admin bean about that connectionFactory and initialize it, create a queue and an exchange on Rabbit Broker using the RabbitTemplate provided by Spring framework-Rabbit APIs -->
<bean id="Admin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">
<constructor-arg ref="connectionFactory" />
</bean>
<bean id="rabbitTemplate" class="org.springframework.amqp.rabbit.core.RabbitTemplate"
p:connectionFactory-ref="connectionFactory"
p:routingKey="myRoutingKey"
p:exchange="myExchange" />
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<!-- Define a connectionFactory -->
<bean id="connectionFactory" class="com.rabbitmq.client.connectionFactory">
<constructor-arg value="localhost" />
<property name="username" value="guest" />
<property name="password" value="guest" />
</bean>
<bean id="Admin" class="org.springframework.amqp.rabbit.core.RabbitAdmin">
<constructor-arg ref="connectionFactory" />
</bean>
</beans>
Using this xml file, the error appears saying org.springframework.amqp.rabbit.core.RabbitAdmin could not cast com.rabbitmq.client.connectionFactory for connectionfactory bean.
The exact error is: "nested exception is java.lang.IllegalStateException: Cannot convert value of type [com.rabbitmq.client.ConnectionFactory] to required type [org.springframework.amqp.rabbit.core.RabbitTemplate]: no matching editors or conversion strategy found" .
Hence i have to use bean:
<bean id="connectionFactory"
class="org.springframework.amqp.rabbit.connection.SingleConnectionFactory">
</bean>
Are you sure that you used the same Rabbit MQ broker? Could you be using a broker on a different server, or an upgraded/downgraded version of RabbitMQ?
The other thing to look at is your jvm. Is it possible that you don't have enough memory configured and now the garbage collector is thrashing? Run top and see if the jvm's memory usage is close to the configured memory size.
Are you using an old version of RabbitMQ. Lots of Linux distros include RabbitMQ 1.7.2 which is an old version that has problems with large numbers of messages. Large is hard to define because it depends on your RAM, but RabbitMQ does not like to use more than 40% of RAM because it needs to copy a persistence transaction log in order to process it and clean it for log rollover. This can cause RabbitMQ to crash, and, of course, processing the huge logs will slow it down. RabbitMQ 2.4.1 handles the persister logs much better, in smaller chunks, and it also has much, much faster message routing code.
This still sounds to me like a Java problem, either Spring is just a pig and is terribly inefficient, or you have not given your jvm enough RAM to avoid frequent gc runs. What setting are you using for -Xmx?

Resources