Saturday, 28 March 2015

Abstracting JMS over lambdas: Scala vs Java 8

Follows two implementations of a JMS abstraction layer using functional interfaces in Java 8 and Scala 2.11.

Let's start with Java 8.
First the definition of two functional interfaces:
import javax.jms.Session;

@FunctionalInterface
public interface MessagingSession {
  void withSession(final Session session);
}
and import javax.jms.MessageProducer;
@FunctionalInterface
public interface MessagingProducer {
  void produce(final MessageProducer producer);
}
The main class:
import javax.jms.Connection;
import javax.jms.ConnectionFactory;
import javax.jms.Destination;
import javax.jms.Session;
import javax.jms.TextMessage;

import org.apache.activemq.ActiveMQConnectionFactory;

public class Messaging {
  private final boolean transacted = false;
  private final int ackMode = Session.AUTO_ACKNOWLEDGE;
 
  private final ConnectionFactory connectionFactory;
  private final Connection connection;
 
  private Session session = null;
 
  public Messaging() throws Exception {
    this.connectionFactory = new ActiveMQConnectionFactory("vm://localhost");
    this.connection = connectionFactory.createConnection();
    connection.start();
  }
 
  public Destination createQueue(final String qn) throws Exception {
    return session.createQueue(qn);
  }
 
  public TextMessage createTextMessage(final String text) throws Exception {
    return session.createTextMessage(text);
  }
 
  public void withSession(final MessagingSession messagingSession) throws Exception {
    session = connection.createSession(transacted, ackMode);
    messagingSession.withSession(session);
  }
 
  public void withProducer(final Destination destination, final MessagingProducer messagingProducer) throws Exception {
    messagingProducer.produce(session.createProducer(destination));
  }
}
And a demo class - how to use the above:
import javax.jms.Destination;
import javax.jms.TextMessage;

public class JavaMessagingDemo {
  public static void main(String[] args) throws Exception {
    final Messaging messaging = new Messaging();
  
    messaging.withSession((session) -> {
      try {
        final Destination destination = messaging.createQueue("ANOTHER.QUEUE");
        messaging.withProducer(destination, (producer) -> {
          try {
            final TextMessage message = messaging.createTextMessage("MY.MESSAGE");
            producer.send(message);
          } catch (Exception e) {
            e.printStackTrace();
          }
        });
      } catch (Exception e) {
        e.printStackTrace();
      }
    });
  }
}

In Scala 2.11:
import javax.jms.Session
import org.apache.activemq.ActiveMQConnectionFactory
import javax.jms.Destination
import javax.jms.MessageProducer

object Messaging {
  val transacted = false
  val ackMode = Session.AUTO_ACKNOWLEDGE
  val connectionFactory = new ActiveMQConnectionFactory("vm://localhost")
  val connection = connectionFactory.createConnection
  connection.start
  
  implicit def jms2richsession(session: Session) = new EnrichedJMSSession(session)
  
  def withSession(f: Session => Unit) = f(connection.createSession(transacted, ackMode))
  
  class EnrichedJMSSession(val session: Session) {
    def withProducer(dest: Destination)(f: MessageProducer => Unit) = f(session.createProducer(dest))
  }
}

object ScalaDemo {
  import Messaging._
  
  def main(args: Array[String]): Unit = {
    withSession { session =>  
      val dest = session.createQueue("MY.QUEUE")
      session.withProducer(dest) { producer =>
        val message = session.createTextMessage("Some message")
        producer.send(message)
      }
    }
  }
}

No comments:

Blog Archive