Package net.fp.rp.workflow.message

Source Code of net.fp.rp.workflow.message.JBossTextMessageSender

/*
* Copyright (C) 2004-2006 Paul Browne, http://www.firstpartners.net,
*
* released under terms of the GPL license
* http://www.opensource.org/licenses/gpl-license.php
*
*/
package net.fp.rp.workflow.message;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Hashtable;

import javax.naming.InitialContext;
import javax.naming.NamingException;

import net.fp.rp.common.exception.RpException;
import net.fp.rp.jms.ITestMessageSender;
import net.fp.rp.jms.JmsTextMessageSender;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* Spring Bean for sending JMS Messages. This one uses the JBoss components
* internally (as JBoss is the only app server / environment that has a problem
* with the Spring way of doing things). If you can, use *
*
* @see JmsTextMessageSender for sending JMS messages as it is more robust
*      across different platforms
*
* This code will <b>not</b> work in a non-JBoss environment, as the JBoss
* components do not always map to the 'official' components. This code is also
* very hacky (stable enough for production use, but hard to understand). The
* basic problem is that (a) the JBoss JMS implementation differs ever so
* slightly from the JMS standard and (b) there is a classloading issue when you
* try to compile and run <b>directly</b> against the JBoss implmentation.
*
* A couple of workarounds were tried , including the use of anothe library
* (such as OpenJMS or ActiveMQ). This solves the original problem, but creates
* difficulites elsewhere (e.g. how does ActiveMQ find the JBoss Queue?). This
* solution uses reflection: We do not need to JBoss types at runtime, but can
* defer finding out what they are until 'after' we deploy. The downside is that
* we lose strong typing (e.g. everything becomes java.lang.object).
*
* On a positive note what makes this solution 'less bad': 1) We provide an
* alternative in the shape of
* @see JmsTextMessageSender 2) All the ugly bits are within <b>private</b>
*      methods of the one class 3) If / When we get a solution it is an easy
*      fix - put together a class implementing ITestMessageSender and then
*      change the Spring config file to use that instead. 4) The incoming
*      messaging handling should not be a problem - we can just write a message
*      driven EJB (no need to write JMS related code)
*
* @todo - resolve the issue above
* @todo - optimisation of this class if required for performance
*
* This project uses Apache, Spring, JBoss and other GPL Licenced Code
*
* @author Paul Browne
*/
public class JBossTextMessageSender implements ITestMessageSender {

  private Log log = LogFactory.getLog(getClass());

  // Properties we set
  private String queueName = null;

  private String serverUrl = null;

  private String namingContextFactory = null;

  private String namingUrlPackages = null;

 
 
  /**
   * Due to a combination of classloading issues a non standard implementation
   * of JMS on JBoss , we invoke the methods on a number of the classes below
   * using reflection - ugly , but it works
   */
  public void sendMessage(String messageText) throws RpException {

    log.debug("Queue name is " + queueName);

    // Objects that we must deal with using reflection
    Object queueConnectionFactory = null; // Should be
    // javax.jms.QueueConnectionFactory

    InitialContext jndiContext = null;
    Object queueConnection = null; // should be javax.jms.QueueConnection
    Object queueSession = null; // should be javax.jms.QueueSession
    Object queueSender = null; // should be javax.jms.QueueSender;
    Object queue = null; // should be //javax.jms.Queue;
    Object message = null; // TextMessage

    /*
     * Create JNDI Initial Context
     */
    try {
      Hashtable env = new Hashtable();
      env.put("java.naming.factory.initial", namingContextFactory);
      env.put("java.naming.provider.url", serverUrl);
      env.put("java.naming.factory.url.pkgs", namingUrlPackages);

      jndiContext = new InitialContext(env);
    } catch (NamingException e) {
      log.debug("Could not create JNDI API " + "context: ", e);
      throw new RpException(e);
    }

    /*
     * Get queue connection factory and queue objects from JNDI context.
     */
    try {

      queueConnectionFactory = jndiContext
          .lookup("UIL2ConnectionFactory");

      queue = jndiContext.lookup(queueName);

    } catch (NamingException e) {
      log.debug("JNDI API lookup failed: ", e);
      throw new RpException(e);
    }

    /*
     * Create connection, session, sender objects. Send the message. Cleanup
     * JMS connection.
     */
    try {
      queueConnection = getQueueConnection(queueConnectionFactory);

      queueSession = createQueueSession(queueConnection);
      queueSender = createQueueSender(queueSession, queue);
      message = createTextMessage(messageText, queueSession);

      log.debug("Sending message: " + messageText);

      sendMessageText(queueSender, message);

   
    } finally {
      if (queueConnection != null) {
        try {
          invokeCloseOnConnection(queueConnection);
        } catch (RpException e) {
          // Ignore - we can do nothign about this
        }
      }
    }

  }

