-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refs #410: pull out annotations to own package
- Loading branch information
Jaiden Ashmore
authored and
Jaiden Ashmore
committed
Oct 6, 2024
1 parent
5630a7a
commit 4bd7ea0
Showing
110 changed files
with
1,322 additions
and
1,273 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
# Java Dynamic SQS Listener Annotations | ||
|
||
Wrapper around the core library that allows for setting up using annotations to simplify the usage. | ||
ore message listener. | ||
|
||
## More Information | ||
|
||
For more information you can look at the root project [README.md](../README.md) which provides more information about the architecture | ||
of the application. The [API](../api) is also a good location to find more information about what each part of the framework is how | ||
they interact with each other. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
|
||
description = "Contains a way to attach message listeners via annotations" | ||
|
||
dependencies { | ||
api(project(":java-dynamic-sqs-listener-core")) | ||
implementation(project(":common-utils")) | ||
implementation(project(":annotation-utils")) | ||
compileOnly(project(":documentation-annotations")) | ||
|
||
testImplementation(project(":elasticmq-sqs-client")) | ||
} |
131 changes: 131 additions & 0 deletions
131
...ava/com/jashmore/sqs/annotations/container/AnnotationMessageListenerContainerFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,131 @@ | ||
package com.jashmore.sqs.annotations.container; | ||
|
||
import com.jashmore.sqs.QueueProperties; | ||
import com.jashmore.sqs.argument.ArgumentResolverService; | ||
import com.jashmore.sqs.client.QueueResolver; | ||
import com.jashmore.sqs.client.SqsAsyncClientProvider; | ||
import com.jashmore.sqs.container.MessageListenerContainer; | ||
import com.jashmore.sqs.container.MessageListenerContainerFactory; | ||
import com.jashmore.sqs.container.MessageListenerContainerInitialisationException; | ||
import com.jashmore.sqs.processor.CoreMessageProcessor; | ||
import com.jashmore.sqs.processor.DecoratingMessageProcessorFactory; | ||
import com.jashmore.sqs.processor.MessageProcessor; | ||
import com.jashmore.sqs.util.annotation.AnnotationUtils; | ||
import com.jashmore.sqs.util.identifier.IdentifierUtils; | ||
import com.jashmore.sqs.util.string.StringUtils; | ||
import lombok.Builder; | ||
import org.immutables.value.Value; | ||
import software.amazon.awssdk.services.sqs.SqsAsyncClient; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.Method; | ||
import java.util.Optional; | ||
import java.util.function.Function; | ||
import java.util.function.Supplier; | ||
|
||
/** | ||
* {@link MessageListenerContainerFactory} that can be used to build against an annotated method | ||
* @param <A> | ||
*/ | ||
public class AnnotationMessageListenerContainerFactory<A extends Annotation> implements MessageListenerContainerFactory { | ||
private final Class<A> annotationClass; | ||
private final Function<A, String> identifierMapper; | ||
private final Function<A, String> sqsClientIdentifier; | ||
private final Function<A, String> queueNameOrUrlMapper; | ||
private final QueueResolver queueResolver; | ||
private final SqsAsyncClientProvider sqsAsyncClientProvider; | ||
private final DecoratingMessageProcessorFactory decoratingMessageProcessorFactory; | ||
private final ArgumentResolverService argumentResolverService; | ||
private final Function<AnnotationDetails<A>, MessageListenerContainer> containerFactory; | ||
|
||
/** | ||
* Constructor. | ||
* | ||
* @param annotationClass the class instance of the annotation | ||
* @param identifierMapper to convert an annotation to the identifier of the listener | ||
* @param sqsClientIdentifierMapper to convert an annotation to the SQS Client identifier | ||
* @param queueNameOrUrlMapper to convert an annotation to the Queue URL or name | ||
* @param queueResolver to resolve queue names to a URL | ||
* @param sqsAsyncClientProvider the method for obtaining a SQS client from the identifier | ||
* @param decoratingMessageProcessorFactory to wrap the message processing with any decorators | ||
* @param argumentResolverService to map the parameters of the method to values in the message | ||
* @param containerFactory converts details about the annotation to the final {@link MessageListenerContainer} | ||
*/ | ||
public AnnotationMessageListenerContainerFactory(final Class<A> annotationClass, | ||
final Function<A, String> identifierMapper, | ||
final Function<A, String> sqsClientIdentifierMapper, | ||
final Function<A, String> queueNameOrUrlMapper, | ||
final QueueResolver queueResolver, | ||
final SqsAsyncClientProvider sqsAsyncClientProvider, | ||
final DecoratingMessageProcessorFactory decoratingMessageProcessorFactory, | ||
final ArgumentResolverService argumentResolverService, | ||
final Function<AnnotationDetails<A>, MessageListenerContainer> containerFactory) { | ||
this.annotationClass = annotationClass; | ||
this.identifierMapper = identifierMapper; | ||
this.sqsClientIdentifier = sqsClientIdentifierMapper; | ||
this.queueNameOrUrlMapper = queueNameOrUrlMapper; | ||
this.queueResolver = queueResolver; | ||
this.sqsAsyncClientProvider = sqsAsyncClientProvider; | ||
this.decoratingMessageProcessorFactory = decoratingMessageProcessorFactory; | ||
this.argumentResolverService = argumentResolverService; | ||
this.containerFactory = containerFactory; | ||
} | ||
|
||
@Override | ||
public Optional<MessageListenerContainer> buildContainer(final Object bean, final Method method) throws MessageListenerContainerInitialisationException { | ||
return AnnotationUtils | ||
.findMethodAnnotation(method, this.annotationClass) | ||
.map(annotation -> { | ||
final SqsAsyncClient sqsAsyncClient = getSqsAsyncClient(annotation); | ||
final QueueProperties queueProperties = QueueProperties.builder() | ||
.queueUrl(queueResolver.resolveQueueUrl(sqsAsyncClient, queueNameOrUrlMapper.apply(annotation))) | ||
.build(); | ||
final String identifier = IdentifierUtils.buildIdentifierForMethod(identifierMapper.apply(annotation), bean.getClass(), method); | ||
|
||
final Supplier<MessageProcessor> messageProcessorSupplier = () -> | ||
decoratingMessageProcessorFactory.decorateMessageProcessor( | ||
sqsAsyncClient, | ||
identifier, | ||
queueProperties, | ||
bean, | ||
method, | ||
new CoreMessageProcessor(argumentResolverService, queueProperties, sqsAsyncClient, method, bean) | ||
); | ||
|
||
return containerFactory.apply(AnnotationDetails.<A>builder() | ||
.identifier(identifier) | ||
.queueProperties(queueProperties) | ||
.sqsAsyncClient(sqsAsyncClient) | ||
.messageProcessorSupplier(messageProcessorSupplier) | ||
.annotation(annotation) | ||
.build()); | ||
}); | ||
} | ||
|
||
private SqsAsyncClient getSqsAsyncClient(final A annotation) { | ||
final String sqsClient = sqsClientIdentifier.apply(annotation); | ||
|
||
if (!StringUtils.hasText(sqsClient)) { | ||
return sqsAsyncClientProvider | ||
.getDefaultClient() | ||
.orElseThrow(() -> new MessageListenerContainerInitialisationException("Expected the default SQS Client but there is none") | ||
); | ||
} | ||
|
||
return sqsAsyncClientProvider | ||
.getClient(sqsClient) | ||
.orElseThrow(() -> | ||
new MessageListenerContainerInitialisationException("Expected a client with id '" + sqsClient + "' but none were found") | ||
); | ||
} | ||
|
||
@Value | ||
@Builder | ||
public static class AnnotationDetails<A extends Annotation> { | ||
public String identifier; | ||
public SqsAsyncClient sqsAsyncClient; | ||
public QueueProperties queueProperties; | ||
public Supplier<MessageProcessor> messageProcessorSupplier; | ||
public A annotation; | ||
} | ||
} |
58 changes: 58 additions & 0 deletions
58
...m/jashmore/sqs/annotations/core/basic/BasicAnnotationMessageListenerContainerFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,58 @@ | ||
package com.jashmore.sqs.annotations.core.basic; | ||
|
||
import com.jashmore.sqs.annotations.container.AnnotationMessageListenerContainerFactory; | ||
import com.jashmore.sqs.argument.ArgumentResolverService; | ||
import com.jashmore.sqs.client.QueueResolver; | ||
import com.jashmore.sqs.client.SqsAsyncClientProvider; | ||
import com.jashmore.sqs.container.MessageListenerContainer; | ||
import com.jashmore.sqs.container.MessageListenerContainerFactory; | ||
import com.jashmore.sqs.container.MessageListenerContainerInitialisationException; | ||
import com.jashmore.sqs.container.batching.BatchingMessageListenerContainer; | ||
import com.jashmore.sqs.container.batching.BatchingMessageListenerContainerProperties; | ||
import com.jashmore.sqs.processor.DecoratingMessageProcessorFactory; | ||
|
||
import java.lang.reflect.Method; | ||
import java.util.Optional; | ||
|
||
/** | ||
* {@link MessageListenerContainerFactory} that will wrap methods annotated with | ||
* {@link QueueListener @QueueListener} with some predefined implementations of the framework. | ||
*/ | ||
public class BasicAnnotationMessageListenerContainerFactory implements MessageListenerContainerFactory { | ||
|
||
private final AnnotationMessageListenerContainerFactory<QueueListener> delegate; | ||
|
||
public BasicAnnotationMessageListenerContainerFactory( | ||
final ArgumentResolverService argumentResolverService, | ||
final SqsAsyncClientProvider sqsAsyncClientProvider, | ||
final QueueResolver queueResolver, | ||
final QueueListenerParser queueListenerParser, | ||
final DecoratingMessageProcessorFactory decoratingMessageProcessorFactory | ||
) { | ||
this.delegate = new AnnotationMessageListenerContainerFactory<>( | ||
QueueListener.class, | ||
QueueListener::identifier, | ||
QueueListener::sqsClient, | ||
QueueListener::value, | ||
queueResolver, | ||
sqsAsyncClientProvider, | ||
decoratingMessageProcessorFactory, | ||
argumentResolverService, | ||
(details) -> { | ||
final BatchingMessageListenerContainerProperties properties = queueListenerParser.parse(details.annotation); | ||
return new BatchingMessageListenerContainer( | ||
details.identifier, | ||
details.queueProperties, | ||
details.sqsAsyncClient, | ||
details.messageProcessorSupplier, | ||
properties | ||
); | ||
} | ||
); | ||
} | ||
|
||
@Override | ||
public Optional<MessageListenerContainer> buildContainer(final Object bean, final Method method) throws MessageListenerContainerInitialisationException { | ||
return this.delegate.buildContainer(bean, method); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.