Skip to content

Commit

Permalink
Feat/create bindings (#727)
Browse files Browse the repository at this point in the history
* feat: add jms bindings artifact

* feat: add amqp bindings artifact

* feat: add kafka bindings artifact

* chore: update bindings dependencies

* docs: update README.md bindings
  • Loading branch information
timonback committed May 3, 2024
1 parent e277e3a commit b4b293b
Show file tree
Hide file tree
Showing 28 changed files with 803 additions and 2 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/springwolf-bindings.yml
Expand Up @@ -16,7 +16,7 @@ jobs:
strategy:
fail-fast: false
matrix:
binding: [ "googlepubsub", "sns", "sqs" ]
binding: [ "amqp", "googlepubsub", "jms", "kafka", "sns", "sqs" ]

env:
binding: springwolf-bindings/springwolf-${{ matrix.binding }}-binding
Expand Down
3 changes: 3 additions & 0 deletions README.md
Expand Up @@ -85,9 +85,12 @@ More details in the documentation.

| Bindings | Current version | SNAPSHOT version |
|----------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [AMQP Binding](https://github.com/springwolf/springwolf-core/tree/master/springwolf-bindings/springwolf-amqp-binding) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-amqp-binding?color=green&label=springwolf-amqp-binding&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-amqp-binding?label=springwolf-amqp-binding&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
| [AWS SNS Binding](https://github.com/springwolf/springwolf-core/tree/master/springwolf-bindings/springwolf-sns-binding) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-sns-binding?color=green&label=springwolf-sns-binding&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-sns-binding?label=springwolf-sns-binding&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
| [AWS SQS Binding](https://github.com/springwolf/springwolf-core/tree/master/springwolf-bindings/springwolf-sqs-binding) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-sqs-binding?color=green&label=springwolf-sqs-binding&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-sqs-binding?label=springwolf-sqs-binding&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
| [Google PubSub Binding](https://github.com/springwolf/springwolf-core/tree/master/springwolf-bindings/springwolf-googlepubsub-binding) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-googlepubsub-binding?color=green&label=springwolf-googlepubsub-binding&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-googlepubsub-binding?label=springwolf-googlepubsub-binding&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
| [Kafka Binding](https://github.com/springwolf/springwolf-core/tree/master/springwolf-bindings/springwolf-kafka-binding) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-kafka-binding?color=green&label=springwolf-kafka-binding&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-kafka-binding?label=springwolf-kafka-binding&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
| [JMS Binding](https://github.com/springwolf/springwolf-core/tree/master/springwolf-bindings/springwolf-jms-binding) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-jms-binding?color=green&label=springwolf-jms-binding&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-jms-binding?label=springwolf-jms-binding&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |

| Add-on | Current version | SNAPSHOT version |
|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
Expand Down
3 changes: 3 additions & 0 deletions build.gradle
Expand Up @@ -137,7 +137,10 @@ allprojects {
'springwolf-kotlinx-serialization-model-converter'
]
var bindings = [
'springwolf-amqp-binding',
'springwolf-googlepubsub-binding',
'springwolf-jms-binding',
'springwolf-kafka-binding',
'springwolf-sns-binding',
'springwolf-sqs-binding'
]
Expand Down
5 changes: 4 additions & 1 deletion settings.gradle
Expand Up @@ -15,9 +15,12 @@ include(
'springwolf-examples:springwolf-kafka-example',
'springwolf-examples:springwolf-sns-example',
'springwolf-examples:springwolf-sqs-example',
'springwolf-bindings:springwolf-amqp-binding',
'springwolf-bindings:springwolf-googlepubsub-binding',
'springwolf-bindings:springwolf-jms-binding',
'springwolf-bindings:springwolf-kafka-binding',
'springwolf-bindings:springwolf-sns-binding',
'springwolf-bindings:springwolf-sqs-binding',
'springwolf-bindings:springwolf-googlepubsub-binding',
'springwolf-ui',
'springwolf-add-ons:springwolf-common-model-converters',
'springwolf-add-ons:springwolf-generic-binding',
Expand Down
43 changes: 43 additions & 0 deletions springwolf-bindings/springwolf-amqp-binding/build.gradle
@@ -0,0 +1,43 @@
plugins {
id 'java-library'

id 'org.springframework.boot'
id 'io.spring.dependency-management'
id 'ca.cutterslade.analyze'
}

dependencies {
api project(":springwolf-asyncapi")
api project(":springwolf-core")

implementation "org.springframework:spring-context"
implementation "org.springframework:spring-core"
implementation "org.springframework.boot:spring-boot-autoconfigure"

testImplementation "org.assertj:assertj-core:${assertjCoreVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"

testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
}

jar {
enabled = true
archiveClassifier = ''
}
bootJar.enabled = false

java {
withJavadocJar()
withSourcesJar()
}

publishing {
publications {
mavenJava(MavenPublication) {
pom {
name = 'springwolf-amqp-binding'
description = 'Automated JSON API documentation for AMQP Bindings'
}
}
}
}
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.amqp.annotations;

import io.github.springwolf.core.asyncapi.annotations.AsyncListener;
import io.github.springwolf.core.asyncapi.annotations.AsyncOperationBinding;
import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher;

import java.lang.annotation.ElementType;
import java.lang.annotation.Inherited;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* {@code @AmqpAsyncOperationBinding} is a method-level annotation used in combination with {@link AsyncPublisher} or {@link AsyncListener}.
* It configures the operation binding for the AMQP protocol.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@AsyncOperationBinding
@Inherited
public @interface AmqpAsyncOperationBinding {

int expiration() default 0;

String[] cc() default {};

int priority() default 0;

int deliveryMode() default 1;

boolean mandatory() default false;

boolean timestamp() default false;

boolean ack() default false;
}
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.amqp.configuration;

import io.github.springwolf.bindings.amqp.scanners.messages.AmqpMessageBindingProcessor;
import io.github.springwolf.bindings.amqp.scanners.operations.AmqpOperationBindingProcessor;
import io.github.springwolf.core.asyncapi.scanners.bindings.BindingProcessorPriority;
import io.github.springwolf.core.configuration.properties.SpringwolfConfigConstants;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Bean;
import org.springframework.core.annotation.Order;

/**
* Autoconfiguration for the springwolf Amqp Binding.
*/
@AutoConfiguration
@ConditionalOnProperty(name = SpringwolfConfigConstants.SPRINGWOLF_ENABLED, havingValue = "true", matchIfMissing = true)
public class SpringwolfAmqpBindingAutoConfiguration {

@Bean
@Order(value = BindingProcessorPriority.PROTOCOL_BINDING)
@ConditionalOnMissingBean
public AmqpOperationBindingProcessor amqpOperationBindingProcessor() {
return new AmqpOperationBindingProcessor();
}

@Bean
@Order(value = BindingProcessorPriority.PROTOCOL_BINDING)
@ConditionalOnMissingBean
public AmqpMessageBindingProcessor amqpMessageBindingProcessor() {
return new AmqpMessageBindingProcessor();
}
}
@@ -0,0 +1,37 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.amqp.scanners.messages;

import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding;
import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding;
import io.github.springwolf.core.asyncapi.scanners.bindings.messages.MessageBindingProcessor;
import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.util.StringValueResolver;

import java.lang.reflect.AnnotatedElement;
import java.util.Arrays;
import java.util.Optional;

public class AmqpMessageBindingProcessor implements MessageBindingProcessor, EmbeddedValueResolverAware {
private StringValueResolver resolver;

@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.resolver = resolver;
}

@Override
public Optional<ProcessedMessageBinding> process(AnnotatedElement annotatedElement) {
return Arrays.stream(annotatedElement.getAnnotations())
.filter(AmqpAsyncOperationBinding.class::isInstance)
.map(AmqpAsyncOperationBinding.class::cast)
.findAny()
.map(this::mapToMessageBinding);
}

private ProcessedMessageBinding mapToMessageBinding(AmqpAsyncOperationBinding bindingAnnotation) {
AMQPMessageBinding amqpMessageBinding = AMQPMessageBinding.builder().build();

return new ProcessedMessageBinding("amqp", amqpMessageBinding);
}
}
@@ -0,0 +1,28 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.amqp.scanners.operations;

import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding;
import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding;
import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor;
import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding;

import java.util.Arrays;

public class AmqpOperationBindingProcessor extends AbstractOperationBindingProcessor<AmqpAsyncOperationBinding> {
@Override
protected ProcessedOperationBinding mapToOperationBinding(AmqpAsyncOperationBinding bindingAnnotation) {
AMQPOperationBinding amqpOperationBinding = AMQPOperationBinding.builder()
.expiration(bindingAnnotation.expiration())
.cc(Arrays.stream(bindingAnnotation.cc())
.map(this::resolveOrNull)
.toList())
.priority(bindingAnnotation.priority())
.deliveryMode(bindingAnnotation.deliveryMode())
.mandatory(bindingAnnotation.mandatory())
.timestamp(bindingAnnotation.timestamp())
.ack(bindingAnnotation.ack())
.build();

return new ProcessedOperationBinding("amqp", amqpOperationBinding);
}
}
@@ -0,0 +1 @@
io.github.springwolf.bindings.amqp.configuration.SpringwolfAmqpBindingAutoConfiguration
@@ -0,0 +1,40 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.amqp.scanners.messages;

import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPMessageBinding;
import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding;
import io.github.springwolf.core.asyncapi.scanners.bindings.messages.ProcessedMessageBinding;
import org.junit.jupiter.api.Test;

import java.lang.reflect.Method;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThat;

class AmqpMessageBindingProcessorTest {
private final AmqpMessageBindingProcessor processor = new AmqpMessageBindingProcessor();

@Test
void processTest() throws NoSuchMethodException {
Method method = AmqpMessageBindingProcessorTest.class.getMethod("methodWithAnnotation");

ProcessedMessageBinding binding = processor.process(method).get();

assertThat(binding.getType()).isEqualTo("amqp");
assertThat(binding.getBinding()).isEqualTo(new AMQPMessageBinding());
}

@Test
void processWithoutAnnotationTest() throws NoSuchMethodException {
Method method = AmqpMessageBindingProcessorTest.class.getMethod("methodWithoutAnnotation");

Optional<ProcessedMessageBinding> binding = processor.process(method);

assertThat(binding).isNotPresent();
}

@AmqpAsyncOperationBinding
public void methodWithAnnotation() {}

public void methodWithoutAnnotation() {}
}
@@ -0,0 +1,38 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.amqp.scanners.operations;

import io.github.springwolf.asyncapi.v3.bindings.amqp.AMQPOperationBinding;
import io.github.springwolf.bindings.amqp.annotations.AmqpAsyncOperationBinding;
import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding;
import org.junit.jupiter.api.Test;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

class AmqpOperationBindingProcessorTest {
private final AmqpOperationBindingProcessor processor = new AmqpOperationBindingProcessor();

@Test
void mapToOperationBindingTest() throws NoSuchMethodException {
AmqpAsyncOperationBinding annotation = AmqpOperationBindingProcessorTest.class
.getMethod("methodWithAnnotation")
.getAnnotation(AmqpAsyncOperationBinding.class);

ProcessedOperationBinding binding = processor.mapToOperationBinding(annotation);

assertThat(binding.getType()).isEqualTo("amqp");
assertThat(binding.getBinding())
.isEqualTo(AMQPOperationBinding.builder()
.cc(List.of())
.priority(0)
.deliveryMode(1)
.mandatory(false)
.timestamp(false)
.ack(false)
.build());
}

@AmqpAsyncOperationBinding
public void methodWithAnnotation() {}
}
43 changes: 43 additions & 0 deletions springwolf-bindings/springwolf-jms-binding/build.gradle
@@ -0,0 +1,43 @@
plugins {
id 'java-library'

id 'org.springframework.boot'
id 'io.spring.dependency-management'
id 'ca.cutterslade.analyze'
}

dependencies {
api project(":springwolf-asyncapi")
api project(":springwolf-core")

implementation "org.springframework:spring-context"
implementation "org.springframework:spring-core"
implementation "org.springframework.boot:spring-boot-autoconfigure"

testImplementation "org.assertj:assertj-core:${assertjCoreVersion}"
testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}"

testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}"
}

jar {
enabled = true
archiveClassifier = ''
}
bootJar.enabled = false

java {
withJavadocJar()
withSourcesJar()
}

publishing {
publications {
mavenJava(MavenPublication) {
pom {
name = 'springwolf-jms-binding'
description = 'Automated JSON API documentation for JMS Bindings'
}
}
}
}
@@ -0,0 +1,20 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.jms.annotations;

import io.github.springwolf.core.asyncapi.annotations.AsyncListener;
import io.github.springwolf.core.asyncapi.annotations.AsyncOperationBinding;
import io.github.springwolf.core.asyncapi.annotations.AsyncPublisher;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* {@code @JmsAsyncOperationBinding} is a method-level annotation used in combination with {@link AsyncPublisher} or {@link AsyncListener}.
* It configures the operation binding for the JMS protocol.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@AsyncOperationBinding
public @interface JmsAsyncOperationBinding {}

0 comments on commit b4b293b

Please sign in to comment.