Package com.taobao.metamorphosis.client.extension.spring

Source Code of com.taobao.metamorphosis.client.extension.spring.MetaqTemplate

package com.taobao.metamorphosis.client.extension.spring;

import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang.exception.ExceptionUtils;
import org.springframework.beans.factory.DisposableBean;

import com.taobao.gecko.core.util.StringUtils;
import com.taobao.metamorphosis.Message;
import com.taobao.metamorphosis.client.MessageSessionFactory;
import com.taobao.metamorphosis.client.producer.MessageProducer;
import com.taobao.metamorphosis.client.producer.SendMessageCallback;
import com.taobao.metamorphosis.client.producer.SendResult;
import com.taobao.metamorphosis.exception.MetaClientException;
import com.taobao.metamorphosis.utils.ThreadUtils;


/**
* Helper class that simplifies synchronous MetaQ access code.
*
* @author dennis<killme2008@gmail.com>
*
*/
public class MetaqTemplate implements DisposableBean {
    private MessageSessionFactory messageSessionFactory;

    private String defaultTopic;

    private MessageBodyConverter<?> messageBodyConverter;

    private boolean shareProducer = false;

    private volatile MessageProducer sharedProducer;


    /**
     * returns if share a message producer between topics.It's false by default.
     *
     * @return
     * @since 1.4.5
     */
    public boolean isShareProducer() {
        return this.shareProducer;
    }


    /**
     * If true, the template will share a message producer between topics.It's
     * false by default.
     *
     * @param producerPerTopic
     * @since 1.4.5
     */
    public void setShareProducer(boolean producerPerTopic) {
        this.shareProducer = producerPerTopic;
    }

    private final ConcurrentHashMap<String/* topic */, FutureTask<MessageProducer>> producers =
            new ConcurrentHashMap<String, FutureTask<MessageProducer>>();


    /**
     * Returns the default topic for producers.
     *
     * @return
     * @since 1.4.5
     */
    public String getDefaultTopic() {
        return this.defaultTopic;
    }


    /**
     * Returns the message body converter.The default is an instance of
     * JavaSerializationMessageBodyConverter.
     *
     * @return
     */
    public MessageBodyConverter<?> getMessageBodyConverter() {
        return this.messageBodyConverter;
    }


    /**
     * Set message body converter.
     *
     * @param messageBodyConverter
     * @since 1.4.5
     */
    public void setMessageBodyConverter(MessageBodyConverter<?> messageBodyConverter) {
        if (messageBodyConverter == null) {
            throw new IllegalArgumentException("Null messageBodyConverter");
        }
        this.messageBodyConverter = messageBodyConverter;
    }


    /**
     * Set the default topic for producers.
     *
     * @param defaultTopic
     * @since 1.4.5
     */
    public void setDefaultTopic(String defaultTopic) {
        this.defaultTopic = defaultTopic;
    }


    /**
     * Returns the associated message session factory.
     *
     * @return
     * @since 1.4.5
     */
    public MessageSessionFactory getMessageSessionFactory() {
        return this.messageSessionFactory;
    }


    /**
     * Set message session factory fot this template.
     *
     * @param messageSessionFactory
     * @since 1.4.5
     */
    public void setMessageSessionFactory(MessageSessionFactory messageSessionFactory) {
        if (messageSessionFactory == null) {
            throw new IllegalArgumentException("Null messageSessionFactory");
        }
        this.messageSessionFactory = messageSessionFactory;
    }


