diff --git a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/HawkbitEclipseLinkJpaDialect.java b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/HawkbitEclipseLinkJpaDialect.java
index 0c3996a01..845a37d70 100644
--- a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/HawkbitEclipseLinkJpaDialect.java
+++ b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/main/java/org/eclipse/hawkbit/repository/jpa/HawkbitEclipseLinkJpaDialect.java
@@ -10,63 +10,85 @@
package org.eclipse.hawkbit.repository.jpa;
import java.io.Serial;
+import java.lang.reflect.Field;
+import java.sql.Connection;
import java.sql.SQLException;
+import java.util.concurrent.locks.ReentrantLock;
+import jakarta.persistence.EntityManager;
import jakarta.persistence.PersistenceException;
+import lombok.extern.slf4j.Slf4j;
import org.eclipse.hawkbit.repository.jpa.utils.JpaExceptionTranslator;
import org.springframework.dao.DataAccessException;
+import org.springframework.jdbc.datasource.ConnectionHandle;
import org.springframework.jdbc.support.SQLStateSQLExceptionTranslator;
import org.springframework.lang.NonNull;
import org.springframework.orm.jpa.JpaSystemException;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaDialect;
/**
- * {@link EclipseLinkJpaDialect} with additional exception translation
- * mechanisms based on {@link SQLStateSQLExceptionTranslator}.
- *
- * There are multiple variations of exceptions coming out of persistence
- * provider:
- *
- *
- * 1) {@link PersistenceException}s that can be mapped by
- * {@link EclipseLinkJpaDialect} into corresponding {@link DataAccessException}.
- *
- * 2) {@link PersistenceException}s that could not be mapped by
- * {@link EclipseLinkJpaDialect} directly but instead are wrapped into
- * {@link JpaSystemException}.
- *
- * 2.a) here the wrapped exception's causes might be an {@link SQLException}
- * which might be mappable by {@link SQLStateSQLExceptionTranslator} or
- *
- * 2.b.) the wrapped exception's causes due not contain an {@link SQLException}
- * and as a result cannot be mapped.
- *
- * 3) A {@link RuntimeException} that is no {@link PersistenceException}.
- *
- * 3.a) here a cause might be an {@link SQLException} which might be mappable by
- * {@link SQLStateSQLExceptionTranslator} or
- *
- * 3.b.) the cause is not an {@link SQLException} and as a result cannot be
- * mapped.
+ * {@link EclipseLinkJpaDialect} with additional exception translation mechanisms based on {@link SQLStateSQLExceptionTranslator}.
+ * There are multiple variations of exceptions coming out of persistence provider:
+ *
+ * - {@link PersistenceException}s that can be mapped by {@link EclipseLinkJpaDialect} into corresponding {@link DataAccessException}
+ * - {@link PersistenceException}s that could not be mapped by {@link EclipseLinkJpaDialect} directly but instead are wrapped into {@link JpaSystemException}.
+ *
+ * - here the wrapped exception's causes might be an {@link SQLException} which might be mappable by {@link SQLStateSQLExceptionTranslator} or
+ * - the wrapped exception's causes due not contain an {@link SQLException} and as a result cannot be mapped.
+ *
+ *
+ * - A {@link RuntimeException} that is no {@link PersistenceException}.
+ *
+ * - here a cause might be an {@link SQLException} which might be mappable by {@link SQLStateSQLExceptionTranslator} or
+ * - the cause is not an {@link SQLException} and as a result cannot be mapped.
+ *
+ *
+ *
*/
+@Slf4j
class HawkbitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
@Serial
private static final long serialVersionUID = 1L;
+ // TODO: switch to Spring fix - temporarily workaround of https://github.com/eclipse-hawkbit/hawkbit/issues/2876
+ // (https://github.com/spring-projects/spring-framework/issues/36165)
+ private final ReentrantLock supperTransactionIsolationLock;
+ @SuppressWarnings("java:S3011") // temporarily - to workaround bug in supper class
+ HawkbitEclipseLinkJpaDialect() {
+ try {
+ final Field field = EclipseLinkJpaDialect.class.getDeclaredField("transactionIsolationLock");
+ field.setAccessible(true);
+ supperTransactionIsolationLock = (ReentrantLock) field.get(this);
+ } catch (final NoSuchFieldException | IllegalAccessException e) {
+ log.error(e.getMessage(), e);
+ throw new IllegalStateException("Cannot access supper class field transactionIsolationLock", e);
+ }
+ }
+ // hawkbit uses JDBC and no need of lazy connection fetching
+ @Override
+ public ConnectionHandle getJdbcConnection(final EntityManager entityManager, final boolean readOnly) throws PersistenceException {
+ final Connection connection;
+ supperTransactionIsolationLock.lock();
+ try {
+ connection = entityManager.unwrap(Connection.class);
+ } finally {
+ supperTransactionIsolationLock.unlock();
+ }
+ return () -> connection;
+ }
+
@Override
public DataAccessException translateExceptionIfPossible(@NonNull final RuntimeException ex) {
final DataAccessException dataAccessException = super.translateExceptionIfPossible(ex);
-
if (dataAccessException == null) {
return searchAndTranslateSqlException(ex);
}
return translateJpaSystemExceptionIfPossible(dataAccessException);
}
- private static DataAccessException translateJpaSystemExceptionIfPossible(
- final DataAccessException accessException) {
+ private static DataAccessException translateJpaSystemExceptionIfPossible(final DataAccessException accessException) {
if (!(accessException instanceof JpaSystemException)) {
return accessException;
}
@@ -83,7 +105,6 @@ class HawkbitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
if (sqlException == null) {
return null;
}
-
return JpaExceptionTranslator.getTranslator().translate("", null, sqlException);
}
@@ -96,7 +117,6 @@ class HawkbitEclipseLinkJpaDialect extends EclipseLinkJpaDialect {
}
exception = cause;
} while (exception != null);
-
return null;
}
}
\ No newline at end of file
diff --git a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/test/java/org/eclipse/hawkbit/repository/jpa/HawkBitEclipseLinkJpaDialectTest.java b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/test/java/org/eclipse/hawkbit/repository/jpa/HawkbitEclipseLinkJpaDialectTest.java
similarity index 98%
rename from hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/test/java/org/eclipse/hawkbit/repository/jpa/HawkBitEclipseLinkJpaDialectTest.java
rename to hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/test/java/org/eclipse/hawkbit/repository/jpa/HawkbitEclipseLinkJpaDialectTest.java
index 4a99d4092..2b693bc26 100644
--- a/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/test/java/org/eclipse/hawkbit/repository/jpa/HawkBitEclipseLinkJpaDialectTest.java
+++ b/hawkbit-repository/hawkbit-repository-jpa-eclipselink/src/test/java/org/eclipse/hawkbit/repository/jpa/HawkbitEclipseLinkJpaDialectTest.java
@@ -28,7 +28,7 @@ import org.springframework.dao.UncategorizedDataAccessException;
* Feature: Unit Tests - Repository
* Story: Exception handling
*/
-class HawkBitEclipseLinkJpaDialectTest {
+class HawkbitEclipseLinkJpaDialectTest {
private final HawkbitEclipseLinkJpaDialect hawkBitEclipseLinkJpaDialectUnderTest = new HawkbitEclipseLinkJpaDialect();