Google

Jun 19, 2014

JMS Interview Questions and Answers

Q. What is Message Oriented Middleware? What is JMS?
A.  Message Oriented Middleware (MOM) is generally defined as a software infrastructure that asynchronously communicates with other disparate systems (e.g. Mainframe system, C++ System, etc) through the production and consumption of messages. A message may be a request, a report, or an event sent from one part of an enterprise application to another.

Q. How does JMS differ from RPC(Remote Procedure Call)?
A
Remote Procedure Call (e.g. RMI) Java Messaging Service (JMS)
Remote Procedure Call (RPC) technologies like RMI attempt to mimic the behavior of system that runs in one process. When a remote procedure is invoked the caller is blocked until the procedure completes and returns control to the caller. This is a synchronous model where process is performed sequentially ensuring that tasks are completed in a predefined order. The synchronized nature of RPC tightly couples the client (the software making the call) to the server (the software servicing the call). The client can not proceed (i.e. its blocked) until the server responds. The tightly coupled nature of RPC creates highly interdependent systems where a failure on one system has an immediate impact on other systems. With the use of Message Oriented Middleware (MOM), problems with the availability of subsystems are less of an issue. A fundamental concept of MOM is that communications between components is intended to be asynchronous in nature. Code that is written to connect the pieces together assumes that there is a one-way message that requires no immediate response. In other words, there is no blocking. Once a message is sent, the sender can move on to other tasks; it doesn't have to wait for a response. This is the major difference between RPC and asynchronous messaging and is critical to understanding the advantages offered by MOM systems. In an asynchronous messaging system each subsystem (Customer, Account, etc) is decoupled from the other systems. They communicate through the messaging server (aka a broker), so that a failure in one does not impact the operation of the others.

Q. Why use JMS?
A. Message Oriented Middleware (MOM) systems like Websphere MQ (formerly known as MQSeries), webMethods broker, SonicMQ, etc are proprietary systems. Java Message Service (JMS) is a Java API that allows applications to create, send, receive, and read messages in a standard way.  Like JDBC API is used to access database drivers in a standard way.



This is another example of the adapter design pattern. Designed by Sun and several partner companies, the JMS API defines a common set of interfaces and associated semantics that allow programs written in the Java programming language to communicate with other messaging implementations provided by MOM libraries. The JMS API minimizes the set of concepts a programmer must learn to use messaging products but provides enough features to support sophisticated messaging applications.

Many companies have spent decades developing their legacy systems. So, XML can be used in a non-proprietary way to move data from legacy systems to distributed systems like JEE over the wire-using MOM implementation and JMS interface.

Q. What are the components of the JMS architecture?
A.



Message producers: A component that is responsible for creating a message. E.g. QueueSender, and TopicPublisher. An application can have several message producers. Each producer might be responsible for creating different types of messages and sending them to different destinations (i.e. Topic or Queue). A message producer will send messages to a destination regardless of whether or not a consumer is there to consume it.

Message consumers: A component which resides on the receiving end of a messaging application. Its responsibility is to listen for messages on a destination (i.e. Topic or Queue) . E.g. QueueReceiver, TopicSubscriber, MessageDrivenBean (MDB). A MDB is simply a JMS message consumer. A client cannot access a MDB directly as you would do with Session or Entity beans. You can only interface with a MDB by sending a JMS message to a destination (i.e. Topic or Queue) on which the MDB is listening.

Message destinations: A component which a client uses to specify the target of messages it sends/receives. E.g. Topic (publish/Subscribe domain) and Queue (Point-to-Point domain). Message destinations typically live on a MOM, which is remote to the clients. Message destinations are administered objects that need to be configured.

JMS messages: A message is a component that contains the information (aka payload) that must be communicated to another application or component. E.g. TextMessage (XML file), ObjectMessage (serialized object) etc.



JMS Administered objects: JMS administered objects are objects containing configuration information that are set up during application deployment or configuration and later used by JMS clients. They make it practical to administer the JMS API in the enterprise. These administered objects are initialized when the application server starts. When a producer or a consumer needs to get a connection to receive or send a JMS message, then you need to locate the configured administered objects QueueConnectionFactory or TopicConnectionFactory. Message destinations are administered objects that need to be configured as well. These administered objects hide provider-specific details from JMS clients.

