I am using JMS for the first time and am using Glassfish 3.1.1. I have set up a JMS Connection Factory:
Pool Name: jms/QueueConnectionFactory
JNDI Name: jms/QueueConnectionFactory
Resource Type: javax.jms.QueueConnectionFactory
and a Destination Resource:
JNDI Name: jms/ProcessBatchQueue
Physical Destination: ProcessBatchQueue
Resource Type: javax.jms.Queue
I have deployed a war with a servlet that accepts a file, parses it and saves the contents to a database. If this is all successful it sends a message to the queue:
#Resource(lookup = "jms/ProcessBatchQueue")
private Queue processBatchQueue;
private void sendProcessBatchMessage(String batchID) throws JMSException
{
log.info("Attempting to send process batch message for batch ID: "
+ batchID);
Connection jmsConnection = connectionFactory.createConnection();
Session jmsSession = jmsConnection.createSession(false,
Session.AUTO_ACKNOWLEDGE);
TextMessage message = jmsSession.createTextMessage();
message.setText(batchID);
MessageProducer msgProducer = jmsSession.createProducer(processBatchQueue);
msgProducer.send(message);
jmsConnection.close();
}
I have a deployed an ear with an MDB that should be listening to the queue and actioning the message:
#MessageDriven(mappedName = "jms/ProcessBatchQueue")
public class BatchReceiver
{
private final Logger log = LoggerFactory.getLogger(BatchReceiver.class);
public void onMessage(Message message)
{
log.info("Received message from jms/ProcessBatchQueue: " + message);
try
{
if (message instanceof TextMessage)
{
String batchId = ((TextMessage) message).getText();
// do processing
}
else
{
log.error("Received invalid message type from jms/ProcessBatchQueue");
}
}
catch (Exception ex)
{
String error = "Received error '" + ex.toString()
+ "' retrieving message from jms/BatchProcessingTopic.";
Throwable linkedEx = ex.getCause();
if (linkedEx != null)
{
log.error(error += "Linked exception: " + linkedEx.getMessage(),
linkedEx);
}
else
{
log.error(error + ", " + ex.getMessage(), ex);
}
}
}
}
In my war logs, I get the
log.info("Attempting to send process batch message for batch ID: " + batchID);
statement, but in the ear logs, I get nothing that would indicate that the MDB is receiving the message.
My understanding is that I should be able to "just" deploy the ear with the MDB and it should start receiving the messages. Is there a config step that I've missed?
Is there some way to confirm that the message generated in the servlet is making it to the queue in the first place? There are no errors in any log including server.log.
Your bean does not implement javax.jms.MessageListener, it just has an onMessage() method with a the same signature.
It's also possible that you miss the activationConfig part of the annotation, but I'm not sure if it's required in Java EE 6. See if it's the case anyway:
#MessageDriven(
activationConfig = {
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "ProcessBatchQueue")},
mappedName = "jms/ProcessBatchQueue")
Related
# Here is my settings.cfg file:
# Thank you.Here is what i tried.My settings.cfg file
[DEFAULT]
# Settings which apply to all the Sessions.
ConnectionType=initiator
LogonTimeout=30
ReconnectInterval=20
ResetOnLogon=Y
FileLogPath=C:\Work\QuickFIXJ\logs
FileStorePath=C:\Work\QuickFIXJ\logs
[SESSION]
# Settings specifically for one session
BeginString=FIX.4.4
SenderCompID=XYZ
TargetCompID=TYZ
TimeZone=Asia/Tokyo
StartTime=16:00:00
EndTime=13:30:00
HeartBtInt=60
SocketConnectPort=7200
SocketConnectHost=123.123.123.123
UseDataDictionary=Y
DataDictionary=C:\Work\QuickFIXJ\datadictionary\FIX44.xml
[GATEWAY]
Port=4444
[TRANSPORT]
Port=4444
and then
//initiator code:
public class TestQuickFixJConnectivity {
public static void main(String[] args) {
SocketInitiator socketInitiator = null;
try {
SessionSettings sessionSettings = new SessionSettings("C:\\Work\\QuickFixJ\\sessionSettings.txt");
Application application = new TestApplicationImpl();
FileStoreFactory fileStoreFactory = new FileStoreFactory(sessionSettings);
FileLogFactory logFactory = new FileLogFactory(sessionSettings);
MessageFactory messageFactory = new DefaultMessageFactory();
socketInitiator = new SocketInitiator(application,
fileStoreFactory, sessionSettings, logFactory,
messageFactory);
socketInitiator.start();
SessionID sessionId = socketInitiator.getSessions().get(0);
sendLogonRequest(sessionId);
int i = 0;
do {
try {
Thread.sleep(1000);
System.out.println(socketInitiator.isLoggedOn());
} catch (InterruptedException e) {
e.printStackTrace();
}
i++;
} while ((!socketInitiator.isLoggedOn()) && (i < 30));
} catch (ConfigError e) {
e.printStackTrace();
} catch (SessionNotFound e) {
e.printStackTrace();
} catch (Exception exp) {
exp.printStackTrace();
} finally {
if (socketInitiator != null) {
socketInitiator.stop(true);
}
}
}
private static void sendLogonRequest(SessionID sessionId) throws SessionNotFound {
Logon logon = new Logon();
Message msg=new Message();
Header header = msg.getHeader();
logon.set(new HeartBtInt(60));
logon.set(new ResetSeqNumFlag(true));
header.setField(new BeginString("FIX.4.4"));
header.setField(new MsgType("AP"));
header.setField(new SenderCompId("XYZ"));
header.setField(new TagetCompId("TYZ"));
header.setField(new ResetSeqNumFlag(true));
//here i m setting all the fields in the csv report .
msg.setField(705,new SortQty(""));
// ....
//below statement returning false
boolean sent = Session.sendToTarget(msg, sessionId);
System.out.println("Logon Message Sent : " + sent);
}
}
Please find my observations below:
In the event logs I am seeing as Created session: and the message which I am trying to send. Also I could see that the sender sequence number is getting incremented in the logs.
Messages.log and header.logs are blank and body.log has the message which i am trying to send.
Also onCreate and ToApp are being called when I try to run the code.
I want to know whether i have sent the message successfully ?
Also boolean sent = Session.sendToTarget(msg, sessionId); is returning false.
I don't see ToAdmin and FromAdmin being executed in my code. Also Do I need to write the acceptor code as well for the same, or just the initiator code will be fine. The DataDictionary which i am using has all the fields set, but I am not sure whether its being used by QuickFixJ when i try to execute the code.
Please advise whats going wrong in this?
OK your settings file looks ok and you're saying it works, but I don't think you need GATEWAY and TRANSPORT headings
As for your code, all you need to do to start with is setup the default QuickFIX Application, FileStoreFactory, LogFactory, MessageFactory and Initiator which you have done.
The default QuickFIX automatically logs on to the Target in your settings file, and if the logon is accepted then it begins to heartbeat. From your comments it sounds like this is happening.
So what's going wrong is your sendLogonRequest is not necessary. Also, if you do send "extra" logons then the target FIX engine will probably reject or ignore them. The reject message would be seen in the logs or file store.
So then you have the QuickFIX API with which to start with you can simply output messages to your own log.
Something like this
public void fromApp(Message msg, SessionID s) throws UnsupportedMessageType, FieldNotFound, IncorrectTagValue
{
log.debug(String.valueOf(LocalTime.now()) + " INITIATOR: FromApp " + msg.toString());
}
public void toApp(Message msg, SessionID s)
{
log.info(String.valueOf(LocalTime.now()) + " INITIATOR: ToApp " + msg.toString());
}
public void fromAdmin(Message msg, SessionID s) throws FieldNotFound, IncorrectTagValue
{
Log.trace("INITIATOR: FromAdmin " + msg.getClass() + " " + msg.toString());
}
public void onCreate(SessionID s)
{
log.info("INITIATOR: OnCreate " + s.toString());
}
public void onLogout(SessionID s)
{
log.error("INITIATOR: OnLogout " + s.toString());
}
public void onLogon(SessionID s)
{
log.info("INITIATOR: OnLogon " + s.toString());
}
public void toAdmin(Message msg, SessionID s)
{
log.trace("INITIATOR: ToAdmin " + msg.getClass() + " " + msg.toString());
}
Then when you want to send a message, try something like this:
QuoteReqID id = new QuoteReqID("1234");
// Create Quote Request message
QuoteRequest qr = new QuoteRequest(id);
// Setup outgoing group and specify an index for each group tag
NoRelatedSym g = new NoRelatedSym();
String instrument = m.getString("EUR/USD");
Symbol symbol = new Symbol(instrument);
g.setField(1, symbol);
QuoteRequestType qt = new QuoteRequestType(102);
g.setField(2, qt);
OrderQty qty = new OrderQty("1000000");
g.setField(3, qty);
SettlType sType = new SettlType("B");
g.setField(4, sType);
SettlDate sDate = new SettlDate("20170315");
g.setField(5, sDate);
Account account = new Account("357647");
g.setField(6, account);
// add group to request
qr.addGroup(g);
Session s = Session.lookupSession(i.getSessions().get(0));
s.send(qr);
I have a distributed queue on Weblogic. Messages are read from the queue using JMS onMessage() function. However the messages are not purged from the queue as long as the deployment is running. The message state string is always 'receive'. How do we ensure that the message is not picked up again in case a restart of the deployment is done?
#Override
public void onMessage(Message msg) {
try {
String msgText;
if (msg instanceof TextMessage) {
msgText = ((TextMessage) msg).getText();
} else {
msgText = msg.toString();
}
System.out.println("Message Received from Message_RESPONSE_QUEUE: " + msgText + " - " + count++);
// now send the message to queue2
InitialContext ic2 = getInitialContext2();
getMsgFromQueue qs = new getMsgFromQueue();
qs.init2(ic2, QUEUE2);
qs.send(msg, null);
} catch (JMSException jmse) {
} catch (NamingException ex) {
Logger.getLogger(getMsgFromQueue.class.getName()).log(Level.SEVERE, null, ex);
}
}
The message from the JMS queue does not get removed until JMS server receives an acknowledgement.
Here's some references that you may find useful -
http://docs.oracle.com/cd/E17904_01/web.1111/e15493/prog_details.htm#i1156227
http://docs.oracle.com/cd/E17904_01/web.1111/e15493/prog_details.htm#i1152248
http://docs.oracle.com/cd/E17904_01/web.1111/e15493/prog_details.htm#i1156227
I am trying to create a synchronous request using JMS on JBoss
Code for MDB is:
#Resource(mappedName = "java:/ConnectionFactory")
private ConnectionFactory connectionFactory;
#Override
public void onMessage(Message message) {
logger.info("Received message for client call");
if (message instanceof ObjectMessage) {
Connection con = null;
try {
con = connectionFactory.createConnection();
con.start();
Requests requests = (Requests) ((ObjectMessage) message)
.getObject();
String response = getClient().get(getRequest(requests));
con = connectionFactory.createConnection();
Session ses = con.createSession(true, Session.AUTO_ACKNOWLEDGE);
MessageProducer producer = ses.createProducer(message
.getJMSReplyTo());
TextMessage replyMsg = ses.createTextMessage();
replyMsg.setJMSCorrelationID(message.getJMSCorrelationID());
replyMsg.setText(response);
logger.info("Sending reply to client call : " + response );
producer.send(replyMsg);
} catch (JMSException e) {
logger.severe(e.getMessage());
} finally {
if (con != null) {
try {
con.close();
} catch (Exception e2) {
logger.severe(e2.getMessage());
}
}
}
}
}
Code for client is:
#Resource(mappedName = "java:/ConnectionFactory")
private QueueConnectionFactory queueConnectionFactory;
#Resource(mappedName = "java:/queue/request")
private Queue requestQueue;
#Override
public Responses getResponses(Requests requests) {
QueueConnection connection = null;
try {
connection = queueConnectionFactory.createQueueConnection();
connection.start();
QueueSession session = connection.createQueueSession(false,
Session.AUTO_ACKNOWLEDGE);
MessageProducer messageProducer = session
.createProducer(requestQueue);
ObjectMessage message = session.createObjectMessage();
message.setObject(requests);
TemporaryQueue temp = session.createTemporaryQueue();
MessageConsumer consumer = session.createConsumer(temp);
message.setJMSReplyTo(temp);
messageProducer.send(message);
Message response = consumer.receive();
if (response instanceof TextMessage) {
logger.info("Received response");
return new Responses(null, ((TextMessage) response).getText());
}
} catch (JMSException e) {
logger.severe(e.getMessage());
} finally {
if (connection != null) {
try {
connection.close();
} catch (Exception e2) {
logger.severe(e2.getMessage());
}
}
}
return null;
}
The message is received fine on the queue, the response message is created and the MessageProducer sends the response without issue, with no errors. However the consumer just sits and waits indefinitely. I have also tried creating a separate reply queue rather then using a temporary queue and the result is the same.
I am guessing that I am missing something basic with this set up but I cannot for the life of me see anything I am doing wrong.
There is no other code, the 2 things I have read on this that can cause problems is that the connection.start() isn't called or the repsonses are going to some other different receiver, which isn't happening here (as far as I know - there are no other messaging parts to the code outside of these classes yet)
So I guess my question is, should the above code work or am I missing some fundamental understanding of the JMS flow?
So..I persevered and I got it to work.
The answer is that when I create the session, the transacted attribute in both the client and the MDB had to be set to false:
Session ses = con.createSession(true, Session.AUTO_ACKNOWLEDGE);
had to be changed to:
Session ses = con.createSession(false, Session.AUTO_ACKNOWLEDGE);
for both client and server.
I know why now! I am effectively doing the below which is taken from the Oracle JMS documentation!
If you try to use a request/reply mechanism, whereby you send a message and then try to receive a reply to the sent message in the same transaction, the program will hang, because the send cannot take place until the transaction is committed. The following code fragment illustrates the problem:
// Don’t do this!
outMsg.setJMSReplyTo(replyQueue);
producer.send(outQueue, outMsg);
consumer = session.createConsumer(replyQueue);
inMsg = consumer.receive();
session.commit();
I have a MDB running on JBoss 7.1, and a simple Java application as a client on another machine. The goal is the following:
the client sends a request (ObjectMessage) to the server
the server processes the request and sends back a response to the client (ObjectMessage again)
I thought to use a TemporaryQueue on the client to listen for the response (because I don't know how to do it asynchronously), and the JMSReplyTo Message's property to correctly reply back because I should support multiple independent clients.
This is the client:
public class MessagingService{
private static final String JBOSS_HOST = "localhost";
private static final int JBOSS_PORT = 5455;
private static Map connectionParams = new HashMap();
private Window window;
private Queue remoteQueue;
private TemporaryQueue localQueue;
private ConnectionFactory connectionFactory;
private Connection connection;
private Session session;
public MessagingService(Window myWindow){
this.window = myWindow;
MessagingService.connectionParams.put(TransportConstants.PORT_PROP_NAME, JBOSS_PORT);
MessagingService.connectionParams.put(TransportConstants.HOST_PROP_NAME, JBOSS_HOST);
TransportConfiguration transportConfiguration = new TransportConfiguration(NettyConnectorFactory.class.getName(), connectionParams);
this.connectionFactory = (ConnectionFactory) HornetQJMSClient.createConnectionFactoryWithoutHA(JMSFactoryType.CF, transportConfiguration);
}
public void sendRequest(ClientRequest request) {
try {
connection = connectionFactory.createConnection();
this.session = connection.createSession(false, QueueSession.AUTO_ACKNOWLEDGE);
this.remoteQueue = HornetQJMSClient.createQueue("testQueue");
this.localQueue = session.createTemporaryQueue();
MessageProducer producer = session.createProducer(remoteQueue);
MessageConsumer consumer = session.createConsumer(localQueue);
ObjectMessage message = session.createObjectMessage();
message.setObject(request);
message.setJMSReplyTo(localQueue);
producer.send(message);
ObjectMessage response = (ObjectMessage) consumer.receive();
ServerResponse serverResponse = (ServerResponse) response.getObject();
this.window.dispatchResponse(serverResponse);
this.session.close();
} catch (JMSException e) {
// TODO splittare e differenziare
e.printStackTrace();
}
}
Now I'm having troubles writing the server side, as I cannot figure out how to establish a Connection to a TemporaryQueue...
public void onMessage(Message message) {
try {
if (message instanceof ObjectMessage) {
Destination replyDestination = message.getJMSReplyTo();
ObjectMessage objectMessage = (ObjectMessage) message;
ClientRequest request = (ClientRequest) objectMessage.getObject();
System.out.println("Queue: I received an ObjectMessage at " + new Date());
System.out.println("Client Request Details: ");
System.out.println(request.getDeparture());
System.out.println(request.getArrival());
System.out.println(request.getDate());
System.out.println("Replying...");
// no idea what to do here
Connection connection = ? ? ? ? ? ? ? ?
Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
MessageProducer replyProducer = session.createProducer(replyDestination);
ServerResponse serverResponse = new ServerResponse("TEST RESPONSE");
ObjectMessage response = session.createObjectMessage();
response.setObject(serverResponse);
replyProducer.send(response);
} else {
System.out.println("Not a valid message for this Queue MDB");
}
} catch (JMSException e) {
e.printStackTrace();
}
}
I cannot figure out what am I missing
You are asking the wrong question here.. You should look at how to create a Connection inside any Bean.
you need to get the ConnectionFactory, and create the connection accordingly.
For more information, look at the javaee examples on the HornetQ download.
In specific look at javaee/mdb-tx-send/ when you download hornetq.
#MessageDriven(name = "MDBMessageSendTxExample",
activationConfig =
{
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue"),
#ActivationConfigProperty(propertyName = "destination", propertyValue = "queue/testQueue")
})
public class MDBMessageSendTxExample implements MessageListener
{
#Resource(mappedName = "java:/JmsXA")
ConnectionFactory connectionFactory;
public void onMessage(Message message)
{
Connection conn = null;
try
{
// your code here...
//Step 11. we create a JMS connection
conn = connectionFactory.createConnection();
//Step 12. We create a JMS session
Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
//Step 13. we create a producer for the reply queue
MessageProducer producer = sess.createProducer(replyDestination);
//Step 14. we create a message and send it
producer.send(sess.createTextMessage("this is a reply"));
}
catch (Exception e)
{
e.printStackTrace();
}
finally
{
if(conn != null)
{
try
{
conn.close();
}
catch (JMSException e)
{
}
}
}
}
I am a newer for EJB3 dev.
When I write a EJB3 mdb and I want to deploy it to my jboss (jboss-4.2.3.GA)
some error info is here:
--- MBeans waiting for other MBeans --- ObjectName: jboss.j2ee:jar=HelloWorldEjb.jar,name=QueneMDB01,service=EJB3 State:
FAILED Reason: org.jboss.deployment.DeploymentException: Required
config property RequiredConfigPropertyM
etaData#12c08c7[name=destination
descriptions=[DescriptionMetaData#1941dc9[language=zh]]] for messag
ingType 'javax.jms.MessageListener' not found in activation config
[ActivationConfigProperty(destina tionType=javax.jms.Queue),
ActivationConfigProperty(acknowledgeMode=Auto-acknowledge)]
ra=jboss.jca: service=RARDeployment,name='jms-ra.rar'
--- MBEANS THAT ARE THE ROOT CAUSE OF THE PROBLEM --- ObjectName: jboss.j2ee:jar=HelloWorldEjb.jar,name=QueneMDB01,service=EJB3 State:
FAILED Reason: org.jboss.deployment.DeploymentException: Required
config property RequiredConfigPropertyM
etaData#12c08c7[name=destination
descriptions=[DescriptionMetaData#1941dc9[language=zh]]] for messag
ingType 'javax.jms.MessageListener' not found in activation config
[ActivationConfigProperty(destina tionType=javax.jms.Queue),
ActivationConfigProperty(acknowledgeMode=Auto-acknowledge)]
ra=jboss.jca: service=RARDeployment,name='jms-ra.rar'
and my mdb is :
#MessageDriven(activationConfig = {
#ActivationConfigProperty(propertyName = "acknowledgeMode", propertyValue = "Auto-acknowledge"),
#ActivationConfigProperty(propertyName = "destinationType", propertyValue = "javax.jms.Queue") })
public class QueneMDB01 implements MessageListener
{
public void onMessage(Message msg) {
// TODO Auto-generated method stub
try {
TextMessage textMessage = (TextMessage) msg;
System.out.println("MyQueneMDBBean is called "
+ textMessage.getText() + " ");
} catch (JMSException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
From your error i'd say you forgot to add the destination name (queue name probably).
FAILED Reason: org.jboss.deployment.DeploymentException: Required config property RequiredConfigPropertyM etaData#12c08c7[name=destination descriptions=[DescriptionMetaData#1941dc9[language=zh]]
Example:
http://www.javaissues.com/2011/06/ejb3-message-driven-bean-hello-world.html
BTW, you've set up your queues/topics in JBoss right?
Hope this helps,
Dave