Skip to content

Commit

Permalink
Merge pull request #655 from ctasada/ctasada/decouple-binding-annotat…
Browse files Browse the repository at this point in the history
…ions

(feat): Decoupled Binding annotations
  • Loading branch information
ctasada authored Mar 18, 2024
2 parents fcd41cc + 92d7718 commit 21628c0
Show file tree
Hide file tree
Showing 22 changed files with 661 additions and 2 deletions.
56 changes: 56 additions & 0 deletions .github/workflows/springwolf-bindings.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
name: springwolf-bindings

on:
push:
branches:
- master
pull_request:
types: [ opened, synchronize, ready_for_review ]

jobs:
build:

runs-on: ubuntu-latest
timeout-minutes: 10

strategy:
fail-fast: false
matrix:
binding: [ "sns", "sqs" ]

env:
binding: springwolf-bindings/springwolf-${{ matrix.binding }}-binding

steps:
- uses: actions/checkout@v4

- name: Set up JDK
uses: actions/setup-java@v4
with:
distribution: 'temurin'
java-version: '17'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3

- name: Check formatting (before running tests) on binding
run: ./gradlew -p ${{ env.binding }} spotlessCheck

- name: Run unit tests
run: ./gradlew -p ${{ env.binding }} test

- name: Run build, check, analyzeDependencies on binding
run: ./gradlew -p ${{ env.binding }} build

- name: Publish package
if: github.ref == 'refs/heads/master'
run: ./gradlew -p ${{ env.binding }} publish
env:
ORG_GRADLE_PROJECT_SNAPSHOT: true

ORG_GRADLE_PROJECT_SIGNINGKEY: ${{secrets.ORG_GRADLE_PROJECT_SIGNINGKEY}}
ORG_GRADLE_PROJECT_SIGNINGPASSWORD: ${{secrets.ORG_GRADLE_PROJECT_SIGNINGPASSWORD}}

ORG_GRADLE_PROJECT_MAVEN_URL: https://s01.oss.sonatype.org/content/repositories/snapshots/
ORG_GRADLE_PROJECT_MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }}
ORG_GRADLE_PROJECT_MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ springwolf-add-ons/build/
springwolf-core/build/
springwolf-examples/build/
springwolf-plugins/build/
springwolf-bindings/build/
springwolf-ui/build/
springwolf-add-ons/springwolf-common-model-converters/build/
springwolf-examples/springwolf-amqp-example/build/
Expand All @@ -14,6 +15,7 @@ springwolf-plugins/springwolf-amqp-plugin/build/
springwolf-plugins/springwolf-cloud-stream-plugin/build/
springwolf-plugins/springwolf-kafka-plugin/build/
springwolf-plugins/springwolf-sqs-plugin/build/
springwolf-bindings/springwolf-sqs-binding/build/

