예제 #1
0
    public void run() {
      try {
        for (int i = 0; i < numMessages; i++) {
          TextMessage tm = sess.createTextMessage("message" + i);

          prod.send(tm);

          log.trace("Sent message " + i);
        }
      } catch (Exception e) {
        log.error("Failed to send", e);
        ex = e;
      }
    }
/**
 * A Netty FrameDecoder used to decode messages.
 *
 * @author <a href="mailto:[email protected]">Tim Fox</a>
 * @author <a href="*****@*****.**">Andy Taylor</a>
 * @author <a href="*****@*****.**">Trustin Lee</a>
 * @version $Revision$, $Date$
 */
public class MessagingFrameDecoder extends FrameDecoder {
  private static final Logger log = Logger.getLogger(MessagingFrameDecoder.class);

  private final BufferHandler handler;

  public MessagingFrameDecoder(final BufferHandler handler) {
    this.handler = handler;
  }

  // FrameDecoder overrides
  // -------------------------------------------------------------------------------------

  @Override
  protected Object decode(ChannelHandlerContext ctx, Channel channel, ChannelBuffer in)
      throws Exception {
    // TODO - we can avoid this entirely if we maintain fragmented packets in the handler
    int start = in.readerIndex();

    int length = handler.isReadyToHandle(new ChannelBufferWrapper(in));
    if (length == -1) {
      in.readerIndex(start);
      return null;
    }

    in.readerIndex(start + SIZE_INT);
    return in.readBytes(length);
  }
}
  public void handlePacket(final Packet packet) {
    byte type = packet.getType();

    try {
      switch (type) {
        case SESS_RECEIVETOKENS:
          {
            SessionProducerFlowCreditMessage message = (SessionProducerFlowCreditMessage) packet;

            clientSession.receiveProducerCredits(message.getProducerID(), message.getTokens());

            break;
          }
        case SESS_RECEIVE_MSG:
          {
            SessionReceiveMessage message = (SessionReceiveMessage) packet;

            clientSession.handleReceiveMessage(message.getConsumerID(), message.getClientMessage());

            break;
          }
        case EXCEPTION:
          {
            // TODO - we can provide a means for async exceptions to get back to to client
            // For now we just log it
            MessagingExceptionMessage mem = (MessagingExceptionMessage) packet;

            log.error("Received exception asynchronously from server", mem.getException());

            break;
          }
        default:
          {
            throw new IllegalStateException("Invalid packet: " + type);
          }
      }
    } catch (Exception e) {
      log.error("Failed to handle packet", e);
    }
  }
/**
 * A RealJournalImplTest you need to define -Djava.library.path=${project-root}/native/src/.libs
 * when calling the JVM If you are running this test in eclipse you should do: I - Run->Open Run
 * Dialog II - Find the class on the list (you will find it if you already tried running this
 * testcase before) III - Add -Djava.library.path=<your project place>/native/src/.libs
 *
 * @author <a href="mailto:[email protected]">Tim Fox</a>
 * @author <a href="mailto:[email protected]">Clebert Suconic</a>
 */
public class RealAIOJournalImplTest extends JournalImplTestUnit {
  private static final Logger log = Logger.getLogger(RealAIOJournalImplTest.class);

  // Need to run the test over a local disk (no NFS)
  protected String journalDir = System.getProperty("java.io.tmpdir", "/tmp") + "/journal-test";

  @Override
  protected void setUp() throws Exception {
    super.setUp();
    if (!AsynchronousFileImpl.isLoaded()) {
      fail(
          String.format(
              "libAIO is not loaded on %s %s %s",
              System.getProperty("os.name"),
              System.getProperty("os.arch"),
              System.getProperty("os.version")));
    }
  }

  @Override
  protected void tearDown() throws Exception {
    super.tearDown();
    deleteDirectory(new File(journalDir));
  }

  @Override
  protected SequentialFileFactory getFileFactory() throws Exception {
    File file = new File(journalDir);

    deleteDirectory(file);

    file.mkdir();

    return new AIOSequentialFileFactory(journalDir);
  }

  @Override
  protected int getAlignment() {
    return 512;
  }
}
/**
 * @author <a href="mailto:[email protected]">Ovidiu Feodorov</a>
 * @author <a href="mailto:[email protected]">Tim Fox</a>
 * @version <tt>$Revision$</tt> $Id$
 */
public class JBossConnectionFactory
    implements ConnectionFactory,
        QueueConnectionFactory,
        TopicConnectionFactory,
        XAConnectionFactory,
        XAQueueConnectionFactory,
        XATopicConnectionFactory,
        Serializable /*
                      * , Referenceable
                      * http://jira.jboss.org/jira/browse/JBMESSAGING-395
                      */ {
  // Constants ------------------------------------------------------------------------------------

  private static final long serialVersionUID = -2810634789345348326L;

  private static final Logger log = Logger.getLogger(JBossConnectionFactory.class);

  // Static ---------------------------------------------------------------------------------------

  // Attributes -----------------------------------------------------------------------------------

  private transient volatile ClientSessionFactory sessionFactory;

  private final TransportConfiguration connectorConfig;

  private final TransportConfiguration backupConnectorConfig;

  private final String clientID;

  private final int dupsOKBatchSize;

  private final long pingPeriod;

  private final long callTimeout;

  private final int consumerWindowSize;

  private final int consumerMaxRate;

  private final int producerWindowSize;

  private final int producerMaxRate;

  private final boolean blockOnAcknowledge;

  private final boolean blockOnNonPersistentSend;

  private final boolean blockOnPersistentSend;

  private final boolean autoGroupId;

  // Constructors ---------------------------------------------------------------------------------

  public JBossConnectionFactory(
      final TransportConfiguration connectorConfig,
      final TransportConfiguration backupConnectorConfig,
      final long pingPeriod,
      final long callTimeout,
      final String clientID,
      final int dupsOKBatchSize,
      final int consumerWindowSize,
      final int consumerMaxRate,
      final int producerWindowSize,
      final int producerMaxRate,
      final boolean blockOnAcknowledge,
      final boolean blockOnNonPersistentSend,
      final boolean blockOnPersistentSend,
      final boolean autoGroupId) {
    this.connectorConfig = connectorConfig;
    this.backupConnectorConfig = backupConnectorConfig;
    this.clientID = clientID;
    this.dupsOKBatchSize = dupsOKBatchSize;
    this.pingPeriod = pingPeriod;
    this.callTimeout = callTimeout;
    this.consumerMaxRate = consumerMaxRate;
    this.consumerWindowSize = consumerWindowSize;
    this.producerMaxRate = producerMaxRate;
    this.producerWindowSize = producerWindowSize;
    this.blockOnAcknowledge = blockOnAcknowledge;
    this.blockOnNonPersistentSend = blockOnNonPersistentSend;
    this.blockOnPersistentSend = blockOnPersistentSend;
    this.autoGroupId = autoGroupId;
  }

  // ConnectionFactory implementation -------------------------------------------------------------

  public Connection createConnection() throws JMSException {
    return createConnection(null, null);
  }

  public Connection createConnection(final String username, final String password)
      throws JMSException {
    return createConnectionInternal(
        username, password, false, JBossConnection.TYPE_GENERIC_CONNECTION);
  }

  // QueueConnectionFactory implementation --------------------------------------------------------

  public QueueConnection createQueueConnection() throws JMSException {
    return createQueueConnection(null, null);
  }

  public QueueConnection createQueueConnection(final String username, final String password)
      throws JMSException {
    return createConnectionInternal(
        username, password, false, JBossConnection.TYPE_QUEUE_CONNECTION);
  }

  // TopicConnectionFactory implementation --------------------------------------------------------

  public TopicConnection createTopicConnection() throws JMSException {
    return createTopicConnection(null, null);
  }

  public TopicConnection createTopicConnection(final String username, final String password)
      throws JMSException {
    return createConnectionInternal(
        username, password, false, JBossConnection.TYPE_TOPIC_CONNECTION);
  }

  // XAConnectionFactory implementation -----------------------------------------------------------

  public XAConnection createXAConnection() throws JMSException {
    return createXAConnection(null, null);
  }

  public XAConnection createXAConnection(final String username, final String password)
      throws JMSException {
    return createConnectionInternal(
        username, password, true, JBossConnection.TYPE_GENERIC_CONNECTION);
  }

  // XAQueueConnectionFactory implementation ------------------------------------------------------

  public XAQueueConnection createXAQueueConnection() throws JMSException {
    return createXAQueueConnection(null, null);
  }

  public XAQueueConnection createXAQueueConnection(final String username, final String password)
      throws JMSException {
    return createConnectionInternal(
        username, password, true, JBossConnection.TYPE_QUEUE_CONNECTION);
  }

  // XATopicConnectionFactory implementation ------------------------------------------------------

  public XATopicConnection createXATopicConnection() throws JMSException {
    return createXATopicConnection(null, null);
  }

  public XATopicConnection createXATopicConnection(final String username, final String password)
      throws JMSException {
    return createConnectionInternal(
        username, password, true, JBossConnection.TYPE_TOPIC_CONNECTION);
  }

  // Referenceable implementation -----------------------------------------------------------------

  public Reference getReference() throws NamingException {
    return new Reference(
        this.getClass().getCanonicalName(),
        new SerializableObjectRefAddr("JBM-CF", this),
        ConnectionFactoryObjectFactory.class.getCanonicalName(),
        null);
  }

  // Public ---------------------------------------------------------------------------------------

  public TransportConfiguration getConnectorFactory() {
    return connectorConfig;
  }

  public long getPingPeriod() {
    return pingPeriod;
  }

  public long getCallTimeout() {
    return callTimeout;
  }

  public String getClientID() {
    return clientID;
  }

  public int getDupsOKBatchSize() {
    return dupsOKBatchSize;
  }

  public int getConsumerWindowSize() {
    return consumerWindowSize;
  }

  public int getConsumerMaxRate() {
    return consumerMaxRate;
  }

  public int getProducerWindowSize() {
    return producerWindowSize;
  }

  public int getProducerMaxRate() {
    return producerMaxRate;
  }

  public boolean isBlockOnAcknowledge() {
    return blockOnAcknowledge;
  }

  public boolean isBlockOnNonPersistentSend() {
    return blockOnNonPersistentSend;
  }

  public boolean isBlockOnPersistentSend() {
    return blockOnPersistentSend;
  }

  public boolean isAutoGroupId() {
    return autoGroupId;
  }

  // Package protected ----------------------------------------------------------------------------

  // Protected ------------------------------------------------------------------------------------

  protected JBossConnection createConnectionInternal(
      final String username, final String password, final boolean isXA, final int type)
      throws JMSException {
    if (sessionFactory == null) {
      // It doesn't matter if more than one is created due to a race
      sessionFactory =
          new ClientSessionFactoryImpl(
              connectorConfig,
              backupConnectorConfig,
              pingPeriod,
              callTimeout,
              consumerWindowSize,
              consumerMaxRate,
              producerWindowSize,
              producerMaxRate,
              blockOnAcknowledge,
              blockOnNonPersistentSend,
              blockOnPersistentSend,
              autoGroupId);
    }

    if (username != null) {
      // Since core has no connection concept, we need to create a session in order to authenticate
      // at this time

      ClientSession sess = null;

      try {
        sess = sessionFactory.createSession(username, password, false, false, false, false);
      } catch (MessagingException e) {
        throw JMSExceptionHelper.convertFromMessagingException(e);
      } finally {
        if (sess != null) {
          try {
            sess.close();
          } catch (Throwable ignore) {
          }
        }
      }
    }

    return new JBossConnection(username, password, type, clientID, dupsOKBatchSize, sessionFactory);
  }

  // Private --------------------------------------------------------------------------------------

  // Inner classes --------------------------------------------------------------------------------
}
예제 #6
0
  private void propertiesPreserved(boolean persistent, boolean messageIDInHeader) throws Exception {
    BridgeImpl bridge = null;

    Connection connSource = null;

    Connection connTarget = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              messageIDInHeader);

      bridge.start();

      connSource = cf0.createConnection();

      connTarget = cf1.createConnection();

      log.trace("Sending " + NUM_MESSAGES + " messages");

      Session sessSource = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      Session sessTarget = connTarget.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageConsumer cons = sessTarget.createConsumer(targetQueue);

      connTarget.start();

      MessageProducer prod = sessSource.createProducer(sourceQueue);

      prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);

      TextMessage tm = sessSource.createTextMessage("blahmessage");

      prod.setPriority(7);

      prod.setTimeToLive(1 * 60 * 60 * 1000);

      prod.send(tm);

      long expiration = tm.getJMSExpiration();

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      tm = (TextMessage) cons.receive(1000);

      assertNotNull(tm);

      assertEquals("blahmessage", tm.getText());

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      assertEquals(7, tm.getJMSPriority());

      assertTrue(Math.abs(expiration - tm.getJMSExpiration()) < 100);

      Message m = cons.receive(5000);

      assertNull(m);

      // Now do one with expiration = 0

      tm = sessSource.createTextMessage("blahmessage2");

      prod.setPriority(7);

      prod.setTimeToLive(0);

      prod.send(tm);

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      tm = (TextMessage) cons.receive(1000);

      assertNotNull(tm);

      assertEquals("blahmessage2", tm.getText());

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      assertEquals(7, tm.getJMSPriority());

      assertEquals(0, tm.getJMSExpiration());

      m = cons.receive(5000);

      assertNull(m);

      tm = sessSource.createTextMessage("blahmessage3");

      final boolean myBool = false;
      final byte myByte = (byte) 23;
      final double myDouble = 17625765d;
      final float myFloat = 87127.23f;
      final int myInt = 123;
      final long myLong = 81728712;
      final short myShort = (short) 88;
      final String myString = "ojweodewj";
      final String myJMSX = "aardvark";

      tm.setBooleanProperty("mybool", myBool);
      tm.setByteProperty("mybyte", myByte);
      tm.setDoubleProperty("mydouble", myDouble);
      tm.setFloatProperty("myfloat", myFloat);
      tm.setIntProperty("myint", myInt);
      tm.setLongProperty("mylong", myLong);
      tm.setShortProperty("myshort", myShort);
      tm.setStringProperty("mystring", myString);

      tm.setStringProperty("JMSXMyNaughtyJMSXProperty", myJMSX);

      prod.send(tm);

      tm = (TextMessage) cons.receive(1000);

      assertNotNull(tm);

      assertEquals("blahmessage3", tm.getText());

      assertEquals(myBool, tm.getBooleanProperty("mybool"));
      assertEquals(myByte, tm.getByteProperty("mybyte"));
      assertEquals(myDouble, tm.getDoubleProperty("mydouble"));
      assertEquals(myFloat, tm.getFloatProperty("myfloat"));
      assertEquals(myInt, tm.getIntProperty("myint"));
      assertEquals(myLong, tm.getLongProperty("mylong"));
      assertEquals(myShort, tm.getShortProperty("myshort"));
      assertEquals(myString, tm.getStringProperty("mystring"));
      assertEquals(myJMSX, tm.getStringProperty("JMSXMyNaughtyJMSXProperty"));

      m = cons.receive(5000);

    } finally {
      if (bridge != null) {
        bridge.stop();
      }

      if (connSource != null) {
        connSource.close();
      }

      if (connTarget != null) {
        connTarget.close();
      }
    }
  }
