From 65ccfb2838cb443beed3bee1e6fbdca3c4ed10a7 Mon Sep 17 00:00:00 2001 From: JiriOndrusek Date: Thu, 8 Feb 2018 12:47:10 +0100 Subject: [PATCH] ARTEMIS-1669 JMS message is not received when using a non-transactional JMSConnectionFactoryDefinition --- .../jms/client/ActiveMQConnectionFactory.java | 11 ++ .../ActiveMQRAManagedConnectionFactory.java | 4 + .../ra/ActiveMQRASessionFactoryImpl.java | 9 +- .../artemis/ra/ActiveMQResourceAdapter.java | 14 ++ .../tests/integration/ra/IgnoreJTATest.java | 126 ++++++++++++++++++ 5 files changed, 159 insertions(+), 5 deletions(-) create mode 100644 tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/IgnoreJTATest.java diff --git a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQConnectionFactory.java b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQConnectionFactory.java index aad68a90ab..2ab3bf7e57 100644 --- a/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQConnectionFactory.java +++ b/artemis-jms-client/src/main/java/org/apache/activemq/artemis/jms/client/ActiveMQConnectionFactory.java @@ -90,6 +90,8 @@ public class ActiveMQConnectionFactory extends JNDIStorable implements Connectio private boolean finalizeChecks; + private boolean ignoreJTA; + @Override public void writeExternal(ObjectOutput out) throws IOException { URI uri = toURI(); @@ -712,6 +714,15 @@ public class ActiveMQConnectionFactory extends JNDIStorable implements Connectio serverLocator.setInitialMessagePacketSize(size); } + public boolean isIgnoreJTA() { + return ignoreJTA; + } + + public void setIgnoreJTA(boolean ignoreJTA) { + checkWrite(); + this.ignoreJTA = ignoreJTA; + } + /** * @param interceptorList a comma separated string of incoming interceptor class names to be used. Each interceptor needs a default Constructor to be used with this method. */ diff --git a/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRAManagedConnectionFactory.java b/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRAManagedConnectionFactory.java index 96ce33a401..ef5698b1c2 100644 --- a/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRAManagedConnectionFactory.java +++ b/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRAManagedConnectionFactory.java @@ -268,6 +268,10 @@ public final class ActiveMQRAManagedConnectionFactory implements ManagedConnecti return ra; } + public boolean isIgnoreJTA() { + return ra.isIgnoreJTA(); + } + /** * Set the resource adapter *
diff --git a/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRASessionFactoryImpl.java b/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRASessionFactoryImpl.java index 12d6ae28ea..0716baca07 100644 --- a/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRASessionFactoryImpl.java +++ b/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQRASessionFactoryImpl.java @@ -819,13 +819,12 @@ public final class ActiveMQRASessionFactoryImpl extends ActiveMQConnectionForCon //from createSession // In a Java EE web or EJB container, when there is an active JTA transaction in progress: //Both arguments {@code transacted} and {@code acknowledgeMode} are ignored. - if (inJtaTransaction()) { + // fix of ARTEMIS-1669 - when a JMSConnectionFactoryDefinition annotation with the transactional attribute set to false="false" is set + // then it should not be included in any JTA transaction and behave like that there is no JTA transaction. + if (!mcf.isIgnoreJTA() && inJtaTransaction()) { transacted = true; //from getAcknowledgeMode - // If the session is not transacted, returns the - // current acknowledgement mode for the session. - // If the session - // is transacted, returns SESSION_TRANSACTED. + // If the session is transacted, returns SESSION_TRANSACTED. acknowledgeMode = Session.SESSION_TRANSACTED; } else { //In the Java EE web or EJB container, when there is no active JTA transaction in progress diff --git a/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQResourceAdapter.java b/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQResourceAdapter.java index 684792eb01..b40ef59e3e 100644 --- a/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQResourceAdapter.java +++ b/artemis-ra/src/main/java/org/apache/activemq/artemis/ra/ActiveMQResourceAdapter.java @@ -122,6 +122,10 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable { private String entries; + //fix of ARTEMIS-1669 - propagated value of transactional attribute JMSConnectionFactoryDefinition annotation with the + //default value is falso -> original behavior + private boolean ignoreJTA; + /** * Keep track of the connection factories that we create so we don't create a bunch of instances of factories * configured the exact same way. Using the same connection factory instance also makes connection load-balancing @@ -2030,6 +2034,8 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable { if (val5 != null) { cf.setDeserializationWhiteList(val5); } + + cf.setIgnoreJTA(isIgnoreJTA()); } public void setManagedConnectionFactory(ActiveMQRAManagedConnectionFactory activeMQRAManagedConnectionFactory) { @@ -2047,4 +2053,12 @@ public class ActiveMQResourceAdapter implements ResourceAdapter, Serializable { knownConnectionFactories.remove(properties).getA().close(); } } + + public boolean isIgnoreJTA() { + return ignoreJTA; + } + + public void setIgnoreJTA(boolean ignoreJTA) { + this.ignoreJTA = ignoreJTA; + } } diff --git a/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/IgnoreJTATest.java b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/IgnoreJTATest.java new file mode 100644 index 0000000000..c4a6b62d6e --- /dev/null +++ b/tests/integration-tests/src/test/java/org/apache/activemq/artemis/tests/integration/ra/IgnoreJTATest.java @@ -0,0 +1,126 @@ +/* + * 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.tests.integration.ra; + +import org.apache.activemq.artemis.api.jms.ActiveMQJMSClient; +import org.apache.activemq.artemis.core.remoting.impl.invm.InVMConnectorFactory; +import org.apache.activemq.artemis.ra.ActiveMQRAConnectionFactory; +import org.apache.activemq.artemis.ra.ActiveMQRAConnectionFactoryImpl; +import org.apache.activemq.artemis.ra.ActiveMQRAConnectionManager; +import org.apache.activemq.artemis.ra.ActiveMQRAManagedConnectionFactory; +import org.apache.activemq.artemis.ra.ActiveMQResourceAdapter; +import org.apache.activemq.artemis.service.extensions.ServiceUtils; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import javax.jms.IllegalStateException; +import javax.jms.Message; +import javax.jms.MessageConsumer; +import javax.jms.MessageProducer; +import javax.jms.Queue; +import javax.jms.QueueConnection; +import javax.jms.Session; +import javax.jms.TextMessage; + +public class IgnoreJTATest extends ActiveMQRATestBase { + + protected ActiveMQResourceAdapter resourceAdapter; + protected ActiveMQRAConnectionFactory qraConnectionFactory; + protected ActiveMQRAManagedConnectionFactory mcf; + ActiveMQRAConnectionManager qraConnectionManager = new ActiveMQRAConnectionManager(); + + @Override + @Before + public void setUp() throws Exception { + useDummyTransactionManager(); + super.setUp(); + + resourceAdapter = new ActiveMQResourceAdapter(); + resourceAdapter.setEntries("[\"java://jmsXA\"]"); + + resourceAdapter.setConnectorClassName(InVMConnectorFactory.class.getName()); + MyBootstrapContext ctx = new MyBootstrapContext(); + resourceAdapter.start(ctx); + mcf = new ActiveMQRAManagedConnectionFactory(); + mcf.setResourceAdapter(resourceAdapter); + qraConnectionFactory = new ActiveMQRAConnectionFactoryImpl(mcf, qraConnectionManager); + } + + @Override + @After + public void tearDown() throws Exception { + ((DummyTransactionManager) ServiceUtils.getTransactionManager()).tx = null; + if (resourceAdapter != null) { + resourceAdapter.stop(); + } + + qraConnectionManager.stop(); + super.tearDown(); + } + + @Test(expected = IllegalStateException.class) + public void testIgnoreJTA() throws Exception { + testSendAndReceive(true); + } + + @Test + public void testDontIgnoreJTA() throws Exception { + testSendAndReceive(false); + } + + @Test + public void testDefaultIgnoreJTA() throws Exception { + testSendAndReceive(null); + } + + private void testSendAndReceive(Boolean ignoreJTA) throws Exception { + setDummyTX(); + setupDLQ(10); + resourceAdapter = newResourceAdapter(); + if (ignoreJTA != null) { + resourceAdapter.setIgnoreJTA(ignoreJTA); + } + MyBootstrapContext ctx = new MyBootstrapContext(); + resourceAdapter.start(ctx); + ActiveMQRAManagedConnectionFactory mcf = new ActiveMQRAManagedConnectionFactory(); + mcf.setResourceAdapter(resourceAdapter); + ActiveMQRAConnectionFactory qraConnectionFactory = new ActiveMQRAConnectionFactoryImpl(mcf, qraConnectionManager); + QueueConnection queueConnection = qraConnectionFactory.createQueueConnection(); + Session s = queueConnection.createSession(true, Session.AUTO_ACKNOWLEDGE); + Queue q = ActiveMQJMSClient.createQueue(MDBQUEUE); + MessageProducer mp = s.createProducer(q); + MessageConsumer consumer = s.createConsumer(q); + Message message = s.createTextMessage("test"); + mp.send(message); + s.commit(); + queueConnection.start(); + TextMessage textMessage = (TextMessage) consumer.receive(1000); + assertNotNull(textMessage); + assertEquals(textMessage.getText(), "test"); + s.rollback(); + textMessage = (TextMessage) consumer.receive(1000); + assertNotNull(textMessage); + assertEquals(textMessage.getText(), "test"); + s.commit(); + } + + private void setDummyTX() { + ((DummyTransactionManager) ServiceUtils.getTransactionManager()).tx = new DummyTransaction(); + } +}