    /**
     * Returns or create a message producer for topic.
     *
     * @param topic
     * @return
     * @since 1.4.5
     */
    public MessageProducer getOrCreateProducer(final String topic) {
        if (!this.shareProducer) {
            FutureTask<MessageProducer> task = this.producers.get(topic);
            if (task == null) {
                task = new FutureTask<MessageProducer>(new Callable<MessageProducer>() {

                    @Override
                    public MessageProducer call() throws Exception {
                        MessageProducer producer = MetaqTemplate.this.messageSessionFactory.createProducer();
                        producer.publish(topic);
                        if (!StringUtils.isBlank(MetaqTemplate.this.defaultTopic)) {
                            producer.setDefaultTopic(MetaqTemplate.this.defaultTopic);
                        }
                        return producer;
                    }

                });
                FutureTask<MessageProducer> oldTask = this.producers.putIfAbsent(topic, task);
                if (oldTask != null) {
                    task = oldTask;
                }
                else {
                    task.run();
                }
            }

            try {
                MessageProducer producer = task.get();
                return producer;
            }
            catch (ExecutionException e) {
                throw ThreadUtils.launderThrowable(e.getCause());
            }
            catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        else {
            if (this.sharedProducer == null) {
                synchronized (this) {
                    if (this.sharedProducer == null) {
                        this.sharedProducer = this.messageSessionFactory.createProducer();
                        if (!StringUtils.isBlank(this.defaultTopic)) {
                            this.sharedProducer.setDefaultTopic(this.defaultTopic);
                        }
                    }
                }
            }
            this.sharedProducer.publish(topic);
            return this.sharedProducer;
        }
        throw new IllegalStateException("Could not create producer for topic '" + topic + "'");
    }


    /**
     * Send message built by message builder.Returns the sent result.
     *
     * @param builder
     * @return
     * @throws InterruptedException
     * @since 1.4.5
     */
    public SendResult send(MessageBuilder builder, long timeout, TimeUnit unit) throws InterruptedException {
        Message msg = builder.build(this.messageBodyConverter);
        final String topic = msg.getTopic();
        MessageProducer producer = this.getOrCreateProducer(topic);
        try {
            return producer.sendMessage(msg, timeout, unit);
        }
        catch (MetaClientException e) {
            return new SendResult(false, null, -1, ExceptionUtils.getFullStackTrace(e));
        }
    }


    /**
     * Send message built by message builder.Returns the sent result.
     *
     * @param builder
     * @return
     * @throws InterruptedException
     * @since 1.4.5
     */
    public SendResult send(MessageBuilder builder) throws InterruptedException {
        Message msg = builder.build(this.messageBodyConverter);
        final String topic = msg.getTopic();
        MessageProducer producer = this.getOrCreateProducer(topic);
        try {
            return producer.sendMessage(msg);
        }
        catch (MetaClientException e) {
            return new SendResult(false, null, -1, ExceptionUtils.getFullStackTrace(e));
        }
    }


    /**
     * Send message asynchronously with callback.
     *
     * @param builder
     * @param cb
     * @param timeout
     * @param unit
     * @since 1.4.5
     */
    public void send(MessageBuilder builder, SendMessageCallback cb, long timeout, TimeUnit unit) {
        Message msg = builder.build(this.messageBodyConverter);
        final String topic = msg.getTopic();
        MessageProducer producer = this.getOrCreateProducer(topic);
        producer.sendMessage(msg, cb, timeout, unit);
    }


    @Override
    public void destroy() throws Exception {
        if (this.sharedProducer != null) {
            this.sharedProducer.shutdown();
            this.sharedProducer = null;
        }
        for (FutureTask<MessageProducer> task : this.producers.values()) {
            try {
                MessageProducer producer = task.get(5000, TimeUnit.MILLISECONDS);
                if (producer != null) {
                    producer.shutdown();
                }
            }
            catch (Exception e) {
                // ignore
            }
        }
        this.producers.clear();

    }


    /**
     * Send message asynchronously with callback.
     *
     * @param builder
     * @param cb
     * @since 1.4.5
     */
    public void send(MessageBuilder builder, SendMessageCallback cb) {
        Message msg = builder.build(this.messageBodyConverter);
        final String topic = msg.getTopic();
        MessageProducer producer = this.getOrCreateProducer(topic);
        producer.sendMessage(msg, cb);
    }

}
TOP

Related Classes of com.taobao.metamorphosis.client.extension.spring.MetaqTemplate

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.