예제 #7
0
  private void messageIDInHeader(boolean on) throws Exception {
    BridgeImpl bridge = null;

    Connection connSource = null;

    Connection connTarget = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              on);

      bridge.start();

      connSource = cf0.createConnection();

      connTarget = cf1.createConnection();

      log.trace("Sending " + NUM_MESSAGES + " messages");

      List ids1 = new ArrayList();

      Session sessSource = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSource.createProducer(sourceQueue);

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = sessSource.createTextMessage("message" + i);

        // We add some headers to make sure they get passed through ok
        tm.setStringProperty("wib", "uhuh");
        tm.setBooleanProperty("cheese", true);
        tm.setIntProperty("Sausages", 23);

        // We add some JMSX ones too

        tm.setStringProperty("JMSXGroupID", "mygroup543");
        tm.setIntProperty("JMSXGroupSeq", 777);

        prod.send(tm);

        ids1.add(tm.getJMSMessageID());
      }

      log.trace("Sent the first messages");

      Session sessTarget = connTarget.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageConsumer cons = sessTarget.createConsumer(targetQueue);

      connTarget.start();

      List msgs = new ArrayList();

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = (TextMessage) cons.receive(5000);

        assertNotNull(tm);

        assertEquals("message" + i, tm.getText());

        assertEquals("uhuh", tm.getStringProperty("wib"));
        assertTrue(tm.getBooleanProperty("cheese"));
        assertEquals(23, tm.getIntProperty("Sausages"));

        assertEquals("mygroup543", tm.getStringProperty("JMSXGroupID"));
        assertEquals(777, tm.getIntProperty("JMSXGroupSeq"));

        if (on) {
          String header = tm.getStringProperty(JBossMessage.JBOSS_MESSAGING_BRIDGE_MESSAGE_ID_LIST);

          assertNotNull(header);

          assertEquals(ids1.get(i), header);

          msgs.add(tm);
        }
      }

      if (on) {
        // Now we send them again back to the source

        Iterator iter = msgs.iterator();

        List ids2 = new ArrayList();

        while (iter.hasNext()) {
          Message msg = (Message) iter.next();

          prod.send(msg);

          ids2.add(msg.getJMSMessageID());
        }

        // And consume them again

        for (int i = 0; i < NUM_MESSAGES; i++) {
          TextMessage tm = (TextMessage) cons.receive(5000);

          assertNotNull(tm);

          assertEquals("message" + i, tm.getText());

          assertEquals("uhuh", tm.getStringProperty("wib"));
          assertTrue(tm.getBooleanProperty("cheese"));
          assertEquals(23, tm.getIntProperty("Sausages"));

          assertEquals("mygroup543", tm.getStringProperty("JMSXGroupID"));
          assertEquals(777, tm.getIntProperty("JMSXGroupSeq"));

          String header = tm.getStringProperty(JBossMessage.JBOSS_MESSAGING_BRIDGE_MESSAGE_ID_LIST);

          assertNotNull(header);

          assertEquals(ids1.get(i) + "," + ids2.get(i), header);
        }
      }

    } finally {
      if (bridge != null) {
        bridge.stop();
      }

      if (connSource != null) {
        connSource.close();
      }

      if (connTarget != null) {
        connTarget.close();
      }
    }
  }
예제 #8
0
  public void testStartBridgeWithJTATransactionAlreadyRunning() throws Exception {
    BridgeImpl bridge = null;

    Transaction toResume = null;

    Transaction started = null;

    TransactionManager mgr = TransactionManagerLocator.getInstance().locate();

    try {

      toResume = mgr.suspend();

      mgr.begin();

      started = mgr.getTransaction();

      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceTopicFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              false);

      bridge.start();

      this.sendMessages(cf0, sourceTopic, 0, NUM_MESSAGES, false);

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);
    } finally {
      if (started != null) {
        try {
          started.rollback();
        } catch (Exception e) {
          log.error("Failed to rollback", e);
        }
      }

      if (toResume != null) {
        try {
          mgr.resume(toResume);
        } catch (Exception e) {
          log.error("Failed to resume", e);
        }
      }
      if (bridge != null) {
        bridge.stop();
      }
    }
  }
예제 #9
0
/**
 * A BridgeTest
 *
 * @author <a href="mailto:[email protected]">Tim Fox</a>
 * @version <tt>$Revision$</tt>
 *     <p>$Id$
 */
public class BridgeTest extends BridgeTestBase {
  private static final Logger log = Logger.getLogger(BridgeTest.class);

  public BridgeTest(String name) {
    super(name);
  }

  // MaxBatchSize but no MaxBatchTime

