Package com.jbrisbin.groovy.mqdsl

Source Code of com.jbrisbin.groovy.mqdsl.RabbitMQBuilder$EventInvokingMessageListener

/*
* Copyright (c) 2010 by J. Brisbin <jon@jbrisbin.com>
*
* 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.jbrisbin.groovy.mqdsl;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentLinkedQueue;

import com.rabbitmq.client.Channel;
import groovy.lang.Closure;
import groovy.lang.GString;
import groovy.lang.GroovyObjectSupport;
import groovy.util.BuilderSupport;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.AcknowledgeMode;
import org.springframework.amqp.core.Binding;
import org.springframework.amqp.core.BindingBuilder;
import org.springframework.amqp.core.CustomExchange;
import org.springframework.amqp.core.DirectExchange;
import org.springframework.amqp.core.Exchange;
import org.springframework.amqp.core.FanoutExchange;
import org.springframework.amqp.core.HeadersExchange;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.core.MessageListener;
import org.springframework.amqp.core.MessageProperties;
import org.springframework.amqp.core.Queue;
import org.springframework.amqp.core.TopicExchange;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitAdmin;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer;
import org.springframework.amqp.rabbit.listener.adapter.MessageListenerAdapter;
import org.springframework.util.StringUtils;

/**
* Created by IntelliJ IDEA. User: jbrisbin Date: Mar 31, 2010 Time: 10:16:03 AM To change this template use File |
* Settings | File Templates.
*/
@SuppressWarnings({"unchecked"})
public class RabbitMQBuilder extends BuilderSupport {

  static final String BEFORE_PUBLISH = "beforePublish";
  static final String AFTER_PUBLISH = "afterPublish";
  static final String EXCHANGE = "exchange";
  static final String ROUTING_KEY = "routingKey";
  static final String DURABLE = "durable";
  static final String AUTO_DELETE = "autoDelete";
  static final String EXCLUSIVE = "exclusive";
  static final String ARGUMENTS = "arguments";
  static final String NAME = "name";
  static final String TYPE = "type";
  static final String DIRECT = "direct";
  static final String TOPIC = "topic";
  static final String FANOUT = "fanout";
  static final String HEADERS = "headers";
  static final String ON = "on";
  static final String QUEUE = "queue";
  static final String CONSUME = "consume";
  static final String PUBLISH = "publish";
  static final String ON_MESSAGE = "onmessage";
  static final String ACK = "ack";
  static final String CALL = "call";
  static final String ERROR = "error";

  Logger log = LoggerFactory.getLogger(getClass());
  ConnectionFactory connectionFactory;
  ConcurrentLinkedQueue<SimpleMessageListenerContainer> listenerContainers = new ConcurrentLinkedQueue<SimpleMessageListenerContainer>();
  RabbitTemplate rabbitTemplate;
  RabbitAdmin rabbitAdmin;
  Exchange currentExchange;
  Queue currentQueue;
  String currentRoutingKey = null;
  List<Channel> activeChannels = new LinkedList<Channel>();
  Map<String, List<Closure>> eventHandlers = new LinkedHashMap<String, List<Closure>>();

  public ConnectionFactory getConnectionFactory() {
    return connectionFactory;
  }

  public void setConnectionFactory(ConnectionFactory connectionFactory) {
    this.connectionFactory = connectionFactory;
    this.rabbitTemplate = new RabbitTemplate(connectionFactory);
    this.rabbitAdmin = new RabbitAdmin(connectionFactory);
  }

  public boolean isActive() {
    for (SimpleMessageListenerContainer c : listenerContainers) {
      if (c.isActive()) {
        return true;
      }
    }
    return false;
  }

  public void cancelAllConsumers() {
    for (SimpleMessageListenerContainer c : listenerContainers) {
      c.shutdown();
    }
  }

