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 Integration Examples Update 2.x #4502

Merged
merged 15 commits into from
Jul 22, 2022
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
3 changes: 3 additions & 0 deletions docs/se/oci/01_oci.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ It is recommended that you use the OCI Java SDK directly, in particular the Asyn
For more information see:

* link:{oci-url}[OCI Documentation ]
* link:{helidon-tag}/examples/integrations/oci/atp-reactive/[Helidon SE OCI ATP Example]
* link:{helidon-tag}/examples/integrations/oci/objectstorage-reactive/[Helidon SE OCI Object Storage Example]
* link:{helidon-tag}/examples/integrations/oci/metrics-reactive/[Helidon SE OCI Metrics Example]
* link:{helidon-tag}/examples/integrations/oci/vault-reactive/[Helidon SE OCI Vault Example]

== Experimental
Expand Down
2 changes: 1 addition & 1 deletion docs/se/oci/02_object-storage.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use the OCI Java SDK directly, in particular the Async clients. For more informa

* link:{oci-objstore-url}[OCI Object Storage Documentation ]
* link:{oci-objstore-javadoc}[OCI Object Storage Javadoc ]
* link:{helidon-tag}/examples/integrations/oci/vault-reactive/[Helidon SE OCI Vault Example]
* link:{helidon-tag}/examples/integrations/oci/objectstorage-reactive/[Helidon SE OCI Object Storage Example]

== Experimental

Expand Down
2 changes: 1 addition & 1 deletion docs/se/oci/04_atp.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ use the OCI Java SDK directly, in particular the Async clients. For more informa

* link:{oci-atp-url}[OCI Database Documentation ]
* link:{oci-atp-javadoc}[OCI Database Javadoc ]
* link:{helidon-tag}/examples/integrations/oci/vault-reactive/[Helidon SE OCI Vault Example]
* link:{helidon-tag}/examples/integrations/oci/atp-reactive/[Helidon SE OCI ATP Example]

== Experimental

Expand Down
10 changes: 5 additions & 5 deletions examples/integrations/oci/atp-cdi/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>io.helidon.applications</groupId>
<artifactId>helidon-mp</artifactId>
<version>2.4.2-SNAPSHOT</version>
<version>2.5.2-SNAPSHOT</version>
<relativePath>../../../../applications/mp/pom.xml</relativePath>
</parent>

Expand All @@ -48,12 +48,12 @@
<type>pom</type>
</dependency>
<dependency>
<groupId>io.helidon.integrations.oci</groupId>
<artifactId>helidon-integrations-oci-cdi</artifactId>
<groupId>io.helidon.integrations.oci.sdk</groupId>
<artifactId>helidon-integrations-oci-sdk-cdi</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.integrations.oci</groupId>
<artifactId>helidon-integrations-oci-atp</artifactId>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-database</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.config</groupId>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
* Copyright (c) 2021, 2022 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 @@ -16,27 +16,37 @@

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

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.security.KeyStore;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Objects;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.util.Objects;
import java.util.Optional;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;

import javax.inject.Inject;
import javax.inject.Named;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManagerFactory;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.core.Response;

import io.helidon.integrations.common.rest.ApiOptionalResponse;
import io.helidon.integrations.oci.atp.OciAutonomousDb;
import io.helidon.integrations.oci.atp.GenerateAutonomousDatabaseWallet;

import com.oracle.bmc.database.Database;
import com.oracle.bmc.database.model.GenerateAutonomousDatabaseWalletDetails;
import com.oracle.bmc.database.requests.GenerateAutonomousDatabaseWalletRequest;
import com.oracle.bmc.database.responses.GenerateAutonomousDatabaseWalletResponse;
import com.oracle.bmc.http.internal.ResponseHelper;
import oracle.security.pki.OraclePKIProvider;
import oracle.ucp.jdbc.PoolDataSource;