  public void testNoMaxBatchTime_AtMostOnce_P() throws Exception {
    testNoMaxBatchTime(QualityOfServiceMode.AT_MOST_ONCE, true);
  }

  public void testNoMaxBatchTime_DuplicatesOk_P() throws Exception {
    testNoMaxBatchTime(QualityOfServiceMode.DUPLICATES_OK, true);
  }

  public void testNoMaxBatchTime_OnceAndOnlyOnce_P() throws Exception {
    testNoMaxBatchTime(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true);
  }

  public void testNoMaxBatchTime_AtMostOnce_NP() throws Exception {
    testNoMaxBatchTime(QualityOfServiceMode.AT_MOST_ONCE, false);
  }

  public void testNoMaxBatchTime_DuplicatesOk_NP() throws Exception {
    testNoMaxBatchTime(QualityOfServiceMode.DUPLICATES_OK, false);
  }

  public void testNoMaxBatchTime_OnceAndOnlyOnce_NP() throws Exception {
    testNoMaxBatchTime(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false);
  }

  // Same server

  // MaxBatchSize but no MaxBatchTime

  public void testNoMaxBatchTimeSameServer_AtMostOnce_P() throws Exception {
    testNoMaxBatchTimeSameServer(QualityOfServiceMode.AT_MOST_ONCE, true);
  }

  public void testNoMaxBatchTimeSameServer_DuplicatesOk_P() throws Exception {
    testNoMaxBatchTimeSameServer(QualityOfServiceMode.DUPLICATES_OK, true);
  }

  public void testNoMaxBatchTimeSameServer_OnceAndOnlyOnce_P() throws Exception {
    testNoMaxBatchTimeSameServer(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true);
  }

  public void testNoMaxBatchTimeSameServer_AtMostOnce_NP() throws Exception {
    testNoMaxBatchTimeSameServer(QualityOfServiceMode.AT_MOST_ONCE, false);
  }

  public void testNoMaxBatchTimeSameServer_DuplicatesOk_NP() throws Exception {
    testNoMaxBatchTimeSameServer(QualityOfServiceMode.DUPLICATES_OK, false);
  }

  public void testNoMaxBatchTimeSameServer_OnceAndOnlyOnce_NP() throws Exception {
    testNoMaxBatchTimeSameServer(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false);
  }

  // MaxBatchTime but no MaxBatchSize

  public void testMaxBatchTime_AtMostOnce_P() throws Exception {
    this.testMaxBatchTime(QualityOfServiceMode.AT_MOST_ONCE, true);
  }

  public void testMaxBatchTime_DuplicatesOk_P() throws Exception {
    this.testMaxBatchTime(QualityOfServiceMode.DUPLICATES_OK, true);
  }

  public void testMaxBatchTime_OnceAndOnlyOnce_P() throws Exception {
    testMaxBatchTime(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true);
  }

  public void testMaxBatchTime_AtMostOnce_NP() throws Exception {
    this.testMaxBatchTime(QualityOfServiceMode.AT_MOST_ONCE, false);
  }

  public void testMaxBatchTime_DuplicatesOk_NP() throws Exception {
    this.testMaxBatchTime(QualityOfServiceMode.DUPLICATES_OK, false);
  }

  public void testMaxBatchTime_OnceAndOnlyOnce_NP() throws Exception {
    testMaxBatchTime(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false);
  }

  // Same server

  // MaxBatchTime but no MaxBatchSize

  public void testMaxBatchTimeSameServer_AtMostOnce_P() throws Exception {
    this.testMaxBatchTimeSameServer(QualityOfServiceMode.AT_MOST_ONCE, true);
  }

  public void testMaxBatchTimeSameServer_DuplicatesOk_P() throws Exception {
    this.testMaxBatchTimeSameServer(QualityOfServiceMode.DUPLICATES_OK, true);
  }

  public void testMaxBatchTimeSameServer_OnceAndOnlyOnce_P() throws Exception {
    testMaxBatchTimeSameServer(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true);
  }

  public void testMaxBatchTimeSameServer_AtMostOnce_NP() throws Exception {
    this.testMaxBatchTimeSameServer(QualityOfServiceMode.AT_MOST_ONCE, false);
  }

  public void testMaxBatchTimeSameServer_DuplicatesOk_NP() throws Exception {
    this.testMaxBatchTimeSameServer(QualityOfServiceMode.DUPLICATES_OK, false);
  }

  public void testMaxBatchTimeSameServer_OnceAndOnlyOnce_NP() throws Exception {
    testMaxBatchTimeSameServer(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false);
  }

  // Stress with batch size of 50

  public void testStress_AtMostOnce_P_50() throws Exception {
    testStress(QualityOfServiceMode.AT_MOST_ONCE, true, 50);
  }

  public void testStress_DuplicatesOk_P_50() throws Exception {
    testStress(QualityOfServiceMode.DUPLICATES_OK, true, 50);
  }

  public void testStress_OnceAndOnlyOnce_P_50() throws Exception {
    testStress(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true, 50);
  }

  public void testStress_AtMostOnce_NP_50() throws Exception {
    testStress(QualityOfServiceMode.AT_MOST_ONCE, false, 50);
  }

  public void testStress_DuplicatesOk_NP_50() throws Exception {
    testStress(QualityOfServiceMode.DUPLICATES_OK, false, 50);
  }

  public void testStress_OnceAndOnlyOnce_NP_50() throws Exception {
    testStress(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false, 50);
  }

  // Stress with batch size of 1

  public void testStress_AtMostOnce_P_1() throws Exception {
    testStress(QualityOfServiceMode.AT_MOST_ONCE, true, 1);
  }

  public void testStress_DuplicatesOk_P_1() throws Exception {
    testStress(QualityOfServiceMode.DUPLICATES_OK, true, 1);
  }

  public void testStress_OnceAndOnlyOnce_P_1() throws Exception {
    testStress(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true, 1);
  }

  public void testStress_AtMostOnce_NP_1() throws Exception {
    testStress(QualityOfServiceMode.AT_MOST_ONCE, false, 1);
  }

  public void testStress_DuplicatesOk_NP_1() throws Exception {
    testStress(QualityOfServiceMode.DUPLICATES_OK, false, 1);
  }

  public void testStress_OnceAndOnlyOnce_NP_1() throws Exception {
    testStress(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false, 1);
  }

  // Max batch time

  public void testStressMaxBatchTime_OnceAndOnlyOnce_NP() throws Exception {
    this.testStressBatchTime(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false, 200);
  }

  public void testStressMaxBatchTime_OnceAndOnlyOnce_P() throws Exception {
    this.testStressBatchTime(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true, 200);
  }

  // Stress on same server

  // Stress with batch size of 50

  public void testStressSameServer_AtMostOnce_P_50() throws Exception {
    testStressSameServer(QualityOfServiceMode.AT_MOST_ONCE, true, 50);
  }

  public void testStressSameServer_DuplicatesOk_P_50() throws Exception {
    testStressSameServer(QualityOfServiceMode.DUPLICATES_OK, true, 50);
  }

  public void testStressSameServer_OnceAndOnlyOnce_P_50() throws Exception {
    testStress(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true, 50);
  }

  public void testStressSameServer_AtMostOnce_NP_50() throws Exception {
    testStressSameServer(QualityOfServiceMode.AT_MOST_ONCE, false, 50);
  }

  public void testStressSameServer_DuplicatesOk_NP_50() throws Exception {
    testStressSameServer(QualityOfServiceMode.DUPLICATES_OK, false, 50);
  }

  public void testStressSameServer_OnceAndOnlyOnce_NP_50() throws Exception {
    testStressSameServer(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false, 50);
  }

  // Stress with batch size of 1

  public void testStressSameServer_AtMostOnce_P_1() throws Exception {
    testStressSameServer(QualityOfServiceMode.AT_MOST_ONCE, true, 1);
  }

  public void testStressSameServer_DuplicatesOk_P_1() throws Exception {
    testStressSameServer(QualityOfServiceMode.DUPLICATES_OK, true, 1);
  }

  public void testStressSameServer_OnceAndOnlyOnce_P_1() throws Exception {
    testStressSameServer(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, true, 1);
  }

  public void testStressSameServer_AtMostOnce_NP_1() throws Exception {
    testStressSameServer(QualityOfServiceMode.AT_MOST_ONCE, false, 1);
  }

  public void testStressSameServer_DuplicatesOk_NP_1() throws Exception {
    testStressSameServer(QualityOfServiceMode.DUPLICATES_OK, false, 1);
  }

  public void testStressSameServer_OnceAndOnlyOnce_NP_1() throws Exception {
    testStressSameServer(QualityOfServiceMode.ONCE_AND_ONLY_ONCE, false, 1);
  }

