/**
* Redistribution and use of this software and associated documentation
* ("Software"), with or without modification, are permitted provided
* that the following conditions are met:
*
* 1. Redistributions of source code must retain copyright
* statements and notices. Redistributions must also contain a
* copy of this document.
*
* 2. Redistributions in binary form must reproduce the
* above copyright notice, this list of conditions and the
* following disclaimer in the documentation and/or other
* materials provided with the distribution.
*
* 3. The name "Exolab" must not be used to endorse or promote
* products derived from this Software without prior written
* permission of Exoffice Technologies. For written permission,
* please contact info@exolab.org.
*
* 4. Products derived from this Software may not be called "Exolab"
* nor may "Exolab" appear in their names without prior written
* permission of Exoffice Technologies. Exolab is a registered
* trademark of Exoffice Technologies.
*
* 5. Due credit should be given to the Exolab Project
* (http://www.exolab.org/).
*
* THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
* NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
* EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
* INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*
* Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved.
*
* $Id: SimpleQueueListener.java,v 1.3 2001/09/25 05:57:18 jima Exp $
*
* Date Author Changes
* 04/25/2000 jima Created
*/
package openjms.examples.client.console;
import java.io.PrintStream;
import java.util.Hashtable;
import javax.naming.InitialContext;
import javax.naming.Context;
import javax.jms.DeliveryMode;
import javax.jms.Session;
import javax.jms.QueueConnectionFactory;
import javax.jms.QueueConnection;
import javax.jms.QueueSession;
import javax.jms.QueueReceiver;
import javax.jms.MessageListener;
import javax.jms.Message;
import javax.jms.Queue;
import javax.jms.TextMessage;
import javax.jms.QueueConnectionFactory;
import javax.jms.JMSException;
import org.exolab.jms.util.CommandLine;
import org.exolab.core.logger.LoggerFactory;
import org.exolab.core.logger.LoggerIfc;
import org.exolab.core.logger.LogEventType;
import org.exolab.jms.client.JmsQueueConnectionFactory;
import org.exolab.jms.jndi.JndiConstants;
import org.exolab.jms.jndi.rmi.RmiJndiInitialContextFactory;
/**
* The simple receiver is used to subscribe to a particular queue and receive
* events. It will set a message listener so that events can be pushed down
* to it when they become available.
*/
public class SimpleQueueListener
implements MessageListener, TimerListener
{
public SimpleQueueListener(QueueConnection connection,
QueueReceiver receiver, int ackMode, int seconds)
{
this(connection, receiver, ackMode, false, 0, seconds);
}
public SimpleQueueListener(QueueConnection connection,
QueueReceiver receiver, int ackMode, int count, int seconds)
{
this(connection, receiver, ackMode, true, count, seconds);
}
private SimpleQueueListener(QueueConnection connection,
QueueReceiver receiver, int ackMode,
boolean counting, int count, int seconds)
{
connection_ = connection;
receiver_ = receiver;
ackMode_ = ackMode;
counting_ = counting;
count_ = count;
seconds_ = seconds;
timer_ = new Timer(this, seconds_ * 1000);
timer_.start();
received_ = 0;
}
static public void main(String[] args)
{
try
{
CommandLine cmdline = new CommandLine(args);
if (cmdline.exists("help"))
{
// the help option has been specified, print the usage
// information
usage();
}
else if (cmdline.exists("queue"))
{
// see if an ack mode has been specified. If it hasn't
// then assume CLIENT_ACKNOWLEDGE mode.
int ackMode = Session.CLIENT_ACKNOWLEDGE;
if (cmdline.exists("ackmode"))
{
String mode = cmdline.value("ackmode");
if (mode.equals("auto"))
{
ackMode = Session.AUTO_ACKNOWLEDGE;
}
else if (mode.equals("dups"))
{
ackMode = Session.DUPS_OK_ACKNOWLEDGE;
}
else if (!mode.equals("client"))
{
// ignore all ack modes, to test no acking
ackMode = -1;
}
}
// enable debugging - unbdocumented option
if (cmdline.exists("debug")) {
LoggerIfc logger = LoggerFactory.getLogger();
logger.setLogLevel(LogEventType.Debug);
}
String queue_name = cmdline.value("queue");
if (queue_name != null)
{
// connect to the JNDI server and get a reference to
// root context
Hashtable props = new Hashtable();
String mode = cmdline.value("mode");
String modeType =
RmiJndiInitialContextFactory.class.getName();
if (cmdline.exists("jndiport"))
{
props.put(JndiConstants.PORT_NUMBER_PROPERTY,
new Integer(cmdline.value("jndiport")));
}
if (cmdline.exists("jndihost"))
{
props.put(JndiConstants.HOST_PROPERTY,
cmdline.value("jndihost"));
}
// override the default server name if specified on the
// command line.
if (cmdline.exists("jndiname"))
{
props.put(JndiConstants.NAME_PROPERTY,
cmdline.value("jndiname"));
}
if ((mode != null) &&
(mode.equals("ipc")))
{
System.out.println("Using IPC mode");
modeType =
org.exolab.jms.jndi.mipc.IpcJndiInitialContextFactory.class.getName();
}
props.put(Context.INITIAL_CONTEXT_FACTORY, modeType);
Context context = new InitialContext(props);
// lookup the connection factory from the context
QueueConnectionFactory factory = (QueueConnectionFactory)
context.lookup("JmsQueueConnectionFactory");
// if we can't find the factory then throw an exception
if (factory == null)
{
throw new RuntimeException(
"Failed to locate connection factory");
}
LoggerFactory.getLogger().logDebug("Have the connection factory " + factory);
QueueConnection connection =
factory.createQueueConnection();
connection.start();
QueueSession session =
connection.createQueueSession(false, ackMode);
Queue queue = null;
if (cmdline.exists("persistent"))
{
queue = (Queue)context.lookup(queue_name);
}
else
{
queue = session.createQueue(queue_name);
}
if (queue == null)
{
System.err.println("Failed to get administered object"
+ " exiting.....");
System.exit(-1);
}
// if the 'name' option has been specified then assume a
// durable receiver otherwise transient
QueueReceiver receiver = null;
receiver = session.createReceiver(queue);
int secs = 10;
boolean counted = false;
int count = 1;
if (cmdline.exists("count"))
{
counted = true;
try
{
String value = cmdline.value("count");
count = Integer.parseInt(value);
}
catch (Exception exception)
{
System.err.println("Illegal count value");
System.exit(-1);
}
secs = 5 * 60; // timeout after 5 mins by default
}
if (cmdline.exists("timeout"))
{
secs = Integer.parseInt(cmdline.value("timeout"));
}
SimpleQueueListener listener = (counted)
? new SimpleQueueListener(connection, receiver, ackMode, count, secs)
: new SimpleQueueListener(connection, receiver, ackMode, secs);
receiver.setMessageListener(listener);
System.err.println("Message listener has been set");
}
else
{
System.err.println("Cannot subscribe to messages under "
+ "null queue");
}
}
else
{
// anything else print the usage message
usage();
}
}
catch (Exception exception)
{
System.err.println("Fatal error: " + exception + "\nExiting.....");
System.exit(-1);
}
}
/**
* All messages that for this receiver are pumped down to this method
*
* @param message message to retrieve
*/
public void onMessage(Message message)
{
System.err.print("Received message: " + message + ", ");
++received_;
String mode = "unknown";
String id = "unset";
try
{
if (message.getJMSDeliveryMode() == DeliveryMode.NON_PERSISTENT)
{
mode = "NON_PERSISTENT";
}
else if (message.getJMSDeliveryMode() == DeliveryMode.PERSISTENT)
{
mode = "PERSISTENT";
}
}
catch (JMSException ignore)
{
}
try
{
id = message.getJMSMessageID();
}
catch (JMSException ignore)
{
}
System.err.println("JMSDeliveryMode=" + mode + ", JMSMessageID=" + id);
timer_.reset();
try
{
if (ackMode_ == Session.CLIENT_ACKNOWLEDGE)
{
message.acknowledge();
}
}
catch (JMSException exception)
{
System.err.println("Warning in ack " + exception);
}
if (counting_ && received_ >= count_)
{
try
{
// can't do the close in the same thread as the callback.
// therefore reset the message listener and set the timer
// to do the exist and clean up in another thread. Doing
// a close in the same thread can cause a lockup
receiver_.setMessageListener(null);
timer_.reset(2000);
}
catch (JMSException exception)
{
System.err.println("Could not unset the listener " + exception);
}
}
}
public void onTimeout()
{
exit("No message received in the last " + seconds_ +
" seconds, exiting");
}
/**
* Print out information on running this sevice
*/
static protected void usage()
{
PrintStream out = System.out;
out.println("usage: java " + SimpleQueueListener.class.getName() +
" [options]\n");
out.println("options:");
out.println(" -queue <name> queue to subscribe to.\n");
out.println(" -name <receiver> durable receiver name.\n");
out.println(" -mode <ipc | rmi> " +
"connect using ipc or rmi mode. " +
"Defaults to 'rmi'.\n");
out.println(" -ackmode <auto | client | dups>\n" +
" message acknowledgement mode. " +
"Defaults to 'client'.\n");
out.println(" -persistent " +
"specifies persistent delivery mode.\n");
out.println(" -jndiport <num> port where the jndi server runs.\n");
out.println(" -jndihost <host> host where jndi server runs.\n");
out.println(" -jndiname <name> name of the jndi server\n");
out.println(" -count <num> number of messages to wait for.\n");
out.println(" -timeout <seconds> seconds to wait before exiting.\n");
out.println(" -help displays this screen.\n");
}
private void exit(String message)
{
System.err.println(message);
timer_.stop();
try
{
System.err.println("Calling close on the connection");
connection_.close();
}
catch (Exception error)
{
error.printStackTrace();
}
}
private QueueReceiver receiver_;
private QueueConnection connection_;
private int ackMode_;
private Timer timer_;
private int seconds_;
private boolean counting_;
private int count_;
private int received_;
}