JNDI naming service: For a producer and consumer to be able to use the administered objects to send and receive messages, they must know how to locate things such as the destination and connection factories.

Example To publish a message to a topic: (Note: exception handling etc are omitted for brevity)

 String factoryJndiName = "WSMQTopicConnectionFactory";
 String destinationJndiName = "wsmq/topic/ProductManagerTopic";

 //JNDI lookup of administered ConnectionFactory object
 Context iniCtx = new InitialContext();
 TopicConnectionFactory topicCF = (TopicConnectionFactory) iniCtx.lookup(factoryJndiName);

 //JNDI lookup of administered destination (i.e. Topic)
 Topic topicDestination = (Topic) iniCtx.lookup(destinationJndiName);

 //get a connection from the TopicConnectionFactory
 TopicConnection publishConnection = topicCF.createTopicConnection(); 
 
 //get a session from the connection. Session should be accessed by only one thread.
 TopicSession publishSession =   
                 publishConnection.createTopicSession(false,TopicSession.AUTO_ACKNOWLEDGE);
 
 //create a publisher from the session
 TopicPublisher publisher = publishSession.createPublisher(reqDestination);

 //create a JMS message to send
 TextMessage message = publishSession.createTextMessage();
 message.setText("JMS test message");

 //send the message
 publisher.publish(message, DeliveryMode.NON_PERSISTENT, 4, 0);


To consume a message

String factoryJndiName = "WSMQTopicConnectionFactory";
String destinationJndiName = "wsmq/topic/ProductManagerTopic";

//JNDI lookup of administered ConnectionFactory object
Context iniCtx = new InitialContext();
TopicConnectionFactory topicCF = (TopicConnectionFactory) iniCtx.lookup(factoryJndiName);

//JNDI lookup of administered destination (i.e. Topic)
Topic topicDestination = (Topic) iniCtx.lookup(destinationJndiName);

//get a connection from the TopicConnectionFactory
TopicConnection subscribeConnection = topicCF.createTopicConnection(); 
 
//get a session from the connection
TopicSession subscribeSession = 
                  subscribeConnection.createTopicSession(false,TopicSession.AUTO_ACKNOWLEDGE);
 
//create a subscriber from the session
TopicSubscriber subscriber = subscribeSession.createsubscriber(reqDestination);

//look for messages every 1 second
while (true) {
    Message response = subscriber.receive();

    if (response != null && response instanceof TextMessage) {
         System.out.println (((TextMessage) response).getText());
    } 

    Thread.sleep(1000);
}


If you use JEE container with a Message Driven Bean (MDB) or Spring Container with a message listener, the container will provide the infrastructure for receiving messages, and invokes the onMessage(Message message) to process the message.

public void onMessage(Message message) {

    String text = null;
    if (message instanceof TextMessage) {
       text = ((TextMessage)message).getText();
    }

    log.info(text);
}


Q. What is a message broker?
A. A message broker acts as a server in a MOM. A message broker performs the following operations on a message it receives:

  • Processes message header information.
  • Performs security checks and encryption/decryption of a received message.
  • Handles errors and exceptions.
  • Routes message header and the payload (aka message body).
  • Invokes a method with the payload contained in the incoming message (e.g. calling onMessage(..) method on a Message Driven Bean (MDB)).
  • Transforms the message to some other format. For example XML payload can be converted to other formats like HTML etc with XSLT.

Labels: ,

Aug 6, 2013

Spring JMS with Websphere MQ (aka MQ Series) -- Part 2 (Sender)



This is the continuation of Spring JMS with Websphere MQ -- Part 1.


Step 5: In Part 1, we configured the Connectionfactory, and in this step  configure the JMSTemplate with the @Configurable Spring annotation

package com.myapp.jms;

import java.io.IOException;

import javax.annotation.Resource;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;

@Configuration
public class MyAppJmsTemplateConfig {

 @Value("${my.queue}")
    private String myAppQueueName;
 
 @Resource (name = "internalJmsConnectionFactory")
 private ConnectionFactory connectionFactory;
 