  public void testParams() throws Exception {
    BridgeImpl bridge = null;

    try {
      QualityOfServiceMode qosMode = QualityOfServiceMode.AT_MOST_ONCE;

      int batchSize = 10;

      int maxBatchTime = -1;

      String sourceUsername = null;

      String sourcePassword = null;

      String destUsername = null;

      String destPassword = null;

      String selector = null;

      long failureRetryInterval = 5000;

      int maxRetries = 10;

      String subName = null;

      String clientID = null;

      try {
        bridge =
            new BridgeImpl(
                null,
                cff1,
                sourceQueueFactory,
                targetQueueFactory,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                failureRetryInterval,
                maxRetries,
                qosMode,
                batchSize,
                maxBatchTime,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }

      try {
        bridge =
            new BridgeImpl(
                cff0,
                null,
                sourceQueueFactory,
                targetQueueFactory,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                failureRetryInterval,
                maxRetries,
                qosMode,
                batchSize,
                maxBatchTime,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }

      try {
        bridge =
            new BridgeImpl(
                cff0,
                cff1,
                null,
                targetQueueFactory,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                failureRetryInterval,
                maxRetries,
                qosMode,
                batchSize,
                maxBatchTime,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }

      try {
        bridge =
            new BridgeImpl(
                cff0,
                cff1,
                sourceQueueFactory,
                null,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                failureRetryInterval,
                maxRetries,
                qosMode,
                batchSize,
                maxBatchTime,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }

      try {
        bridge =
            new BridgeImpl(
                cff0,
                cff1,
                sourceQueueFactory,
                targetQueueFactory,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                -2,
                maxRetries,
                qosMode,
                batchSize,
                maxBatchTime,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }

      try {
        bridge =
            new BridgeImpl(
                cff0,
                cff1,
                sourceQueueFactory,
                targetQueueFactory,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                -1,
                10,
                qosMode,
                batchSize,
                maxBatchTime,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }

      try {
        bridge =
            new BridgeImpl(
                cff0,
                cff1,
                sourceQueueFactory,
                null,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                failureRetryInterval,
                maxRetries,
                qosMode,
                0,
                maxBatchTime,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }

      try {
        bridge =
            new BridgeImpl(
                cff0,
                cff1,
                sourceQueueFactory,
                null,
                sourceUsername,
                sourcePassword,
                destUsername,
                destPassword,
                selector,
                failureRetryInterval,
                maxRetries,
                qosMode,
                batchSize,
                -2,
                subName,
                clientID,
                false);
      } catch (IllegalArgumentException e) {
        // Ok
      }
    } finally {
      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  public void testSelector() throws Exception {
    BridgeImpl bridge = null;

    Connection connSource = null;

    Connection connTarget = null;

    try {
      final int NUM_MESSAGES = 10;

      String selector = "vegetable='radish'";

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              selector,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              false);

      bridge.start();

      connSource = cf0.createConnection();

      Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSend.createProducer(sourceQueue);

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = sessSend.createTextMessage("message" + i);

        if (i >= NUM_MESSAGES / 2) {
          tm.setStringProperty("vegetable", "radish");
        } else {
          tm.setStringProperty("vegetable", "cauliflower");
        }

        prod.send(tm);
      }

      connTarget = cf1.createConnection();

      Session sessRec = connTarget.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageConsumer cons = sessRec.createConsumer(targetQueue);

      connTarget.start();

      for (int i = NUM_MESSAGES / 2; i < NUM_MESSAGES; i++) {
        TextMessage tm = (TextMessage) cons.receive(1000);

        assertNotNull(tm);

        assertEquals("message" + i, tm.getText());
      }

      Message m = cons.receive(1000);

      assertNull(m);

    } finally {
      if (connSource != null) {
        connSource.close();
      }

      if (connTarget != null) {
        connTarget.close();
      }

      if (bridge != null) {
        bridge.stop();
      }

      removeAllMessages(sourceQueue.getQueueName(), true, 0);
    }
  }

  public void testStartBridgeWithJTATransactionAlreadyRunning() throws Exception {
    BridgeImpl bridge = null;

    Transaction toResume = null;

    Transaction started = null;

    TransactionManager mgr = TransactionManagerLocator.getInstance().locate();

    try {

      toResume = mgr.suspend();

      mgr.begin();

      started = mgr.getTransaction();

      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceTopicFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              false);

      bridge.start();

      this.sendMessages(cf0, sourceTopic, 0, NUM_MESSAGES, false);

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);
    } finally {
      if (started != null) {
        try {
          started.rollback();
        } catch (Exception e) {
          log.error("Failed to rollback", e);
        }
      }

      if (toResume != null) {
        try {
          mgr.resume(toResume);
        } catch (Exception e) {
          log.error("Failed to resume", e);
        }
      }
      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  public void testNonDurableSubscriber() throws Exception {
    BridgeImpl bridge = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceTopicFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              false);

      bridge.start();

      sendMessages(cf0, sourceTopic, 0, NUM_MESSAGES, false);

      checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);
    } finally {
      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  public void testDurableSubscriber() throws Exception {
    BridgeImpl bridge = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceTopicFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              "subTest",
              "clientid123",
              false);

      bridge.start();

      sendMessages(cf0, sourceTopic, 0, NUM_MESSAGES, true);

      checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);
    } finally {
      if (bridge != null) {
        bridge.stop();
      }

      // Now unsubscribe
      Connection conn = cf0.createConnection();
      conn.setClientID("clientid123");
      Session sess = conn.createSession(false, Session.AUTO_ACKNOWLEDGE);
      sess.unsubscribe("subTest");
      conn.close();
    }
  }

  public void testMessageIDInHeaderOn() throws Exception {
    messageIDInHeader(true);
  }

  public void testMessageIDInHeaderOff() throws Exception {
    messageIDInHeader(false);
  }

  private void messageIDInHeader(boolean on) throws Exception {
    BridgeImpl bridge = null;

    Connection connSource = null;

    Connection connTarget = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              on);

      bridge.start();

      connSource = cf0.createConnection();

      connTarget = cf1.createConnection();

      log.trace("Sending " + NUM_MESSAGES + " messages");

      List ids1 = new ArrayList();

      Session sessSource = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSource.createProducer(sourceQueue);

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = sessSource.createTextMessage("message" + i);

        // We add some headers to make sure they get passed through ok
        tm.setStringProperty("wib", "uhuh");
        tm.setBooleanProperty("cheese", true);
        tm.setIntProperty("Sausages", 23);

        // We add some JMSX ones too

        tm.setStringProperty("JMSXGroupID", "mygroup543");
        tm.setIntProperty("JMSXGroupSeq", 777);

        prod.send(tm);

        ids1.add(tm.getJMSMessageID());
      }

      log.trace("Sent the first messages");

      Session sessTarget = connTarget.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageConsumer cons = sessTarget.createConsumer(targetQueue);

      connTarget.start();

      List msgs = new ArrayList();

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = (TextMessage) cons.receive(5000);

        assertNotNull(tm);

        assertEquals("message" + i, tm.getText());

        assertEquals("uhuh", tm.getStringProperty("wib"));
        assertTrue(tm.getBooleanProperty("cheese"));
        assertEquals(23, tm.getIntProperty("Sausages"));

        assertEquals("mygroup543", tm.getStringProperty("JMSXGroupID"));
        assertEquals(777, tm.getIntProperty("JMSXGroupSeq"));

        if (on) {
          String header = tm.getStringProperty(JBossMessage.JBOSS_MESSAGING_BRIDGE_MESSAGE_ID_LIST);

          assertNotNull(header);

          assertEquals(ids1.get(i), header);

          msgs.add(tm);
        }
      }

      if (on) {
        // Now we send them again back to the source

        Iterator iter = msgs.iterator();

        List ids2 = new ArrayList();

        while (iter.hasNext()) {
          Message msg = (Message) iter.next();

          prod.send(msg);

          ids2.add(msg.getJMSMessageID());
        }

        // And consume them again

        for (int i = 0; i < NUM_MESSAGES; i++) {
          TextMessage tm = (TextMessage) cons.receive(5000);

          assertNotNull(tm);

          assertEquals("message" + i, tm.getText());

          assertEquals("uhuh", tm.getStringProperty("wib"));
          assertTrue(tm.getBooleanProperty("cheese"));
          assertEquals(23, tm.getIntProperty("Sausages"));

          assertEquals("mygroup543", tm.getStringProperty("JMSXGroupID"));
          assertEquals(777, tm.getIntProperty("JMSXGroupSeq"));

          String header = tm.getStringProperty(JBossMessage.JBOSS_MESSAGING_BRIDGE_MESSAGE_ID_LIST);

          assertNotNull(header);

          assertEquals(ids1.get(i) + "," + ids2.get(i), header);
        }
      }

    } finally {
      if (bridge != null) {
        bridge.stop();
      }

      if (connSource != null) {
        connSource.close();
      }

      if (connTarget != null) {
        connTarget.close();
      }
    }
  }

  public void testPropertiesPreservedPOn() throws Exception {
    propertiesPreserved(true, true);
  }

  public void testPropertiesPreservedNPoff() throws Exception {
    propertiesPreserved(false, true);
  }

  public void testPropertiesPreservedNPOn() throws Exception {
    propertiesPreserved(false, true);
  }

  public void testPropertiesPreservedPoff() throws Exception {
    propertiesPreserved(true, true);
  }

  private void propertiesPreserved(boolean persistent, boolean messageIDInHeader) throws Exception {
    BridgeImpl bridge = null;

    Connection connSource = null;

    Connection connTarget = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              messageIDInHeader);

      bridge.start();

      connSource = cf0.createConnection();

      connTarget = cf1.createConnection();

      log.trace("Sending " + NUM_MESSAGES + " messages");

      Session sessSource = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      Session sessTarget = connTarget.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageConsumer cons = sessTarget.createConsumer(targetQueue);

      connTarget.start();

      MessageProducer prod = sessSource.createProducer(sourceQueue);

      prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);

      TextMessage tm = sessSource.createTextMessage("blahmessage");

      prod.setPriority(7);

      prod.setTimeToLive(1 * 60 * 60 * 1000);

      prod.send(tm);

      long expiration = tm.getJMSExpiration();

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      tm = (TextMessage) cons.receive(1000);

      assertNotNull(tm);

      assertEquals("blahmessage", tm.getText());

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      assertEquals(7, tm.getJMSPriority());

      assertTrue(Math.abs(expiration - tm.getJMSExpiration()) < 100);

      Message m = cons.receive(5000);

      assertNull(m);

      // Now do one with expiration = 0

      tm = sessSource.createTextMessage("blahmessage2");

      prod.setPriority(7);

      prod.setTimeToLive(0);

      prod.send(tm);

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      tm = (TextMessage) cons.receive(1000);

      assertNotNull(tm);

      assertEquals("blahmessage2", tm.getText());

      assertEquals(
          persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT,
          tm.getJMSDeliveryMode());

      assertEquals(7, tm.getJMSPriority());

      assertEquals(0, tm.getJMSExpiration());

      m = cons.receive(5000);

      assertNull(m);

      tm = sessSource.createTextMessage("blahmessage3");

      final boolean myBool = false;
      final byte myByte = (byte) 23;
      final double myDouble = 17625765d;
      final float myFloat = 87127.23f;
      final int myInt = 123;
      final long myLong = 81728712;
      final short myShort = (short) 88;
      final String myString = "ojweodewj";
      final String myJMSX = "aardvark";

      tm.setBooleanProperty("mybool", myBool);
      tm.setByteProperty("mybyte", myByte);
      tm.setDoubleProperty("mydouble", myDouble);
      tm.setFloatProperty("myfloat", myFloat);
      tm.setIntProperty("myint", myInt);
      tm.setLongProperty("mylong", myLong);
      tm.setShortProperty("myshort", myShort);
      tm.setStringProperty("mystring", myString);

      tm.setStringProperty("JMSXMyNaughtyJMSXProperty", myJMSX);

      prod.send(tm);

      tm = (TextMessage) cons.receive(1000);

      assertNotNull(tm);

      assertEquals("blahmessage3", tm.getText());

      assertEquals(myBool, tm.getBooleanProperty("mybool"));
      assertEquals(myByte, tm.getByteProperty("mybyte"));
      assertEquals(myDouble, tm.getDoubleProperty("mydouble"));
      assertEquals(myFloat, tm.getFloatProperty("myfloat"));
      assertEquals(myInt, tm.getIntProperty("myint"));
      assertEquals(myLong, tm.getLongProperty("mylong"));
      assertEquals(myShort, tm.getShortProperty("myshort"));
      assertEquals(myString, tm.getStringProperty("mystring"));
      assertEquals(myJMSX, tm.getStringProperty("JMSXMyNaughtyJMSXProperty"));

      m = cons.receive(5000);

    } finally {
      if (bridge != null) {
        bridge.stop();
      }

      if (connSource != null) {
        connSource.close();
      }

      if (connTarget != null) {
        connTarget.close();
      }
    }
  }

  public void testNoMessageIDInHeader() throws Exception {
    BridgeImpl bridge = null;

    Connection connSource = null;

    Connection connTarget = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              false);

      bridge.start();

      connSource = cf0.createConnection();

      connTarget = cf1.createConnection();

      log.trace("Sending " + NUM_MESSAGES + " messages");

      Session sessSource = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSource.createProducer(sourceQueue);

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = sessSource.createTextMessage("message" + i);

        // We add some headers to make sure they get passed through ok
        tm.setStringProperty("wib", "uhuh");
        tm.setBooleanProperty("cheese", true);
        tm.setIntProperty("Sausages", 23);

        prod.send(tm);
      }

      log.trace("Sent the first messages");

      Session sessTarget = connTarget.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageConsumer cons = sessTarget.createConsumer(targetQueue);

      connTarget.start();

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = (TextMessage) cons.receive(5000);

        assertNotNull(tm);

        assertEquals("message" + i, tm.getText());

        assertEquals("uhuh", tm.getStringProperty("wib"));
        assertTrue(tm.getBooleanProperty("cheese"));
        assertEquals(23, tm.getIntProperty("Sausages"));

        String header = tm.getStringProperty(JBossMessage.JBOSS_MESSAGING_BRIDGE_MESSAGE_ID_LIST);

        assertNull(header);
      }
    } finally {
      if (bridge != null) {
        bridge.stop();
      }

      if (connSource != null) {
        connSource.close();
      }

      if (connTarget != null) {
        connTarget.close();
      }
    }
  }

  // Private -------------------------------------------------------------------------------

  private void testStress(QualityOfServiceMode qosMode, boolean persistent, int batchSize)
      throws Exception {
    Connection connSource = null;

    BridgeImpl bridge = null;

    Thread t = null;

    try {
      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              qosMode,
              batchSize,
              -1,
              null,
              null,
              false);

      bridge.start();

      connSource = cf0.createConnection();

      Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSend.createProducer(sourceQueue);

      final int NUM_MESSAGES = 250;

      StressSender sender = new StressSender();
      sender.sess = sessSend;
      sender.prod = prod;
      sender.numMessages = NUM_MESSAGES;
      prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);

      t = new Thread(sender);

      t.start();

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);

      t.join();

      if (sender.ex != null) {
        // An error occurred during the send
        throw sender.ex;
      }

    } finally {
      if (t != null) {
        t.join(10000);
      }

      if (connSource != null) {
        try {
          connSource.close();
        } catch (Exception e) {
          log.error("Failed to close connection", e);
        }
      }

      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  private void testStressBatchTime(
      QualityOfServiceMode qosMode, boolean persistent, int maxBatchTime) throws Exception {
    Connection connSource = null;

    BridgeImpl bridge = null;

    Thread t = null;

    try {
      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              qosMode,
              2,
              maxBatchTime,
              null,
              null,
              false);

      bridge.start();

      connSource = cf0.createConnection();

      Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSend.createProducer(sourceQueue);

      final int NUM_MESSAGES = 5000;

      StressSender sender = new StressSender();
      sender.sess = sessSend;
      sender.prod = prod;
      sender.numMessages = NUM_MESSAGES;
      prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);

      t = new Thread(sender);

      t.start();

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);

      t.join();

      if (sender.ex != null) {
        // An error occurred during the send
        throw sender.ex;
      }

    } finally {
      if (t != null) {
        t.join(10000);
      }

      if (connSource != null) {
        try {
          connSource.close();
        } catch (Exception e) {
          log.error("Failed to close connection", e);
        }
      }

      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  // Both source and destination on same rm
  private void testStressSameServer(QualityOfServiceMode qosMode, boolean persistent, int batchSize)
      throws Exception {
    Connection connSource = null;

    BridgeImpl bridge = null;

    Thread t = null;

    try {
      bridge =
          new BridgeImpl(
              cff0,
              cff0,
              sourceQueueFactory,
              localTargetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              qosMode,
              batchSize,
              -1,
              null,
              null,
              false);

      bridge.start();

      connSource = cf0.createConnection();

      Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSend.createProducer(sourceQueue);

      final int NUM_MESSAGES = 2000;

      StressSender sender = new StressSender();
      sender.sess = sessSend;
      sender.prod = prod;
      sender.numMessages = NUM_MESSAGES;
      prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);

      t = new Thread(sender);

      t.start();

      this.checkAllMessageReceivedInOrder(cf0, localTargetQueue, 0, NUM_MESSAGES);

      t.join();

      if (sender.ex != null) {
        // An error occurred during the send
        throw sender.ex;
      }

    } finally {
      if (t != null) {
        t.join(10000);
      }

      if (connSource != null) {
        try {
          connSource.close();
        } catch (Exception e) {
          log.error("Failed to close connection", e);
        }
      }

      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  private void testNoMaxBatchTime(QualityOfServiceMode qosMode, boolean persistent)
      throws Exception {
    BridgeImpl bridge = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              qosMode,
              NUM_MESSAGES,
              -1,
              null,
              null,
              false);

      bridge.start();

      // Send half the messges

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES / 2, persistent);

      // Verify none are received

      this.checkEmpty(targetQueue, 1);

      // Send the other half

      this.sendMessages(cf0, sourceQueue, NUM_MESSAGES / 2, NUM_MESSAGES / 2, persistent);

      // This should now be receivable

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);

      // Send another batch with one more than batch size

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES + 1, persistent);

      // Make sure only batch size are received

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);

      // Final batch

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES - 1, persistent);

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, NUM_MESSAGES, 1);

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES - 1);
    } finally {
      if (bridge != null) {
        log.info("Stopping bridge");
        bridge.stop();
      }
    }
  }

  private void testNoMaxBatchTimeSameServer(QualityOfServiceMode qosMode, boolean persistent)
      throws Exception {
    BridgeImpl bridge = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff0,
              sourceQueueFactory,
              localTargetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              qosMode,
              NUM_MESSAGES,
              -1,
              null,
              null,
              false);

      bridge.start();

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES / 2, persistent);

      this.checkEmpty(targetQueue, 1);

      // Send the other half

      this.sendMessages(cf0, sourceQueue, NUM_MESSAGES / 2, NUM_MESSAGES / 2, persistent);

      // This should now be receivable

      this.checkAllMessageReceivedInOrder(cf0, localTargetQueue, 0, NUM_MESSAGES);

      this.checkEmpty(localTargetQueue, 0);

      this.checkEmpty(sourceQueue, 0);

      // Send another batch with one more than batch size

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES + 1, persistent);

      // Make sure only batch size are received

      this.checkAllMessageReceivedInOrder(cf0, localTargetQueue, 0, NUM_MESSAGES);

      // Final batch

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES - 1, persistent);

      this.checkAllMessageReceivedInOrder(cf0, localTargetQueue, NUM_MESSAGES, 1);

      this.checkAllMessageReceivedInOrder(cf0, localTargetQueue, 0, NUM_MESSAGES - 1);
    } finally {
      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  private void testMaxBatchTime(QualityOfServiceMode qosMode, boolean persistent) throws Exception {
    BridgeImpl bridge = null;

    try {
      final long MAX_BATCH_TIME = 3000;

      final int MAX_BATCH_SIZE = 100000; // something big so it won't reach it

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              3000,
              10,
              qosMode,
              MAX_BATCH_SIZE,
              MAX_BATCH_TIME,
              null,
              null,
              false);

      bridge.start();

      final int NUM_MESSAGES = 10;

      // Send some message

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES, persistent);

      // Verify none are received

      this.checkEmpty(targetQueue, 1);

      // Messages should now be receivable

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);
    } finally {
      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  private void testMaxBatchTimeSameServer(QualityOfServiceMode qosMode, boolean persistent)
      throws Exception {
    BridgeImpl bridge = null;

    try {
      final long MAX_BATCH_TIME = 3000;

      final int MAX_BATCH_SIZE = 100000; // something big so it won't reach it

      bridge =
          new BridgeImpl(
              cff0,
              cff0,
              sourceQueueFactory,
              localTargetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              3000,
              10,
              qosMode,
              MAX_BATCH_SIZE,
              MAX_BATCH_TIME,
              null,
              null,
              false);

      bridge.start();

      final int NUM_MESSAGES = 10;

      // Send some message

      // Send some message

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES, persistent);

      // Verify none are received

      this.checkEmpty(localTargetQueue, 0);
      ;

      // Messages should now be receivable

      this.checkAllMessageReceivedInOrder(cf0, localTargetQueue, 0, NUM_MESSAGES);
    } finally {
      if (bridge != null) {
        bridge.stop();
      }
    }
  }

  // Inner classes -------------------------------------------------------------------

  private static class StressSender implements Runnable {
    int numMessages;

    Session sess;

    MessageProducer prod;

    Exception ex;

    public void run() {
      try {
        for (int i = 0; i < numMessages; i++) {
          TextMessage tm = sess.createTextMessage("message" + i);

          prod.send(tm);

          log.trace("Sent message " + i);
        }
      } catch (Exception e) {
        log.error("Failed to send", e);
        ex = e;
      }
    }
  }
}
예제 #10
0
  private void testNoMaxBatchTime(QualityOfServiceMode qosMode, boolean persistent)
      throws Exception {
    BridgeImpl bridge = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              qosMode,
              NUM_MESSAGES,
              -1,
              null,
              null,
              false);

      bridge.start();

      // Send half the messges

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES / 2, persistent);

      // Verify none are received

      this.checkEmpty(targetQueue, 1);

      // Send the other half

      this.sendMessages(cf0, sourceQueue, NUM_MESSAGES / 2, NUM_MESSAGES / 2, persistent);

      // This should now be receivable

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);

      // Send another batch with one more than batch size

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES + 1, persistent);

      // Make sure only batch size are received

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES);

      // Final batch

      this.sendMessages(cf0, sourceQueue, 0, NUM_MESSAGES - 1, persistent);

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, NUM_MESSAGES, 1);

      this.checkAllMessageReceivedInOrder(cf1, targetQueue, 0, NUM_MESSAGES - 1);
    } finally {
      if (bridge != null) {
        log.info("Stopping bridge");
        bridge.stop();
      }
    }
  }
