Repository: deepjavalibrary/djl
Pull request #1852 (2022-08-01 21:48:56)

Catch security exception in get environment call
## Description ##

Brief description of what this PR is about

This PR is to fix https://github.com/deepjavalibrary/djl/discussions/1848

The customer run into the get environment security issue. This PR put the environment call into a utility function and catch the exception.

- If this change is a backward incompatible change, why must this change be made?
- Interesting edge cases to note here


codecov-commenter: # [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1852?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) Report
> Merging [#1852](https://codecov.io/gh/deepjavalibrary/djl/pull/1852?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) (7a9a17a) into [master](https://codecov.io/gh/deepjavalibrary/djl/commit/bb5073f7ffc33f1883621fc1783dbb01e70b418f?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) (bb5073f) will **decrease** coverage by `2.36%`.
> The diff coverage is `64.45%`.

```diff
@@             Coverage Diff              @@
##             master    #1852      +/-   ##
============================================
- Coverage     72.08%   69.71%   -2.37%     
- Complexity     5126     5530     +404     
============================================
  Files           473      526      +53     
  Lines         21970    24455    +2485     
  Branches       2351     2665     +314     
============================================
+ Hits          15838    17050    +1212     
- Misses         4925     6094    +1169     
- Partials       1207     1311     +104     
```


| [Impacted Files](https://codecov.io/gh/deepjavalibrary/djl/pull/1852?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | Coverage Δ | |
|---|---|---|
| [api/src/main/java/ai/djl/modality/cv/Image.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L0ltYWdlLmphdmE=) | `69.23% <ø> (-4.11%)` | :arrow_down: |
| [...rc/main/java/ai/djl/modality/cv/MultiBoxPrior.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L011bHRpQm94UHJpb3IuamF2YQ==) | `76.00% <ø> (ø)` | |
| [...rc/main/java/ai/djl/modality/cv/output/Joints.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9Kb2ludHMuamF2YQ==) | `71.42% <ø> (ø)` | |
| [.../main/java/ai/djl/modality/cv/output/Landmark.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9MYW5kbWFyay5qYXZh) | `100.00% <ø> (ø)` | |
| [...main/java/ai/djl/modality/cv/output/Rectangle.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L291dHB1dC9SZWN0YW5nbGUuamF2YQ==) | `72.41% <0.00%> (ø)` | |
| [...i/djl/modality/cv/translator/BigGANTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvQmlnR0FOVHJhbnNsYXRvci5qYXZh) | `21.42% <0.00%> (-5.24%)` | :arrow_down: |
| [...odality/cv/translator/BigGANTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvQmlnR0FOVHJhbnNsYXRvckZhY3RvcnkuamF2YQ==) | `33.33% <0.00%> (+8.33%)` | :arrow_up: |
| [...nslator/InstanceSegmentationTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvSW5zdGFuY2VTZWdtZW50YXRpb25UcmFuc2xhdG9yRmFjdG9yeS5qYXZh) | `14.28% <0.00%> (-3.90%)` | :arrow_down: |
| [.../cv/translator/SemanticSegmentationTranslator.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvU2VtYW50aWNTZWdtZW50YXRpb25UcmFuc2xhdG9yLmphdmE=) | `0.00% <0.00%> (ø)` | |
| [.../cv/translator/StyleTransferTranslatorFactory.java](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary#diff-YXBpL3NyYy9tYWluL2phdmEvYWkvZGpsL21vZGFsaXR5L2N2L3RyYW5zbGF0b3IvU3R5bGVUcmFuc2ZlclRyYW5zbGF0b3JGYWN0b3J5LmphdmE=) | `40.00% <ø> (ø)` | |
| ... and [421 more](https://codecov.io/gh/deepjavalibrary/djl/pull/1852/diff?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1852?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/deepjavalibrary/djl/pull/1852?src=pr&el=footer&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Last update [17f80f8...7a9a17a](https://codecov.io/gh/deepjavalibrary/djl/pull/1852?src=pr&el=lastupdated&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=deepjavalibrary).


Patch:
diff --git a/api/src/main/java/ai/djl/engine/Engine.java b/api/src/main/java/ai/djl/engine/Engine.java
index 69cdd7c7e..ec3420ad8 100644
--- a/api/src/main/java/ai/djl/engine/Engine.java
+++ b/api/src/main/java/ai/djl/engine/Engine.java
@@ -71,7 +71,7 @@ public abstract class Engine {
             return null;
         }
 
-        String defaultEngine = System.getenv("DJL_DEFAULT_ENGINE");
+        String defaultEngine = Utils.getenv("DJL_DEFAULT_ENGINE");
         defaultEngine = System.getProperty("ai.djl.default_engine", defaultEngine);
         if (defaultEngine == null || defaultEngine.isEmpty()) {
             int rank = Integer.MAX_VALUE;
@@ -340,7 +340,7 @@ public abstract class Engine {
 
         System.out.println();
         System.out.println("--------- Environment Variables ---------");
-        System.getenv().forEach((k, v) -> System.out.println(k + ": " + v));
+        Utils.getenv().forEach((k, v) -> System.out.println(k + ": " + v));
 
         System.out.println();
         System.out.println("-------------- Directories --------------");
diff --git a/api/src/main/java/ai/djl/training/util/ProgressBar.java b/api/src/main/java/ai/djl/training/util/ProgressBar.java
index ba26d73ec..6300116dc 100644
--- a/api/src/main/java/ai/djl/training/util/ProgressBar.java
+++ b/api/src/main/java/ai/djl/training/util/ProgressBar.java
@@ -13,6 +13,7 @@
 package ai.djl.training.util;
 
 import ai.djl.util.Progress;
+import ai.djl.util.Utils;
 
 /**
  * {@code ProgressBar} is an implementation of {@link Progress}. It can be used to display the
@@ -142,7 +143,7 @@ public final class ProgressBar implements Progress {
         if (System.getProperty("os.name").startsWith("Win")) {
             return '=';
         } else if (System.getProperty("os.name").startsWith("Linux")) {
-            String lang = System.getenv("LANG");
+            String lang = Utils.getenv("LANG");
             if (lang == null || !lang.contains("UTF-8")) {
                 return '=';
             }
diff --git a/api/src/main/java/ai/djl/util/Utils.java b/api/src/main/java/ai/djl/util/Utils.java
index da6c2af34..1903eb095 100644
--- a/api/src/main/java/ai/djl/util/Utils.java
+++ b/api/src/main/java/ai/djl/util/Utils.java
@@ -16,6 +16,7 @@ import ai.djl.ndarray.NDArray;
 import ai.djl.nn.Parameter;
 
 import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
 
 import java.io.BufferedInputStream;
 import java.io.ByteArrayOutputStream;
@@ -31,6 +32,7 @@ import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Map;
 import java.util.Objects;
 import java.util.Scanner;
 import java.util.regex.Matcher;
@@ -40,6 +42,8 @@ import java.util.stream.Collectors;
 /** A class containing utility methods. */
 public final class Utils {
 
+    private static final Logger logger = LoggerFactory.getLogger(Utils.class);
+
     private Utils() {}
 
     /**
@@ -326,7 +330,7 @@ public final class Utils {
     public static Path getEngineCacheDir() {
         String cacheDir = System.getProperty("ENGINE_CACHE_DIR");
         if (cacheDir == null || cacheDir.isEmpty()) {
-            cacheDir = System.getenv("ENGINE_CACHE_DIR");
+            cacheDir = Utils.getenv("ENGINE_CACHE_DIR");
             if (cacheDir == null || cacheDir.isEmpty()) {
                 return getCacheDir();
             }
@@ -342,7 +346,7 @@ public final class Utils {
     public static Path getCacheDir() {
         String cacheDir = System.getProperty("DJL_CACHE_DIR");
         if (cacheDir == null || cacheDir.isEmpty()) {
-            cacheDir = System.getenv("DJL_CACHE_DIR");
+            cacheDir = Utils.getenv("DJL_CACHE_DIR");
             if (cacheDir == null || cacheDir.isEmpty()) {
                 Path dir = Paths.get(System.getProperty("user.home"));
                 if (!Files.isWritable(dir)) {
@@ -377,4 +381,49 @@ public final class Utils {
         }
         return modelDir.toAbsolutePath();
     }
+
+    /**
+     * Gets the value of the specified environment variable.
+     *
+     * @param name the name of the environment variable
+     * @param def a default value
+     * @return the string value of the variable, or {@code def} if the variable is not defined in
+     *     the system environment or security manager doesn't allow access to the environment
+     *     variable
+     */
+    public static String getenv(String name, String def) {
+        try {
+            String val = System.getenv(name);
+            return val == null ? def : val;
+        } catch (SecurityException e) {
+            logger.warn("Security manager doesn't allow access to the environment variable");
+        }
+        return def;
+    }
+
+    /**
+     * Gets the value of the specified environment variable.
+     *
+     * @param name the name of the environment variable
+     * @return the string value of the variable, or {@code null} if the variable is not defined in
+     *     the system environment or security manager doesn't allow access to the environment
+     *     variable
+     */
+    public static String getenv(String name) {
+        return getenv(name, null);
+    }
+
+    /**
+     * Returns an unmodifiable string map view of the current system environment.
+     *
+     * @return the environment as a map of variable names to values
+     */
+    public static Map<String, String> getenv() {
+        try {
+            return System.getenv();
+        } catch (SecurityException e) {
+            logger.warn("Security manager doesn't allow access to the environment variable");
+        }
+        return Collections.emptyMap();
+    }
 }
diff --git a/api/src/main/java/ai/djl/util/cuda/CudaUtils.java b/api/src/main/java/ai/djl/util/cuda/CudaUtils.java
index fac429c39..cf51a47a1 100644
--- a/api/src/main/java/ai/djl/util/cuda/CudaUtils.java
+++ b/api/src/main/java/ai/djl/util/cuda/CudaUtils.java
@@ -14,6 +14,7 @@ package ai.djl.util.cuda;
 
 import ai.djl.Device;
 import ai.djl.engine.EngineException;
+import ai.djl.util.Utils;
 
 import com.sun.jna.Native;
 
@@ -156,12 +157,12 @@ public final class CudaUtils {
     private static CudaLibrary loadLibrary() {
         try {
             if (System.getProperty("os.name").startsWith("Win")) {
-                String path = System.getenv("PATH");
+                String path = Utils.getenv("PATH");
                 if (path == null) {
                     return null;
                 }
                 Pattern p = Pattern.compile("cudart64_\\d+\\.dll");
-                String cudaPath = System.getenv("CUDA_PATH");
+                String cudaPath = Utils.getenv("CUDA_PATH");
                 String[] searchPath;
                 if (cudaPath == null) {
                     searchPath = path.split(";");
diff --git a/engines/dlr/dlr-engine/src/main/java/ai/djl/dlr/jni/LibUtils.java b/engines/dlr/dlr-engine/src/main/java/ai/djl/dlr/jni/LibUtils.java
index 84d3d5dad..c701c3114 100644
--- a/engines/dlr/dlr-engine/src/main/java/ai/djl/dlr/jni/LibUtils.java
+++ b/engines/dlr/dlr-engine/src/main/java/ai/djl/dlr/jni/LibUtils.java
@@ -139,7 +139,7 @@ public final class LibUtils {
     }
 
     private static String findNativeOverrideLibrary() {
-        String libPath = System.getenv("DLR_LIBRARY_PATH");
+        String libPath = Utils.getenv("DLR_LIBRARY_PATH");
         if (libPath != null) {
             String libName = findLibraryInPath(libPath);
             if (libName != null) {
diff --git a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxEngine.java b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxEngine.java
index 1e2d634ea..5d028ec4c 100644
--- a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxEngine.java
+++ b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/engine/MxEngine.java
@@ -25,6 +25,7 @@ import ai.djl.training.LocalParameterServer;
 import ai.djl.training.ParameterServer;
 import ai.djl.training.optimizer.Optimizer;
 import ai.djl.util.RandomUtils;
+import ai.djl.util.Utils;
 
 import java.io.FileNotFoundException;
 import java.nio.file.Files;
@@ -58,11 +59,9 @@ public final class MxEngine extends Engine {
             Runtime.getRuntime().addShutdownHook(new Thread(JnaUtils::waitAll)); // NOPMD
 
             // load extra MXNet library
-            String paths = System.getenv("MXNET_EXTRA_LIBRARY_PATH");
-            boolean extraLibVerbose = false;
-            if (System.getenv().containsKey(MXNET_EXTRA_LIBRARY_VERBOSE)) {
-                extraLibVerbose = Boolean.parseBoolean(System.getenv(MXNET_EXTRA_LIBRARY_VERBOSE));
-            }
+            String paths = Utils.getenv("MXNET_EXTRA_LIBRARY_PATH");
+            boolean extraLibVerbose =
+                    Boolean.parseBoolean(Utils.getenv(MXNET_EXTRA_LIBRARY_VERBOSE));
             if (paths != null) {
                 String[] files = paths.split(",");
                 for (String file : files) {
diff --git a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/jna/LibUtils.java b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/jna/LibUtils.java
index acb0a32dc..e7dec4926 100644
--- a/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/jna/LibUtils.java
+++ b/engines/mxnet/mxnet-engine/src/main/java/ai/djl/mxnet/jna/LibUtils.java
@@ -86,7 +86,7 @@ public final class LibUtils {
     }
 
     private static String findOverrideLibrary() {
-        String libPath = System.getenv("MXNET_LIBRARY_PATH");
+        String libPath = Utils.getenv("MXNET_LIBRARY_PATH");
         if (libPath != null) {
             String libName = findLibraryInPath(libPath);
             if (libName != null) {
@@ -102,7 +102,7 @@ public final class LibUtils {
     }
 
     private static synchronized String findLibraryInClasspath() {
-        String overrideVersion = System.getenv("MXNET_VERSION");
+        String overrideVersion = Utils.getenv("MXNET_VERSION");
         if (overrideVersion == null) {
             overrideVersion = System.getProperty("MXNET_VERSION");
         }
diff --git a/engines/paddlepaddle/paddlepaddle-engine/src/main/java/ai/djl/paddlepaddle/jni/LibUtils.java b/engines/paddlepaddle/paddlepaddle-engine/src/main/java/ai/djl/paddlepaddle/jni/LibUtils.java
index 412e3ab71..aa446468a 100644
--- a/engines/paddlepaddle/paddlepaddle-engine/src/main/java/ai/djl/paddlepaddle/jni/LibUtils.java
+++ b/engines/paddlepaddle/paddlepaddle-engine/src/main/java/ai/djl/paddlepaddle/jni/LibUtils.java
@@ -90,7 +90,7 @@ public final class LibUtils {
                     "Paddle MKL/GPU requires user to set LD_LIBRARY_PATH="
                             + libDir
                             + ", the current one is set to: "
-                            + System.getenv("LD_LIBRARY_PATH"));
+                            + Utils.getenv("LD_LIBRARY_PATH"));
             List<String> names = Arrays.asList("libdnnl.so.2", "libiomp5.so", "libmklml_intel.so");
             names.forEach(
                     name -> {
@@ -123,7 +123,7 @@ public final class LibUtils {
     }
 
     private static String findOverrideLibrary() {
-        String libPath = System.getenv("PADDLE_LIBRARY_PATH");
+        String libPath = Utils.getenv("PADDLE_LIBRARY_PATH");
         if (libPath != null) {
             String libName = findLibraryInPath(libPath);
             if (libName != null) {
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtEngine.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtEngine.java
index 03e5887f9..c590524f6 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtEngine.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/engine/PtEngine.java
@@ -22,6 +22,7 @@ import ai.djl.pytorch.jni.JniUtils;
 import ai.djl.pytorch.jni.LibUtils;
 import ai.djl.training.GradientCollector;
 import ai.djl.util.RandomUtils;
+import ai.djl.util.Utils;
 
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -64,7 +65,7 @@ public final class PtEngine extends Engine {
             logger.info("Number of inter-op threads is " + JniUtils.getNumInteropThreads());
             logger.info("Number of intra-op threads is " + JniUtils.getNumThreads());
 
-            String paths = System.getenv("PYTORCH_EXTRA_LIBRARY_PATH");
+            String paths = Utils.getenv("PYTORCH_EXTRA_LIBRARY_PATH");
             if (paths == null) {
                 paths = System.getProperty("PYTORCH_EXTRA_LIBRARY_PATH");
             }
diff --git a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/LibUtils.java b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/LibUtils.java
index 840c50e15..8c85e4fc7 100644
--- a/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/LibUtils.java
+++ b/engines/pytorch/pytorch-engine/src/main/java/ai/djl/pytorch/jni/LibUtils.java
@@ -169,7 +169,7 @@ public final class LibUtils {
     }
 
     private static LibTorch findOverrideLibrary() {
-        String libPath = System.getenv("PYTORCH_LIBRARY_PATH");
+        String libPath = Utils.getenv("PYTORCH_LIBRARY_PATH");
         if (libPath != null) {
             LibTorch lib = findLibraryInPath(libPath);
             if (lib != null) {
@@ -268,7 +268,7 @@ public final class LibUtils {
 
     private static LibTorch findNativeLibrary() {
         Platform platform = Platform.detectPlatform("pytorch");
-        String overrideVersion = System.getenv("PYTORCH_VERSION");
+        String overrideVersion = Utils.getenv("PYTORCH_VERSION");
         if (overrideVersion == null) {
             overrideVersion = System.getProperty("PYTORCH_VERSION");
         }
@@ -366,7 +366,7 @@ public final class LibUtils {
         String precxx11;
         if (System.getProperty("os.name").startsWith("Linux")
                 && (Boolean.getBoolean("PYTORCH_PRECXX11")
-                        || Boolean.parseBoolean(System.getenv("PYTORCH_PRECXX11"))
+                        || Boolean.parseBoolean(Utils.getenv("PYTORCH_PRECXX11"))
                         || ("aarch64".equals(platform.getOsArch())
                                 && "linux".equals(platform.getOsPrefix())))) {
             precxx11 = "-precxx11";
@@ -509,14 +509,14 @@ public final class LibUtils {
             this.dir = dir;
             this.apiVersion = platform.getApiVersion();
             this.classifier = platform.getClassifier();
-            version = System.getenv("PYTORCH_VERSION");
+            version = Utils.getenv("PYTORCH_VERSION");
             if (version == null) {
                 version = System.getProperty("PYTORCH_VERSION");
                 if (version == null) {
                     version = platform.getVersion();
                 }
             }
-            flavor = System.getenv("PYTORCH_FLAVOR");
+            flavor = Utils.getenv("PYTORCH_FLAVOR");
             if (flavor == null) {
                 flavor = System.getProperty("PYTORCH_FLAVOR");
                 if (flavor == null) {
diff --git a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java
index 01ec79b56..b60213f78 100644
--- a/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java
+++ b/engines/tensorflow/tensorflow-engine/src/main/java/ai/djl/tensorflow/engine/javacpp/LibUtils.java
@@ -65,7 +65,7 @@ public final class LibUtils {
     }
 
     private static String findOverrideLibrary() {
-        String libPath = System.getenv("TENSORFLOW_LIBRARY_PATH");
+        String libPath = Utils.getenv("TENSORFLOW_LIBRARY_PATH");
         if (libPath != null) {
             String libName = findLibraryInPath(libPath);
             if (libName != null) {
diff --git a/engines/tensorrt/src/main/java/ai/djl/tensorrt/engine/TrtEngine.java b/engines/tensorrt/src/main/java/ai/djl/tensorrt/engine/TrtEngine.java
index afc25f02a..98fc0bcc0 100644
--- a/engines/tensorrt/src/main/java/ai/djl/tensorrt/engine/TrtEngine.java
+++ b/engines/tensorrt/src/main/java/ai/djl/tensorrt/engine/TrtEngine.java
@@ -22,6 +22,7 @@ import ai.djl.nn.SymbolBlock;
 import ai.djl.tensorrt.jni.JniUtils;
 import ai.djl.tensorrt.jni.LibUtils;
 import ai.djl.training.GradientCollector;
+import ai.djl.util.Utils;
 
 import java.io.FileNotFoundException;
 import java.nio.file.Files;
@@ -49,7 +50,7 @@ public final class TrtEngine extends Engine {
         try {
             LibUtils.loadLibrary();
             JniUtils.initPlugins("");
-            String paths = System.getenv("TENSORRT_EXTRA_LIBRARY_PATH");
+            String paths = Utils.getenv("TENSORRT_EXTRA_LIBRARY_PATH");
             if (paths == null) {
                 paths = System.getProperty("TENSORRT_EXTRA_LIBRARY_PATH");
             }
diff --git a/extensions/aws-ai/src/main/java/ai/djl/aws/sagemaker/SageMaker.java b/extensions/aws-ai/src/main/java/ai/djl/aws/sagemaker/SageMaker.java
index a62cf16e9..88a23aa28 100644
--- a/extensions/aws-ai/src/main/java/ai/djl/aws/sagemaker/SageMaker.java
+++ b/extensions/aws-ai/src/main/java/ai/djl/aws/sagemaker/SageMaker.java
@@ -455,7 +455,7 @@ public final class SageMaker {
     }
 
     private String getContainerImageName() {
-        String metadataFile = System.getenv("ECS_CONTAINER_METADATA_FILE");
+        String metadataFile = Utils.getenv("ECS_CONTAINER_METADATA_FILE");
         if (metadataFile == null) {
             throw new AssertionError("Not in a ECS container.");
         }


Test patch:
diff --git a/api/src/test/java/ai/djl/util/UtilsTest.java b/api/src/test/java/ai/djl/util/UtilsTest.java
index bcc84ecb0..cdb4f4dc7 100644
--- a/api/src/test/java/ai/djl/util/UtilsTest.java
+++ b/api/src/test/java/ai/djl/util/UtilsTest.java
@@ -78,4 +78,12 @@ public class UtilsTest {
         float[] array = Utils.toFloatArray(list);
         Assert.assertEquals(array, new float[] {1f, 2f});
     }
+
+    @Test
+    public void testGetenv() {
+        if (!Utils.getenv().containsKey("TEST")) {
+            Assert.assertNull(Utils.getenv("TEST"));
+            Assert.assertEquals(Utils.getenv("TEST", "test"), "test");
+        }
+    }
 }