private void doCleanUp(final boolean sendCloseMessage) throws ActiveMQException { try { if (closed) { return; } // We need an extra flag closing, since we need to prevent any more messages getting queued to // execute // after this and we can't just set the closed flag to true here, since after/in onmessage the // message // might be acked and if the consumer is already closed, the ack will be ignored closing = true; // Now we wait for any current handler runners to run. waitForOnMessageToComplete(true); resetLargeMessageController(); closed = true; synchronized (this) { if (receiverThread != null) { // Wake up any receive() thread that might be waiting notify(); } handler = null; receiverThread = null; } flushAcks(); clearBuffer(); if (sendCloseMessage) { sessionContext.closeConsumer(this); } } catch (Throwable t) { // Consumer close should always return without exception } session.removeConsumer(this); }
private ClientMessage receive(final long timeout, final boolean forcingDelivery) throws ActiveMQException { checkClosed(); if (largeMessageReceived != null) { // Check if there are pending packets to be received largeMessageReceived.discardBody(); largeMessageReceived = null; } if (rateLimiter != null) { rateLimiter.limit(); } if (handler != null) { throw ActiveMQClientMessageBundle.BUNDLE.messageHandlerSet(); } if (clientWindowSize == 0) { startSlowConsumer(); } receiverThread = Thread.currentThread(); // To verify if deliveryForced was already call boolean deliveryForced = false; // To control when to call deliveryForce boolean callForceDelivery = false; long start = -1; long toWait = timeout == 0 ? Long.MAX_VALUE : timeout; try { while (true) { ClientMessageInternal m = null; synchronized (this) { while ((stopped || (m = buffer.poll()) == null) && !closed && toWait > 0) { if (start == -1) { start = System.currentTimeMillis(); } if (m == null && forcingDelivery) { if (stopped) { break; } // we only force delivery once per call to receive if (!deliveryForced) { callForceDelivery = true; break; } } try { wait(toWait); } catch (InterruptedException e) { throw new ActiveMQInterruptedException(e); } if (m != null || closed) { break; } long now = System.currentTimeMillis(); toWait -= now - start; start = now; } } if (failedOver) { if (m == null) { // if failed over and the buffer is null, we reset the state and try it again failedOver = false; deliveryForced = false; toWait = timeout == 0 ? Long.MAX_VALUE : timeout; continue; } else { failedOver = false; } } if (callForceDelivery) { if (isTrace) { ActiveMQClientLogger.LOGGER.trace("Forcing delivery"); } // JBPAPP-6030 - Calling forceDelivery outside of the lock to avoid distributed dead locks sessionContext.forceDelivery(this, forceDeliveryCount++); callForceDelivery = false; deliveryForced = true; continue; } if (m != null) { session.workDone(); if (m.containsProperty(ClientConsumerImpl.FORCED_DELIVERY_MESSAGE)) { long seq = m.getLongProperty(ClientConsumerImpl.FORCED_DELIVERY_MESSAGE); // Need to check if forceDelivery was called at this call // As we could be receiving a message that came from a previous call if (forcingDelivery && deliveryForced && seq == forceDeliveryCount - 1) { // forced delivery messages are discarded, nothing has been delivered by the queue resetIfSlowConsumer(); if (isTrace) { ActiveMQClientLogger.LOGGER.trace( "There was nothing on the queue, leaving it now:: returning null"); } return null; } else { if (isTrace) { ActiveMQClientLogger.LOGGER.trace( "Ignored force delivery answer as it belonged to another call"); } // Ignore the message continue; } } // if we have already pre acked we can't expire boolean expired = m.isExpired(); flowControlBeforeConsumption(m); if (expired) { m.discardBody(); session.expire(this, m); if (clientWindowSize == 0) { startSlowConsumer(); } if (toWait > 0) { continue; } else { return null; } } if (m.isLargeMessage()) { largeMessageReceived = m; } if (isTrace) { ActiveMQClientLogger.LOGGER.trace("Returning " + m); } return m; } else { if (isTrace) { ActiveMQClientLogger.LOGGER.trace("Returning null"); } resetIfSlowConsumer(); return null; } } } finally { receiverThread = null; } }