예제 #11
0
  // Both source and destination on same rm
  private void testStressSameServer(QualityOfServiceMode qosMode, boolean persistent, int batchSize)
      throws Exception {
    Connection connSource = null;

    BridgeImpl bridge = null;

    Thread t = null;

    try {
      bridge =
          new BridgeImpl(
              cff0,
              cff0,
              sourceQueueFactory,
              localTargetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              qosMode,
              batchSize,
              -1,
              null,
              null,
              false);

      bridge.start();

      connSource = cf0.createConnection();

      Session sessSend = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSend.createProducer(sourceQueue);

      final int NUM_MESSAGES = 2000;

      StressSender sender = new StressSender();
      sender.sess = sessSend;
      sender.prod = prod;
      sender.numMessages = NUM_MESSAGES;
      prod.setDeliveryMode(persistent ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT);

      t = new Thread(sender);

      t.start();

      this.checkAllMessageReceivedInOrder(cf0, localTargetQueue, 0, NUM_MESSAGES);

      t.join();

      if (sender.ex != null) {
        // An error occurred during the send
        throw sender.ex;
      }

    } finally {
      if (t != null) {
        t.join(10000);
      }

      if (connSource != null) {
        try {
          connSource.close();
        } catch (Exception e) {
          log.error("Failed to close connection", e);
        }
      }

      if (bridge != null) {
        bridge.stop();
      }
    }
  }