 @Bean(name = "myAppJmsTemplate")
 public JmsTemplate busniessExceptionJmsTemplate() throws JMSException, IOException {
  
  JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory); 
  jmsTemplate.setExplicitQosEnabled(true);
  jmsTemplate.setDefaultDestinationName(myAppQueueName);
  return jmsTemplate;
 }
}

Step 6: Define the Spring context xml file META-INF/spring/myApp-applicationContext.xml file.

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" 
    xmlns:jee="http://www.springframework.org/schema/jee" 
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:task="http://www.springframework.org/schema/task"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:jms="http://www.springframework.org/schema/integration/jms"
    xmlns:cache="http://www.springframework.org/schema/cache"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" 
    xsi:schemaLocation="
            http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
            http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.1.xsd
            http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.1.xsd
            http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
            http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
            http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-3.1.xsd
            http://www.springframework.org/schema/jms http://www.springframework.org/schema/jms/spring-jms-3.1.xsd
            http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd     
            http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache-3.1.xsd">

 <bean id="placeholderConfig" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="ignoreUnresolvablePlaceholders" value="false" />
    <property name="location" value="classpath:calculation/validation.properties" />
 </bean>
 
  <context:component-scan base-package="com.myapp.jms">

</beans>

Step 7: Define the message sender class that publishes the message to the default queue that was configured earlier.

package com.myapp.service.impl;

import com.google.common.base.Stopwatch;
import com.myapp.service.MyAppService;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import javax.annotation.concurrent.ThreadSafe;
import javax.jms.JMSException;
import javax.jms.Message;
import javax.jms.Session;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.core.MessageCreator;
import org.springframework.stereotype.Component;
import org.springframework.util.Assert;

/**
 * Asynchronously submits a string to the JMS queue
 */
@Component
@ThreadSafe
public class MyAppServiceImpl implements MyAppService
{
    
    private static final Logger LOG = LoggerFactory.getLogger(MyAppServiceImpl.class);
    
    @Resource(name = "myAppJmsTemplate")
    private JmsTemplate jmsTemplate;
    
    @Value("${my.publishers.count}")
    int publisherCount;
    

    private ExecutorService pooledSender;
    
    @PostConstruct
    void init()
    {
        pooledSender = Executors.newFixedThreadPool(publisherCount);
    }
    
   
    @Override
    public void send(final String msg)
    {
        pooledSender.execute(new Runnable()
        {
            @Override
            public void run()
            {
                send(msg);
            }
            
            private void send(final String msg, int retryCount)
            {
                
                Stopwatch stopwatch = new Stopwatch().start();
                try
                {
 
                    jmsTemplate.send(new MessageCreator()
                    {
                        @Override
                        public Message createMessage(Session session) throws JMSException
                        {
                            return session.createTextMessage(msg);
                        }
                    });
                }
                catch (Exception e)
                {
                    LOG.warn("Unable to send message to JMS Queue {}", msg);
                   
                }
                LOG.info(" message sent to JMS Queue in {} ms", stopwatch.elapsedMillis());
            }
        });
    }
}


Step 8: Finally, the JUnit test class that

package com.myapp.service.impl;

import com.myapp.service.MyAppExecutionService;

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

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.PropertySource;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:META-INF/spring/myApp-applicationContext.xml")
@PropertySource(
{
    "classpath:jms/internalConnection.properties"
   
})
public class MyAppServiceImplSenderIntegrationTest
{
    
    private static final Logger LOG = LoggerFactory.getLogger(MyAppServiceImplSenderIntegrationTest.class);
    
    @Resource
    private MyAppExecutionService executionService;
    
    
    @Test
    public void myAppIntegrationTest()
    {
        
        for (int i = 0; i < 1; i++)
        {
            final Map<String, String> detailMap = new HashMap<String, String>();
            detailMap.put("KeyA", "ValueA" + i);
            detailMap.put("KeyB", "ValueB" + i);
            executionService.send(detailMap.toString());
        }
    }
}



Labels: ,

Aug 1, 2013

Spring JMS with Websphere MQ (aka MQ Series) -- Part 2 (Receiver or Subscriber)



