Skip to content

Commit ab68e91

Browse files
authored
A Spring starter for oracle nosql (#122)
Signed-off-by: Cezar Andrei <675678+cezarfx@users.noreply.github.com>
1 parent f1a021e commit ab68e91

File tree

21 files changed

+656
-10
lines changed

21 files changed

+656
-10
lines changed

spring-cloud-oci/docs/src/main/asciidoc/index.adoc

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@ include::storage.adoc[]
3030

3131
include::notifications.adoc[]
3232

33+
include::nosql.adoc[]
34+
3335
include::queues.adoc[]
3436

3537
include::streaming.adoc[]
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
// Copyright (c) 2024, Oracle and/or its affiliates.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
3+
4+
[#oci-nosql]
5+
== Oracle NoSQL Database
6+
7+
https://docs.oracle.com/en-us/iaas/nosql-database/index.html[Oracle NoSQL Database] service offering on-demand throughput and storage based provisioning that supports JSON, Table and Key-Value datatypes, all with flexible transaction guarantees.
8+
9+
Maven coordinates:
10+
11+
[source,xml]
12+
----
13+
<dependency>
14+
<groupId>com.oracle.cloud.spring</groupId>
15+
<artifactId>spring-cloud-oci-starter-nosql</artifactId>
16+
</dependency>
17+
----
18+
19+
Gradle coordinates:
20+
21+
[source,subs="normal"]
22+
----
23+
dependencies {
24+
implementation("com.oracle.cloud.spring:spring-cloud-oci-starter-nosql")
25+
}
26+
----
27+
28+
=== Using Oracle NoSQL Database
29+
30+
The starter automatically configures and registers a `NosqlDBConfig` bean in the Spring application, allowing the use of Oracle NoSQL Database repositories.
31+
32+
[source,yaml]
33+
----
34+
spring:
35+
cloud:
36+
oci:
37+
config:
38+
type: file
39+
region:
40+
static: us-ashburn-1
41+
----
42+
43+
Enable NoSQL repositories in your application by using the `@EnableNosqlRepositories` annotation and extending the `AbstractNosqlConfiguration` class.
44+
45+
[source,java]
46+
----
47+
import com.oracle.nosql.spring.data.config.AbstractNosqlConfiguration;
48+
import com.oracle.nosql.spring.data.repository.config.EnableNosqlRepositories;
49+
import org.springframework.boot.SpringApplication;
50+
import org.springframework.boot.autoconfigure.SpringBootApplication;
51+
52+
@SpringBootApplication
53+
@EnableNosqlRepositories
54+
public class MyApp extends AbstractNosqlConfiguration {
55+
public static void main(String[] args) {
56+
SpringApplication.run(MyApp.class, args);
57+
}
58+
}
59+
----
60+
61+
NoSQL repositories and tables are simply defined by extending the `NosqlRepository` interface and applying the `@NosqlTable` annotation:
62+
63+
[source,java]
64+
----
65+
public interface BookRepository extends NosqlRepository<Book, Long> {
66+
// Add repository methods as needed.
67+
Iterable<Book> findByAuthor(String author);
68+
Iterable<Book> findByTitle(String title);
69+
}
70+
----
71+
72+
[source,java]
73+
----
74+
@NosqlTable(tableName = "books")
75+
public class Book {
76+
@NosqlId(generated = true)
77+
long id;
78+
String title;
79+
String author;
80+
double price;
81+
}
82+
----
83+
84+
85+
=== Configuration
86+
87+
The Spring Boot Starter for Oracle Cloud NoSQL Database provides the following configuration options:
88+
89+
|===
90+
^| Name ^| Description ^| Required ^| Default value
91+
| `spring.cloud.oci.nosql.enabled` | Enables the NoSQL DB Config. | No | `true`
92+
|===
93+
94+
95+
=== Sample
96+
97+
A sample application provided https://github.com/oracle/spring-cloud-oracle/tree/main/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample[here] contains the examples to demonstrates the usage of OCI Spring Cloud NoSQL module.

spring-cloud-oci/pom.xml

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,8 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
7575
<spring-cloud-oci-dependencies.version>${project.version}</spring-cloud-oci-dependencies.version>
7676
<spring-cloud-dependencies.version>2023.0.2</spring-cloud-dependencies.version>
7777
<spring-framework.version>6.1.10</spring-framework.version>
78+
<spring-data-oracle-nosql.version>2.0.0</spring-data-oracle-nosql.version>
79+
<oracle.nosql.driver.version>5.4.15</oracle.nosql.driver.version>
7880
<jakarta-mail.version>2.0.3</jakarta-mail.version>
7981
<oci-sdk.version>3.44.3</oci-sdk.version>
8082
<maven.compiler.source>17</maven.compiler.source>
@@ -172,6 +174,46 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
172174
<version>${spring-framework.version}</version>
173175
<scope>compile</scope>
174176
</dependency>
177+
<dependency>
178+
<groupId>com.oracle.nosql.sdk</groupId>
179+
<artifactId>spring-data-oracle-nosql</artifactId>
180+
<version>${spring-data-oracle-nosql.version}</version>
181+
</dependency>
182+
<dependency>
183+
<groupId>com.oracle.nosql.sdk</groupId>
184+
<artifactId>nosqldriver</artifactId>
185+
<version>${oracle.nosql.driver.version}</version>
186+
</dependency>
187+
<dependency>
188+
<groupId>org.springframework.data</groupId>
189+
<artifactId>spring-data-commons</artifactId>
190+
<version>${spring-boot.version}</version>
191+
</dependency>
192+
<dependency>
193+
<groupId>org.springframework</groupId>
194+
<artifactId>spring-core</artifactId>
195+
<version>${spring-framework.version}</version>
196+
</dependency>
197+
<dependency>
198+
<groupId>org.springframework</groupId>
199+
<artifactId>spring-tx</artifactId>
200+
<version>${spring-framework.version}</version>
201+
</dependency>
202+
<dependency>
203+
<groupId>org.springframework</groupId>
204+
<artifactId>spring-expression</artifactId>
205+
<version>${spring-framework.version}</version>
206+
</dependency>
207+
<dependency>
208+
<groupId>org.springframework</groupId>
209+
<artifactId>spring-beans</artifactId>
210+
<version>${spring-framework.version}</version>
211+
</dependency>
212+
<dependency>
213+
<groupId>org.springframework</groupId>
214+
<artifactId>spring-context</artifactId>
215+
<version>${spring-framework.version}</version>
216+
</dependency>
175217
<dependency>
176218
<groupId>org.eclipse.angus</groupId>
177219
<artifactId>jakarta.mail</artifactId>

spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,11 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
100100
<artifactId>spring-cloud-oci-logging</artifactId>
101101
<optional>true</optional>
102102
</dependency>
103+
<dependency>
104+
<groupId>com.oracle.nosql.sdk</groupId>
105+
<artifactId>spring-data-oracle-nosql</artifactId>
106+
<optional>true</optional>
107+
</dependency>
103108
<dependency>
104109
<groupId>com.oracle.cloud.spring</groupId>
105110
<artifactId>spring-cloud-oci-function</artifactId>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
/*
2+
** Copyright (c) 2024, Oracle and/or its affiliates.
3+
** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
4+
*/
5+
package com.oracle.cloud.spring.nosql;
6+
7+
import java.io.IOException;
8+
9+
import com.oracle.bmc.auth.RegionProvider;
10+
import com.oracle.cloud.spring.autoconfigure.core.CredentialsProperties;
11+
import com.oracle.nosql.spring.data.config.NosqlDbConfig;
12+
import oracle.nosql.driver.iam.SignatureProvider;
13+
import org.springframework.beans.factory.annotation.Qualifier;
14+
import org.springframework.boot.autoconfigure.AutoConfiguration;
15+
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
16+
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
17+
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
18+
import org.springframework.cloud.context.config.annotation.RefreshScope;
19+
import org.springframework.context.annotation.Bean;
20+
21+
import static com.oracle.cloud.spring.autoconfigure.core.RegionProviderAutoConfiguration.regionProviderQualifier;
22+
23+
@AutoConfiguration
24+
@ConditionalOnClass(NosqlDbConfig.class)
25+
@ConditionalOnProperty(name = "spring.cloud.oci.nosql.enabled", havingValue = "true", matchIfMissing = true)
26+
public class NoSQLAutoConfiguration {
27+
@Bean
28+
@RefreshScope
29+
@ConditionalOnMissingBean
30+
public NosqlDbConfig nosqlDbConfig(@Qualifier(regionProviderQualifier) RegionProvider regionProvider,
31+
CredentialsProperties properties) throws IOException {
32+
String profile = properties.hasProfile() ? properties.getProfile() : "DEFAULT";
33+
SignatureProvider signatureProvider;
34+
switch (properties.getType()) {
35+
case WORKLOAD_IDENTITY -> signatureProvider = SignatureProvider.createWithOkeWorkloadIdentity();
36+
case RESOURCE_PRINCIPAL -> signatureProvider = SignatureProvider.createWithResourcePrincipal();
37+
case INSTANCE_PRINCIPAL ->
38+
signatureProvider = SignatureProvider.createWithInstancePrincipal();
39+
case SIMPLE -> signatureProvider = new SignatureProvider(
40+
properties.getTenantId(),
41+
properties.getUserId(),
42+
properties.getFingerprint(),
43+
properties.getPrivateKey(),
44+
properties.getPassPhrase() != null ? properties.getPassPhrase().toCharArray() : null
45+
);
46+
case SESSION_TOKEN -> {
47+
if (properties.hasFile()) {
48+
signatureProvider = SignatureProvider.createWithSessionToken(properties.getFile(), profile);
49+
} else {
50+
signatureProvider = SignatureProvider.createWithSessionToken(profile);
51+
}
52+
}
53+
default -> {
54+
if (properties.hasFile()) {
55+
signatureProvider = new SignatureProvider(properties.getFile(), profile);
56+
} else {
57+
signatureProvider = new SignatureProvider(profile);
58+
}
59+
60+
}
61+
}
62+
return new NosqlDbConfig(regionProvider.getRegion().getRegionId(), signatureProvider);
63+
}
64+
}

spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,12 @@
6565
"type": "java.lang.Boolean",
6666
"description": "Auto-configure OCI Autonomous Database components.",
6767
"defaultValue": true
68+
},
69+
{
70+
"name": "spring.cloud.oci.nosql.enabled",
71+
"type": "java.lang.Boolean",
72+
"description": "Auto-configure Oracle NoSQL Database components.",
73+
"defaultValue": true
6874
}
6975
]
7076
}

spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ com.oracle.cloud.spring.genai.GenAIAutoConfiguration
1111
com.oracle.cloud.spring.vault.VaultAutoConfiguration
1212
com.oracle.cloud.spring.adb.AutonomousDbAutoConfiguration
1313
com.oracle.cloud.spring.email.EmailDeliveryAutoConfiguration
14+
com.oracle.cloud.spring.nosql.NoSQLAutoConfiguration

spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,24 @@
88
import com.oracle.bmc.Region;
99
import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider;
1010
import com.oracle.bmc.auth.RegionProvider;
11+
import com.oracle.cloud.spring.autoconfigure.core.CredentialsProperties;
1112
import com.oracle.cloud.spring.core.compartment.CompartmentProvider;
1213
import com.oracle.cloud.spring.core.compartment.StaticCompartmentProvider;
1314
import com.oracle.cloud.spring.core.region.StaticRegionProvider;
15+
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
1416
import org.springframework.context.annotation.Bean;
1517
import org.springframework.context.annotation.Configuration;
1618

19+
import static org.assertj.core.api.Assertions.assertThat;
1720
import static org.mockito.Mockito.mock;
1821

1922
@Configuration
2023
public class TestCommonConfigurationBeans {
24+
@Bean
25+
CredentialsProperties credentialsProperties() {
26+
return new CredentialsProperties();
27+
}
28+
2129
@Bean
2230
BasicAuthenticationDetailsProvider credentialsProvider() {
2331
return mock(BasicAuthenticationDetailsProvider.class);
@@ -33,4 +41,17 @@ CompartmentProvider compartmentProvider() {
3341
return new StaticCompartmentProvider("compartmentOCID");
3442
}
3543

44+
public static void assertBeanLoaded(AssertableApplicationContext ctx, Class<?> clazz) {
45+
assertBeanLoaded(ctx, clazz, true);
46+
}
47+
48+
public static void assertBeanNotLoaded(AssertableApplicationContext ctx, Class<?> clazz) {
49+
assertBeanLoaded(ctx, clazz, false);
50+
}
51+
52+
static void assertBeanLoaded(AssertableApplicationContext ctx, Class<?> clazz, boolean loaded) {
53+
String[] beans = ctx.getBeanNamesForType(clazz);
54+
assertThat(beans).hasSize(loaded ? 2 : 0);
55+
}
56+
3657
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// Copyright (c) 2024, Oracle and/or its affiliates.
2+
// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/
3+
package com.oracle.cloud.spring.nosql;
4+
5+
import com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans;
6+
import com.oracle.nosql.spring.data.config.NosqlDbConfig;
7+
import org.junit.jupiter.api.Test;
8+
import org.springframework.boot.autoconfigure.AutoConfigurations;
9+
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
10+
11+
import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanLoaded;
12+
import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanNotLoaded;
13+
14+
public class NoSQLAutoConfigurationTests {
15+
private final ApplicationContextRunner contextRunner = new ApplicationContextRunner()
16+
.withPropertyValues("spring.cloud.oci.nosql.enabled=true")
17+
.withConfiguration(AutoConfigurations.of(NoSQLAutoConfiguration.class))
18+
.withUserConfiguration(TestCommonConfigurationBeans.class);
19+
20+
@Test
21+
void beansAreLoaded() {
22+
contextRunner.run(ctx -> assertBeanLoaded(ctx, NosqlDbConfig.class));
23+
}
24+
25+
@Test
26+
void beansAreNotLoadedWhenDisabled() {
27+
contextRunner.withPropertyValues("spring.cloud.oci.nosql.enabled=false")
28+
.run(ctx -> assertBeanNotLoaded(ctx, NosqlDbConfig.class));
29+
}
30+
}

spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
import com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans;
66
import org.junit.jupiter.api.Test;
77
import org.springframework.boot.autoconfigure.AutoConfigurations;
8-
import org.springframework.boot.test.context.assertj.AssertableApplicationContext;
98
import org.springframework.boot.test.context.runner.ApplicationContextRunner;
109

11-
import static org.assertj.core.api.Assertions.assertThat;
10+
import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanLoaded;
11+
import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanNotLoaded;
1212

1313
public class VaultAutoConfigurationTests {
1414
private final String vaultIdProperty = "spring.cloud.oci.vault.vault-id=xyz";
@@ -22,23 +22,18 @@ public class VaultAutoConfigurationTests {
2222
@Test
2323
void beansAreLoaded() {
2424
contextRunner.withPropertyValues(vaultIdProperty)
25-
.run(ctx -> assertVaultTemplateBean(ctx, true));
25+
.run(ctx -> assertBeanLoaded(ctx, VaultTemplate.class));
2626
}
2727

2828
@Test
2929
void beansAreNotLoadedWhenDisabled() {
3030
contextRunner.withPropertyValues(vaultIdProperty,
3131
"spring.cloud.oci.vault.enabled=false")
32-
.run(ctx -> assertVaultTemplateBean(ctx, false));
32+
.run(ctx -> assertBeanNotLoaded(ctx, VaultTemplate.class));
3333
}
3434

3535
@Test
3636
void beansAreNotLoadedWhenNoVault() {
37-
contextRunner.run(ctx -> assertVaultTemplateBean(ctx, false));
38-
}
39-
40-
private void assertVaultTemplateBean(AssertableApplicationContext ctx, boolean hasBean) {
41-
String[] beans = ctx.getBeanNamesForType(VaultTemplate.class);
42-
assertThat(beans).hasSize(hasBean ? 2 : 0);
37+
contextRunner.run(ctx -> assertBeanNotLoaded(ctx, VaultTemplate.class));
4338
}
4439
}

spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,11 @@
157157
<artifactId>spring-cloud-oci-starter-email</artifactId>
158158
<version>${project.version}</version>
159159
</dependency>
160+
<dependency>
161+
<groupId>com.oracle.cloud.spring</groupId>
162+
<artifactId>spring-cloud-oci-starter-nosql</artifactId>
163+
<version>${project.version}</version>
164+
</dependency>
160165
</dependencies>
161166
</dependencyManagement>
162167

spring-cloud-oci/spring-cloud-oci-samples/pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or
5050
<module>spring-cloud-oci-function-sample</module>
5151
<module>spring-cloud-oci-adb-sample</module>
5252
<module>spring-cloud-oci-email-sample</module>
53+
<module>spring-cloud-oci-nosql-sample</module>
5354
</modules>
5455

5556
<artifactId>spring-cloud-oci-samples</artifactId>

0 commit comments

Comments
 (0)