diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml
index f28db8d..808b20f 100644
--- a/.github/workflows/build.yml
+++ b/.github/workflows/build.yml
@@ -38,7 +38,7 @@ jobs:
sed -i 's/^IBMI_PORT=/IBMI_PORT=${{ secrets.IBMI_PORT }}/' ${{ env.CONFIG_PROPERTIES }}
- name: Build with Maven
- run: mvn -B package --file pom.xml
+ run: mvn --batch-mode clean package --file pom.xml
- name: Update Dependency Graph
uses: advanced-security/maven-dependency-submission-action@v4
diff --git a/checkstyle/suppressions.xml b/checkstyle/suppressions.xml
index fe7f865..9014a70 100644
--- a/checkstyle/suppressions.xml
+++ b/checkstyle/suppressions.xml
@@ -11,5 +11,6 @@
+
diff --git a/pom.xml b/pom.xml
index 1f7d844..8f2e103 100644
--- a/pom.xml
+++ b/pom.xml
@@ -274,6 +274,9 @@
org.apache.maven.plugins
maven-javadoc-plugin
${maven-javadoc-plugin.version}
+
+ all,-missing
+
diff --git a/src/main/java/io/github/mapepire_ibmi/NoAuthTrustManager.java b/src/main/java/io/github/mapepire_ibmi/NoAuthTrustManager.java
deleted file mode 100644
index ada7154..0000000
--- a/src/main/java/io/github/mapepire_ibmi/NoAuthTrustManager.java
+++ /dev/null
@@ -1,27 +0,0 @@
-package io.github.mapepire_ibmi;
-
-import java.security.cert.CertificateException;
-import java.security.cert.X509Certificate;
-
-import javax.net.ssl.X509TrustManager;
-
-/**
- * Represents a manager that handles which X509 certificates may be used to
- * authenticate the remote side of a secure socket.
- */
-class NoAuthTrustManager implements X509TrustManager {
- @Override
- public void checkClientTrusted(final X509Certificate[] chain, final String authType)
- throws CertificateException {
- }
-
- @Override
- public void checkServerTrusted(final X509Certificate[] chain, final String authType)
- throws CertificateException {
- }
-
- @Override
- public X509Certificate[] getAcceptedIssuers() {
- return new X509Certificate[0];
- }
-}
diff --git a/src/main/java/io/github/mapepire_ibmi/Pool.java b/src/main/java/io/github/mapepire_ibmi/Pool.java
index cce0bfe..217f46c 100644
--- a/src/main/java/io/github/mapepire_ibmi/Pool.java
+++ b/src/main/java/io/github/mapepire_ibmi/Pool.java
@@ -1,9 +1,5 @@
package io.github.mapepire_ibmi;
-import java.net.URISyntaxException;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
-import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -11,19 +7,14 @@
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
-import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonMappingException;
-
import io.github.mapepire_ibmi.types.JobStatus;
import io.github.mapepire_ibmi.types.PoolAddOptions;
import io.github.mapepire_ibmi.types.PoolOptions;
import io.github.mapepire_ibmi.types.QueryOptions;
import io.github.mapepire_ibmi.types.QueryResult;
import io.github.mapepire_ibmi.types.exceptions.ClientException;
-import io.github.mapepire_ibmi.types.exceptions.UnknownServerException;
/**
* Represents a connection pool for managing SQL jobs.
@@ -59,21 +50,8 @@ public Pool(PoolOptions options) {
* size.
*
* @return A CompletableFuture that resolves when all jobs have been created.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
- * @throws ClientException
*/
- public CompletableFuture init()
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException,
- ClientException {
+ public CompletableFuture init() throws Exception {
if (this.options.getMaxSize() <= 0) {
throw new ClientException("Max size must be greater than 0");
} else if (this.options.getStartingSize() <= 0) {
@@ -126,19 +104,8 @@ public void cleanup() {
* Add a new job to the pool.
*
* @return A CompletableFuture that resolves to the new job.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public CompletableFuture addJob()
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public CompletableFuture addJob() throws Exception {
PoolAddOptions poolAddOptions = new PoolAddOptions();
return this.addJob(poolAddOptions);
}
@@ -148,19 +115,8 @@ public CompletableFuture addJob()
*
* @param options Options for configuring an addition to the connection pool.
* @return A CompletableFuture that resolves to the new job.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public CompletableFuture addJob(PoolAddOptions options)
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public CompletableFuture addJob(PoolAddOptions options) throws Exception {
if (options.getExistingJob() != null) {
cleanup();
}
@@ -201,19 +157,8 @@ public SqlJob getReadyJob() {
* full but all jobs are busy.
*
* @return The retrieved job.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public synchronized SqlJob getJob()
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public synchronized SqlJob getJob() throws Exception {
SqlJob job = this.getReadyJob();
if (job == null) {
// This code finds a job that is busy, but has the least requests on the queue
@@ -241,19 +186,8 @@ public synchronized SqlJob getJob()
* otherwise, it may create a new job if the pool is not full.
*
* @return A CompletableFuture that resolves to a ready job.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public CompletableFuture waitForJob()
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public CompletableFuture waitForJob() throws Exception {
return this.waitForJob(false);
}
@@ -264,19 +198,8 @@ public CompletableFuture waitForJob()
* @param useNewJob Whether a new job should be created even if the pool is
* full.
* @return A CompletableFuture that resolves to a ready job.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public CompletableFuture waitForJob(boolean useNewJob)
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public CompletableFuture waitForJob(boolean useNewJob) throws Exception {
SqlJob job = getReadyJob();
if (job == null) {
@@ -298,19 +221,8 @@ public CompletableFuture waitForJob(boolean useNewJob)
* the pool.
*
* @return A CompletableFuture that resolves to a ready job or a new job.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public CompletableFuture popJob()
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public CompletableFuture popJob() throws Exception {
// TODO: dead code: what to do with it?
SqlJob readyJob = getReadyJob();
if (readyJob != null) {
@@ -329,19 +241,8 @@ public CompletableFuture popJob()
*
* @param sql The SQL query.
* @return A new Query instance.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public Query query(String sql)
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public Query query(String sql) throws Exception {
QueryOptions queryOptions = new QueryOptions();
return this.query(sql, queryOptions);
}
@@ -352,19 +253,8 @@ public Query query(String sql)
* @param sql The SQL query.
* @param opts The options for configuring the query.
* @return A new Query instance.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public Query query(String sql, QueryOptions opts)
- throws JsonMappingException, KeyManagementException, JsonProcessingException, NoSuchAlgorithmException,
- InterruptedException, ExecutionException, URISyntaxException, SQLException, UnknownServerException {
+ public Query query(String sql, QueryOptions opts) throws Exception {
SqlJob job = this.getJob();
return job.query(sql, opts);
}
@@ -375,20 +265,8 @@ public Query query(String sql, QueryOptions opts)
* @param The type of data to be returned.
* @param sql The SQL command to execute.
* @return A CompletableFuture that resolves to the query result.
- * @throws ClientException
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
*/
- public CompletableFuture> execute(String sql) throws JsonMappingException,
- KeyManagementException, JsonProcessingException, NoSuchAlgorithmException, InterruptedException,
- ExecutionException, URISyntaxException, SQLException, UnknownServerException, ClientException {
+ public CompletableFuture> execute(String sql) throws Exception {
QueryOptions queryOptions = new QueryOptions();
return this.execute(sql, queryOptions);
}
@@ -400,20 +278,8 @@ public CompletableFuture> execute(String sql) throws JsonMapp
* @param sql The SQL command to execute.
* @param opts The options for configuring the query.
* @return A CompletableFuture that resolves to the query result.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws JsonProcessingException
- * @throws KeyManagementException
- * @throws JsonMappingException
- * @throws ClientException
*/
- public CompletableFuture> execute(String sql, QueryOptions opts) throws JsonMappingException,
- KeyManagementException, JsonProcessingException, NoSuchAlgorithmException, InterruptedException,
- ExecutionException, URISyntaxException, SQLException, UnknownServerException, ClientException {
+ public CompletableFuture> execute(String sql, QueryOptions opts) throws Exception {
SqlJob job = this.getJob();
return job.execute(sql, opts);
}
diff --git a/src/main/java/io/github/mapepire_ibmi/Query.java b/src/main/java/io/github/mapepire_ibmi/Query.java
index 66d29df..62befae 100644
--- a/src/main/java/io/github/mapepire_ibmi/Query.java
+++ b/src/main/java/io/github/mapepire_ibmi/Query.java
@@ -5,11 +5,8 @@
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
-import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -141,17 +138,14 @@ public static synchronized List getOpenIds(SqlJob forJob) {
/**
* Clean up queries that are done or are in error state from the global query
* list.
- *
- * @throws ExecutionException
- * @throws InterruptedException
*/
- public synchronized CompletableFuture cleanup() throws InterruptedException, ExecutionException {
+ public synchronized CompletableFuture cleanup() throws Exception {
List> futures = globalQueryList.stream()
.filter(query -> query.getState() == QueryState.RUN_DONE || query.getState() == QueryState.ERROR)
.map(query -> CompletableFuture.runAsync(() -> {
try {
query.close();
- } catch (JsonProcessingException | InterruptedException | ExecutionException e) {
+ } catch (Exception e) {
e.printStackTrace();
}
}))
@@ -170,15 +164,8 @@ public synchronized CompletableFuture cleanup() throws InterruptedExceptio
*
* @param The type of data to be returned.
* @return A CompletableFuture that resolves to the query result.
- * @throws SQLException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws ClientException
- * @throws JsonProcessingException
- * @throws JsonMappingException
*/
- public CompletableFuture> execute() throws JsonMappingException, JsonProcessingException,
- ClientException, InterruptedException, ExecutionException, SQLException {
+ public CompletableFuture> execute() throws Exception {
return this.execute(100);
}
@@ -188,15 +175,8 @@ public CompletableFuture> execute() throws JsonMappingExcepti
* @param The type of data to be returned.
* @param rowsToFetch The number of rows to fetch.
* @return A CompletableFuture that resolves to the query result.
- * @throws ClientException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws SQLException
*/
- public CompletableFuture> execute(int rowsToFetch) throws ClientException, JsonMappingException,
- JsonProcessingException, InterruptedException, ExecutionException, SQLException {
+ public CompletableFuture> execute(int rowsToFetch) throws Exception {
if (rowsToFetch <= 0) {
throw new ClientException("Rows to fetch must be greater than 0");
}
@@ -275,16 +255,8 @@ public CompletableFuture> execute(int rowsToFetch) throws Cli
* Fetch more rows from the currently running query.
*
* @return A CompletableFuture that resolves to the query result.
- * @throws SQLException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws UnknownServerException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws ClientException
*/
- public CompletableFuture> fetchMore() throws JsonMappingException, JsonProcessingException,
- UnknownServerException, InterruptedException, ExecutionException, SQLException, ClientException {
+ public CompletableFuture> fetchMore() throws Exception {
return this.fetchMore(this.rowsToFetch);
}
@@ -293,17 +265,8 @@ public CompletableFuture> fetchMore() throws JsonMappingExcep
*
* @param rowsToFetch The number of additional rows to fetch.
* @return A CompletableFuture that resolves to the query result.
- * @throws ClientException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws SQLException
- * @throws UnknownServerException
*/
- public CompletableFuture> fetchMore(int rowsToFetch)
- throws ClientException, JsonMappingException,
- JsonProcessingException, InterruptedException, ExecutionException, SQLException, UnknownServerException {
+ public CompletableFuture> fetchMore(int rowsToFetch) throws Exception {
if (rowsToFetch <= 0) {
throw new ClientException("Rows to fetch must be greater than 0");
}
@@ -358,13 +321,8 @@ public CompletableFuture> fetchMore(int rowsToFetch)
* Close the query.
*
* @return A CompletableFuture that resolves when the query is closed.
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
*/
- public CompletableFuture close()
- throws JsonMappingException, JsonProcessingException, InterruptedException, ExecutionException {
+ public CompletableFuture close() throws Exception {
if (correlationId != null && state != QueryState.RUN_DONE) {
state = QueryState.RUN_DONE;
diff --git a/src/main/java/io/github/mapepire_ibmi/SqlJob.java b/src/main/java/io/github/mapepire_ibmi/SqlJob.java
index eaad875..c129ae6 100644
--- a/src/main/java/io/github/mapepire_ibmi/SqlJob.java
+++ b/src/main/java/io/github/mapepire_ibmi/SqlJob.java
@@ -1,11 +1,14 @@
package io.github.mapepire_ibmi;
+import java.io.ByteArrayInputStream;
+import java.io.InputStream;
import java.net.URI;
-import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
-import java.security.KeyManagementException;
-import java.security.NoSuchAlgorithmException;
+import java.security.KeyStore;
import java.security.SecureRandom;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateFactory;
+import java.security.cert.X509Certificate;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.Base64;
@@ -14,19 +17,19 @@
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.CompletionException;
-import java.util.concurrent.ExecutionException;
import java.util.stream.Collectors;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactory;
+import javax.net.ssl.X509TrustManager;
import org.java_websocket.client.WebSocketClient;
import org.java_websocket.drafts.Draft_6455;
import org.java_websocket.handshake.ServerHandshake;
import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.JsonMappingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;
@@ -45,7 +48,6 @@
import io.github.mapepire_ibmi.types.SetConfigResult;
import io.github.mapepire_ibmi.types.TransactionEndType;
import io.github.mapepire_ibmi.types.VersionCheckResult;
-import io.github.mapepire_ibmi.types.exceptions.ClientException;
import io.github.mapepire_ibmi.types.exceptions.UnknownServerException;
import io.github.mapepire_ibmi.types.jdbcOptions.Option;
import io.github.mapepire_ibmi.types.jdbcOptions.TransactionIsolation;
@@ -147,17 +149,95 @@ public static synchronized String getNewUniqueId(String prefix) {
*
* @param db2Server The server details for the connection.
* @return A CompletableFuture that resolves to the WebSocketClient instance.
- * @throws NoSuchAlgorithmException
- * @throws KeyManagementException
- * @throws URISyntaxException
*/
- private CompletableFuture getChannel(DaemonServer db2Server)
- throws NoSuchAlgorithmException, KeyManagementException, URISyntaxException {
- SSLContext sslContext = SSLContext.getInstance("TLS");
- NoAuthTrustManager trustManager = new NoAuthTrustManager();
- sslContext.init(null, new TrustManager[] { trustManager }, new SecureRandom());
- SSLSocketFactory factory = sslContext.getSocketFactory();
+ private CompletableFuture getChannel(DaemonServer db2Server) throws Exception {
+ TrustManagerFactory tmf;
+ X509TrustManager customTrustManager = null;
+ X509TrustManager jdkTrustManager = null;
+
+ if (db2Server.getCa() != null) {
+ // Convert custom CA from string to X509Certificate
+ InputStream inputStream = new ByteArrayInputStream(db2Server.getCa().getBytes());
+ X509Certificate caCert = (X509Certificate) CertificateFactory.getInstance("X509")
+ .generateCertificate(inputStream);
+
+ // Create a custom key store and load custom certificate
+ KeyStore customKeyStore = KeyStore.getInstance("PKCS12");
+ customKeyStore.load(null, null);
+ customKeyStore.setCertificateEntry("mapepire-ca", caCert);
+
+ // Initialize a TrustManagerFactory with custom key store
+ tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init(customKeyStore);
+
+ // Get the custom X509TrustManager
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509TrustManager) {
+ customTrustManager = (X509TrustManager) tm;
+ break;
+ }
+ }
+ }
+
+ // Initialize TrustManagerFactory
+ tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
+ tmf.init((KeyStore) null);
+
+ // Get the JDK X509TrustManager
+ for (TrustManager tm : tmf.getTrustManagers()) {
+ if (tm instanceof X509TrustManager) {
+ jdkTrustManager = (X509TrustManager) tm;
+ break;
+ }
+ }
+
+ final X509TrustManager finalCustomTrustManager = customTrustManager;
+ final X509TrustManager finalJdkTrustManager = jdkTrustManager;
+ X509TrustManager mapepireTrustManager = new X509TrustManager() {
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ if (finalCustomTrustManager != null) {
+ X509Certificate[] jdkTrust = finalJdkTrustManager.getAcceptedIssuers();
+ X509Certificate[] custTrust = finalCustomTrustManager.getAcceptedIssuers();
+ X509Certificate[] merge = new X509Certificate[custTrust.length + jdkTrust.length];
+
+ for (int i = 0; i < custTrust.length; i++) {
+ merge[i] = custTrust[i];
+ }
+
+ for (int i = 0; i < jdkTrust.length; i++) {
+ merge[custTrust.length + i] = jdkTrust[i];
+ }
+
+ return merge;
+ } else {
+ return finalJdkTrustManager.getAcceptedIssuers();
+ }
+ }
+
+ @Override
+ public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ if (db2Server.getRejectUnauthorized()) {
+ if (finalCustomTrustManager != null) {
+ try {
+ finalCustomTrustManager.checkServerTrusted(chain, authType);
+ } catch (CertificateException e) {
+ finalJdkTrustManager.checkServerTrusted(chain, authType);
+ }
+ } else {
+ finalJdkTrustManager.checkServerTrusted(chain, authType);
+ }
+ }
+ }
+
+ @Override
+ public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
+ }
+ };
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, new TrustManager[] { mapepireTrustManager }, new SecureRandom());
+ SSLContext.setDefault(sslContext);
URI uri = new URI("wss://" + db2Server.getHost() + ":" + db2Server.getPort() + "/db/");
Map httpHeaders = new HashMap<>();
String auth = db2Server.getUser() + ":" + db2Server.getPassword();
@@ -214,14 +294,9 @@ public void onError(Exception e) {
}
}
};
+ SSLSocketFactory factory = sslContext.getSocketFactory();
wsc.setSocketFactory(factory);
- // TODO: Implement
- // if (db2Server.getIgnoreUnauthorized()) {
- // }
- // if (db2Server.getCa() != null) {
- // }
-
return CompletableFuture.completedFuture(wsc);
}
@@ -230,13 +305,8 @@ public void onError(Exception e) {
*
* @param content The message content to send.
* @return A CompletableFuture that resolves to the server's response.
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws ExecutionException
- * @throws InterruptedException
*/
- public CompletableFuture send(String content)
- throws JsonMappingException, JsonProcessingException, InterruptedException, ExecutionException {
+ public CompletableFuture send(String content) throws Exception {
if (this.isTracingChannelData) {
System.out.println("\n>> " + content);
}
@@ -280,19 +350,8 @@ public int getRunningCount() {
*
* @param db2Server The server details for the connection.
* @return A CompletableFuture that resolves to the connection result.
- * @throws URISyntaxException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws NoSuchAlgorithmException
- * @throws KeyManagementException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture connect(DaemonServer db2Server) throws KeyManagementException,
- NoSuchAlgorithmException, InterruptedException, ExecutionException, URISyntaxException,
- JsonMappingException, JsonProcessingException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture connect(DaemonServer db2Server) throws Exception {
this.status = JobStatus.Connecting;
ObjectMapper objectMapper = SingletonObjectMapper.getInstance();
@@ -390,17 +449,8 @@ public Query query(String sql, QueryOptions opts) {
* @param The type of data to be returned.
* @param sql The SQL command to execute.
* @return A CompletableFuture that resolves to the query result.
- * @throws UnknownServerException
- * @throws SQLException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws ClientException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- */
- public CompletableFuture> execute(String sql)
- throws JsonMappingException, JsonProcessingException, ClientException, InterruptedException,
- ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture> execute(String sql) throws Exception {
return this.execute(sql, new QueryOptions());
}
@@ -411,17 +461,8 @@ public CompletableFuture> execute(String sql)
* @param sql The SQL command to execute.
* @param opts The options for configuring the query.
* @return A CompletableFuture that resolves to the query result.
- * @throws SQLException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws ClientException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws UnknownServerException
- */
- public CompletableFuture> execute(String sql, QueryOptions opts)
- throws JsonMappingException, JsonProcessingException, ClientException, InterruptedException,
- ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture> execute(String sql, QueryOptions opts) throws Exception {
Query query = query(sql, opts);
return query.execute()
.thenCompose(queryResult -> {
@@ -448,15 +489,8 @@ public CompletableFuture> execute(String sql, QueryOptions op
* Get the version information from the database server.
*
* @return A CompletableFuture that resolves to the version check result.
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture getVersion() throws JsonMappingException, JsonProcessingException,
- InterruptedException, ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture getVersion() throws Exception {
ObjectMapper objectMapper = SingletonObjectMapper.getInstance();
ObjectNode versionRequest = objectMapper.createObjectNode();
versionRequest.put("id", SqlJob.getNewUniqueId());
@@ -489,15 +523,8 @@ public CompletableFuture getVersion() throws JsonMappingExce
*
* @param statement The SQL statement to explain.
* @return A CompletableFuture that resolves to the explain results.
- * @throws SQLException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws UnknownServerException
- */
- public CompletableFuture> explain(String statement) throws JsonMappingException,
- JsonProcessingException, InterruptedException, ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture> explain(String statement) throws Exception {
return this.explain(statement, ExplainType.RUN);
}
@@ -507,15 +534,8 @@ public CompletableFuture> explain(String statement) throws Jso
* @param statement The SQL statement to explain.
* @param type The type of explain to perform (default is ExplainType.Run).
* @return A CompletableFuture that resolves to the explain results.
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture> explain(String statement, ExplainType type) throws JsonMappingException,
- JsonProcessingException, InterruptedException, ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture> explain(String statement, ExplainType type) throws Exception {
ObjectMapper objectMapper = SingletonObjectMapper.getInstance();
ObjectNode explainRequest = objectMapper.createObjectNode();
explainRequest.put("id", SqlJob.getNewUniqueId());
@@ -556,15 +576,8 @@ public String getTraceFilePath() {
* Get trace data from the backend.
*
* @return A CompletableFuture that resolves to the trace data result.
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture getTraceData() throws JsonMappingException, JsonProcessingException,
- InterruptedException, ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture getTraceData() throws Exception {
ObjectMapper objectMapper = SingletonObjectMapper.getInstance();
ObjectNode traceDataRequest = objectMapper.createObjectNode();
traceDataRequest.put("id", SqlJob.getNewUniqueId());
@@ -597,15 +610,8 @@ public CompletableFuture getTraceData() throws JsonMappingEx
*
* @param dest The server trace destination.
* @return A CompletableFuture that resolves to the set config result.
- * @throws JsonMappingException
- * @throws JsonProcessingException
- * @throws InterruptedException
- * @throws ExecutionException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture setTraceDest(ServerTraceDest dest) throws JsonMappingException,
- JsonProcessingException, InterruptedException, ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture setTraceDest(ServerTraceDest dest) throws Exception {
return setTraceConfig(dest, null, null, null);
}
@@ -614,15 +620,8 @@ public CompletableFuture setTraceDest(ServerTraceDest dest) thr
*
* @param level The server trace level.
* @return A CompletableFuture that resolves to the set config result.
- * @throws JsonMappingException
- * @throws JsonProcessingException
- * @throws InterruptedException
- * @throws ExecutionException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture setTraceLevel(ServerTraceLevel level) throws JsonMappingException,
- JsonProcessingException, InterruptedException, ExecutionException, SQLException, UnknownServerException {
+ */
+ public CompletableFuture setTraceLevel(ServerTraceLevel level) throws Exception {
return setTraceConfig(null, level, null, null);
}
@@ -631,16 +630,8 @@ public CompletableFuture setTraceLevel(ServerTraceLevel level)
*
* @param jtOpenTraceDest The JTOpen trace data destination.
* @return A CompletableFuture that resolves to the set config result.
- * @throws JsonMappingException
- * @throws JsonProcessingException
- * @throws InterruptedException
- * @throws ExecutionException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture setJtOpenTraceDest(ServerTraceDest jtOpenTraceDest)
- throws JsonMappingException, JsonProcessingException, InterruptedException, ExecutionException,
- SQLException, UnknownServerException {
+ */
+ public CompletableFuture setJtOpenTraceDest(ServerTraceDest jtOpenTraceDest) throws Exception {
return setTraceConfig(null, null, jtOpenTraceDest, null);
}
@@ -649,16 +640,8 @@ public CompletableFuture setJtOpenTraceDest(ServerTraceDest jtO
*
* @param jtOpenTraceLevel The JTOpen trace level.
* @return A CompletableFuture that resolves to the set config result.
- * @throws JsonMappingException
- * @throws JsonProcessingException
- * @throws InterruptedException
- * @throws ExecutionException
- * @throws SQLException
- * @throws UnknownServerException
- */
- public CompletableFuture setJtOpenTraceLevel(ServerTraceLevel jtOpenTraceLevel)
- throws JsonMappingException, JsonProcessingException, InterruptedException, ExecutionException,
- SQLException, UnknownServerException {
+ */
+ public CompletableFuture setJtOpenTraceLevel(ServerTraceLevel jtOpenTraceLevel) throws Exception {
return setTraceConfig(null, null, null, jtOpenTraceLevel);
}
@@ -670,17 +653,9 @@ public CompletableFuture setJtOpenTraceLevel(ServerTraceLevel j
* @param jtOpenTraceDest The JTOpen trace data destination.
* @param jtOpenTraceLevel The JTOpen trace level.
* @return A CompletableFuture that resolves to the set config result.
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- * @throws SQLException
- * @throws UnknownServerException
*/
public CompletableFuture setTraceConfig(ServerTraceDest dest, ServerTraceLevel level,
- ServerTraceDest jtOpenTraceDest, ServerTraceLevel jtOpenTraceLevel)
- throws JsonMappingException, JsonProcessingException, InterruptedException, ExecutionException,
- SQLException, UnknownServerException {
+ ServerTraceDest jtOpenTraceDest, ServerTraceLevel jtOpenTraceLevel) throws Exception {
ObjectMapper objectMapper = SingletonObjectMapper.getInstance();
ObjectNode setTraceConfigRequest = objectMapper.createObjectNode();
setTraceConfigRequest.put("id", SqlJob.getNewUniqueId());
@@ -755,15 +730,8 @@ public boolean underCommitControl() {
*
* @return A CompletableFuture that resolves to the count of pending
* transactions.
- * @throws SQLException
- * @throws ClientException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- */
- public CompletableFuture getPendingTransactions() throws JsonMappingException, JsonProcessingException,
- InterruptedException, ExecutionException, ClientException, SQLException {
+ */
+ public CompletableFuture getPendingTransactions() throws Exception {
ObjectMapper objectMapper = SingletonObjectMapper.getInstance();
String transactionCountQuery = String.join("\n", Arrays.asList(
"select count(*) as thecount",
@@ -796,16 +764,8 @@ public CompletableFuture getPendingTransactions() throws JsonMappingExc
* @param type The type of transaction ending (commit or rollback).
* @return A CompletableFuture that resolves to the result of the transaction
* operation.
- * @throws SQLException
- * @throws ExecutionException
- * @throws InterruptedException
- * @throws ClientException
- * @throws JsonProcessingException
- * @throws JsonMappingException
- */
- public CompletableFuture> endTransaction(TransactionEndType type)
- throws JsonMappingException, JsonProcessingException, ClientException, InterruptedException,
- ExecutionException, SQLException {
+ */
+ public CompletableFuture> endTransaction(TransactionEndType type) throws Exception {
String query;
switch (type) {
diff --git a/src/main/java/io/github/mapepire_ibmi/Tls.java b/src/main/java/io/github/mapepire_ibmi/Tls.java
index 1ca636f..9aa0174 100644
--- a/src/main/java/io/github/mapepire_ibmi/Tls.java
+++ b/src/main/java/io/github/mapepire_ibmi/Tls.java
@@ -1,7 +1,25 @@
package io.github.mapepire_ibmi;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.security.SecureRandom;
+import java.security.cert.Certificate;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+import java.util.Base64;
+import java.util.HashMap;
+import java.util.Map;
import java.util.concurrent.CompletableFuture;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.X509TrustManager;
+
+import org.java_websocket.client.WebSocketClient;
+import org.java_websocket.drafts.Draft_6455;
+import org.java_websocket.handshake.ServerHandshake;
+
import io.github.mapepire_ibmi.types.DaemonServer;
/**
@@ -9,18 +27,74 @@
*/
public class Tls {
/**
- * Get the SSL/TLS certificate from a specified DB2 server.
- *
- * This function establishes a secure connection to the server and retrieves the
- * peer certificate information, which includes details about the server's
- * SSL/TLS certificate.
+ * Get the SSL server certificate for a specified DB2 server.
*
- * @param creds The server details for the connection.
- * @return A CompletableFuture that resolves to the detailed peer certificate
- * information.
+ * @param db2Server The server details for the connection.
+ * @return A CompletableFuture that resolves to the SSL server certificate.
*/
- public CompletableFuture getCertificate(DaemonServer creds) {
- // TODO: Add implementation
- return CompletableFuture.completedFuture(null);
+ public static CompletableFuture getCertificate(DaemonServer db2Server) throws Exception {
+ X509TrustManager noAuthTrustManager = new X509TrustManager() {
+ @Override
+ public void checkClientTrusted(final X509Certificate[] chain, final String authType)
+ throws CertificateException {
+ }
+
+ @Override
+ public void checkServerTrusted(final X509Certificate[] chain, final String authType)
+ throws CertificateException {
+ }
+
+ @Override
+ public X509Certificate[] getAcceptedIssuers() {
+ return new X509Certificate[0];
+ }
+ };
+
+ SSLContext sslContext = SSLContext.getInstance("TLS");
+ sslContext.init(null, new TrustManager[] { noAuthTrustManager }, new SecureRandom());
+ SSLContext.setDefault(sslContext);
+ URI uri = new URI("wss://" + db2Server.getHost() + ":" + db2Server.getPort() + "/db/");
+ Map httpHeaders = new HashMap<>();
+ String auth = db2Server.getUser() + ":" + db2Server.getPassword();
+ String encodedAuth = Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
+ httpHeaders.put("Authorization", "Basic " + encodedAuth);
+
+ CompletableFuture certificateFuture = new CompletableFuture<>();
+ WebSocketClient wsc = new WebSocketClient(uri, new Draft_6455(), httpHeaders, 5000) {
+ @Override
+ public void onOpen(ServerHandshake handshakedata) {
+ try {
+ Certificate[] peerCertificates = this.getSSLSession().getPeerCertificates();
+ byte[] encodedCa = peerCertificates[0].getEncoded();
+ StringBuilder ca = new StringBuilder();
+ ca.append("-----BEGIN CERTIFICATE-----\n");
+ ca.append(Base64.getEncoder().encodeToString(encodedCa));
+ ca.append("\n-----END CERTIFICATE-----\n");
+ certificateFuture.complete(ca.toString());
+ } catch (Exception e) {
+ certificateFuture.completeExceptionally(e);
+ } finally {
+ this.close();
+ }
+ }
+
+ @Override
+ public void onMessage(String message) {
+ }
+
+ @Override
+ public void onClose(int code, String reason, boolean remote) {
+ }
+
+ @Override
+ public void onError(Exception e) {
+ certificateFuture.completeExceptionally(e);
+ }
+ };
+ SSLSocketFactory factory = sslContext.getSocketFactory();
+ wsc.setSocketFactory(factory);
+ wsc.connect();
+
+ return certificateFuture;
}
}
diff --git a/src/main/java/io/github/mapepire_ibmi/types/DaemonServer.java b/src/main/java/io/github/mapepire_ibmi/types/DaemonServer.java
index 93fab8d..186619d 100644
--- a/src/main/java/io/github/mapepire_ibmi/types/DaemonServer.java
+++ b/src/main/java/io/github/mapepire_ibmi/types/DaemonServer.java
@@ -33,8 +33,8 @@ public class DaemonServer {
/**
* Whether to ignore unauthorized certificates.
*/
- @JsonProperty("ignoreUnauthorized")
- private boolean ignoreUnauthorized;
+ @JsonProperty("rejectUnauthorized")
+ private boolean rejectUnauthorized = true;
/**
* The certificate authority (CA) for validating the server's certificate.
@@ -49,6 +49,38 @@ public DaemonServer() {
}
+ /**
+ * Construct a new DaemonServer instance.
+ *
+ * @param host The hostname or IP address of the server.
+ * @param port The port number to connect to.
+ * @param user The username for authentication.
+ * @param password The password for authentication.
+ */
+ public DaemonServer(String host, int port, String user, String password) {
+ this.host = host;
+ this.port = port;
+ this.user = user;
+ this.password = password;
+ }
+
+ /**
+ * Construct a new DaemonServer instance.
+ *
+ * @param host The hostname or IP address of the server.
+ * @param port The port number to connect to.
+ * @param user The username for authentication.
+ * @param password The password for authentication.
+ * @param rejectUnauthorized Whether to ignore unauthorized certificates.
+ */
+ public DaemonServer(String host, int port, String user, String password, boolean rejectUnauthorized) {
+ this.host = host;
+ this.port = port;
+ this.user = user;
+ this.password = password;
+ this.rejectUnauthorized = rejectUnauthorized;
+ }
+
/**
* Construct a new DaemonServer instance.
*
@@ -56,17 +88,17 @@ public DaemonServer() {
* @param port The port number to connect to.
* @param user The username for authentication.
* @param password The password for authentication.
- * @param ignoreUnauthorized Whether to ignore unauthorized certificates.
+ * @param rejectUnauthorized Whether to ignore unauthorized certificates.
* @param ca The certificate authority (CA) for validating the
* server's certificate.
*/
- public DaemonServer(String host, int port, String user, String password, boolean ignoreUnauthorized,
+ public DaemonServer(String host, int port, String user, String password, boolean rejectUnauthorized,
String ca) {
this.host = host;
this.port = port;
this.user = user;
this.password = password;
- this.ignoreUnauthorized = ignoreUnauthorized;
+ this.rejectUnauthorized = rejectUnauthorized;
this.ca = ca;
}
@@ -147,17 +179,17 @@ public void setPassword(String password) {
*
* @return Whether to ignore unauthorized certificates.
*/
- public boolean getIgnoreUnauthorized() {
- return ignoreUnauthorized;
+ public boolean getRejectUnauthorized() {
+ return rejectUnauthorized;
}
/**
* Set whether to ignore unauthorized certificates.
*
- * @param ignoreUnauthorized Whether to ignore unauthorized certificates.
+ * @param rejectUnauthorized Whether to ignore unauthorized certificates.
*/
- public void setIgnoreUnauthorized(boolean ignoreUnauthorized) {
- this.ignoreUnauthorized = ignoreUnauthorized;
+ public void setRejectUnauthorized(boolean rejectUnauthorized) {
+ this.rejectUnauthorized = rejectUnauthorized;
}
/**
diff --git a/src/test/java/io/github/mapepire_ibmi/CLTest.java b/src/test/java/io/github/mapepire_ibmi/CLTest.java
index 003758a..be3f499 100644
--- a/src/test/java/io/github/mapepire_ibmi/CLTest.java
+++ b/src/test/java/io/github/mapepire_ibmi/CLTest.java
@@ -20,7 +20,7 @@ void validCLCommand() throws Exception {
job.close();
assertTrue(result.getSuccess());
- assertTrue(result.getData().size() > 0);
+ assertNotNull(result.getData());
}
@Test
diff --git a/src/test/java/io/github/mapepire_ibmi/ConnectTest.java b/src/test/java/io/github/mapepire_ibmi/ConnectTest.java
index 7a1fdaf..d363b5f 100644
--- a/src/test/java/io/github/mapepire_ibmi/ConnectTest.java
+++ b/src/test/java/io/github/mapepire_ibmi/ConnectTest.java
@@ -1,6 +1,5 @@
package io.github.mapepire_ibmi;
-import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotEquals;
import static org.junit.jupiter.api.Assertions.assertThrowsExactly;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -35,9 +34,8 @@ void invalidConnection() throws Exception {
}
});
- assertEquals(
- "java.sql.SQLException: The application server rejected the connection. (User ID is not known.:FAKE_USER)",
- e.getMessage());
+ assertTrue(e.getMessage()
+ .contains("The application server rejected the connection."));
}
@Test
diff --git a/src/test/java/io/github/mapepire_ibmi/MapepireTest.java b/src/test/java/io/github/mapepire_ibmi/MapepireTest.java
index c1460a5..43005d1 100644
--- a/src/test/java/io/github/mapepire_ibmi/MapepireTest.java
+++ b/src/test/java/io/github/mapepire_ibmi/MapepireTest.java
@@ -1,7 +1,6 @@
package io.github.mapepire_ibmi;
import java.io.FileNotFoundException;
-import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.Arrays;
@@ -17,16 +16,40 @@
@Timeout(25)
class MapepireTest {
- private static DaemonServer creds;
- private static DaemonServer invalidCreds;
- private static final String CONFIG_FILE = "config.properties";
+ private static String host;
+ private static String user;
+ private static String password;
+ private static int port;
+ private static String invalidCA = "-----BEGIN CERTIFICATE-----\n" +
+ "MIIDtjCCAp6gAwIBAgIUaZwqO1YXrSGUZ+j2YlefGD+Li3UwDQYJKoZIhvcNAQEL\n" +
+ "BQAwcjELMAkGA1UEBhMCZHIxCzAJBgNVBAgMAnNlMQwwCgYDVQQHDAN0eXUxDDAK\n" +
+ "BgNVBAoMA3NlcjELMAkGA1UECwwCaGYxDzANBgNVBAMMBmRyZnRnZzEcMBoGCSqG\n" +
+ "SIb3DQEJARYNbG9nQGdtYWlsLmNvbTAeFw0yNDEwMDIxODU3MDFaFw0yNTEwMDIx\n" +
+ "ODU3MDFaMHQxCzAJBgNVBAYTAkNBMQswCQYDVQQIDAJPTjEQMA4GA1UEBwwHVG9y\n" +
+ "b250bzEMMAoGA1UECgwDSUJNMQswCQYDVQQLDAJMTDEMMAoGA1UEAwwDSk9OMR0w\n" +
+ "GwYJKoZIhvcNAQkBFg5mYWtlQGdtYWlsLmNvbTCCASIwDQYJKoZIhvcNAQEBBQAD\n" +
+ "ggEPADCCAQoCggEBAI39BFoVAXIc0HFH7MgDAI53ExKgZkyBXGjFsooyzM/u215h\n" +
+ "QLtsfirmsFU8Kq2HOY1UaB1PRq4nrHYrwO7nYpmA14/9EgEXQsSRDH8LO18sSUQb\n" +
+ "hOX3622CunKDT77O7z5LakPuVvOsj1XBVTyFONTTzcuWW0mcnupj7j+WF+fldV3y\n" +
+ "Z64rfk/wJ2W1FjWNgxtm076KivVrV4RvL7DmGQH5sCENCx4eaGh2LGe1kb5yACQ3\n" +
+ "9zeC9aEwogEh2QRV8x3LzsroF3NR/IqzIm6L3kaiyWTsQkVlztmGpXY3WnFgfoBj\n" +
+ "e6IZOCRXzA9iTS1dRDGnFSzcRawf+PSIbP88LZ0CAwEAAaNCMEAwHQYDVR0OBBYE\n" +
+ "FH1B2+PDJmga5MwzswnukmSEt50OMB8GA1UdIwQYMBaAFPHGkLtIDz/tR3iBLgzU\n" +
+ "DjEK+tsoMA0GCSqGSIb3DQEBCwUAA4IBAQCnlEjRBF+IUNRfYVqOW4uHJriaBViu\n" +
+ "6zdXG+13pa7La+mAZ0BsoP1pLhrWjDul271MTOYsq429XBtlfxaNJiqHuPNjccKa\n" +
+ "wga2NFLAZriHYUvyP4Ld/H0IVAleIem4w2vwqHqayV2GeQCn5H+LknIaTzHKuRZ9\n" +
+ "fv6C/V5jBJFAJ29tYh79lioIRIZ6nzYLGWQIXbh9Y8uNIMbU3z4fqRQN65gKCkBB\n" +
+ "HaelrFfJI+UCGwOnr4qTKxkEB/lNz47O7kh4vmAk4mU3IsSWDMsydFHCTPLMg/Me\n" +
+ "TYn5iFqPQJhDoSiE8W0CeyAUXyhwWg7l9qiBaA+nI+t1Y307ld4T46x4\n" +
+ "-----END CERTIFICATE-----";
+ private static String configFile = "config.properties";
@BeforeAll
- public static void setup() throws IOException, ParseException {
+ public static void setup() throws Exception {
Properties properties = new Properties();
- try (InputStream input = MapepireTest.class.getClassLoader().getResourceAsStream(CONFIG_FILE)) {
+ try (InputStream input = MapepireTest.class.getClassLoader().getResourceAsStream(configFile)) {
if (input == null) {
- throw new FileNotFoundException("Unable to find " + CONFIG_FILE);
+ throw new FileNotFoundException("Unable to find " + configFile);
}
properties.load(input);
}
@@ -41,22 +64,20 @@ public static void setup() throws IOException, ParseException {
secrets.put(key, value);
}
- String host = secrets.get(keys.get(0));
- String user = secrets.get(keys.get(1));
- String password = secrets.get(keys.get(2));
- int port = Integer.parseInt(secrets.get(keys.get(3)));
-
- creds = new DaemonServer(host, port, user, password, true, "");
- invalidCreds = new DaemonServer(host, port, "FAKE_USER", "FAKE_PASSWORD", true, "");
-
- // TODO: Get certificate
+ host = secrets.get(keys.get(0));
+ user = secrets.get(keys.get(1));
+ password = secrets.get(keys.get(2));
+ port = Integer.parseInt(secrets.get(keys.get(3)));
}
- public static DaemonServer getCreds() {
+ public static DaemonServer getCreds() throws Exception {
+ DaemonServer creds = new DaemonServer(host, port, user, password);
+ String ca = Tls.getCertificate(creds).get();
+ creds.setCa(ca);
return creds;
}
public static DaemonServer getInvalidCreds() {
- return invalidCreds;
+ return new DaemonServer(host, port, "FAKE_USER", "FAKE_PASSWORD", false, invalidCA);
}
}
diff --git a/src/test/java/io/github/mapepire_ibmi/SqlTest.java b/src/test/java/io/github/mapepire_ibmi/SqlTest.java
index 6bc3b7b..c70706d 100644
--- a/src/test/java/io/github/mapepire_ibmi/SqlTest.java
+++ b/src/test/java/io/github/mapepire_ibmi/SqlTest.java
@@ -72,7 +72,7 @@ void simpleQueryWithJDBCOptions() throws Exception {
assertTrue(result.getHasResults());
assertNotNull(result.getMetadata());
assertTrue(result.getData().size() > 0);
- assertEquals("[SQL5016] Qualified object name DEPARTMENT not valid., 42833, -5016", e.getMessage());
+ assertTrue(e.getMessage().contains("[SQL5016] Qualified object name DEPARTMENT not valid."));
}
@Test
@@ -94,7 +94,7 @@ void simpleQueryInTerseFormat() throws Exception {
assertNotNull(result.getMetadata());
assertFalse(result.getIsDone());
assertEquals(5, result.getData().size());
- assertEquals("NAME", row.get(0));
+ assertNotNull(row.get(0));
}
@Test
@@ -133,9 +133,8 @@ void notExistentTableQuery() throws Exception {
}
});
- assertEquals(
- "[SQL0204] SCOOBY in " + getCreds().getUser().toUpperCase() + " type *FILE not found., 42704, -204",
- e.getMessage());
+ assertTrue(e.getMessage()
+ .contains("[SQL0204] SCOOBY in " + getCreds().getUser().toUpperCase() + " type *FILE not found."));
}
@Test
@@ -155,7 +154,7 @@ void emptyQuery() throws Exception {
}
});
- assertEquals("A string parameter value with zero length was detected., 43617, -99999", e.getMessage());
+ assertTrue(e.getMessage().contains("A string parameter value with zero length was detected."));
}
@Test
@@ -175,9 +174,8 @@ void invalidTokenQuery() throws Exception {
}
});
- assertEquals(
- "[SQL0104] Token A was not valid. Valid tokens: ( CL END GET SET TAG CALL DROP FREE HOLD LOCK OPEN WITH ALTER., 42601, -104",
- e.getMessage());
+ assertTrue(e.getMessage().contains(
+ "[SQL0104] Token A was not valid. Valid tokens: ( CL END GET SET TAG CALL DROP FREE HOLD LOCK OPEN WITH ALTER."));
}
@Test
@@ -275,9 +273,9 @@ void executeOnPreparedQueryInTerseFormat() throws Exception {
SqlJob job = new SqlJob();
job.connect(MapepireTest.getCreds()).get();
- QueryOptions options = new QueryOptions(true, false, Arrays.asList("PHONE"));
+ QueryOptions options = new QueryOptions(true, false, Arrays.asList("TABLE_NAME"));
Query query = job.query("SELECT * FROM SAMPLE.SYSCOLUMNS WHERE COLUMN_NAME = ?", options);
- QueryResult