diff --git a/java/jdbc-reactive-extensions-intro/pom.xml b/java/jdbc-reactive-extensions-intro/pom.xml new file mode 100644 index 00000000..f00a4998 --- /dev/null +++ b/java/jdbc-reactive-extensions-intro/pom.xml @@ -0,0 +1,74 @@ + + + + 4.0.0 + + com.oracle.jdbc.reactive + jdbc-reactive-extensions-intro + 1.0-SNAPSHOT + jdbc-reactive-extensions-intro + + + UTF-8 + 21 + 21 + + + + + com.oracle.database.jdbc + ojdbc17-production + 23.7.0.25.01 + pom + + + + + + + + maven-clean-plugin + 3.1.0 + + + maven-site-plugin + 3.7.1 + + + maven-project-info-reports-plugin + 3.0.0 + + + + maven-resources-plugin + 3.0.2 + + + maven-compiler-plugin + 3.8.0 + + + maven-surefire-plugin + 2.22.1 + + + maven-jar-plugin + 3.0.2 + + + maven-install-plugin + 2.5.2 + + + maven-deploy-plugin + 2.8.2 + + + + + + diff --git a/java/jdbc-reactive-extensions-intro/src/main/java/com/oracle/jdbc/reactive/DatabaseConfig.java b/java/jdbc-reactive-extensions-intro/src/main/java/com/oracle/jdbc/reactive/DatabaseConfig.java new file mode 100644 index 00000000..9aea8534 --- /dev/null +++ b/java/jdbc-reactive-extensions-intro/src/main/java/com/oracle/jdbc/reactive/DatabaseConfig.java @@ -0,0 +1,120 @@ +/* + Copyright (c) 2024, Oracle and/or its affiliates. + + This software is dual-licensed to you under the Universal Permissive License + (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License + 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose + either license. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.oracle.jdbc.reactive; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.pool.OracleDataSource; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.sql.SQLException; +import java.util.Properties; + +public class DatabaseConfig { + + private static final ConfigData CONFIG_DATA = loadConfig(); + + private static ConfigData loadConfig() { + Properties properties = new Properties(); + try { + var fileStream = Files.newInputStream(Path.of("src/main/resources/config.properties")); + properties.load(fileStream); + return new ConfigData(properties.getProperty("DRIVER"), properties.getProperty("USER"), + properties.getProperty("PASSWORD"), properties.getProperty("HOST"), + Integer.parseInt(properties.getProperty("PORT")), properties.getProperty("DATABASE"), + properties.getProperty("DB_TABLE_NAME")); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + } + + public static OracleDataSource getDataSource() throws SQLException { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration data is not available, check file path."); + } + OracleDataSource dataSource = new OracleDataSource(); + dataSource + .setURL("jdbc:oracle:thin:@" + CONFIG_DATA.host() + ":" + CONFIG_DATA.port() + "/" + CONFIG_DATA.database()); + dataSource.setUser(CONFIG_DATA.user()); + dataSource.setPassword(CONFIG_DATA.password()); + return dataSource; + } + + public static OracleConnection getConnection() throws SQLException { + return (OracleConnection) getDataSource().getConnection(); + } + + public static String getDbTableName() { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration could not be loaded."); + } + return CONFIG_DATA.dbTableName(); + } + + public static String getDriver() { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration could not be loaded."); + } + return CONFIG_DATA.driver(); + } + + public static String getUser() { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration could not be loaded."); + } + return CONFIG_DATA.user(); + } + + public static String getPassword() { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration could not be loaded."); + } + return CONFIG_DATA.password(); + } + + public static String getHost() { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration could not be loaded."); + } + return CONFIG_DATA.host(); + } + + public static int getPort() { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration could not be loaded."); + } + return CONFIG_DATA.port(); + } + + public static String getDatabase() { + if (CONFIG_DATA == null) { + throw new IllegalStateException("Configuration could not be loaded."); + } + return CONFIG_DATA.database(); + } + + private record ConfigData(String driver, String user, String password, String host, int port, String database, + String dbTableName) { + } +} \ No newline at end of file diff --git a/java/jdbc-reactive-extensions-intro/src/main/java/com/oracle/jdbc/reactive/SQLStatementWithAsynchronousJDBC.java b/java/jdbc-reactive-extensions-intro/src/main/java/com/oracle/jdbc/reactive/SQLStatementWithAsynchronousJDBC.java new file mode 100644 index 00000000..ac65d50b --- /dev/null +++ b/java/jdbc-reactive-extensions-intro/src/main/java/com/oracle/jdbc/reactive/SQLStatementWithAsynchronousJDBC.java @@ -0,0 +1,178 @@ +/* + Copyright (c) 2024, Oracle and/or its affiliates. + + This software is dual-licensed to you under the Universal Permissive License + (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl or Apache License + 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose + either license. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + https://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + +package com.oracle.jdbc.reactive; + +import java.sql.SQLException; +import java.util.concurrent.Flow; +import java.util.concurrent.SubmissionPublisher; +import java.util.stream.IntStream; + +import oracle.jdbc.OracleConnection; +import oracle.jdbc.OraclePreparedStatement; +import oracle.jdbc.OracleResultSet; +import oracle.jdbc.OracleStatement; + +public class SQLStatementWithAsynchronousJDBC { + + public static void main(String[] args) throws InterruptedException { + SQLStatementWithAsynchronousJDBC asyncSQL = new SQLStatementWithAsynchronousJDBC(); + try (OracleConnection conn = DatabaseConfig.getConnection()) { + asyncSQL.createTable(conn); + IntStream.rangeClosed(0, 3).forEach(i -> asyncSQL.insertData(conn, i, "Java " + i, "Duke " + i)); + asyncSQL.readData(conn); + Thread.sleep(5000); + asyncSQL.dropTable(conn); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private Flow.Publisher insertData(OracleConnection connection, int id, String firstName, String lastName) { + try { + final OraclePreparedStatement insertStatement = (OraclePreparedStatement) connection + .prepareStatement("INSERT INTO employee_names (id, first_name, last_name) VALUES (?, ?, ?)"); + insertStatement.setInt(1, id); + insertStatement.setString(2, firstName); + insertStatement.setString(3, lastName); + + Flow.Publisher insertPublisher = insertStatement.unwrap(OraclePreparedStatement.class) + .executeAsyncOracle(); + + insertPublisher.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(1L); + } + + public void onNext(Boolean item) { + } + + public void onError(Throwable throwable) { + closeStatement(); + throwable.printStackTrace(); + } + + public void onComplete() { + closeStatement(); + } + + void closeStatement() { + try { + if (insertStatement != null && !insertStatement.isClosed()) { + insertStatement.close(); + } + } catch (SQLException closeException) { + closeException.printStackTrace(); + } + } + }); + + return insertPublisher; + } catch (SQLException e) { + e.printStackTrace(); + SubmissionPublisher publisher = new SubmissionPublisher<>(); + publisher.close(); + return publisher; + } + } + + public Flow.Publisher readData(OracleConnection connection) { + try { + final OraclePreparedStatement readStatement = (OraclePreparedStatement) connection + .prepareStatement("SELECT * FROM employee_names WHERE first_name LIKE ?"); + readStatement.setString(1, "Jav%"); + + Flow.Publisher readPublisher = readStatement.unwrap(OraclePreparedStatement.class) + .executeQueryAsyncOracle(); + + readPublisher.subscribe(new Flow.Subscriber() { + private Flow.Subscription subscription; + + public void onSubscribe(Flow.Subscription subscription) { + this.subscription = subscription; + subscription.request(Long.MAX_VALUE); + } + + public void onNext(OracleResultSet resultSet) { + try { + while (resultSet.next()) { + int id = resultSet.getInt("id"); + String firstName = resultSet.getString("first_name"); + String lastName = resultSet.getString("last_name"); + System.out.println("ID: " + id + ", First Name: " + firstName + ", Last Name: " + lastName); + } + System.out.println("Finished receiving stream data successfully. \nPreparing to drop table..."); + } catch (SQLException e) { + onError(e); + } + } + + public void onError(Throwable throwable) { + closeStatement(); + throwable.printStackTrace(); + } + + public void onComplete() { + closeStatement(); + } + + void closeStatement() { + try { + if (readStatement != null && !readStatement.isClosed()) { + readStatement.close(); + } + } catch (SQLException closeException) { + closeException.printStackTrace(); + } + } + }); + return readPublisher; + } catch (SQLException e) { + e.printStackTrace(); + SubmissionPublisher publisher = new SubmissionPublisher<>(); + publisher.close(); + return publisher; + } + } + + private void createTable(OracleConnection connection) { + String createTableSQL = "CREATE TABLE employee_names (id NUMBER PRIMARY KEY, first_name VARCHAR2(50), last_name VARCHAR2(50))"; + try (OracleStatement createTableStatement = (OracleStatement) connection.createStatement()) { + createTableStatement.execute(createTableSQL); + System.out.println("Table 'employee_names' created successfully."); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + private void dropTable(OracleConnection connection) { + String dropTableSQL = "DROP TABLE employee_names"; + try (OracleStatement dropTableStatement = (OracleStatement) connection.createStatement()) { + dropTableStatement.execute(dropTableSQL); + System.out.println("Table 'employee_names' dropped successfully."); + } catch (SQLException e) { + e.printStackTrace(); + } + } +} diff --git a/java/jdbc-reactive-extensions-intro/src/main/resources/config.properties b/java/jdbc-reactive-extensions-intro/src/main/resources/config.properties new file mode 100644 index 00000000..562d101d --- /dev/null +++ b/java/jdbc-reactive-extensions-intro/src/main/resources/config.properties @@ -0,0 +1,7 @@ +HOST= +PORT= +DATABASE= +USER= +SCHEMA= +DB_TABLE_NAME=employee_names \ No newline at end of file diff --git a/java/jdbc-reactive-extensions-intro/src/sql/jdbc-reactive-extensions-intro.sql b/java/jdbc-reactive-extensions-intro/src/sql/jdbc-reactive-extensions-intro.sql new file mode 100644 index 00000000..1c1f69b4 --- /dev/null +++ b/java/jdbc-reactive-extensions-intro/src/sql/jdbc-reactive-extensions-intro.sql @@ -0,0 +1,33 @@ +-- THIS TABLE IS CREATED FROM JAVA CODE -> SQLStatementWithAsynchronousJDBC.java -> createTable() method +-- CREATE TABLE employee_names (id NUMBER PRIMARY KEY, first_name VARCHAR2(50), last_name VARCHAR2(50)) + +--IF YOU WANT TO CONFIRM YOU HAVE A TABLE WHILE ON DEBUGBING MODE +DESCRIBE employee_names; + +--IF YOU WANT TO CHECK THE TABLE RECORDS WHILE ON DEBUGGING MODE +SELECT * FROM employee_names; + +/* + +INSERT INTO employee_names (id, first_name, last_name) VALUES (1, 'John', 'Doe'); + +INSERT INTO employee_names (id, first_name, last_name) +VALUES (2, 'Jane', 'Smith'); + +INSERT INTO employee_names (id, first_name, last_name) +VALUES (3, 'David', 'Lee'); + +INSERT INTO employee_names (id, first_name, last_name) +VALUES (4, 'Emily', 'Jones'); + +INSERT INTO employee_names (id, first_name, last_name) +VALUES (5, 'Michael', 'Brown'); +COMMIT; + +*/ + +/* +-- TABLE IS DROPPED FROM JAVA CODE -> SQLStatementWithAsynchronousJDBC.java -> dropTable() method +DROP TABLE employee_names; +COMMIT; +*/