import org.eclipse.microprofile.config.inject.ConfigProperty;
/**
* JAX-RS resource - REST API for the atp example.
Expand All @@ -45,16 +55,23 @@
public class AtpResource {
private static final Logger LOGGER = Logger.getLogger(AtpResource.class.getName());

private final OciAutonomousDb autonomousDb;
private final Database databaseClient;
private final PoolDataSource atpDataSource;
private final String atpTnsNetServiceName;

private final String atpOcid;
private final String walletPassword;

@Inject
AtpResource(OciAutonomousDb autonomousDb, @Named("atp") PoolDataSource atpDataSource,
@ConfigProperty(name = "oracle.ucp.jdbc.PoolDataSource.atp.tnsNetServiceName") String atpTnsNetServiceName) {
this.autonomousDb = autonomousDb;
AtpResource(Database databaseClient, @Named("atp") PoolDataSource atpDataSource,
@ConfigProperty(name = "oracle.ucp.jdbc.PoolDataSource.atp.tnsNetServiceName") String atpTnsNetServiceName,
@ConfigProperty(name = "oci.atp.ocid") String atpOcid,
@ConfigProperty(name = "oci.atp.walletPassword") String walletPassword) {
this.databaseClient = databaseClient;
this.atpDataSource = Objects.requireNonNull(atpDataSource);
this.atpTnsNetServiceName = atpTnsNetServiceName;
this.atpOcid = atpOcid;
this.walletPassword = walletPassword;
}

/**
Expand All @@ -65,21 +82,34 @@ public class AtpResource {
@GET
@Path("/wallet")
public Response generateWallet() {
ApiOptionalResponse<GenerateAutonomousDatabaseWallet.Response> ociResponse = autonomousDb.generateWallet(GenerateAutonomousDatabaseWallet.Request.builder());
Optional<GenerateAutonomousDatabaseWallet.Response> entity = ociResponse.entity();
ResponseHelper.shouldAutoCloseResponseInputStream(false);
GenerateAutonomousDatabaseWalletResponse walletResponse =
databaseClient.generateAutonomousDatabaseWallet(
GenerateAutonomousDatabaseWalletRequest.builder()
.autonomousDatabaseId(this.atpOcid)
.generateAutonomousDatabaseWalletDetails(
GenerateAutonomousDatabaseWalletDetails.builder()
.password(this.walletPassword)
.build())
.build());

if (entity.isEmpty()) {
LOGGER.log(Level.SEVERE, "GenerateAutonomousDatabaseWallet.Response is empty");
if (walletResponse.getContentLength() == 0) {
LOGGER.log(Level.SEVERE, "GenerateAutonomousDatabaseWalletResponse is empty");
return Response.status(Response.Status.NOT_FOUND).build();
}

GenerateAutonomousDatabaseWallet.Response response = entity.get();
GenerateAutonomousDatabaseWallet.WalletArchive walletArchive = response.walletArchive();
byte[] walletContent = null;
try {
walletContent = walletResponse.getInputStream().readAllBytes();
} catch (IOException e) {
LOGGER.log(Level.SEVERE, "Error processing GenerateAutonomousDatabaseWalletResponse", e);
return Response.status(Response.Status.INTERNAL_SERVER_ERROR).build();
}
String returnEntity = null;
try {
this.atpDataSource.setSSLContext(walletArchive.getSSLContext());
this.atpDataSource.setURL(walletArchive.getJdbcUrl(this.atpTnsNetServiceName));
try(
this.atpDataSource.setSSLContext(getSSLContext(walletContent));
this.atpDataSource.setURL(getJdbcUrl(walletContent, this.atpTnsNetServiceName));
try (
Connection connection = this.atpDataSource.getConnection();
PreparedStatement ps = connection.prepareStatement("SELECT 'Hello world!!' FROM DUAL");
ResultSet rs = ps.executeQuery()
Expand All @@ -94,5 +124,61 @@ public Response generateWallet() {

return Response.status(Response.Status.OK).entity(returnEntity).build();
}

/**
* Returns SSLContext based on cwallet.sso in wallet.
*
* @param walletContent
* @return SSLContext
*/
private static SSLContext getSSLContext(byte[] walletContent) throws IllegalStateException {
SSLContext sslContext = null;
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) {
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().equals("cwallet.sso")) {
KeyStore keyStore = KeyStore.getInstance("SSO", new OraclePKIProvider());
keyStore.load(zis, null);
TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance("PKIX");
KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance("PKIX");
trustManagerFactory.init(keyStore);
keyManagerFactory.init(keyStore, null);
sslContext = SSLContext.getInstance("TLS");
sslContext.init(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), null);
}
zis.closeEntry();
}
} catch (RuntimeException | Error throwMe) {
throw throwMe;
} catch (Exception e) {
throw new IllegalStateException("Error while getting SSLContext from wallet.", e);
}
return sslContext;
}

