private void testBoolean(final String name, final boolean flag) throws Exception {
    message.putBooleanProperty(new SimpleString(name), flag);
    Assert.assertTrue(filter.match(message));

    message.putBooleanProperty(new SimpleString(name), !flag);
    Assert.assertTrue(!filter.match(message));
  }
  /* Hook for processing message before forwarding */
  protected ServerMessage beforeForward(final ServerMessage message) {
    if (useDuplicateDetection) {
      // We keep our own DuplicateID for the Bridge, so bouncing back and forths will work fine
      byte[] bytes = getDuplicateBytes(nodeUUID, message.getMessageID());

      message.putBytesProperty(MessageImpl.HDR_BRIDGE_DUPLICATE_ID, bytes);
    }

    if (transformer != null) {
      final ServerMessage transformedMessage = transformer.transform(message);
      if (transformedMessage != message) {
        if (logger.isDebugEnabled()) {
          logger.debug(
              "The transformer "
                  + transformer
                  + " made a copy of the message "
                  + message
                  + " as transformedMessage");
        }
      }
      return transformedMessage;
    } else {
      return message;
    }
  }
 /** @param packet */
 private void handlePageWrite(final ReplicationPageWriteMessage packet) throws Exception {
   PagedMessage pgdMessage = packet.getPagedMessage();
   pgdMessage.initMessage(storageManager);
   ServerMessage msg = pgdMessage.getMessage();
   Page page = getPage(msg.getAddress(), packet.getPageNumber());
   page.write(pgdMessage);
 }
  @Override
  public HandleStatus handle(final MessageReference ref) throws Exception {
    if (filter != null && !filter.match(ref.getMessage())) {
      return HandleStatus.NO_MATCH;
    }

    synchronized (this) {
      if (!active || !session.isWritable(this)) {
        if (logger.isDebugEnabled()) {
          logger.debug(this + "::Ignoring reference on bridge as it is set to inactive ref=" + ref);
        }
        return HandleStatus.BUSY;
      }

      if (deliveringLargeMessage) {
        return HandleStatus.BUSY;
      }

      if (logger.isTraceEnabled()) {
        logger.trace("Bridge " + this + " is handling reference=" + ref);
      }

      ref.handled();

      synchronized (refs) {
        refs.put(ref.getMessage().getMessageID(), ref);
      }

      final ServerMessage message = beforeForward(ref.getMessage());

      final SimpleString dest;

      if (forwardingAddress != null) {
        dest = forwardingAddress;
      } else {
        // Preserve the original address
        dest = message.getAddress();
      }

      pendingAcks.countUp();

      try {
        if (message.isLargeMessage()) {
          deliveringLargeMessage = true;
          deliverLargeMessage(dest, ref, (LargeServerMessage) message);
          return HandleStatus.HANDLED;
        } else {
          return deliverStandardMessage(dest, ref, message);
        }
      } catch (Exception e) {
        // If an exception happened, we must count down immediately
        pendingAcks.countDown();
        throw e;
      }
    }
  }
  @Override
  public void serverSend(
      final Receiver receiver,
      final Delivery delivery,
      String address,
      int messageFormat,
      ByteBuf messageEncoded)
      throws Exception {
    EncodedMessage encodedMessage =
        new EncodedMessage(
            messageFormat,
            messageEncoded.array(),
            messageEncoded.arrayOffset(),
            messageEncoded.writerIndex());

    ServerMessage message = manager.getConverter().inbound(encodedMessage);
    // use the address on the receiver if not null, if null let's hope it was set correctly on the
    // message
    if (address != null) {
      message.setAddress(new SimpleString(address));
    }

    recoverContext();

    try {
      serverSession.send(message, false);

      manager
          .getServer()
          .getStorageManager()
          .afterCompleteOperations(
              new IOCallback() {
                @Override
                public void done() {
                  synchronized (connection.getLock()) {
                    delivery.settle();
                    connection.flush();
                  }
                }

                @Override
                public void onError(int errorCode, String errorMessage) {
                  synchronized (connection.getLock()) {
                    receiver.setCondition(
                        new ErrorCondition(
                            AmqpError.ILLEGAL_STATE, errorCode + ":" + errorMessage));
                    connection.flush();
                  }
                }
              });
    } finally {
      resetContext();
    }
  }
  @Test
  public void testAMQTimestamp() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("AMQTimestamp=12345678"));

    message.setTimestamp(87654321);

    Assert.assertFalse(filter.match(message));

    message.setTimestamp(12345678);

    Assert.assertTrue(filter.match(message));
  }
 @Override
 public void handleNoMessageReferences(Map<Long, ServerMessage> messages) {
   for (ServerMessage msg : messages.values()) {
     if (msg.getRefCount() == 0) {
       ActiveMQServerLogger.LOGGER.journalUnreferencedMessage(msg.getMessageID());
       try {
         storageManager.deleteMessage(msg.getMessageID());
       } catch (Exception ignored) {
         ActiveMQServerLogger.LOGGER.journalErrorDeletingMessage(ignored, msg.getMessageID());
       }
     }
   }
 }
 public boolean checkForcedConsumer(ServerMessage message) {
   if (message.containsProperty(ClientConsumerImpl.FORCED_DELIVERY_MESSAGE)) {
     System.out.println("MessagePullHandler.checkForcedConsumer");
     if (next >= 0) {
       if (timeout <= 0) {
         latch.countDown();
       } else {
         messagePullFuture =
             scheduledPool.schedule(
                 new Runnable() {
                   @Override
                   public void run() {
                     if (next >= 0) {
                       handleDeliverNullDispatch();
                     }
                   }
                 },
                 timeout,
                 TimeUnit.MILLISECONDS);
       }
     }
     return false;
   } else {
     next = -1;
     if (messagePullFuture != null) {
       messagePullFuture.cancel(true);
     }
     latch.countDown();
     return true;
   }
 }
  /**
   * @param ref
   * @param message
   * @return
   */
  private HandleStatus deliverStandardMessage(
      SimpleString dest, final MessageReference ref, ServerMessage message) {
    // if we failover during send then there is a chance that the
    // that this will throw a disconnect, we need to remove the message
    // from the acks so it will get resent, duplicate detection will cope
    // with any messages resent

    if (logger.isTraceEnabled()) {
      logger.trace("going to send message: " + message + " from " + this.getQueue());
    }

    try {
      producer.send(dest, message);
    } catch (final ActiveMQException e) {
      ActiveMQServerLogger.LOGGER.bridgeUnableToSendMessage(e, ref);

      synchronized (refs) {
        // We remove this reference as we are returning busy which means the reference will never
        // leave the Queue.
        // because of this we have to remove the reference here
        refs.remove(message.getMessageID());

        // The delivering count should also be decreased as to avoid inconsistencies
        ((QueueImpl) ref.getQueue()).decDelivering();
      }

      connectionFailed(e, false);

      return HandleStatus.BUSY;
    }

    return HandleStatus.HANDLED;
  }
  @Test
  public void testNewlineMatch() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("fooprop LIKE '%1234%'"));

    message.putStringProperty(new SimpleString("fooprop"), new SimpleString("hello1234\n"));

    Assert.assertTrue(filter.match(message));
  }
    @Override
    public void handle(Message<?> message) {
      ServerMessage msg =
          new ServerMessageImpl(
              storageManager.generateID(), VertxConstants.INITIAL_MESSAGE_BUFFER_SIZE);
      msg.setAddress(new SimpleString(queueName));
      msg.setDurable(true);
      msg.encodeMessageIDToBuffer();

      String replyAddress = message.replyAddress();
      if (replyAddress != null) {
        msg.putStringProperty(VertxConstants.VERTX_MESSAGE_REPLYADDRESS, replyAddress);
      }

      // it'd be better that Message expose its type information
      int type = getMessageType(message);

      msg.putIntProperty(VertxConstants.VERTX_MESSAGE_TYPE, type);

      manualEncodeVertxMessageBody(msg.getBodyBuffer(), message.body(), type);

      try {
        postOffice.route(msg, null, false);
      } catch (Exception e) {
        ActiveMQVertxLogger.LOGGER.error("failed to route msg " + msg, e);
      }
    }
  @Test
  public void testFilterForgets() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("color = 'RED'"));

    message.putStringProperty(new SimpleString("color"), new SimpleString("RED"));
    Assert.assertTrue(filter.match(message));
    message = new ServerMessageImpl();
    Assert.assertFalse(filter.match(message));
  }
  @Test
  public void testIS_NOT_NULLWithNullProperty() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("myNullProp IS NOT NULL"));

    assertFalse(filter.match(message));

    message.putStringProperty("myNullProp", "JMS");
    assertTrue(filter.match(message));
  }
  @Test
  public void testNOT_LIKEWithNullProperty() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("myNullProp NOT LIKE '1_3'"));

    assertFalse(filter.match(message));

    message.putStringProperty("myNullProp", "JMS");
    assertTrue(filter.match(message));
  }
  @Test
  public void testNOT_INWithNullProperty() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("myNullProp NOT IN ('foo','jms','test')"));

    assertFalse(filter.match(message));

    message.putStringProperty("myNullProp", "JMS");
    assertTrue(filter.match(message));
  }
  @Test
  public void testAMQSize() throws Exception {
    message.setAddress(RandomUtil.randomSimpleString());

    int encodeSize = message.getEncodeSize();

    Filter moreThanSmall =
        FilterImpl.createFilter(new SimpleString("AMQSize > " + (encodeSize - 1)));
    Filter lessThanLarge =
        FilterImpl.createFilter(new SimpleString("AMQSize < " + (encodeSize + 1)));

    Filter lessThanSmall = FilterImpl.createFilter(new SimpleString("AMQSize < " + encodeSize));
    Filter moreThanLarge = FilterImpl.createFilter(new SimpleString("AMQSize > " + encodeSize));

    Assert.assertTrue(moreThanSmall.match(message));
    Assert.assertTrue(lessThanLarge.match(message));

    Assert.assertFalse(lessThanSmall.match(message));
    Assert.assertFalse(moreThanLarge.match(message));
  }
  @Test
  public void testAMQDurable() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("AMQDurable='DURABLE'"));

    message.setDurable(true);

    Assert.assertTrue(filter.match(message));

    message.setDurable(false);

    Assert.assertFalse(filter.match(message));

    filter = FilterImpl.createFilter(new SimpleString("AMQDurable='NON_DURABLE'"));

    message = new ServerMessageImpl();
    message.setDurable(true);

    Assert.assertFalse(filter.match(message));

    message.setDurable(false);

    Assert.assertTrue(filter.match(message));
  }
  @Test
  public void testAMQPriority() throws Exception {
    filter = FilterImpl.createFilter(new SimpleString("AMQPriority=3"));

    for (int i = 0; i < 10; i++) {
      message.setPriority((byte) i);

      if (i == 3) {
        Assert.assertTrue(filter.match(message));
      } else {
        Assert.assertFalse(filter.match(message));
      }
    }
  }
 /**
  * We convert the core address to an ActiveMQ Destination. We use the actual address on the
  * message rather than the destination set on the consumer because it maybe different and the JMS
  * spec says that it should be what ever was set on publish/send so a divert or wildcard may mean
  * thats its different to the destination subscribed to by the consumer
  */
 public static ActiveMQDestination toAMQAddress(
     ServerMessage message, ActiveMQDestination actualDestination) {
   String address = message.getAddress().toString();
   String strippedAddress =
       address
           .replace(JMS_QUEUE_ADDRESS_PREFIX, "")
           .replace(JMS_TEMP_QUEUE_ADDRESS_PREFIX, "")
           .replace(JMS_TOPIC_ADDRESS_PREFIX, "")
           .replace(JMS_TEMP_TOPIC_ADDRESS_PREFIX, "");
   if (actualDestination.isQueue()) {
     return new ActiveMQQueue(strippedAddress);
   } else {
     return new ActiveMQTopic(strippedAddress);
   }
 }
  public static MessageDispatch createMessageDispatch(
      MessageReference reference, ServerMessage message, AMQConsumer consumer)
      throws IOException, JMSException {
    ActiveMQMessage amqMessage =
        toAMQMessage(
            reference, message, consumer.getMarshaller(), consumer.getOpenwireDestination());

    // we can use core message id for sequenceId
    amqMessage.getMessageId().setBrokerSequenceId(message.getMessageID());
    MessageDispatch md = new MessageDispatch();
    md.setConsumerId(consumer.getId());
    md.setRedeliveryCounter(reference.getDeliveryCount() - 1);
    md.setDeliverySequenceId(amqMessage.getMessageId().getBrokerSequenceId());
    md.setMessage(amqMessage);
    ActiveMQDestination destination = amqMessage.getDestination();
    md.setDestination(destination);

    return md;
  }
 public int handleDeliver(ServerMessage message, int deliveryCount) {
   MessageDispatch dispatch;
   try {
     if (messagePullHandler != null && !messagePullHandler.checkForcedConsumer(message)) {
       return 0;
     }
     // decrement deliveryCount as AMQ client tends to add 1.
     dispatch = OpenWireMessageConverter.createMessageDispatch(message, deliveryCount - 1, this);
     int size = dispatch.getMessage().getSize();
     this.deliveringRefs.add(
         new MessageInfo(dispatch.getMessage().getMessageId(), message.getMessageID(), size));
     session.deliverMessage(dispatch);
     windowAvailable.decrementAndGet();
     return size;
   } catch (IOException e) {
     return 0;
   } catch (Throwable t) {
     return 0;
   }
 }
 private void doPutStringProperty(final String key, final String value) {
   message.putStringProperty(new SimpleString(key), new SimpleString(value));
 }
  @Override
  public boolean page(
      ServerMessage message,
      final Transaction tx,
      RouteContextList listCtx,
      final ReadLock managerLock)
      throws Exception {

    if (!running) {
      throw new IllegalStateException("PagingStore(" + getStoreName() + ") not initialized");
    }

    boolean full = isFull();

    if (addressFullMessagePolicy == AddressFullMessagePolicy.DROP
        || addressFullMessagePolicy == AddressFullMessagePolicy.FAIL) {
      if (full) {
        if (!printedDropMessagesWarning) {
          printedDropMessagesWarning = true;

          ActiveMQServerLogger.LOGGER.pageStoreDropMessages(storeName, sizeInBytes.get(), maxSize);
        }

        if (message.isLargeMessage()) {
          ((LargeServerMessage) message).deleteFile();
        }

        if (addressFullMessagePolicy == AddressFullMessagePolicy.FAIL) {
          throw ActiveMQMessageBundle.BUNDLE.addressIsFull(address.toString());
        }

        // Address is full, we just pretend we are paging, and drop the data
        return true;
      } else {
        return false;
      }
    } else if (addressFullMessagePolicy == AddressFullMessagePolicy.BLOCK) {
      return false;
    }

    // We need to ensure a read lock, as depage could change the paging state
    lock.readLock().lock();

    try {
      // First check done concurrently, to avoid synchronization and increase throughput
      if (!paging) {
        return false;
      }
    } finally {
      lock.readLock().unlock();
    }

    managerLock.lock();
    try {
      lock.writeLock().lock();

      try {
        if (!paging) {
          return false;
        }

        if (!message.isDurable()) {
          // The address should never be transient when paging (even for non-persistent messages
          // when paging)
          // This will force everything to be persisted
          message.forceAddress(address);
        }

        final long transactionID = tx == null ? -1 : tx.getID();
        PagedMessage pagedMessage =
            new PagedMessageImpl(message, routeQueues(tx, listCtx), transactionID);

        if (message.isLargeMessage()) {
          ((LargeServerMessage) message).setPaged();
        }

        int bytesToWrite = pagedMessage.getEncodeSize() + Page.SIZE_RECORD;

        if (currentPageSize.addAndGet(bytesToWrite) > pageSize
            && currentPage.getNumberOfMessages() > 0) {
          // Make sure nothing is currently validating or using currentPage
          openNewPage();
          currentPageSize.addAndGet(bytesToWrite);
        }

        if (tx != null) {
          installPageTransaction(tx, listCtx);
        }

        // the apply counter will make sure we write a record on journal
        // especially on the case for non transactional sends and paging
        // doing this will give us a possibility of recovering the page counters
        applyPageCounters(tx, getCurrentPage(), listCtx);

        currentPage.write(pagedMessage);

        if (tx == null && syncNonTransactional && message.isDurable()) {
          sync();
        }

        if (isTrace) {
          ActiveMQServerLogger.LOGGER.trace(
              "Paging message "
                  + pagedMessage
                  + " on pageStore "
                  + this.getStoreName()
                  + " pageId="
                  + currentPage.getPageId());
        }

        return true;
      } finally {
        lock.writeLock().unlock();
      }
    } finally {
      managerLock.unlock();
    }
  }
  private static ActiveMQMessage toAMQMessage(
      MessageReference reference,
      ServerMessage coreMessage,
      WireFormat marshaller,
      ActiveMQDestination actualDestination)
      throws IOException {
    ActiveMQMessage amqMsg = null;
    byte coreType = coreMessage.getType();
    switch (coreType) {
      case org.apache.activemq.artemis.api.core.Message.BYTES_TYPE:
        amqMsg = new ActiveMQBytesMessage();
        break;
      case org.apache.activemq.artemis.api.core.Message.MAP_TYPE:
        amqMsg = new ActiveMQMapMessage();
        break;
      case org.apache.activemq.artemis.api.core.Message.OBJECT_TYPE:
        amqMsg = new ActiveMQObjectMessage();
        break;
      case org.apache.activemq.artemis.api.core.Message.STREAM_TYPE:
        amqMsg = new ActiveMQStreamMessage();
        break;
      case org.apache.activemq.artemis.api.core.Message.TEXT_TYPE:
        amqMsg = new ActiveMQTextMessage();
        break;
      case org.apache.activemq.artemis.api.core.Message.DEFAULT_TYPE:
        amqMsg = new ActiveMQMessage();
        break;
      default:
        throw new IllegalStateException("Unknown message type: " + coreMessage.getType());
    }

    String type = coreMessage.getStringProperty(new SimpleString("JMSType"));
    if (type != null) {
      amqMsg.setJMSType(type);
    }
    amqMsg.setPersistent(coreMessage.isDurable());
    amqMsg.setExpiration(coreMessage.getExpiration());
    amqMsg.setPriority(coreMessage.getPriority());
    amqMsg.setTimestamp(coreMessage.getTimestamp());

    Long brokerInTime = (Long) coreMessage.getObjectProperty(AMQ_MSG_BROKER_IN_TIME);
    if (brokerInTime == null) {
      brokerInTime = 0L;
    }
    amqMsg.setBrokerInTime(brokerInTime);

    ActiveMQBuffer buffer = coreMessage.getBodyBufferDuplicate();
    Boolean compressProp = (Boolean) coreMessage.getObjectProperty(AMQ_MSG_COMPRESSED);
    boolean isCompressed = compressProp == null ? false : compressProp.booleanValue();
    amqMsg.setCompressed(isCompressed);

    if (buffer != null) {
      buffer.resetReaderIndex();
      byte[] bytes = null;
      synchronized (buffer) {
        if (coreType == org.apache.activemq.artemis.api.core.Message.TEXT_TYPE) {
          SimpleString text = buffer.readNullableSimpleString();
          if (text != null) {
            ByteArrayOutputStream bytesOut = new ByteArrayOutputStream(text.length() + 4);
            OutputStream out = bytesOut;
            if (isCompressed) {
              out = new DeflaterOutputStream(out);
            }
            try (DataOutputStream dataOut = new DataOutputStream(out)) {
              MarshallingSupport.writeUTF8(dataOut, text.toString());
              bytes = bytesOut.toByteArray();
            }
          }
        } else if (coreType == org.apache.activemq.artemis.api.core.Message.MAP_TYPE) {
          TypedProperties mapData = new TypedProperties();
          // it could be a null map
          if (buffer.readableBytes() > 0) {
            mapData.decode(buffer);
            Map<String, Object> map = mapData.getMap();
            ByteArrayOutputStream out = new ByteArrayOutputStream(mapData.getEncodeSize());
            OutputStream os = out;
            if (isCompressed) {
              os = new DeflaterOutputStream(os);
            }
            try (DataOutputStream dataOut = new DataOutputStream(os)) {
              MarshallingSupport.marshalPrimitiveMap(map, dataOut);
            }
            bytes = out.toByteArray();
          }

        } else if (coreType == org.apache.activemq.artemis.api.core.Message.OBJECT_TYPE) {
          int len = buffer.readInt();
          bytes = new byte[len];
          buffer.readBytes(bytes);
          if (isCompressed) {
            ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
            try (DeflaterOutputStream out = new DeflaterOutputStream(bytesOut)) {
              out.write(bytes);
            }
            bytes = bytesOut.toByteArray();
          }
        } else if (coreType == org.apache.activemq.artemis.api.core.Message.STREAM_TYPE) {
          org.apache.activemq.util.ByteArrayOutputStream bytesOut =
              new org.apache.activemq.util.ByteArrayOutputStream();
          OutputStream out = bytesOut;
          if (isCompressed) {
            out = new DeflaterOutputStream(bytesOut);
          }
          try (DataOutputStream dataOut = new DataOutputStream(out)) {

            boolean stop = false;
            while (!stop && buffer.readable()) {
              byte primitiveType = buffer.readByte();
              switch (primitiveType) {
                case DataConstants.BOOLEAN:
                  MarshallingSupport.marshalBoolean(dataOut, buffer.readBoolean());
                  break;
                case DataConstants.BYTE:
                  MarshallingSupport.marshalByte(dataOut, buffer.readByte());
                  break;
                case DataConstants.BYTES:
                  int len = buffer.readInt();
                  byte[] bytesData = new byte[len];
                  buffer.readBytes(bytesData);
                  MarshallingSupport.marshalByteArray(dataOut, bytesData);
                  break;
                case DataConstants.CHAR:
                  char ch = (char) buffer.readShort();
                  MarshallingSupport.marshalChar(dataOut, ch);
                  break;
                case DataConstants.DOUBLE:
                  double doubleVal = Double.longBitsToDouble(buffer.readLong());
                  MarshallingSupport.marshalDouble(dataOut, doubleVal);
                  break;
                case DataConstants.FLOAT:
                  Float floatVal = Float.intBitsToFloat(buffer.readInt());
                  MarshallingSupport.marshalFloat(dataOut, floatVal);
                  break;
                case DataConstants.INT:
                  MarshallingSupport.marshalInt(dataOut, buffer.readInt());
                  break;
                case DataConstants.LONG:
                  MarshallingSupport.marshalLong(dataOut, buffer.readLong());
                  break;
                case DataConstants.SHORT:
                  MarshallingSupport.marshalShort(dataOut, buffer.readShort());
                  break;
                case DataConstants.STRING:
                  String string = buffer.readNullableString();
                  if (string == null) {
                    MarshallingSupport.marshalNull(dataOut);
                  } else {
                    MarshallingSupport.marshalString(dataOut, string);
                  }
                  break;
                default:
                  // now we stop
                  stop = true;
                  break;
              }
            }
          }
          bytes = bytesOut.toByteArray();
        } else if (coreType == org.apache.activemq.artemis.api.core.Message.BYTES_TYPE) {
          int n = buffer.readableBytes();
          bytes = new byte[n];
          buffer.readBytes(bytes);
          if (isCompressed) {
            int length = bytes.length;
            Deflater deflater = new Deflater();
            try (org.apache.activemq.util.ByteArrayOutputStream compressed =
                new org.apache.activemq.util.ByteArrayOutputStream()) {
              compressed.write(new byte[4]);
              deflater.setInput(bytes);
              deflater.finish();
              byte[] bytesBuf = new byte[1024];
              while (!deflater.finished()) {
                int count = deflater.deflate(bytesBuf);
                compressed.write(bytesBuf, 0, count);
              }
              ByteSequence byteSeq = compressed.toByteSequence();
              ByteSequenceData.writeIntBig(byteSeq, length);
              bytes = Arrays.copyOfRange(byteSeq.data, 0, byteSeq.length);
            } finally {
              deflater.end();
            }
          }
        } else {
          int n = buffer.readableBytes();
          bytes = new byte[n];
          buffer.readBytes(bytes);
          if (isCompressed) {
            try (ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
                DeflaterOutputStream out = new DeflaterOutputStream(bytesOut)) {
              out.write(bytes);
              bytes = bytesOut.toByteArray();
            }
          }
        }

        buffer.resetReaderIndex(); // this is important for topics as the buffer
        // may be read multiple times
      }

      if (bytes != null) {
        ByteSequence content = new ByteSequence(bytes);
        amqMsg.setContent(content);
      }
    }

    // we need check null because messages may come from other clients
    // and those amq specific attribute may not be set.
    Long arrival = (Long) coreMessage.getObjectProperty(AMQ_MSG_ARRIVAL);
    if (arrival == null) {
      // messages from other sources (like core client) may not set this prop
      arrival = 0L;
    }
    amqMsg.setArrival(arrival);

    String brokerPath = (String) coreMessage.getObjectProperty(AMQ_MSG_BROKER_PATH);
    if (brokerPath != null && brokerPath.isEmpty()) {
      String[] brokers = brokerPath.split(",");
      BrokerId[] bids = new BrokerId[brokers.length];
      for (int i = 0; i < bids.length; i++) {
        bids[i] = new BrokerId(brokers[i]);
      }
      amqMsg.setBrokerPath(bids);
    }

    String clusterPath = (String) coreMessage.getObjectProperty(AMQ_MSG_CLUSTER);
    if (clusterPath != null && clusterPath.isEmpty()) {
      String[] cluster = clusterPath.split(",");
      BrokerId[] bids = new BrokerId[cluster.length];
      for (int i = 0; i < bids.length; i++) {
        bids[i] = new BrokerId(cluster[i]);
      }
      amqMsg.setCluster(bids);
    }

    Integer commandId = (Integer) coreMessage.getObjectProperty(AMQ_MSG_COMMAND_ID);
    if (commandId == null) {
      commandId = -1;
    }
    amqMsg.setCommandId(commandId);

    SimpleString corrId = (SimpleString) coreMessage.getObjectProperty("JMSCorrelationID");
    if (corrId != null) {
      amqMsg.setCorrelationId(corrId.toString());
    }

    byte[] dsBytes = (byte[]) coreMessage.getObjectProperty(AMQ_MSG_DATASTRUCTURE);
    if (dsBytes != null) {
      ByteSequence seq = new ByteSequence(dsBytes);
      DataStructure ds = (DataStructure) marshaller.unmarshal(seq);
      amqMsg.setDataStructure(ds);
    }

    amqMsg.setDestination(OpenWireUtil.toAMQAddress(coreMessage, actualDestination));

    Object value = coreMessage.getObjectProperty(AMQ_MSG_GROUP_ID);
    if (value != null) {
      String groupId = value.toString();
      amqMsg.setGroupID(groupId);
    }

    Integer groupSequence = (Integer) coreMessage.getObjectProperty(AMQ_MSG_GROUP_SEQUENCE);
    if (groupSequence == null) {
      groupSequence = -1;
    }
    amqMsg.setGroupSequence(groupSequence);

    MessageId mid = null;
    byte[] midBytes = (byte[]) coreMessage.getObjectProperty(AMQ_MSG_MESSAGE_ID);
    if (midBytes != null) {
      ByteSequence midSeq = new ByteSequence(midBytes);
      mid = (MessageId) marshaller.unmarshal(midSeq);
    } else {
      mid = new MessageId(UUIDGenerator.getInstance().generateStringUUID() + ":-1");
    }

    amqMsg.setMessageId(mid);

    byte[] origDestBytes = (byte[]) coreMessage.getObjectProperty(AMQ_MSG_ORIG_DESTINATION);
    if (origDestBytes != null) {
      ActiveMQDestination origDest =
          (ActiveMQDestination) marshaller.unmarshal(new ByteSequence(origDestBytes));
      amqMsg.setOriginalDestination(origDest);
    }

    byte[] origTxIdBytes = (byte[]) coreMessage.getObjectProperty(AMQ_MSG_ORIG_TXID);
    if (origTxIdBytes != null) {
      TransactionId origTxId =
          (TransactionId) marshaller.unmarshal(new ByteSequence(origTxIdBytes));
      amqMsg.setOriginalTransactionId(origTxId);
    }

    byte[] producerIdBytes = (byte[]) coreMessage.getObjectProperty(AMQ_MSG_PRODUCER_ID);
    if (producerIdBytes != null) {
      ProducerId producerId = (ProducerId) marshaller.unmarshal(new ByteSequence(producerIdBytes));
      amqMsg.setProducerId(producerId);
    }

    byte[] marshalledBytes = (byte[]) coreMessage.getObjectProperty(AMQ_MSG_MARSHALL_PROP);
    if (marshalledBytes != null) {
      amqMsg.setMarshalledProperties(new ByteSequence(marshalledBytes));
    }

    amqMsg.setRedeliveryCounter(reference.getDeliveryCount() - 1);

    byte[] replyToBytes = (byte[]) coreMessage.getObjectProperty(AMQ_MSG_REPLY_TO);
    if (replyToBytes != null) {
      ActiveMQDestination replyTo =
          (ActiveMQDestination) marshaller.unmarshal(new ByteSequence(replyToBytes));
      amqMsg.setReplyTo(replyTo);
    }

    String userId = (String) coreMessage.getObjectProperty(AMQ_MSG_USER_ID);
    if (userId != null) {
      amqMsg.setUserID(userId);
    }

    Boolean isDroppable = (Boolean) coreMessage.getObjectProperty(AMQ_MSG_DROPPABLE);
    if (isDroppable != null) {
      amqMsg.setDroppable(isDroppable);
    }

    SimpleString dlqCause =
        (SimpleString) coreMessage.getObjectProperty(AMQ_MSG_DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY);
    if (dlqCause != null) {
      try {
        amqMsg.setStringProperty(
            ActiveMQMessage.DLQ_DELIVERY_FAILURE_CAUSE_PROPERTY, dlqCause.toString());
      } catch (JMSException e) {
        throw new IOException("failure to set dlq property " + dlqCause, e);
      }
    }

    Set<SimpleString> props = coreMessage.getPropertyNames();
    if (props != null) {
      for (SimpleString s : props) {
        String keyStr = s.toString();
        if (keyStr.startsWith("_AMQ") || keyStr.startsWith("__HDR_")) {
          continue;
        }
        Object prop = coreMessage.getObjectProperty(s);
        try {
          if (prop instanceof SimpleString) {
            amqMsg.setObjectProperty(s.toString(), prop.toString());
          } else {
            amqMsg.setObjectProperty(s.toString(), prop);
          }
        } catch (JMSException e) {
          throw new IOException("exception setting property " + s + " : " + prop, e);
        }
      }
    }
    try {
      amqMsg.onSend();
      amqMsg.setCompressed(isCompressed);
    } catch (JMSException e) {
      throw new IOException("Failed to covert to Openwire message", e);
    }
    return amqMsg;
  }