Skip to content

Commit 128b451

Browse files
committed
Add DB2 support for Docker Compose
1 parent 84e6594 commit 128b451

File tree

13 files changed

+452
-0
lines changed

13 files changed

+452
-0
lines changed

spring-boot-project/spring-boot-dependencies/build.gradle

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,6 +1602,13 @@ bom {
16021602
.formatted(version.toString("_")) }
16031603
}
16041604
}
1605+
library("R2DBC DB2", "1.1.0") {
1606+
group("com.ibm.db2") {
1607+
modules = [
1608+
"db2-r2dbc"
1609+
]
1610+
}
1611+
}
16051612
library("R2DBC H2", "1.0.0.RELEASE") {
16061613
considerSnapshots()
16071614
group("io.r2dbc") {

spring-boot-project/spring-boot-docker-compose/build.gradle

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ dependencies {
2424
dockerTestRuntimeOnly("io.r2dbc:r2dbc-mssql")
2525
dockerTestRuntimeOnly("org.postgresql:postgresql")
2626
dockerTestRuntimeOnly("org.postgresql:r2dbc-postgresql")
27+
dockerTestRuntimeOnly("com.ibm.db2:jcc")
28+
dockerTestRuntimeOnly("com.ibm.db2:db2-r2dbc")
2729

2830
implementation("com.fasterxml.jackson.core:jackson-databind")
2931
implementation("com.fasterxml.jackson.module:jackson-module-parameter-names")
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docker.compose.service.connection.db2;
18+
19+
import java.sql.Driver;
20+
21+
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
22+
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
23+
import org.springframework.boot.jdbc.DatabaseDriver;
24+
import org.springframework.boot.testsupport.container.TestImage;
25+
import org.springframework.jdbc.core.JdbcTemplate;
26+
import org.springframework.jdbc.datasource.SimpleDriverDataSource;
27+
import org.springframework.util.ClassUtils;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
31+
/**
32+
* Integration tests for {@link Db2JdbcDockerComposeConnectionDetailsFactory}.
33+
*
34+
* @author Yanming Zhou
35+
*/
36+
class Db2JdbcDockerComposeConnectionDetailsFactoryIntegrationTests {
37+
38+
@DockerComposeTest(composeFile = "db2-compose.yaml", image = TestImage.DB2)
39+
void runCreatesConnectionDetails(JdbcConnectionDetails connectionDetails) throws Exception {
40+
assertConnectionDetails(connectionDetails);
41+
checkDatabaseAccess(connectionDetails);
42+
}
43+
44+
private void assertConnectionDetails(JdbcConnectionDetails connectionDetails) {
45+
assertThat(connectionDetails.getUsername()).isEqualTo("db2inst2");
46+
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
47+
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:db2://").endsWith("/mydb");
48+
}
49+
50+
@SuppressWarnings("unchecked")
51+
private void checkDatabaseAccess(JdbcConnectionDetails connectionDetails) throws ClassNotFoundException {
52+
SimpleDriverDataSource dataSource = new SimpleDriverDataSource();
53+
dataSource.setUrl(connectionDetails.getJdbcUrl());
54+
dataSource.setUsername(connectionDetails.getUsername());
55+
dataSource.setPassword(connectionDetails.getPassword());
56+
dataSource.setDriverClass((Class<? extends Driver>) ClassUtils.forName(connectionDetails.getDriverClassName(),
57+
getClass().getClassLoader()));
58+
JdbcTemplate template = new JdbcTemplate(dataSource);
59+
assertThat(template.queryForObject(DatabaseDriver.DB2.getValidationQuery(), Integer.class)).isEqualTo(1);
60+
}
61+
62+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docker.compose.service.connection.db2;
18+
19+
import java.time.Duration;
20+
21+
import io.r2dbc.spi.ConnectionFactories;
22+
import io.r2dbc.spi.ConnectionFactoryOptions;
23+
24+
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
25+
import org.springframework.boot.docker.compose.service.connection.test.DockerComposeTest;
26+
import org.springframework.boot.jdbc.DatabaseDriver;
27+
import org.springframework.boot.testsupport.container.TestImage;
28+
import org.springframework.r2dbc.core.DatabaseClient;
29+
30+
import static org.assertj.core.api.Assertions.assertThat;
31+
32+
/**
33+
* Integration tests for {@link Db2R2dbcDockerComposeConnectionDetailsFactory}.
34+
*
35+
* @author Yanming Zhou
36+
*/
37+
class Db2R2dbcDockerComposeConnectionDetailsFactoryIntegrationTests {
38+
39+
@DockerComposeTest(composeFile = "db2-compose.yaml", image = TestImage.DB2)
40+
void runCreatesConnectionDetails(R2dbcConnectionDetails connectionDetails) {
41+
assertConnectionDetails(connectionDetails);
42+
checkDatabaseAccess(connectionDetails);
43+
}
44+
45+
private void assertConnectionDetails(R2dbcConnectionDetails connectionDetails) {
46+
ConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();
47+
assertThat(connectionFactoryOptions.toString()).contains("database=mydb", "driver=db2", "user=db2inst2");
48+
assertThat(connectionFactoryOptions.getRequiredValue(ConnectionFactoryOptions.PASSWORD)).isEqualTo("secret");
49+
}
50+
51+
private void checkDatabaseAccess(R2dbcConnectionDetails connectionDetails) {
52+
ConnectionFactoryOptions connectionFactoryOptions = connectionDetails.getConnectionFactoryOptions();
53+
Object result = DatabaseClient.create(ConnectionFactories.get(connectionFactoryOptions))
54+
.sql(DatabaseDriver.DB2.getValidationQuery())
55+
.map((row, metadata) -> row.get(0))
56+
.first()
57+
.block(Duration.ofSeconds(30));
58+
assertThat(result).isEqualTo(1);
59+
}
60+
61+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
services:
2+
database:
3+
image: '{imageName}'
4+
ports:
5+
- '50000'
6+
environment:
7+
- 'LICENSE=accept'
8+
- 'DB2INST1=db2inst2'
9+
- 'DB2INST1_PASSWORD=secret'
10+
- 'DBNAME=mydb'
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docker.compose.service.connection.db2;
18+
19+
import java.util.Map;
20+
21+
import org.springframework.util.Assert;
22+
import org.springframework.util.StringUtils;
23+
24+
/**
25+
* DB2 environment details.
26+
*
27+
* @author Yanming Zhou
28+
*/
29+
class Db2Environment {
30+
31+
private final String username;
32+
33+
private final String password;
34+
35+
private final String database;
36+
37+
Db2Environment(Map<String, String> env) {
38+
this.username = env.getOrDefault("DB2INSTANCE", "db2inst1");
39+
this.password = env.get("DB2INST1_PASSWORD");
40+
Assert.state(StringUtils.hasLength(this.password), "DB2 password must be provided");
41+
this.database = env.getOrDefault("DBNAME", "testdb");
42+
}
43+
44+
String getUsername() {
45+
return this.username;
46+
}
47+
48+
String getPassword() {
49+
return this.password;
50+
}
51+
52+
String getDatabase() {
53+
return this.database;
54+
}
55+
56+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docker.compose.service.connection.db2;
18+
19+
import org.springframework.boot.autoconfigure.jdbc.JdbcConnectionDetails;
20+
import org.springframework.boot.docker.compose.core.RunningService;
21+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
22+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
23+
import org.springframework.boot.docker.compose.service.connection.jdbc.JdbcUrlBuilder;
24+
25+
/**
26+
* {@link DockerComposeConnectionDetailsFactory} to create {@link JdbcConnectionDetails}
27+
* for a {@code db2} service.
28+
*
29+
* @author Yanming Zhou
30+
*/
31+
class Db2JdbcDockerComposeConnectionDetailsFactory
32+
extends DockerComposeConnectionDetailsFactory<JdbcConnectionDetails> {
33+
34+
private static final String[] DB2_CONTAINER_NAMES = { "db2_community/db2", "ibmcom/db2" };
35+
36+
protected Db2JdbcDockerComposeConnectionDetailsFactory() {
37+
super(DB2_CONTAINER_NAMES);
38+
}
39+
40+
@Override
41+
protected JdbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
42+
return new Db2JdbcDockerComposeConnectionDetails(source.getRunningService());
43+
}
44+
45+
/**
46+
* {@link JdbcConnectionDetails} backed by a {@code db2} {@link RunningService}.
47+
*/
48+
static class Db2JdbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
49+
implements JdbcConnectionDetails {
50+
51+
private static final JdbcUrlBuilder jdbcUrlBuilder = new JdbcUrlBuilder("db2", 50000);
52+
53+
private final Db2Environment environment;
54+
55+
private final String jdbcUrl;
56+
57+
Db2JdbcDockerComposeConnectionDetails(RunningService service) {
58+
super(service);
59+
this.environment = new Db2Environment(service.env());
60+
this.jdbcUrl = jdbcUrlBuilder.build(service, this.environment.getDatabase());
61+
}
62+
63+
@Override
64+
public String getUsername() {
65+
return this.environment.getUsername();
66+
}
67+
68+
@Override
69+
public String getPassword() {
70+
return this.environment.getPassword();
71+
}
72+
73+
@Override
74+
public String getJdbcUrl() {
75+
return this.jdbcUrl;
76+
}
77+
78+
}
79+
80+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.boot.docker.compose.service.connection.db2;
18+
19+
import io.r2dbc.spi.ConnectionFactoryOptions;
20+
21+
import org.springframework.boot.autoconfigure.r2dbc.R2dbcConnectionDetails;
22+
import org.springframework.boot.docker.compose.core.RunningService;
23+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionDetailsFactory;
24+
import org.springframework.boot.docker.compose.service.connection.DockerComposeConnectionSource;
25+
import org.springframework.boot.docker.compose.service.connection.r2dbc.ConnectionFactoryOptionsBuilder;
26+
27+
/**
28+
* {@link DockerComposeConnectionDetailsFactory} to create {@link R2dbcConnectionDetails}
29+
* for a {@code db2} service.
30+
*
31+
* @author Yanming Zhou
32+
*/
33+
class Db2R2dbcDockerComposeConnectionDetailsFactory
34+
extends DockerComposeConnectionDetailsFactory<R2dbcConnectionDetails> {
35+
36+
private static final String[] DB2_CONTAINER_NAMES = { "db2_community/db2", "ibmcom/db2" };
37+
38+
Db2R2dbcDockerComposeConnectionDetailsFactory() {
39+
super(DB2_CONTAINER_NAMES, "io.r2dbc.spi.ConnectionFactoryOptions");
40+
}
41+
42+
@Override
43+
protected R2dbcConnectionDetails getDockerComposeConnectionDetails(DockerComposeConnectionSource source) {
44+
return new Db2DbR2dbcDockerComposeConnectionDetails(source.getRunningService());
45+
}
46+
47+
/**
48+
* {@link R2dbcConnectionDetails} backed by a {@code db2} {@link RunningService}.
49+
*/
50+
static class Db2DbR2dbcDockerComposeConnectionDetails extends DockerComposeConnectionDetails
51+
implements R2dbcConnectionDetails {
52+
53+
private static final ConnectionFactoryOptionsBuilder connectionFactoryOptionsBuilder = new ConnectionFactoryOptionsBuilder(
54+
"db2", 50000);
55+
56+
private final ConnectionFactoryOptions connectionFactoryOptions;
57+
58+
Db2DbR2dbcDockerComposeConnectionDetails(RunningService service) {
59+
super(service);
60+
Db2Environment environment = new Db2Environment(service.env());
61+
this.connectionFactoryOptions = connectionFactoryOptionsBuilder.build(service, environment.getDatabase(),
62+
environment.getUsername(), environment.getPassword());
63+
}
64+
65+
@Override
66+
public ConnectionFactoryOptions getConnectionFactoryOptions() {
67+
return this.connectionFactoryOptions;
68+
}
69+
70+
}
71+
72+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
/*
2+
* Copyright 2012-2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
/**
18+
* Auto-configuration for Docker Compose DB2 service connections.
19+
*/
20+
package org.springframework.boot.docker.compose.service.connection.db2;

0 commit comments

Comments
 (0)