This is the continuation Spring JMS with Websphere MQ -- Part 1 (Configuration), and Spring JMS with Websphere MQ -- Part 2 (Sender).


Step 1: Write a listener class to receive the message by invoking the onMessage(Message message) method.

package com.myapp.service.impl;

import javax.jms.Message;
import javax.jms.MessageListener;
import javax.jms.TextMessage;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
//@Transactional
public class MyAppListenerListener implements MessageListener
{
    
    private static Logger LOG = LoggerFactory.getLogger(MyAppListenerListener.class);
    
    @Override
    public void onMessage(Message message)
    {
        LOG.info("Entered ...............");
        
        if (message instanceof TextMessage)
        {
            try
            {
                String msg = ((TextMessage) message).getText();
                LOG.debug("Message contents: {} ", msg);
                System.out.println(msg);
            }
            catch (Exception e)
            {
                LOG.error("Error processing the message");
               
            }
            
        }
        
    }
}


Step 2 :  Configure the Spring container and bootstrap the MyAppListenerListener  to the container. You can set up multiple consumers to run concurrently in multiple threads. This basically involves extending the class MyAppJmsTemplateConfig defined in part -2.

package com.myapp.jms;

import java.io.IOException;

import javax.annotation.Resource;
import javax.jms.ConnectionFactory;
import javax.jms.JMSException;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;

@Configuration
@ComponentScan(basePackageClasses =
{
    MyAppListener.class
})
@PropertySource(
{
    "classpath:jms/internalConnection.properties"
})
public class MyAppJmsTemplateConfig  {

 @Value("${my.queue}")
    private String myAppQueueName;
 
 @Resource (name = "internalJmsConnectionFactory")
 private ConnectionFactory connectionFactory;
 
 @Resource
    private MyAppListener myAppListener;
 
 private int maxConsumers = 3; //3 concurrent consumers
 
 @Bean(name = "myAppJmsTemplate")
 public JmsTemplate myAppJmsTemplate() throws JMSException, IOException {
  
  JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory); 
  jmsTemplate.setExplicitQosEnabled(true);
  jmsTemplate.setDefaultDestinationName(myAppQueueName);
  return jmsTemplate;
 } 
 
   /**
     * Sets up the JMS MessageListener 
     * 
     * @return
     */
    @Bean
    public DefaultMessageListenerContainer myAppListenerContainer()
    {
        DefaultMessageListenerContainer listenerContainer = new DefaultMessageListenerContainer();
        listenerContainer.setConnectionFactory(internalJmsConnectionFactory);
        listenerContainer.setDestinationName(myAppQueueName);
        listenerContainer.setMessageListener(myAppListener);
        listenerContainer.setMaxConcurrentConsumers(maxConsumers);
        listenerContainer.setSessionTransacted(true);
        return listenerContainer;
    }
}


Refer to the myAppListenerContainer( ) method to bind the Spring listener container to the listener you defined earlier itself.


Step 3: Finally,the JUnit test class that waits for 10 minutes. In other words, waiting for the onMessage(...) method to be kicked off asynchronously when a message arrives on the queue.

package com.myapp.service.impl;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:META-INF/spring/myApp-applicationContext.xml")
public class DeCalcRunListenerIntegrationTest
{
    
    @Test
    public void testOnMessage() throws InterruptedException
    {
        Thread.sleep(300000);
    }  
}

Labels: ,

Jul 30, 2013

Spring JMS with Websphere MQ (aka MQ Series) -- Part 1 (configuration)

Messaging systems are used in enterprise applications for scalability. Here is the series of JMS tutorials. Stay tuned for more parts to follow.



Step 1: Add the relevant dependency jars to the pom.xml file.

<!-- Spring -->
<dependency>
 <groupId>org.springframework</groupId>
 <artifactId>spring-jms</artifactId>
</dependency>
<!-- JMS/MQ -->
<dependency>
 <groupId>com.ibm.webshere.mq7</groupId>
 <artifactId>commonservices</artifactId>
</dependency>
<dependency>
 <groupId>com.ibm.webshere.mq7</groupId>
 <artifactId>com-ibm-mqjms</artifactId>
