[ 
https://issues.apache.org/jira/browse/GEODE-10523?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18039347#comment-18039347
 ] 

ASF subversion and git services commented on GEODE-10523:
---------------------------------------------------------

Commit 490947a5b39af28bf1b293dc3bd2cee56398d40d in geode's branch 
refs/heads/develop from Jinwoo Hwang
[ https://gitbox.apache.org/repos/asf?p=geode.git;h=490947a5b3 ]

[GEODE-10523] 2.0 RELEASE BLOCKER : gfsh issues after Spring Shell 3 migration 
(#7958)

* GEODE-10523: Fix NullPointerException in gfsh startup

- Add terminal initialization before promptLoop()
- Implement history file migration from JLine 2 to JLine 3 format
- Fix banner display to stdout in non-headless mode

After migrating from Spring Shell 1.x to 3.x, terminal and lineReader
were not being initialized, causing NPE when gfsh tried to read input.
Also fixed incompatible history file format and missing banner output.

* Restore original printAsInfo behavior

- Revert printAsInfo() to use logger.info() in non-headless mode
  (matching pre-Jakarta migration behavior from commit 30cd67814^)
- Move printBannerAndWelcome() after terminal initialization
- This ensures banner output is consistent with original behavior

> gfsh issues after Spring Shell 3 migration
> ------------------------------------------
>
>                 Key: GEODE-10523
>                 URL: https://issues.apache.org/jira/browse/GEODE-10523
>             Project: Geode
>          Issue Type: Bug
>            Reporter: Jinwoo Hwang
>            Assignee: Jinwoo Hwang
>            Priority: Major
>             Fix For: 2.0.0
>
>
> h2. Description
> After migrating from Spring Shell 1.x to Spring Shell 3.x, gfsh fails to 
> start with a {{NullPointerException}} when attempting to read user input. The 
> terminal and line reader components are never initialized before the prompt 
> loop begins.
> h2. Steps to Reproduce
>  # Build Apache Geode with the Spring Shell 3.x migration changes
>  # Navigate to {{geode-assembly/build/install/apache-geode}}
>  # Run {{./bin/gfsh}}
>  # Observe the error
> h2. Expected Behavior
> gfsh should start successfully, display the banner, and present an 
> interactive prompt to the user.
> h2. Actual Behavior
> gfsh crashes with the following error:
> {code:java}
> [error 2025/11/16 12:18:09.159 EST  <Gfsh Launcher> tid=0x11] Error in shell 
> main loop
> java.lang.NullPointerException: Cannot invoke 
> "org.jline.reader.LineReader.readLine(String)" because "reader" is null
>       at 
> org.apache.geode.management.internal.cli.shell.Gfsh.readLine(Gfsh.java:321)
>       at 
> org.apache.geode.management.internal.cli.shell.Gfsh.promptLoop(Gfsh.java:1393)
>       at 
> org.apache.geode.management.internal.cli.shell.Gfsh.run(Gfsh.java:1593)
>       at java.base/java.lang.Thread.run(Thread.java:840)
> Exception in thread "main" java.lang.NullPointerException: Cannot invoke 
> "org.apache.geode.management.internal.cli.shell.ExitShellRequest.getExitCode()"
>  because "exitRequest" is null
>       at 
> org.apache.geode.management.internal.cli.Launcher.parseOptions(Launcher.java:240)
>       at 
> org.apache.geode.management.internal.cli.Launcher.parseCommandLine(Launcher.java:248)
>       at 
> org.apache.geode.management.internal.cli.Launcher.main(Launcher.java:132)
> {code}
> h2. Additional Issues Discovered
> h3. History File Format Incompatibility
> When fixing the NPE issue, a secondary issue was discovered: old JLine 2 
> history files are incompatible with JLine 3, causing warnings:
> {code:java}
> WARNING: Failed to load history
> java.lang.IllegalArgumentException: Bad history file syntax! The history file 
> `/Users/jihwan/.geode/.gfsh.history` may be an older history: please remove 
> it or use a different history file.
> {code}
> h3. Missing Banner
> The gfsh banner was not being displayed because {{printAsInfo()}} was using 
> logger instead of stdout in non-headless mode.
> h2. Root Cause
> The Spring Shell 3.x migration removed the automatic terminal initialization 
> that Spring Shell 1.x provided. In the migrated code:
>  # {*}NPE Issue{*}: The {{terminal}} and {{lineReader}} fields were never 
> initialized before {{run()}} called {{{}promptLoop(){}}}, which tried to use 
> the null {{{}lineReader{}}}.
>  # {*}History Issue{*}: JLine 2 used a different history file format (with 
> {{//}} comment lines) that JLine 3 cannot parse.
>  # {*}Banner Issue{*}: The {{printAsInfo()}} method was calling 
> {{logger.info()}} instead of printing to stdout in interactive mode.
> h2. Solution
> The fix involves three changes:
> h3. 1. Initialize Terminal and LineReader
> In {{{}Gfsh.java{}}}, the {{run()}} method now initializes the terminal and 
> line reader before starting the prompt loop:
> {code:java}
> @Override
> public void run() {
>   try {
>     // Print banner before initializing terminal to ensure it's visible
>     printBannerAndWelcome();
>     // Initialize terminal and line reader before starting prompt loop
>     if (!isHeadlessMode) {
>       initializeTerminal();
>       createConsoleReader();
>     }
>     promptLoop();
>   } catch (Exception e) {
>     gfshFileLogger.severe("Error in shell main loop", e);
>   }
> }
> private void initializeTerminal() throws IOException {
>   if (terminal == null) {
>     terminal = TerminalBuilder.builder()
>         .system(true)
>         .build();
>   }
> }
> {code}
> h3. 2. Migrate Old History Files
> Added {{migrateHistoryFileIfNeeded()}} method in {{Gfsh.java}} to detect and 
> migrate old JLine 2 history files:
> {code:java}
> private void migrateHistoryFileIfNeeded() {
>   try {
>     Path historyPath = Paths.get(getHistoryFileName());
>     if (!Files.exists(historyPath)) {
>       return;
>     }
>     // Check if file contains old format markers (lines starting with // or #)
>     java.util.List<String> lines = Files.readAllLines(historyPath);
>     boolean hasOldFormat = false;
>     for (String line : lines) {
>       String trimmed = line.trim();
>       if (trimmed.startsWith("//") || trimmed.startsWith("#")) {
>         hasOldFormat = true;
>         break;
>       }
>     }
>     if (hasOldFormat) {
>       // Backup old history file
>       Path backupPath = historyPath.getParent()
>           .resolve(historyPath.getFileName().toString() + ".old");
>       Files.move(historyPath, backupPath,
>           java.nio.file.StandardCopyOption.REPLACE_EXISTING);
>       gfshFileLogger.info("Migrated old history file format. Backup saved to: 
> " + backupPath);
>     }
>   } catch (IOException e) {
>     gfshFileLogger.warning("Could not migrate history file", e);
>   }
> }
> {code}
> h3. 3. Fix Banner Display
> Modified {{printAsInfo()}} to always print to stdout:
> {code:java}
> public void printAsInfo(String message) {
>   // Always print to stdout for user-facing messages like banner
>   println(message);
>   // Also log to file if not in headless mode
>   if (!isHeadlessMode) {
>     logger.info(message);
>   }
> }
> {code}
> h2. Files Modified
>  # 
> {{geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/shell/Gfsh.java}}
>  ** Added {{initializeTerminal()}} method
>  ** Added {{migrateHistoryFileIfNeeded()}} method
>  ** Modified {{run()}} method to initialize components
>  ** Modified {{printAsInfo()}} to print to stdout
>  ** Added imports: {{{}java.nio.file.Files{}}}, {{java.nio.file.Path}}
>  # 
> {{geode-gfsh/src/main/java/org/apache/geode/management/internal/cli/shell/jline/GfshHistory.java}}
>  ** Added {{attach()}} override with exception handling for migration
>  ** Added {{migrateOldHistoryFile()}} method
> h2. Testing
> After applying the fix:
>  * gfsh starts without errors
>  * Banner is displayed correctly
>  * Interactive prompt works
>  * Old history files are automatically migrated
>  * Command history works with new format
> h2. Impact
>  * {*}Severity{*}: Critical (gfsh completely unusable)
>  * {*}Affected Versions{*}: Any version after Spring Shell 3.x migration
>  * {*}Workaround{*}: None (gfsh cannot be used)
> h2. Related Issues
> This issue is a direct result of the Spring Shell 1.x to 3.x migration effort.



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to