/* * 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.soak.client; import javax.transaction.xa.XAResource; import javax.transaction.xa.Xid; import org.apache.activemq.artemis.api.core.client.ClientSession; import org.apache.activemq.artemis.api.core.client.ClientSessionFactory; import org.apache.activemq.artemis.core.transaction.impl.XidImpl; import org.apache.activemq.artemis.tests.unit.UnitTestLogger; import org.apache.activemq.artemis.utils.UUIDGenerator; /** * WARNING: This is not a sample on how you should handle XA. You are supposed to use a * TransactionManager. This class is doing the job of a TransactionManager that fits for the purpose * of this test only, however there are many more pitfalls to deal with Transactions. * <p> * This is just to stress and soak test Transactions with ActiveMQ Artemis. * <p> * And this is dealing with XA directly for the purpose testing only. */ public abstract class ClientAbstract extends Thread { // Constants ----------------------------------------------------- private static final UnitTestLogger log = UnitTestLogger.LOGGER; // Attributes ---------------------------------------------------- protected ClientSession session; protected final ClientSessionFactory sf; protected Xid activeXid; protected volatile boolean running = true; protected int errors = 0; /** * A commit was called * case we don't find the Xid, means it was accepted */ protected volatile boolean pendingCommit = false; // Static -------------------------------------------------------- // Constructors -------------------------------------------------- public ClientAbstract(ClientSessionFactory sf) { this.sf = sf; } // Public -------------------------------------------------------- public ClientSession getConnection() { return session; } public int getErrorsCount() { return errors; } public final void connect() { while (running) { try { disconnect(); session = sf.createXASession(); if (activeXid != null) { synchronized (ClientAbstract.class) { Xid[] xids = session.recover(XAResource.TMSTARTRSCAN); boolean found = false; for (Xid recXid : xids) { if (recXid.equals(activeXid)) { // System.out.println("Calling commit after a prepare on " + this); found = true; callCommit(); } } if (!found) { if (pendingCommit) { onCommit(); } else { onRollback(); } activeXid = null; pendingCommit = false; } } } connectClients(); break; } catch (Exception e) { ClientAbstract.log.warn("Can't connect to server, retrying"); disconnect(); try { Thread.sleep(1000); } catch (InterruptedException ignored) { // if an interruption was sent, we will respect it and leave the loop break; } } } } @Override public void run() { connect(); } protected void callCommit() throws Exception { pendingCommit = true; session.commit(activeXid, false); pendingCommit = false; activeXid = null; onCommit(); } protected void callPrepare() throws Exception { session.prepare(activeXid); } public void beginTX() throws Exception { activeXid = newXID(); session.start(activeXid, XAResource.TMNOFLAGS); } public void endTX() throws Exception { session.end(activeXid, XAResource.TMSUCCESS); callPrepare(); callCommit(); } public void setRunning(final boolean running) { this.running = running; } /** * @return */ private XidImpl newXID() { return new XidImpl("tst".getBytes(), 1, UUIDGenerator.getInstance().generateStringUUID().getBytes()); } protected abstract void connectClients() throws Exception; protected abstract void onCommit(); protected abstract void onRollback(); public void disconnect() { try { if (session != null) { session.close(); } } catch (Exception ignored) { ignored.printStackTrace(); } session = null; } // Package protected --------------------------------------------- // Protected ----------------------------------------------------- // Private ------------------------------------------------------- // Inner classes ------------------------------------------------- }