</dependency>
<dependency>
 <groupId>com.ibm.webshere.mq7</groupId>
 <artifactId>com-ibm-mq</artifactId>
</dependency>
<dependency>
 <groupId>com.ibm.webshere.mq7</groupId>
 <artifactId>dhbcore</artifactId>
</dependency>
<dependency>
 <groupId>com.ibm.webshere.mq7</groupId>
 <artifactId>com-ibm-mq-jmqi</artifactId>
</dependency>
<dependency>
 <groupId>javax.jms</groupId>
 <artifactId>jms</artifactId>
</dependency>
<dependency>
 <groupId>javax.jms</groupId>
 <artifactId>jms</artifactId>
</dependency>


Step 2: Define the JMS properties jms/internalConnection.properties as shown below

#connection factory properties
jms.transportType=1  # i.e. TCP
jms.hostName=your_host
jms.channel=your.channel
jms.port=1414
jms.queueManager=your.que.manager
jms.sslEnabled=false
jms.sslCipherSuite=
jms.ssl.keystore.path=
jms.ssl.password=
 
#destination property 
my.queueName=my.queue 


Step 3: An abstract class that configures the  ConnectionFactory.

package com.myapp.jms;

import java.util.Properties;

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.convert.support.ConfigurableConversionService;
import org.springframework.core.convert.support.DefaultConversionService;

import com.ibm.mq.jms.MQConnectionFactory;
import com.ibm.mq.jms.MQQueueConnectionFactory;

public class AbstractMqJmsConnectionConfig {

 private static final Logger LOG = LoggerFactory.getLogger(AbstractMqJmsConnectionConfig.class);

 private final ConfigurableConversionService conversionService = new DefaultConversionService();

 protected ConnectionFactory createQueueConnectionFactory(Properties properties) throws JMSException {
  MQQueueConnectionFactory connectionFactory = new MQQueueConnectionFactory();

  setConnectionFactoryProperties(connectionFactory, properties);

  return connectionFactory;
 }

 private void setConnectionFactoryProperties(MQConnectionFactory connectionFactory, Properties properties)
   throws JMSException {
    
  connectionFactory.setTransportType(conversionService.convert(properties.getProperty("jms.transportType"), Integer.class));
  connectionFactory.setHostName(properties.getProperty("jms.hostName"));
  connectionFactory.setChannel(properties.getProperty("jms.channel"));
  connectionFactory.setPort(conversionService.convert(properties.getProperty("jms.port"), Integer.class));
  connectionFactory.setQueueManager(properties.getProperty("jms.queueManager"));
  connectionFactory.setClientID(properties.getProperty("jms.clientid"));
  
  if (conversionService.convert(properties.getProperty("jms.sslEnabled"), Boolean.class)) {
   setSSLSystemProperties(properties);
   connectionFactory.setSSLCipherSuite(properties.getProperty("jms.sslCipherSuite"));
  }
 }

 private void setSSLSystemProperties(Properties properties) {
  String sslkeystoreFullPath = properties.getProperty("jms.ssl.keystore.path");
  LOG.info("Setting sslkeystoreFullPath : {}", sslkeystoreFullPath);
  System.setProperty("javax.net.ssl.keyStore", sslkeystoreFullPath);
  System.setProperty("javax.net.ssl.keyStorePassword", properties.getProperty("jms.ssl.password"));
 }

}

Note:  The  ConfigurableConversionService  utility class from spring is handy to convert string property values to relevant data types like Integer, Boolean, etc.

Step 4: Define the concrete class that loads the internalConnection.properties and has the Spring @Configuration annotation for the Spring dependency injection.

package com.myapp.jms;

import java.io.IOException;
import java.util.Properties;

import javax.jms.ConnectionFactory;
import javax.jms.JMSException;

import org.springframework.beans.factory.config.PropertiesFactoryBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.ClassPathResource;

@Configuration
public class InternalJmsConnectionFactoryConfig extends AbstractMqJmsConnectionConfig {
 
 
 @Bean (name="internalJmsConnectionFactory")
 protected ConnectionFactory createQueueConnectionFactory() throws JMSException, IOException {
  return createQueueConnectionFactory(internalUMJMSProperties());
 }
 

