Package org.objectweb.joram.mom.dest.jmsbridge

Source Code of org.objectweb.joram.mom.dest.jmsbridge.JMSBridgeQueue

/*
* JORAM: Java(TM) Open Reliable Asynchronous Messaging
* Copyright (C) 2004 - 2011 ScalAgent Distributed Technologies
* Copyright (C) 2003 - 2004 Bull SA
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307
* USA.
*
* Initial developer(s): Frederic Maistre (Bull SA)
* Contributor(s): ScalAgent Distributed Technologies
*/
package org.objectweb.joram.mom.dest.jmsbridge;

import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.Properties;
import java.util.Vector;

import org.objectweb.joram.mom.dest.Queue;
import org.objectweb.joram.mom.messages.Message;
import org.objectweb.joram.mom.notifications.ClientMessages;
import org.objectweb.joram.mom.notifications.QueueMsgReply;
import org.objectweb.joram.mom.notifications.ReceiveRequest;
import org.objectweb.joram.mom.util.DMQManager;
import org.objectweb.joram.shared.MessageErrorConstants;
import org.objectweb.joram.shared.excepts.AccessException;
import org.objectweb.joram.shared.selectors.Selector;
import org.objectweb.util.monolog.api.BasicLevel;

import fr.dyade.aaa.agent.AgentId;
import fr.dyade.aaa.agent.DeleteNot;
import fr.dyade.aaa.agent.Notification;

/**
* The <code>BridgeQueue</code> class implements a specific queue which
* forwards the messages it receives to a foreign JMS destination, and
* gets the messages it is requested to deliver from the same foreign
* destination.
* <p>
* This queue is in fact a bridge linking JORAM and a foreign JMS server.
*/
public class JMSBridgeQueue extends Queue {

  /** define serialVersionUID for interoperability */
  private static final long serialVersionUID = 1L;

  /** The JMS module for accessing the foreign JMS destination. */
  private JMSBridgeModule jmsModule;

  /**
   * Table persisting the outgoing messages until acknowledgment by the
   * bridge module.
   * <p>
   * <b>Key:</b> message identifier<br>
   * <b>Value:</b> message
   */
  private Hashtable outTable;

  public JMSBridgeQueue() {
    fixed = true;
    // creates the table for outgoing messages.
    outTable = new Hashtable();
  }

  /**
   * Configures a <code>BridgeQueue</code> instance.
   *
   * @param prop The initial set of properties.
   */
  public void setProperties(Properties prop, boolean firstTime) throws Exception {
    super.setProperties(prop, firstTime);
    // creates the JMS module for communication with external provider
    jmsModule = new JMSBridgeModule(prop);
  }

  /**
   * Initializes the destination.
   *
   * @param firstTime   true when first called by the factory
   */
  public void initialize(boolean firstTime) {
    if (logger.isLoggable(BasicLevel.DEBUG))
      logger.log(BasicLevel.DEBUG, "initialize(" + firstTime + ')');

    // initialize the destination
    super.initialize(firstTime);

    // Initializing the JMS module.
    jmsModule.init(getId());

    // Re-launching the JMS module.
    try {
      jmsModule.connect();

      // Re-emitting the receive requests:
      for (int i = 0; i < requests.size(); i++)
        jmsModule.receive();

      // Re-emetting the pending messages:
      Message momMsg;
      Vector outMessages = new Vector();
      Message currentMsg;
      for (Enumeration keys = outTable.keys(); keys.hasMoreElements();) {
        momMsg = (Message) outTable.get(keys.nextElement());

        int i = 0;
        while (i < outMessages.size()) {
          currentMsg = (Message) outMessages.get(i);

          if (momMsg.order < currentMsg.order)
            break;

          i++;
        }
        outMessages.insertElementAt(momMsg, i);
      }

      while (! outMessages.isEmpty()) {
        momMsg = (Message) outMessages.remove(0);
        jmsModule.send(momMsg.getFullMessage());
      }
    } catch (Exception exc) {
      if (logger.isLoggable(BasicLevel.ERROR))
        logger.log(BasicLevel.ERROR, "", exc);
    }
  }

  /**
   * Specializes this <code>Queue</code> method for processing the
   * specific bridge notifications.
   *
   * @throws Exception
   */
  public void react(AgentId from, Notification not) throws Exception {
    if (not instanceof JMSBridgeDeliveryNot) {
      bridgeDelivery(from, (JMSBridgeDeliveryNot) not);
    } else if (not instanceof JMSBridgeAckNot)
      bridgeAck((JMSBridgeAckNot) not);
    else
      super.react(from, not);
  }

  public void agentFinalize(boolean lastTime) {
    super.agentFinalize(lastTime);
    close();
  }

  public String toString() {
    return "BridgeQueue:" + getId().toString();
  }

