reinhapa / rabbitmq-cdi

Provides a JavaEE Event ←→ RabbitMQ bridge
MIT License
17 stars 11 forks source link
hacktoberfest hacktoberfest2020

= Provides a JavaEE Event <--> RabbitMQ bridge. Patrick Reinhart https://github.com/reinhapa[@reinhapa] :project-name: rabbitmq-cdi :group-name: net.reini :project-full-path: reinhapa/{project-name} :github-branch: master

image:https://img.shields.io/badge/license-MIT-blue.svg["MIT License", link="https://github.com/{project-full-path}/blob/{github-branch}/LICENSE"] image:https://img.shields.io/maven-central/v/{group-name}/{project-name}.svg?label=Maven%20Central["Maven Central", link="https://search.maven.org/search?q=g:%22{group-name}%22%20AND%20a:%22{project-name}%22"] image:https://javadoc.io/badge2/{group-name}/{project-name}/javadoc.svg["javadoc", link="https://javadoc.io/doc/{group-name}/{project-name}"] image:https://img.shields.io/codecov/c/github/{project-full-path}/{github-branch}.svg["Code Coverage", link="https://codecov.io/github/{project-full-path}?branch={github-branch}"] image:https://github.com/{project-full-path}/actions/workflows/gradle.yml/badge.svg["CI", link="https://github.com/{project-full-path}/actions/workflows/gradle.yml"]

Supported Versions:

image:https://img.shields.io/badge/Java-11-blue.svg["Java 11"] image:https://img.shields.io/badge/Java-17-blue.svg["Java 22"]

This project contains all needed classes to bind JavaEE enterprise events to a RabbitMQ exchange for outgoing events. Inbound events can also be bound to the respective queues and will be handed over to all JavaEE event observers.

The RabbitMQ message content is done via JSON serialization of a Java Bean compatible PoJo object and vice versa.

== Usage example

First you need to define event objects using standard Java Bean syntax:

[source,java]

public class EventOne { private boolean enabled;

public boolean isEnabled() { return enabled; }

public void setEnabled(boolean enabled) { this.enabled = enabled; } }

public class EventTwo { private String value;

public String getValue() { return value; }

public void setValue(String value) { this.value = value; } }

As second step you have to define the bindings:

[source,java]

@Dependent public class RabbitBinder extends EventBinder { @Override protected void bindEvents() {

ExchangeDeclaration testExchangeOne = declarerFactory()
.createExchangeDeclaration("test.exchange.one")
  .withExchangeType(BuiltinExchangeType.DIRECT)
  .withAutoDelete(false)
  .withDurable(false); // <1>

QueueDeclaration testQueue = declarerFactory()
.createQueueDeclaration("test.queue")
  .withAutoDelete(false)
  .withDurable(false)
  .withExclusiveAccess(false); // <2>

bind(EventOne.class)
  .toExchange("test.exchange.one");
  .withDeclaration(testExchangeOne) // <3>
bind(EventOne.class)
  .toExchange("test.exchange.two")
  .withRoutingKey("test.key")
  .withEncoder(new MyCustomEncoder()); // <4>

bind(EventTwo.class)
  .toQueue("test.queue");
bind(EventTwo.class)
  .toQueue("test.queue")
  .withDecoder(new MyCustomDecoder())
  .withDeclaration(testQueue)
  .autoAck(); // <5>

} }

<1> Create exchange declaration for exchange with name 'test.exchange.one' and type 'direct' <2> Creates queue declaration for queue with name 'test.queue' <3> Uses an empty routing key for exchange 'test.exchange.one' and adds exchange declaration for this publisher <4> Specifies a custom event encoder <5> Specifies a custom event decoder, enables auto acknowledge and adds queue declaration for this consumer Note to declarations: Created declarations are not automatically declared on broker side. For each consumer/producer own channels exist because of that reason it is necessary to add the declaration needed to a binding via .withDeclaration(..) Only these declarations are applied for this consumer/producer As last step you need to initialize the binder either in a singleton startup bean or servlet after having also configured the connection settings: [source,java] ---- @Singleton @Startup public class BindingInitializer { @Inject private RabbitBinder binder; @PostConstruct public void initialize() { try { binder.configuration() .addHost("somehost.somedomain") // <1> .setUsername("myuser") // <2> .setPassword("mypassword"); // <3> .setSecure(true) // <4> .setConnectTimeout(10000) // <5> .setConnectRetryWaitTime(10000) // <6> .setRequestedConnectionHeartbeatTimeout(3) // <7> .withPrefetchCount(5); //8 binder.initialize(); } catch (IOException e) { LoggerFactory.getLogger(getClass()).error("Unable to initialize", e); } } } ---- <1> Specifies a AMQP host name (there can be added more than one here) <2> Specifies a connection user name <3> Specifies a connection password <4> Enables the transport layer security (TLS) <5> Sets the connect timeout to 10 sec <6> Set the time to wait between connection retries to 10 sec <7> Set the heartbeat timeout to 3 sec (To detect connection problems) <8> Set the prefetch count which configures how many messages are downloaded at once from broker === Alternative connection definition Alternatively the connection can also be configured using a respective URI string: [source,java] ---- @Singleton @Startup public class BindingInitializer { @Inject private RabbitBinder binder; @PostConstruct public void initialize() { try { binder.configuration() .setUri("amqp://user:mysecret@somehost.somedomain/virtualhost"); // <1> binder.initialize(); } catch (IOException e) { LoggerFactory.getLogger(getClass()).error("Unable to initialize", e); } } } ---- <1> Specifies a AMQP connection URI More information about the detailed URI can be found in the https://www.rabbitmq.com/uri-spec.html[RabbitMQ URI specification]. === Multiple server connections In case you have to support two different servers, create a binder implementation for each host and initialize them in one single binding initializer: [source,java] ---- @Singleton @Startup public class BindingInitializer { @Inject private RabbitBinder binderOne; @Inject private RabbitBinder binderTwo; @PostConstruct public void initialize() { try { binderOne.configuration() .addHost("hostOne.somedomain") .setUsername("myuser") .setPassword("mypassword"); binderTwo.configuration() .addHost("hostTwo.somedomain") .setUsername("myuser") .setPassword("mypassword"); binderOne.initialize(); binderTwo.initialize(); } catch (IOException e) { LoggerFactory.getLogger(getClass()).error("Unable to initialize", e); } } } ---- === Usage in a container Now the events can be used within your JavaEE container: [source,java] ---- public class EventDemoBean { @Inject private Event eventOnes; public void submitEvent(boolean enabled) { EventOne eventOne = new EventOne(); eventOne.setEnabled(enabled); eventOnes.fire(eventOne); } public void receiveEvent(@Observes EventTwo eventTwo) { String data = eventTwo.getData(); // do some work } } ---- == Contribute Contributions are always welcome. Use https://google.github.io/styleguide/javaguide.html[Google code style format] for your changes. == License This project is licensed under the https://github.com/{project-full-path}/blob/{github-branch}/LICENSE[MIT license]