예제 #12
0
  public void testNoMessageIDInHeader() throws Exception {
    BridgeImpl bridge = null;

    Connection connSource = null;

    Connection connTarget = null;

    try {
      final int NUM_MESSAGES = 10;

      bridge =
          new BridgeImpl(
              cff0,
              cff1,
              sourceQueueFactory,
              targetQueueFactory,
              null,
              null,
              null,
              null,
              null,
              5000,
              10,
              QualityOfServiceMode.AT_MOST_ONCE,
              1,
              -1,
              null,
              null,
              false);

      bridge.start();

      connSource = cf0.createConnection();

      connTarget = cf1.createConnection();

      log.trace("Sending " + NUM_MESSAGES + " messages");

      Session sessSource = connSource.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageProducer prod = sessSource.createProducer(sourceQueue);

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = sessSource.createTextMessage("message" + i);

        // We add some headers to make sure they get passed through ok
        tm.setStringProperty("wib", "uhuh");
        tm.setBooleanProperty("cheese", true);
        tm.setIntProperty("Sausages", 23);

        prod.send(tm);
      }

      log.trace("Sent the first messages");

      Session sessTarget = connTarget.createSession(false, Session.AUTO_ACKNOWLEDGE);

      MessageConsumer cons = sessTarget.createConsumer(targetQueue);

      connTarget.start();

      for (int i = 0; i < NUM_MESSAGES; i++) {
        TextMessage tm = (TextMessage) cons.receive(5000);

        assertNotNull(tm);

        assertEquals("message" + i, tm.getText());

        assertEquals("uhuh", tm.getStringProperty("wib"));
        assertTrue(tm.getBooleanProperty("cheese"));
        assertEquals(23, tm.getIntProperty("Sausages"));

        String header = tm.getStringProperty(JBossMessage.JBOSS_MESSAGING_BRIDGE_MESSAGE_ID_LIST);

        assertNull(header);
      }
    } finally {
      if (bridge != null) {
        bridge.stop();
      }

      if (connSource != null) {
        connSource.close();
      }

      if (connTarget != null) {
        connTarget.close();
      }
    }
  }
예제 #13
0
/**
 * Implementation of a JMS Message JMS Messages only live on the client side - the server only deals
 * with MessageImpl instances
 *
 * @author <a href="mailto:[email protected]">Ovidiu Feodorov</a>
 * @author <a href="mailto:[email protected]">Tim Fox</a>
 * @author <a href="mailto:[email protected]">Tyronne Wickramarathne</a> Partially ported from
 *     JBossMQ implementation originally written by:
 * @author Norbert Lataille ([email protected])
 * @author Hiram Chirino ([email protected])
 * @author David Maplesden ([email protected])
 * @author <a href="mailto:[email protected]">Adrian Brock</a>
 * @author <a href="mailto:[email protected]">Andy Taylor</a> $Id: JBossMessage.java 3466
 *     2007-12-10 18:44:52Z timfox $
 */
public class JBossMessage implements javax.jms.Message {
  // Constants -----------------------------------------------------

  public static final SimpleString REPLYTO_HEADER_NAME = new SimpleString("JMSReplyTo");

  public static final SimpleString CORRELATIONID_HEADER_NAME = new SimpleString("JMSCorrelationID");

  public static final SimpleString JBM_MESSAGE_ID = new SimpleString("JMSMessageID");

  public static final SimpleString TYPE_HEADER_NAME = new SimpleString("JMSType");

  private static final SimpleString JMS = new SimpleString("JMS");

  private static final SimpleString JMSX = new SimpleString("JMSX");

  private static final SimpleString JMS_ = new SimpleString("JMS_");

  public static final String JMSXDELIVERYCOUNT = "JMSXDeliveryCount";

  public static final String JMSXGROUPID = "JMSXGroupID";

  // Used when bridging a message
  public static final String JBOSS_MESSAGING_BRIDGE_MESSAGE_ID_LIST = "JBM_BRIDGE_MSG_ID_LIST";

  public static final String JMS_JBOSS_SCHEDULED_DELIVERY_PROP_NAME =
      "JMS_JBOSS_SCHEDULED_DELIVERY_PROP_NAME";

  public static final byte TYPE = 0;

  // Static --------------------------------------------------------

  private static final HashSet<String> reservedIdentifiers = new HashSet<String>();

  static {
    reservedIdentifiers.add("NULL");
    reservedIdentifiers.add("TRUE");
    reservedIdentifiers.add("FALSE");
    reservedIdentifiers.add("NOT");
    reservedIdentifiers.add("AND");
    reservedIdentifiers.add("OR");
    reservedIdentifiers.add("BETWEEN");
    reservedIdentifiers.add("LIKE");
    reservedIdentifiers.add("IN");
    reservedIdentifiers.add("IS");
    reservedIdentifiers.add("ESCAPE");
  }

  private static final Logger log = Logger.getLogger(JBossMessage.class);

  public static JBossMessage createMessage(
      final ClientMessage message, final ClientSession session) {
    int type = message.getType();

    JBossMessage msg;

    switch (type) {
      case JBossMessage.TYPE:
        {
          msg = new JBossMessage(message, session);
          break;
        }
      case JBossBytesMessage.TYPE:
        {
          msg = new JBossBytesMessage(message, session);
          break;
        }
      case JBossMapMessage.TYPE:
        {
          msg = new JBossMapMessage(message, session);
          break;
        }
      case JBossObjectMessage.TYPE:
        {
          msg = new JBossObjectMessage(message, session);
          break;
        }
      case JBossStreamMessage.TYPE:
        {
          msg = new JBossStreamMessage(message, session);
          break;
        }
      case JBossTextMessage.TYPE:
        {
          msg = new JBossTextMessage(message, session);
          break;
        }
      default:
        {
          throw new IllegalArgumentException("Invalid message type " + type);
        }
    }

    return msg;
  }

  // Attributes ----------------------------------------------------

  // The underlying message
  protected ClientMessage message;

  protected MessagingBuffer body;

  private ClientSession session;

  // Read-only?
  protected boolean readOnly;

  // Cache it
  private Destination dest;

  // Cache it
  private String msgID;

  // Cache it
  private Destination replyTo;

  // Cache it
  private String jmsCorrelationID;

  // Cache it
  private String jmsType;

  private long scheduledDeliveryTime = 0;

  // Constructors --------------------------------------------------
  /** constructors for test purposes only */
  public JBossMessage() {
    message =
        new ClientMessageImpl(
            JBossMessage.TYPE,
            true,
            0,
            System.currentTimeMillis(),
            (byte) 4,
            new ByteBufferWrapper(ByteBuffer.allocate(1024)));

    // TODO - can we lazily create this?
    body = message.getBody();
  }

  public JBossMessage(byte type) {
    message =
        new ClientMessageImpl(
            type,
            true,
            0,
            System.currentTimeMillis(),
            (byte) 4,
            new ByteBufferWrapper(ByteBuffer.allocate(1024)));

    // TODO - can we lazily create this?
    body = message.getBody();
  }