 private Properties internalJMSProperties() throws IOException {
  PropertiesFactoryBean factory = new PropertiesFactoryBean();
  factory.setLocation(new ClassPathResource("jms/internalConnection.properties"));
  factory.afterPropertiesSet();
  return factory.getObject();
 }
}


More on JMS

Labels: ,

Feb 13, 2013

JMS versus AMQP, Enterprise Integration Patterns (EIP), and Spring Integration versus Apache Camel

Q. Why do you need AMQP when there is JMS?
A. AMQP stands for Advanced Message Queuing Protocol, and was developed to address the problem of interoperability by creating a standard for how messages should be structured and transmitted between platforms the same way as SMTP, HTTP, FTP, etc. have created interoperable systems. This standard binary wire level protocol for messaging would therefore allow hetrogeneous disparate systems between and within companies to exchange messages regrdless of the message broker vendor or platform. 


RabbitMQ, Apache Qpid, StormMQ, etc are open source message broker softwares (i.e. MOM - message-oriented middlewares) that implements the Advanced Message Queuing Protocol (AMQP). 

Q. How does AMQP differ from JMS?
A. JMS is a standard messaging API for the Java platform. It provides a level of abstraction that frees developers from having to worry about specific implementation and wire protocols. This is similar to the JDBC API that allows you to easily switch databases. With JMS, you can switch from one JMS complian message broker (e.g. Web Methods) with another one (e.g. MQSeries or WebspehreMQ) with little or no changes to your source code. It also provides interoperability between other JVM based languages like Scala and Groovy. Altough JMS brokers can be used in .NET applications,  the whole JMS specification does not guarantee interoperability, and integration between Java to .NET  or Java to Ruby, is proprietary and can be quite tricky. In scenarios where you want to send a message from a Java based message producer to a .NET based message consumer, then you need a message based cross platform interoperability that is what AMQP does. With AMQP, you can use any AMQP compliant client library, and AMQP compliant message broker.


Q. What are the different alternatives to integrate various enterprise systems?
A.

Alternative 1: Custom Solution. Implement an individual solution that works for your problem without separating problems into little pieces. For example, use Apache CXF for Web services, overnight batch job runs to load data feeds, JMS for messaging, etc. This is more suited for small use cases. This has higher maintainability and developer effort. The developer has to handle errors, service retries, transactional management, etc. This is suited if you want to integrate one or two applications using one or two protocols. 


Alternative 2: Using an (opensource) integration framework like Spring Integration or Apache Camel. This helps you integrate systems in a standardised way adhering to the enterprise integration patterns (EIP). Apache Camel is a light weight integration framework that allows you to use HTTP, FTP, JMS, EJB, JPA, RMI, JMS, JMX, LDAP, and Netty to name a few. You use the same concept to integrate various protocols in Apache Camel. This increases maintainability and reduces developer effort. This is more suited  if you want to integrate several applications with different protocols.


Alternative 3: Using an ESB (Enterprise Service Bus) to integrate your applications. For example, Oracle Service Bus, TIBCO ESB, webMethods, etc. Under the hood, the ESB also uses an integration framework and provide more services and management functionalities like monitoring, high availability, clustering, graphical user inteface for routing and configuring, etc. Usually, an ESB is a complex and powerful product with a higher learning curve. Suited for very large integration projects. Projects requiring BPM (Business Process Managemnt) integration and other integrated services like monitoring, clustering, etc.



Q. What is an architecture that enables separate applications to work together, but in a de-coupled fashion such that applications can be easily added or removed without affecting the others?
A. This is achieved via a Message Oriented Middleware (aka a message bus).



Q. How can the caller be sure that exactly one receiver will receive the document or perform the call?
A. Use the point-to-point channel


Q. How can the sender broadcast an event to all interested receivers?
A. Use the publish subscribe channel.

Q. What will the messaging system do with a message it cannot deliver?
A. Put it on the dead letter channel.

Q. How can the sender make sure that a message will be delivered, even if the messaging system fails?
A. Use the "guaranteed delivery" mechanism.


