From 128af7ae13ac3b47a342a8b482c906a5b38727fd Mon Sep 17 00:00:00 2001 From: David M Date: Sat, 10 Jan 2026 12:21:56 +0100 Subject: [PATCH 1/2] fixed sonar findings --- .../src/main/java/org/freedesktop/dbus/Marshalling.java | 3 +-- .../java/org/freedesktop/dbus/RemoteInvocationHandler.java | 7 +++---- .../src/main/java/org/freedesktop/dbus/utils/Util.java | 7 +------ .../github/hypfvieh/dbus/examples/daemon/RunDaemon.java | 3 +-- .../hypfvieh/dbus/examples/systemd/PrintUserSessions.java | 3 +-- .../src/test/java/sample/issue/ExportClass.java | 4 +--- .../src/test/java/sample/issue/Issue290Test.java | 4 +--- 7 files changed, 9 insertions(+), 22 deletions(-) diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/Marshalling.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/Marshalling.java index c7872a7ee..17804f5a0 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/Marshalling.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/Marshalling.java @@ -759,8 +759,7 @@ public static Object[] deSerializeParameters(Object[] _parameters, Type[] _types return new Object[] {o}; } else if (!_methodCall && Struct.class.isAssignableFrom(clz)) { LOGGER.trace("(4) Deserializing Struct return"); - Object[] val = deSerializeParameters(_parameters, types, _conn, true); - return val; + return deSerializeParameters(_parameters, types, _conn, true); } } diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java index 393fd7234..2a856eb08 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/RemoteInvocationHandler.java @@ -58,8 +58,9 @@ public Object invoke(Object _proxy, Method _method, Object[] _args) throws Throw return _args[0] != null && remote.equals(((RemoteInvocationHandler) Proxy.getInvocationHandler(_args[0])).remote); } } catch (IllegalArgumentException _exIa) { - return Boolean.FALSE; + LOGGER.trace("Error calling equals method", _exIa); } + return Boolean.FALSE; case "finalize": return null; case "getClass": @@ -85,10 +86,8 @@ public Object invoke(Object _proxy, Method _method, Object[] _args) throws Throw } else if (_args.length == 2 && _args[0] instanceof Long l && _args[1] instanceof Integer i) { remote.wait(l, i); } - if (_args.length <= 2) { - return null; - } } + return null; case "toString": return remote.toString(); default: diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java index 90234322a..ae7f68953 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java @@ -306,12 +306,7 @@ public static List getTextfileFromUrl(String _url, Charset _charset, boo } try { - URL dlUrl; - if (fileUrl.startsWith("file:/")) { - dlUrl = new URI(fileUrl).toURL(); - } else { - dlUrl = new URI(fileUrl).toURL(); - } + URL dlUrl = new URI(fileUrl).toURL(); URLConnection urlConn = dlUrl.openConnection(); urlConn.setDoInput(true); urlConn.setUseCaches(false); diff --git a/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/daemon/RunDaemon.java b/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/daemon/RunDaemon.java index f99fc500f..021c9a8e8 100755 --- a/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/daemon/RunDaemon.java +++ b/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/daemon/RunDaemon.java @@ -10,7 +10,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.IOException; import java.time.Duration; import java.util.Objects; @@ -55,7 +54,7 @@ private void startDaemon() { } @SuppressWarnings("PMD.UnusedLocalVariable") - private void connectSelf() throws DBusException, IOException { + private void connectSelf() throws DBusException { BusAddress busAddress = BusAddress.of(newAddress); log.info("Connecting to embedded DBus {}", busAddress); try (DBusConnection conn = DBusConnectionBuilder.forAddress(busAddress).build()) { diff --git a/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/systemd/PrintUserSessions.java b/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/systemd/PrintUserSessions.java index 693905fc9..28f4fe780 100644 --- a/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/systemd/PrintUserSessions.java +++ b/dbus-java-examples/src/main/java/com/github/hypfvieh/dbus/examples/systemd/PrintUserSessions.java @@ -9,7 +9,6 @@ import org.freedesktop.dbus.exceptions.DBusException; import org.freedesktop.dbus.interfaces.Properties; -import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.List; @@ -51,7 +50,7 @@ public final class PrintUserSessions { private PrintUserSessions() {} public static void main(String[] _args) - throws IOException, DBusException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { + throws DBusException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { try (DBusConnection sessionConnection = DBusConnectionBuilder.forSystemBus().build()) { diff --git a/dbus-java-tests/src/test/java/sample/issue/ExportClass.java b/dbus-java-tests/src/test/java/sample/issue/ExportClass.java index b8c3b752e..d66074e77 100644 --- a/dbus-java-tests/src/test/java/sample/issue/ExportClass.java +++ b/dbus-java-tests/src/test/java/sample/issue/ExportClass.java @@ -5,8 +5,6 @@ import org.freedesktop.dbus.interfaces.DBusInterface; import org.slf4j.LoggerFactory; -import java.io.IOException; - public class ExportClass implements DBusInterface { @Override @@ -19,7 +17,7 @@ public String getObjectPath() { return "/"; } - public static void main(String[] _args) throws DBusException, InterruptedException, IOException { + public static void main(String[] _args) throws DBusException, InterruptedException { try (DBusConnection conn = DBusConnectionBuilder.forSessionBus().build()) { conn.requestBusName("sample.issue"); diff --git a/dbus-java-tests/src/test/java/sample/issue/Issue290Test.java b/dbus-java-tests/src/test/java/sample/issue/Issue290Test.java index e44bfa0ed..628824cd0 100644 --- a/dbus-java-tests/src/test/java/sample/issue/Issue290Test.java +++ b/dbus-java-tests/src/test/java/sample/issue/Issue290Test.java @@ -11,8 +11,6 @@ import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; -import java.io.IOException; - public class Issue290Test extends AbstractDBusDaemonBaseTest { private static DBusConnection connection; @@ -26,7 +24,7 @@ static void beforeAll() throws DBusException { } @AfterAll - static void afterAll() throws IOException { + static void afterAll() { if (connection != null) { connection.close(); } From 560c163e7f6fa47b0c8f2fe88bf8d474e04f1452 Mon Sep 17 00:00:00 2001 From: David M Date: Mon, 12 Jan 2026 14:56:42 +0100 Subject: [PATCH 2/2] Added support for virtual threads --- README.md | 4 + .../connections/base/ReceivingService.java | 38 +++++--- .../config/ReceivingServiceConfig.java | 96 +++++++++++++----- .../config/ReceivingServiceConfigBuilder.java | 97 ++++++++++++++++--- .../connections/shared/ExecutorNames.java | 16 ++- .../java/org/freedesktop/dbus/utils/Util.java | 17 ++++ .../base/ReceivingServiceTest.java | 76 ++++++++++----- .../org/freedesktop/dbus/utils/UtilTest.java | 24 +++++ 8 files changed, 291 insertions(+), 77 deletions(-) create mode 100644 dbus-java-tests/src/test/java/org/freedesktop/dbus/utils/UtilTest.java diff --git a/README.md b/README.md index ec6fb30d7..1bfbb3fe1 100644 --- a/README.md +++ b/README.md @@ -83,6 +83,10 @@ The library will remain open source and MIT licensed and can still be used, fork - with this change, you can also create Structs and use them as return value having something like `GetCurrentStateStruct` instead of using the long Tuple-name - Further details on this in [#285](https://github.com/hypfvieh/dbus-java/issues/285) - Added new commandline option `--disable-tuples` to `InterfaceCodeGenerator` to create `Struct` classes instead of `Tuple`s for multi value return (**Caution** the generated code will only work with dbus-java 6.0.0+) + - Added support for Virtual-Threads in `ReceivingService` + - This can be enabled using the `DBusConnectionBuilder`, example: `DBusConnection sessionConnection = DBusConnectionBuilder.forSystemBus().receivingThreadConfig().withAllVirtualThreads(true).connectionConfig().build()` + - Virtual-Threads can be enabled/disabled for each of the different executor services used in `ReceivingService`: `SIGNAL`, `ERROR`, `METHODCALL`, `METHODRETURN` + - default remains native threads on all executors ##### Changes in 5.2.0 (2025-12-21): - removed properties from dbus-java.version which causes issues with reproducable builds ([PR#279](https://github.com/hypfvieh/dbus-java/issues/279)) diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/base/ReceivingService.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/base/ReceivingService.java index 7620b4dc3..c38934b76 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/base/ReceivingService.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/base/ReceivingService.java @@ -9,13 +9,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Arrays; import java.util.Map; import java.util.Map.Entry; import java.util.Optional; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; -import java.util.concurrent.TimeUnit; +import java.util.concurrent.*; /** * Service providing threads for every type of message expected to be received by DBus. @@ -42,20 +40,34 @@ public class ReceivingService { ReceivingService(String _namePrefix, ReceivingServiceConfig _rsCfg) { String prefix = _namePrefix == null ? "" : _namePrefix; ReceivingServiceConfig rsCfg = Optional.ofNullable(_rsCfg).orElse(ReceivingServiceConfigBuilder.getDefaultConfig()); - executors.put(ExecutorNames.SIGNAL, - Executors.newFixedThreadPool(rsCfg.getSignalThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-Signal-Receiver-", true, rsCfg.getSignalThreadPriority()))); - executors.put(ExecutorNames.ERROR, - Executors.newFixedThreadPool(rsCfg.getErrorThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-Error-Receiver-", true, rsCfg.getErrorThreadPriority()))); - // we need multiple threads here so recursive method calls are possible - executors.put(ExecutorNames.METHODCALL, - Executors.newFixedThreadPool(rsCfg.getMethodCallThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-MethodCall-Receiver-", true, rsCfg.getMethodCallThreadPriority()))); - executors.put(ExecutorNames.METHODRETURN, - Executors.newFixedThreadPool(rsCfg.getMethodReturnThreadPoolSize(), new NameableThreadFactory(prefix + "DBus-MethodReturn-Receiver-", true, rsCfg.getMethodReturnThreadPriority()))); + Arrays.stream(ExecutorNames.values()) + .forEach(t -> { + executors.put(t, + Executors.newFixedThreadPool(rsCfg.getPoolSize(t), createFactory(prefix + t.getThreadName() + "-", _rsCfg.isVirtual(t), _rsCfg.getPriority(t)))); + }); retryHandler = rsCfg.getRetryHandler(); } + /** + * Create thread factory for creating native or virtual threads. + * + * @param _name name for created threads + * @param _virtualThreads true to create virtual threads + * @param _priority thread priority (only used for non-virtual threads) + * @return {@link ThreadFactory} + * + * @since 6.0.0 - 2026-01-10 + */ + private ThreadFactory createFactory(String _name, boolean _virtualThreads, int _priority) { + if (_virtualThreads) { + return Thread.ofVirtual().name(_name, 1L).factory(); + } else { + return new NameableThreadFactory(_name, true, _priority); + } + } + /** * Execute a runnable which handles a signal. * diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfig.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfig.java index b22fa27d8..622cc5158 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfig.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfig.java @@ -1,7 +1,12 @@ package org.freedesktop.dbus.connections.config; +import org.freedesktop.dbus.connections.shared.ExecutorNames; import org.freedesktop.dbus.connections.shared.IThreadPoolRetryHandler; +import java.util.EnumMap; +import java.util.Map; +import java.util.Optional; + /** * Bean which holds configuration for {@link org.freedesktop.dbus.connections.base.ReceivingService}. * @@ -9,90 +14,133 @@ * @since 4.2.0 - 2022-07-14 */ public final class ReceivingServiceConfig { - private int signalThreadPoolSize = 1; - private int errorThreadPoolSize = 1; - private int methodCallThreadPoolSize = 4; - private int methodReturnThreadPoolSize = 1; - private int signalThreadPriority = Thread.NORM_PRIORITY; - private int methodCallThreadPriority = Thread.NORM_PRIORITY; - private int errorThreadPriority = Thread.NORM_PRIORITY; - private int methodReturnThreadPriority = Thread.NORM_PRIORITY; + + private final Map threadConfigs = new EnumMap<>(ExecutorNames.class); private IThreadPoolRetryHandler retryHandler; ReceivingServiceConfig() { + threadConfigs.put(ExecutorNames.SIGNAL, new ThreadCfg(1, Thread.NORM_PRIORITY, false)); + threadConfigs.put(ExecutorNames.ERROR, new ThreadCfg(1, Thread.NORM_PRIORITY, false)); + threadConfigs.put(ExecutorNames.METHODCALL, new ThreadCfg(4, Thread.NORM_PRIORITY, false)); + threadConfigs.put(ExecutorNames.METHODRETURN, new ThreadCfg(1, Thread.NORM_PRIORITY, false)); } public int getSignalThreadPoolSize() { - return signalThreadPoolSize; + return threadConfigs.get(ExecutorNames.SIGNAL).poolSize(); } public int getErrorThreadPoolSize() { - return errorThreadPoolSize; + return threadConfigs.get(ExecutorNames.ERROR).poolSize(); } public int getMethodCallThreadPoolSize() { - return methodCallThreadPoolSize; + return threadConfigs.get(ExecutorNames.METHODCALL).poolSize(); } public int getMethodReturnThreadPoolSize() { - return methodReturnThreadPoolSize; + return threadConfigs.get(ExecutorNames.METHODRETURN).poolSize(); } public int getSignalThreadPriority() { - return signalThreadPriority; + return threadConfigs.get(ExecutorNames.SIGNAL).priority(); } public int getMethodCallThreadPriority() { - return methodCallThreadPriority; + return threadConfigs.get(ExecutorNames.METHODCALL).priority(); } public int getErrorThreadPriority() { - return errorThreadPriority; + return threadConfigs.get(ExecutorNames.ERROR).priority(); } public int getMethodReturnThreadPriority() { - return methodReturnThreadPriority; + return threadConfigs.get(ExecutorNames.METHODRETURN).priority(); } public IThreadPoolRetryHandler getRetryHandler() { return retryHandler; } + public boolean isSignalVirtualThreads() { + return threadConfigs.get(ExecutorNames.SIGNAL).virtual(); + } + + public boolean isErrorVirtualThreads() { + return threadConfigs.get(ExecutorNames.ERROR).virtual(); + } + + public boolean isMethodCallVirtualThreads() { + return threadConfigs.get(ExecutorNames.METHODCALL).virtual(); + } + + public boolean isMethodReturnVirtualThreads() { + return threadConfigs.get(ExecutorNames.METHODRETURN).virtual(); + } + + public boolean isVirtual(ExecutorNames _type) { + return Optional.ofNullable(_type).map(p -> threadConfigs.get(p).virtual()).orElseThrow(); + } + + public int getPoolSize(ExecutorNames _type) { + return Optional.ofNullable(_type).map(p -> threadConfigs.get(p).poolSize()).orElseThrow(); + } + + public int getPriority(ExecutorNames _type) { + return Optional.ofNullable(_type).map(p -> threadConfigs.get(p).priority()).orElseThrow(); + } + void setSignalThreadPoolSize(int _signalThreadPoolSize) { - signalThreadPoolSize = _signalThreadPoolSize; + threadConfigs.compute(ExecutorNames.SIGNAL, (t, u) -> new ThreadCfg(_signalThreadPoolSize, u.priority(), u.virtual())); } void setErrorThreadPoolSize(int _errorThreadPoolSize) { - errorThreadPoolSize = _errorThreadPoolSize; + threadConfigs.compute(ExecutorNames.ERROR, (t, u) -> new ThreadCfg(_errorThreadPoolSize, u.priority(), u.virtual())); } void setMethodCallThreadPoolSize(int _methodCallThreadPoolSize) { - methodCallThreadPoolSize = _methodCallThreadPoolSize; + threadConfigs.compute(ExecutorNames.METHODCALL, (t, u) -> new ThreadCfg(_methodCallThreadPoolSize, u.priority(), u.virtual())); } void setMethodReturnThreadPoolSize(int _methodReturnThreadPoolSize) { - methodReturnThreadPoolSize = _methodReturnThreadPoolSize; + threadConfigs.compute(ExecutorNames.METHODRETURN, (t, u) -> new ThreadCfg(_methodReturnThreadPoolSize, u.priority(), u.virtual())); } void setSignalThreadPriority(int _signalThreadPriority) { - signalThreadPriority = _signalThreadPriority; + threadConfigs.compute(ExecutorNames.SIGNAL, (t, u) -> new ThreadCfg(u.poolSize(), _signalThreadPriority, u.virtual())); } void setMethodCallThreadPriority(int _methodCallThreadPriority) { - methodCallThreadPriority = _methodCallThreadPriority; + threadConfigs.compute(ExecutorNames.METHODCALL, (t, u) -> new ThreadCfg(u.poolSize(), _methodCallThreadPriority, u.virtual())); } void setErrorThreadPriority(int _errorThreadPriority) { - errorThreadPriority = _errorThreadPriority; + threadConfigs.compute(ExecutorNames.ERROR, (t, u) -> new ThreadCfg(u.poolSize(), _errorThreadPriority, u.virtual())); } void setMethodReturnThreadPriority(int _methodReturnThreadPriority) { - methodReturnThreadPriority = _methodReturnThreadPriority; + threadConfigs.compute(ExecutorNames.METHODRETURN, (t, u) -> new ThreadCfg(u.poolSize(), _methodReturnThreadPriority, u.virtual())); } void setRetryHandler(IThreadPoolRetryHandler _retryHandler) { retryHandler = _retryHandler; } + void setSignalVirtualThreads(boolean _signalVirtualThreads) { + threadConfigs.compute(ExecutorNames.SIGNAL, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _signalVirtualThreads)); + } + + void setErrorVirtualThreads(boolean _errorVirtualThreads) { + threadConfigs.compute(ExecutorNames.ERROR, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _errorVirtualThreads)); + } + + void setMethodCallVirtualThreads(boolean _methodCallVirtualThreads) { + threadConfigs.compute(ExecutorNames.METHODCALL, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _methodCallVirtualThreads)); + } + + void setMethodReturnVirtualThreads(boolean _methodReturnVirtualThreads) { + threadConfigs.compute(ExecutorNames.METHODRETURN, (t, u) -> new ThreadCfg(u.poolSize(), u.priority(), _methodReturnVirtualThreads)); + } + + private record ThreadCfg(int poolSize, int priority, boolean virtual) {} } diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfigBuilder.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfigBuilder.java index f1313cbb8..386432af8 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfigBuilder.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/config/ReceivingServiceConfigBuilder.java @@ -26,14 +26,18 @@ public final class ReceivingServiceConfigBuilder connectionBuilder; @@ -114,7 +118,7 @@ public ReceivingServiceConfigBuilder withSignalThreadPriority(int _priority) } /** - * Sets the thread priority of the created signal thread(s). + * Sets the thread priority of the created error thread(s). *

* Default: {@link Thread#NORM_PRIORITY} ({@value Thread#NORM_PRIORITY}); * @@ -129,7 +133,7 @@ public ReceivingServiceConfigBuilder withErrorThreadPriority(int _priority) { } /** - * Sets the thread priority of the created signal thread(s). + * Sets the thread priority of the created method call thread(s). *

* Default: {@link Thread#NORM_PRIORITY} ({@value Thread#NORM_PRIORITY}); * @@ -144,7 +148,7 @@ public ReceivingServiceConfigBuilder withMethedCallThreadPriority(int _priori } /** - * Sets the thread priority of the created signal thread(s). + * Sets the thread priority of the created method return thread(s). *

* Default: {@link Thread#NORM_PRIORITY} ({@value Thread#NORM_PRIORITY}); * @@ -158,6 +162,85 @@ public ReceivingServiceConfigBuilder withMethodReturnThreadPriority(int _prio return this; } + /** + * Use virtual threads for the created signal thread(s). + *

+ * Default: {@value false}; + * + * @param _virtual true to use virtual threads, false to use native threads + * @return this + * + * @since 6.0.0 - 2026-01-10 + */ + public ReceivingServiceConfigBuilder withVirtualSignalThreads(boolean _virtual) { + config.setSignalVirtualThreads(_virtual); + return this; + } + + /** + * Use virtual threads for the created error thread(s). + *

+ * Default: {@value false}; + * + * @param _virtual true to use virtual threads, false to use native threads + * @return this + * + * @since 6.0.0 - 2026-01-10 + */ + public ReceivingServiceConfigBuilder withVirtualErrorThreads(boolean _virtual) { + config.setErrorVirtualThreads(_virtual); + return this; + } + + /** + * Use virtual threads for the created method call thread(s). + *

+ * Default: {@value false}; + * + * @param _virtual true to use virtual threads, false to use native threads + * @return this + * + * @since 6.0.0 - 2026-01-10 + */ + public ReceivingServiceConfigBuilder withMethodCallSignalThreads(boolean _virtual) { + config.setMethodCallVirtualThreads(_virtual); + return this; + } + + /** + * Use virtual threads for the created method return thread(s). + *

+ * Default: {@value false}; + * + * @param _virtual true to use virtual threads, false to use native threads + * @return this + * + * @since 6.0.0 - 2026-01-10 + */ + public ReceivingServiceConfigBuilder withVirtualMethodReturnThreads(boolean _virtual) { + config.setMethodReturnVirtualThreads(_virtual); + return this; + } + + /** + * Use virtual threads for all created thread(s). + *

+ * Default: {@value false}; + * + * @param _virtual true to use virtual threads, false to use native threads + * @return this + * + * @since 6.0.0 - 2026-01-10 + */ + public ReceivingServiceConfigBuilder withAllVirtualThreads(boolean _virtual) { + config.setSignalVirtualThreads(_virtual); + config.setMethodCallVirtualThreads(_virtual); + config.setErrorVirtualThreads(_virtual); + config.setMethodReturnVirtualThreads(_virtual); + + return this; + } + /** * Sets the retry handler which should be called when executing a runnable in {@link ReceivingService} thread pools fail. *

@@ -196,12 +279,4 @@ public static ReceivingServiceConfig getDefaultConfig() { return DEFAULT_CFG; } - /** - * Returns the default retry handler used for {@link ReceivingService}. - * @return default handler - */ - public static IThreadPoolRetryHandler getDefaultRetryHandler() { - return DEFAULT_RETRYHANDLER; - } - } diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/shared/ExecutorNames.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/shared/ExecutorNames.java index 34970b862..849c6f896 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/shared/ExecutorNames.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/connections/shared/ExecutorNames.java @@ -7,21 +7,27 @@ * @version 4.0.1 - 2022-02-02 */ public enum ExecutorNames { - SIGNAL("SignalExecutor"), - ERROR("ErrorExecutor"), - METHODCALL("MethodCallExecutor"), - METHODRETURN("MethodReturnExecutor"); + SIGNAL("SignalExecutor", "DBus-Signal-Receiver"), + ERROR("ErrorExecutor", "DBus-Error-Receiver"), + METHODCALL("MethodCallExecutor", "DBus-MethodCall-Receiver"), + METHODRETURN("MethodReturnExecutor", "DBus-MethodReturn-Receiver"); private final String description; + private final String threadName; - ExecutorNames(String _name) { + ExecutorNames(String _name, String _threadName) { description = _name; + threadName = _threadName; } public String getDescription() { return description; } + public String getThreadName() { + return threadName; + } + @Override public String toString() { return description; diff --git a/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java b/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java index ae7f68953..e844a3ce3 100644 --- a/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java +++ b/dbus-java-core/src/main/java/org/freedesktop/dbus/utils/Util.java @@ -733,4 +733,21 @@ public static String extractClassNameFromFqcn(String _fqcn) { return _fqcn.substring(lastDot + 1); } + /** + * Checks if the given value is not lower than the minimum. + * + * @param _minimum minimum allowed value + * @param _checkVal value to check + * + * @return checkVal if valid + * + * @throws IllegalArgumentException when value is lower than minimum + */ + public static int requireMinimum(int _minimum, int _checkVal) { + if (_checkVal < _minimum) { + throw new IllegalArgumentException("Value " + _checkVal + " is lower than the required minimum of " + _minimum); + } + return _checkVal; + } + } diff --git a/dbus-java-tests/src/test/java/org/freedesktop/dbus/connections/base/ReceivingServiceTest.java b/dbus-java-tests/src/test/java/org/freedesktop/dbus/connections/base/ReceivingServiceTest.java index 3ba51afba..a0632c309 100644 --- a/dbus-java-tests/src/test/java/org/freedesktop/dbus/connections/base/ReceivingServiceTest.java +++ b/dbus-java-tests/src/test/java/org/freedesktop/dbus/connections/base/ReceivingServiceTest.java @@ -7,6 +7,8 @@ import org.freedesktop.dbus.exceptions.IllegalThreadPoolStateException; import org.freedesktop.dbus.test.AbstractBaseTest; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.ValueSource; import java.util.Collection; import java.util.List; @@ -18,10 +20,14 @@ class ReceivingServiceTest extends AbstractBaseTest { /** * Tests that no retry is attempted when no retry handler is installed. */ - @Test - void testRetryHandlerNotUsed() { + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testRetryHandlerNotUsed(boolean _virtual) { - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).withRetryHandler(null).build(); + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withRetryHandler(null) + .withAllVirtualThreads(_virtual) + .build(); ReceivingService service = new ReceivingService("", build) { @Override @@ -38,8 +44,9 @@ ExecutorService getExecutor(ExecutorNames _executor) { /** * Tests that 5 retries will be attempted due to the handler returning true 5 times. */ - @Test - void testRetryHandlerCalled5Times() { + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testRetryHandlerCalled5Times(boolean _virtual) { IThreadPoolRetryHandler handler = new IThreadPoolRetryHandler() { private int count = 0; @@ -50,7 +57,9 @@ public boolean handle(ExecutorNames _executor, Exception _ex) { } }; - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).withRetryHandler(handler).build(); + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withAllVirtualThreads(_virtual) + .withRetryHandler(handler).build(); ReceivingService service = new ReceivingService("", build) { @Override @@ -67,9 +76,12 @@ ExecutorService getExecutor(ExecutorNames _executor) { /** * Test that the default retry handler is only called for the defined retries. */ - @Test - void testDefaultRetryHandler() { - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).build(); + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testDefaultRetryHandler(boolean _virtual) { + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withAllVirtualThreads(_virtual) + .build(); ReceivingService service = new ReceivingService("", build) { @Override @@ -87,11 +99,14 @@ ExecutorService getExecutor(ExecutorNames _executor) { /** * Test that retrying will be interrupted when the hard limit of {@value ReceivingService#MAX_RETRIES} is reached. */ - @Test - void testRetryHandlerHardLimit() { + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testRetryHandlerHardLimit(boolean _virtual) { IThreadPoolRetryHandler handler = (executor, ex) -> true; - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).withRetryHandler(handler).build(); + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withAllVirtualThreads(_virtual) + .withRetryHandler(handler).build(); ReceivingService service = new ReceivingService("", build) { @Override @@ -131,8 +146,9 @@ ExecutorService getExecutor(ExecutorNames _executor) { /** * Test that checks that the retry handler has not been called because no exception was thrown. */ - @Test - void testRetryHandlerNotCalledBecauseNoFailure() { + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testRetryHandlerNotCalledBecauseNoFailure(boolean _virtual) { AtomicBoolean handlerWasCalled = new AtomicBoolean(); IThreadPoolRetryHandler handler = (executor, ex) -> { @@ -140,7 +156,9 @@ void testRetryHandlerNotCalledBecauseNoFailure() { return true; }; - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).withRetryHandler(handler).build(); + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withAllVirtualThreads(_virtual) + .withRetryHandler(handler).build(); ReceivingService service = new ReceivingService("", build) { @Override @@ -160,9 +178,12 @@ ExecutorService getExecutor(ExecutorNames _executor) { /** * Test that a proper exception is thrown when no executor was returned. */ - @Test - void testExecutorNull() { - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).withRetryHandler(null).build(); + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testExecutorNull(boolean _virtual) { + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withAllVirtualThreads(_virtual) + .withRetryHandler(null).build(); ReceivingService service = new ReceivingService("", build) { @Override @@ -179,9 +200,13 @@ ExecutorService getExecutor(ExecutorNames _executor) { /** * Test that a proper exception is thrown when executor was shutdown or terminated. */ - @Test - void testExecutorShutdownOrTerminated() { - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).withRetryHandler(null).build(); + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testExecutorShutdownOrTerminated(boolean _virtual) { + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withAllVirtualThreads(_virtual) + .withRetryHandler(null).build(); + NoOpExecutorService exec = new NoOpExecutorService(); exec.shutdown = true; @@ -207,9 +232,12 @@ ExecutorService getExecutor(ExecutorNames _executor) { /** * Test that a proper exception is thrown when service was closed. */ - @Test - void testReceivingServiceClosed() { - ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null).withRetryHandler(null).build(); + @ParameterizedTest(name = "{index} -> Virtual: {0}") + @ValueSource(booleans = { true, false }) + void testReceivingServiceClosed(boolean _virtual) { + ReceivingServiceConfig build = new ReceivingServiceConfigBuilder<>(null) + .withAllVirtualThreads(_virtual) + .withRetryHandler(null).build(); ReceivingService service = new ReceivingService("", build) { @Override diff --git a/dbus-java-tests/src/test/java/org/freedesktop/dbus/utils/UtilTest.java b/dbus-java-tests/src/test/java/org/freedesktop/dbus/utils/UtilTest.java new file mode 100644 index 000000000..5b3bb88db --- /dev/null +++ b/dbus-java-tests/src/test/java/org/freedesktop/dbus/utils/UtilTest.java @@ -0,0 +1,24 @@ +package org.freedesktop.dbus.utils; + +import static org.junit.jupiter.api.Assertions.*; + +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; + +class UtilTest { + + @ParameterizedTest(name = "{index}: {0}") + @CsvSource({ + "Min OK, 1, 3, false", + "Min Equal, 1, 1, false", + "Min lower, 5, 1, true" + }) + void testRequireMinimum(String _name, int _minVal, int _testVal, boolean _throws) { + if (_throws) { + assertThrows(IllegalArgumentException.class, () -> Util.requireMinimum(_minVal, _testVal)); + } else { + int result = assertDoesNotThrow(() -> Util.requireMinimum(_minVal, _testVal)); + assertEquals(_testVal, result); + } + } +}