浏览代码

ZOOKEEPER-4050: Zookeeper Inspector reports "List of default node viewers is empty" when not specifically run from the zookeeper-contrib/zookeeper-contrib-zooinspector directory

ISSUE
---
See https://issues.apache.org/jira/browse/ZOOKEEPER-4050 for details on the issue.

This is a follow-on PR to issues identified in https://github.com/apache/zookeeper/pull/1551.  While that PR fixed some launch issues, currently ZooInspector still needs to be run from the root ZooInspector directory because it expects the `defaultConnectionSettings.cfg` and `defaultNodeViewers.cfg` to exist on the filesystem in a specific location.  The previous PR ensured that these files are now bundled into the fat jar built by Maven, so this new PR makes the checks for these files fall back to checking the classpath (i.e. checking inside the jar) for these files if they can't be found on the filesystem first.  This means that the `zooInspector.sh` and `zooInspector.cmd` scripts can now be run from anywhere once the project is built.

TESTING
---
I've tested cloning, building and running ZooInspector on Mac OS Catalina (10.15.7) on Java 8 with these fixes and invoking `zooInspector.sh` from different directories to ensure it runs properly and doesn't display the aforementioned error.

I ran `mvn verify spotbugs:check checkstyle:check -Pfull-build -Dsurefire-forkcount=4` in the `zookeeper-contrib/zookeeper-contrib-zooinspector` directory (per https://cwiki.apache.org/confluence/display/ZOOKEEPER/HowToContribute#HowToContribute-FinalChecksonPullRequest) and got these results:

```
[INFO] You have 0 Checkstyle violations.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  15.037 s
[INFO] Finished at: 2021-02-01T20:30:04-08:00
[INFO] ------------------------------------------------------------------------
```

Since all of my proposed changes are in the `zookeeper-contrib` subtree (and specifically only in `zookeeper-contrib-zooinspector`, I did not run the wider unit tests for the Zookeeper project as a whole.

Author: brentwritescode <brentwritescode@gmail.com>
Author: Brent Nash <brent.nash@crowdstrike.com>

Reviewers: Enrico Olivelli <eolivelli@apache.org>, Damien Diederen <ddiederen@apache.org>

Closes #1589 from brentwritescode/ZOOKEEPER-4050

(cherry picked from commit 245ff759b0e9fe0a1815e03433306ac805bf5e95)
Signed-off-by: Damien Diederen <ddiederen@apache.org>
brentwritescode 4 年之前
父节点
当前提交
4b5cc72e0a

+ 60 - 37
zookeeper-contrib/zookeeper-contrib-zooinspector/src/main/java/org/apache/zookeeper/inspector/manager/ZooInspectorManagerImpl.java

@@ -20,9 +20,12 @@ package org.apache.zookeeper.inspector.manager;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
 import java.io.File;
+import java.io.FileNotFoundException;
 import java.io.FileReader;
 import java.io.FileWriter;
 import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -91,6 +94,12 @@ public class ZooInspectorManagerImpl implements ZooInspectorManager {
      */
     public static final String AUTH_DATA_KEY = "authData";
 
+    private static final String DEFAULT_ENCRYPTION_MANAGER =
+        BasicDataEncryptionManager.class.getName();
+    private static final int DEFAULT_TIMEOUT = 5000;
+    private static final String DEFAULT_HOSTS = "localhost:2181";
+    private static final String DEFAULT_AUTH_SCHEME = "";
+    private static final String DEFAULT_AUTH_VALUE = "";
 
     private static final File defaultNodeViewersFile = new File(
             "./src/main/resources/defaultNodeViewers.cfg");
@@ -713,55 +722,47 @@ public class ZooInspectorManagerImpl implements ZooInspectorManager {
     public List<String> loadNodeViewersFile(File selectedFile)
             throws IOException {
         List<String> result = new ArrayList<String>();
-        if (defaultNodeViewersFile.exists()) {
-            FileReader reader = new FileReader(selectedFile);
-            try {
-                BufferedReader buff = new BufferedReader(reader);
-                try {
-                    while (buff.ready()) {
-                        String line = buff.readLine();
-                        if (line != null && line.length() > 0 && !line.startsWith("#")) {
-                            result.add(line);
-                        }
+
+        try(BufferedReader reader = getReaderForFile(selectedFile)) {
+            if(reader == null) {
+                return result;
+            }
+
+            String line = "";
+            while (line != null) {
+                line = reader.readLine();
+                if(line != null) {
+                    line = line.trim();
+                    if (!line.isEmpty() && !line.startsWith("#")) {
+                        result.add(line);
                     }
-                } finally {
-                    buff.close();
                 }
-            } finally {
-                reader.close();
             }
         }
+
         return result;
     }
 
     private void loadDefaultConnectionFile() throws IOException {
-        if (defaultConnectionFile.exists()) {
-            Properties props = new Properties();
+        Properties props = new Properties();
 
-            FileReader reader = new FileReader(defaultConnectionFile);
-            try {
+        try(BufferedReader reader = getReaderForFile(defaultConnectionFile)) {
+            //If reader is null, it's OK.  Default values will get set below.
+            if(reader != null) {
                 props.load(reader);
-            } finally {
-                reader.close();
             }
-            defaultEncryptionManager = props
-                    .getProperty(DATA_ENCRYPTION_MANAGER) == null ? "org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager"
-                    : props.getProperty(DATA_ENCRYPTION_MANAGER);
-            defaultTimeout = props.getProperty(SESSION_TIMEOUT) == null ? "5000"
-                    : props.getProperty(SESSION_TIMEOUT);
-            defaultHosts = props.getProperty(CONNECT_STRING) == null ? "localhost:2181"
-                    : props.getProperty(CONNECT_STRING);
-            defaultAuthScheme = props.getProperty(AUTH_SCHEME_KEY) == null ? ""
-                    : props.getProperty(AUTH_SCHEME_KEY);
-            defaultAuthValue = props.getProperty(AUTH_DATA_KEY) == null ? ""
-                    : props.getProperty(AUTH_DATA_KEY);
-        } else {
-            defaultEncryptionManager = "org.apache.zookeeper.inspector.encryption.BasicDataEncryptionManager";
-            defaultTimeout = "5000";
-            defaultHosts = "localhost:2181";
-            defaultAuthScheme = "";
-            defaultAuthValue = "";
         }
+
+        defaultEncryptionManager = props.getProperty(DATA_ENCRYPTION_MANAGER) == null ?
+            DEFAULT_ENCRYPTION_MANAGER : props.getProperty(DATA_ENCRYPTION_MANAGER);
+        defaultTimeout = props.getProperty(SESSION_TIMEOUT) == null ?
+            Integer.toString(DEFAULT_TIMEOUT) : props.getProperty(SESSION_TIMEOUT);
+        defaultHosts = props.getProperty(CONNECT_STRING) == null ?
+            DEFAULT_HOSTS : props.getProperty(CONNECT_STRING);
+        defaultAuthScheme = props.getProperty(AUTH_SCHEME_KEY) == null ?
+            DEFAULT_AUTH_SCHEME : props.getProperty(AUTH_SCHEME_KEY);
+        defaultAuthValue = props.getProperty(AUTH_DATA_KEY) == null ?
+            DEFAULT_AUTH_VALUE : props.getProperty(AUTH_DATA_KEY);
     }
 
     /*
@@ -872,4 +873,26 @@ public class ZooInspectorManagerImpl implements ZooInspectorManager {
     public void setLastConnectionProps(Properties connectionProps) {
         this.lastConnectionProps = connectionProps;
     }
+
+    private static BufferedReader getReaderForFile(File file) {
+        //check the filesystem first
+        if (file.exists()) {
+            try {
+                return new BufferedReader(new FileReader(file));
+            } catch (FileNotFoundException e) {
+                return null;
+            }
+        }
+
+        //fall back to checking the CLASSPATH with only the filename
+        //(for cases where the file exists in src/main/resources)
+        InputStream classpathStream = ZooInspectorManagerImpl.class.getClassLoader()
+            .getResourceAsStream(file.getName());
+        if (classpathStream != null) {
+            return new BufferedReader(new InputStreamReader(classpathStream));
+        }
+
+        //couldn't find the file anywhere
+        return null;
+    }
 }