You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hop.apache.org by ha...@apache.org on 2026/07/31 10:14:59 UTC
(hop) branch main updated: [SONAR] fix some more issues (#7713)
This is an automated email from the ASF dual-hosted git repository.
hansva pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/hop.git
The following commit(s) were added to refs/heads/main by this push:
new d6e493a6ce [SONAR] fix some more issues (#7713)
d6e493a6ce is described below
commit d6e493a6ce4c54f7f4bbf2b7839ddbce89389659
Author: Hans Van Akelyen <ha...@gmail.com>
AuthorDate: Fri Jul 31 12:14:52 2026 +0200
[SONAR] fix some more issues (#7713)
---
.../org/apache/hop/core/util/TempFileUtil.java | 1 +
.../hop/core/logging/LogChannelFileWriter.java | 3 +
.../java/org/apache/hop/www/ShutdownServlet.java | 3 +
.../org/apache/hop/www/StartWorkflowServlet.java | 3 +
.../engines/remote/RemoteWorkflowEngineTest.java | 8 +--
.../actions/as400command/ActionAs400Command.java | 19 +++---
.../apache/hop/databases/db2/DB2DatabaseMeta.java | 1 +
.../hop/databases/derby/DerbyDatabaseMeta.java | 1 +
.../hop/databases/duckdb/DuckDBDatabaseMeta.java | 1 +
.../databases/informix/InformixDatabaseMeta.java | 1 +
.../hop/databases/sqlite/SqliteDatabaseMeta.java | 1 +
.../databases/teradata/TeradataDatabaseMeta.java | 1 +
.../org/apache/hop/beam/core/fn/TimestampFn.java | 4 ++
.../workflow/actions/mail/ActionMailDialog.java | 2 +
.../passwords/aes/Aes2TwoWayPasswordEncoder.java | 6 +-
.../hop/projects/resources/ResourceAttributes.java | 2 +
.../apache/hop/neo4j/core/data/GraphNodeData.java | 1 +
.../salesforce/SalesforceConnectionEditor.java | 2 +
.../transforms/databasejoin/DatabaseJoinMeta.java | 67 +++++++++++-----------
.../dynamicsqlrow/DynamicSqlRowMeta.java | 65 +++++++++++----------
.../transforms/excelwriter/ods/OdsExcelWriter.java | 36 +++++-------
.../ui/hopgui/file/shared/DrillDownGuiPlugin.java | 8 ++-
.../file/shared/PipelineRowSamplerHelper.java | 2 +
.../perspective/explorer/ExplorerPerspective.java | 11 +++-
.../hop/ui/hopgui/terminal/JediTerminalWidget.java | 6 +-
25 files changed, 144 insertions(+), 111 deletions(-)
diff --git a/core/src/main/java/org/apache/hop/core/util/TempFileUtil.java b/core/src/main/java/org/apache/hop/core/util/TempFileUtil.java
index ad9dd317a3..3b4af79ba8 100644
--- a/core/src/main/java/org/apache/hop/core/util/TempFileUtil.java
+++ b/core/src/main/java/org/apache/hop/core/util/TempFileUtil.java
@@ -56,6 +56,7 @@ public class TempFileUtil {
* @return the path of the newly created file
* @throws IOException in case the file could not be created
*/
+ @SuppressWarnings("java:S5443") // the permissions below are exactly what makes this safe
public static Path createTempFile(String prefix, String suffix) throws IOException {
if (POSIX) {
return Files.createTempFile(prefix, suffix, OWNER_ONLY);
diff --git a/engine/src/main/java/org/apache/hop/core/logging/LogChannelFileWriter.java b/engine/src/main/java/org/apache/hop/core/logging/LogChannelFileWriter.java
index e2785079b0..e924094b40 100644
--- a/engine/src/main/java/org/apache/hop/core/logging/LogChannelFileWriter.java
+++ b/engine/src/main/java/org/apache/hop/core/logging/LogChannelFileWriter.java
@@ -95,6 +95,9 @@ public class LogChannelFileWriter {
exception = null;
active.set(true);
+ // A platform thread on purpose: this one lives for the duration of the logging channel and is
+ // referenced by callers to join on, a virtual thread buys us nothing here.
+ @SuppressWarnings("java:S6881")
Thread thread =
new Thread(
() -> {
diff --git a/engine/src/main/java/org/apache/hop/www/ShutdownServlet.java b/engine/src/main/java/org/apache/hop/www/ShutdownServlet.java
index 4fb9ba3aea..27fd879140 100644
--- a/engine/src/main/java/org/apache/hop/www/ShutdownServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/ShutdownServlet.java
@@ -31,6 +31,9 @@ public class ShutdownServlet extends BaseHttpServlet {
/** Delay before the shutdown is performed, to give the servlet time to respond. */
private static final long SHUTDOWN_DELAY_MS = 2000L;
+ // Hop runs its own embedded server, not a managed JEE container. The timer below is what lets
+ // this servlet answer the request before the server it runs on is taken down.
+ @SuppressWarnings("java:S2654")
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
diff --git a/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java b/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java
index cf0a9e50ed..6ab9ab560f 100644
--- a/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java
+++ b/engine/src/main/java/org/apache/hop/www/StartWorkflowServlet.java
@@ -58,6 +58,9 @@ public class StartWorkflowServlet extends BaseHttpServlet implements IHopServerP
super(workflowMap);
}
+ // Hop runs its own embedded server, not a managed JEE container. The lock below guards the
+ // re-creation of a finished workflow against concurrent start requests.
+ @SuppressWarnings("java:S2654")
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
diff --git a/engine/src/test/java/org/apache/hop/workflow/engines/remote/RemoteWorkflowEngineTest.java b/engine/src/test/java/org/apache/hop/workflow/engines/remote/RemoteWorkflowEngineTest.java
index af1f8170c3..0543b74754 100644
--- a/engine/src/test/java/org/apache/hop/workflow/engines/remote/RemoteWorkflowEngineTest.java
+++ b/engine/src/test/java/org/apache/hop/workflow/engines/remote/RemoteWorkflowEngineTest.java
@@ -136,12 +136,12 @@ class RemoteWorkflowEngineTest {
engine.setMetadataProvider(metadataProvider);
engine.setVariable("RUN_CONFIG", "remote");
+ WorkflowRunConfiguration runConfiguration =
+ metadataProvider.getSerializer(WorkflowRunConfiguration.class).load("remote");
+
HopException e =
assertThrows(
- HopException.class,
- () ->
- engine.validateRunConfigurationChain(
- metadataProvider.getSerializer(WorkflowRunConfiguration.class).load("remote")));
+ HopException.class, () -> engine.validateRunConfigurationChain(runConfiguration));
assertTrue(e.getMessage().contains("remote -> remote"), "The chain should be reported: " + e);
}
diff --git a/plugins/databases/as400/src/main/java/org/apache/hop/workflow/actions/as400command/ActionAs400Command.java b/plugins/databases/as400/src/main/java/org/apache/hop/workflow/actions/as400command/ActionAs400Command.java
index 5d0210edb5..982c90dca2 100644
--- a/plugins/databases/as400/src/main/java/org/apache/hop/workflow/actions/as400command/ActionAs400Command.java
+++ b/plugins/databases/as400/src/main/java/org/apache/hop/workflow/actions/as400command/ActionAs400Command.java
@@ -317,20 +317,21 @@ public class ActionAs400Command extends ActionBase implements Cloneable, IAction
this.getProxyServer(variables.resolve(proxyHost), variables.resolve(proxyPort));
// Create an AS400 object
- AS400 system =
+ try (AS400 system =
new AS400(
variables.resolve(server),
variables.resolve(user),
Utils.resolvePassword(this, password),
- proxyServer);
- try {
- system.connectService(AS400.COMMAND);
- } finally {
+ proxyServer)) {
try {
- // This is only a connection test, so release the service again
- system.disconnectService(AS400.COMMAND);
- } catch (Exception e) {
- // Ignore
+ system.connectService(AS400.COMMAND);
+ } finally {
+ try {
+ // This is only a connection test, so release the service again
+ system.disconnectService(AS400.COMMAND);
+ } catch (Exception e) {
+ // Ignore
+ }
}
}
diff --git a/plugins/databases/db2/src/main/java/org/apache/hop/databases/db2/DB2DatabaseMeta.java b/plugins/databases/db2/src/main/java/org/apache/hop/databases/db2/DB2DatabaseMeta.java
index b379b13631..28a41317f7 100644
--- a/plugins/databases/db2/src/main/java/org/apache/hop/databases/db2/DB2DatabaseMeta.java
+++ b/plugins/databases/db2/src/main/java/org/apache/hop/databases/db2/DB2DatabaseMeta.java
@@ -61,6 +61,7 @@ public class DB2DatabaseMeta extends BaseDatabaseMeta implements IDatabase {
}
@Override
+ @SuppressWarnings("java:S1313") // the driver version is not an IP address
public DriverDownload getDriverDownload() {
return DriverDownload.builder()
.mavenCoordinate("com.ibm.db2:jcc")
diff --git a/plugins/databases/derby/src/main/java/org/apache/hop/databases/derby/DerbyDatabaseMeta.java b/plugins/databases/derby/src/main/java/org/apache/hop/databases/derby/DerbyDatabaseMeta.java
index 29aa0f02db..90fc8364e4 100644
--- a/plugins/databases/derby/src/main/java/org/apache/hop/databases/derby/DerbyDatabaseMeta.java
+++ b/plugins/databases/derby/src/main/java/org/apache/hop/databases/derby/DerbyDatabaseMeta.java
@@ -60,6 +60,7 @@ public class DerbyDatabaseMeta extends BaseDatabaseMeta implements IDatabase {
}
@Override
+ @SuppressWarnings("java:S1313") // the driver version is not an IP address
public DriverDownload getDriverDownload() {
return DriverDownload.builder()
.mavenCoordinate("org.apache.derby:derbyclient")
diff --git a/plugins/databases/duckdb/src/main/java/org/apache/hop/databases/duckdb/DuckDBDatabaseMeta.java b/plugins/databases/duckdb/src/main/java/org/apache/hop/databases/duckdb/DuckDBDatabaseMeta.java
index ed41946c24..e2ec8c6f1b 100644
--- a/plugins/databases/duckdb/src/main/java/org/apache/hop/databases/duckdb/DuckDBDatabaseMeta.java
+++ b/plugins/databases/duckdb/src/main/java/org/apache/hop/databases/duckdb/DuckDBDatabaseMeta.java
@@ -142,6 +142,7 @@ public class DuckDBDatabaseMeta extends BaseDatabaseMeta implements IDatabase {
}
@Override
+ @SuppressWarnings("java:S1313") // the driver version is not an IP address
public DriverDownload getDriverDownload() {
return DriverDownload.builder()
.mavenCoordinate("org.duckdb:duckdb_jdbc")
diff --git a/plugins/databases/informix/src/main/java/org/apache/hop/databases/informix/InformixDatabaseMeta.java b/plugins/databases/informix/src/main/java/org/apache/hop/databases/informix/InformixDatabaseMeta.java
index 836abbb0b7..50293eeb45 100644
--- a/plugins/databases/informix/src/main/java/org/apache/hop/databases/informix/InformixDatabaseMeta.java
+++ b/plugins/databases/informix/src/main/java/org/apache/hop/databases/informix/InformixDatabaseMeta.java
@@ -75,6 +75,7 @@ public class InformixDatabaseMeta extends BaseDatabaseMeta implements IDatabase
}
@Override
+ @SuppressWarnings("java:S1313") // the driver version is not an IP address
public DriverDownload getDriverDownload() {
return DriverDownload.builder()
.mavenCoordinate("com.ibm.informix:jdbc")
diff --git a/plugins/databases/sqlite/src/main/java/org/apache/hop/databases/sqlite/SqliteDatabaseMeta.java b/plugins/databases/sqlite/src/main/java/org/apache/hop/databases/sqlite/SqliteDatabaseMeta.java
index e935b8874b..b37a434250 100644
--- a/plugins/databases/sqlite/src/main/java/org/apache/hop/databases/sqlite/SqliteDatabaseMeta.java
+++ b/plugins/databases/sqlite/src/main/java/org/apache/hop/databases/sqlite/SqliteDatabaseMeta.java
@@ -61,6 +61,7 @@ public class SqliteDatabaseMeta extends BaseDatabaseMeta implements IDatabase {
}
@Override
+ @SuppressWarnings("java:S1313") // the driver version is not an IP address
public DriverDownload getDriverDownload() {
return DriverDownload.builder()
.mavenCoordinate("org.xerial:sqlite-jdbc")
diff --git a/plugins/databases/teradata/src/main/java/org/apache/hop/databases/teradata/TeradataDatabaseMeta.java b/plugins/databases/teradata/src/main/java/org/apache/hop/databases/teradata/TeradataDatabaseMeta.java
index 11f3fe3ea3..ad9c238b50 100644
--- a/plugins/databases/teradata/src/main/java/org/apache/hop/databases/teradata/TeradataDatabaseMeta.java
+++ b/plugins/databases/teradata/src/main/java/org/apache/hop/databases/teradata/TeradataDatabaseMeta.java
@@ -67,6 +67,7 @@ public class TeradataDatabaseMeta extends BaseDatabaseMeta implements IDatabase
}
@Override
+ @SuppressWarnings("java:S1313") // the driver version is not an IP address
public DriverDownload getDriverDownload() {
return DriverDownload.builder()
.mavenCoordinate("com.teradata.jdbc:terajdbc")
diff --git a/plugins/engines/beam/src/main/java/org/apache/hop/beam/core/fn/TimestampFn.java b/plugins/engines/beam/src/main/java/org/apache/hop/beam/core/fn/TimestampFn.java
index 7d163a2cca..e09025cea3 100644
--- a/plugins/engines/beam/src/main/java/org/apache/hop/beam/core/fn/TimestampFn.java
+++ b/plugins/engines/beam/src/main/java/org/apache/hop/beam/core/fn/TimestampFn.java
@@ -128,6 +128,10 @@ public class TimestampFn extends DoFn<HopRow, HopRow> {
if (IValueMeta.TYPE_TIMESTAMP == fieldValueMeta.getType()) {
java.sql.Timestamp timestamp =
((ValueMetaTimestamp) fieldValueMeta).getTimestamp(fieldData);
+ if (timestamp == null) {
+ throw new HopException(
+ "Timestamp field contains a null value, this can't be used to set a timestamp on a bounded/unbounded collection of data");
+ }
instant = new Instant(timestamp.toInstant());
} else {
Date date = fieldValueMeta.getDate(fieldData);
diff --git a/plugins/misc/mail/src/main/java/org/apache/hop/mail/workflow/actions/mail/ActionMailDialog.java b/plugins/misc/mail/src/main/java/org/apache/hop/mail/workflow/actions/mail/ActionMailDialog.java
index 8b3ba6f7df..9c2ab1f97a 100644
--- a/plugins/misc/mail/src/main/java/org/apache/hop/mail/workflow/actions/mail/ActionMailDialog.java
+++ b/plugins/misc/mail/src/main/java/org/apache/hop/mail/workflow/actions/mail/ActionMailDialog.java
@@ -1204,6 +1204,8 @@ public class ActionMailDialog extends ActionDialog {
IMAGES_FILE_TYPES,
true);
if (filename != null) {
+ // Created once per image the user picks, reuse would gain us nothing
+ @SuppressWarnings("java:S2119")
Random random = new Random();
wContentID.setText(Long.toString(Math.abs(random.nextLong()), 32));
}
diff --git a/plugins/misc/passwords/src/main/java/org/apache/hop/passwords/aes/Aes2TwoWayPasswordEncoder.java b/plugins/misc/passwords/src/main/java/org/apache/hop/passwords/aes/Aes2TwoWayPasswordEncoder.java
index bcfd713469..c7679f582e 100644
--- a/plugins/misc/passwords/src/main/java/org/apache/hop/passwords/aes/Aes2TwoWayPasswordEncoder.java
+++ b/plugins/misc/passwords/src/main/java/org/apache/hop/passwords/aes/Aes2TwoWayPasswordEncoder.java
@@ -52,6 +52,9 @@ public class Aes2TwoWayPasswordEncoder implements ITwoWayPasswordEncoder {
public static final String AES_PREFIX = "AES2 ";
public static final String AES_ALGORITHM = "AES/GCM/NoPadding";
+ /** {@link SecureRandom} is thread safe, seeding it once per encoded password is wasteful. */
+ private static final SecureRandom SECURE_RANDOM = new SecureRandom();
+
private SecretKeySpec secretKeySpec;
@Override
@@ -103,8 +106,7 @@ public class Aes2TwoWayPasswordEncoder implements ITwoWayPasswordEncoder {
// Generate a new, unique 12-byte IV for this encryption
byte[] iv = new byte[12];
- SecureRandom secureRandom = new SecureRandom();
- secureRandom.nextBytes(iv);
+ SECURE_RANDOM.nextBytes(iv);
// Initialize a new Cipher with the unique IV
GCMParameterSpec parameterSpec = new GCMParameterSpec(128, iv);
diff --git a/plugins/misc/projects/src/main/java/org/apache/hop/projects/resources/ResourceAttributes.java b/plugins/misc/projects/src/main/java/org/apache/hop/projects/resources/ResourceAttributes.java
index 2d3878ccc0..50f8819c77 100644
--- a/plugins/misc/projects/src/main/java/org/apache/hop/projects/resources/ResourceAttributes.java
+++ b/plugins/misc/projects/src/main/java/org/apache/hop/projects/resources/ResourceAttributes.java
@@ -68,6 +68,8 @@ public final class ResourceAttributes {
* <li>Development / CI / CB / other → off
* </ul>
*/
+ // False positive: StringUtils.isNotBlank() is false for null, so 'explicit' can't be null here
+ @SuppressWarnings("javabugs:S2259")
public static String resolveOnEnable(IAttributes attributes, String purpose) {
String explicit = attributes != null ? attributes.getAttribute(GROUP, KEY_ON_ENABLE) : null;
if (StringUtils.isNotBlank(explicit)) {
diff --git a/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/data/GraphNodeData.java b/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/data/GraphNodeData.java
index 51522be616..f4380a5e34 100644
--- a/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/data/GraphNodeData.java
+++ b/plugins/tech/neo4j/src/main/java/org/apache/hop/neo4j/core/data/GraphNodeData.java
@@ -110,6 +110,7 @@ public class GraphNodeData {
}
public GraphNodeData(JSONObject jNode) {
+ this();
id = (String) jNode.get("id");
JSONArray jLabels = (JSONArray) jNode.get("labels");
diff --git a/plugins/tech/salesforce/src/main/java/org/apache/hop/metadata/salesforce/SalesforceConnectionEditor.java b/plugins/tech/salesforce/src/main/java/org/apache/hop/metadata/salesforce/SalesforceConnectionEditor.java
index d7a40f2657..ed61d4cd48 100644
--- a/plugins/tech/salesforce/src/main/java/org/apache/hop/metadata/salesforce/SalesforceConnectionEditor.java
+++ b/plugins/tech/salesforce/src/main/java/org/apache/hop/metadata/salesforce/SalesforceConnectionEditor.java
@@ -778,6 +778,8 @@ public class SalesforceConnectionEditor extends MetadataEditor<SalesforceConnect
private void generatePKCEParameters() {
try {
// Generate code verifier (43-128 characters, URL-safe)
+ // Created once per OAuth authorization flow, reuse would gain us nothing
+ @SuppressWarnings("java:S2119")
SecureRandom secureRandom = new SecureRandom();
byte[] randomBytes = new byte[32];
secureRandom.nextBytes(randomBytes);
diff --git a/plugins/transforms/databasejoin/src/main/java/org/apache/hop/pipeline/transforms/databasejoin/DatabaseJoinMeta.java b/plugins/transforms/databasejoin/src/main/java/org/apache/hop/pipeline/transforms/databasejoin/DatabaseJoinMeta.java
index e36278e200..a8d9ce0902 100644
--- a/plugins/transforms/databasejoin/src/main/java/org/apache/hop/pipeline/transforms/databasejoin/DatabaseJoinMeta.java
+++ b/plugins/transforms/databasejoin/src/main/java/org/apache/hop/pipeline/transforms/databasejoin/DatabaseJoinMeta.java
@@ -283,50 +283,49 @@ public class DatabaseJoinMeta extends BaseTransformMeta<DatabaseJoin, DatabaseJo
e);
}
- Database db = new Database(loggingObject, variables, databaseMeta);
- databases = new Database[] {db}; // Keep track of this one for cancelQuery
-
- // Which fields are parameters?
- // info[0] comes from the database connection.
- //
- IRowMeta param = getParameterRow(row);
+ try (Database db = new Database(loggingObject, variables, databaseMeta)) {
+ databases = new Database[] {db}; // Keep track of this one for cancelQuery
- // First try without connecting to the database... (can be S L O W)
- // See if it's in the cache...
- //
- IRowMeta add = null;
- try {
- add = db.getQueryFields(variables.resolve(sql), true, param, new Object[param.size()]);
- } catch (HopDatabaseException dbe) {
- throw new HopTransformException(
- BaseMessages.getString(PKG, "DatabaseJoinMeta.Exception.UnableToDetermineQueryFields")
- + Const.CR
- + sql,
- dbe);
- }
+ // Which fields are parameters?
+ // info[0] comes from the database connection.
+ //
+ IRowMeta param = getParameterRow(row);
- if (add != null) { // Cache hit, just return it this...
- for (int i = 0; i < add.size(); i++) {
- IValueMeta v = add.getValueMeta(i);
- v.setOrigin(name);
- }
- row.addRowMeta(add);
- } else {
- // No cache hit, connect to the database, do it the hard way...
+ // First try without connecting to the database... (can be S L O W)
+ // See if it's in the cache...
//
+ IRowMeta add = null;
try {
- db.connect();
add = db.getQueryFields(variables.resolve(sql), true, param, new Object[param.size()]);
+ } catch (HopDatabaseException dbe) {
+ throw new HopTransformException(
+ BaseMessages.getString(PKG, "DatabaseJoinMeta.Exception.UnableToDetermineQueryFields")
+ + Const.CR
+ + sql,
+ dbe);
+ }
+
+ if (add != null) { // Cache hit, just return it this...
for (int i = 0; i < add.size(); i++) {
IValueMeta v = add.getValueMeta(i);
v.setOrigin(name);
}
row.addRowMeta(add);
- } catch (HopDatabaseException dbe) {
- throw new HopTransformException(
- BaseMessages.getString(PKG, "DatabaseJoinMeta.Exception.ErrorObtainingFields"), dbe);
- } finally {
- db.close();
+ } else {
+ // No cache hit, connect to the database, do it the hard way...
+ //
+ try {
+ db.connect();
+ add = db.getQueryFields(variables.resolve(sql), true, param, new Object[param.size()]);
+ for (int i = 0; i < add.size(); i++) {
+ IValueMeta v = add.getValueMeta(i);
+ v.setOrigin(name);
+ }
+ row.addRowMeta(add);
+ } catch (HopDatabaseException dbe) {
+ throw new HopTransformException(
+ BaseMessages.getString(PKG, "DatabaseJoinMeta.Exception.ErrorObtainingFields"), dbe);
+ }
}
}
}
diff --git a/plugins/transforms/dynamicsqlrow/src/main/java/org/apache/hop/pipeline/transforms/dynamicsqlrow/DynamicSqlRowMeta.java b/plugins/transforms/dynamicsqlrow/src/main/java/org/apache/hop/pipeline/transforms/dynamicsqlrow/DynamicSqlRowMeta.java
index ac169f6c30..b9eea3da64 100644
--- a/plugins/transforms/dynamicsqlrow/src/main/java/org/apache/hop/pipeline/transforms/dynamicsqlrow/DynamicSqlRowMeta.java
+++ b/plugins/transforms/dynamicsqlrow/src/main/java/org/apache/hop/pipeline/transforms/dynamicsqlrow/DynamicSqlRowMeta.java
@@ -150,48 +150,47 @@ public class DynamicSqlRowMeta extends BaseTransformMeta<DynamicSqlRow, DynamicS
return;
}
- Database db = new Database(loggingObject, variables, databaseMeta);
- // Keep track of this one for cancelQuery
- databases = new Database[] {db};
+ try (Database db = new Database(loggingObject, variables, databaseMeta)) {
+ // Keep track of this one for cancelQuery
+ databases = new Database[] {db};
- // First try without connecting to the database... (can be S L O W)
- // See if it's in the cache...
- IRowMeta add = null;
- String realSql = sql;
- if (replaceVariables) {
- realSql = variables.resolve(realSql);
- }
- try {
- add = db.getQueryFields(realSql, false);
- } catch (HopDatabaseException dbe) {
- throw new HopTransformException(
- BaseMessages.getString(PKG, "DynamicSQLRowMeta.Exception.UnableToDetermineQueryFields")
- + Const.CR
- + sql,
- dbe);
- }
- // Cache hit, just return it this...
- if (add != null) {
- for (int i = 0; i < add.size(); i++) {
- IValueMeta v = add.getValueMeta(i);
- v.setOrigin(name);
+ // First try without connecting to the database... (can be S L O W)
+ // See if it's in the cache...
+ IRowMeta add = null;
+ String realSql = sql;
+ if (replaceVariables) {
+ realSql = variables.resolve(realSql);
}
- row.addRowMeta(add);
- } else {
- // No cache hit, connect to the database, do it the hard way...
try {
- db.connect();
add = db.getQueryFields(realSql, false);
+ } catch (HopDatabaseException dbe) {
+ throw new HopTransformException(
+ BaseMessages.getString(PKG, "DynamicSQLRowMeta.Exception.UnableToDetermineQueryFields")
+ + Const.CR
+ + sql,
+ dbe);
+ }
+ // Cache hit, just return it this...
+ if (add != null) {
for (int i = 0; i < add.size(); i++) {
IValueMeta v = add.getValueMeta(i);
v.setOrigin(name);
}
row.addRowMeta(add);
- } catch (HopDatabaseException dbe) {
- throw new HopTransformException(
- BaseMessages.getString(PKG, "DynamicSQLRowMeta.Exception.ErrorObtainingFields"), dbe);
- } finally {
- db.close();
+ } else {
+ // No cache hit, connect to the database, do it the hard way...
+ try {
+ db.connect();
+ add = db.getQueryFields(realSql, false);
+ for (int i = 0; i < add.size(); i++) {
+ IValueMeta v = add.getValueMeta(i);
+ v.setOrigin(name);
+ }
+ row.addRowMeta(add);
+ } catch (HopDatabaseException dbe) {
+ throw new HopTransformException(
+ BaseMessages.getString(PKG, "DynamicSQLRowMeta.Exception.ErrorObtainingFields"), dbe);
+ }
}
}
}
diff --git a/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ods/OdsExcelWriter.java b/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ods/OdsExcelWriter.java
index 9c406c122c..3fa854f3e0 100644
--- a/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ods/OdsExcelWriter.java
+++ b/plugins/transforms/excel/src/main/java/org/apache/hop/pipeline/transforms/excelwriter/ods/OdsExcelWriter.java
@@ -262,12 +262,9 @@ public class OdsExcelWriter {
}
public void closeOutputFile(ExcelWriterWorkbookDefinition fileDefinition) throws HopException {
- OutputStream out = null;
- CountingOutputStream countingOut = null;
- try {
- countingOut =
- new CountingOutputStream(HopVfs.getOutputStream(fileDefinition.getFile(), false));
- out = new BufferedOutputStream(countingOut);
+ try (CountingOutputStream countingOut =
+ new CountingOutputStream(HopVfs.getOutputStream(fileDefinition.getFile(), false));
+ OutputStream out = new BufferedOutputStream(countingOut)) {
if (meta.isFooterEnabled()) {
writeHeader(fileDefinition, fileDefinition.getPosX(), fileDefinition.getPosY());
@@ -285,23 +282,18 @@ public class OdsExcelWriter {
if (meta.isForceFormulaRecalculation()) {
OdsFormulaHelper.prepareForRecalculation(document);
}
- document.save(out);
- document.close();
- } catch (Exception e) {
- throw new HopException(e);
- } finally {
- if (out != null) {
- try {
- out.flush();
- if (countingOut != null) {
- long written = countingOut.getCount();
- transform.recordBytesWritten(written, fileDefinition.getFile());
- }
- out.close();
- } catch (Exception e) {
- throw new HopException("Error closing ODS file " + fileDefinition.getFile(), e);
- }
+ try {
+ document.save(out);
+ } finally {
+ document.close();
}
+
+ // Flush before reading the byte count, the stream is closed by the resource block
+ //
+ out.flush();
+ transform.recordBytesWritten(countingOut.getCount(), fileDefinition.getFile());
+ } catch (Exception e) {
+ throw new HopException("Error closing ODS file " + fileDefinition.getFile(), e);
}
}
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/DrillDownGuiPlugin.java b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/DrillDownGuiPlugin.java
index a33b656b19..35b4abb877 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/DrillDownGuiPlugin.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/DrillDownGuiPlugin.java
@@ -243,7 +243,8 @@ public class DrillDownGuiPlugin {
*/
private void findRunningChildAndOpen(
Object parentEngine, String childName, Display display, HopGui hopGui) {
- new Thread(
+ Thread.ofVirtual()
+ .start(
() -> {
try {
for (int i = 0; i < 50; i++) {
@@ -268,11 +269,12 @@ public class DrillDownGuiPlugin {
Thread.sleep(100);
}
display.asyncExec(() -> showNoRunningExecution(hopGui));
+ } catch (InterruptedException e) {
+ Thread.currentThread().interrupt();
} catch (Exception e) {
// Ignore
}
- })
- .start();
+ });
}
/**
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/PipelineRowSamplerHelper.java b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/PipelineRowSamplerHelper.java
index 632858f014..f4412eedd7 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/PipelineRowSamplerHelper.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/file/shared/PipelineRowSamplerHelper.java
@@ -135,6 +135,8 @@ public final class PipelineRowSamplerHelper {
if (meta == null) {
return;
}
+ // Created once per pipeline start and shared by all the row listeners below
+ @SuppressWarnings("java:S2119")
final Random random = new Random();
// Per-key counters for Random sampling (transform name or hop key)
final Map<String, AtomicInteger> rowCounters = new ConcurrentHashMap<>();
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
index f294f82414..eba5a019ba 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/perspective/explorer/ExplorerPerspective.java
@@ -1807,7 +1807,12 @@ public class ExplorerPerspective implements IHopPerspective, TabClosable, IFileD
private void updateClosedFileIfNameSynchronized(FileObject targetFile) {
try {
String filename = HopVfs.getFilename(targetFile);
- String extension = filename.substring(filename.lastIndexOf('.'));
+ int dotIndex = filename.lastIndexOf('.');
+ if (dotIndex < 0) {
+ // No extension: not a pipeline or workflow file
+ return;
+ }
+ String extension = filename.substring(dotIndex);
// Check if it's a pipeline or workflow file
if (".hpl".equalsIgnoreCase(extension)) {
@@ -2575,6 +2580,10 @@ public class ExplorerPerspective implements IHopPerspective, TabClosable, IFileD
* @return The selected explorer file or null if nothing is selected
*/
public ExplorerFile getSelectedFile() {
+ if (tree == null) {
+ // The perspective was never initialized, there's nothing to select
+ return null;
+ }
TreeItem[] selection = tree.getSelection();
if (selection == null || selection.length == 0) {
return null;
diff --git a/ui/src/main/java/org/apache/hop/ui/hopgui/terminal/JediTerminalWidget.java b/ui/src/main/java/org/apache/hop/ui/hopgui/terminal/JediTerminalWidget.java
index 4b4914ced8..91c865e5fe 100644
--- a/ui/src/main/java/org/apache/hop/ui/hopgui/terminal/JediTerminalWidget.java
+++ b/ui/src/main/java/org/apache/hop/ui/hopgui/terminal/JediTerminalWidget.java
@@ -340,7 +340,8 @@ public class JediTerminalWidget implements ITerminalWidget {
jediTermWidget.start();
// Request focus after terminal initialization
- new Thread(
+ Thread.ofVirtual()
+ .start(
() -> {
try {
Thread.sleep(100);
@@ -359,8 +360,7 @@ public class JediTerminalWidget implements ITerminalWidget {
} catch (Exception e) {
log.logDebug("Error requesting initial AWT focus: " + e.getMessage());
}
- })
- .start();
+ });
} catch (Exception e) {
log.logError("Error starting JediTerm shell process", e);