/**
   * This method deals with messages arrived as regular message but its contents are compressed.
   * Such messages come from message senders who are configured to compress large messages, and if
   * some of the messages are compressed below the min-large-message-size limit, they are sent as
   * regular messages. <br>
   * However when decompressing the message, we are not sure how large the message could be.. for
   * that reason we fake a large message controller that will deal with the message as it was a
   * large message <br>
   * Say that you sent a 1G message full of spaces. That could be just bellow 100K compressed but
   * you wouldn't have enough memory to decompress it
   */
  private void handleCompressedMessage(final ClientMessageInternal clMessage) throws Exception {
    ClientLargeMessageImpl largeMessage = new ClientLargeMessageImpl();
    largeMessage.retrieveExistingData(clMessage);

    File largeMessageCache = null;

    if (session.isCacheLargeMessageClient()) {
      largeMessageCache =
          File.createTempFile("tmp-large-message-" + largeMessage.getMessageID() + "-", ".tmp");
      largeMessageCache.deleteOnExit();
    }

    ClientSessionFactory sf = session.getSessionFactory();
    ServerLocator locator = sf.getServerLocator();
    long callTimeout = locator.getCallTimeout();

    currentLargeMessageController =
        new LargeMessageControllerImpl(
            this, largeMessage.getLargeMessageSize(), callTimeout, largeMessageCache);
    currentLargeMessageController.setLocal(true);

    // sets the packet
    ActiveMQBuffer qbuff = clMessage.getBodyBuffer();
    int bytesToRead = qbuff.writerIndex() - qbuff.readerIndex();
    final byte[] body = qbuff.readBytes(bytesToRead).toByteBuffer().array();

    largeMessage.setLargeMessageController(
        new CompressedLargeMessageControllerImpl(currentLargeMessageController));
    currentLargeMessageController.addPacket(body, body.length, false);

    handleRegularMessage(largeMessage);
  }
  public void decode(final ActiveMQBuffer buffer) {
    channelID = buffer.readLong();

    decodeRest(buffer);

    size = buffer.readerIndex();
  }
 @Override
 public void decodeRest(final ActiveMQBuffer buffer) {
   consumerID = buffer.readLong();
   deliveryCount = buffer.readInt();
   largeMessageSize = buffer.readLong();
   message.decodeHeadersAndProperties(buffer);
 }
 @Override
 public void encodeRest(final ActiveMQBuffer buffer) {
   buffer.writeLong(consumerID);
   buffer.writeInt(deliveryCount);
   buffer.writeLong(largeMessageSize);
   message.encodeHeadersAndProperties(buffer);
 }
  @Override
  public void encodeRest(final ActiveMQBuffer buffer) {
    buffer.writeLong(consumerID);

    buffer.writeLong(messageID);

    buffer.writeBoolean(requiresResponse);
  }
  @Override
  public void decodeRest(final ActiveMQBuffer buffer) {
    consumerID = buffer.readLong();

    messageID = buffer.readLong();

    requiresResponse = buffer.readBoolean();
  }
  /**
   * Large message version of {@link #assertMessageBody(int, ClientMessage)}.
   *
   * @param i
   * @param message
   */
  protected static void assertLargeMessageBody(final int i, final ClientMessage message) {
    ActiveMQBuffer buffer = message.getBodyBuffer();

    for (int j = 0; j < LARGE_MESSAGE_SIZE; j++) {
      Assert.assertTrue(
          "msg " + i + ", expecting " + LARGE_MESSAGE_SIZE + " bytes, got " + j, buffer.readable());
      Assert.assertEquals("equal at " + j, ActiveMQTestBase.getSamplebyte(j), buffer.readByte());
    }
  }
  @Override
  public void decode(ActiveMQBuffer buffer) {
    SimpleString policyStr = buffer.readNullableSimpleString();

    if (policyStr != null) {
      addressFullMessagePolicy = AddressFullMessagePolicy.valueOf(policyStr.toString());
    } else {
      addressFullMessagePolicy = null;
    }

    maxSizeBytes = BufferHelper.readNullableLong(buffer);

    pageSizeBytes = BufferHelper.readNullableLong(buffer);

    pageMaxCache = BufferHelper.readNullableInteger(buffer);

    dropMessagesWhenFull = BufferHelper.readNullableBoolean(buffer);

    maxDeliveryAttempts = BufferHelper.readNullableInteger(buffer);

    messageCounterHistoryDayLimit = BufferHelper.readNullableInteger(buffer);

    redeliveryDelay = BufferHelper.readNullableLong(buffer);

    redeliveryMultiplier = BufferHelper.readNullableDouble(buffer);

    maxRedeliveryDelay = BufferHelper.readNullableLong(buffer);

    deadLetterAddress = buffer.readNullableSimpleString();

    expiryAddress = buffer.readNullableSimpleString();

    expiryDelay = BufferHelper.readNullableLong(buffer);

    lastValueQueue = BufferHelper.readNullableBoolean(buffer);

    redistributionDelay = BufferHelper.readNullableLong(buffer);

    sendToDLAOnNoRoute = BufferHelper.readNullableBoolean(buffer);

    slowConsumerThreshold = BufferHelper.readNullableLong(buffer);

    slowConsumerCheckPeriod = BufferHelper.readNullableLong(buffer);

    policyStr = buffer.readNullableSimpleString();

    if (policyStr != null) {
      slowConsumerPolicy = SlowConsumerPolicy.valueOf(policyStr.toString());
    } else {
      slowConsumerPolicy = null;
    }

    autoCreateJmsQueues = BufferHelper.readNullableBoolean(buffer);

    autoDeleteJmsQueues = BufferHelper.readNullableBoolean(buffer);
  }
  @Override
  public void encodeRest(final ActiveMQBuffer buffer) {
    buffer.writeByte(journalID);

    buffer.writeBoolean(operation.toBoolean());
    buffer.writeLong(id);
    buffer.writeByte(journalRecordType);
    buffer.writeInt(encodingData.getEncodeSize());
    encodingData.encode(buffer);
  }
  @Test
  public void testCreateBuffer() throws Exception {
    EmbeddedChannel channel = createChannel();
    NettyConnection conn = new NettyConnection(emptyMap, channel, new MyListener(), false, false);

    final int size = 1234;

    ActiveMQBuffer buff = conn.createTransportBuffer(size);
    buff.writeByte((byte) 0x00); // Netty buffer does lazy initialization.
    Assert.assertEquals(size, buff.capacity());
  }
 @Override
 public void handshake(NettyServerConnection connection, ActiveMQBuffer buffer) {
   // if we are not an old client then handshake
   if (buffer.getByte(0) == 'A'
       && buffer.getByte(1) == 'R'
       && buffer.getByte(2) == 'T'
       && buffer.getByte(3) == 'E'
       && buffer.getByte(4) == 'M'
       && buffer.getByte(5) == 'I'
       && buffer.getByte(6) == 'S') {
     // todo add some handshaking
     buffer.readBytes(7);
   }
 }
  @Override
  public void encode(ActiveMQBuffer buffer) {
    buffer.writeNullableSimpleString(
        addressFullMessagePolicy != null
            ? new SimpleString(addressFullMessagePolicy.toString())
            : null);

    BufferHelper.writeNullableLong(buffer, maxSizeBytes);

    BufferHelper.writeNullableLong(buffer, pageSizeBytes);

    BufferHelper.writeNullableInteger(buffer, pageMaxCache);

    BufferHelper.writeNullableBoolean(buffer, dropMessagesWhenFull);

    BufferHelper.writeNullableInteger(buffer, maxDeliveryAttempts);

    BufferHelper.writeNullableInteger(buffer, messageCounterHistoryDayLimit);

    BufferHelper.writeNullableLong(buffer, redeliveryDelay);

    BufferHelper.writeNullableDouble(buffer, redeliveryMultiplier);

    BufferHelper.writeNullableLong(buffer, maxRedeliveryDelay);

    buffer.writeNullableSimpleString(deadLetterAddress);

    buffer.writeNullableSimpleString(expiryAddress);

    BufferHelper.writeNullableLong(buffer, expiryDelay);

    BufferHelper.writeNullableBoolean(buffer, lastValueQueue);

    BufferHelper.writeNullableLong(buffer, redistributionDelay);

    BufferHelper.writeNullableBoolean(buffer, sendToDLAOnNoRoute);

    BufferHelper.writeNullableLong(buffer, slowConsumerThreshold);

    BufferHelper.writeNullableLong(buffer, slowConsumerCheckPeriod);

    buffer.writeNullableSimpleString(
        slowConsumerPolicy != null ? new SimpleString(slowConsumerPolicy.toString()) : null);

    BufferHelper.writeNullableBoolean(buffer, autoCreateJmsQueues);

    BufferHelper.writeNullableBoolean(buffer, autoDeleteJmsQueues);
  }
  // This is called periodically to flush the batch buffer
  public void checkFlushBatchBuffer() {
    if (!batchingEnabled) {
      return;
    }

    if (writeLock.tryAcquire()) {
      try {
        if (batchBuffer != null && batchBuffer.readable()) {
          channel.writeAndFlush(batchBuffer.byteBuf());

          batchBuffer = createTransportBuffer(BATCHING_BUFFER_SIZE);
        }
      } finally {
        writeLock.release();
      }
    }
  }
 @Benchmark
 public int encodeUnalignedWithGarbage() {
   outBuffer.clear();
   final JournalAddRecord addRecord =
       new JournalAddRecord(true, 1, (byte) 1, ZeroEncodingSupport.Instance);
   addRecord.setFileID(1);
   addRecord.setCompactCount((short) 1);
   addRecord.encode(outBuffer);
   return addRecord.getEncodeSize();
 }
  public void write(
      final ActiveMQBuffer buffer,
      final boolean flush,
      final boolean batch,
      final ChannelFutureListener futureListener) {
    final ActiveMQBuffer copied = buffer.copy(0, buffer.capacity());

    copied.setIndex(buffer.readerIndex(), buffer.writerIndex());

    try {
      executor.execute(
          new Runnable() {
            public void run() {
              try {
                if (!closed) {
                  copied.readInt(); // read and discard
                  if (isTrace) {
                    ActiveMQServerLogger.LOGGER.trace(
                        InVMConnection.this + "::Sending inVM packet");
                  }
                  handler.bufferReceived(id, copied);
                  if (futureListener != null) {
                    // TODO BEFORE MERGE: (is null a good option here?)
                    futureListener.operationComplete(null);
                  }
                }
              } catch (Exception e) {
                final String msg = "Failed to write to handler on connector " + this;
                ActiveMQServerLogger.LOGGER.errorWritingToInvmConnector(e, this);
                throw new IllegalStateException(msg, e);
              } finally {
                if (isTrace) {
                  ActiveMQServerLogger.LOGGER.trace(InVMConnection.this + "::packet sent done");
                }
              }
            }
          });

      if (flush && flushEnabled) {
        final CountDownLatch latch = new CountDownLatch(1);
        executor.execute(
            new Runnable() {
              public void run() {
                latch.countDown();
              }
            });

        try {
          if (!latch.await(10, TimeUnit.SECONDS)) {
            ActiveMQServerLogger.LOGGER.timedOutFlushingInvmChannel();
          }
        } catch (InterruptedException e) {
          throw new ActiveMQInterruptedException(e);
        }
      }
    } catch (RejectedExecutionException e) {
      // Ignore - this can happen if server/client is shutdown and another request comes in
    }
  }
 @Override
 public void decodeRest(final ActiveMQBuffer buffer) {
   journalID = buffer.readByte();
   operation = ADD_OPERATION_TYPE.toOperation(buffer.readBoolean());
   id = buffer.readLong();
   journalRecordType = buffer.readByte();
   final int recordDataSize = buffer.readInt();
   recordData = new byte[recordDataSize];
   buffer.readBytes(recordData);
 }
 public StompFrame decode(ActiveMQBuffer buffer) throws ActiveMQStompException {
   StompFrame frame = null;
   try {
     frame = frameHandler.decode(buffer);
   } catch (ActiveMQStompException e) {
     switch (e.getCode()) {
       case ActiveMQStompException.INVALID_EOL_V10:
         if (version != null) throw e;
         frameHandler = new StompFrameHandlerV12(this);
         buffer.resetReaderIndex();
         frame = decode(buffer);
         break;
       case ActiveMQStompException.INVALID_COMMAND:
         frameHandler.onError(e);
         break;
       default:
         throw e;
     }
   }
   return frame;
 }
  public ActiveMQBuffer encode(final RemotingConnection connection) {
    ActiveMQBuffer buffer = connection.createTransportBuffer(PacketImpl.INITIAL_PACKET_SIZE);

    // The standard header fields

    buffer.writeInt(0); // The length gets filled in at the end
    buffer.writeByte(type);
    buffer.writeLong(channelID);

    encodeRest(buffer);

    size = buffer.writerIndex();

    // The length doesn't include the actual length byte
    int len = size - DataConstants.SIZE_INT;

    buffer.setInt(0, len);

    return buffer;
  }
  @Override
  public ServerMessage inbound(Object message) throws Exception {

    Message messageSend = (Message) message;
    ServerMessageImpl coreMessage = new ServerMessageImpl(-1, messageSend.getSize());

    String type = messageSend.getType();
    if (type != null) {
      coreMessage.putStringProperty(new SimpleString("JMSType"), new SimpleString(type));
    }
    coreMessage.setDurable(messageSend.isPersistent());
    coreMessage.setExpiration(messageSend.getExpiration());
    coreMessage.setPriority(messageSend.getPriority());
    coreMessage.setTimestamp(messageSend.getTimestamp());

    byte coreType = toCoreType(messageSend.getDataStructureType());
    coreMessage.setType(coreType);

    ActiveMQBuffer body = coreMessage.getBodyBuffer();

    ByteSequence contents = messageSend.getContent();
    if (contents == null && coreType == org.apache.activemq.artemis.api.core.Message.TEXT_TYPE) {
      body.writeNullableString(null);
    } else if (contents != null) {
      boolean messageCompressed = messageSend.isCompressed();
      if (messageCompressed) {
        coreMessage.putBooleanProperty(AMQ_MSG_COMPRESSED, messageCompressed);
      }

      switch (coreType) {
        case org.apache.activemq.artemis.api.core.Message.TEXT_TYPE:
          InputStream tis = new ByteArrayInputStream(contents);
          if (messageCompressed) {
            tis = new InflaterInputStream(tis);
          }
          DataInputStream tdataIn = new DataInputStream(tis);
          String text = MarshallingSupport.readUTF8(tdataIn);
          tdataIn.close();
          body.writeNullableSimpleString(new SimpleString(text));
          break;
        case org.apache.activemq.artemis.api.core.Message.MAP_TYPE:
          InputStream mis = new ByteArrayInputStream(contents);
          if (messageCompressed) {
            mis = new InflaterInputStream(mis);
          }
          DataInputStream mdataIn = new DataInputStream(mis);
          Map<String, Object> map = MarshallingSupport.unmarshalPrimitiveMap(mdataIn);
          mdataIn.close();
          TypedProperties props = new TypedProperties();
          loadMapIntoProperties(props, map);
          props.encode(body);
          break;
        case org.apache.activemq.artemis.api.core.Message.OBJECT_TYPE:
          if (messageCompressed) {
            try (InputStream ois = new InflaterInputStream(new ByteArrayInputStream(contents));
                org.apache.activemq.util.ByteArrayOutputStream decompressed =
                    new org.apache.activemq.util.ByteArrayOutputStream()) {
              byte[] buf = new byte[1024];
              int n = ois.read(buf);
              while (n != -1) {
                decompressed.write(buf, 0, n);
                n = ois.read();
              }
              // read done
              contents = decompressed.toByteSequence();
            }
          }
          body.writeInt(contents.length);
          body.writeBytes(contents.data, contents.offset, contents.length);
          break;
        case org.apache.activemq.artemis.api.core.Message.STREAM_TYPE:
          InputStream sis = new ByteArrayInputStream(contents);
          if (messageCompressed) {
            sis = new InflaterInputStream(sis);
          }
          DataInputStream sdis = new DataInputStream(sis);
          int stype = sdis.read();
          while (stype != -1) {
            switch (stype) {
              case MarshallingSupport.BOOLEAN_TYPE:
                body.writeByte(DataConstants.BOOLEAN);
                body.writeBoolean(sdis.readBoolean());
                break;
              case MarshallingSupport.BYTE_TYPE:
                body.writeByte(DataConstants.BYTE);
                body.writeByte(sdis.readByte());
                break;
              case MarshallingSupport.BYTE_ARRAY_TYPE:
                body.writeByte(DataConstants.BYTES);
                int slen = sdis.readInt();
                byte[] sbytes = new byte[slen];
                sdis.read(sbytes);
                body.writeInt(slen);
                body.writeBytes(sbytes);
                break;
              case MarshallingSupport.CHAR_TYPE:
                body.writeByte(DataConstants.CHAR);
                char schar = sdis.readChar();
                body.writeShort((short) schar);
                break;
              case MarshallingSupport.DOUBLE_TYPE:
                body.writeByte(DataConstants.DOUBLE);
                double sdouble = sdis.readDouble();
                body.writeLong(Double.doubleToLongBits(sdouble));
                break;
              case MarshallingSupport.FLOAT_TYPE:
                body.writeByte(DataConstants.FLOAT);
                float sfloat = sdis.readFloat();
                body.writeInt(Float.floatToIntBits(sfloat));
                break;
              case MarshallingSupport.INTEGER_TYPE:
                body.writeByte(DataConstants.INT);
                body.writeInt(sdis.readInt());
                break;
              case MarshallingSupport.LONG_TYPE:
                body.writeByte(DataConstants.LONG);
                body.writeLong(sdis.readLong());
                break;
              case MarshallingSupport.SHORT_TYPE:
                body.writeByte(DataConstants.SHORT);
                body.writeShort(sdis.readShort());
                break;
              case MarshallingSupport.STRING_TYPE:
                body.writeByte(DataConstants.STRING);
                String sstring = sdis.readUTF();
                body.writeNullableString(sstring);
                break;
              case MarshallingSupport.BIG_STRING_TYPE:
                body.writeByte(DataConstants.STRING);
                String sbigString = MarshallingSupport.readUTF8(sdis);
                body.writeNullableString(sbigString);
                break;
              case MarshallingSupport.NULL:
                body.writeByte(DataConstants.STRING);
                body.writeNullableString(null);
                break;
              default:
                // something we don't know, ignore
                break;
            }
            stype = sdis.read();
          }
          sdis.close();
          break;
        case org.apache.activemq.artemis.api.core.Message.BYTES_TYPE:
          if (messageCompressed) {
            Inflater inflater = new Inflater();
            try (org.apache.activemq.util.ByteArrayOutputStream decompressed =
                new org.apache.activemq.util.ByteArrayOutputStream()) {
              int length = ByteSequenceData.readIntBig(contents);
              contents.offset = 0;
              byte[] data = Arrays.copyOfRange(contents.getData(), 4, contents.getLength());

              inflater.setInput(data);
              byte[] buffer = new byte[length];
              int count = inflater.inflate(buffer);
              decompressed.write(buffer, 0, count);
              contents = decompressed.toByteSequence();
            } catch (Exception e) {
              throw new IOException(e);
            } finally {
              inflater.end();
            }
          }
          body.writeBytes(contents.data, contents.offset, contents.length);
          break;
        default:
          if (messageCompressed) {
            try (org.apache.activemq.util.ByteArrayOutputStream decompressed =
                    new org.apache.activemq.util.ByteArrayOutputStream();
                OutputStream os = new InflaterOutputStream(decompressed)) {
              os.write(contents.data, contents.offset, contents.getLength());
              contents = decompressed.toByteSequence();
            } catch (Exception e) {
              throw new IOException(e);
            }
          }
          body.writeBytes(contents.data, contents.offset, contents.length);
          break;
      }
    }
    // amq specific
    coreMessage.putLongProperty(AMQ_MSG_ARRIVAL, messageSend.getArrival());
    coreMessage.putLongProperty(AMQ_MSG_BROKER_IN_TIME, messageSend.getBrokerInTime());
    BrokerId[] brokers = messageSend.getBrokerPath();
    if (brokers != null) {
      StringBuilder builder = new StringBuilder();
      for (int i = 0; i < brokers.length; i++) {
        builder.append(brokers[i].getValue());
        if (i != (brokers.length - 1)) {
          builder.append(","); // is this separator safe?
        }
      }
      coreMessage.putStringProperty(AMQ_MSG_BROKER_PATH, builder.toString());
    }
    BrokerId[] cluster = messageSend.getCluster();
    if (cluster != null) {
      StringBuilder builder = new StringBuilder();
      for (int i = 0; i < cluster.length; i++) {
        builder.append(cluster[i].getValue());
        if (i != (cluster.length - 1)) {
          builder.append(","); // is this separator safe?
        }
      }
      coreMessage.putStringProperty(AMQ_MSG_CLUSTER, builder.toString());
    }

    coreMessage.putIntProperty(AMQ_MSG_COMMAND_ID, messageSend.getCommandId());
    String corrId = messageSend.getCorrelationId();
    if (corrId != null) {
      coreMessage.putStringProperty("JMSCorrelationID", corrId);
    }
    DataStructure ds = messageSend.getDataStructure();
    if (ds != null) {
      ByteSequence dsBytes = marshaller.marshal(ds);
      dsBytes.compact();
      coreMessage.putBytesProperty(AMQ_MSG_DATASTRUCTURE, dsBytes.data);
    }
    String groupId = messageSend.getGroupID();
    if (groupId != null) {
      coreMessage.putStringProperty(AMQ_MSG_GROUP_ID, groupId);
    }
    coreMessage.putIntProperty(AMQ_MSG_GROUP_SEQUENCE, messageSend.getGroupSequence());

    MessageId messageId = messageSend.getMessageId();

    ByteSequence midBytes = marshaller.marshal(messageId);
    midBytes.compact();
    coreMessage.putBytesProperty(AMQ_MSG_MESSAGE_ID, midBytes.data);

    ProducerId producerId = messageSend.getProducerId();
    if (producerId != null) {
      ByteSequence producerIdBytes = marshaller.marshal(producerId);
      producerIdBytes.compact();
      coreMessage.putBytesProperty(AMQ_MSG_PRODUCER_ID, producerIdBytes.data);
    }
    ByteSequence propBytes = messageSend.getMarshalledProperties();
    if (propBytes != null) {
      propBytes.compact();
      coreMessage.putBytesProperty(AMQ_MSG_MARSHALL_PROP, propBytes.data);
      // unmarshall properties to core so selector will work
      Map<String, Object> props = messageSend.getProperties();
      // Map<String, Object> props = MarshallingSupport.unmarshalPrimitiveMap(new
      // DataInputStream(new ByteArrayInputStream(propBytes)));
      for (Entry<String, Object> ent : props.entrySet()) {
        Object value = ent.getValue();
        try {
          coreMessage.putObjectProperty(ent.getKey(), value);
        } catch (ActiveMQPropertyConversionException e) {
          coreMessage.putStringProperty(ent.getKey(), value.toString());
        }
      }
    }

    ActiveMQDestination replyTo = messageSend.getReplyTo();
    if (replyTo != null) {
      ByteSequence replyToBytes = marshaller.marshal(replyTo);
      replyToBytes.compact();
      coreMessage.putBytesProperty(AMQ_MSG_REPLY_TO, replyToBytes.data);
    }

    ConsumerId consumerId = messageSend.getTargetConsumerId();

    String userId = messageSend.getUserID();
    if (userId != null) {
      coreMessage.putStringProperty(AMQ_MSG_USER_ID, userId);
    }
    coreMessage.putBooleanProperty(AMQ_MSG_DROPPABLE, messageSend.isDroppable());

    ActiveMQDestination origDest = messageSend.getOriginalDestination();
    if (origDest != null) {
      ByteSequence origDestBytes = marshaller.marshal(origDest);
      origDestBytes.compact();
      coreMessage.putBytesProperty(AMQ_MSG_ORIG_DESTINATION, origDestBytes.data);
    }

    return coreMessage;
  }
 @Override
 public void decodeRest(final ActiveMQBuffer buffer) {
   liveStopping = buffer.readInt() == 0 ? LiveStopping.STOP_CALLED : LiveStopping.FAIL_OVER;
 }
 @Override
 public void encodeRest(final ActiveMQBuffer buffer) {
   buffer.writeInt(liveStopping.code);
 }
  public static ActiveMQBuffer toActiveMQBuffer(ByteSequence bytes) {
    ActiveMQBuffer buffer = ActiveMQBuffers.fixedBuffer(bytes.length);

    buffer.writeBytes(bytes.data, bytes.offset, bytes.length);
    return buffer;
  }
 @Override
 public void decodeRest(final ActiveMQBuffer buffer) {
   name = buffer.readString();
   lastConfirmedCommandID = buffer.readInt();
 }
 @Override
 public void encodeRest(final ActiveMQBuffer buffer) {
   buffer.writeString(name);
   buffer.writeInt(lastConfirmedCommandID);
 }
 @Override
 public void encodeRest(ActiveMQBuffer buffer) {
   buffer.writeSimpleString(targetNodeId);
   buffer.writeSimpleString(scaledDownNodeId);
 }
 @Override
 public void decodeRest(ActiveMQBuffer buffer) {
   targetNodeId = buffer.readSimpleString();
   scaledDownNodeId = buffer.readSimpleString();
 }
 @Benchmark
 public int encodeUnaligned() {
   outBuffer.clear();
   record.encode(outBuffer);
   return record.getEncodeSize();
 }
 private void manualEncodeVertxMessageBody(ActiveMQBuffer bodyBuffer, Object body, int type) {
   switch (type) {
     case VertxConstants.TYPE_BOOLEAN:
       bodyBuffer.writeBoolean(((Boolean) body));
       break;
     case VertxConstants.TYPE_BUFFER:
       Buffer buff = (Buffer) body;
       int len = buff.length();
       bodyBuffer.writeInt(len);
       bodyBuffer.writeBytes(((Buffer) body).getBytes());
       break;
     case VertxConstants.TYPE_BYTEARRAY:
       byte[] bytes = (byte[]) body;
       bodyBuffer.writeInt(bytes.length);
       bodyBuffer.writeBytes(bytes);
       break;
     case VertxConstants.TYPE_BYTE:
       bodyBuffer.writeByte((byte) body);
       break;
     case VertxConstants.TYPE_CHARACTER:
       bodyBuffer.writeChar((Character) body);
       break;
     case VertxConstants.TYPE_DOUBLE:
       bodyBuffer.writeDouble((double) body);
       break;
     case VertxConstants.TYPE_FLOAT:
       bodyBuffer.writeFloat((Float) body);
       break;
     case VertxConstants.TYPE_INT:
       bodyBuffer.writeInt((Integer) body);
       break;
     case VertxConstants.TYPE_LONG:
       bodyBuffer.writeLong((Long) body);
       break;
     case VertxConstants.TYPE_SHORT:
       bodyBuffer.writeShort((Short) body);
       break;
     case VertxConstants.TYPE_STRING:
     case VertxConstants.TYPE_PING:
       bodyBuffer.writeString((String) body);
       break;
     case VertxConstants.TYPE_JSON_OBJECT:
       bodyBuffer.writeString(((JsonObject) body).encode());
       break;
     case VertxConstants.TYPE_JSON_ARRAY:
       bodyBuffer.writeString(((JsonArray) body).encode());
       break;
     case VertxConstants.TYPE_REPLY_FAILURE:
       ReplyException except = (ReplyException) body;
       bodyBuffer.writeInt(except.failureType().toInt());
       bodyBuffer.writeInt(except.failureCode());
       bodyBuffer.writeString(except.getMessage());
       break;
     default:
       throw new IllegalArgumentException("Invalid body type: " + type);
   }
 }
  public void write(
      ActiveMQBuffer buffer,
      final boolean flush,
      final boolean batched,
      final ChannelFutureListener futureListener) {

    try {
      writeLock.acquire();

      try {
        if (batchBuffer == null && batchingEnabled && batched && !flush) {
          // Lazily create batch buffer

          batchBuffer = ActiveMQBuffers.dynamicBuffer(BATCHING_BUFFER_SIZE);
        }

        if (batchBuffer != null) {
          batchBuffer.writeBytes(buffer, 0, buffer.writerIndex());

          if (batchBuffer.writerIndex() >= BATCHING_BUFFER_SIZE || !batched || flush) {
            // If the batch buffer is full or it's flush param or not batched then flush the buffer

            buffer = batchBuffer;
          } else {
            return;
          }

          if (!batched || flush) {
            batchBuffer = null;
          } else {
            // Create a new buffer

            batchBuffer = ActiveMQBuffers.dynamicBuffer(BATCHING_BUFFER_SIZE);
          }
        }

        // depending on if we need to flush or not we can use a voidPromise or
        // use a normal promise
        final ByteBuf buf = buffer.byteBuf();
        final ChannelPromise promise;
        if (flush || futureListener != null) {
          promise = channel.newPromise();
        } else {
          promise = channel.voidPromise();
        }

        EventLoop eventLoop = channel.eventLoop();
        boolean inEventLoop = eventLoop.inEventLoop();
        if (!inEventLoop) {
          if (futureListener != null) {
            channel.writeAndFlush(buf, promise).addListener(futureListener);
          } else {
            channel.writeAndFlush(buf, promise);
          }
        } else {
          // create a task which will be picked up by the eventloop and trigger the write.
          // This is mainly needed as this method is triggered by different threads for the same
          // channel.
          // if we not do this we may produce out of order writes.
          final Runnable task =
              new Runnable() {
                @Override
                public void run() {
                  if (futureListener != null) {
                    channel.writeAndFlush(buf, promise).addListener(futureListener);
                  } else {
                    channel.writeAndFlush(buf, promise);
                  }
                }
              };
          // execute the task on the eventloop
          eventLoop.execute(task);
        }

        // only try to wait if not in the eventloop otherwise we will produce a deadlock
        if (flush && !inEventLoop) {
          while (true) {
            try {
              boolean ok = promise.await(10000);

              if (!ok) {
                ActiveMQClientLogger.LOGGER.timeoutFlushingPacket();
              }

              break;
            } catch (InterruptedException e) {
              throw new ActiveMQInterruptedException(e);
            }
          }
        }
      } finally {
        writeLock.release();
      }
    } catch (InterruptedException e) {
      throw new ActiveMQInterruptedException(e);
    }
  }
  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;
  }