org.apache.qpid.disttest.jms.ClientJmsDelegate.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.qpid.disttest.jms.ClientJmsDelegate.java

Source

/*
 * 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.qpid.disttest.jms;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.DeliveryMode;
import javax.jms.Destination;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.MessageConsumer;
import javax.jms.MessageListener;
import javax.jms.MessageProducer;
import javax.jms.Queue;
import javax.jms.Session;
import javax.jms.TextMessage;
import javax.jms.Topic;
import javax.naming.Context;
import javax.naming.NamingException;

import org.apache.commons.lang.builder.ToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.apache.qpid.disttest.DistributedTestConstants;
import org.apache.qpid.disttest.DistributedTestException;
import org.apache.qpid.disttest.client.Client;
import org.apache.qpid.disttest.client.MessageProvider;
import org.apache.qpid.disttest.message.Command;
import org.apache.qpid.disttest.message.CreateConnectionCommand;
import org.apache.qpid.disttest.message.CreateConsumerCommand;
import org.apache.qpid.disttest.message.CreateMessageProviderCommand;
import org.apache.qpid.disttest.message.CreateProducerCommand;
import org.apache.qpid.disttest.message.CreateSessionCommand;
import org.apache.qpid.disttest.message.RegisterClientCommand;
import org.apache.qpid.disttest.message.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class ClientJmsDelegate {
    private static final Logger LOGGER = LoggerFactory.getLogger(ClientJmsDelegate.class);

    private final Context _context;
    private final Destination _controllerQueue;
    private final Connection _controllerConnection;
    private final Session _controllerSession;
    private final MessageProducer _controlQueueProducer;

    private final String _clientName;
    private Queue _instructionQueue;

    private Map<String, Connection> _testConnections;
    private Map<String, Session> _testSessions;
    private Map<String, MessageProducer> _testProducers;
    private Map<String, MessageConsumer> _testConsumers;
    private Map<String, Session> _testSubscriptions;
    private Map<String, MessageProvider> _testMessageProviders;

    private final MessageProvider _defaultMessageProvider;

    public ClientJmsDelegate(final Context context) {
        try {
            _context = context;
            final ConnectionFactory connectionFactory = (ConnectionFactory) _context.lookup("connectionfactory");
            _controllerConnection = connectionFactory.createConnection();
            _controllerConnection.start();
            _controllerQueue = (Destination) context.lookup(DistributedTestConstants.CONTROLLER_QUEUE_JNDI_NAME);
            _controllerSession = _controllerConnection.createSession(false, Session.AUTO_ACKNOWLEDGE);
            _controlQueueProducer = _controllerSession.createProducer(_controllerQueue);
            _clientName = UUID.randomUUID().toString();
            _testConnections = new HashMap<String, Connection>();
            _testSessions = new HashMap<String, Session>();
            _testProducers = new HashMap<String, MessageProducer>();
            _testConsumers = new HashMap<String, MessageConsumer>();
            _testSubscriptions = new HashMap<String, Session>();
            _testMessageProviders = new HashMap<String, MessageProvider>();
            _defaultMessageProvider = new MessageProvider(null);
        } catch (final NamingException ne) {
            throw new DistributedTestException("Unable to create client jms delegate", ne);
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to create client jms delegate", jmse);
        }
    }

    public void setInstructionListener(final Client client) {
        try {
            _instructionQueue = _controllerSession.createTemporaryQueue();
            final MessageConsumer instructionConsumer = _controllerSession.createConsumer(_instructionQueue);
            instructionConsumer.setMessageListener(new MessageListener() {
                @Override
                public void onMessage(final Message message) {
                    client.processInstruction(JmsMessageAdaptor.messageToCommand(message));
                }
            });
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to setup instruction listener", jmse);
        }
    }

    public void sendRegistrationMessage() {
        Command command;
        try {
            command = new RegisterClientCommand(_clientName, _instructionQueue.getQueueName());
        } catch (final JMSException e) {
            throw new DistributedTestException(e);
        }
        sendCommand(command);
    }

    public void sendResponseMessage(final Response responseMessage) {
        sendCommand(responseMessage);
    }

    private void sendCommand(final Command command) {
        try {
            final Message message = JmsMessageAdaptor.commandToMessage(_controllerSession, command);
            _controlQueueProducer.send(message);
            LOGGER.debug("Sent message for " + command.getType() + ". message id: " + message.getJMSMessageID());
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to send command: " + command, jmse);
        }
    }

    public void createConnection(final CreateConnectionCommand command) {
        try {
            final ConnectionFactory connectionFactory = (ConnectionFactory) _context
                    .lookup(command.getConnectionFactoryName());
            final Connection newConnection = connectionFactory.createConnection();
            addConnection(command.getConnectionName(), newConnection);
        } catch (final NamingException ne) {
            throw new DistributedTestException(
                    "Unable to lookup factoryName: " + command.getConnectionFactoryName(), ne);
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to create connection: " + command.getConnectionName()
                    + " (using factory name: " + command.getConnectionFactoryName() + ")", jmse);
        }
    }

    public void createSession(final CreateSessionCommand command) {
        try {
            final Connection connection = _testConnections.get(command.getConnectionName());
            if (connection == null) {
                throw new DistributedTestException(
                        "No test connection found called: " + command.getConnectionName(), command);
            }
            final boolean transacted = command.getAcknowledgeMode() == Session.SESSION_TRANSACTED;

            final Session newSession = connection.createSession(transacted, command.getAcknowledgeMode());
            LOGGER.debug("Created session " + command.getSessionName() + " with transacted = "
                    + newSession.getTransacted() + " and acknowledgeMode = " + newSession.getAcknowledgeMode());

            addSession(command.getSessionName(), newSession);
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to create new session: " + command, jmse);
        }
    }

    public void createProducer(final CreateProducerCommand command) {
        try {
            final Session session = _testSessions.get(command.getSessionName());
            if (session == null) {
                throw new DistributedTestException("No test session found called: " + command.getSessionName(),
                        command);
            }

            synchronized (session) {
                final Destination destination;
                if (command.isTopic()) {
                    destination = session.createTopic(command.getDestinationName());
                } else {
                    destination = session.createQueue(command.getDestinationName());
                }

                final MessageProducer jmsProducer = session.createProducer(destination);

                if (command.getPriority() != -1) {
                    jmsProducer.setPriority(command.getPriority());
                }
                if (command.getTimeToLive() > 0) {
                    jmsProducer.setTimeToLive(command.getTimeToLive());
                }

                if (command.getDeliveryMode() == DeliveryMode.NON_PERSISTENT
                        || command.getDeliveryMode() == DeliveryMode.PERSISTENT) {
                    jmsProducer.setDeliveryMode(command.getDeliveryMode());
                }

                addProducer(command.getParticipantName(), jmsProducer);
            }
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to create new producer: " + command, jmse);
        }
    }

    public void createConsumer(final CreateConsumerCommand command) {
        try {
            final Session session = _testSessions.get(command.getSessionName());
            if (session == null) {
                throw new DistributedTestException("No test session found called: " + command.getSessionName(),
                        command);
            }

            synchronized (session) {
                Destination destination;
                MessageConsumer jmsConsumer;
                if (command.isTopic()) {
                    Topic topic = session.createTopic(command.getDestinationName());
                    if (command.isDurableSubscription()) {
                        String subscription = "subscription-" + command.getParticipantName()
                                + System.currentTimeMillis();
                        jmsConsumer = session.createDurableSubscriber(topic, subscription);

                        _testSubscriptions.put(subscription, session);
                        LOGGER.debug("created durable suscription " + subscription + " to topic " + topic);
                    } else {
                        jmsConsumer = session.createConsumer(topic, command.getSelector());
                    }

                    destination = topic;
                } else {
                    destination = session.createQueue(command.getDestinationName());
                    jmsConsumer = session.createConsumer(destination, command.getSelector());
                }

                _testConsumers.put(command.getParticipantName(), jmsConsumer);
            }
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to create new consumer: " + command, jmse);
        }
    }

    /**
     * destroy the client. Don't call from the Dispatcher thread.
     */
    public void destroy() {
        try {
            // Stopping the connection allows in-flight onMessage calls to
            // finish.
            _controllerConnection.stop();

            if (_controllerSession != null) {
                _controllerSession.close();
            }
            if (_controllerConnection != null) {
                _controllerConnection.close();
            }

        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to destroy cleanly", jmse);
        }
    }

    public Destination getControllerQueue() {
        return _controllerQueue;
    }

    public String getClientName() {
        return _clientName;
    }

    public int getNoOfTestConnections() {
        return _testConnections.size();
    }

    public int getNoOfTestSessions() {
        return _testSessions.size();
    }

    public int getNoOfTestProducers() {
        return _testProducers.size();
    }

    public int getNoOfTestConsumers() {
        return _testConsumers.size();
    }

    public void startConnections() {
        // start connections for consumers
        // it would be better if we could track consumer connections and start
        // only those
        if (!_testConsumers.isEmpty()) {
            for (final Map.Entry<String, Connection> entry : _testConnections.entrySet()) {
                final Connection connection = entry.getValue();
                try {
                    connection.start();
                } catch (final JMSException e) {
                    throw new DistributedTestException(
                            "Failed to start connection '" + entry.getKey() + "' :" + e.getLocalizedMessage());
                }
            }
        }
    }

    public int getAcknowledgeMode(final String sessionName) {
        try {
            final Session session = _testSessions.get(sessionName);
            return session.getAcknowledgeMode();
        } catch (final JMSException jmse) {
            throw new DistributedTestException(
                    "Unable to determine acknowledgement mode for session: " + sessionName, jmse);
        }
    }

    public Message sendNextMessage(final CreateProducerCommand command) {
        Message sentMessage = null;
        MessageProvider messageProvider = _testMessageProviders.get(command.getMessageProviderName());
        if (messageProvider == null) {
            messageProvider = _defaultMessageProvider;
        }

        final Session session = _testSessions.get(command.getSessionName());
        final MessageProducer producer = _testProducers.get(command.getParticipantName());
        try {
            sentMessage = messageProvider.nextMessage(session, command);
            int deliveryMode = producer.getDeliveryMode();
            int priority = producer.getPriority();
            long ttl = producer.getTimeToLive();
            if (messageProvider.isPropertySet(MessageProvider.PRIORITY)) {
                priority = sentMessage.getJMSPriority();
            }
            if (messageProvider.isPropertySet(MessageProvider.DELIVERY_MODE)) {
                deliveryMode = sentMessage.getJMSDeliveryMode();
            }
            if (messageProvider.isPropertySet(MessageProvider.TTL)) {
                ttl = sentMessage.getLongProperty(MessageProvider.TTL);
            }
            producer.send(sentMessage, deliveryMode, priority, ttl);
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to create and send message with producer: "
                    + command.getParticipantName() + " on session: " + command.getSessionName(), jmse);
        }
        return sentMessage;
    }

    protected void addSession(final String sessionName, final Session newSession) {
        _testSessions.put(sessionName, newSession);
    }

    protected void addConnection(final String connectionName, final Connection newConnection) {
        _testConnections.put(connectionName, newConnection);
    }

    protected void addProducer(final String producerName, final MessageProducer jmsProducer) {
        _testProducers.put(producerName, jmsProducer);
    }

    public Message consumeMessage(String consumerName, long receiveInterval) {
        Message consumedMessage = null;
        MessageConsumer consumer = _testConsumers.get(consumerName);
        try {
            consumedMessage = consumer.receive(receiveInterval);
        } catch (JMSException e) {
            throw new DistributedTestException("Unable to consume message with consumer: " + consumerName, e);
        }
        return consumedMessage;
    }

    public void registerListener(String consumerName, MessageListener messageListener) {
        MessageConsumer consumer = _testConsumers.get(consumerName);
        try {
            consumer.setMessageListener(messageListener);
        } catch (JMSException e) {
            throw new DistributedTestException("Unable to register message listener with consumer: " + consumerName,
                    e);
        }
    }

    public void commitOrAcknowledgeMessageIfNecessary(final String sessionName, final Message message) {
        try {
            final Session session = _testSessions.get(sessionName);
            if (session.getTransacted()) {
                synchronized (session) {
                    session.commit();
                }
            } else if (message != null && session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) {
                message.acknowledge();
            }
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to commit or acknowledge message on session: " + sessionName,
                    jmse);
        }
    }

    public void commitIfNecessary(final String sessionName) {
        commitOrAcknowledgeMessageIfNecessary(sessionName, null);
    }

    public void rollbackOrRecoverIfNecessary(String sessionName) {
        try {
            final Session session = _testSessions.get(sessionName);
            synchronized (session) {
                if (session.getTransacted()) {
                    session.rollback();
                } else if (session.getAcknowledgeMode() == Session.CLIENT_ACKNOWLEDGE) {
                    session.recover();
                }
            }
        } catch (final JMSException jmse) {
            throw new DistributedTestException("Unable to rollback or recover on session: " + sessionName, jmse);
        }
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE).append("clientName", _clientName)
                .toString();
    }

    public void tearDownTest() {
        StringBuilder jmsErrorMessages = new StringBuilder();
        int failureCounter = 0;

        for (String subscription : _testSubscriptions.keySet()) {
            Session session = _testSubscriptions.get(subscription);
            try {
                session.unsubscribe(subscription);
            } catch (JMSException e) {
                LOGGER.error("Failed to unsubscribe '" + subscription + "' :" + e.getLocalizedMessage(), e);
                failureCounter++;
                appendErrorMessage(jmsErrorMessages, e);
            }
        }

        for (Map.Entry<String, Connection> entry : _testConnections.entrySet()) {
            Connection connection = entry.getValue();
            try {
                connection.close();
            } catch (JMSException e) {
                LOGGER.error("Failed to close connection '" + entry.getKey() + "' :" + e.getLocalizedMessage(), e);
                failureCounter++;
                appendErrorMessage(jmsErrorMessages, e);
            }
        }

        _testConnections.clear();
        _testSubscriptions.clear();
        _testSessions.clear();
        _testProducers.clear();
        _testConsumers.clear();

        if (failureCounter > 0) {
            throw new DistributedTestException("Tear down test encountered " + failureCounter
                    + " failures with the following errors: " + jmsErrorMessages.toString());
        }
    }

    private void appendErrorMessage(StringBuilder errorMessages, JMSException e) {
        if (errorMessages.length() > 0) {
            errorMessages.append('\n');
        }
        errorMessages.append(e.getMessage());
    }

    public void closeTestConsumer(String consumerName) {
        MessageConsumer consumer = _testConsumers.get(consumerName);
        if (consumer != null) {
            try {
                consumer.close();
                LOGGER.debug("Closed test consumer " + consumerName);
            } catch (JMSException e) {
                throw new DistributedTestException("Failed to close consumer: " + consumerName, e);
            }
        }
    }

    public void closeTestProducer(String producerName) {
        MessageProducer producer = _testProducers.get(producerName);
        if (producer != null) {
            try {
                producer.close();
            } catch (JMSException e) {
                throw new DistributedTestException("Failed to close producer: " + producerName, e);
            }
        }
    }

    /** only supports text messages - returns 0 for other message types */
    public int calculatePayloadSizeFrom(Message message) {
        try {
            if (message != null && message instanceof TextMessage) {
                return ((TextMessage) message).getText().getBytes().length;
            }

            return 0;
        } catch (JMSException e) {
            throw new DistributedTestException("Unable to determine the payload size for message " + message, e);
        }
    }

    public void createMessageProvider(CreateMessageProviderCommand command) {
        _testMessageProviders.put(command.getProviderName(), new MessageProvider(command.getMessageProperties()));
    }
}