/*
* Copyright (c) 1998-2000, Fiorano Software, Inc.
* All Rights Reserved
*
* JMS-EJB Integration Sample
*
* FileName : Subscriber.java
*
* Implements an asynchronous listener to listen
* for messages published on the queue - "primaryQueue".
*
* Receives JMS Messages that were published on the Queue,
* demarshalls the content of the JMS Message to lookup and
* invoke appropriate methods on the EJB with appropriate
* parameters using reflection.
*
*
* USAGE::
* java -Djava.naming.factory.initial=AppServer'sInitialContext Subscriber
*
* Questions/comments/suggestions?
* Please visit: http://www.fiorano.com
* or e-mail: [email protected]
*
* @since 4.4, May 2000
*/
import javax.jms.*;
import javax.ejb.*;
import javax.naming.*;
import javax.rmi.*;
import java.lang.reflect.*;
import java.util.*;
import fiorano.jms.rtl.FioranoInitialContext;
/**
* This class can be run as a stand-alone JMS Application
* The JVM should have a reference of hte appropriate Server
* interfaces (Home/Remote Interfaces of all EJB's that need to be
* invoked) in its CLASSPATH.
*
* Alternatively, this class can also be made as a startup
* class, so that the AppServer is responsible for starting
* and stopping this class within the AppServer's JVM instance.
*
* The main disadvantage of making this class as a startup class
* is the non-proprietary nature of the support for the startup
* classes by the various AppServer vendors.
*
*/
class Subscriber implements MessageListener,ExceptionListener
{
// String identifying the message type
private static final String FIORANO_EJB_MESSAGE = "FIORANO_EJB_MESSAGE";
// AppServer's InitialContext
private InitialContext m_appServerContext;
public static void main (String args[])
{
Subscriber subscriber = new Subscriber ();
try
{
// 1. Create the InitialContext Object used for looking up
// JMS administered objects on the FioranoMQ
// located on the default host.
FioranoInitialContext ic = new FioranoInitialContext ();
ic.bind ();
// 1.1 Lookup Connection Factory and Queue names
//
QueueConnectionFactory qcf =
(QueueConnectionFactory) ic.lookup ("primaryQCF");
Queue queue = (Queue)ic.lookup("primaryQueue");
// 1.2 Dispose the InitialContext resources
//
ic.dispose();
// 2. create and start a queue connection
System.out.println("Creating queue connection");
QueueConnection queueConnection = qcf.createQueueConnection();
// Register an Exception Listner
queueConnection.setExceptionListener (subscriber);
queueConnection.start ();
// 3. create queue session on the connection just created
System.out.println("Creating queue session: not transacted, auto ack");
QueueSession queueSession = queueConnection.createQueueSession(false,1);
// 4. create subscriber
System.out.println("Creating queue, subscriber");
QueueReceiver queueReceiver = queueSession.createReceiver(queue);
// 5. install an asynchronous listener/callback on the subscriber object
// just created
System.out.println ("Ready to subscribe for messages :");
queueReceiver.setMessageListener (new Subscriber ());
}
catch (Exception e)
{
e.printStackTrace ();
}
}
/**
* Message listener which receives messages aysynchronously
* for the bound subscriber.
*
* Read the message properties, and lookup the appropriate
* EJB. Invoke appropriate method on the EJB.
*
* @param Message, received JMS Message
*/
public void onMessage (Message msg)
{
try
{
String msgType = msg.getJMSType();
// Check whether the received messages is
// an EJB invocation message.
if (msgType.equals(FIORANO_EJB_MESSAGE))
{
// Get the contents of the message to invoke apppropriate EJB
String beanName = msg.getStringProperty(JMSConstants.EJB_NAME);
String constName = msg.getStringProperty(JMSConstants.CONST);
int nConstArgs = msg.getIntProperty(JMSConstants.CONST_N_ARGS);
String methodName = msg.getStringProperty(JMSConstants.METHOD_NAME);
int nMethodArgs = msg.getIntProperty(JMSConstants.METHOD_N_ARGS);
// Get Appserver's InitialContext to lookup appropriate Bean references
if (m_appServerContext == null)
{
// Please make sure to set appropriate System
// property.
// In case of WebLogic AppServer, set property
// java.naming.factory.initial=weblogic.jndi.T3InitialContextFactory
//Properties prop = System.getProperties ();
//prop.put ("java.naming.factory.initial", "weblogic.jndi.T3InitialContextFactory");
System.setProperties (prop);
try
{
m_appServerContext = new InitialContext();
}
catch (NamingException err)
{
System.out.println ("Unable to initialize AppServer's InitialContext. Please ensure" +
"to set System property java.naming.factory.initial");
err.printStackTrace ();
}
}
if (m_appServerContext != null)
{
try
{
// Get the constructor types and args to create appropriate EJB
Class[] constTypes = getClassTypesFromMessage(msg, nConstArgs, JMSConstants.CONST, JMSConstants.CONST_TYPE);
Object[] constArgs = getArgumentsFromMessage(msg, nConstArgs, JMSConstants.CONST,JMSConstants.CONST_TYPE );
// Get the class type and parameters for the EJBObject (stub) method to invoke...
Class[] methodTypes = getClassTypesFromMessage(msg, nMethodArgs, JMSConstants.METHOD_NAME, JMSConstants.METHOD_TYPE);
Object[] methodArgs = getArgumentsFromMessage(msg, nMethodArgs, JMSConstants.METHOD_NAME, JMSConstants.METHOD_TYPE);
// Find our home class through JNDI...
Object obj = m_appServerContext.lookup(beanName);
Class beanClass = obj.getClass();
// Find the create method...
Method methodCreate = beanClass.getMethod(constName, constTypes);
// Invoke the create method...
Object ejb = methodCreate.invoke(obj, constArgs);
System.out.println("Received Event. Invoking EJB::Method()" + methodName);
// Find the EJB method in the JMS Message...
Method methodCall = ejb.getClass().getMethod(methodName, methodTypes);
// Invoke the EJB method...
methodCall.invoke(ejb, methodArgs);
}
catch(InvocationTargetException e)
{
System.out.println("ReceiverStartup: InvocationTargetException was thrown");
}
catch(NoSuchMethodException e)
{
System.out.println("ReceiverStartup: NoSuchMethodException was thrown");
}
catch(IllegalAccessException e)
{
System.out.println("ReceiverStartup: IllegalAccessException was thrown");
}
catch(Exception e)
{
System.out.println("ReceiverStartup: An exception was thrown");
}
}
else
System.out.println("JMSSubscription:: Startup Failure");
}
}
catch (JMSException e)
{
e.printStackTrace();
}
}
/**
* Get Class Type from Message
*
* @param message
* @param no of args
* @param argument Name
* @param type name
*/
private Class[] getClassTypesFromMessage (Message msg, int params, String argName, String typeName)
throws JMSException
{
Class[] types = new Class[0];
if (params > 0)
{
types = new Class[params];
for (int i = 0; i < params; i++)
{
String type = msg.getStringProperty(typeName + i);
if (type.equals("String"))
{
types[i] = String.class;
}
else if (type.equals("int"))
{
types[i] = int.class;
}
else if (type.equals("long"))
{
types[i] = long.class;
}
else if (type.equals("float"))
{
types[i] = float.class;
}
else if (type.equals("double"))
{
types[i] = double.class;
}
else if (type.equals("short"))
{
types[i] = short.class;
}
else if (type.equals("byte"))
{
types[i] = byte.class;
}
else if (type.equals("object"))
{
// Extract any type of object...
Object obj = msg.getObjectProperty(argName + i);
types[i] = obj.getClass();
System.out.println("Object instance: " + obj.getClass().getName());
}
else if (type.equals("Message"))
{
types[i] = Message.class;
}
else
System.out.println("Unknown parameter type");
}
}
return types;
}
/**
* Get Arguments Type from Message
*
* @param message
* @param no of args
* @param argument Name
* @param type name
*
* @exception JMSException if the operation fails
*/
private Object[] getArgumentsFromMessage(Message msg, int params, String argName, String argType)
throws JMSException
{
Object[] args = new Object[0];
if (params > 0)
{
args = new Object[params];
for (int i = 0; i < params; i++)
{
String type = msg.getStringProperty(argType + i);
System.out.println ("Arg Type" + argType + " Value" + type);
if (type.equals("String"))
{
String temp = msg.getStringProperty(argName + i);
args[i] = temp;
}
else if (type.equals("int"))
{
int temp = msg.getIntProperty(argName + i);
args[i] = new Integer(temp);
}
else if (type.equals("long"))
{
long temp = msg.getLongProperty(argName + i);
args[i] = new Long(temp);
}
else if (type.equals("float"))
{
float temp = msg.getFloatProperty(argName + i);
args[i] = new Float(temp);
}
else if (type.equals("double"))
{
double temp = msg.getDoubleProperty(argName + i);
args[i] = new Double(temp);
}
else if (type.equals("short"))
{
short temp = msg.getShortProperty(argName + i);
args[i] = new Short(temp);
}
else if (type.equals("byte"))
{
byte temp = msg.getByteProperty(argName + i);
args[i] = new Float(temp);
}
else if (type.equals("object"))
{
Object obj = msg.getObjectProperty(argName + i);
args[i] = obj;
}
else if (type.equals("Message"))
{
args[i] = (javax.jms.Message)msg;
}
// You could add other types here...Object,etc...
else
System.out.println("Unknown parameter type");
}
}
return args;
}
/**
* If a JMS provider detects a serious problem with a
* Connection this method is invoked passing it a JMSException
* describing the problem.
*
* @param JMSException e
*/
public void onException (JMSException e)
{
//Report the Error and take necessary Error handling measures
String error = e.getErrorCode ();
System.out.println (error);
}
}