.gradle/
.idea/
Expand Down
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,14 +75,20 @@ More details in the documentation.
| [Kafka](https://github.com/springwolf/springwolf-core/tree/master/springwolf-plugins/springwolf-kafka-plugin) | [Kafka Example](https://github.com/springwolf/springwolf-core/tree/master/springwolf-examples/springwolf-kafka-example) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-kafka?color=green&label=springwolf-kafka&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-kafka?label=springwolf-kafka&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |

<details>
<summary>Click to expand all artifacts and add-ons</summary>
<summary>Click to expand all artifacts, bindings and add-ons</summary>

| Artifact | Current version | SNAPSHOT version |
|----------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [AsyncAPI implementation](https://github.com/springwolf/springwolf-core/tree/master/springwolf-asyncapi) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-asyncapi?color=green&label=springwolf-asyncapi&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-asyncapi?label=springwolf-asyncapi&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
| [Core](https://github.com/springwolf/springwolf-core/tree/master/springwolf-core) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-core?color=green&label=springwolf-core&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-core?label=springwolf-core&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
| [UI](https://github.com/springwolf/springwolf-core/tree/master/springwolf-ui) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-ui?color=green&label=springwolf-ui&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-ui?label=springwolf-ui&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |

| Bindings | Current version | SNAPSHOT version |
|-------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [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) |


| Add-on | Current version | SNAPSHOT version |
|-------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| [Common Model Converter](https://github.com/springwolf/springwolf-core/tree/master/springwolf-add-ons/springwolf-common-model-converters) | ![Maven Central](https://img.shields.io/maven-central/v/io.github.springwolf/springwolf-common-model-converters?color=green&label=springwolf-common-model-converters&style=plastic) | ![Sonatype Nexus (Snapshots)](https://img.shields.io/nexus/s/io.github.springwolf/springwolf-common-model-converters?label=springwolf-common-model-converters&server=https%3A%2F%2Fs01.oss.sonatype.org&style=plastic) |
Expand Down
4 changes: 3 additions & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
rootProject.name = 'springwolf-core'
rootProject.name = 'springwolf'

include(
'springwolf-asyncapi',
Expand All @@ -15,6 +15,8 @@ include(
'springwolf-examples:springwolf-kafka-example',
'springwolf-examples:springwolf-sns-example',
'springwolf-examples:springwolf-sqs-example',
'springwolf-bindings:springwolf-sns-binding',
'springwolf-bindings:springwolf-sqs-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-sns-binding/build.gradle
Original file line number Diff line number Diff line change
@@ -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-sns-binding'
description = 'Automated JSON API documentation for AWS SNS Bindings'
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.sns.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 @SnsAsyncOperationBinding} is a method-level annotation used in combination with {@link AsyncPublisher} or {@link AsyncListener}.
* It configures the operation binding for the SNS protocol.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@AsyncOperationBinding
@Inherited
public @interface SnsAsyncOperationBinding {

String type() default "sns";

String protocol();

SnsAsyncOperationBindingIdentifier endpoint();

boolean rawMessageDelivery() default true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.sns.annotations;

import io.github.springwolf.asyncapi.v3.bindings.sns.SNSOperationBindingIdentifier;

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;

/**
* @see SNSOperationBindingIdentifier
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER})
@Inherited
public @interface SnsAsyncOperationBindingIdentifier {
/**
* Optional. The endpoint is a URL
*/
String url() default "";
/**
* Optional. The endpoint is an email address
*/
String email() default "";
/**
* Optional. The endpoint is a phone number
*/
String phone() default "";
/**
* Optional. The target is an ARN. For example, for SQS, the identifier may be an ARN, which will be of the form:
* "arn:aws:sqs:{region}:{account-id}:{queueName}"
*/
String arn() default "";
/**
* Optional. The endpoint is identified by a name, which corresponds to an identifying field called 'name' of a
* binding for that protocol on this publish Operation Object. For example, if the protocol is 'sqs' then the name
* refers to the name field sqs binding. We don't use $ref because we are referring, not including.
*/
String name() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.sns.configuration;

import io.github.springwolf.bindings.sns.scanners.messages.SnsMessageBindingProcessor;
import io.github.springwolf.bindings.sns.scanners.operations.SnsOperationBindingProcessor;
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 SQS Binding.
*/
@AutoConfiguration
@ConditionalOnProperty(name = SpringwolfConfigConstants.SPRINGWOLF_ENABLED, havingValue = "true", matchIfMissing = true)
public class SpringwolfSnsBindingAutoConfiguration {

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

@Bean
@Order(value = BindingProcessorPriority.PROTOCOL_BINDING)
@ConditionalOnMissingBean
public SnsOperationBindingProcessor sqsOperationBindingProcessor() {
return new SnsOperationBindingProcessor();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.sns.scanners.messages;

import io.github.springwolf.asyncapi.v3.bindings.sns.SNSMessageBinding;
import io.github.springwolf.bindings.sns.annotations.SnsAsyncOperationBinding;
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.Method;
import java.util.Arrays;
import java.util.Optional;

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

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

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

private ProcessedMessageBinding mapToMessageBinding(SnsAsyncOperationBinding bindingAnnotation) {
return new ProcessedMessageBinding(bindingAnnotation.type(), new SNSMessageBinding());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
// SPDX-License-Identifier: Apache-2.0
package io.github.springwolf.bindings.sns.scanners.operations;

import io.github.springwolf.asyncapi.v3.bindings.sns.SNSOperationBinding;
import io.github.springwolf.asyncapi.v3.bindings.sns.SNSOperationBindingConsumer;
import io.github.springwolf.asyncapi.v3.bindings.sns.SNSOperationBindingIdentifier;
import io.github.springwolf.bindings.sns.annotations.SnsAsyncOperationBinding;
import io.github.springwolf.bindings.sns.annotations.SnsAsyncOperationBindingIdentifier;
import io.github.springwolf.core.asyncapi.scanners.bindings.operations.AbstractOperationBindingProcessor;
import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding;

import java.util.List;

public class SnsOperationBindingProcessor extends AbstractOperationBindingProcessor<SnsAsyncOperationBinding> {

@Override
protected ProcessedOperationBinding mapToOperationBinding(SnsAsyncOperationBinding bindingAnnotation) {
var identifier = convertAnnotation(bindingAnnotation.endpoint());
var protocol = readProtocol(bindingAnnotation.protocol());

var consumer = SNSOperationBindingConsumer.builder()
.protocol(protocol)
.endpoint(identifier)
.rawMessageDelivery(bindingAnnotation.rawMessageDelivery())
.build();
var snsOperationBinding =
SNSOperationBinding.builder().consumers(List.of(consumer)).build();
return new ProcessedOperationBinding(bindingAnnotation.type(), snsOperationBinding);
}

private SNSOperationBindingConsumer.Protocol readProtocol(String protocol) {
return SNSOperationBindingConsumer.Protocol.valueOf(protocol.toUpperCase());
}

private SNSOperationBindingIdentifier convertAnnotation(SnsAsyncOperationBindingIdentifier identifier) {
var builder = SNSOperationBindingIdentifier.builder();

if (!identifier.url().isBlank()) {
builder.url(identifier.url());
}
if (!identifier.arn().isBlank()) {
builder.arn(identifier.arn());
}
if (!identifier.name().isBlank()) {
builder.name(identifier.name());
}
if (!identifier.email().isBlank()) {
builder.email(identifier.email());
}
if (!identifier.phone().isBlank()) {
builder.phone(identifier.phone());
}

return builder.build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
io.github.springwolf.bindings.sns.configuration.SpringwolfSnsBindingAutoConfiguration
Loading

0 comments on commit 21628c0

Please sign in to comment.