  public void call(Closure cl) {
    Channel channel = connectionFactory.createConnection().createChannel(false);
    cl.call(new Object[]{channel});
    activeChannels.add(channel);
  }

  public void close() {
    for (Channel channel : activeChannels) {
      try {
        channel.close();
      } catch (IOException e) {
        log.error(e.getMessage(), e);
      }
    }
    for (SimpleMessageListenerContainer c : listenerContainers) {
      c.shutdown();
    }
  }

  @Override
  protected void nodeCompleted(Object parent, Object node) {
    if (log.isDebugEnabled()) {
      log.debug(String.format("nodeCompleted(Object parent, Object node): %s, %s", parent, node));
    }
    super.nodeCompleted(parent, node);
  }

  @Override
  protected void setParent(Object from, Object to) {
    if (log.isDebugEnabled()) {
      log.debug(String.format("setParent(Object o, Object o1): %s, %s", from, to));
    }
    if (from instanceof Exchange) {
      currentExchange = (Exchange) from;
    }
    if (from instanceof Queue) {
      currentQueue = (Queue) from;
    }
  }

  @Override
  protected Object createNode(Object o) {
    if (log.isDebugEnabled()) {
      log.debug(String.format("createNode(Object o): %s", o));
    }
    if (o instanceof Consume || o instanceof Publish) {
      return o;
    }
    return null;
  }

  @Override
  protected Object createNode(Object node, Object arg) {
    if (log.isDebugEnabled()) {
      log.debug(String.format("setParent(Object node, Object arg): %s, %s", node, arg));
    }
    if (arg instanceof Consume || arg instanceof Publish) {
      return arg;
    }

    return null;
  }

