Skip to content

Latest commit

 

History

History
87 lines (71 loc) · 12 KB

File metadata and controls

87 lines (71 loc) · 12 KB

Architecture & Technical Implementation

This project is a zero-dependency, lightweight, native Windows implementation designed to bypass the traditional complexities of virtualized bash scripts (like SDKMAN!) on Windows operating systems.

The Core Mechanism: Directory Junctions

Instead of constantly appending and pruning your Windows PATH variable to point to different JDK folders (which quickly leads to the 1024-character PATH limit and environment variable bloat), the manager maintains a single Directory Junction (mklink /J) at:

%LOCALAPPDATA%\DiamTek\JVM\current

Your system PATH only ever needs to contain %LOCALAPPDATA%\DiamTek\JVM\current\bin. When you switch Java versions, the manager simply tears down the old junction and repoints it to the target JDK directory. This provides O(1) symlink resolution for the OS.

Dual-Architecture Core (Symlink Mode vs. Legacy Registry Mode)

The engine provides two distinct switching engines that users can toggle via the Settings menu or CLI flags:

  1. Symlink Mode (Default, UAC-Free):

    • Mechanism: Updates the NTFS Directory Junction pointer (%LOCALAPPDATA%\DiamTek\JVM\current) in user-space.
    • Privileges: Standard user space (100% UAC-free, zero admin popups).
    • Compatibility: Native for 99% of modern tools (Maven, Gradle, IntelliJ IDEA, VS Code, Eclipse).
  2. Registry Mode (Legacy, UAC Required):

    • Mechanism: Directly writes the absolute JDK path to the Machine-level Windows Registry (HKLM\SYSTEM\CurrentControlSet\Control\Session Manager\Environment) and updates the system-wide Machine PATH.
    • Privileges: Requires Administrator (UAC) Elevation on every switch, spawning an elevated background PowerShell worker via Start-Process -Verb RunAs.
    • Compatibility: 100% unbreakable fallback for legacy enterprise applications, obscure Windows service runners, or ancient classloaders that perform strict canonical path checks and cannot resolve NTFS Directory Junctions.

Deep OS Environment Management

To ensure deep OS integration without requiring users to download external binaries (like setx augmentations), the tool relies on inline PowerShell execution invoked seamlessly via cmd.exe.

Global/Machine State (HKLM)

  • Updates to the global PATH and JAVA_HOME are performed natively using the .NET framework bridging in PowerShell: [Environment]::SetEnvironmentVariable('JAVA_HOME', $target, 'Machine')
  • The script detects if it is running in standard user space. If required, it dynamically generates an elevated PowerShell script (jvm_elevate_XXXX.ps1) in %TEMP% and executes it via Start-Process -Verb RunAs.

Session State Isolation

  • Updating the Windows Registry does not update the live, running terminal session. To solve this, the script dynamically evaluates the environment block within the execution boundary.
  • Dynamic Filtering: Instead of using batch string substitution (!PATH:string=!), which is vulnerable to quote-collisions and delayed expansion parsing bugs, the manager pipes the variable manipulation to PowerShell using the -not operator against $env:PATH. This guarantees 100% accurate string evaluation and prevents the accidental deletion of unrelated paths (e.g., pruning JAVA_HOME_Backup while searching for JAVA_HOME).

Ecosystem Routing (Universal Candidate Engine)

Like SDKMAN!, this tool intercepts commands for popular Java tools (Maven, Gradle, Kotlin, Scala, Groovy). The CLI acts as a universal router:

  1. It intercepts the jvm install <candidate> <version> command.
  2. It executes a PowerShell Invoke-RestMethod to the respective API (Adoptium, GitHub Releases, Azul, etc.) to securely resolve the download URL and SHA-256 checksums.
  3. The payloads are extracted via Expand-Archive and isolated in %LOCALAPPDATA%\DiamTek\JVM\candidates\<candidate>.
  4. Specific <CANDIDATE>_HOME variables are injected into the registry, mapping the ecosystem completely identically to native Java.

