com.cisco.oss.foundation.message.HornetQMessageProducer.java Source code

Java tutorial

Introduction

Here is the source code for com.cisco.oss.foundation.message.HornetQMessageProducer.java

Source

/*
 * Copyright 2015 Cisco Systems, Inc.
 *
 *  Licensed 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 com.cisco.oss.foundation.message;

import com.cisco.oss.foundation.configuration.ConfigurationFactory;
import com.cisco.oss.foundation.flowcontext.FlowContextFactory;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.hornetq.api.core.HornetQException;
import org.hornetq.api.core.HornetQObjectClosedException;
import org.hornetq.api.core.client.ClientMessage;
import org.hornetq.api.core.client.ClientProducer;
import org.hornetq.api.core.client.ClientSession;
import org.hornetq.api.core.client.SessionFailureListener;
import org.hornetq.core.message.impl.MessageImpl;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * A HornetQ producer wrapper. NOTE: This class is thread safe although wraps HornetQ ClientProducer
 * which is not thread safe. The internal implementation is to provide a single threaded producer instance by using ThreadLocal
 * so this class can be used in a multi-threaded environment.
 * Created by Yair Ogen on 24/04/2014.
 */
class HornetQMessageProducer extends AbstractMessageProducer {

    private static final Logger LOGGER = LoggerFactory.getLogger(HornetQMessageProducer.class);
    private static final ThreadLocal<List<ClientProducer>> producer = new ThreadLocal<List<ClientProducer>>();
    private static final Set<ClientProducer> producersSet = new HashSet<ClientProducer>();
    private Configuration configuration = ConfigurationFactory.getConfiguration();
    private String groupId = "";
    private long expiration = 1800000;

    private AtomicInteger nextIndex = new AtomicInteger(0);

    HornetQMessageProducer(String producerName) {

        super(producerName);
    }

    protected int nextNode(int serverProxisListSize) {
        int index = nextIndex.incrementAndGet() % serverProxisListSize;
        return index;
    }

    @Override
    public String getProducerImpl() {
        return "CORE";
    }

    private ClientProducer getProducer(String groupIdentifier) {
        try {
            if (producer.get() == null) {
                String realQueueName = createQueueIfNeeded();
                List<ClientProducer> producers = new ArrayList<>();
                for (Pair<ClientSession, SessionFailureListener> clientSession : HornetQMessagingFactory
                        .getSession()) {
                    ClientProducer clientProducer = clientSession.getLeft().createProducer(realQueueName);
                    producersSet.add(clientProducer);
                    producers.add(clientProducer);
                }
                producer.set(producers);
            }

            ClientProducer clientProducer = null;
            if (groupIdentifier != null) {
                clientProducer = producer.get().get(groupIdentifier.hashCode() % producer.get().size());
            } else {
                clientProducer = producer.get().get(nextNode(producer.get().size()));
            }
            return clientProducer;

        } catch (Exception e) {
            LOGGER.error("can't create queue producer: {}", e, e);
            throw new QueueException(e);
        }
    }

    private String createQueueIfNeeded() {

        Configuration subset = configuration.subset(producerName);
        queueName = subset.getString("queue.name");

        if (StringUtils.isBlank(queueName)) {
            throw new QueueException(
                    "Check Configuration - missing required queue name for producer: " + producerName);
        }

        String realQueueName = /*"foundation." + */queueName;

        //update expiration
        expiration = subset.getLong("queue.expiration", 1800000);
        groupId = subset.getString("queue.groupId", "");

        return realQueueName;
    }

    @Override
    public void sendMessage(byte[] message) {
        sendMessage(message, new HashMap<String, Object>());
    }

    @Override
    public void sendMessage(String message) {
        sendMessage(message, new HashMap<String, Object>());
    }

    @Override
    public void sendMessage(byte[] message, Map<String, Object> messageHeaders) {

        String groupIdentifier = null;
        if (StringUtils.isNoneBlank(groupId) && messageHeaders.get(groupId) != null) {
            groupIdentifier = messageHeaders.get(groupId).toString();
        }

        try {

            ClientMessage clientMessage = getClientMessage(messageHeaders, groupIdentifier);
            clientMessage.setExpiration(System.currentTimeMillis() + expiration);
            clientMessage.getBodyBuffer().writeBytes(message);
            getProducer(groupIdentifier).send(clientMessage);

        } catch (Exception e) {
            LOGGER.error("can't send message: {}", e, e);
            throw new QueueException(e);
        }

    }

    @Override
    public void sendMessage(String message, Map<String, Object> messageHeaders) {
        try {

            sendMessageInternal(message, messageHeaders);

        } catch (HornetQObjectClosedException e) {
            LOGGER.warn("can't send message. will try one reconnect. error is: {}", e);
            producer.set(null);
            HornetQMessagingFactory.sessionThreadLocal.set(null);
            //retry once it came back till now
            try {
                sendMessageInternal(message, messageHeaders);
            } catch (Exception e1) {
                LOGGER.error("can't send message: {}", e1, e1);
                throw new QueueException(e1);
            }
        } catch (Exception e) {
            LOGGER.error("can't send message: {}", e, e);
            throw new QueueException(e);
        }
    }

    private void sendMessageInternal(String message, Map<String, Object> messageHeaders) throws HornetQException {
        String groupIdentifier = null;
        if (StringUtils.isNoneBlank(groupId) && messageHeaders.get(groupId) != null) {
            groupIdentifier = messageHeaders.get(groupId).toString();
        }

        ClientMessage clientMessage = getClientMessage(messageHeaders, groupIdentifier);
        clientMessage.setExpiration(System.currentTimeMillis() + expiration);
        clientMessage.getBodyBuffer().writeString(message);
        getProducer(groupIdentifier).send(clientMessage);
    }

    private ClientMessage getClientMessage(Map<String, Object> messageHeaders, String groupIdentifier) {

        ClientMessage clientMessage = HornetQMessagingFactory.getSession().get(0).getLeft().createMessage(true);

        clientMessage.putStringProperty(QueueConstants.FLOW_CONTEXT_HEADER,
                FlowContextFactory.serializeNativeFlowContext());

        for (Map.Entry<String, Object> headers : messageHeaders.entrySet()) {
            clientMessage.putObjectProperty(headers.getKey(), headers.getValue());
        }

        return clientMessage;
    }

    @Override
    public void close() {
        if (getProducer(null) != null) {
            try {
                for (ClientProducer clientProducer : producersSet) {
                    clientProducer.close();
                }
            } catch (HornetQException e) {
                LOGGER.error("can't close producer, error: {}", e, e);
            }
        }
    }
}