  @Override
  protected Object createNode(Object o, final Map params) {
    if (log.isDebugEnabled()) {
      log.debug(String.format("createNode(Object o, Map params): %s, %s", o, params));
    }
    String node = o.toString();
    if (ON.equals(node)) {
      // Event handlers
      for (Map.Entry<String, Closure> entry : ((Map<String, Closure>) params).entrySet()) {
        String eventName = entry.getKey();
        List<Closure> handlers;
        if (eventHandlers.containsKey(eventName)) {
          handlers = eventHandlers.get(eventName);
        } else {
          handlers = new ArrayList<Closure>();
          eventHandlers.put(eventName, handlers);
        }
        if (entry.getValue() instanceof List) {
          for (Closure cl : (List<Closure>) entry.getValue()) {
            handlers.add(cl);
          }
        } else if (entry.getValue() instanceof Closure) {
          Closure cl = entry.getValue();
          cl.setProperty(NAME, eventName);
          handlers.add(cl);
        }
      }
      return null;
    } else if (EXCHANGE.equals(node)) {
      boolean durable = params.containsKey(DURABLE) ? (Boolean) params.get(DURABLE) : false;
      boolean autoDelete = params.containsKey(AUTO_DELETE) ? (Boolean) params.get(AUTO_DELETE) : false;
      Map arguments = params.containsKey(ARGUMENTS) ? (Map) params.get(ARGUMENTS) : null;
      currentRoutingKey = null;

      Exchange exchange = null;
      String name = null;
      if (params.containsKey(NAME)) {
        name = params.get(NAME).toString();
      }
      if (params.containsKey(TYPE)) {
        String type = params.containsKey(TYPE) ? params.get(TYPE).toString() : DIRECT;
        if (DIRECT.equals(type)) {
          exchange = new DirectExchange(name, durable, autoDelete, arguments);
        } else if (TOPIC.equals(type)) {
          exchange = new TopicExchange(name, durable, autoDelete, arguments);
        } else if (FANOUT.equals(type)) {
          exchange = new FanoutExchange(name, durable, autoDelete, arguments);
        } else if (HEADERS.equals(type)) {
          exchange = new HeadersExchange(name, durable, autoDelete, arguments);
        } else {
          exchange = new CustomExchange(name, type, durable, autoDelete, arguments);
        }
        currentExchange = exchange;

      } else {
        currentExchange = new DirectExchange(name);
      }
      try {
        rabbitAdmin.declareExchange(currentExchange);
      } catch (Exception e) {
        log.error(e.getMessage(), e);
        dispatchError(e);
      }

      return exchange;
    } else if (QUEUE.equals(node)) {
      boolean durable = params.containsKey(DURABLE) ? (Boolean) params.get(DURABLE) : false;
      boolean autoDelete = params.containsKey(AUTO_DELETE) ? (Boolean) params.get(AUTO_DELETE) : true;
      String routingKey = params.containsKey(ROUTING_KEY) ? params.get(ROUTING_KEY).toString() : null;
      if (null != routingKey) {
        currentRoutingKey = routingKey;
      }
      boolean exclusive = params.containsKey(EXCLUSIVE) ? (Boolean) params.get(EXCLUSIVE) : false;
      Map arguments = params.containsKey(ARGUMENTS) ? (Map) params.get(ARGUMENTS) : null;

      Queue q = null;
      String name;
      if (params.containsKey(NAME)) {
        try {
          if (null == params.get(NAME)) {
            name = null;
          } else {
            name = params.get(NAME).toString();
          }

          if (name == null) {
            q = rabbitAdmin.declareQueue();
          } else {
            q = new Queue(name, durable, exclusive, autoDelete);
            rabbitAdmin.declareQueue(q);
          }
          currentQueue = q;

          if (null != currentExchange) {
            Binding binding = null;
            if (currentExchange instanceof FanoutExchange) {
              binding = BindingBuilder.bind(q).to((FanoutExchange) currentExchange);
            } else if (currentExchange instanceof DirectExchange) {
              binding = BindingBuilder.bind(q).to((DirectExchange) currentExchange).with(routingKey);
            } else if (currentExchange instanceof HeadersExchange) {
              binding = BindingBuilder.bind(q).to((HeadersExchange) currentExchange).whereAll(arguments).match();
            } else if (currentExchange instanceof TopicExchange) {
              binding = BindingBuilder.bind(q).to((TopicExchange) currentExchange).with(routingKey);
            } else if (currentExchange instanceof CustomExchange) {
              binding = BindingBuilder.bind(q).to(currentExchange).with(routingKey).noargs();
            }

            if (null != binding) {
              rabbitAdmin.declareBinding(binding);
            }
          }
        } catch (Exception e) {
          log.error(e.getMessage(), e);
          dispatchError(e);
        }
      }
      return q;
    }

    return null;
  }

  @Override
  protected Object createNode(Object o, Map map, Object o1) {
    if (log.isDebugEnabled()) {
      log.debug(String.format("createNode(Object o, Map map, Object o1): %s, %s, %s", o, map, o1));
    }
    return null;
  }

  @Override
  public Object invokeMethod(String methodName, Object args) {
    if (CONSUME.equals(methodName)) {
      Consume consume = new Consume();
      SimpleMessageListenerContainer listenerContainer = consume.getListenerContainer();
      Object[] params = (Object[]) args;
      for (Object param : params) {
        if (param instanceof Map) {
          Map paramMap = (Map) param;

          if (paramMap.containsKey(ON_MESSAGE)) {
            Object onMessage = paramMap.get(ON_MESSAGE);
            if (onMessage instanceof String) {
              consume.setEventName((String) onMessage);
            } else if (onMessage instanceof Closure) {
              consume.setDelegate((Closure) onMessage);
            } else if (onMessage instanceof MessageListener) {
              listenerContainer.setMessageListener(onMessage);
            } else {
              listenerContainer.setMessageListener(new MessageListenerAdapter(onMessage));
            }
          }

          if (paramMap.containsKey(ACK)) {
            AcknowledgeMode mode = AcknowledgeMode.valueOf(paramMap.get(ACK).toString().toUpperCase());
            listenerContainer.setAcknowledgeMode(mode);
          } else {
            listenerContainer.setAcknowledgeMode(AcknowledgeMode.AUTO);
          }

        } else if (param instanceof Closure) {
          consume.setDelegate((Closure) param);
        }
      }
      listenerContainer.setQueues(currentQueue);
      listenerContainer.afterPropertiesSet();
      listenerContainer.start();
      listenerContainers.add(listenerContainer);

      return super.invokeMethod(methodName, consume);
    } else if (PUBLISH.equals(methodName)) {
      Publish publish = new Publish();
      publish.invokeMethod(CALL, args);
      return super.invokeMethod(methodName, publish);
    }

    return super.invokeMethod(methodName, args);
  }

