From ff7528221dd1995a3baa6f89cb3f1ab02b8a6668 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+eggy03@users.noreply.github.com> Date: Tue, 21 Apr 2026 11:06:50 +0530 Subject: [PATCH 1/5] refactor(dmidecode): improve command generation - Change `getCommandFor` to an instance method `getCommand` - Add `@NonNull` annotation to the return type of `getCommand` Signed-off-by: Egg-03 <111327101+eggy03@users.noreply.github.com> --- .../java/io/github/eggy03/dmidecode/constant/DMIType.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/main/java/io/github/eggy03/dmidecode/constant/DMIType.java b/src/main/java/io/github/eggy03/dmidecode/constant/DMIType.java index 64dc320..a49283e 100644 --- a/src/main/java/io/github/eggy03/dmidecode/constant/DMIType.java +++ b/src/main/java/io/github/eggy03/dmidecode/constant/DMIType.java @@ -5,6 +5,8 @@ */ package io.github.eggy03.dmidecode.constant; +import org.jspecify.annotations.NonNull; + /** * Enumeration of DMI types as defined by the * {@code dmidecode} specification. @@ -72,7 +74,8 @@ public enum DMIType { this.value = value; } - public static String getCommandFor(DMIType type) { - return "sudo /usr/sbin/dmidecode --type " + type.value; + @NonNull + public String getCommand() { + return "sudo /usr/sbin/dmidecode --type " + this.value; } } \ No newline at end of file From 7de9ee3ab07cd7209414f0e4cf753afbd9d6e530 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+eggy03@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:26:09 +0530 Subject: [PATCH 2/5] refactor(terminal): reduce arbitrary command execution chances - Rename `TerminalExecutionException` to `TerminalIOException`. - Introduce a new class `TerminalResult` to encapsulate both stdout and stderr from terminal execution. - Update `TerminalUtility` (renamed to `TerminalService`) to return `TerminalResult` instead of a raw string. - Modify the `execute` method to handle and return both stdout and stderr. It has also been made package private to reduce arbitrary command execution - Update the exception handling to throw `TerminalIOException` for I/O errors. - Add a new method `executeCommand` to `TerminalService` for executing specific DMI commands originating from the `DMIType` enum. Signed-off-by: Egg-03 <111327101+eggy03@users.noreply.github.com> --- ...xception.java => TerminalIOException.java} | 8 +- .../dmidecode/terminal/TerminalResult.java | 52 ++++++++++ .../dmidecode/terminal/TerminalService.java | 97 +++++++++++++++++++ .../dmidecode/utility/TerminalUtility.java | 81 ---------------- 4 files changed, 153 insertions(+), 85 deletions(-) rename src/main/java/io/github/eggy03/dmidecode/exception/{TerminalExecutionException.java => TerminalIOException.java} (67%) create mode 100644 src/main/java/io/github/eggy03/dmidecode/terminal/TerminalResult.java create mode 100644 src/main/java/io/github/eggy03/dmidecode/terminal/TerminalService.java delete mode 100644 src/main/java/io/github/eggy03/dmidecode/utility/TerminalUtility.java diff --git a/src/main/java/io/github/eggy03/dmidecode/exception/TerminalExecutionException.java b/src/main/java/io/github/eggy03/dmidecode/exception/TerminalIOException.java similarity index 67% rename from src/main/java/io/github/eggy03/dmidecode/exception/TerminalExecutionException.java rename to src/main/java/io/github/eggy03/dmidecode/exception/TerminalIOException.java index 3a7597f..29d8cf2 100644 --- a/src/main/java/io/github/eggy03/dmidecode/exception/TerminalExecutionException.java +++ b/src/main/java/io/github/eggy03/dmidecode/exception/TerminalIOException.java @@ -10,20 +10,20 @@ * * @since 0.1.0 */ -public class TerminalExecutionException extends RuntimeException { +public class TerminalIOException extends RuntimeException { @SuppressWarnings("unused") - public TerminalExecutionException(String message, Throwable cause) { + public TerminalIOException(String message, Throwable cause) { super(message, cause); } @SuppressWarnings("unused") - public TerminalExecutionException(String message) { + public TerminalIOException(String message) { super(message); } @SuppressWarnings("unused") - public TerminalExecutionException(Throwable cause) { + public TerminalIOException(Throwable cause) { super("Terminal Execution Failure", cause); } diff --git a/src/main/java/io/github/eggy03/dmidecode/terminal/TerminalResult.java b/src/main/java/io/github/eggy03/dmidecode/terminal/TerminalResult.java new file mode 100644 index 0000000..99a7d9b --- /dev/null +++ b/src/main/java/io/github/eggy03/dmidecode/terminal/TerminalResult.java @@ -0,0 +1,52 @@ +package io.github.eggy03.dmidecode.terminal; + +import org.jspecify.annotations.NonNull; + +import java.util.Objects; + +/** + * Represents the result of a command or script executed via {@link TerminalService}. + *

+ * This class encapsulates both the standard output (stdout) and standard error (stderr) + * produced during execution. + *

+ * + * @since 0.3.0 + */ +public class TerminalResult { + + private final @NonNull String result; + private final @NonNull String error; + + /** + * Constructs a {@link TerminalResult}. + * + * @param result the non-null standard output (stdout) produced by the execution + * @param error the non-null standard error (stderr) produced by the execution + * @throws NullPointerException if either {@code result} or {@code error} is {@code null} + */ + public TerminalResult(@NonNull String result, @NonNull String error) { + this.result = Objects.requireNonNull(result, "result cannot be null"); + this.error = Objects.requireNonNull(error, "error cannot be null"); + } + + + /** + * Returns the standard output (stdout) produced by the execution. + * + * @return a non-null string containing the command output + */ + public @NonNull String getResult() { + return result; + } + + /** + * Returns the standard error (stderr) produced by the execution. + * + * @return a non-null string containing the error output + */ + public @NonNull String getError() { + return error; + } + +} diff --git a/src/main/java/io/github/eggy03/dmidecode/terminal/TerminalService.java b/src/main/java/io/github/eggy03/dmidecode/terminal/TerminalService.java new file mode 100644 index 0000000..101139d --- /dev/null +++ b/src/main/java/io/github/eggy03/dmidecode/terminal/TerminalService.java @@ -0,0 +1,97 @@ +/* + * © 2026 The dmidecode4j contributors + * Licensed under the MIT License. + * See the LICENSE file in the project root for more information. + */ +package io.github.eggy03.dmidecode.terminal; + +import io.github.eggy03.dmidecode.constant.DMIType; +import io.github.eggy03.dmidecode.exception.TerminalIOException; +import org.apache.commons.exec.CommandLine; +import org.apache.commons.exec.DefaultExecutor; +import org.apache.commons.exec.ExecuteException; +import org.apache.commons.exec.ExecuteWatchdog; +import org.apache.commons.exec.PumpStreamHandler; +import org.jspecify.annotations.NonNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.time.Duration; +import java.util.Objects; + +/** + * A service class that provides a way to launch a terminal session + *

+ * for internal use + * + * @since 0.1.0 + */ +public class TerminalService { + + private static final Logger log = LoggerFactory.getLogger(TerminalService.class); + + /** + * Launches a standalone PowerShell session, executes {@link DMIType#getCommand()} and returns the result + * + * @param dmiType The non-null enum value containing the command which shall be executed + * @param timeoutSeconds The non-null, positive value of time in seconds after which the session will be force stopped. + * @return The result of the query executed, wrapped in {@link TerminalResult} + * @since 0.3.0 + */ + @NonNull + public TerminalResult executeCommand(@NonNull DMIType dmiType, long timeoutSeconds) { + Objects.requireNonNull(dmiType, "dmiType cannot be null"); + return execute(dmiType.getCommand(), timeoutSeconds); + } + + + /** + * Launches a standalone Terminal session and executes commands and returns the result + * + * @param command The command to be executed in the Terminal, must not be null + * @param timeoutSeconds Time in seconds after which the session will be force stopped, must not be null. + * @return The result of the command executed, wrapped in {@link TerminalResult} + * @throws IllegalArgumentException if timeout is in negative. + * @since 0.1.0 + */ + @NonNull TerminalResult execute(@NonNull String command, long timeoutSeconds) { + + Objects.requireNonNull(command, "command or script to be executed cannot be null"); + + if (timeoutSeconds < 0) + throw new IllegalArgumentException("Timeout cannot be negative"); + + CommandLine cmdLine = new CommandLine("bash"); + cmdLine.addArgument("-c"); + cmdLine.addArgument(command, false); + + ByteArrayOutputStream resultStream = new ByteArrayOutputStream(); + ByteArrayOutputStream errorStream = new ByteArrayOutputStream(); + + ExecuteWatchdog watchdog = ExecuteWatchdog.builder().setTimeout(Duration.ofSeconds(timeoutSeconds)).get(); + + DefaultExecutor executor = DefaultExecutor.builder().get(); + executor.setStreamHandler(new PumpStreamHandler(resultStream, errorStream)); + executor.setWatchdog(watchdog); + + try { + int exitCode = executor.execute(cmdLine); + log.debug("\nTerminal Execution - SUCCESS\nExit code: {}\nCommand: {}\nStdout: {}\nStderr: {}\n", exitCode, command, resultStream, errorStream); + return new TerminalResult(resultStream.toString(), errorStream.toString()); + } catch (ExecuteException e) { + + boolean processKilled = watchdog.killedProcess(); + if (log.isDebugEnabled()) + log.debug("\nTerminal Execution - FAILURE\nProcess Killed: {}\nTimeout: {}\nCommand: {}\nStdout: {}\nStderr: {}\n", processKilled, timeoutSeconds, command, resultStream, errorStream, e); + else + log.warn("\nTerminal Execution - FAILURE\nProcess Killed: {}\nEnable DEBUG mode to see the commands it tried to execute\n", processKilled, e); + + return new TerminalResult(resultStream.toString(), errorStream.toString()); + + } catch (IOException e) { + throw new TerminalIOException("An I/O Exception occurred while running Terminal", e); + } + } +} diff --git a/src/main/java/io/github/eggy03/dmidecode/utility/TerminalUtility.java b/src/main/java/io/github/eggy03/dmidecode/utility/TerminalUtility.java deleted file mode 100644 index 442938e..0000000 --- a/src/main/java/io/github/eggy03/dmidecode/utility/TerminalUtility.java +++ /dev/null @@ -1,81 +0,0 @@ -/* - * © 2026 The dmidecode4j contributors - * Licensed under the MIT License. - * See the LICENSE file in the project root for more information. - */ -package io.github.eggy03.dmidecode.utility; - -import io.github.eggy03.dmidecode.exception.TerminalExecutionException; -import org.apache.commons.exec.CommandLine; -import org.apache.commons.exec.DefaultExecutor; -import org.apache.commons.exec.ExecuteException; -import org.apache.commons.exec.ExecuteWatchdog; -import org.apache.commons.exec.PumpStreamHandler; -import org.jspecify.annotations.NonNull; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.time.Duration; - -/** - * A utility class that provides a way to launch a terminal session - *

- * Mostly for internal use - * - * @since 0.1.0 - */ -public class TerminalUtility { - - private static final Logger log = LoggerFactory.getLogger(TerminalUtility.class); - - private TerminalUtility() { - throw new IllegalStateException("Utility Class"); - } - - /** - * Launches a standalone terminal session, executes the given command - * and returns the result - * - * @param command The command/script to be executed in the terminal - * @param timeoutSeconds Time in seconds after which the session will be force stopped - * @return The result of the command executed - * @throws TerminalExecutionException When the process is killed pre-maturely upon reaching the timeout - * or when the command yields an error, or when the terminal cannot be accessed. - * @throws IllegalArgumentException If the provided timeout is in the negative - */ - public static @NonNull String executeCommand(@NonNull String command, long timeoutSeconds) { - - if (timeoutSeconds < 0) - throw new IllegalArgumentException("Timeout cannot be negative"); - - CommandLine cmdLine = new CommandLine("bash"); - cmdLine.addArgument("-c"); - cmdLine.addArgument(command, false); - - ByteArrayOutputStream result = new ByteArrayOutputStream(); - ByteArrayOutputStream err = new ByteArrayOutputStream(); - - ExecuteWatchdog watchdog = ExecuteWatchdog.builder().setTimeout(Duration.ofSeconds(timeoutSeconds)).get(); - - DefaultExecutor executor = DefaultExecutor.builder().get(); - executor.setStreamHandler(new PumpStreamHandler(result, err)); - executor.setWatchdog(watchdog); - - try { - int exitCode = executor.execute(cmdLine); - log.debug("\nCommand Executed: {}\nExit code: {}\nError Stream: {}\nResult Stream: {}\n", command, exitCode, err, result); - return result.toString(); - } catch (ExecuteException e) { - String reason = watchdog.killedProcess() ? - "\nProcess executing the following command: " + command + "\nWas killed after a timeout of " + timeoutSeconds + " seconds\n" : - "\nProcess executing the following command: " + command + "\nExited with a non-zero exit code\nTerminal Error Output: " + err; - - throw new TerminalExecutionException(reason, e); - } catch (IOException e) { - String reason = "An I/O Exception occurred during executing the following command:\n" + command; - throw new TerminalExecutionException(reason, e); - } - } -} From 531bfde3e45400060955606b7faaac78fd8892e1 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+eggy03@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:26:32 +0530 Subject: [PATCH 3/5] refactor: rename DMIPortConnectionInformationMapper to DMIPortConnectorInformationMapper Signed-off-by: Egg-03 <111327101+eggy03@users.noreply.github.com> --- ...mationMapper.java => DMIPortConnectorInformationMapper.java} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename src/main/java/io/github/eggy03/dmidecode/mapper/board/{DMIPortConnectionInformationMapper.java => DMIPortConnectorInformationMapper.java} (83%) diff --git a/src/main/java/io/github/eggy03/dmidecode/mapper/board/DMIPortConnectionInformationMapper.java b/src/main/java/io/github/eggy03/dmidecode/mapper/board/DMIPortConnectorInformationMapper.java similarity index 83% rename from src/main/java/io/github/eggy03/dmidecode/mapper/board/DMIPortConnectionInformationMapper.java rename to src/main/java/io/github/eggy03/dmidecode/mapper/board/DMIPortConnectorInformationMapper.java index 99a7d44..963d93a 100644 --- a/src/main/java/io/github/eggy03/dmidecode/mapper/board/DMIPortConnectionInformationMapper.java +++ b/src/main/java/io/github/eggy03/dmidecode/mapper/board/DMIPortConnectorInformationMapper.java @@ -14,5 +14,5 @@ * * @since 0.1.0 */ -public class DMIPortConnectionInformationMapper implements CommonDMIMapper { +public class DMIPortConnectorInformationMapper implements CommonDMIMapper { } From 657c4ff984061c40c0f3cca979c0e3d2cf166ff8 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+eggy03@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:34:24 +0530 Subject: [PATCH 4/5] refactor: add configurable object mapper - introduce `configureObjectMapper` method to allow custom ObjectMapper configuration - use `configureObjectMapper` to create `jacksonMapper` instance in `map` and `mapList` methods Signed-off-by: Egg-03 <111327101+eggy03@users.noreply.github.com> --- .../dmidecode/mapper/CommonDMIMapper.java | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/src/main/java/io/github/eggy03/dmidecode/mapper/CommonDMIMapper.java b/src/main/java/io/github/eggy03/dmidecode/mapper/CommonDMIMapper.java index b6ddd9c..720569f 100644 --- a/src/main/java/io/github/eggy03/dmidecode/mapper/CommonDMIMapper.java +++ b/src/main/java/io/github/eggy03/dmidecode/mapper/CommonDMIMapper.java @@ -47,7 +47,24 @@ */ public interface CommonDMIMapper { - ObjectMapper jacksonMapper = new ObjectMapper(); + /** + * Configure the {@link ObjectMapper} to be used for JSON processing. + * + *

+ * The default implementation returns a new {@link ObjectMapper} instance with default configuration. + *

+ * + *

+ * Custom implementations may override this method to provide a custom-configured + * {@link ObjectMapper}. + *

+ * + * @return the {@link ObjectMapper} to use + * @since 0.3.0 + */ + default @NonNull ObjectMapper configureObjectMapper() { + return new ObjectMapper(); + } /** * Maps raw {@code dmidecode} output into a single entity of type {@code }. @@ -96,6 +113,8 @@ public interface CommonDMIMapper { if (rawDMIData == null) return Optional.empty(); + ObjectMapper jacksonMapper = configureObjectMapper(); + Map keyValueMap = new LinkedHashMap<>(); String key = null; @@ -197,6 +216,8 @@ public interface CommonDMIMapper { if (rawDMIData == null) return Collections.emptyList(); + ObjectMapper jacksonMapper = configureObjectMapper(); + List entityList = new ArrayList<>(); Map keyValueMap = new HashMap<>(); From 23690b75a1cd2d9c75dd1421700e1cfc59339e87 Mon Sep 17 00:00:00 2001 From: Egg-03 <111327101+eggy03@users.noreply.github.com> Date: Tue, 21 Apr 2026 12:47:10 +0530 Subject: [PATCH 5/5] refactor(service): injectable terminal service and mappers - Replace direct instantiation of `TerminalUtility` and mappers with dependency injection of `TerminalService` and specific mappers. - Introduce package-private constructors to facilitate dependency injection. - Update `get` methods to utilize the injected `TerminalService` and mappers. - Add `Objects.requireNonNull` checks for injected dependencies to ensure non-nullability. - This change improves testability and maintainability by decoupling service classes from their dependencies, for the upcoming test rewrite Signed-off-by: Egg-03 <111327101+eggy03@users.noreply.github.com> --- .../service/board/DMIBIOSLanguageService.java | 35 +++++++++++++++--- .../service/board/DMIBIOSService.java | 35 +++++++++++++++--- .../service/board/DMIBaseboardService.java | 35 +++++++++++++++--- .../service/board/DMIChassisService.java | 35 +++++++++++++++--- .../DMIPortConnectorInformationService.java | 37 ++++++++++++++++--- .../service/board/DMISystemSlotsService.java | 35 +++++++++++++++--- .../memory/DMIMemoryDeviceService.java | 35 +++++++++++++++--- .../memory/DMIPhysicalMemoryArrayService.java | 35 +++++++++++++++--- .../peripheral/DMIPortableBatteryService.java | 35 +++++++++++++++--- .../service/processor/DMICacheService.java | 35 +++++++++++++++--- .../processor/DMIProcessorService.java | 35 +++++++++++++++--- .../service/system/DMISystemService.java | 35 +++++++++++++++--- 12 files changed, 361 insertions(+), 61 deletions(-) diff --git a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSLanguageService.java b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSLanguageService.java index 9aa263e..456bba9 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSLanguageService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSLanguageService.java @@ -12,9 +12,11 @@ import io.github.eggy03.dmidecode.mapper.CommonDMIMapper; import io.github.eggy03.dmidecode.mapper.board.DMIBIOSLanguageMapper; import io.github.eggy03.dmidecode.service.OptionalCommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; +import java.util.Objects; import java.util.Optional; /** @@ -34,6 +36,30 @@ */ public class DMIBIOSLanguageService implements OptionalCommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIBIOSLanguageMapper mapper; + + /** + * Creates {@link DMIBIOSLanguageService} with default configuration. + * + * @since 0.3.0 + */ + public DMIBIOSLanguageService() { + this(new TerminalService(), new DMIBIOSLanguageMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIBIOSLanguageService(@NonNull TerminalService terminalService, @NonNull DMIBIOSLanguageMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves BIOS language information present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -50,9 +76,8 @@ public class DMIBIOSLanguageService implements OptionalCommonDMIServiceInterface @Override @InvokesFragileMethod(targetClass = CommonDMIMapper.class, methodType = MethodType.INTERFACE_DEFAULT_METHOD) public @NonNull Optional get(long timeout) { - return new DMIBIOSLanguageMapper().mapToEntity( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.BIOS_LANGUAGE), timeout), - DMIBIOSLanguage.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.BIOS_LANGUAGE, timeout); + return mapper.mapToEntity(result.getResult(), DMIBIOSLanguage.class); } } \ No newline at end of file diff --git a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSService.java b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSService.java index 83bdf75..c81b5e9 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBIOSService.java @@ -13,10 +13,12 @@ import io.github.eggy03.dmidecode.mapper.CommonDMIMapper; import io.github.eggy03.dmidecode.mapper.board.DMIBIOSMapper; import io.github.eggy03.dmidecode.service.CommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; import java.util.List; +import java.util.Objects; /** * Service class for fetching BIOS information from the system. @@ -35,6 +37,30 @@ */ public class DMIBIOSService implements CommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIBIOSMapper mapper; + + /** + * Creates {@link DMIBIOSService} with default configuration. + * + * @since 0.3.0 + */ + public DMIBIOSService() { + this(new TerminalService(), new DMIBIOSMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIBIOSService(@NonNull TerminalService terminalService, @NonNull DMIBIOSMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves BIOS entries present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -51,9 +77,8 @@ public class DMIBIOSService implements CommonDMIServiceInterface { @Override @InvokesFragileMethod(targetClass = CommonDMIMapper.class, methodType = MethodType.INTERFACE_DEFAULT_METHOD) public @NonNull @Unmodifiable List get(long timeout) { - return new DMIBIOSMapper().mapToList( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.BIOS), timeout), - DMIBIOS.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.BIOS, timeout); + return mapper.mapToList(result.getResult(), DMIBIOS.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBaseboardService.java b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBaseboardService.java index 71d728b..e584c93 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBaseboardService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIBaseboardService.java @@ -12,9 +12,11 @@ import io.github.eggy03.dmidecode.mapper.CommonDMIMapper; import io.github.eggy03.dmidecode.mapper.board.DMIBaseboardMapper; import io.github.eggy03.dmidecode.service.OptionalCommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; +import java.util.Objects; import java.util.Optional; /** @@ -35,6 +37,30 @@ */ public class DMIBaseboardService implements OptionalCommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIBaseboardMapper mapper; + + /** + * Creates {@link DMIBaseboardService} with default configuration. + * + * @since 0.3.0 + */ + public DMIBaseboardService() { + this(new TerminalService(), new DMIBaseboardMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIBaseboardService(@NonNull TerminalService terminalService, @NonNull DMIBaseboardMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves baseboard information present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -51,9 +77,8 @@ public class DMIBaseboardService implements OptionalCommonDMIServiceInterface get(long timeout) { - return new DMIBaseboardMapper().mapToEntity( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.BASEBOARD), timeout), - DMIBaseboard.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.BASEBOARD, timeout); + return mapper.mapToEntity(result.getResult(), DMIBaseboard.class); } } \ No newline at end of file diff --git a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIChassisService.java b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIChassisService.java index 33517a1..89bb782 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIChassisService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIChassisService.java @@ -12,9 +12,11 @@ import io.github.eggy03.dmidecode.mapper.CommonDMIMapper; import io.github.eggy03.dmidecode.mapper.board.DMIChassisMapper; import io.github.eggy03.dmidecode.service.OptionalCommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; +import java.util.Objects; import java.util.Optional; /** @@ -34,6 +36,30 @@ */ public class DMIChassisService implements OptionalCommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIChassisMapper mapper; + + /** + * Creates {@link DMIChassisService} with default configuration. + * + * @since 0.3.0 + */ + public DMIChassisService() { + this(new TerminalService(), new DMIChassisMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIChassisService(@NonNull TerminalService terminalService, @NonNull DMIChassisMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves chassis information present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -50,9 +76,8 @@ public class DMIChassisService implements OptionalCommonDMIServiceInterface get(long timeout) { - return new DMIChassisMapper().mapToEntity( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.CHASSIS), timeout), - DMIChassis.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.CHASSIS, timeout); + return mapper.mapToEntity(result.getResult(), DMIChassis.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIPortConnectorInformationService.java b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIPortConnectorInformationService.java index da214d8..970bb36 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/board/DMIPortConnectorInformationService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/board/DMIPortConnectorInformationService.java @@ -11,12 +11,14 @@ import io.github.eggy03.dmidecode.constant.DMIType; import io.github.eggy03.dmidecode.entity.board.DMIPortConnectorInformation; import io.github.eggy03.dmidecode.mapper.CommonDMIMapper; -import io.github.eggy03.dmidecode.mapper.board.DMIPortConnectionInformationMapper; +import io.github.eggy03.dmidecode.mapper.board.DMIPortConnectorInformationMapper; import io.github.eggy03.dmidecode.service.CommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; import java.util.List; +import java.util.Objects; /** * Service class for fetching port connector information from the system. @@ -35,6 +37,30 @@ */ public class DMIPortConnectorInformationService implements CommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIPortConnectorInformationMapper mapper; + + /** + * Creates {@link DMIPortConnectorInformationService} with default configuration. + * + * @since 0.3.0 + */ + public DMIPortConnectorInformationService() { + this(new TerminalService(), new DMIPortConnectorInformationMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIPortConnectorInformationService(@NonNull TerminalService terminalService, @NonNull DMIPortConnectorInformationMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves port connector entries present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -52,9 +78,8 @@ public class DMIPortConnectorInformationService implements CommonDMIServiceInter @Override @InvokesFragileMethod(targetClass = CommonDMIMapper.class, methodType = MethodType.INTERFACE_DEFAULT_METHOD) public @Unmodifiable @NonNull List get(long timeout) { - return new DMIPortConnectionInformationMapper().mapToList( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.PORT_CONNECTOR), timeout), - DMIPortConnectorInformation.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.PORT_CONNECTOR, timeout); + return mapper.mapToList(result.getResult(), DMIPortConnectorInformation.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/board/DMISystemSlotsService.java b/src/main/java/io/github/eggy03/dmidecode/service/board/DMISystemSlotsService.java index e3ee2b0..11908dd 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/board/DMISystemSlotsService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/board/DMISystemSlotsService.java @@ -13,10 +13,12 @@ import io.github.eggy03.dmidecode.mapper.CommonDMIMapper; import io.github.eggy03.dmidecode.mapper.board.DMISystemSlotsMapper; import io.github.eggy03.dmidecode.service.CommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; import java.util.List; +import java.util.Objects; /** * Service class for fetching system slot information from the system. @@ -35,6 +37,30 @@ */ public class DMISystemSlotsService implements CommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMISystemSlotsMapper mapper; + + /** + * Creates {@link DMISystemSlotsService} with default configuration. + * + * @since 0.3.0 + */ + public DMISystemSlotsService() { + this(new TerminalService(), new DMISystemSlotsMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMISystemSlotsService(@NonNull TerminalService terminalService, @NonNull DMISystemSlotsMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves system slot entries present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -52,9 +78,8 @@ public class DMISystemSlotsService implements CommonDMIServiceInterface get(long timeout) { - return new DMISystemSlotsMapper().mapToList( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.SYSTEM_SLOTS), timeout), - DMISystemSlots.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.SYSTEM_SLOTS, timeout); + return mapper.mapToList(result.getResult(), DMISystemSlots.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIMemoryDeviceService.java b/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIMemoryDeviceService.java index 8579237..8c6bdf9 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIMemoryDeviceService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIMemoryDeviceService.java @@ -10,10 +10,12 @@ import io.github.eggy03.dmidecode.entity.memory.DMIMemoryDevice; import io.github.eggy03.dmidecode.mapper.physicalmemory.DMIMemoryDeviceMapper; import io.github.eggy03.dmidecode.service.CommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; import java.util.List; +import java.util.Objects; /** * Service class for fetching memory device information from the system. @@ -32,6 +34,30 @@ */ public class DMIMemoryDeviceService implements CommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIMemoryDeviceMapper mapper; + + /** + * Creates {@link DMIMemoryDeviceService} with default configuration. + * + * @since 0.3.0 + */ + public DMIMemoryDeviceService() { + this(new TerminalService(), new DMIMemoryDeviceMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIMemoryDeviceService(@NonNull TerminalService terminalService, @NonNull DMIMemoryDeviceMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves memory device entries present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -48,9 +74,8 @@ public class DMIMemoryDeviceService implements CommonDMIServiceInterface get(long timeout) { - return new DMIMemoryDeviceMapper().mapToList( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.MEMORY_DEVICE), timeout), - DMIMemoryDevice.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.MEMORY_DEVICE, timeout); + return mapper.mapToList(result.getResult(), DMIMemoryDevice.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIPhysicalMemoryArrayService.java b/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIPhysicalMemoryArrayService.java index 74b6aa6..1e5f7fc 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIPhysicalMemoryArrayService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/memory/DMIPhysicalMemoryArrayService.java @@ -9,9 +9,11 @@ import io.github.eggy03.dmidecode.entity.memory.DMIPhysicalMemoryArray; import io.github.eggy03.dmidecode.mapper.physicalmemory.DMIPhysicalMemoryArrayMapper; import io.github.eggy03.dmidecode.service.OptionalCommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; +import java.util.Objects; import java.util.Optional; /** @@ -31,6 +33,30 @@ */ public class DMIPhysicalMemoryArrayService implements OptionalCommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIPhysicalMemoryArrayMapper mapper; + + /** + * Creates {@link DMIPhysicalMemoryArrayService} with default configuration. + * + * @since 0.3.0 + */ + public DMIPhysicalMemoryArrayService() { + this(new TerminalService(), new DMIPhysicalMemoryArrayMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIPhysicalMemoryArrayService(@NonNull TerminalService terminalService, @NonNull DMIPhysicalMemoryArrayMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves physical memory array information present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -47,9 +73,8 @@ public class DMIPhysicalMemoryArrayService implements OptionalCommonDMIServiceIn */ @Override public @NonNull Optional get(long timeout) { - return new DMIPhysicalMemoryArrayMapper().mapToEntity( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.PHYSICAL_MEMORY_ARRAY), timeout), - DMIPhysicalMemoryArray.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.PHYSICAL_MEMORY_ARRAY, timeout); + return mapper.mapToEntity(result.getResult(), DMIPhysicalMemoryArray.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/peripheral/DMIPortableBatteryService.java b/src/main/java/io/github/eggy03/dmidecode/service/peripheral/DMIPortableBatteryService.java index 3748a44..951634b 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/peripheral/DMIPortableBatteryService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/peripheral/DMIPortableBatteryService.java @@ -10,10 +10,12 @@ import io.github.eggy03.dmidecode.entity.peripheral.DMIPortableBattery; import io.github.eggy03.dmidecode.mapper.peripheral.DMIPortableBatteryMapper; import io.github.eggy03.dmidecode.service.CommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; import java.util.List; +import java.util.Objects; /** * Service class for fetching portable battery information from the system. @@ -32,6 +34,30 @@ */ public class DMIPortableBatteryService implements CommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIPortableBatteryMapper mapper; + + /** + * Creates {@link DMIPortableBatteryService} with default configuration. + * + * @since 0.3.0 + */ + public DMIPortableBatteryService() { + this(new TerminalService(), new DMIPortableBatteryMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIPortableBatteryService(@NonNull TerminalService terminalService, @NonNull DMIPortableBatteryMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves portable battery entries present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -48,9 +74,8 @@ public class DMIPortableBatteryService implements CommonDMIServiceInterface get(long timeout) { - return new DMIPortableBatteryMapper().mapToList( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.PORTABLE_BATTERY), timeout), - DMIPortableBattery.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.PORTABLE_BATTERY, timeout); + return mapper.mapToList(result.getResult(), DMIPortableBattery.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/processor/DMICacheService.java b/src/main/java/io/github/eggy03/dmidecode/service/processor/DMICacheService.java index b4e1aa9..bb10e12 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/processor/DMICacheService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/processor/DMICacheService.java @@ -10,10 +10,12 @@ import io.github.eggy03.dmidecode.entity.processor.DMICache; import io.github.eggy03.dmidecode.mapper.processor.DMICacheMapper; import io.github.eggy03.dmidecode.service.CommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; import java.util.List; +import java.util.Objects; /** * Service class for fetching cache information from the system. @@ -32,6 +34,30 @@ */ public class DMICacheService implements CommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMICacheMapper mapper; + + /** + * Creates {@link DMICacheService} with default configuration. + * + * @since 0.3.0 + */ + public DMICacheService() { + this(new TerminalService(), new DMICacheMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMICacheService(@NonNull TerminalService terminalService, @NonNull DMICacheMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves cache entries present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -48,9 +74,8 @@ public class DMICacheService implements CommonDMIServiceInterface { */ @Override public @Unmodifiable @NonNull List get(long timeout) { - return new DMICacheMapper().mapToList( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.CACHE), timeout), - DMICache.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.CACHE, timeout); + return mapper.mapToList(result.getResult(), DMICache.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/processor/DMIProcessorService.java b/src/main/java/io/github/eggy03/dmidecode/service/processor/DMIProcessorService.java index 7559a41..ae7a20d 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/processor/DMIProcessorService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/processor/DMIProcessorService.java @@ -10,10 +10,12 @@ import io.github.eggy03.dmidecode.entity.processor.DMIProcessor; import io.github.eggy03.dmidecode.mapper.processor.DMIProcessorMapper; import io.github.eggy03.dmidecode.service.CommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; import java.util.List; +import java.util.Objects; /** * Service class for fetching processor information from the system. @@ -32,6 +34,30 @@ */ public class DMIProcessorService implements CommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMIProcessorMapper mapper; + + /** + * Creates {@link DMIProcessorService} with default configuration. + * + * @since 0.3.0 + */ + public DMIProcessorService() { + this(new TerminalService(), new DMIProcessorMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMIProcessorService(@NonNull TerminalService terminalService, @NonNull DMIProcessorMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves processor information present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -47,10 +73,9 @@ public class DMIProcessorService implements CommonDMIServiceInterface get(long timeout) { - return new DMIProcessorMapper().mapToList( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.PROCESSOR), timeout), - DMIProcessor.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.PROCESSOR, timeout); + return mapper.mapToList(result.getResult(), DMIProcessor.class); } } diff --git a/src/main/java/io/github/eggy03/dmidecode/service/system/DMISystemService.java b/src/main/java/io/github/eggy03/dmidecode/service/system/DMISystemService.java index 18000bd..5dcb635 100644 --- a/src/main/java/io/github/eggy03/dmidecode/service/system/DMISystemService.java +++ b/src/main/java/io/github/eggy03/dmidecode/service/system/DMISystemService.java @@ -10,9 +10,11 @@ import io.github.eggy03.dmidecode.entity.system.DMISystem; import io.github.eggy03.dmidecode.mapper.system.DMISystemMapper; import io.github.eggy03.dmidecode.service.OptionalCommonDMIServiceInterface; -import io.github.eggy03.dmidecode.utility.TerminalUtility; +import io.github.eggy03.dmidecode.terminal.TerminalResult; +import io.github.eggy03.dmidecode.terminal.TerminalService; import org.jspecify.annotations.NonNull; +import java.util.Objects; import java.util.Optional; /** @@ -32,6 +34,30 @@ */ public class DMISystemService implements OptionalCommonDMIServiceInterface { + private final TerminalService terminalService; + private final DMISystemMapper mapper; + + /** + * Creates {@link DMISystemService} with default configuration. + * + * @since 0.3.0 + */ + public DMISystemService() { + this(new TerminalService(), new DMISystemMapper()); + } + + /** + * Package Private constructor with injectable dependencies + * + * @param terminalService the {@link TerminalService} instance to use, must not be {@code null} + * @param mapper the mapper instance to use, must not be {@code null} + * @since 0.3.0 + */ + DMISystemService(@NonNull TerminalService terminalService, @NonNull DMISystemMapper mapper) { + this.terminalService = Objects.requireNonNull(terminalService, "terminalService cannot be null"); + this.mapper = Objects.requireNonNull(mapper, "mapper cannot be null"); + } + /** * Retrieves system information present in the system * using an isolated {@code dmidecode} process with a configurable timeout. @@ -48,9 +74,8 @@ public class DMISystemService implements OptionalCommonDMIServiceInterface get(long timeout) { - return new DMISystemMapper().mapToEntity( - TerminalUtility.executeCommand(DMIType.getCommandFor(DMIType.SYSTEM), timeout), - DMISystem.class - ); + + TerminalResult result = terminalService.executeCommand(DMIType.SYSTEM, timeout); + return mapper.mapToEntity(result.getResult(), DMISystem.class); } }