  private Object createTextMessage(String message, Object qSession)
      throws RpException {

    // qSession is a QueueSession
    // we want to invoke create createTextMessage (string)

    Object returnObject = null;

    log.debug("Incoming object is null:" + (qSession == null));

    // Create Parameter Away (Method
    Class[] paramMethodArray = new Class[1];
    paramMethodArray[0] = String.class;

    // Create Param Array (invoke)
    Object[] invokeMethodArray = new Object[1];
    invokeMethodArray[0] = message;

    try {
      // Create the Text Method
      Method tmpMethod = qSession.getClass().getMethod(
          "createTextMessage", paramMethodArray);

      log.debug("tmpMethod:" + tmpMethod);

      returnObject = tmpMethod.invoke(qSession, invokeMethodArray);

    } catch (IllegalAccessException iae) {
      log.warn(iae);
      throw new RpException(iae);
    } catch (InvocationTargetException ite) {
      log.warn(ite);
      throw new RpException(ite);
    } catch (NoSuchMethodException nsme) {
      log.warn(nsme);
      throw new RpException(nsme);
    }

    return returnObject;

  }

  private void sendMessageText(Object qSender, Object message)
      throws RpException {
    // queueSender.send(message);

    // queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

    log.debug("Incoming object is null:" + (qSender == null));

    // Create Parameter Away (Method
    Class[] paramMethodArray = new Class[1];
    paramMethodArray[0] = javax.jms.Message.class;

    // Create Param Array (invoke)
    Object[] invokeMethodArray = new Object[1];
    invokeMethodArray[0] = message;

    try {

      // Loop and find the method we are looking for
      Method tmpMethod = null;
      Method[] methods = qSender.getClass().getMethods();
      for (int a = 0; a < methods.length; a++) {
        // log.debug("Method:" + a + " " + methods[a]);

        if (methods[a].toString().indexOf("send") > -1) {
          log.debug("match found");
          tmpMethod = methods[a];
        }

      }
      // Carry out the method call
      if (tmpMethod != null) {
        log.debug("tmpMethod:" + tmpMethod);
        tmpMethod.invoke(qSender, invokeMethodArray);
      } else {
        throw new RpException("No createSenderMethod found");
      }

    } catch (IllegalAccessException iae) {
      log.warn(iae);
      throw new RpException(iae);
    } catch (InvocationTargetException ite) {
      log.warn(ite);
      throw new RpException(ite);
    }

  }

  private void invokeCloseOnConnection(Object queueConnection)
      throws RpException {
    // queueConnection.close();

    log.debug("Incoming object is null:" + (queueConnection == null));

    try {
      Method tmpMethod = queueConnection.getClass().getMethod("close",
          new Class[0]);

      log.debug("tmpMethod:" + tmpMethod);

      tmpMethod.invoke(queueConnection, new Object[0]);
    } catch (IllegalAccessException iae) {
      log.debug(iae);
      throw new RpException(iae);
    } catch (InvocationTargetException ite) {
      log.debug(ite);
      throw new RpException(ite);
    } catch (NoSuchMethodException nsme) {
      log.debug(nsme);
      throw new RpException(nsme);
    }

  }