Real-Time PowerShell Session Propagation (Set-JvmVar)

Because Windows process environments cannot ordinarily be modified by a child batch process, install.ps1 injects a native PowerShell function hook into $PROFILE. When jvm switches an active tool or JDK:

  1. jvm.bat writes target environment pairs (KEY=VALUE) to $env:TEMP\.jvm_session_target.
  2. The PowerShell wrapper intercepts the return code and invokes Set-JvmVar.
  3. Set-JvmVar surgically strips the old \bin directory from $env:Path and prepends the new \bin directory directly into the current PowerShell process memory.
  4. It updates $env:JAVA_HOME (or corresponding tool variables) live, providing instantaneous switching without reopening terminal tabs.

Bulletproof Batch Heredoc Escaping

Windows cmd.exe does not natively support Bash-style heredocs (cat <<EOF). Embedding multi-line PowerShell scripts inside a batch ( ... ) > script.ps1 redirection block requires careful escaping:

  • Redirection operators (<, >) are escaped as ^<, ^>.
  • Pipes (|) and command separators (&) are escaped as ^|, ^&.
  • Parentheses ((, )) are escaped as ^(, ^) to prevent premature termination of the enclosing batch block.
  • Exclamation marks (!) are escaped as ^^! to prevent corruption by CMD's delayed variable expansion engine (setlocal enabledelayedexpansion).

Deep Uninstaller & Windows Integration Architecture

The uninstaller subsystem (uninstall.ps1) is designed for 100% total system sanitization:

  1. UAC Escalation: Uses .NET security principals to check for elevated tokens; if missing, automatically spawns an elevated PowerShell host via Start-Process -Verb RunAs.
  2. Registry Integration: Registers under HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\DiamTek.JVM with native Windows "Installed apps" metadata, dynamic EstimatedSize computation (with a 1,024 KB floor for Windows 11 compatibility), and creates a Start Menu uninstaller shortcut in Start Menu\Programs\DiamTek.
  3. Dual-Scope Cleanup: Cleans both User and Machine environment variables and PATH registries, surgically strips the $PROFILE hook, deletes the AppData Ecosystem cache, purges Windows Terminal profiles, removes pinned taskbar shortcuts, cleans session files, and prompts to clean C:\Program Files\Java.

Windows Terminal & Shell Integration Architecture

To provide a first-class modern Windows developer experience while strictly maintaining 100% pure Batch & PowerShell code:

  1. Dynamic Profile Injection: install.ps1 scans for Windows Terminal configurations across Release, Preview, and Unpackaged locations (LocalState\settings.json). It injects a dedicated profile with GUID {b20650a4-4212-4d64-9edf-744e9285e2be}, pointing to high-resolution assets/icon.png.
  2. Tab Lifecycle Management: Configured with cmd.exe /c and closeOnExit: always. When a developer exits the interactive JVM menu (exit /B 0), the hosting cmd.exe process terminates, signaling Windows Terminal to immediately close the tab.
  3. Shortcut Synchronization: Creates Start Menu application shortcuts targeting wt.exe -p "Java Version Manager" (falling back to cmd.exe /c on systems without Windows Terminal). During installation and self-updates, the script automatically searches %APPDATA%\Microsoft\Internet Explorer\Quick Launch\User Pinned\TaskBar\ to detect and update existing pinned taskbar shortcuts in place.
  4. AppUserModelID & Taskbar Mechanics: Windows Terminal is a packaged WinUI app that hardcodes its own process-level AppUserModelID (Microsoft.WindowsTerminal...) on all hosting windows. By registering a dedicated profile with native icon and dropdown integration rather than forcing brittle binary wrappers, the utility respects the OS container model while maintaining a zero-binary, 100% script-based repository.

