I am looking for spring module that can help me to integrate spring REST web services with message bus(RabbitMQ). REST web service are acting as a consumer of AMQP messages from the client. Whenever messages are sent over the bus it is an AMQP message and to make it work with REST, it has to be converted in to REST call. Is anyone aware of the existing solution to make it work?
I personally don't see the value in this i.e. using a synchronous REST interface to consume some a-synchonous AMQP messages as you are kind of losing the purpose / advantages of an a-synchonous message system like RabbitMQ.
The great thing about AMQP is that it's a wire protocol and not tied to one language (e.g. JMS is pretty much tied to Java). This means you could use Java / Spring / AMQP library, Node.JS / AMQP library, C# / AMQP library etc. This article explains the advantages better than me http://www.wmrichards.com/amqp.pdf My point is, if you're looking for REST to create a bridge between another language / system etc to RabbitMQ then I would first of all investigate if the other language / system supports an AMQP library.
However, if you MUST have a REST'ful interface you could create a simple controller using SpringMVC and inject a private AmqpTemplate amqpTemplate;
with some methods. This effectively creates your REST-to-AMQP bridge / proxy. The spring configuration / Java Controller is as follows (note this has been tested and works): -
/spring/restAmqpContext.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:rabbit="http://www.springframework.org/schema/rabbit"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.1.xsd
http://www.springframework.org/schema/rabbit http://www.springframework.org/schema/rabbit/spring-rabbit.xsd">
<!-- Location of "config.properties" to override RabbitMQ connection details if required. -->
<context:property-placeholder ignore-resource-not-found="true"
location="classpath:/config.properties,
${DATA_HOME:}/config.properties" />
<bean class="com.bobmarks.controller.RestAmqpController">
<property name="amqpTemplate" ref="amqpTemplate"/>
</bean>
<mvc:default-servlet-handler />
<mvc:annotation-driven/>
<rabbit:connection-factory id="amqpConnectionFactory"
host="${rabbitmq.host:localhost}"
port="${rabbitmq.port:5672}"
username="${rabbitmq.username:guest}"
password="${rabbitmq.password:guest}"
publisher-confirms="${rabbitmq.publisher.confirms:true}"
publisher-returns="${rabbitmq.publisher.returns:true}" />
<rabbit:template id="amqpTemplate" connection-factory="amqpConnectionFactory" mandatory="true" />
<rabbit:admin id="rabbitAdmin" connection-factory="amqpConnectionFactory" />
<rabbit:queue name="my_queue" />
<rabbit:direct-exchange name="my_exchange">
<rabbit:bindings><rabbit:binding queue="my_queue" key="my_binding" /></rabbit:bindings>
</rabbit:direct-exchange>
RestAmqpController.java
package com.bobmarks.controller;
import java.util.Date;
import org.springframework.amqp.AmqpException;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
/**
* Simple Rest To AMQP Controller.
*/
@Controller
@RequestMapping(value = "/rest2amqp")
public class RestAmqpController {
private AmqpTemplate amqpTemplate;
public RestAmqpController() {}
public void setAmqpTemplate(AmqpTemplate amqpTemplate) {
this.amqpTemplate = amqpTemplate;
}
@RequestMapping(method = RequestMethod.GET)
public ResponseEntity<String> message(@RequestParam(value = "message") String message) {
try {
amqpTemplate.convertAndSend("my_exchange", "my_binding", message);
return new ResponseEntity<String>("Message sent to AMQP queue at: " + new Date(), HttpStatus.OK);
}
catch (AmqpException amqpEx) {
return new ResponseEntity<String>(amqpEx.getMessage(), HttpStatus.BAD_REQUEST);
}
}
}
These are packaged up in the usual way (Tomcat / Spring Boot / etc) and for example if the project is called data the REST endpoint to send a message would be as follows: -
http://localhost/data/rest2amqp?message=Hello_World
This is probably better shown with screenshots.
Screenshot of submitting message (just using FireFox)
Screenshot of RabbitMQ Admin Client showing message arrived
Screenshot of actual message
NOTE: This is a very basic example with a single RabbitMQ exchange / queue and doesn't contain security or any of the other basic stuff you would probably want!