package examples.xml.biztalk;
import java.io.*;
import java.rmi.RemoteException;
import java.util.Date;
import java.util.Hashtable;
import java.util.Vector;
import javax.ejb.CreateException;
import javax.jms.*;
import javax.jts.*;
import javax.naming.*;
import org.w3c.dom.*;
import examples.xml.biztalk.ejb.*;
import weblogic.jndi.Environment;
import weblogic.xml.dom.*;
/**
* BizServer pulls messages off of the BizTalk queue, constructs
* a DOMIncomingMessage
* and dispatches it to registered BizBeans. Within the
* <font face="Courier New" size = -1>waitForMessages</font> method,
* the QueueReceiver does an explicit receive. This means that
* this is a singled-threaded implementation, i.e. the thread running the server
* will pause until a message is received. To make this a mutli-threaded application,
* you would have to implement the JMS MessageListener interface. See
* WebLogic JMS documentation for more information.
* <P>
* A BizServer can be run using the examples.xml.biztalk.AdminCLU utility.
*
* @author Copyright (c) 2000 by BEA Systems, Inc. All Rights Reserved.
*/
public class BizServer {
public final static String JNDI_FACTORY= "weblogic.jndi.WLInitialContextFactory";
public final static String JMS_FACTORY= "javax.jms.QueueConnectionFactory";
private QueueConnectionFactory qconFactory;
private QueueConnection qconSender;
private QueueSession qsessionSender;
private QueueSender qsender;
private Queue outqueue=null;
private TextMessage outmsg;
private QueueConnection qconReceiver;
private QueueSession qsessionReceiver;
private QueueReceiver qreceiver;
private Queue inqueue=null;
private TextMessage inmsg;
private Context context;
private static BizBeanHome ejbHome;
private PrintWriter log;
private BizConfig config;
private boolean verbose = true;
boolean quit = false;
private String logname;
public static void main(String args[]) throws Exception {
if (args.length != 1) {
System.err.println("Usage: examples.xml.biztalk.BizServer <servername>");
System.exit(0);
}
BizServer s = new BizServer(args[0]);
while (!s.quit) {
s.waitForMessages();
}
s.log.println("Exiting");
if (s.inqueue != null) s.closeInQ();
if (s.outqueue != null) s.closeOutQ();
s.log.close();
}
public PrintWriter getLog() {return log;}
/*
* Constructs a BizServer object associated with the named configuration.
* Config information for this server is located in the configuration
* file, <I>name</I>.xml, where <I>name</I> is the constructor's parameter.
*
* @param name of this server. Used to locate configuration and log file.
*/
public BizServer(String name) {
try {
context = (new Environment()).getInitialContext();
}
catch (NamingException namee) {
System.err.println("Unable to establish JNDI context.");
quit = true;
return;
}
config = new BizConfig();
verbose = config.getVerbose();
//
// open log
//
String separator = System.getProperty("file.separator");
logname = config.getBizHome()+separator+name+".log";
try {
log = new PrintWriter( new FileOutputStream(logname, true), true);
log.println("Starting Bizserver: "+name);
}
catch (IOException ioe) {
System.err.println("Unable to open log file, "+logname+". Using System.err");
log = new PrintWriter(System.err, true);
logname = "stderr";
}
config.setLog(log);
//
// load config file
//
Date date = new Date();
if (verbose) log.println(date.toString()+" Starting...");
if (!config.loadConfig(name)) {
log.println("Invalid config file, "+config.getConfigFile());
quit = true;
return;
}
//
// create queues
//
try {
initInQ(config.getInQ());
initOutQ(config.getErrorQ());
}
catch (NamingException namee) {
log.println("Unable to establish context.");
quit = true;
return;
}
catch (JMSException jmse) {
log.println("Unable to create JMS connection.");
quit = true;
return;
}
}
/**
* Sets up the output queue.
*
* @param outQ Output queue name
*
* @exception NamingException unable to establish context
* @exception JMSException unable to setup JMS queue
*/
private void initOutQ(String outQ)
throws NamingException, JMSException {
initSender(context, outQ);
}
/**
* Sets up the input queue.
*
* @param inQ Input queue name
* @param outQ Output queue name
*
* @exception NamingException unable to establish context
* @exception JMSException unable to setup JMS queue
*/
private void initInQ(String inQ)
throws NamingException, JMSException {
initReceiver(context, inQ);
}
private void initSender(Context ctx, String queueName)
throws NamingException, JMSException
{
// Look up the ConnectionFactory
qconFactory = (QueueConnectionFactory)ctx.lookup(JMS_FACTORY);
// Get a QueueConnection from the
// QueueConnectionFactory
qconSender = qconFactory.createQueueConnection();
// Get a QueueSession that is not transacted
// and acknowledges automatically
qsessionSender = qconSender.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
// Look up the Queue
outqueue = (Queue) ctx.lookup(queueName);
// Create a message producer (QueueSender)
// for the Queue we looked up.
qsender = qsessionSender.createSender(outqueue);
// Create a message object
outmsg = qsessionSender.createTextMessage();
// Start the connection
qconSender.start();
}
/**
* Send a message to the queue. Use the QueueSender's default delivery mode, timeToLive and priority.
*
* @param the message to be sent
* @exception JMSException if JMS fails to send the message due to some internal error.
* @exception MessageFormatException if invalid message specified
* @exception InvalidDestinationException if a client uses this method with a Queue sender with an invalid queue.
*/
private void send(String message) throws JMSException
{
outmsg.setText(message);
qsender.send(outmsg);
}
/**
* Send a message to the queue. Use the QueueSender's default delivery mode, timeToLive and priority.
*
* @param the message to be sent
* @exception JMSException if JMS fails to send the message due to some internal error.
* @exception MessageFormatException if invalid message specified
* @exception InvalidDestinationException if a client uses this method with a Queue sender with an invalid queue.
*/
private void send(Message message) throws JMSException
{
if (verbose) log.println("sending");
qsender.send(message);
}
/**
* Close out queue connections
*
* @exception JMSException if JMS fails to close out due to some error.
*/
private void closeOutQ()
throws JMSException
{
try {
qsender.close();
qsessionSender.close();
qconSender.close();
}
catch (JMSException jmse) {}
}
/**
* Close out queue connections
*
* @exception JMSException if JMS fails to close out due to some error.
*/
private void closeInQ()
throws JMSException
{
try {
qreceiver.close();
qsessionReceiver.close();
qconReceiver.close();
}
catch (JMSException jmse) {}
}
private void initReceiver(Context ctx, String queueName)
throws NamingException, JMSException
{
// Look up the ConnectionFactory
qconFactory = (QueueConnectionFactory)ctx.lookup(JMS_FACTORY);
qconReceiver = qconFactory.createQueueConnection();
qsessionReceiver = qconReceiver.createQueueSession(false,Session.AUTO_ACKNOWLEDGE);
try {
inqueue = (Queue) ctx.lookup(queueName);
} catch (NamingException ne) {
inqueue = qsessionReceiver.createQueue(queueName);
ctx.bind(queueName, inqueue);
}
if (verbose) log.println("Connected to "+inqueue.toString());
qreceiver = qsessionReceiver.createReceiver(inqueue);
qconReceiver.start();
}
/**
* Wait for a message to arrive. The message
* is validated as a Biztalk document, parsed into a
* DOMIncomingMessage object and passed to registered beans.
*
*/
public void waitForMessages() {
String txt;
boolean route = false;
Message message;
try {
message = qreceiver.receive();
}
catch (JMSException jmse) {
log.println(jmse.getMessage());
return;
}
if (verbose) log.println("Message received.");
try {
if (message instanceof TextMessage) {
txt = ((TextMessage)message).getText();
}
else {
txt = message.toString();
}
}
catch (JMSException jmse) {
log.println("Unable to retrieve text from message.");
routeIt(message);
return;
}
if (verbose) log.println("JMS message text: "+txt);
try {
if (verbose) log.println ("Parsing message...");
IncomingMessage im = new DOMIncomingMessage(txt);
//
// obtain beans assoc with this doctype and service each one.
// Route to other server as nec.
//
String myUri = config.getURI();
String toAddr = im.getToAddress();
String docType = im.getType();
if (verbose) log.println("Document type: "+docType);
//
// check for admin message first
//
if (docType.equals(BizConfig.BIZ_ADMIN)) {
if (verbose) {
log.println("Config message received from admin.");
reconfig();
return;
}
}
if (docType.equals(BizConfig.BIZ_STOP)) {
if (verbose) {
log.println("Shutdown message received from admin.");
shutdown();
return;
}
}
route = false; // true -> error handling message
if (myUri != null) {
if (toAddr.equals(myUri)) {
//
// This is the target Bizserver. Service all beans
//
Vector beans = config.getBizBeansForDoc(docType);
for (int j=0;j<beans.size();j++) {
// service this bean
BizBeanHome beanHome = (BizBeanHome) beans.elementAt(j);
try {
if (verbose) log.println("Invoking bean: "+
(beanHome.getClass()).getName());
BizBean bean = beanHome.create();
bean.service(im);
}
catch (CreateException e) {
log.println("Unable to invoke bean: "+
beanHome.getClass().getName());
route = true;
}
}
}
else {
log.println("to address ("+toAddr+") does not match this server's URI ("+myUri+")");
route = true; // wrong location
}
}
} catch (BizException bize) {
log.println("BizException: "+bize.getMessage());
route = true;
}
catch (Exception e){
e.printStackTrace(log);
}
finally {
if (verbose) log.println("finally");
if (route) {
routeIt(message);
}
}
}
private void routeIt(Message msg) {
if (verbose) log.println("routing");
try {
send(msg);
}
catch (JMSException jmse) {
log.println("Unable to queue to error queue, "+config.getErrorQ());
jmse.printStackTrace(log);
}
}
private void reconfig() {
try {
config.reloadConfig();
}
catch (Exception e) {
e.printStackTrace(log);
}
}
private void shutdown() {
log.println("Shutting down.");
quit = true;
}
}