Plugin has been created to simplify subscribe/publish pattern of JMS in reactive manner.
To configure plugin do the steps described below:
<dependency>
<groupId>io.github.israiloff</groupId>
<artifactId>broker</artifactId>
<version>VERSION</version>
</dependency>
Where VERSION is the latest version of the Broker plugin. You can check it out in the Package Registry.
- Configure connection parameters in your application.yml.
io:
github:
israiloff:
broker:
url: tcp://localhost:61616/
user: admin
password: admin
exchangeType: TOPIC
- url - the broker's actual address.
- username - username registered in the broker's system.
- password - password of the user discribed above.
- exchangeType - Type of exchange strategy (TOPIC/QUEUE).
Message publishing in reactive manner via this plugin is pretty easy.
First of all, you must inject instance of Publisher interface. Then somewhere of your reactive downstream call the publish(..) method. Pass the topic name, body and headers into it. That's it!
/**
* Dummy class.
*/
@RequiredArgsConstructor
class Dummy {
/**
* Instance injection of {@code Publisher}.
*/
private final Publisher publisher;
/**
* Main action method.
*
* @param data Some dummy data.
* @return Operation end signal.
*/
public Mono<Void> dummy(String data) {
return echo(data)
.flatMap(result -> publisher.publish("dummy-topic", result, this.getHeaders()));
}
/**
* Gets predefined headers.
*
* @return Headers.
*/
public Map<String, Object> getHeaders() {
var map = new HashMap<String, Object>();
map.put("dummy-header", "dummy-value");
return map;
}
/**
* Returns what receives.
*
* @param str Some text data.
* @return Received data.
*/
public Mono<String> echo(String str) {
return Mono.just(str);
}
}
Topic subscription is a bit complexer than message publishing. To subscribe to some topic you must implement the Subscriber interface. You will see that the Subscriber interface has three members. The getTopic() method returns the name of the topic to which you want to subscribe. getMsgClass() method returns the class of the object that you expect in the message's body. And handle(..) method handles an incoming message.
Note that expected message (i.e. TRequestModel) of the Subscriber interface must implement the Serializable interface.
/**
* Dummy subscriber implementation.
*/
public class DummySubscriber implements Subscriber<DummyModel> {
/**
* Gets message body's class.
*
* @return Class of message's body.
*/
@Override
public Class<DummyModel> getMsgClass() {
return DummyModel.class;
}
/**
* Gets the topic name.
*
* @return Topic name.
*/
@Override
public String getTopic() {
return "dummy-topic";
}
/**
* Incoming message handler.
*
* @param message Incoming message.
* @return End operation signal.
*/
@Override
public Mono<Void> handle(Message<DummyModel> message) {
System.out.println(message.model());
return Mono.empty();
}
}
/**
* Expected Message's body.
*
* @param str Dummy text data.
*/
public record DummyModel(String str) implements Serializable {
}
To disable the plugin for running your unit tests you must mock up a few components. Moreover, the mocking components must be qualified by their proper bean names. The mocking components will be listed below.
You can mock up above components by using Mockito mocking framework in your test configuration class.
import jakarta.jms.ConnectionFactory;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jms.core.JmsTemplate;
import org.springframework.jms.support.converter.MessageConverter;
import io.github.israiloff.broker.JmsConfig;
import io.github.israiloff.broker.JmsSubPubConfig;
@Configuration
public class TestConfig {
@MockBean(name = JmsConfig.CONNECTION_FACTORY)
public ConnectionFactory getConnectionFactory;
@MockBean(name = JmsConfig.MESSAGE_CONVERTER)
public MessageConverter jacksonJmsMessageConverter;
@MockBean(name = JmsSubPubConfig.JMS_TEMPLATE)
public JmsTemplate jmsTemplate;
}
You must create a bean of implemented Subscribers by yourself (by annotating service with @Service or @Component annotations, or by declaring it in configuration class via @Bean annotation).
The second important thing is to register beans of this plugin by scanning elements via @ComponentScan("io.github.israiloff.broker") or via @SpringBootApplication(scanBasePackages = {"io.github.israiloff.broker"}).