diff --git a/spring-cloud-oci/docs/src/main/asciidoc/index.adoc b/spring-cloud-oci/docs/src/main/asciidoc/index.adoc index f8706233..bbdaa1e5 100644 --- a/spring-cloud-oci/docs/src/main/asciidoc/index.adoc +++ b/spring-cloud-oci/docs/src/main/asciidoc/index.adoc @@ -30,6 +30,8 @@ include::storage.adoc[] include::notifications.adoc[] +include::nosql.adoc[] + include::queues.adoc[] include::streaming.adoc[] diff --git a/spring-cloud-oci/docs/src/main/asciidoc/nosql.adoc b/spring-cloud-oci/docs/src/main/asciidoc/nosql.adoc new file mode 100644 index 00000000..2ec84972 --- /dev/null +++ b/spring-cloud-oci/docs/src/main/asciidoc/nosql.adoc @@ -0,0 +1,97 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ + +[#oci-nosql] +== Oracle NoSQL Database + +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. + +Maven coordinates: + +[source,xml] +---- + + com.oracle.cloud.spring + spring-cloud-oci-starter-nosql + +---- + +Gradle coordinates: + +[source,subs="normal"] +---- +dependencies { + implementation("com.oracle.cloud.spring:spring-cloud-oci-starter-nosql") +} +---- + +=== Using Oracle NoSQL Database + +The starter automatically configures and registers a `NosqlDBConfig` bean in the Spring application, allowing the use of Oracle NoSQL Database repositories. + +[source,yaml] +---- +spring: + cloud: + oci: + config: + type: file + region: + static: us-ashburn-1 +---- + +Enable NoSQL repositories in your application by using the `@EnableNosqlRepositories` annotation and extending the `AbstractNosqlConfiguration` class. + +[source,java] +---- +import com.oracle.nosql.spring.data.config.AbstractNosqlConfiguration; +import com.oracle.nosql.spring.data.repository.config.EnableNosqlRepositories; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableNosqlRepositories +public class MyApp extends AbstractNosqlConfiguration { + public static void main(String[] args) { + SpringApplication.run(MyApp.class, args); + } +} +---- + +NoSQL repositories and tables are simply defined by extending the `NosqlRepository` interface and applying the `@NosqlTable` annotation: + +[source,java] +---- +public interface BookRepository extends NosqlRepository { + // Add repository methods as needed. + Iterable findByAuthor(String author); + Iterable findByTitle(String title); +} +---- + +[source,java] +---- +@NosqlTable(tableName = "books") +public class Book { + @NosqlId(generated = true) + long id; + String title; + String author; + double price; +} +---- + + +=== Configuration + +The Spring Boot Starter for Oracle Cloud NoSQL Database provides the following configuration options: + +|=== +^| Name ^| Description ^| Required ^| Default value +| `spring.cloud.oci.nosql.enabled` | Enables the NoSQL DB Config. | No | `true` +|=== + + +=== Sample + +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. diff --git a/spring-cloud-oci/pom.xml b/spring-cloud-oci/pom.xml index e4431d2b..c68fe6c7 100644 --- a/spring-cloud-oci/pom.xml +++ b/spring-cloud-oci/pom.xml @@ -75,6 +75,8 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or ${project.version} 2023.0.2 6.1.10 + 2.0.0 + 5.4.15 2.0.3 3.44.3 17 @@ -172,6 +174,46 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or ${spring-framework.version} compile + + com.oracle.nosql.sdk + spring-data-oracle-nosql + ${spring-data-oracle-nosql.version} + + + com.oracle.nosql.sdk + nosqldriver + ${oracle.nosql.driver.version} + + + org.springframework.data + spring-data-commons + ${spring-boot.version} + + + org.springframework + spring-core + ${spring-framework.version} + + + org.springframework + spring-tx + ${spring-framework.version} + + + org.springframework + spring-expression + ${spring-framework.version} + + + org.springframework + spring-beans + ${spring-framework.version} + + + org.springframework + spring-context + ${spring-framework.version} + org.eclipse.angus jakarta.mail diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml b/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml index c2bf5dfd..774c81df 100644 --- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml +++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/pom.xml @@ -100,6 +100,11 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or spring-cloud-oci-logging true + + com.oracle.nosql.sdk + spring-data-oracle-nosql + true + com.oracle.cloud.spring spring-cloud-oci-function diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfiguration.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfiguration.java new file mode 100644 index 00000000..3dafc2d2 --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfiguration.java @@ -0,0 +1,64 @@ +/* + ** Copyright (c) 2024, Oracle and/or its affiliates. + ** Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ + */ +package com.oracle.cloud.spring.nosql; + +import java.io.IOException; + +import com.oracle.bmc.auth.RegionProvider; +import com.oracle.cloud.spring.autoconfigure.core.CredentialsProperties; +import com.oracle.nosql.spring.data.config.NosqlDbConfig; +import oracle.nosql.driver.iam.SignatureProvider; +import org.springframework.beans.factory.annotation.Qualifier; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.cloud.context.config.annotation.RefreshScope; +import org.springframework.context.annotation.Bean; + +import static com.oracle.cloud.spring.autoconfigure.core.RegionProviderAutoConfiguration.regionProviderQualifier; + +@AutoConfiguration +@ConditionalOnClass(NosqlDbConfig.class) +@ConditionalOnProperty(name = "spring.cloud.oci.nosql.enabled", havingValue = "true", matchIfMissing = true) +public class NoSQLAutoConfiguration { + @Bean + @RefreshScope + @ConditionalOnMissingBean + public NosqlDbConfig nosqlDbConfig(@Qualifier(regionProviderQualifier) RegionProvider regionProvider, + CredentialsProperties properties) throws IOException { + String profile = properties.hasProfile() ? properties.getProfile() : "DEFAULT"; + SignatureProvider signatureProvider; + switch (properties.getType()) { + case WORKLOAD_IDENTITY -> signatureProvider = SignatureProvider.createWithOkeWorkloadIdentity(); + case RESOURCE_PRINCIPAL -> signatureProvider = SignatureProvider.createWithResourcePrincipal(); + case INSTANCE_PRINCIPAL -> + signatureProvider = SignatureProvider.createWithInstancePrincipal(); + case SIMPLE -> signatureProvider = new SignatureProvider( + properties.getTenantId(), + properties.getUserId(), + properties.getFingerprint(), + properties.getPrivateKey(), + properties.getPassPhrase() != null ? properties.getPassPhrase().toCharArray() : null + ); + case SESSION_TOKEN -> { + if (properties.hasFile()) { + signatureProvider = SignatureProvider.createWithSessionToken(properties.getFile(), profile); + } else { + signatureProvider = SignatureProvider.createWithSessionToken(profile); + } + } + default -> { + if (properties.hasFile()) { + signatureProvider = new SignatureProvider(properties.getFile(), profile); + } else { + signatureProvider = new SignatureProvider(profile); + } + + } + } + return new NosqlDbConfig(regionProvider.getRegion().getRegionId(), signatureProvider); + } +} diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json index ebdbd56f..9d2965a0 100644 --- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json +++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/additional-spring-configuration-metadata.json @@ -65,6 +65,12 @@ "type": "java.lang.Boolean", "description": "Auto-configure OCI Autonomous Database components.", "defaultValue": true + }, + { + "name": "spring.cloud.oci.nosql.enabled", + "type": "java.lang.Boolean", + "description": "Auto-configure Oracle NoSQL Database components.", + "defaultValue": true } ] } diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports index fd16f8d8..e960b8c9 100644 --- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports +++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -11,3 +11,4 @@ com.oracle.cloud.spring.genai.GenAIAutoConfiguration com.oracle.cloud.spring.vault.VaultAutoConfiguration com.oracle.cloud.spring.adb.AutonomousDbAutoConfiguration com.oracle.cloud.spring.email.EmailDeliveryAutoConfiguration +com.oracle.cloud.spring.nosql.NoSQLAutoConfiguration diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java index 78252811..07c2c32c 100644 --- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java +++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/autoconfigure/TestCommonConfigurationBeans.java @@ -8,16 +8,24 @@ import com.oracle.bmc.Region; import com.oracle.bmc.auth.BasicAuthenticationDetailsProvider; import com.oracle.bmc.auth.RegionProvider; +import com.oracle.cloud.spring.autoconfigure.core.CredentialsProperties; import com.oracle.cloud.spring.core.compartment.CompartmentProvider; import com.oracle.cloud.spring.core.compartment.StaticCompartmentProvider; import com.oracle.cloud.spring.core.region.StaticRegionProvider; +import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import static org.assertj.core.api.Assertions.assertThat; import static org.mockito.Mockito.mock; @Configuration public class TestCommonConfigurationBeans { + @Bean + CredentialsProperties credentialsProperties() { + return new CredentialsProperties(); + } + @Bean BasicAuthenticationDetailsProvider credentialsProvider() { return mock(BasicAuthenticationDetailsProvider.class); @@ -33,4 +41,17 @@ CompartmentProvider compartmentProvider() { return new StaticCompartmentProvider("compartmentOCID"); } + public static void assertBeanLoaded(AssertableApplicationContext ctx, Class clazz) { + assertBeanLoaded(ctx, clazz, true); + } + + public static void assertBeanNotLoaded(AssertableApplicationContext ctx, Class clazz) { + assertBeanLoaded(ctx, clazz, false); + } + + static void assertBeanLoaded(AssertableApplicationContext ctx, Class clazz, boolean loaded) { + String[] beans = ctx.getBeanNamesForType(clazz); + assertThat(beans).hasSize(loaded ? 2 : 0); + } + } diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfigurationTests.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfigurationTests.java new file mode 100644 index 00000000..d96d3e91 --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/nosql/NoSQLAutoConfigurationTests.java @@ -0,0 +1,30 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ +package com.oracle.cloud.spring.nosql; + +import com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans; +import com.oracle.nosql.spring.data.config.NosqlDbConfig; +import org.junit.jupiter.api.Test; +import org.springframework.boot.autoconfigure.AutoConfigurations; +import org.springframework.boot.test.context.runner.ApplicationContextRunner; + +import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanLoaded; +import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanNotLoaded; + +public class NoSQLAutoConfigurationTests { + private final ApplicationContextRunner contextRunner = new ApplicationContextRunner() + .withPropertyValues("spring.cloud.oci.nosql.enabled=true") + .withConfiguration(AutoConfigurations.of(NoSQLAutoConfiguration.class)) + .withUserConfiguration(TestCommonConfigurationBeans.class); + + @Test + void beansAreLoaded() { + contextRunner.run(ctx -> assertBeanLoaded(ctx, NosqlDbConfig.class)); + } + + @Test + void beansAreNotLoadedWhenDisabled() { + contextRunner.withPropertyValues("spring.cloud.oci.nosql.enabled=false") + .run(ctx -> assertBeanNotLoaded(ctx, NosqlDbConfig.class)); + } +} diff --git a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java index f21236c7..2dfbc516 100644 --- a/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java +++ b/spring-cloud-oci/spring-cloud-oci-autoconfigure/src/test/java/com/oracle/cloud/spring/vault/VaultAutoConfigurationTests.java @@ -5,10 +5,10 @@ import com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans; import org.junit.jupiter.api.Test; import org.springframework.boot.autoconfigure.AutoConfigurations; -import org.springframework.boot.test.context.assertj.AssertableApplicationContext; import org.springframework.boot.test.context.runner.ApplicationContextRunner; -import static org.assertj.core.api.Assertions.assertThat; +import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanLoaded; +import static com.oracle.cloud.spring.autoconfigure.TestCommonConfigurationBeans.assertBeanNotLoaded; public class VaultAutoConfigurationTests { private final String vaultIdProperty = "spring.cloud.oci.vault.vault-id=xyz"; @@ -22,23 +22,18 @@ public class VaultAutoConfigurationTests { @Test void beansAreLoaded() { contextRunner.withPropertyValues(vaultIdProperty) - .run(ctx -> assertVaultTemplateBean(ctx, true)); + .run(ctx -> assertBeanLoaded(ctx, VaultTemplate.class)); } @Test void beansAreNotLoadedWhenDisabled() { contextRunner.withPropertyValues(vaultIdProperty, "spring.cloud.oci.vault.enabled=false") - .run(ctx -> assertVaultTemplateBean(ctx, false)); + .run(ctx -> assertBeanNotLoaded(ctx, VaultTemplate.class)); } @Test void beansAreNotLoadedWhenNoVault() { - contextRunner.run(ctx -> assertVaultTemplateBean(ctx, false)); - } - - private void assertVaultTemplateBean(AssertableApplicationContext ctx, boolean hasBean) { - String[] beans = ctx.getBeanNamesForType(VaultTemplate.class); - assertThat(beans).hasSize(hasBean ? 2 : 0); + contextRunner.run(ctx -> assertBeanNotLoaded(ctx, VaultTemplate.class)); } } diff --git a/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml b/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml index bf13918e..80c10722 100644 --- a/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml +++ b/spring-cloud-oci/spring-cloud-oci-dependencies/pom.xml @@ -157,6 +157,11 @@ spring-cloud-oci-starter-email ${project.version} + + com.oracle.cloud.spring + spring-cloud-oci-starter-nosql + ${project.version} + diff --git a/spring-cloud-oci/spring-cloud-oci-samples/pom.xml b/spring-cloud-oci/spring-cloud-oci-samples/pom.xml index ef7f13f2..0e0f2b90 100644 --- a/spring-cloud-oci/spring-cloud-oci-samples/pom.xml +++ b/spring-cloud-oci/spring-cloud-oci-samples/pom.xml @@ -50,6 +50,7 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or spring-cloud-oci-function-sample spring-cloud-oci-adb-sample spring-cloud-oci-email-sample + spring-cloud-oci-nosql-sample spring-cloud-oci-samples diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/pom.xml b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/pom.xml new file mode 100644 index 00000000..e2fea8bf --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/pom.xml @@ -0,0 +1,77 @@ + + + + + + com.oracle.cloud.spring + spring-cloud-oci-samples + 1.3.0-SNAPSHOT + + 4.0.0 + com.oracle.cloud.spring.sample.nosql + spring-cloud-oci-nosql-sample + spring-cloud-oci-nosql-sample + spring-cloud-oci-nosql-sample + + + Oracle America, Inc. + https://www.oracle.com + + + + + Oracle + obaas_ww at oracle.com + Oracle America, Inc. + https://www.oracle.com + + + + + + The Universal Permissive License (UPL), Version 1.0 + https://oss.oracle.com/licenses/upl/ + repo + + + + + https://github.com/oracle/spring-cloud-oracle + scm:git:https://github.com/oracle/spring-cloud-oracle.git + scm:git:git@github.com:oracle/spring-cloud-oracle.git + + + + 17 + + + + com.oracle.cloud.spring + spring-cloud-oci-starter-nosql + + + com.oracle.cloud.spring.sample.common + spring-cloud-oci-common-samples-utils + + + com.oracle.cloud.spring.sample.common + spring-cloud-oci-common-samples-utils + test-jar + + + + + + + org.springframework.boot + spring-boot-maven-plugin + + + + + + diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/Book.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/Book.java new file mode 100644 index 00000000..3f67d551 --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/Book.java @@ -0,0 +1,75 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ +package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample; + +import com.oracle.nosql.spring.data.core.mapping.NosqlId; +import com.oracle.nosql.spring.data.core.mapping.NosqlTable; + +// Requires a NoSQL table named "books" in your OCI Account. +@NosqlTable(tableName = "books") +public class Book { + @NosqlId(generated = true) + long id; + String title; + String author; + double price; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getTitle() { + return title; + } + + public void setTitle(String title) { + this.title = title; + } + + public String getAuthor() { + return author; + } + + public void setAuthor(String author) { + this.author = author; + } + + public double getPrice() { + return price; + } + + public void setPrice(double price) { + this.price = price; + } + + @Override + public final boolean equals(Object o) { + if (this == o) return true; + if (!(o instanceof Book book)) return false; + + return getId() == book.getId() && Double.compare(getPrice(), book.getPrice()) == 0 && getTitle().equals(book.getTitle()) && getAuthor().equals(book.getAuthor()); + } + + @Override + public int hashCode() { + int result = Long.hashCode(getId()); + result = 31 * result + getTitle().hashCode(); + result = 31 * result + getAuthor().hashCode(); + result = 31 * result + Double.hashCode(getPrice()); + return result; + } + + @Override + public String toString() { + return "Book{" + + "id=" + id + + ", title='" + title + '\'' + + ", author='" + author + '\'' + + ", price=" + price + + '}'; + } +} \ No newline at end of file diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookController.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookController.java new file mode 100644 index 00000000..de4ddaea --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookController.java @@ -0,0 +1,64 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ +package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample; + +import java.util.ArrayList; +import java.util.List; + +import org.springframework.http.HttpStatusCode; +import org.springframework.http.ResponseEntity; +import org.springframework.util.StringUtils; +import org.springframework.web.bind.annotation.DeleteMapping; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/books") +public class BookController { + private final BookRepository bookRepository; + + public BookController(BookRepository bookRepository) { + this.bookRepository = bookRepository; + } + + @GetMapping + public ResponseEntity> getAllBooks(@RequestParam(name = "title", required = false) String title, + @RequestParam(name = "author", required = false) String author) { + List books = new ArrayList<>(); + if (StringUtils.hasText(title)) { + bookRepository.findByTitle(title).forEach(books::add); + } else if (StringUtils.hasText(author)) { + bookRepository.findByAuthor(author).forEach(books::add); + } else { + bookRepository.findAll().forEach(books::add); + } + + return ResponseEntity.ok(books); + } + + @PostMapping + public ResponseEntity addBook(@RequestBody Book book) { + Book created = bookRepository.save(book); + return new ResponseEntity<>(created, HttpStatusCode.valueOf(201)); + } + + @PutMapping + public ResponseEntity updateBook(@RequestBody Book book) { + if (book.getId() < 1) { + return ResponseEntity.badRequest().build(); + } + return addBook(bookRepository.save(book)); + } + + @DeleteMapping("/{id}") + public ResponseEntity deleteBook(@PathVariable(name = "id") Long id) { + bookRepository.deleteById(id); + return ResponseEntity.noContent().build(); + } +} diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookRepository.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookRepository.java new file mode 100644 index 00000000..008343a2 --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/BookRepository.java @@ -0,0 +1,10 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ +package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample; + +import com.oracle.nosql.spring.data.repository.NosqlRepository; + +public interface BookRepository extends NosqlRepository { + Iterable findByAuthor(String author); + Iterable findByTitle(String title); +} \ No newline at end of file diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/SpringCloudOciNoSQLSampleApplication.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/SpringCloudOciNoSQLSampleApplication.java new file mode 100644 index 00000000..ec6061df --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/SpringCloudOciNoSQLSampleApplication.java @@ -0,0 +1,16 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ +package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample; + +import com.oracle.nosql.spring.data.config.AbstractNosqlConfiguration; +import com.oracle.nosql.spring.data.repository.config.EnableNosqlRepositories; +import org.springframework.boot.SpringApplication; +import org.springframework.boot.autoconfigure.SpringBootApplication; + +@SpringBootApplication +@EnableNosqlRepositories +public class SpringCloudOciNoSQLSampleApplication extends AbstractNosqlConfiguration { + public static void main(String[] args) { + SpringApplication.run(SpringCloudOciNoSQLSampleApplication.class, args); + } +} diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/resources/application.yaml b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/resources/application.yaml new file mode 100644 index 00000000..a9f0eeb1 --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/main/resources/application.yaml @@ -0,0 +1,7 @@ +spring: + cloud: + oci: + config: + type: file + region: + static: us-ashburn-1 diff --git a/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/test/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/NoSQLSampleApplicationIT.java b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/test/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/NoSQLSampleApplicationIT.java new file mode 100644 index 00000000..c62dbddc --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-samples/spring-cloud-oci-nosql-sample/src/test/java/com/oracle/cloud/spring/sample/nosql/springcloudnosqlsample/NoSQLSampleApplicationIT.java @@ -0,0 +1,67 @@ +// Copyright (c) 2024, Oracle and/or its affiliates. +// Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/ +package com.oracle.cloud.spring.sample.nosql.springcloudnosqlsample; + +import java.util.List; + +import org.junit.jupiter.api.Test; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.context.SpringBootTest; + +import static org.assertj.core.api.Assertions.assertThat; + +@SpringBootTest +public class NoSQLSampleApplicationIT { + @Autowired + private BookController bookController; + + @Autowired + BookRepository bookRepository; + + @Test + void bookControllerTest() { + // clear the book database before running the test + bookRepository.deleteAll(); + // Create three Book objects + Book book1 = new Book(); + book1.setTitle("To Kill a Mockingbird"); + book1.setAuthor("Harper Lee"); + book1.setPrice(12.99); + + Book book2 = new Book(); + book2.setTitle("1984"); + book2.setAuthor("George Orwell"); + book2.setPrice(10.99); + + Book book3 = new Book(); + book3.setTitle("Animal Farm"); + book3.setAuthor("George Orwell"); // Same author as book2 + book3.setPrice(9.99); + + Book created1 = bookController.addBook(book1).getBody(); + Book created2 = bookController.addBook(book2).getBody(); + Book created3 = bookController.addBook(book3).getBody(); + + // Query books based on author + List georgeOrwellBooks = bookController.getAllBooks(null, "George Orwell").getBody(); + assertThat(georgeOrwellBooks).hasSize(2); + + // Query books based on title + List titleQueryBooks = bookController.getAllBooks("To Kill a Mockingbird", null).getBody(); + assertThat(titleQueryBooks).hasSize(1); + assertThat(titleQueryBooks.get(0)).isEqualTo(created1); + + // Update book + assertThat(created3).isNotNull(); + created3.setPrice(25.00); + Book updated3 = bookController.updateBook(created3).getBody(); + assertThat(updated3).isNotNull(); + assertThat(updated3.getPrice()).isEqualTo(25.0); + + // Delete book and verify it's gone + assertThat(created2).isNotNull(); + bookController.deleteBook(created2.getId()); + List title1984Books = bookController.getAllBooks("1984", null).getBody(); + assertThat(title1984Books).hasSize(0); + } +} diff --git a/spring-cloud-oci/spring-cloud-oci-starters/pom.xml b/spring-cloud-oci/spring-cloud-oci-starters/pom.xml index 03b6492f..527d88a8 100644 --- a/spring-cloud-oci/spring-cloud-oci-starters/pom.xml +++ b/spring-cloud-oci/spring-cloud-oci-starters/pom.xml @@ -59,6 +59,7 @@ Licensed under the Universal Permissive License v 1.0 as shown at https://oss.or spring-cloud-oci-starter-queue spring-cloud-oci-starter-function spring-cloud-oci-starter-email + spring-cloud-oci-starter-nosql \ No newline at end of file diff --git a/spring-cloud-oci/spring-cloud-oci-starters/spring-cloud-oci-starter-nosql/pom.xml b/spring-cloud-oci/spring-cloud-oci-starters/spring-cloud-oci-starter-nosql/pom.xml new file mode 100644 index 00000000..18387a3f --- /dev/null +++ b/spring-cloud-oci/spring-cloud-oci-starters/spring-cloud-oci-starter-nosql/pom.xml @@ -0,0 +1,60 @@ + + + + + 4.0.0 + + spring-cloud-oci-starters + com.oracle.cloud.spring + 1.3.0-SNAPSHOT + + + spring-cloud-oci-starter-nosql + Spring Cloud Oracle NoSQL Starter Module + Spring Cloud Oracle NoSQL Starter Module + https://github.com/oracle/spring-cloud-oci/#spring-cloud-oci-documentation + + + Oracle America, Inc. + https://www.oracle.com + + + + + Oracle + obaas_ww at oracle.com + Oracle America, Inc. + https://www.oracle.com + + + + + + The Universal Permissive License (UPL), Version 1.0 + https://oss.oracle.com/licenses/upl/ + repo + + + + + https://github.com/oracle/spring-cloud-oracle + scm:git:https://github.com/oracle/spring-cloud-oracle.git + scm:git:git@github.com:oracle/spring-cloud-oracle.git + + + + + com.oracle.cloud.spring + spring-cloud-oci-starter + + + com.oracle.nosql.sdk + spring-data-oracle-nosql + + + +