Multi-Channel Packaging Pipelines

  • Winget: Native YAML manifest (packages\winget\DiamTek.JVM.yaml) declaring installer metadata and portable packaging.
  • Scoop: JSON manifest (packages\scoop\jvm.json) that automates downloading and bootstraps install.ps1.
  • Chocolatey: Package specification (packages\choco\jvm.nuspec) with automated chocolateyInstall.ps1 and chocolateyUninstall.ps1 scripts.
  • WiX Toolset v4 (MSI): Automated build script (packages\msi\build-msi.ps1) that compiles native, per-user Windows Installers (.msi) bundling jvm.bat, companion branding assets, uninstall.ps1, LICENSE, and README.md:
    • Embedded Cabinet Architecture: Built with <MediaTemplate EmbedCab="yes" /> to generate an internal #cab1.cab data stream inside the .msi binary. This produces truly standalone, single-file installers (~900 KB) without loose external .cab files, simplifying distribution and offline caching.
    • Multi-Architecture Support (x64 & arm64): Compiles native installers targeting both 64-bit Intel/AMD and ARM64 Windows platforms via WiX v4 -arch switches, setting native architecture properties while defaulting to building both ($Arch = "all").
    • Upgrade & Downgrade Safety: Configured with <MajorUpgrade DowngradeErrorMessage="..." Schedule="afterInstallInitialize" /> allowing clean upgrades over prior versions while preventing accidental downgrade conflicts.
    • Deferred Action Execution Order & Hook Isolation:
      • Isolated Hook Architecture: Internal hook scripts (msi-install-hook.ps1 and msi-uninstall-hook.ps1) reside privately in %LOCALAPPDATA%\DiamTek\JVM\, strictly segregating them from the CLI %LOCALAPPDATA%\DiamTek\JVM\bin\ folder so internal scripts never pollute the user's command line or PATH.
      • Install Hook: Scheduled After="CreateShortcuts" (sequence 4501) rather than After="InstallFiles" (sequence 4002). Standard Windows Installer action CreateShortcuts generates the Start Menu .lnk at sequence 4500; scheduling the hook afterward ensures the shortcut exists before PowerShell attempts to polish it with Windows Terminal (wt.exe) profiles and custom arguments.
      • Path Resolution in WixQuietExec: Standard Windows Installer deferred custom actions run in the Windows Installer service context without inheriting standard shell environment PATHs. Hardcoding [WindowsFolder]System32\WindowsPowerShell\v1.0\powershell.exe guarantees deterministic 64-bit PowerShell invocation, completely eliminating 0x80070002 ("file not found") execution errors.
      • Uninstall Hook: Scheduled Before="RemoveFiles" to ensure PowerShell profile cleanup, Windows Terminal configuration scrubbing, dangling sub-process termination, and environment variable removal occur while the installed components are still present on disk.
      • Start Menu Uninstaller Shortcut: Packages an explicit MSI shortcut targeting [SystemFolder]msiexec.exe /x [ProductCode] under Start Menu\Programs\DiamTek, allowing instant uninstallation discovery via Windows Search ("Uninstall Java Version Manager" and "Uninstall JVM").
      • Race Condition Elimination: The MSI uninstaller relies purely on standard Windows Installer actions (RemoveFile, RemoveFolderEx) for directory teardown, omitting background asynchronous CMD deletions to avoid file-lock race conditions (Windows Installer Error 2318).
    • Automated Verification Suite (packages\msi\test-msi.ps1): Implements an automated 18-point synthetic integration suite designed for CI/CD pipelines and GitHub Actions build provenance attestations (actions/attest-build-provenance). The suite actively tests live operating system integration (Windows Installer service msiexec, binary layout, CLI bin/ directory hygiene, Start Menu application and uninstaller shortcuts indexed by Windows Search, registry metadata, PATH propagation, Windows Terminal profile injection, CLI sanity subshell execution, clean uninstallation, and zero filesystem residuals). Features an autonomous 4-tier fallback engine (local MSI -> local WiX compiler -> GitHub Release binary -> remote source bootstrap + user-space .NET SDK / WiX CLI toolchain) and supports -ShowUI (native progress dialog /qb) and -KeepInstalled (retaining JVM post-test for direct terminal usage).