  /**
   * Reacts to <code>BridgeDeliveryNot</code> notifications holding a message
   * received from the foreign JMS server.
   *
   * @param from  AgentId
   * @param not   BridgeDeliveryNot
   */
  private void bridgeDelivery(AgentId from, JMSBridgeDeliveryNot not) {
    ClientMessages clientMessages = new ClientMessages();
    clientMessages.addMessage(not.getMessage());
    // it come from bridge, so set destId for from
    //(do not preProcess this ClientMessage).
    super.doClientMessages(getId(), clientMessages);
  }

  /**
   * Reacts to <code>BridgeAckNot</code> notifications holding the identifier
   * of a message successfully delivered to the foreign JMS server.
   *
   * @param not BridgeAckNot
   */
  private void bridgeAck(JMSBridgeAckNot not) {
    outTable.remove(not.getIdentifier());
  }

  /**
   * Method specializing the reaction to a <code>ReceiveRequest</code>
   * instance, requesting a message.
   * <p>
   * This method stores the request and requests a message through the JMS
   * interface.
   *
   * @exception AccessException  If the sender is not a reader.
   */
  public void receiveRequest(AgentId from, ReceiveRequest not) throws AccessException {
    // If client is not a reader, sending an exception.
    if (! isReader(from))
      throw new AccessException("READ right not granted");

    // Storing the request:
    not.requester = from;
    not.setExpiration(System.currentTimeMillis());
    requests.add(not);

    // Launching a delivery sequence for this request:
    int reqIndex = requests.size() - 1;
    deliverMessages(reqIndex);

    if ((requests.size() - 1) == reqIndex) {
      // If the request has not been answered:
      if (not.getTimeOut() == -1) {
        // If it is an immediate delivery request, requesting the foreign JMS
        // destination for an immediate delivery.
        requests.remove(reqIndex);

        org.objectweb.joram.shared.messages.Message message = null;
        try {
          message = jmsModule.receiveNoWait();
        } catch (Exception exc) {
          // JMS module not properly initialized.
          if (logger.isLoggable(BasicLevel.ERROR))
            logger.log(BasicLevel.ERROR,
                       "Failing receive request on remote destination: ", exc);
        }

        // If message not null but not selected, setting it to null.
        if ((message != null) &&
            ! Selector.matches(message, not.getSelector()))
          message = null;

        QueueMsgReply reply = new QueueMsgReply(not);
        if (message != null)
          reply.addMessage(message);
        forward(from, reply);

        if (logger.isLoggable(BasicLevel.DEBUG))
          logger.log(BasicLevel.DEBUG,
          "Receive answered.");
      } else {
        // Else, requesting the foreign JMS destination for a delivery:
        try {
          jmsModule.receive();
        } catch (Exception exc) {
          // JMS module not properly initialized.
          if (logger.isLoggable(BasicLevel.ERROR))
            logger.log(BasicLevel.ERROR,
                       "Failing receive request on remote destination: ", exc);
        }
      }
    }
  }

  /**
   * Method specializing the processing of a <code>ClientMessages</code>
   * instance.
   * <p>
   * This method sends the messages to the foreign JMS destination.
   */
  public ClientMessages preProcess(AgentId from, ClientMessages not) {
    if (getId().equals(from))
      return not;

    // Sending each message:
    Message message;
    for (Iterator msgs = not.getMessages().iterator(); msgs.hasNext();) {
      message = new Message((org.objectweb.joram.shared.messages.Message) msgs.next());
      message.order = arrivalsCounter++;

      outTable.put(message.getIdentifier(), message);

      try {
        jmsModule.send(message.getFullMessage());
      } catch (Exception exc) {
        if (logger.isLoggable(BasicLevel.ERROR))
          logger.log(BasicLevel.ERROR,
                     "Failing sending to remote  destination: ", exc);

        outTable.remove(message.getIdentifier());
        DMQManager dmqManager = new DMQManager(not.getDMQId(), dmqId, getId());
        nbMsgsSentToDMQSinceCreation++;
        dmqManager.addDeadMessage(message.getFullMessage(), MessageErrorConstants.UNEXPECTED_ERROR);
        dmqManager.sendToDMQ();
      }
    }
    return null;
  }

  /**
   * Method specifically processing a
   * <code>fr.dyade.aaa.agent.DeleteNot</code> instance.
   * <p>
   * This method closes the JMS resources used for connecting to the foreign
   * JMS server.
   */
  protected void doDeleteNot(DeleteNot not) {
    jmsModule.close();
    super.doDeleteNot(not);
  }
 
  private void close() {
    jmsModule.close();
  }
}
TOP

Related Classes of org.objectweb.joram.mom.dest.jmsbridge.JMSBridgeQueue

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.