  void dispatchError(Throwable t) {
    dispatchEvent(ERROR, new Object[]{t});
  }

  void dispatchEvent(String name, Object[] args) {
    if (log.isDebugEnabled()) {
      log.debug("Dispatching event " + name + " with args: " + arrayToString(args));
    }
    if (eventHandlers.containsKey(name)) {
      for (Closure cl : eventHandlers.get(name)) {
        cl.call(args);
      }
    }
  }

  String arrayToString(Object[] o) {
    StringBuffer buff = new StringBuffer("[");
    for (int i = 0; i < o.length; i++) {
      if (i > 0) {
        buff.append(",");
      }
      buff.append(String.valueOf(o[i]));
    }
    buff.append("]");
    return buff.toString();
  }

  class Consume extends GroovyObjectSupport {

    SimpleMessageListenerContainer listenerContainer = new SimpleMessageListenerContainer(connectionFactory);
    String eventName = null;
    Closure delegate = null;

    Consume() {
    }

    public String getEventName() {
      return eventName;
    }

    public void setEventName(String eventName) {
      this.eventName = eventName;
      listenerContainer.setMessageListener(new EventInvokingMessageListener(this));
    }

    public Closure getDelegate() {
      return delegate;
    }

    public void setDelegate(Closure delegate) {
      this.delegate = delegate;
      listenerContainer.setMessageListener(new ClosureInvokingMessageListener(this));
    }

    public SimpleMessageListenerContainer getListenerContainer() {
      return listenerContainer;
    }

    public void shutdown() {
      listenerContainer.shutdown();
      listenerContainers.remove(listenerContainer);
    }
  }

  class ClosureInvokingMessageListener implements MessageListener {

    Consume consume;
    Object lastResult = null;

    ClosureInvokingMessageListener(Consume consume) {
      this.consume = consume;
    }

    public Object getLastResult() {
      return lastResult;
    }

    @Override
    public void onMessage(Message message) {
      if (null != consume.getDelegate()) {
        lastResult = consume.getDelegate().call(message);
        if (null == lastResult || (lastResult instanceof Boolean && !((Boolean) lastResult).booleanValue())) {
          consume.shutdown();
        }
      }
    }
  }

  class EventInvokingMessageListener implements MessageListener {

    Consume consume;

    EventInvokingMessageListener(Consume consume) {
      this.consume = consume;
    }

    @Override
    public void onMessage(Message message) {
      if (null != consume.getEventName()) {
        dispatchEvent(consume.getEventName(), new Object[]{message});
        consume.shutdown();
      }
    }
  }

  class Publish extends GroovyObjectSupport {
    public Object call(Map<String, Object> params, Object bodyObj) throws IOException {
      String exchange = null != currentExchange ? currentExchange.getName() : null;
      if (null != params && params.containsKey(EXCHANGE)) {
        Object oexchange = params.get(EXCHANGE);
        if (null != oexchange && StringUtils.hasText(oexchange.toString())) {
          exchange = oexchange.toString();
        }
      }
      String routingKey = currentRoutingKey;
      if (null != params && params.containsKey(ROUTING_KEY)) {
        Object oroutingKey = params.get(ROUTING_KEY);
        if (null != oroutingKey && StringUtils.hasText(oroutingKey.toString())) {
          routingKey = oroutingKey.toString();
        }
      }
      return call(exchange, routingKey, params, bodyObj);
    }