/**
* Returns JDBC URL with connection description for the given service based on tnsnames.ora in wallet.
*
* @param walletContent
* @param tnsNetServiceName
* @return String
*/
private static String getJdbcUrl(byte[] walletContent, String tnsNetServiceName) throws IllegalStateException {
String jdbcUrl = null;
try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(new ByteArrayInputStream(walletContent)))) {
ZipEntry entry = null;
while ((entry = zis.getNextEntry()) != null) {
if (entry.getName().equals("tnsnames.ora")) {
jdbcUrl = new String(zis.readAllBytes(), StandardCharsets.UTF_8)
.replaceFirst(tnsNetServiceName + "\\s*=\\s*", "jdbc:oracle:thin:@")
.replaceAll("\\n[^\\n]+", "");
}
zis.closeEntry();
}
} catch (IOException e) {
throw new IllegalStateException("Error while getting JDBC URL from wallet.", e);
}
return jdbcUrl;
}
}

10 changes: 5 additions & 5 deletions examples/integrations/oci/atp-cdi/src/main/java/module-info.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2021 Oracle and/or its affiliates.
* Copyright (c) 2021, 2022 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 @@ -22,16 +22,16 @@
requires java.naming;
requires java.sql;
requires java.ws.rs;
requires jakarta.inject.api;

requires microprofile.config.api;

requires io.helidon.config.yaml.mp;
requires io.helidon.integrations.common.rest;
requires io.helidon.integrations.oci.cdi;
requires io.helidon.integrations.oci.atp;
requires io.helidon.microprofile.cdi;

requires oci.java.sdk.common;
requires oci.java.sdk.database;
requires com.oracle.database.ucp;
requires oraclepki;

exports io.helidon.examples.integrations.oci.atp.cdi;
}
2 changes: 1 addition & 1 deletion examples/integrations/oci/atp-reactive/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Before running the test, make sure to update required properties in `application

- oci.atp.ocid: This is OCID of your running ATP instance.
- oci.atp.walletPassword: password to encrypt the keys inside the wallet. The password must be at least 8 characters long and must include at least 1 letter and either 1 numeric character or 1 special character.
- oracle.ucp.jdbc.PoolDataSource.atp.tnsNetServiceName: netServiceName of your database running inside OCI ATP as can be found in `tnsnames.ora` file.
- db.tnsNetServiceName: netServiceName of your database running inside OCI ATP as can be found in `tnsnames.ora` file.
- db.userName: User to access your database running inside OCI ATP.
- db.password: Password of user to access your database running inside OCI ATP.

Expand Down
12 changes: 9 additions & 3 deletions examples/integrations/oci/atp-reactive/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
<parent>
<groupId>io.helidon.applications</groupId>
<artifactId>helidon-se</artifactId>
<version>2.4.2-SNAPSHOT</version>
<version>2.5.2-SNAPSHOT</version>
<relativePath>../../../../applications/se/pom.xml</relativePath>
</parent>

Expand Down Expand Up @@ -60,8 +60,14 @@
<artifactId>helidon-config-yaml</artifactId>
</dependency>
<dependency>
<groupId>io.helidon.integrations.oci</groupId>
<artifactId>helidon-integrations-oci-atp</artifactId>
<groupId>com.oracle.oci.sdk</groupId>
<artifactId>oci-java-sdk-database</artifactId>
</dependency>
<dependency>
<!-- required by SDK -->
arjav-desai marked this conversation as resolved.
Show resolved Hide resolved
<groupId>jakarta.inject</groupId>
<artifactId>jakarta.inject-api</artifactId>
<scope>runtime</scope>
</dependency>
</dependencies>

Expand Down
Loading