/** * 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.broker; import javax.jms.DeliveryMode; import javax.jms.MessageNotWriteableException; import java.io.ByteArrayOutputStream; import java.io.DataOutputStream; import java.io.File; import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Iterator; import java.util.concurrent.TimeUnit; import org.apache.activemq.CombinationTestSupport; import org.apache.activemq.broker.region.RegionBroker; import org.apache.activemq.broker.region.policy.FixedCountSubscriptionRecoveryPolicy; import org.apache.activemq.broker.region.policy.PolicyEntry; import org.apache.activemq.broker.region.policy.PolicyMap; import org.apache.activemq.broker.region.policy.RoundRobinDispatchPolicy; import org.apache.activemq.command.ActiveMQDestination; import org.apache.activemq.command.ActiveMQTextMessage; import org.apache.activemq.command.ConnectionId; import org.apache.activemq.command.ConnectionInfo; import org.apache.activemq.command.ConsumerInfo; import org.apache.activemq.command.DestinationInfo; import org.apache.activemq.command.LocalTransactionId; import org.apache.activemq.command.Message; import org.apache.activemq.command.MessageAck; import org.apache.activemq.command.MessageDispatch; import org.apache.activemq.command.MessageId; import org.apache.activemq.command.ProducerInfo; import org.apache.activemq.command.RemoveInfo; import org.apache.activemq.command.SessionInfo; import org.apache.activemq.command.TransactionId; import org.apache.activemq.command.TransactionInfo; import org.apache.activemq.command.XATransactionId; import org.apache.activemq.store.PersistenceAdapter; import org.apache.activemq.usage.SystemUsage; public class BrokerTestSupport extends CombinationTestSupport { /** * Setting this to false makes the test run faster but they may be less * accurate. */ public static final boolean FAST_NO_MESSAGE_LEFT_ASSERT = System.getProperty("FAST_NO_MESSAGE_LEFT_ASSERT", "true").equals("true"); protected RegionBroker regionBroker; public BrokerService broker; protected long idGenerator; protected int msgIdGenerator; protected int txGenerator; protected int tempDestGenerator; public PersistenceAdapter persistenceAdapter; protected String queueName = "TEST"; protected int maxWait = 10000; protected SystemUsage memoryManager; protected PolicyMap policyMap = new PolicyMap(); @Override protected void setUp() throws Exception { super.setUp(); broker = createBroker(); policyMap.setDefaultEntry(getDefaultPolicy()); broker.setDestinationPolicy(policyMap); broker.start(); } protected PolicyEntry getDefaultPolicy() { PolicyEntry policy = new PolicyEntry(); policy.setDispatchPolicy(new RoundRobinDispatchPolicy()); policy.setSubscriptionRecoveryPolicy(new FixedCountSubscriptionRecoveryPolicy()); return policy; } protected BrokerService createBroker() throws Exception { BrokerService broker = BrokerFactory.createBroker(new URI("broker:()/localhost?persistent=false")); return broker; } @Override protected void tearDown() throws Exception { broker.stop(); broker.waitUntilStopped(); broker = null; regionBroker = null; persistenceAdapter = null; memoryManager = null; super.tearDown(); } protected ConsumerInfo createConsumerInfo(SessionInfo sessionInfo, ActiveMQDestination destination) throws Exception { ConsumerInfo info = new ConsumerInfo(sessionInfo, ++idGenerator); info.setBrowser(false); info.setDestination(destination); info.setPrefetchSize(1000); info.setDispatchAsync(false); return info; } protected RemoveInfo closeConsumerInfo(ConsumerInfo consumerInfo) { return consumerInfo.createRemoveCommand(); } protected ProducerInfo createProducerInfo(SessionInfo sessionInfo) throws Exception { ProducerInfo info = new ProducerInfo(sessionInfo, ++idGenerator); return info; } protected SessionInfo createSessionInfo(ConnectionInfo connectionInfo) throws Exception { SessionInfo info = new SessionInfo(connectionInfo, ++idGenerator); return info; } protected ConnectionInfo createConnectionInfo() throws Exception { ConnectionInfo info = new ConnectionInfo(); info.setConnectionId(new ConnectionId("connection:" + (++idGenerator))); info.setClientId(info.getConnectionId().getValue()); return info; } protected Message createMessage(ProducerInfo producerInfo, ActiveMQDestination destination) { ActiveMQTextMessage message = new ActiveMQTextMessage(); message.setMessageId(new MessageId(producerInfo, ++msgIdGenerator)); message.setDestination(destination); message.setPersistent(false); try { message.setText("Test Message Payload."); } catch (MessageNotWriteableException e) { } return message; } protected MessageAck createAck(ConsumerInfo consumerInfo, Message msg, int count, byte ackType) { MessageAck ack = new MessageAck(); ack.setAckType(ackType); ack.setConsumerId(consumerInfo.getConsumerId()); ack.setDestination(msg.getDestination()); ack.setLastMessageId(msg.getMessageId()); ack.setMessageCount(count); return ack; } protected void gc() { regionBroker.gc(); } protected void profilerPause(String prompt) throws IOException { if (System.getProperty("profiler") != null) { System.out.println(); System.out.println(prompt + "> Press enter to continue: "); while (System.in.read() != '\n') { } System.out.println(prompt + "> Done."); } } protected RemoveInfo closeConnectionInfo(ConnectionInfo info) { return info.createRemoveCommand(); } protected RemoveInfo closeSessionInfo(SessionInfo info) { return info.createRemoveCommand(); } protected RemoveInfo closeProducerInfo(ProducerInfo info) { return info.createRemoveCommand(); } protected Message createMessage(ProducerInfo producerInfo, ActiveMQDestination destination, int deliveryMode) { Message message = createMessage(producerInfo, destination); message.setPersistent(deliveryMode == DeliveryMode.PERSISTENT); return message; } protected LocalTransactionId createLocalTransaction(SessionInfo info) { LocalTransactionId id = new LocalTransactionId(info.getSessionId().getParentId(), ++txGenerator); return id; } protected XATransactionId createXATransaction(SessionInfo info) throws IOException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); DataOutputStream os = new DataOutputStream(baos); os.writeLong(++txGenerator); os.close(); byte[] bs = baos.toByteArray(); XATransactionId xid = new XATransactionId(); xid.setBranchQualifier(bs); xid.setGlobalTransactionId(bs); xid.setFormatId(55); return xid; } protected TransactionInfo createBeginTransaction(ConnectionInfo connectionInfo, TransactionId txid) { TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.BEGIN); return info; } protected TransactionInfo createPrepareTransaction(ConnectionInfo connectionInfo, TransactionId txid) { TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.PREPARE); return info; } protected TransactionInfo createCommitTransaction1Phase(ConnectionInfo connectionInfo, TransactionId txid) { TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.COMMIT_ONE_PHASE); return info; } protected TransactionInfo createCommitTransaction2Phase(ConnectionInfo connectionInfo, TransactionId txid) { TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.COMMIT_TWO_PHASE); return info; } protected TransactionInfo createRollbackTransaction(ConnectionInfo connectionInfo, TransactionId txid) { TransactionInfo info = new TransactionInfo(connectionInfo.getConnectionId(), txid, TransactionInfo.ROLLBACK); return info; } protected int countMessagesInQueue(StubConnection connection, ConnectionInfo connectionInfo, ActiveMQDestination destination) throws Exception { SessionInfo sessionInfo = createSessionInfo(connectionInfo); connection.send(sessionInfo); ConsumerInfo consumerInfo = createConsumerInfo(sessionInfo, destination); consumerInfo.setPrefetchSize(1); consumerInfo.setBrowser(true); connection.send(consumerInfo); ArrayList<Object> skipped = new ArrayList<>(); // Now get the messages. Object m = connection.getDispatchQueue().poll(maxWait, TimeUnit.MILLISECONDS); int i = 0; while (m != null) { if (m instanceof MessageDispatch && ((MessageDispatch) m).getConsumerId().equals(consumerInfo.getConsumerId())) { MessageDispatch md = (MessageDispatch) m; if (md.getMessage() != null) { i++; connection.send(createAck(consumerInfo, md.getMessage(), 1, MessageAck.STANDARD_ACK_TYPE)); } else { break; } } else { skipped.add(m); } m = connection.getDispatchQueue().poll(maxWait, TimeUnit.MILLISECONDS); } for (Iterator<Object> iter = skipped.iterator(); iter.hasNext(); ) { connection.getDispatchQueue().put(iter.next()); } connection.send(closeSessionInfo(sessionInfo)); return i; } protected DestinationInfo createTempDestinationInfo(ConnectionInfo connectionInfo, byte destinationType) { DestinationInfo info = new DestinationInfo(); info.setConnectionId(connectionInfo.getConnectionId()); info.setOperationType(DestinationInfo.ADD_OPERATION_TYPE); info.setDestination(ActiveMQDestination.createDestination(info.getConnectionId() + ":" + (++tempDestGenerator), destinationType)); return info; } protected ActiveMQDestination createDestinationInfo(StubConnection connection, ConnectionInfo connectionInfo1, byte destinationType) throws Exception { if ((destinationType & ActiveMQDestination.TEMP_MASK) != 0) { DestinationInfo info = createTempDestinationInfo(connectionInfo1, destinationType); connection.send(info); return info.getDestination(); } else { return ActiveMQDestination.createDestination(queueName, destinationType); } } protected DestinationInfo closeDestinationInfo(DestinationInfo info) { info.setOperationType(DestinationInfo.REMOVE_OPERATION_TYPE); info.setTimeout(0); return info; } public static void recursiveDelete(File f) { if (f.isDirectory()) { File[] files = f.listFiles(); for (int i = 0; i < files.length; i++) { recursiveDelete(files[i]); } } f.delete(); } protected StubConnection createConnection() throws Exception { return new StubConnection(broker); } /** * @param connection * @return * @throws InterruptedException */ public Message receiveMessage(StubConnection connection) throws InterruptedException { return receiveMessage(connection, maxWait); } public Message receiveMessage(StubConnection connection, long timeout) throws InterruptedException { while (true) { Object o = connection.getDispatchQueue().poll(timeout, TimeUnit.MILLISECONDS); if (o == null) { return null; } if (o instanceof MessageDispatch) { MessageDispatch dispatch = (MessageDispatch) o; if (dispatch.getMessage() == null) { return null; } dispatch.setMessage(dispatch.getMessage().copy()); dispatch.getMessage().setRedeliveryCounter(dispatch.getRedeliveryCounter()); return dispatch.getMessage(); } } } protected void assertNoMessagesLeft(StubConnection connection) throws InterruptedException { long wait = FAST_NO_MESSAGE_LEFT_ASSERT ? 0 : maxWait; while (true) { Object o = connection.getDispatchQueue().poll(wait, TimeUnit.MILLISECONDS); if (o == null) { return; } if (o instanceof MessageDispatch && ((MessageDispatch) o).getMessage() != null) { fail("Received a message: " + ((MessageDispatch) o).getMessage().getMessageId()); } } } }