Skip to content

Commit 8dcff29

Browse files
authored
Add common container factory interface (#829)
This introduces a common interface for all message listener containers. Prior to this commit, the reader and listener containers had no common abstraction. This is needed to introduce a generic container factory customizer in Spring Boot.
1 parent 0012125 commit 8dcff29

18 files changed

+222
-66
lines changed

spring-pulsar-docs/src/main/antora/modules/ROOT/pages/whats-new.adoc

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,17 @@ When using Spring Boot the `PulsarTopicBuilder` is now a registered bean that is
2424
Therefore, if you are using Spring Boot, you can simply inject the builder where needed.
2525
Otherwise, use one of the `PulsarTopicBuilder` constructors directly.
2626

27+
==== Listener/ReaderContainerFactory
28+
The `PulsarContainerFactory` common interface was introduced to bridge the gap between listener and reader container factories.
29+
As part of this, the following APIs were deprecated, copied, and renamed:
30+
31+
- `ListenerContainerFactory#createListenerContainer` replaced with `ListenerContainerFactory#createRegisteredContainer`
32+
33+
- `ReaderContainerFactory#createReaderContainer(E endpoint)` replaced with `ReaderContainerFactory#createRegisteredContainer`
34+
35+
- `ReaderContainerFactory#createReaderContainer(String... topics)` replaced with `ReaderContainerFactory#createContainer`
36+
37+
2738
=== Breaking Changes
2839

2940
==== PulsarTopic#<init>

spring-pulsar-reactive/src/main/java/org/springframework/pulsar/reactive/config/DefaultReactivePulsarListenerContainerFactory.java

Lines changed: 9 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -139,25 +139,21 @@ public DefaultReactivePulsarMessageListenerContainer<T> createContainerInstance(
139139
return new DefaultReactivePulsarMessageListenerContainer<>(this.getConsumerFactory(), containerProps);
140140
}
141141

142+
@SuppressWarnings("rawtypes")
142143
@Override
143-
public DefaultReactivePulsarMessageListenerContainer<T> createListenerContainer(
144+
public DefaultReactivePulsarMessageListenerContainer<T> createRegisteredContainer(
144145
ReactivePulsarListenerEndpoint<T> endpoint) {
145-
DefaultReactivePulsarMessageListenerContainer<T> instance = createContainerInstance(endpoint);
146-
if (endpoint instanceof AbstractReactivePulsarListenerEndpoint) {
147-
configureEndpoint((AbstractReactivePulsarListenerEndpoint<T>) endpoint);
146+
var instance = createContainerInstance(endpoint);
147+
if (endpoint instanceof AbstractReactivePulsarListenerEndpoint abstractReactiveEndpoint) {
148+
if (abstractReactiveEndpoint.getFluxListener() == null) {
149+
JavaUtils.INSTANCE.acceptIfNotNull(this.fluxListener, abstractReactiveEndpoint::setFluxListener);
150+
}
148151
}
149-
150152
endpoint.setupListenerContainer(instance, this.messageConverter);
151153
initializeContainer(instance, endpoint);
152154
return instance;
153155
}
154156

155-
private void configureEndpoint(AbstractReactivePulsarListenerEndpoint<T> aplEndpoint) {
156-
if (aplEndpoint.getFluxListener() == null) {
157-
JavaUtils.INSTANCE.acceptIfNotNull(this.fluxListener, aplEndpoint::setFluxListener);
158-
}
159-
}
160-
161157
@Override
162158
public DefaultReactivePulsarMessageListenerContainer<T> createContainer(String... topics) {
163159
ReactivePulsarListenerEndpoint<T> endpoint = new ReactivePulsarListenerEndpoint<>() {
@@ -168,7 +164,7 @@ public List<String> getTopics() {
168164
}
169165

170166
};
171-
DefaultReactivePulsarMessageListenerContainer<T> container = createContainerInstance(endpoint);
167+
var container = createContainerInstance(endpoint);
172168
initializeContainer(container, endpoint);
173169
return container;
174170
}

spring-pulsar-reactive/src/test/java/org/springframework/pulsar/reactive/config/DefaultReactivePulsarListenerContainerFactoryTests.java

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@
1818

1919
import static org.assertj.core.api.Assertions.assertThat;
2020
import static org.mockito.Mockito.mock;
21+
import static org.mockito.Mockito.spy;
22+
import static org.mockito.Mockito.verify;
2123
import static org.mockito.Mockito.when;
2224

2325
import org.apache.pulsar.client.api.SubscriptionType;
@@ -32,6 +34,18 @@
3234
*/
3335
class DefaultReactivePulsarListenerContainerFactoryTests {
3436

37+
@SuppressWarnings({ "removal", "unchecked" })
38+
@Test
39+
void deprecatedCreateListenerContainerCallsReplacementApi() {
40+
var containerFactory = spy(new DefaultReactivePulsarListenerContainerFactory<String>(
41+
mock(ReactivePulsarConsumerFactory.class), new ReactivePulsarContainerProperties<>()));
42+
var endpoint = mock(ReactivePulsarListenerEndpoint.class);
43+
when(endpoint.getConcurrency()).thenReturn(1);
44+
var createdContainer = containerFactory.createListenerContainer(endpoint);
45+
assertThat(createdContainer).isNotNull();
46+
verify(containerFactory).createRegisteredContainer(endpoint);
47+
}
48+
3549
@SuppressWarnings("unchecked")
3650
@Nested
3751
class SubscriptionTypeFrom {
@@ -44,7 +58,7 @@ void factoryPropsUsedWhenNotSetOnEndpoint() {
4458
mock(ReactivePulsarConsumerFactory.class), factoryProps);
4559
var endpoint = mock(ReactivePulsarListenerEndpoint.class);
4660
when(endpoint.getConcurrency()).thenReturn(1);
47-
var createdContainer = containerFactory.createListenerContainer(endpoint);
61+
var createdContainer = containerFactory.createRegisteredContainer(endpoint);
4862
assertThat(createdContainer.getContainerProperties().getSubscriptionType())
4963
.isEqualTo(SubscriptionType.Shared);
5064
}
@@ -58,7 +72,7 @@ void endpointTakesPrecedenceOverFactoryProps() {
5872
var endpoint = mock(ReactivePulsarListenerEndpoint.class);
5973
when(endpoint.getConcurrency()).thenReturn(1);
6074
when(endpoint.getSubscriptionType()).thenReturn(SubscriptionType.Failover);
61-
var createdContainer = containerFactory.createListenerContainer(endpoint);
75+
var createdContainer = containerFactory.createRegisteredContainer(endpoint);
6276
assertThat(createdContainer.getContainerProperties().getSubscriptionType())
6377
.isEqualTo(SubscriptionType.Failover);
6478
}
@@ -70,7 +84,7 @@ void defaultUsedWhenNotSetOnEndpointNorFactoryProps() {
7084
mock(ReactivePulsarConsumerFactory.class), factoryProps);
7185
var endpoint = mock(ReactivePulsarListenerEndpoint.class);
7286
when(endpoint.getConcurrency()).thenReturn(1);
73-
var createdContainer = containerFactory.createListenerContainer(endpoint);
87+
var createdContainer = containerFactory.createRegisteredContainer(endpoint);
7488
assertThat(createdContainer.getContainerProperties().getSubscriptionType())
7589
.isEqualTo(SubscriptionType.Exclusive);
7690

@@ -90,7 +104,7 @@ void factoryPropsUsedWhenNotSetOnEndpoint() {
90104
mock(ReactivePulsarConsumerFactory.class), factoryProps);
91105
var endpoint = mock(ReactivePulsarListenerEndpoint.class);
92106
when(endpoint.getConcurrency()).thenReturn(1);
93-
var createdContainer = containerFactory.createListenerContainer(endpoint);
107+
var createdContainer = containerFactory.createRegisteredContainer(endpoint);
94108
assertThat(createdContainer.getContainerProperties().getSubscriptionName())
95109
.isEqualTo("my-factory-subscription");
96110
}
@@ -104,7 +118,7 @@ void endpointTakesPrecedenceOverFactoryProps() {
104118
var endpoint = mock(ReactivePulsarListenerEndpoint.class);
105119
when(endpoint.getConcurrency()).thenReturn(1);
106120
when(endpoint.getSubscriptionName()).thenReturn("my-endpoint-subscription");
107-
var createdContainer = containerFactory.createListenerContainer(endpoint);
121+
var createdContainer = containerFactory.createRegisteredContainer(endpoint);
108122
assertThat(createdContainer.getContainerProperties().getSubscriptionName())
109123
.isEqualTo("my-endpoint-subscription");
110124
}
@@ -117,10 +131,10 @@ void defaultUsedWhenNotSetOnEndpointNorFactoryProps() {
117131
var endpoint = mock(ReactivePulsarListenerEndpoint.class);
118132
when(endpoint.getConcurrency()).thenReturn(1);
119133

120-
var container1 = containerFactory.createListenerContainer(endpoint);
134+
var container1 = containerFactory.createRegisteredContainer(endpoint);
121135
assertThat(container1.getContainerProperties().getSubscriptionName())
122136
.startsWith("org.springframework.Pulsar.ReactivePulsarListenerEndpointContainer#");
123-
var container2 = containerFactory.createListenerContainer(endpoint);
137+
var container2 = containerFactory.createRegisteredContainer(endpoint);
124138
assertThat(container2.getContainerProperties().getSubscriptionName())
125139
.startsWith("org.springframework.Pulsar.ReactivePulsarListenerEndpointContainer#");
126140
assertThat(container1.getContainerProperties().getSubscriptionName())

spring-pulsar-reactive/src/test/java/org/springframework/pulsar/reactive/listener/ReactivePulsarListenerSpelTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,9 +171,9 @@ class ContainerFactoryAttribute {
171171
@Test
172172
void containerFactoryDerivedFromAttribute(
173173
@Autowired ReactivePulsarListenerContainerFactory<String> containerFactory) {
174-
verify(containerFactory).createListenerContainer(argThat(endpoint -> endpoint.getId().equals("foo")));
175-
verify(containerFactory).createListenerContainer(argThat(endpoint -> endpoint.getId().equals("bar")));
176-
verify(containerFactory).createListenerContainer(argThat(endpoint -> endpoint.getId().equals("zaa")));
174+
verify(containerFactory).createRegisteredContainer(argThat(endpoint -> endpoint.getId().equals("foo")));
175+
verify(containerFactory).createRegisteredContainer(argThat(endpoint -> endpoint.getId().equals("bar")));
176+
verify(containerFactory).createRegisteredContainer(argThat(endpoint -> endpoint.getId().equals("zaa")));
177177
}
178178

179179
@EnablePulsar

spring-pulsar/src/main/java/org/springframework/pulsar/config/AbstractPulsarListenerContainerFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -106,7 +106,7 @@ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEv
106106

107107
@SuppressWarnings("unchecked")
108108
@Override
109-
public C createListenerContainer(PulsarListenerEndpoint endpoint) {
109+
public C createRegisteredContainer(PulsarListenerEndpoint endpoint) {
110110
C instance = createContainerInstance(endpoint);
111111
JavaUtils.INSTANCE.acceptIfNotNull(endpoint.getId(), instance::setBeanName);
112112
if (endpoint instanceof AbstractPulsarListenerEndpoint) {

spring-pulsar/src/main/java/org/springframework/pulsar/config/AbstractPulsarReaderContainerFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 the original author or authors.
2+
* Copyright 2023-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -99,7 +99,7 @@ public void setApplicationEventPublisher(ApplicationEventPublisher applicationEv
9999

100100
@SuppressWarnings("unchecked")
101101
@Override
102-
public C createReaderContainer(PulsarReaderEndpoint<PulsarMessageReaderContainer> endpoint) {
102+
public C createRegisteredContainer(PulsarReaderEndpoint<PulsarMessageReaderContainer> endpoint) {
103103
C instance = createContainerInstance(endpoint);
104104
JavaUtils.INSTANCE.acceptIfNotNull(endpoint.getId(), instance::setBeanName);
105105
if (endpoint instanceof AbstractPulsarReaderEndpoint) {

spring-pulsar/src/main/java/org/springframework/pulsar/config/DefaultPulsarReaderContainerFactory.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 the original author or authors.
2+
* Copyright 2023-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -56,7 +56,7 @@ protected void initializeContainer(DefaultPulsarMessageReaderContainer<T> instan
5656
}
5757

5858
@Override
59-
public DefaultPulsarMessageReaderContainer<T> createReaderContainer(String... topics) {
59+
public DefaultPulsarMessageReaderContainer<T> createContainer(String... topics) {
6060
// TODO
6161
return null;
6262
}

spring-pulsar/src/main/java/org/springframework/pulsar/config/GenericListenerEndpointRegistry.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -138,7 +138,7 @@ public void registerListenerContainer(E endpoint, ListenerContainerFactory<? ext
138138

139139
protected C createListenerContainer(E endpoint, ListenerContainerFactory<? extends C, E> factory) {
140140

141-
C listenerContainer = factory.createListenerContainer(endpoint);
141+
C listenerContainer = factory.createRegisteredContainer(endpoint);
142142

143143
if (listenerContainer instanceof InitializingBean) {
144144
try {

spring-pulsar/src/main/java/org/springframework/pulsar/config/GenericReaderEndpointRegistry.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2023 the original author or authors.
2+
* Copyright 2023-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -136,7 +136,7 @@ public void registerReaderContainer(E endpoint, ReaderContainerFactory<? extends
136136
}
137137

138138
protected C createReaderContainer(E endpoint, ReaderContainerFactory<? extends C, E> factory) {
139-
C readerContainer = factory.createReaderContainer(endpoint);
139+
C readerContainer = factory.createRegisteredContainer(endpoint);
140140
if (readerContainer instanceof InitializingBean) {
141141
try {
142142
((InitializingBean) readerContainer).afterPropertiesSet();
Lines changed: 10 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022-2023 the original author or authors.
2+
* Copyright 2022-2024 the original author or authors.
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -16,7 +16,6 @@
1616

1717
package org.springframework.pulsar.config;
1818

19-
import org.springframework.pulsar.annotation.PulsarListener;
2019
import org.springframework.pulsar.listener.MessageListenerContainer;
2120

2221
/**
@@ -26,24 +25,22 @@
2625
* @param <E> listener endpoint type.
2726
* @author Soby Chacko
2827
* @author Christophe Bornet
28+
* @author Chris Bono
2929
*/
30-
public interface ListenerContainerFactory<C extends MessageListenerContainer, E extends ListenerEndpoint<C>> {
30+
public interface ListenerContainerFactory<C extends MessageListenerContainer, E extends ListenerEndpoint<C>>
31+
extends PulsarContainerFactory<C, E> {
3132

3233
/**
3334
* Create a {@link MessageListenerContainer} for the given {@link ListenerEndpoint}.
3435
* Containers created using this method are added to the listener endpoint registry.
3536
* @param endpoint the endpoint to configure
3637
* @return the created container
38+
* @deprecated since 1.2.0 for removal in 1.4.0 in favor of
39+
* {@link PulsarContainerFactory#createRegisteredContainer}
3740
*/
38-
C createListenerContainer(E endpoint);
39-
40-
/**
41-
* Create and configure a container without a listener; used to create containers that
42-
* are not used for {@link PulsarListener} annotations. Containers created using this
43-
* method are not added to the listener endpoint registry.
44-
* @param topics the topics.
45-
* @return the container.
46-
*/
47-
C createContainer(String... topics);
41+
@Deprecated(since = "1.2.0", forRemoval = true)
42+
default C createListenerContainer(E endpoint) {
43+
return createRegisteredContainer(endpoint);
44+
}
4845

4946
}

0 commit comments

Comments
 (0)