  /*
   * Create a new message prior to sending
   */
  protected JBossMessage(final byte type, final ClientSession session) {
    message = session.createClientMessage(type, true, 0, System.currentTimeMillis(), (byte) 4);

    // TODO - can we lazily create this?
    body = message.getBody();
  }

  public JBossMessage(final ClientSession session) {
    this(JBossMessage.TYPE, session);
  }

  /** Constructor for when receiving a message from the server */
  public JBossMessage(final ClientMessage message, ClientSession session) {
    this.message = message;

    this.readOnly = true;

    this.session = session;

    this.body = message.getBody();
  }

  /*
   * A constructor that takes a foreign message
   */
  public JBossMessage(final Message foreign, final ClientSession session) throws JMSException {
    this(foreign, JBossMessage.TYPE, session);
  }

  protected JBossMessage(final Message foreign, final byte type, final ClientSession session)
      throws JMSException {
    this(type, session);

    setJMSTimestamp(foreign.getJMSTimestamp());

    try {
      byte[] corrIDBytes = foreign.getJMSCorrelationIDAsBytes();
      setJMSCorrelationIDAsBytes(corrIDBytes);
    } catch (JMSException e) {
      // specified as String
      String corrIDString = foreign.getJMSCorrelationID();
      if (corrIDString != null) {
        setJMSCorrelationID(corrIDString);
      }
    }

    setJMSReplyTo(foreign.getJMSReplyTo());
    setJMSDestination(foreign.getJMSDestination());
    setJMSDeliveryMode(foreign.getJMSDeliveryMode());
    setJMSExpiration(foreign.getJMSExpiration());
    setJMSPriority(foreign.getJMSPriority());
    setJMSType(foreign.getJMSType());

    // We can't avoid a cast warning here since getPropertyNames() is on the JMS API
    for (Enumeration<String> props = foreign.getPropertyNames(); props.hasMoreElements(); ) {
      String name = (String) props.nextElement();

      Object prop = foreign.getObjectProperty(name);

      this.setObjectProperty(name, prop);
    }
  }

  // javax.jmx.Message implementation ------------------------------

  public String getJMSMessageID() {
    if (msgID == null) {
      SimpleString id = (SimpleString) message.getProperty(JBM_MESSAGE_ID);

      msgID = id == null ? null : id.toString();
    }
    return msgID;
  }

  public void setJMSMessageID(final String jmsMessageID) throws JMSException {
    if (jmsMessageID != null && !jmsMessageID.startsWith("ID:")) {
      throw new JMSException("JMSMessageID must start with ID:");
    }
    if (jmsMessageID == null) {
      message.removeProperty(JBM_MESSAGE_ID);
    } else {
      message.putStringProperty(JBM_MESSAGE_ID, new SimpleString(jmsMessageID));
    }
    msgID = jmsMessageID;
  }

  public long getJMSTimestamp() throws JMSException {
    return message.getTimestamp();
  }

  public void setJMSTimestamp(final long timestamp) throws JMSException {
    message.setTimestamp(timestamp);
  }

  public byte[] getJMSCorrelationIDAsBytes() throws JMSException {
    Object obj = message.getProperty(CORRELATIONID_HEADER_NAME);

    if (obj instanceof byte[]) {
      return (byte[]) obj;
    } else {
      return null;
    }
  }

  public void setJMSCorrelationIDAsBytes(final byte[] correlationID) throws JMSException {
    if (correlationID == null || correlationID.length == 0) {
      throw new JMSException("Please specify a non-zero length byte[]");
    }
    message.putBytesProperty(CORRELATIONID_HEADER_NAME, correlationID);
  }

  public void setJMSCorrelationID(final String correlationID) throws JMSException {
    if (correlationID == null) {
      message.removeProperty(CORRELATIONID_HEADER_NAME);

      jmsCorrelationID = null;
    } else {
      message.putStringProperty(CORRELATIONID_HEADER_NAME, new SimpleString(correlationID));

      jmsCorrelationID = correlationID;
    }
  }

  public String getJMSCorrelationID() throws JMSException {
    if (jmsCorrelationID == null) {
      Object obj = message.getProperty(CORRELATIONID_HEADER_NAME);

      if (obj != null) {
        jmsCorrelationID = ((SimpleString) obj).toString();
      }
    }

    return jmsCorrelationID;
  }

  public long getScheduledDeliveryTime() {
    return scheduledDeliveryTime;
  }

  public void setScheduledDeliveryTime(long scheduledDeliveryTime) {
    message.putLongProperty(
        new SimpleString(JMS_JBOSS_SCHEDULED_DELIVERY_PROP_NAME), scheduledDeliveryTime);
    this.scheduledDeliveryTime = scheduledDeliveryTime;
  }

  public Destination getJMSReplyTo() throws JMSException {
    if (replyTo == null) {
      SimpleString repl = (SimpleString) message.getProperty(REPLYTO_HEADER_NAME);

      if (repl != null) {
        replyTo = JBossDestination.fromAddress(repl.toString());
      }
    }
    return replyTo;
  }

  public void setJMSReplyTo(final Destination dest) throws JMSException {
    if (dest == null) {
      message.removeProperty(REPLYTO_HEADER_NAME);

      replyTo = null;
    } else {
      if (dest instanceof JBossDestination == false) {
        throw new InvalidDestinationException("Not a JBoss destination " + dest);
      }

      JBossDestination jbd = (JBossDestination) dest;

      message.putStringProperty(REPLYTO_HEADER_NAME, jbd.getSimpleAddress());

      replyTo = jbd;
    }
  }

  public Destination getJMSDestination() throws JMSException {
    if (dest == null) {
      SimpleString sdest = message.getDestination();

      dest = sdest == null ? null : JBossDestination.fromAddress(sdest.toString());
    }

    return dest;
  }

  public void setJMSDestination(final Destination destination) throws JMSException {
    this.dest = destination;
  }

  public int getJMSDeliveryMode() throws JMSException {
    return message.isDurable() ? DeliveryMode.PERSISTENT : DeliveryMode.NON_PERSISTENT;
  }

  public void setJMSDeliveryMode(final int deliveryMode) throws JMSException {
    if (deliveryMode == DeliveryMode.PERSISTENT) {
      message.setDurable(true);
    } else if (deliveryMode == DeliveryMode.NON_PERSISTENT) {
      message.setDurable(false);
    } else {
      throw new JMSException(
          "DeliveryImpl mode must be either DeliveryMode.PERSISTENT "
              + "or DeliveryMode.NON_PERSISTENT");
    }
  }

  public boolean getJMSRedelivered() throws JMSException {
    return message.getDeliveryCount() > 1;
  }

  public void setJMSRedelivered(final boolean redelivered) throws JMSException {
    if (!redelivered) {
      message.setDeliveryCount(1);
    } else {
      if (message.getDeliveryCount() > 1) {
        // do nothing
      } else {
        message.setDeliveryCount(2);
      }
    }
  }

  public void setJMSType(final String type) throws JMSException {
    if (type != null) {
      message.putStringProperty(TYPE_HEADER_NAME, new SimpleString(type));

      jmsType = type;
    }
  }

  public String getJMSType() throws JMSException {
    if (jmsType == null) {
      SimpleString ss = (SimpleString) message.getProperty(TYPE_HEADER_NAME);

      if (ss != null) {
        jmsType = ss.toString();
      }
    }
    return jmsType;
  }

  public long getJMSExpiration() throws JMSException {
    return message.getExpiration();
  }

  public void setJMSExpiration(final long expiration) throws JMSException {
    message.setExpiration(expiration);
  }

  public int getJMSPriority() throws JMSException {
    return message.getPriority();
  }

  public void setJMSPriority(final int priority) throws JMSException {
    checkPriority(priority);

    message.setPriority((byte) priority);
  }

  public void clearProperties() throws JMSException {
    List<SimpleString> toRemove = new ArrayList<SimpleString>();

    for (SimpleString propName : message.getPropertyNames()) {
      if (!propName.startsWith(JMS) || propName.startsWith(JMSX) || propName.startsWith(JMS_)) {
        toRemove.add(propName);
      }
    }

    for (SimpleString propName : toRemove) {
      message.removeProperty(propName);
    }
  }

  public void clearBody() throws JMSException {
    readOnly = false;
  }

  public boolean propertyExists(final String name) throws JMSException {
    return message.containsProperty(new SimpleString(name))
        || name.equals(JMSXDELIVERYCOUNT)
        || (JMSXGROUPID.equals(name) && message.containsProperty(MessageImpl.GROUP_ID));
  }

  public boolean getBooleanProperty(final String name) throws JMSException {
    Object value = message.getProperty(new SimpleString(name));
    if (value == null) return Boolean.valueOf(null).booleanValue();

    if (value instanceof Boolean) return ((Boolean) value).booleanValue();
    else if (value instanceof SimpleString)
      return Boolean.valueOf(((SimpleString) value).toString()).booleanValue();
    else throw new MessageFormatException("Invalid conversion");
  }

  public byte getByteProperty(final String name) throws JMSException {
    Object value = message.getProperty(new SimpleString(name));
    if (value == null) throw new NumberFormatException("Message property '" + name + "' not set.");

    if (value instanceof Byte) return ((Byte) value).byteValue();
    else if (value instanceof SimpleString)
      return Byte.parseByte(((SimpleString) value).toString());
    else throw new MessageFormatException("Invalid conversion");
  }

  public short getShortProperty(final String name) throws JMSException {
    Object value = message.getProperty(new SimpleString(name));
    if (value == null) throw new NumberFormatException("Message property '" + name + "' not set.");

    if (value instanceof Byte) return ((Byte) value).shortValue();
    else if (value instanceof Short) return ((Short) value).shortValue();
    else if (value instanceof SimpleString)
      return Short.parseShort(((SimpleString) value).toString());
    else throw new MessageFormatException("Invalid conversion");
  }

