This is an automated email from the ASF dual-hosted git repository.

tbonelee pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/master by this push:
     new 9b42f2654b [ZEPPELIN-6462] Close interpreter-setting.json streams with 
try-with-resources
9b42f2654b is described below

commit 9b42f2654be2fea9fdddf310686270ebc005d4d6
Author: dae won <[email protected]>
AuthorDate: Thu Aug 6 11:02:46 2026 +0900

    [ZEPPELIN-6462] Close interpreter-setting.json streams with 
try-with-resources
    
    ### What is this PR for?
    
    `InterpreterSettingManager` discovers interpreters by reading each 
interpreter's `interpreter-setting.json`. Two helpers do this, and neither 
closes the stream it opens:
    
    ```java
    // registerInterpreterFromResource
    getInterpreterListFromJson(url.openStream());
    
    // registerInterpreterFromPath
    getInterpreterListFromJson(new 
FileInputStream(interpreterJsonPath.toFile()));
    ```
    
    The shared sink wraps the stream in an `InputStreamReader` and hands it to 
`gson.fromJson(...)`. Gson does not close a reader passed to it — the caller 
owns it — so the descriptor leaks on the normal path. There is no `finally` or 
try-with-resources either, so it also leaks when parsing throws, for example a 
`JsonSyntaxException` from a malformed setting file.
    
    This is not limited to startup. After installing an interpreter through 
`POST /api/interpreter/install`, `InterpreterService.downloadInterpreter()` 
calls `refreshInterpreterTemplates()`, which re-runs the whole directory scan. 
Every install therefore leaks one descriptor per interpreter directory, and the 
leaks accumulate on a long-running server.
    
    This PR wraps each stream in a try-with-resources at the call site that 
opens it. Parsing and registration behaviour is unchanged. No signatures or 
access modifiers change.
    
    ### What type of PR is it?
    Bug Fix
    
    ### Todos
    * [x] Close the stream opened in `registerInterpreterFromResource`
    * [x] Close the stream opened in `registerInterpreterFromPath`
    
    ### What is the Jira issue?
    * https://issues.apache.org/jira/browse/ZEPPELIN-6462
    
    ### How should this be tested?
    
    ```bash
    ./mvnw package -pl zeppelin-server --am \
      
-Dtest='InterpreterSettingManagerTest,InterpreterFactoryTest,InterpreterSettingTest'
 \
      -DfailIfNoTests=false
    ```
    
    `Tests run: 26, Failures: 0, Errors: 0, Skipped: 0`, and `zeppelin-server` 
builds.
    
    No tests accompany this change. Asserting that a stream is closed requires 
a seam in production code to inject a tracked stream, and an earlier revision 
of this PR added one — that is not worth carrying for a two-line fix, so it has 
been removed along with the tests that used it. The remaining change is the 
try-with-resources itself.
    
    ### Screenshots (if appropriate)
    N/A
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    
    
    Closes #5355 from big-cir/ZEPPELIN-6462.
    
    Signed-off-by: ChanHo Lee <[email protected]>
---
 .../zeppelin/interpreter/InterpreterSettingManager.java    | 14 ++++++++------
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git 
a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
 
b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
index e295938220..f6086f4d06 100644
--- 
a/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
+++ 
b/zeppelin-server/src/main/java/org/apache/zeppelin/interpreter/InterpreterSettingManager.java
@@ -486,9 +486,10 @@ public class InterpreterSettingManager implements 
NoteEventListener {
     }
 
     LOGGER.debug("Reading interpreter-setting.json from {} as Resource", url);
-    List<RegisteredInterpreter> registeredInterpreterList =
-        getInterpreterListFromJson(url.openStream());
-    registerInterpreterSetting(registeredInterpreterList, interpreterDir, 
override);
+    try (InputStream stream = url.openStream()) {
+      List<RegisteredInterpreter> registeredInterpreterList = 
getInterpreterListFromJson(stream);
+      registerInterpreterSetting(registeredInterpreterList, interpreterDir, 
override);
+    }
     return true;
   }
 
@@ -498,9 +499,10 @@ public class InterpreterSettingManager implements 
NoteEventListener {
     Path interpreterJsonPath = Paths.get(interpreterDir, interpreterJson);
     if (Files.exists(interpreterJsonPath)) {
       LOGGER.debug("Reading interpreter-setting.json from file {}", 
interpreterJsonPath);
-      List<RegisteredInterpreter> registeredInterpreterList =
-          getInterpreterListFromJson(new 
FileInputStream(interpreterJsonPath.toFile()));
-      registerInterpreterSetting(registeredInterpreterList, interpreterDir, 
override);
+      try (InputStream stream = new 
FileInputStream(interpreterJsonPath.toFile())) {
+        List<RegisteredInterpreter> registeredInterpreterList = 
getInterpreterListFromJson(stream);
+        registerInterpreterSetting(registeredInterpreterList, interpreterDir, 
override);
+      }
       return true;
     }
     return false;

Reply via email to