@Override
  public Map<String, Object>[] listMessages(final String filterStr) throws Exception {
    checkStarted();

    clearIO();
    try {
      Filter filter = FilterImpl.createFilter(filterStr);
      List<Map<String, Object>> messages = new ArrayList<>();
      queue.flushExecutor();
      try (LinkedListIterator<MessageReference> iterator = queue.totalIterator()) {
        while (iterator.hasNext()) {
          MessageReference ref = iterator.next();
          if (filter == null || filter.match(ref.getMessage())) {
            Message message = ref.getMessage();
            messages.add(message.toMap());
          }
        }
        return messages.toArray(new Map[messages.size()]);
      }
    } catch (ActiveMQException e) {
      throw new IllegalStateException(e.getMessage());
    } finally {
      blockOnIO();
    }
  }
  @Override
  public long countMessages(final String filterStr) throws Exception {
    checkStarted();

    clearIO();
    try {
      Filter filter = FilterImpl.createFilter(filterStr);
      if (filter == null) {
        return getMessageCount();
      } else {
        try (LinkedListIterator<MessageReference> iterator = queue.totalIterator()) {
          int count = 0;
          while (iterator.hasNext()) {
            MessageReference ref = iterator.next();
            if (filter.match(ref.getMessage())) {
              count++;
            }
          }
          return count;
        }
      }
    } finally {
      blockOnIO();
    }
  }
  @Override
  public CompositeData[] browse(String filterStr) throws Exception {
    checkStarted();

    clearIO();
    try {
      int pageSize =
          addressSettingsRepository
              .getMatch(queue.getName().toString())
              .getManagementBrowsePageSize();
      int currentPageSize = 0;
      ArrayList<CompositeData> c = new ArrayList<>();
      Filter filter = FilterImpl.createFilter(filterStr);
      queue.flushExecutor();
      try (LinkedListIterator<MessageReference> iterator = queue.totalIterator()) {
        while (iterator.hasNext() && currentPageSize++ < pageSize) {
          MessageReference ref = iterator.next();
          if (filter == null || filter.match(ref.getMessage())) {
            c.add(OpenTypeSupport.convert(ref));
          }
        }
        CompositeData[] rc = new CompositeData[c.size()];
        c.toArray(rc);
        return rc;
      }
    } catch (ActiveMQException e) {
      throw new IllegalStateException(e.getMessage());
    } finally {
      blockOnIO();
    }
  }
  @Override
  public synchronized void addTail(final MessageReference ref, final boolean direct) {
    SimpleString prop = ref.getMessage().getSimpleStringProperty(Message.HDR_LAST_VALUE_NAME);

    if (prop != null) {
      HolderReference hr = map.get(prop);

      if (hr != null) {
        // We need to overwrite the old ref with the new one and ack the old one

        MessageReference oldRef = hr.getReference();

        referenceHandled();

        try {
          oldRef.acknowledge();
        } catch (Exception e) {
          ActiveMQServerLogger.LOGGER.errorAckingOldReference(e);
        }

        hr.setReference(ref);

      } else {
        hr = new HolderReference(prop, ref);

        map.put(prop, hr);

        super.addTail(hr, direct);
      }
    } else {
      super.addTail(ref, direct);
    }
  }
  @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;
      }
    }
  }
 /**
  * @param refs
  * @return
  */
 private Map<String, Object>[] convertMessagesToMaps(List<MessageReference> refs)
     throws ActiveMQException {
   Map<String, Object>[] messages = new Map[refs.size()];
   int i = 0;
   for (MessageReference ref : refs) {
     Message message = ref.getMessage();
     messages[i++] = message.toMap();
   }
   return messages;
 }
  @Override
  public void handleAddMessage(Map<Long, Map<Long, AddMessageRecord>> queueMap) throws Exception {
    for (Map.Entry<Long, Map<Long, AddMessageRecord>> entry : queueMap.entrySet()) {
      long queueID = entry.getKey();

      Map<Long, AddMessageRecord> queueRecords = entry.getValue();

      Queue queue = this.queues.get(queueID);

      if (queue == null) {
        if (queueRecords.values().size() != 0) {
          ActiveMQServerLogger.LOGGER.journalCannotFindQueueForMessage(queueID);
        }

        continue;
      }

      // Redistribution could install a Redistributor while we are still loading records, what will
      // be an issue with
      // prepared ACKs
      // We make sure te Queue is paused before we reroute values.
      queue.pause();

      Collection<AddMessageRecord> valueRecords = queueRecords.values();

      long currentTime = System.currentTimeMillis();

      for (AddMessageRecord record : valueRecords) {
        long scheduledDeliveryTime = record.getScheduledDeliveryTime();

        if (scheduledDeliveryTime != 0 && scheduledDeliveryTime <= currentTime) {
          scheduledDeliveryTime = 0;
          record.getMessage().removeProperty(Message.HDR_SCHEDULED_DELIVERY_TIME);
        }

        if (scheduledDeliveryTime != 0) {
          record
              .getMessage()
              .putLongProperty(Message.HDR_SCHEDULED_DELIVERY_TIME, scheduledDeliveryTime);
        }

        MessageReference ref = postOffice.reroute(record.getMessage(), queue, null);

        ref.setDeliveryCount(record.getDeliveryCount());

        if (scheduledDeliveryTime != 0) {
          record.getMessage().removeProperty(Message.HDR_SCHEDULED_DELIVERY_TIME);
        }
      }
    }
  }
  @Override
  public void handlePreparedTransaction(
      Transaction tx,
      List<MessageReference> referencesToAck,
      Xid xid,
      ResourceManager resourceManager)
      throws Exception {
    for (MessageReference ack : referencesToAck) {
      ack.getQueue().reacknowledge(tx, ack);
    }

    tx.setState(Transaction.State.PREPARED);

    resourceManager.putTransaction(xid, tx);
  }
  /**
   * @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;
  }
  @Override
  public synchronized void addHead(final MessageReference ref) {
    SimpleString prop = ref.getMessage().getSimpleStringProperty(Message.HDR_LAST_VALUE_NAME);

    if (prop != null) {
      HolderReference hr = map.get(prop);

      if (hr != null) {
        // We keep the current ref and ack the one we are returning

        super.referenceHandled();

        try {
          super.acknowledge(ref);
        } catch (Exception e) {
          ActiveMQServerLogger.LOGGER.errorAckingOldReference(e);
        }
      } else {
        map.put(prop, (HolderReference) ref);

        super.addHead(ref);
      }
    } else {
      super.addHead(ref);
    }
  }
  protected Map<String, Object>[] getFirstMessage() throws Exception {
    checkStarted();

    clearIO();
    try {
      List<Map<String, Object>> messages = new ArrayList<>();
      queue.flushExecutor();
      try (LinkedListIterator<MessageReference> iterator = queue.totalIterator()) {
        // returns just the first, as it's the first only
        if (iterator.hasNext()) {
          MessageReference ref = iterator.next();
          Message message = ref.getMessage();
          messages.add(message.toMap());
        }
        return messages.toArray(new Map[1]);
      }
    } finally {
      blockOnIO();
    }
  }
  @Override
  protected void refRemoved(MessageReference ref) {
    synchronized (this) {
      SimpleString prop = ref.getMessage().getSimpleStringProperty(Message.HDR_LAST_VALUE_NAME);

      if (prop != null) {
        map.remove(prop);
      }
    }

    super.refRemoved(ref);
  }
  private void cancelRefs() {
    LinkedList<MessageReference> list = new LinkedList<>();

    synchronized (refs) {
      list.addAll(refs.values());
      refs.clear();
    }

    if (logger.isTraceEnabled()) {
      logger.trace("BridgeImpl::cancelRefs cancelling " + list.size() + " references");
    }

    if (logger.isTraceEnabled() && list.isEmpty()) {
      logger.trace("didn't have any references to cancel on bridge " + this);
      return;
    }

    ListIterator<MessageReference> listIterator = list.listIterator(list.size());

    Queue refqueue;

    long timeBase = System.currentTimeMillis();

    while (listIterator.hasPrevious()) {
      MessageReference ref = listIterator.previous();

      if (logger.isTraceEnabled()) {
        logger.trace("BridgeImpl::cancelRefs Cancelling reference " + ref + " on bridge " + this);
      }

      refqueue = ref.getQueue();

      try {
        refqueue.cancel(ref, timeBase);
      } catch (Exception e) {
        // There isn't much we can do besides log an error
        ActiveMQServerLogger.LOGGER.errorCancellingRefOnBridge(e, ref);
      }
    }
  }
  @Override
  public void sendAcknowledged(final Message message) {
    if (logger.isTraceEnabled()) {
      logger.trace("BridgeImpl::sendAcknowledged received confirmation for message " + message);
    }
    if (active) {
      try {

        final MessageReference ref;

        synchronized (refs) {
          ref = refs.remove(message.getMessageID());
        }

        if (ref != null) {
          if (logger.isTraceEnabled()) {
            logger.trace(
                "BridgeImpl::sendAcknowledged bridge "
                    + this
                    + " Acking "
                    + ref
                    + " on queue "
                    + ref.getQueue());
          }
          ref.getQueue().acknowledge(ref);
          pendingAcks.countDown();
        } else {
          if (logger.isTraceEnabled()) {
            logger.trace(
                "BridgeImpl::sendAcknowledged bridge "
                    + this
                    + " could not find reference for message "
                    + message);
          }
        }
      } catch (Exception e) {
        ActiveMQServerLogger.LOGGER.bridgeFailedToAck(e);
      }
    }
  }
  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;
  }
  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;
  }
 @Override
 public MessageReference copy(final Queue queue) {
   return ref.copy(queue);
 }
 @Override
 public void decrementDeliveryCount() {
   ref.decrementDeliveryCount();
 }
 @Override
 public void setScheduledDeliveryTime(final long scheduledDeliveryTime) {
   ref.setScheduledDeliveryTime(scheduledDeliveryTime);
 }
 @Override
 public boolean isAlreadyAcked() {
   return ref.isAlreadyAcked();
 }
 @Override
 public Queue getQueue() {
   return ref.getQueue();
 }
 @Override
 public long getScheduledDeliveryTime() {
   return ref.getScheduledDeliveryTime();
 }
 @Override
 public void incrementDeliveryCount() {
   ref.incrementDeliveryCount();
 }
 /* (non-Javadoc)
  * @see org.apache.activemq.artemis.core.server.MessageReference#acknowledge(org.apache.activemq.artemis.core.server.MessageReference)
  */
 @Override
 public void acknowledge() throws Exception {
   ref.getQueue().acknowledge(this);
 }
 @Override
 public int getPersistedCount() {
   return ref.getPersistedCount();
 }
 @Override
 public void setPersistedCount(int count) {
   ref.setPersistedCount(count);
 }
 @Override
 public ServerMessage getMessage() {
   return ref.getMessage();
 }
 @Override
 public int getDeliveryCount() {
   return ref.getDeliveryCount();
 }
 /* (non-Javadoc)
  * @see org.apache.activemq.artemis.core.server.MessageReference#getMessageMemoryEstimate()
  */
 @Override
 public int getMessageMemoryEstimate() {
   return ref.getMessage().getMemoryEstimate();
 }
 @Override
 public void setDeliveryCount(final int deliveryCount) {
   ref.setDeliveryCount(deliveryCount);
 }