public void finish() throws Exception {
      synchronized (lock) {
        if (largeMessage == null) {
          // handleClose could be calling close while handle is also calling finish.
          // As a result one of them could get here after the largeMessage is already gone.
          // On that case we just ignore this call
          return;
        }
        if (context != null) {
          context.close();
        }

        largeMessage.releaseResources();

        largeMessage.decrementDelayDeletionCount();

        if (preAcknowledge && !browseOnly) {
          // PreAck will have an extra reference
          largeMessage.decrementDelayDeletionCount();
        }

        largeMessageDeliverer = null;

        largeMessage = null;
      }
    }
    public boolean deliver() throws Exception {
      lockDelivery.readLock().lock();
      try {
        if (largeMessage == null) {
          return true;
        }

        if (availableCredits != null && availableCredits.get() <= 0) {
          if (HornetQServerLogger.LOGGER.isTraceEnabled()) {
            HornetQServerLogger.LOGGER.trace(
                this
                    + "::FlowControl::delivery largeMessage interrupting as there are no more credits, available="
                    + availableCredits);
          }

          return false;
        }

        if (!sentInitialPacket) {
          context = largeMessage.getBodyEncoder();

          sizePendingLargeMessage = context.getLargeBodySize();

          context.open();

          sentInitialPacket = true;

          int packetSize =
              callback.sendLargeMessage(
                  largeMessage, id, context.getLargeBodySize(), ref.getDeliveryCount());

          if (availableCredits != null) {
            availableCredits.addAndGet(-packetSize);

            if (HornetQServerLogger.LOGGER.isTraceEnabled()) {
              HornetQServerLogger.LOGGER.trace(
                  this
                      + "::FlowControl::"
                      + " deliver initialpackage with "
                      + packetSize
                      + " delivered, available now = "
                      + availableCredits);
            }
          }

          // Execute the rest of the large message on a different thread so as not to tie up the
          // delivery thread
          // for too long

          resumeLargeMessage();

          return false;
        } else {
          if (availableCredits != null && availableCredits.get() <= 0) {
            if (ServerConsumerImpl.isTrace) {
              HornetQServerLogger.LOGGER.trace(
                  this
                      + "::FlowControl::deliverLargeMessage Leaving loop of send LargeMessage because of credits, available="
                      + availableCredits);
            }

            return false;
          }

          int localChunkLen = 0;

          localChunkLen =
              (int)
                  Math.min(
                      sizePendingLargeMessage - positionPendingLargeMessage, minLargeMessageSize);

          HornetQBuffer bodyBuffer = HornetQBuffers.fixedBuffer(localChunkLen);

          context.encode(bodyBuffer, localChunkLen);

          byte[] body = bodyBuffer.toByteBuffer().array();

          int packetSize =
              callback.sendLargeMessageContinuation(
                  id,
                  body,
                  positionPendingLargeMessage + localChunkLen < sizePendingLargeMessage,
                  false);

          int chunkLen = body.length;

          if (availableCredits != null) {
            availableCredits.addAndGet(-packetSize);

            if (HornetQServerLogger.LOGGER.isTraceEnabled()) {
              HornetQServerLogger.LOGGER.trace(
                  this
                      + "::FlowControl::largeMessage deliver continuation, packetSize="
                      + packetSize
                      + " available now="
                      + availableCredits);
            }
          }

          positionPendingLargeMessage += chunkLen;

          if (positionPendingLargeMessage < sizePendingLargeMessage) {
            resumeLargeMessage();

            return false;
          }
        }

        if (ServerConsumerImpl.isTrace) {
          HornetQServerLogger.LOGGER.trace("Finished deliverLargeMessage");
        }

        finish();

        return true;
      } finally {
        lockDelivery.readLock().unlock();
      }
    }
Example #3
0
  public int sendMessage(ServerMessage serverMessage, long consumerID, int deliveryCount) {
    LargeServerMessageImpl largeMessage = null;
    ServerMessage newServerMessage = serverMessage;
    try {
      StompSubscription subscription = subscriptions.get(consumerID);
      StompFrame frame = null;
      if (serverMessage.isLargeMessage()) {
        newServerMessage = serverMessage.copy();

        largeMessage = (LargeServerMessageImpl) serverMessage;
        BodyEncoder encoder = largeMessage.getBodyEncoder();
        encoder.open();
        int bodySize = (int) encoder.getLargeBodySize();

        // large message doesn't have a body.
        ((ServerMessageImpl) newServerMessage).createBody(bodySize);
        encoder.encode(newServerMessage.getBodyBuffer(), bodySize);
        encoder.close();
      }

      if (serverMessage.getBooleanProperty(Message.HDR_LARGE_COMPRESSED)) {
        // decompress
        HornetQBuffer qbuff = newServerMessage.getBodyBuffer();
        int bytesToRead = qbuff.writerIndex() - MessageImpl.BODY_OFFSET;
        Inflater inflater = new Inflater();
        inflater.setInput(qbuff.readBytes(bytesToRead).toByteBuffer().array());

        // get the real size of large message
        long sizeBody = newServerMessage.getLongProperty(Message.HDR_LARGE_BODY_SIZE);

        byte[] data = new byte[(int) sizeBody];
        inflater.inflate(data);
        inflater.end();
        qbuff.resetReaderIndex();
        qbuff.resetWriterIndex();
        qbuff.writeBytes(data);
      }

      frame = connection.createStompMessage(newServerMessage, subscription, deliveryCount);

      int length = frame.getEncodedSize();

      if (subscription.getAck().equals(Stomp.Headers.Subscribe.AckModeValues.AUTO)) {
        if (manager.send(connection, frame)) {
          // we ack and commit only if the send is successful
          session.acknowledge(consumerID, newServerMessage.getMessageID());
          session.commit();
        }
      } else {
        messagesToAck.put(
            newServerMessage.getMessageID(), new Pair<Long, Integer>(consumerID, length));
        // Must send AFTER adding to messagesToAck - or could get acked from client BEFORE it's been
        // added!
        manager.send(connection, frame);
      }

      return length;
    } catch (Exception e) {
      return 0;
    } finally {
      if (largeMessage != null) {
        largeMessage.releaseResources();
        largeMessage = null;
      }
    }
  }