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

OCI examples remove reactive API #6969

Merged
Merged
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

This file was deleted.

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Helidon ATP Reactive Examples
# Helidon ATP Nima Examples

This example demonstrates how user can easily retrieve wallet from their ATP instance running in OCI and use information from that wallet to setup DataSource to do Database operations.

Expand All @@ -16,7 +16,7 @@ Once you have updated required properties, you can run the example:

```shell script
mvn clean install
java -jar ./target/helidon-examples-integrations-oci-atp-reactive.jar
java -jar ./target/helidon-examples-integrations-oci-atp.jar
```

To verify that, you can retrieve wallet and do database operation:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,18 +29,18 @@
</parent>

<groupId>io.helidon.examples.integrations.oci</groupId>
<artifactId>helidon-examples-integrations-oci-atp-reactive</artifactId>
<name>Helidon Examples Integration OCI ATP Reactive</name>
<description>Reactive integration with OCI ATP.</description>
<artifactId>helidon-examples-integrations-oci-atp</artifactId>
<name>Helidon Examples Integration OCI ATP Nima</name>
<description>Nima integration with OCI ATP.</description>

<properties>
<mainClass>io.helidon.examples.integrations.oci.atp.reactive.OciAtpMain</mainClass>
<mainClass>io.helidon.examples.integrations.oci.atp.OciAtpMain</mainClass>
</properties>

<dependencies>
<dependency>
<groupId>io.helidon.reactive.webserver</groupId>
<artifactId>helidon-reactive-webserver</artifactId>
<groupId>io.helidon.nima.webserver</groupId>
<artifactId>helidon-nima-webserver</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.reactive.dbclient</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021, 2022 Oracle and/or its affiliates.
* Copyright (c) 2021, 2023 Oracle and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -14,14 +14,15 @@
* limitations under the License.
*/

package io.helidon.examples.integrations.oci.atp.reactive;
package io.helidon.examples.integrations.oci.atp;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.sql.SQLException;
import java.time.Duration;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.zip.ZipEntry;
Expand All @@ -32,16 +33,19 @@
import javax.net.ssl.TrustManagerFactory;

import io.helidon.common.http.Http;
import io.helidon.common.reactive.Single;
import io.helidon.config.Config;
import io.helidon.config.ConfigException;
aserkes marked this conversation as resolved.
Show resolved Hide resolved
import io.helidon.nima.webserver.http.HttpRules;
import io.helidon.nima.webserver.http.HttpService;
import io.helidon.nima.webserver.http.ServerRequest;
import io.helidon.nima.webserver.http.ServerResponse;
import io.helidon.reactive.dbclient.DbClient;
import io.helidon.reactive.dbclient.jdbc.JdbcDbClientProvider;
import io.helidon.reactive.webserver.Routing;
import io.helidon.reactive.webserver.ServerRequest;
import io.helidon.reactive.webserver.ServerResponse;
import io.helidon.reactive.webserver.Service;

import com.oracle.bmc.database.DatabaseAsync;
import com.oracle.bmc.ConfigFileReader;
import com.oracle.bmc.auth.AuthenticationDetailsProvider;
import com.oracle.bmc.auth.ConfigFileAuthenticationDetailsProvider;
import com.oracle.bmc.database.DatabaseClient;
import com.oracle.bmc.database.model.GenerateAutonomousDatabaseWalletDetails;
import com.oracle.bmc.database.requests.GenerateAutonomousDatabaseWalletRequest;
import com.oracle.bmc.database.responses.GenerateAutonomousDatabaseWalletResponse;
Expand All @@ -50,45 +54,48 @@
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