  public int getIntProperty(final String name) throws JMSException {
    if (JMSXDELIVERYCOUNT.equals(name)) {
      return message.getDeliveryCount();
    }

    Object value = message.getProperty(new SimpleString(name));

    if (value == null) {
      throw new NumberFormatException("Message property '" + name + "' not set.");
    }

    if (value instanceof Byte) {
      return ((Byte) value).intValue();
    } else if (value instanceof Short) {
      return ((Short) value).intValue();
    } else if (value instanceof Integer) {
      return ((Integer) value).intValue();
    } else if (value instanceof SimpleString) {
      return Integer.parseInt(((SimpleString) value).toString());
    } else {
      throw new MessageFormatException("Invalid conversion");
    }
  }

  public long getLongProperty(final String name) throws JMSException {
    if (JMSXDELIVERYCOUNT.equals(name)) {
      return message.getDeliveryCount();
    }

    Object value = message.getProperty(new SimpleString(name));

    if (value == null) {
      throw new NumberFormatException("Message property '" + name + "' not set.");
    }

    if (value instanceof Byte) {
      return ((Byte) value).longValue();
    } else if (value instanceof Short) {
      return ((Short) value).longValue();
    } else if (value instanceof Integer) {
      return ((Integer) value).longValue();
    } else if (value instanceof Long) {
      return ((Long) value).longValue();
    } else if (value instanceof SimpleString) {
      return Long.parseLong(((SimpleString) value).toString());
    } else {
      throw new MessageFormatException("Invalid conversion");
    }
  }

  public float getFloatProperty(final String name) throws JMSException {
    Object value = message.getProperty(new SimpleString(name));
    if (value == null) return Float.valueOf(null).floatValue();

    if (value instanceof Float) return ((Float) value).floatValue();
    else if (value instanceof SimpleString)
      return Float.parseFloat(((SimpleString) value).toString());
    else throw new MessageFormatException("Invalid conversion");
  }

  public double getDoubleProperty(final String name) throws JMSException {
    Object value = message.getProperty(new SimpleString(name));
    if (value == null) return Double.valueOf(null).doubleValue();

    if (value instanceof Float) return ((Float) value).doubleValue();
    else if (value instanceof Double) return ((Double) value).doubleValue();
    else if (value instanceof SimpleString)
      return Double.parseDouble(((SimpleString) value).toString());
    else throw new MessageFormatException("Invalid conversion");
  }

  public String getStringProperty(final String name) throws JMSException {
    if (JMSXDELIVERYCOUNT.equals(name)) {
      return String.valueOf(message.getDeliveryCount());
    }
    Object value;
    if (JMSXGROUPID.equals(name)) {
      value = message.getProperty(MessageImpl.GROUP_ID);
    } else {
      value = message.getProperty(new SimpleString(name));
    }
    if (value == null) return null;

    if (value instanceof SimpleString) {
      return ((SimpleString) value).toString();
    } else if (value instanceof Boolean) {
      return value.toString();
    } else if (value instanceof Byte) {
      return value.toString();
    } else if (value instanceof Short) {
      return value.toString();
    } else if (value instanceof Integer) {
      return value.toString();
    } else if (value instanceof Long) {
      return value.toString();
    } else if (value instanceof Float) {
      return value.toString();
    } else if (value instanceof Double) {
      return value.toString();
    } else {
      throw new MessageFormatException("Invalid conversion");
    }
  }

  public Object getObjectProperty(final String name) throws JMSException {
    if (JMSXDELIVERYCOUNT.equals(name)) {
      return String.valueOf(message.getDeliveryCount());
    }
    Object val = message.getProperty(new SimpleString(name));
    if (val instanceof SimpleString) {
      val = ((SimpleString) val).toString();
    }
    return val;
  }

  public Enumeration getPropertyNames() throws JMSException {
    HashSet<String> set = new HashSet<String>();

    for (SimpleString propName : message.getPropertyNames()) {
      if (!propName.startsWith(JMS) || propName.startsWith(JMSX) || propName.startsWith(JMS_)) {
        set.add(propName.toString());
      }
    }

    set.add(JMSXDELIVERYCOUNT);

    return Collections.enumeration(set);
  }

  public void setBooleanProperty(final String name, final boolean value) throws JMSException {
    Boolean b = Boolean.valueOf(value);
    checkProperty(name, b);
    message.putBooleanProperty(new SimpleString(name), b);
  }

  public void setByteProperty(final String name, final byte value) throws JMSException {
    Byte b = new Byte(value);
    checkProperty(name, b);
    message.putByteProperty(new SimpleString(name), value);
  }

  public void setShortProperty(final String name, final short value) throws JMSException {
    Short s = new Short(value);
    checkProperty(name, s);
    message.putShortProperty(new SimpleString(name), value);
  }

  public void setIntProperty(final String name, final int value) throws JMSException {
    Integer i = new Integer(value);
    checkProperty(name, i);
    message.putIntProperty(new SimpleString(name), value);
  }

  public void setLongProperty(final String name, final long value) throws JMSException {
    Long l = new Long(value);
    checkProperty(name, l);
    if (JMS_JBOSS_SCHEDULED_DELIVERY_PROP_NAME.equals(name)) {
      scheduledDeliveryTime = l;
    }
    message.putLongProperty(new SimpleString(name), value);
  }

  public void setFloatProperty(final String name, final float value) throws JMSException {
    Float f = new Float(value);
    checkProperty(name, f);
    message.putFloatProperty(new SimpleString(name), f);
  }

  public void setDoubleProperty(final String name, final double value) throws JMSException {
    Double d = new Double(value);
    checkProperty(name, d);
    message.putDoubleProperty(new SimpleString(name), d);
  }

  public void setStringProperty(final String name, final String value) throws JMSException {
    checkProperty(name, value);
    if (JMSXGROUPID.equals(name)) {
      message.putStringProperty(MessageImpl.GROUP_ID, new SimpleString(value));
    } else {
      message.putStringProperty(new SimpleString(name), new SimpleString(value));
    }
  }

  public void setObjectProperty(final String name, final Object value) throws JMSException {
    checkProperty(name, value);

    SimpleString key = new SimpleString(name);

    if (value instanceof Boolean) {
      message.putBooleanProperty(key, (Boolean) value);
    } else if (value instanceof Byte) {
      message.putByteProperty(key, (Byte) value);
    } else if (value instanceof Short) {
      message.putShortProperty(key, (Short) value);
    } else if (value instanceof Integer) {
      message.putIntProperty(key, (Integer) value);
    } else if (value instanceof Long) {
      message.putLongProperty(key, (Long) value);
    } else if (value instanceof Float) {
      message.putFloatProperty(key, (Float) value);
    } else if (value instanceof Double) {
      message.putDoubleProperty(key, (Double) value);
    } else if (value instanceof String) {
      message.putStringProperty(key, new SimpleString((String) value));
    } else {
      throw new MessageFormatException("Invalid property type");
    }
  }

  public void acknowledge() throws JMSException {
    try {
      session.commit();
    } catch (MessagingException e) {
      JMSException je = new JMSException(e.toString());

      je.initCause(e);

      throw je;
    }
  }

  // Public --------------------------------------------------------

  public ClientMessage getCoreMessage() {
    return message;
  }

  public void doBeforeSend() throws Exception {
    body.flip();

    message.setBody(body);
  }

  public void doBeforeReceive() throws Exception {
    body = message.getBody();
  }

  public byte getType() {
    return JBossMessage.TYPE;
  }

  public ClientSession getSession() {
    return session;
  }

  public String toString() {
    StringBuffer sb = new StringBuffer("JBossMessage[");
    sb.append("");
    sb.append(getJMSMessageID());
    sb.append("]:");
    sb.append(message.isDurable() ? "PERSISTENT" : "NON-PERSISTENT");
    return sb.toString();
  }

  // Package protected ---------------------------------------------

  // Protected -----------------------------------------------------

  protected void checkWrite() throws JMSException {
    if (readOnly) {
      throw new MessageNotWriteableException("Message is read-only");
    }
  }

  protected void checkRead() throws JMSException {
    if (!readOnly) {
      throw new MessageNotReadableException("Message is write-only");
    }
  }

  // Private ------------------------------------------------------------

  private void checkProperty(final String name, final Object value) throws JMSException {
    checkWrite();

    if (name == null) {
      throw new IllegalArgumentException("The name of a property must not be null.");
    }

    if (name.equals("")) {
      throw new IllegalArgumentException("The name of a property must not be an empty String.");
    }

    if (!isValidJavaIdentifier(name)) {
      throw new IllegalArgumentException(
          "The property name '" + name + "' is not a valid java identifier.");
    }

    if (reservedIdentifiers.contains(name)) {
      throw new IllegalArgumentException(
          "The property name '" + name + "' is reserved due to selector syntax.");
    }

    if (name.startsWith("JMS")) {
      if (name.length() > 3) {
        char c = name.charAt(3);
        if (c != 'X' && c != '_') {
          // See http://java.sun.com/javaee/5/docs/api/
          // (java.jms.Message javadoc)
          // "Property names must obey the rules for a message selector identifier"
          // "Any name that does not begin with 'JMS' is an application-specific property name"
          throw new IllegalArgumentException(
              "The property name '" + name + "' is illegal since it starts with JMS");
        }
      } else {
        throw new IllegalArgumentException(
            "The property name '" + name + "' is illegal since it starts with JMS");
      }
    }
  }

  private boolean isValidJavaIdentifier(final String s) {
    if (s == null || s.length() == 0) {
      return false;
    }

    char[] c = s.toCharArray();

    if (!Character.isJavaIdentifierStart(c[0])) {
      return false;
    }

    for (int i = 1; i < c.length; i++) {
      if (!Character.isJavaIdentifierPart(c[i])) {
        return false;
      }
    }

    return true;
  }

  private void checkPriority(int priority) throws JMSException {
    if (priority < 0 || priority > 9) {
      throw new JMSException(priority + " is not valid: priority must be between 0 and 9");
    }
  }

  // Inner classes -------------------------------------------------
}