Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import org.reactivecommons.async.commons.communications.Message;
import reactor.core.publisher.Mono;

@FunctionalInterface
public interface DiscardNotifier {
Mono<Void> notifyDiscard(Message message);
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import java.util.Set;

@FunctionalInterface
public interface Matcher {
String match(Set<String> sources, String target);
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,9 +44,9 @@ class UnroutableMessageNotifierTest {

@BeforeEach
void setUp() {
// Usar el constructor por defecto y espiar el sink interno
// Use the default constructor and spy on the internal sink
unroutableMessageNotifier = new UnroutableMessageNotifier();
// Inyectar el mock del sink usando un spy para poder verificarlo
// Inject the sink mock using a spy to verify it
try {
java.lang.reflect.Field sinkField = UnroutableMessageNotifier.class.getDeclaredField("sink");
sinkField.setAccessible(true);
Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ buildscript {
plugins {
id 'jacoco'
id 'org.sonarqube' version '6.3.1.5724'
id 'org.springframework.boot' version '3.5.5' apply false
id 'org.springframework.boot' version '3.5.6' apply false
id 'io.github.gradle-nexus.publish-plugin' version '2.0.0'
id 'co.com.bancolombia.cleanArchitecture' version '3.25.0'
id 'co.com.bancolombia.cleanArchitecture' version '3.26.1'
}

repositories {
Expand Down
229 changes: 229 additions & 0 deletions docs/docs/migration-guides.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
---
sidebar_position: 4
---

# Migration

## From 5.x.x to 6.x.x

### New Features

- **Connection customization:** You can now customize the RabbitMQ connection by defining a
`ConnectionFactoryCustomizer` bean. For more details,
see [Customizing the connection](/reactive-commons-java/docs/reactive-commons/configuration_properties/rabbitmq#customizing-the-connection).

```java title="Programmatic configuration"

@Bean
public ConnectionFactoryCustomizer connectionFactoryCustomizer() {
return (ConnectionFactoryCustomizer) (asyncProps, connectionFactory) -> {
connectionFactory.setExceptionHandler(new MyCustomExceptionHandler()); // Optional custom exception handler
connectionFactory.setCredentialsProvider(new MyCustomCredentialsProvider()); // Optional custom credentials provider
return connectionFactory;
};
}
```

### Change notes

- The configuration property `listenReplies` for RabbitMQ now defaults to `null`. Previously, it was `true`, causing all
applications to subscribe to a reply queue even when not needed.
- The domain `app` is now **required**. If not defined, the application will fail to start.

### Actions

- If your application uses the ReqReply pattern, you must explicitly set `app.async.app.listenReplies` to `true`.
Otherwise, it should be `false` to avoid unnecessary resource usage:

```yaml title="application.yaml"
app:
async:
app:
listenReplies: true # set to true if ReqReply is required, false if not
```

```java title="Programmatic configuration"
@Configuration
public class MyDomainConfig {

@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
// Additional connection configuration goes here...
return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder()
.connectionProperties(propertiesApp)
.listenReplies(Boolean.TRUE) // set to true if ReqReply is required, false if not
.build())
.build();
}
}
```

---

- The domain `app` must be defined in your configuration. Otherwise, the application will throw an exception at startup:

```yaml title="application.yaml"
app:
async:
app: # Configure the 'app' domain
# domain configuration goes here
```

```java title="Programmatic configuration"
@Configuration
public class MyDomainConfig {

@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
// Additional connection configuration goes here...
return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder() // Configure the 'app' domain
.connectionProperties(propertiesApp)
.build())
.build();
}
}
```

## From 4.x.x to 5.x.x

### New Features

- **Support for multiple brokers:** It is now possible to configure and connect to up to two brokers simultaneously,
using
independent domains in the configuration.

### Change notes

- Configuration properties are now defined per domain, allowing each to have its own properties and connection
settings.
- The broker connection is no longer manually defined in the code. It is now automatically managed based on the
configuration declared in the `application.yaml` file or through programmatic configuration.

### Actions

- The `app` domain needs to be defined to specify the configuration properties.

Before:

```yaml title="application.yaml"
app:
async:
withDLQRetry: true
maxRetries: 1
retryDelay: 1000
```

Now:

```yaml title="application.yaml"
app:
async:
app: # this is the name of the default domain
withDLQRetry: true
maxRetries: 1
retryDelay: 1000
```

- Migrate the connection configuration:

Before: the connection was defined manually in a Java class, as shown below:

```java
@Log4j2
@Configuration
@RequiredArgsConstructor
public class MyDomainConfig {

private final RabbitMQConnectionProperties properties;
private static final String TLS = "TLSv1.2";
private static final String FAIL_MSG = "Error creating ConnectionFactoryProvider in enroll";

@Primary
@Bean
public ConnectionFactoryProvider getConnectionFactoryProvider() {
final var factory = new ConnectionFactory();
var map = PropertyMapper.get();
map.from(properties::hostname).whenNonNull().to(factory::setHost);
map.from(properties::port).to(factory::setPort);
map.from(properties::username).whenNonNull().to(factory::setUsername);
map.from(properties::password).whenNonNull().to(factory::setPassword);
map.from(properties::ssl).whenTrue().as(isSsl -> factory).to(this::configureSsl);
return () -> factory;
}

private void configureSsl(ConnectionFactory factory) {
try {
var sslContext = SSLContext.getInstance(TLS);
var trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustManagerFactory.init((KeyStore) null);
sslContext.init(null, trustManagerFactory.getTrustManagers(), null);
factory.useSslProtocol(sslContext);
} catch (KeyManagementException | KeyStoreException | NoSuchAlgorithmException e) {
log.error("{}: {}", FAIL_MSG, e);
}
}
}
```

Now: the connection is configured directly in the `application.yaml` file per domain:

```yaml title="application.yaml"
app:
async:
app: # this is the name of the default domain
connectionProperties: # you can override the connection properties of each domain
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /
# Another domain can be configured with same properties structure that app
accounts: # this is a second domain name and can have another independent setup
connectionProperties: # you can override the connection properties of each domain
host: localhost
port: 5672
username: guest
password: guest
virtual-host: /accounts
```

Domains can also be configured programmatically:

```java title="Programmatic configuration"
@Configuration
public class MyDomainConfig {

@Bean
@Primary
public AsyncRabbitPropsDomainProperties customDomainProperties() {
RabbitProperties propertiesApp = new RabbitProperties();
propertiesApp.setHost("localhost");
propertiesApp.setPort(5672);
propertiesApp.setVirtualHost("/");
propertiesApp.setUsername("guest");
propertiesApp.setPassword("guest");

RabbitProperties propertiesAccounts = new RabbitProperties();
propertiesAccounts.setHost("localhost");
propertiesAccounts.setPort(5672);
propertiesAccounts.setVirtualHost("/accounts");
propertiesAccounts.setUsername("guest");
propertiesAccounts.setPassword("guest");

return AsyncRabbitPropsDomainProperties.builder()
.withDomain("app", AsyncProps.builder()
.connectionProperties(propertiesApp)
.build())
.withDomain("accounts", AsyncProps.builder()
.connectionProperties(propertiesAccounts)
.build())
.build();
}
}
```
7 changes: 4 additions & 3 deletions docs/docs/reactive-commons/1-getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Commons.

You need Java JRE installed (Java 17 or later).

You also need to install RabbitMQ. Follow the [instructions from the website](https://www.rabbitmq.com/download.html)
You also need to install RabbitMQ. Follow the [instructions from the website](https://www.rabbitmq.com/download.html).

## Start RabbitMQ

Expand Down Expand Up @@ -50,15 +50,16 @@ dependencies {
}
```

Note: If you will use Cloud Events, you should include the Cloud Events dependency:
:::tip
If you will use Cloud Events, you should include the Cloud Events dependency:

```groovy
dependencies {
implementation 'io.cloudevents:cloudevents-json-jackson:4.0.1'
}
```

```groovy
:::

### Configuration properties

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reactive-commons/3-sending-a-command.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
sidebar_position: 2
sidebar_position: 3
---

# Sending a Command
Expand Down
3 changes: 2 additions & 1 deletion docs/docs/reactive-commons/_category_.json
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
{
"label": "Reactive Commons",
"position": 2,
"collapsed": false,
"link": {
"type": "generated-index",
"description": "Learn how to build reactive systems using the Reactive Commons library."
}
}
}
Loading