class AtpService implements Service {
class AtpService implements HttpService {
private static final Logger LOGGER = Logger.getLogger(AtpService.class.getName());

private final DatabaseAsync databaseAsyncClient;
private final DatabaseClient databaseClient;
private final Config config;

AtpService(DatabaseAsync databaseAsyncClient, Config config) {
this.databaseAsyncClient = databaseAsyncClient;
this.config = config;
AtpService(Config config) {
try {
// this requires OCI configuration in the usual place
// ~/.oci/config
AuthenticationDetailsProvider authProvider = new ConfigFileAuthenticationDetailsProvider(ConfigFileReader.parseDefault());
databaseClient = DatabaseClient.builder().build(authProvider);
this.config = config;
} catch (IOException e) {
throw new ConfigException("Failed to read configuration properties", e);
}
}

@Override
public void update(Routing.Rules rules) {
/**
* A service registers itself by updating the routine rules.
*
* @param rules the routing rules.
*/
public void routing(HttpRules rules) {
rules.get("/wallet", this::generateWallet);
}

/**
* Generate wallet file for the configured ATP.
*
* @param req request
* @param res response
*/
private void generateWallet(ServerRequest req, ServerResponse res) {
OciResponseHandler<GenerateAutonomousDatabaseWalletRequest,
GenerateAutonomousDatabaseWalletResponse> walletHandler =
new OciResponseHandler<>();
GenerateAutonomousDatabaseWalletResponse walletResponse = null;
try {
databaseAsyncClient.generateAutonomousDatabaseWallet(
GenerateAutonomousDatabaseWalletRequest.builder()
.autonomousDatabaseId(config.get("oci.atp.ocid").asString().get())
.generateAutonomousDatabaseWalletDetails(
GenerateAutonomousDatabaseWalletDetails.builder()
.password(config.get("oci.atp.walletPassword").asString().get())
.build())
.build(), walletHandler);
walletResponse = walletHandler.waitForCompletion();
} catch (Exception e) {
LOGGER.log(Level.SEVERE, "Error waiting for GenerateAutonomousDatabaseWalletResponse", e);
res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send();
return;
}
GenerateAutonomousDatabaseWalletResponse walletResponse = databaseClient.generateAutonomousDatabaseWallet(
GenerateAutonomousDatabaseWalletRequest.builder()
.autonomousDatabaseId(config.get("oci.atp.ocid").asString().get())
.generateAutonomousDatabaseWalletDetails(
GenerateAutonomousDatabaseWalletDetails.builder()
.password(config.get("oci.atp.walletPassword").asString().get())
.build())
.build());

if (walletResponse.getContentLength() == 0) {
LOGGER.log(Level.SEVERE, "GenerateAutonomousDatabaseWalletResponse is empty");
Expand All @@ -101,20 +108,27 @@ private void generateWallet(ServerRequest req, ServerResponse res) {
walletContent = walletResponse.getInputStream().readAllBytes();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Error processing GenerateAutonomousDatabaseWalletResponse", e);
res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send();
res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(e.getMessage());
return;
}

createDbClient(walletContent)
.flatMap(dbClient -> dbClient.execute(exec -> exec.query("SELECT 'Hello world!!' FROM DUAL")))
.first()
.map(dbRow -> dbRow.column(1).as(String.class))
.ifEmpty(() -> res.status(404).send())
.onError(res::send)
.forSingle(res::send);
try {
String result = createDbClient(walletContent)
.execute(exec -> exec.query("SELECT 'Hello world!!' FROM DUAL"))
.first()
.map(dbRow -> dbRow.column(1).as(String.class))
.await(Duration.ofSeconds(60));
if (result == null || result.isEmpty()) {
res.status(Http.Status.NOT_FOUND_404).send();
} else {
res.send(result);
}
} catch (Exception e) {
res.status(Http.Status.INTERNAL_SERVER_ERROR_500).send(e.getMessage());
}
}

Single<DbClient> createDbClient(byte[] walletContent) {
DbClient createDbClient(byte[] walletContent) {
PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
try {
pds.setSSLContext(getSSLContext(walletContent));
Expand All @@ -123,22 +137,23 @@ Single<DbClient> createDbClient(byte[] walletContent) {
.orElseThrow(() -> new IllegalStateException("Missing tnsNetServiceName!!"))));
pds.setUser(config.get("db.userName").as(String.class).orElse("ADMIN"));
pds.setPassword(config.get("db.password")
.as(String.class)
.orElseThrow(() -> new IllegalStateException("Missing password!!")));
.as(String.class)
.orElseThrow(() -> new IllegalStateException("Missing password!!")));
pds.setConnectionFactoryClassName(OracleDataSource.class.getName());
} catch (SQLException e) {
LOGGER.log(Level.SEVERE, "Error setting up PoolDataSource", e);
return Single.error(e);
throw new RuntimeException(e);
}
return Single.just(new JdbcDbClientProvider().builder()
.connectionPool(() -> {
try {
return pds.getConnection();
} catch (SQLException e) {
throw new IllegalStateException("Error while setting up new connection", e);
}
})
.build());

return new JdbcDbClientProvider().builder()
.connectionPool(() -> {
try {
return pds.getConnection();
} catch (SQLException e) {
throw new IllegalStateException("Error while setting up new connection", e);
}
})
.build();
}

/**
Expand Down Expand Up @@ -174,8 +189,8 @@ private static SSLContext getSSLContext(byte[] walletContent) throws IllegalStat
/**
* Returns JDBC URL with connection description for the given service based on tnsnames.ora in wallet.
*
* @param walletContent
* @param tnsNetServiceName
* @param walletContent walletContent
* @param tnsNetServiceName tnsNetServiceName
* @return String
*/
private static String getJdbcUrl(byte[] walletContent, String tnsNetServiceName) throws IllegalStateException {
Expand Down
Loading