Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Enable Spring Pulsar with Spring Boot 3.2.x #1296

Closed
wants to merge 3 commits into from
Closed
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 @@ -16,30 +16,47 @@

package io.spring.start.site.container;

import java.util.Arrays;
import java.util.Collection;
import java.util.Set;
import java.util.TreeSet;
import java.util.function.Consumer;

import io.spring.initializr.generator.container.docker.compose.ComposeService.Builder;
import io.spring.initializr.generator.container.docker.compose.ComposeService;

/**
* Description of a Docker service.
*
* @author Stephane Nicoll
* @author Chris Bono
*/
public class DockerService implements Consumer<Builder> {
public final class DockerService implements Consumer<ComposeService.Builder> {

private final String image;

private final String imageTag;

private final String website;

private final String command;

private final int[] ports;

DockerService(String image, String imageTag, String website, int... ports) {
this.image = image;
this.imageTag = imageTag;
this.website = website;
this.ports = ports;
private DockerService(DockerService.Builder builder) {
this.image = builder.image;
this.imageTag = builder.imageTag;
this.website = builder.website;
this.command = builder.command;
this.ports = builder.ports.stream().mapToInt(Number::intValue).toArray();
}

/**
* Return a new builder using the specified image and optional tag.
* @param imageAndTag the image (and optional tag) to use for the service
* @return the new builder instance.
*/
public static DockerService.Builder withImageAndTag(String imageAndTag) {
return new DockerService.Builder(imageAndTag);
}

/**
Expand Down Expand Up @@ -67,6 +84,14 @@ public String getWebsite() {
return this.website;
}

/**
* Return the command to use to override the default command (optional).
* @return the command
*/
public String getCommand() {
return this.command;
}

/**
* Return the ports that should be exposed by the service.
* @return the ports to expose
Expand All @@ -76,8 +101,72 @@ public int[] getPorts() {
}

@Override
public void accept(Builder builder) {
builder.image(this.image).imageTag(this.imageTag).imageWebsite(this.website).ports(this.ports);
public void accept(ComposeService.Builder builder) {
builder.image(this.image)
.imageTag(this.imageTag)
.imageWebsite(this.website)
.command(this.command)
.ports(this.ports);
}

/**
* Builder for {@link DockerService}.
*/
public static class Builder {

private String image;

private String imageTag = "latest";

private String website;

private String command;

private final Set<Integer> ports = new TreeSet<>();

protected Builder(String imageAndTag) {
String[] split = imageAndTag.split(":", 2);
String tag = (split.length == 1) ? "latest" : split[1];
image(split[0]).imageTag(tag);
}

public DockerService.Builder image(String image) {
this.image = image;
return this;
}

public DockerService.Builder imageTag(String imageTag) {
this.imageTag = imageTag;
return this;
}

public DockerService.Builder website(String website) {
this.website = website;
return this;
}

public DockerService.Builder command(String command) {
this.command = command;
return this;
}

public DockerService.Builder ports(Collection<Integer> ports) {
this.ports.addAll(ports);
return this;
}

public DockerService.Builder ports(int... ports) {
return ports(Arrays.stream(ports).boxed().toList());
}

/**
* Builds the {@link DockerService} instance.
* @return the built instance
*/
public DockerService build() {
return new DockerService(this);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
*
* @author Stephane Nicoll
* @author Moritz Halbritter
* @author Chris Bono
*/
public class SimpleDockerServiceResolver implements DockerServiceResolver {

Expand All @@ -41,66 +42,100 @@ public SimpleDockerServiceResolver() {
this.dockerServices.put("mysql", mysql());
this.dockerServices.put("oracle", oracle());
this.dockerServices.put("postgres", postgres());
this.dockerServices.put("pulsar", pulsar());
this.dockerServices.put("rabbit", rabbit());
this.dockerServices.put("redis", redis());
this.dockerServices.put("sqlServer", sqlServer());
this.dockerServices.put("zipkin", zipkin());
}

private static DockerService activeMQ() {
return new DockerService("symptoma/activemq", "latest", "https://hub.docker.com/r/symptoma/activemq", 61616);
return DockerService.withImageAndTag("symptoma/activemq")
.website("https://hub.docker.com/r/symptoma/activemq")
.ports(61616)
.build();
}

private static DockerService cassandra() {
return new DockerService("cassandra", "latest", "https://hub.docker.com/_/cassandra", 9042);
return DockerService.withImageAndTag("cassandra")
.website("https://hub.docker.com/_/cassandra")
.ports(9042)
.build();
}

private static DockerService elasticsearch() {
// They don't provide a 'latest' tag
return new DockerService("docker.elastic.co/elasticsearch/elasticsearch", "7.17.10",
"https://www.docker.elastic.co/r/elasticsearch", 9200, 9300);
return DockerService.withImageAndTag("docker.elastic.co/elasticsearch/elasticsearch:7.17.10")
.website("https://www.docker.elastic.co/r/elasticsearch")
.ports(9200, 9300)
.build();
}

private static DockerService kafka() {
return new DockerService("confluentinc/cp-kafka", "latest", "https://hub.docker.com/r/confluentinc/cp-kafka",
9092);
return DockerService.withImageAndTag("confluentinc/cp-kafka")
.website("https://hub.docker.com/r/confluentinc/cp-kafka")
.ports(9092)
.build();
}

private static DockerService mariaDb() {
return new DockerService("mariadb", "latest", "https://hub.docker.com/_/mariadb", 3306);
return DockerService.withImageAndTag("mariadb").website("https://hub.docker.com/_/mariadb").ports(3306).build();
}

private static DockerService mongoDb() {
return new DockerService("mongo", "latest", "https://hub.docker.com/_/mongo", 27017);
return DockerService.withImageAndTag("mongo").website("https://hub.docker.com/_/mongo").ports(27017).build();
}

private static DockerService mysql() {
return new DockerService("mysql", "latest", "https://hub.docker.com/_/mysql", 3306);
return DockerService.withImageAndTag("mysql").website("https://hub.docker.com/_/mysql").ports(3306).build();
}

private static DockerService oracle() {
return new DockerService("gvenzl/oracle-xe", "latest", "https://hub.docker.com/r/gvenzl/oracle-xe", 1521);
return DockerService.withImageAndTag("gvenzl/oracle-xe")
.website("https://hub.docker.com/r/gvenzl/oracle-xe")
.ports(1521)
.build();
}

private static DockerService postgres() {
return new DockerService("postgres", "latest", "https://hub.docker.com/_/postgres", 5432);
return DockerService.withImageAndTag("postgres")
.website("https://hub.docker.com/_/postgres")
.ports(5432)
.build();
}

private static DockerService pulsar() {
// The latest tag they provide is not the 'latest' GA
return DockerService.withImageAndTag("apachepulsar/pulsar:3.1.0")
.website("https://hub.docker.com/r/apachepulsar/pulsar")
.command("bin/pulsar standalone")
.ports(8080, 6650)
.build();
}

private static DockerService rabbit() {
return new DockerService("rabbitmq", "latest", "https://hub.docker.com/_/rabbitmq", 5672);
return DockerService.withImageAndTag("rabbitmq")
.website("https://hub.docker.com/_/rabbitmq")
.ports(5672)
.build();
}

private static DockerService redis() {
return new DockerService("redis", "latest", "https://hub.docker.com/_/redis", 6379);
return DockerService.withImageAndTag("redis").website("https://hub.docker.com/_/redis").ports(6379).build();
}

private static DockerService sqlServer() {
return new DockerService("mcr.microsoft.com/mssql/server", "latest",
"https://mcr.microsoft.com/en-us/product/mssql/server/about/", 1433);
return DockerService.withImageAndTag("mcr.microsoft.com/mssql/server")
.website("https://mcr.microsoft.com/en-us/product/mssql/server/about/")
.ports(1433)
.build();
}

private static DockerService zipkin() {
return new DockerService("openzipkin/zipkin", "latest", "https://hub.docker.com/r/openzipkin/zipkin/", 9411);
return DockerService.withImageAndTag("openzipkin/zipkin")
.website("https://hub.docker.com/r/openzipkin/zipkin/")
.ports(9411)
.build();
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,27 +16,67 @@

package io.spring.start.site.extension.dependency.springpulsar;

import io.spring.initializr.generator.condition.ConditionalOnPlatformVersion;
import io.spring.initializr.generator.condition.ConditionalOnRequestedDependency;
import io.spring.initializr.generator.condition.ProjectGenerationCondition;
import io.spring.initializr.generator.project.ProjectDescription;
import io.spring.initializr.generator.project.ProjectGenerationConfiguration;
import io.spring.initializr.metadata.InitializrMetadata;
import io.spring.start.site.container.ComposeFileCustomizer;
import io.spring.start.site.container.DockerServiceResolver;
import io.spring.start.site.container.ServiceConnections;
import io.spring.start.site.container.ServiceConnectionsCustomizer;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.context.annotation.Conditional;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
* Configuration for generation of projects that depend on Pulsar.
*
* @author Chris Bono
*/
@ProjectGenerationConfiguration
@ConditionalOnRequestedDependency("pulsar")
@Conditional(SpringPulsarProjectGenerationConfiguration.OnPulsarRequestedDependencyCondition.class)
class SpringPulsarProjectGenerationConfiguration {

private static final String TESTCONTAINERS_CLASS_NAME = "org.testcontainers.containers.PulsarContainer";

@Bean
@ConditionalOnPlatformVersion("3.2.0-SNAPSHOT")
@ConditionalOnRequestedDependency("testcontainers")
ServiceConnectionsCustomizer pulsarServiceConnectionsCustomizer(DockerServiceResolver serviceResolver) {
return (serviceConnections) -> serviceResolver.doWith("pulsar",
(service) -> serviceConnections.addServiceConnection(ServiceConnections.ServiceConnection
.ofContainer("pulsar", service, TESTCONTAINERS_CLASS_NAME, false)));
}

@Bean
@ConditionalOnPlatformVersion("3.2.0-SNAPSHOT")
@ConditionalOnRequestedDependency("docker-compose")
ComposeFileCustomizer pulsarComposeFileCustomizer(DockerServiceResolver serviceResolver) {
return (composeFile) -> serviceResolver.doWith("pulsar",
(service) -> composeFile.services().add("pulsar", service));
}

@Bean
@ConditionalOnPlatformVersion("[3.0.0,3.2.0-M1)")
@ConditionalOnRequestedDependency("cloud-stream")
SpringPulsarBinderBuildCustomizer pulsarBinderBuildCustomizer(InitializrMetadata metadata,
ProjectDescription description) {
return new SpringPulsarBinderBuildCustomizer(metadata, description);
}

static class OnPulsarRequestedDependencyCondition extends ProjectGenerationCondition {

@Override
protected boolean matches(ProjectDescription description, ConditionContext context,
AnnotatedTypeMetadata metadata) {
return description.getRequestedDependencies().containsKey("pulsar")
|| description.getRequestedDependencies().containsKey("pulsar-reactive");
}

}

}
28 changes: 15 additions & 13 deletions start-site/src/main/resources/application.yml
Original file line number Diff line number Diff line change
Expand Up @@ -788,30 +788,32 @@ initializr:
href: https://docs.spring.io/spring-boot/docs/{bootVersion}/reference/htmlsingle/index.html#messaging.jms.artemis
- name: Spring for Apache Pulsar
id: pulsar
compatibilityRange: "[3.0.0,3.2.0-M1)"
mappings:
- compatibilityRange: "[3.0.0,3.2.0-M1)"
version: 0.2.0
compatibilityRange: "[3.0.0,3.2.0-SNAPSHOT]"
description: Build messaging applications with Apache Pulsar
groupId: org.springframework.pulsar
artifactId: spring-pulsar-spring-boot-starter
links:
- rel: reference
href: https://docs.spring.io/spring-pulsar/docs/0.2.x/reference/html/
- name: Spring for Apache Pulsar (Reactive)
id: pulsar-reactive
compatibilityRange: "[3.0.0,3.2.0-M1)"
href: https://docs.spring.io/spring-boot/docs/{bootVersion}/reference/htmlsingle/index.html#messaging.pulsar
mappings:
- compatibilityRange: "[3.0.0,3.2.0-M1)"
version: 0.2.0
groupId: org.springframework.pulsar
artifactId: spring-pulsar-spring-boot-starter
starter: false
- name: Spring for Apache Pulsar (Reactive)
id: pulsar-reactive
compatibilityRange: "[3.0.0,3.2.0-SNAPSHOT]"
description: Build reactive messaging applications with Apache Pulsar
facets:
- reactive
groupId: org.springframework.pulsar
artifactId: spring-pulsar-reactive-spring-boot-starter
links:
- rel: reference
href: https://docs.spring.io/spring-pulsar/docs/0.2.x/reference/html/#reactive-pulsar
href: https://docs.spring.io/spring-boot/docs/{bootVersion}/reference/htmlsingle/index.html#messaging.pulsar
mappings:
- compatibilityRange: "[3.0.0,3.2.0-M1)"
version: 0.2.0
groupId: org.springframework.pulsar
artifactId: spring-pulsar-reactive-spring-boot-starter
starter: false
- name: WebSocket
id: websocket
description: Build Servlet-based WebSocket applications with SockJS and STOMP.
Expand Down
Loading
Loading