Q. What are the diffrent ways to route messages?
A. EIP (Enterprise Integration Patterns) define different types of rules based routing to solve common enterprise intergration problems. Like GoF design patterns is the EIP allows integration architects and designers to share a common vocabulary.

  1. Content based routing uses XPath predicates to route messages based on the message content.  Content enricher supplements the original message with additional relevant information recieved from the other sources.
  2. Splitter  provides the EIP service engine to split messages into separate parts based on the XPATH expression. Splits a composite message into a series of individual message parts.
  3. Split Aggregator is used to collect and store individual message parts until a complete set of co-related message parts has been recieved. Once all the related parts have been recieved, they are aggregated to form a single message.
  4. Static Recipent List based routing inspects an incoming message, and depending upon the number of recipients mentioned in the list, it can forward the message to all channels associated with the "recipients list".  
  5. A Resquencer is used to get a stream of related but out of sequence messages back into correct order. Because individual messages may follow different routes, some messages are likely to pass through the processing steps sooner than others, resulting in the messages getting out of order. A resequencer usually does not modify the message contents.
  6. A message filter is a processor that eliminates undesired messages based on specific criteria. Filtering is controlled by specifying a predicate in the filter: when the predicate is true, the incoming message is allowed to pass; otherwise, it is blocked. A message filter usually does not modify the message contents.


Q. How would you deal with large message volumes?
A.
  • You can reduce the data volume with the use of "Claim Check" pattern, which allows you to replace message content with a claim check (a unique key), which can be used to retrieve the message content at a later time. The message content will be stored temporarily in a persistent store like a database or file system. This pattern is very useful when message content is very large and not all components require all information.
  • A Content Filter can be used to remove unwanted data elements from a message. It is useful to simplify the structure of the message. Very often, messages are represented as tree structures containing many levels of nested, repeating groups because they are modeled after generic, normalized database structures. Very often, this level of nesting is superfluous and a Content Filter can be used to 'flatten' the hierarchy into a simple list of elements that can be more easily understood and processed by other systems.


Q. How would you go about choosing between Spring Integration and Apache Camel to solve common integration problems?
A. 

Spring Integration provides an extension to the Spring programming model to support the well-known Enterprise Integration Patterns while building on the Spring Framework's existing support for enterprise integrationSpring Integration is more suited, if you already have got a Spring project and need to add some integration stuff to it. It requires almost no additional effort to learn Spring Integration if you know Spring itself. Nevertheless, Spring Integration only offers very rudimenary support for technologies such as AMQP, Spring Application Events, Feeds (e.g, RSS/ATOM), File, FTP, FTPS, SFTP, Gemfire, Groovy, HTTP (REST), TCP/IP, JDBC, JMS, JMX, Mail (IMAP/IDLE/POP3), MongoDB, Redis, RMI, Twitter, Web Services (SOAP), and XMPP. Integrations are implemented by writing a lot of XML based DSL(without a real DSL - Domain Specific Language). Spring Integration can be though of as a catch up game to Apache Camel as JavaEE did a catch up with Spring.

Apache Camel is a powerful open source integration framework based on known Enterprise Integration Patterns with powerful support for integration with core Spring. Apache Camel is almost identical to Mule ESB, and offers many components (even more than Spring Integration) for almost every technology you could think of. If there is no component available, you can create your own component very easily starting with a Maven archetype. Camel also supports a Spring based XML configuration as well as a "DSL" for Java, Groovy, and Scala. The benefits of using the Java DSL is that your IDE can auto complete your code as you start typing, rather than having to mess around with buckets of XML. The Java DSL is also very expressive as you can mix and match your own code within the language for Expression or Predicate evaluations. So, it has better readability and there are commercial tools like "Fuse IDE" for generating XML based DSL code.

Mule ESB is another choice and as the name suggests, it is an ESB including additional bells and whistles. This can be compared to "Apache ServiceMix", which is an extension to Apache Camel. Mule also only offers XML based DSL. The Mule Studio is a visual designer. Mule does provide proprietary connector support for systems like SAP, Tibco Rendevous, PayPal, Sibel CRM, IBM's CICS, etc.

So, the decision is not clear cut and it depends on your needs.



Labels: ,