    public Object call(String exchange, String routingKey, Map<String, Object> headers, Object bodyObj) throws IOException {
      Message msg = createMessage(headers, bodyObj);
      if (null == exchange && null != currentExchange) {
        exchange = currentExchange.getName();
      }
      if (null == routingKey && null != currentRoutingKey) {
        routingKey = currentRoutingKey;
      }

      dispatchEvent(BEFORE_PUBLISH, new Object[]{exchange, routingKey, msg});
      try {
        rabbitTemplate.send(exchange, routingKey, msg);
        dispatchEvent(AFTER_PUBLISH, new Object[]{exchange, routingKey, msg});
      } catch (Exception e) {
        dispatchError(e);
      }


      return this;
    }

    public Object call(Map<String, Object> params, Closure bodyClosure) throws IOException {
      String exchange = params.containsKey(EXCHANGE) ? params.remove(EXCHANGE).toString() : null;
      String routingKey = params.containsKey(ROUTING_KEY) ? params.remove(ROUTING_KEY).toString() : null;
      ByteArrayOutputStream bytesOut = new ByteArrayOutputStream();
      Object bodyObj = bodyClosure.call(bytesOut);
      bytesOut.flush();

      byte[] bytes = bytesOut.toByteArray();
      if (bytes.length > 0) {
        return call(exchange, routingKey, params, bytes);
      } else {
        return call(exchange, routingKey, params, bodyObj);
      }
    }

    private MessageProperties createProperties(Map<String, Object> headers) {
      MessageProperties msgProps = new MessageProperties();
      for (Map.Entry<String, Object> entry : headers.entrySet()) {
        String key = entry.getKey();
        String value = null != entry.getValue() ? entry.getValue().toString() : null;
        if ("contentType".equals(key)) {
          msgProps.setContentType(value);
        } else if ("correlationId".equals(key)) {
          msgProps.setCorrelationId(value.getBytes());
        } else if ("replyTo".equals(key)) {
          msgProps.setReplyTo(value);
        } else if ("contentEncoding".equals(key)) {
          msgProps.setContentEncoding(value);
        } else {
          msgProps.setHeader(key, value);
        }
      }
      return msgProps;
    }

    private Message createMessage(Map<String, Object> params, Object bodyObj) throws IOException {
      MessageProperties msgProps = createProperties(params);
      if (bodyObj instanceof Closure) {
        // If it's a Closure, invoke it to get the value
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        Closure cl = (Closure) bodyObj;
        Object returnFromBodyClosure = cl.call(new Object[]{out});
        if (returnFromBodyClosure instanceof Message) {
          return (Message) returnFromBodyClosure;
        } else if (returnFromBodyClosure instanceof String) {
          return new Message(((String) returnFromBodyClosure).getBytes(), msgProps);
        } else {
          out.flush();
          return new Message(out.toByteArray(), msgProps);
        }
      } else if (bodyObj instanceof String || bodyObj instanceof GString) {
        // If it's sort of a String, toString() it
        return new Message(bodyObj.toString().getBytes(), msgProps);
      } else if (bodyObj instanceof byte[]) {
        // If it's raw bytes, don't do anything
        return new Message((byte[]) bodyObj, msgProps);
      } else {
        // Otherwise, write the object out using JDK serialization
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oout = new ObjectOutputStream(bout);
        oout.writeObject(bodyObj);
        oout.flush();
        oout.close();
        bout.flush();

        return new Message(bout.toByteArray(), msgProps);
      }
    }
  }

}
TOP

Related Classes of com.jbrisbin.groovy.mqdsl.RabbitMQBuilder$EventInvokingMessageListener

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.