  private Object createQueueSession(Object queueConnection)
      throws RpException {

    // should return QueueSession
    // queueConnection.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);

    Object returnObject = null;
    log.debug("Incoming object is null:" + (queueConnection == null));

    // Create Parameter Away (Method
    Class[] paramMethodArray = new Class[2];
    paramMethodArray[0] = boolean.class;
    paramMethodArray[1] = int.class;

    // Create Param Array (invoke)
    Object[] invokeMethodArray = new Object[2];
    invokeMethodArray[0] = Boolean.FALSE;
    invokeMethodArray[1] = javax.jms.Session.AUTO_ACKNOWLEDGE;

    try {
      Method tmpMethod = queueConnection.getClass().getMethod(
          "createQueueSession", paramMethodArray);

      log.debug("tmpMethod:" + tmpMethod);

      returnObject = tmpMethod.invoke(queueConnection, invokeMethodArray);
    } catch (IllegalAccessException iae) {
      log.warn(iae);
      throw new RpException(iae);
    } catch (InvocationTargetException ite) {
      log.warn(ite);
      throw new RpException(ite);
    } catch (NoSuchMethodException nsme) {
      log.warn(nsme);
      throw new RpException(nsme);
    }

    return returnObject;

  }

  /**
   * We do it this way , so we don't have to risk a class cast (causing
   * problems on JBoss)
   *
   * @param qSession
   * @param queue
   * @return
   */
  private Object createQueueSender(Object qSession, Object queue)
      throws RpException {

    Object returnObject = null;
    log.debug("Incoming QueueSession is null:" + (qSession == null));
    log.debug("Incoming queue is null:" + (queue == null));

    // Create Param Array (invoke)
    Object[] invokeMethodArray = new Object[1];
    invokeMethodArray[0] = queue;

    try {
      // Loop and find the method we are looking for
      Method tmpMethod = null;
      Method[] methods = qSession.getClass().getMethods();
      for (int a = 0; a < methods.length; a++) {

        if (methods[a].toString().indexOf("createSender") > -1) {

          tmpMethod = methods[a];
          log.debug("match found" + tmpMethod);
        }

      }
      // Carry out the method call
      if (tmpMethod != null) {
        log.debug("using method:" + tmpMethod);
        returnObject = tmpMethod.invoke(qSession, invokeMethodArray);
      } else {
        throw new RpException("No createSenderMethod found");
      }

    } catch (IllegalAccessException iae) {
      log.debug(iae);
      throw new RpException(iae);
    } catch (InvocationTargetException ite) {
      log.debug(ite);
      throw new RpException(ite);
    }

    return returnObject;

  }

  /**
   * Get the QueueConnection on an object using reflection
   *
   * @param QueueConnection ,
   *            passed in as an object
   * @return
   */
  private Object getQueueConnection(Object queueConnection)
      throws RpException {

    Object returnObject = null;
    log.debug("Incoming object is null:" + (queueConnection == null));

    try {
      Method tmpMethod = queueConnection.getClass().getMethod(
          "createQueueConnection", new Class[0]);

      log.debug("tmpMethod:" + tmpMethod);

      returnObject = tmpMethod.invoke(queueConnection, new Object[0]);
    } catch (IllegalAccessException iae) {
      log.debug(iae);
      throw new RpException(iae);
    } catch (InvocationTargetException ite) {
      log.debug(ite);
      throw new RpException(ite);
    } catch (NoSuchMethodException nsme) {
      log.debug(nsme);
      throw new RpException(nsme);
    }

    return returnObject;
  }

  /**
   * @param queueName
   *            The queueName to set.
   */
  public void setQueueName(String queueName) {
    this.queueName = queueName;
  }

  /**
   * @return Returns the queueName.
   */
  public String getQueueName() {
    return queueName;
  }

  /**
   * @param serverUrl
   *            The serverUrl to set.
   */
  public void setServerUrl(String serverUrl) {
    this.serverUrl = serverUrl;
  }

  /**
   * @return Returns the serverUrl.
   */
  public String getServerUrl() {
    return serverUrl;
  }

  /**
   * @param namingContextFactory
   *            The namingContextFactory to set.
   */
  public void setNamingContextFactory(String namingContextFactory) {
    this.namingContextFactory = namingContextFactory;
  }

  /**
   * @return Returns the namingContextFactory.
   */
  public String getNamingContextFactory() {
    return namingContextFactory;
  }

  /**
   * @param namingUrlPackages
   *            The namingUrlPackages to set.
   */
  public void setNamingUrlPackages(String namingUrlPackages) {
    this.namingUrlPackages = namingUrlPackages;
  }

  /**
   * @return Returns the namingUrlPackages.
   */
  public String getNamingUrlPackages() {
    return namingUrlPackages;
  }
}
TOP

Related Classes of net.fp.rp.workflow.message.JBossTextMessageSender

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.