private void callOnMessage() throws Exception { if (closing || stopped) { return; } session.workDone(); // We pull the message from the buffer from inside the Runnable so we can ensure priority // ordering. If we just added a Runnable with the message to the executor immediately as we get // it // we could not do that ClientMessageInternal message; // Must store handler in local variable since might get set to null // otherwise while this is executing and give NPE when calling onMessage MessageHandler theHandler = handler; if (theHandler != null) { if (rateLimiter != null) { rateLimiter.limit(); } failedOver = false; synchronized (this) { message = buffer.poll(); } if (message != null) { if (message.containsProperty(ClientConsumerImpl.FORCED_DELIVERY_MESSAGE)) { // Ignore, this could be a relic from a previous receiveImmediate(); return; } boolean expired = message.isExpired(); flowControlBeforeConsumption(message); if (!expired) { if (isTrace) { ActiveMQClientLogger.LOGGER.trace("Calling handler.onMessage"); } final ClassLoader originalLoader = AccessController.doPrivileged( new PrivilegedAction<ClassLoader>() { public ClassLoader run() { ClassLoader originalLoader = Thread.currentThread().getContextClassLoader(); Thread.currentThread().setContextClassLoader(contextClassLoader); return originalLoader; } }); onMessageThread = Thread.currentThread(); try { theHandler.onMessage(message); } finally { try { AccessController.doPrivileged( new PrivilegedAction<Object>() { public Object run() { Thread.currentThread().setContextClassLoader(originalLoader); return null; } }); } catch (Exception e) { ActiveMQClientLogger.LOGGER.warn(e.getMessage(), e); } onMessageThread = null; } if (isTrace) { ActiveMQClientLogger.LOGGER.trace("Handler.onMessage done"); } if (message.isLargeMessage()) { message.discardBody(); } } else { session.expire(this, message); } // If slow consumer, we need to send 1 credit to make sure we get another message if (clientWindowSize == 0) { startSlowConsumer(); } } } }
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; } }