Skip to content

Commit da05e9e

Browse files
quaffwilkinsona
authored andcommitted
Add DB2 support for Docker Compose
1 parent d815cad commit da05e9e

File tree

11 files changed

+320
-1
lines changed

11 files changed

+320
-1
lines changed

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ dependencies {
1919
dockerTestImplementation("org.junit.jupiter:junit-jupiter")
2020
dockerTestImplementation("org.testcontainers:testcontainers")
2121

22+
dockerTestRuntimeOnly("com.ibm.db2:jcc")
2223
dockerTestRuntimeOnly("com.microsoft.sqlserver:mssql-jdbc")
2324
dockerTestRuntimeOnly("com.oracle.database.r2dbc:oracle-r2dbc")
2425
dockerTestRuntimeOnly("io.r2dbc:r2dbc-mssql")
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("db2inst1");
46+
assertThat(connectionDetails.getPassword()).isEqualTo("secret");
47+
assertThat(connectionDetails.getJdbcUrl()).startsWith("jdbc:db2://").endsWith("/testdb");
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,18 @@
1+
services:
2+
database:
3+
image: '{imageName}'
4+
ports:
5+
- '50000'
6+
privileged: true
7+
environment:
8+
- 'LICENSE=accept'
9+
- 'DB2INSTANCE=db2inst1'
10+
- 'DB2INST1_PASSWORD=secret'
11+
- 'DBNAME=testdb'
12+
- 'AUTOCONFIG=false'
13+
- 'ARCHIVE_LOGS=false'
14+
healthcheck:
15+
test: 'su - db2inst1 -c "db2 connect to testdb user db2inst1 using secret"'
16+
start_period: 90s
17+
labels:
18+
org.springframework.boot.readiness-check.tcp.disable: true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
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.get("DBNAME");
42+
Assert.state(StringUtils.hasLength(this.database), "DB2 database must be provided");
43+
}
44+
45+
String getUsername() {
46+
return this.username;
47+
}
48+
49+
String getPassword() {
50+
return this.password;
51+
}
52+
53+
String getDatabase() {
54+
return this.database;
55+
}
56+
57+
}
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 = { "ibmcom/db2", "db2_community/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,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;

spring-boot-project/spring-boot-docker-compose/src/main/resources/META-INF/spring.factories

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ org.springframework.boot.docker.compose.service.connection.activemq.ActiveMQClas
99
org.springframework.boot.docker.compose.service.connection.activemq.ActiveMQDockerComposeConnectionDetailsFactory,\
1010
org.springframework.boot.docker.compose.service.connection.activemq.ArtemisDockerComposeConnectionDetailsFactory,\
1111
org.springframework.boot.docker.compose.service.connection.cassandra.CassandraDockerComposeConnectionDetailsFactory,\
12+
org.springframework.boot.docker.compose.service.connection.db2.Db2JdbcDockerComposeConnectionDetailsFactory,\
1213
org.springframework.boot.docker.compose.service.connection.elasticsearch.ElasticsearchDockerComposeConnectionDetailsFactory,\
1314
org.springframework.boot.docker.compose.service.connection.flyway.JdbcAdaptingFlywayConnectionDetailsFactory,\
1415
org.springframework.boot.docker.compose.service.connection.hazelcast.HazelcastDockerComposeConnectionDetailsFactory,\
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
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.Collections;
20+
import java.util.Map;
21+
22+
import org.junit.jupiter.api.Test;
23+
24+
import static org.assertj.core.api.Assertions.assertThat;
25+
import static org.assertj.core.api.Assertions.assertThatIllegalStateException;
26+
27+
/**
28+
* Tests for {@link Db2Environment}.
29+
*
30+
* @author Yanming Zhou
31+
*/
32+
class Db2EnvironmentTests {
33+
34+
@Test
35+
void createWhenNoDb2InstancePasswordThrowsException() {
36+
assertThatIllegalStateException().isThrownBy(() -> new Db2Environment(Collections.emptyMap()))
37+
.withMessage("DB2 password must be provided");
38+
}
39+
40+
@Test
41+
void createWhenNoDb2InstanceDatabaseThrowsException() {
42+
assertThatIllegalStateException().isThrownBy(() -> new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret")))
43+
.withMessage("DB2 database must be provided");
44+
}
45+
46+
@Test
47+
void getUsernameWhenNoDb2Instance() {
48+
Db2Environment environment = new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
49+
assertThat(environment.getUsername()).isEqualTo("db2inst1");
50+
}
51+
52+
@Test
53+
void getUsernameWhenHasDb2Instance() {
54+
Db2Environment environment = new Db2Environment(
55+
Map.of("DB2INSTANCE", "db2inst2", "DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
56+
assertThat(environment.getUsername()).isEqualTo("db2inst2");
57+
}
58+
59+
@Test
60+
void getPasswordWhenHasDb2InstancePassword() {
61+
Db2Environment environment = new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
62+
assertThat(environment.getPassword()).isEqualTo("secret");
63+
}
64+
65+
@Test
66+
void getDatabaseWhenHasDbName() {
67+
Db2Environment environment = new Db2Environment(Map.of("DB2INST1_PASSWORD", "secret", "DBNAME", "testdb"));
68+
assertThat(environment.getDatabase()).isEqualTo("testdb");
69+
}
70+
71+
}

spring-boot-project/spring-boot-docs/src/docs/antora/modules/reference/pages/features/dev-services.adoc

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ The following service connections are currently supported:
9999
| Containers named "hazelcast/hazelcast".
100100

101101
| `JdbcConnectionDetails`
102-
| Containers named "gvenzl/oracle-free", "gvenzl/oracle-xe", "mariadb", "bitnami/mariadb", "mssql/server", "mysql", "bitnami/mysql", "postgres", or "bitnami/postgresql"
102+
| Containers named "gvenzl/oracle-free", "gvenzl/oracle-xe", "db2_community/db2", "ibmcom/db2", "mariadb", "bitnami/mariadb", "mssql/server", "mysql", "bitnami/mysql", "postgres", or "bitnami/postgresql"
103103

104104
| `LdapConnectionDetails`
105105
| Containers named "osixia/openldap"

spring-boot-project/spring-boot-tools/spring-boot-test-support-docker/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ dependencies {
1717
optional("org.testcontainers:activemq")
1818
optional("org.testcontainers:cassandra")
1919
optional("org.testcontainers:couchbase")
20+
optional("org.testcontainers:db2")
2021
optional("org.testcontainers:elasticsearch")
2122
optional("org.testcontainers:grafana")
2223
optional("org.testcontainers:junit-jupiter")

0 commit comments

Comments
 (0)