/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.activemq.artemis.jms.client; import javax.jms.MessageListener; import javax.jms.Session; import org.apache.activemq.artemis.api.core.ActiveMQException; import org.apache.activemq.artemis.api.core.client.ClientConsumer; import org.apache.activemq.artemis.api.core.client.ClientMessage; import org.apache.activemq.artemis.api.core.client.MessageHandler; import org.apache.activemq.artemis.api.jms.ActiveMQJMSConstants; import org.apache.activemq.artemis.core.client.impl.ClientSessionInternal; public class JMSMessageListenerWrapper implements MessageHandler { private final ConnectionFactoryOptions options; private final ActiveMQConnection connection; private final ActiveMQSession session; private final MessageListener listener; private final ClientConsumer consumer; private final boolean transactedOrClientAck; private final boolean individualACK; protected JMSMessageListenerWrapper(final ConnectionFactoryOptions options, final ActiveMQConnection connection, final ActiveMQSession session, final ClientConsumer consumer, final MessageListener listener, final int ackMode) { this.options = options; this.connection = connection; this.session = session; this.consumer = consumer; this.listener = listener; transactedOrClientAck = (ackMode == Session.SESSION_TRANSACTED || ackMode == Session.CLIENT_ACKNOWLEDGE) || session.isXA(); individualACK = (ackMode == ActiveMQJMSConstants.INDIVIDUAL_ACKNOWLEDGE); } /** * In this method we apply the JMS acknowledgement and redelivery semantics * as per JMS spec */ @Override public void onMessage(final ClientMessage message) { ActiveMQMessage msg = ActiveMQMessage.createMessage(message, session.getCoreSession(), options); if (individualACK) { msg.setIndividualAcknowledge(); } try { msg.doBeforeReceive(); } catch (Exception e) { ActiveMQJMSClientLogger.LOGGER.errorPreparingMessageForReceipt(msg.getCoreMessage().toString(), e); return; } if (transactedOrClientAck) { try { message.acknowledge(); } catch (ActiveMQException e) { ((ClientSessionInternal) session.getCoreSession()).markRollbackOnly(); ActiveMQJMSClientLogger.LOGGER.errorProcessingMessage(e); } } try { connection.getThreadAwareContext().setCurrentThread(false); listener.onMessage(msg); } catch (RuntimeException e) { // See JMS 1.1 spec, section 4.5.2 ActiveMQJMSClientLogger.LOGGER.onMessageError(e); if (!transactedOrClientAck) { try { if (individualACK) { message.individualAcknowledge(); } session.getCoreSession().rollback(true); session.setRecoverCalled(true); } catch (Exception e2) { ActiveMQJMSClientLogger.LOGGER.errorRecoveringSession(e2); } } } finally { connection.getThreadAwareContext().clearCurrentThread(false); } if (!session.isRecoverCalled() && !individualACK) { try { // We don't want to call this if the consumer was closed from inside onMessage if (!consumer.isClosed() && !transactedOrClientAck) { message.acknowledge(); } } catch (ActiveMQException e) { ((ClientSessionInternal) session.getCoreSession()).markRollbackOnly(); ActiveMQJMSClientLogger.LOGGER.errorProcessingMessage(e); } } session.setRecoverCalled(false); } }