Skip to content

Commit 9e3d277

Browse files
committed
add powershell version
Signed-off-by: Tony Germano <tony@germano.name>
1 parent 63f60d2 commit 9e3d277

1 file changed

Lines changed: 290 additions & 0 deletions

File tree

Lines changed: 290 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,290 @@
1+
#
2+
# SPDX-License-Identifier: MPL-2.0
3+
# SPDX-FileCopyrightText: 2025 Tony Germano and Mitch Gaffigan
4+
#
5+
6+
# =============================================================================
7+
# Open Integration Engine Server Launcher Script (PowerShell Version)
8+
#
9+
# Description:
10+
# This script is the main launcher for the Open Integration Engine (OIE)
11+
# server. It prepares the Java environment and executes the server launcher
12+
# JAR file.
13+
#
14+
# The script automatically finds a compatible Java runtime (version 17+ by
15+
# default) by searching for a valid executable in the following priority order:
16+
# 1. The OIE_JAVA_PATH environment variable.
17+
# 2. The -java-cmd directive in the oieserver.vmoptions file or included
18+
# .vmoptions files. Must specify the path to the 'java' executable.
19+
# This is the preferred way to declare the desired version for running
20+
# the server and can be overridden by OIE_JAVA_PATH. Can be a relative
21+
# path from the location of this script.
22+
# 3. The JAVA_HOME environment variable.
23+
# 4. The 'java' command available in the system's PATH.
24+
#
25+
# It also parses the 'oieserver.vmoptions' file to configure JVM options,
26+
# system properties (-D...), and classpath modifications.
27+
#
28+
# Usage:
29+
# ./oieserver.ps1 [app-arguments]
30+
#
31+
# All [app-arguments] are passed directly to the underlying Java application
32+
# (com.mirth.connect.server.launcher.MirthLauncher).
33+
#
34+
# Configuration via Environment Variables:
35+
# OIE_JAVA_PATH - (Highest priority) Set the full path to the 'java'
36+
# executable to be used. Can be a relative path from the
37+
# location of this script or a tilde path
38+
# (e.g., ~/path/to/java).
39+
# JAVA_HOME - Set the path to the root of a Java installation. The
40+
# script will look for 'bin/java' within this path.
41+
# =============================================================================
42+
43+
# --- Script Parameters and Initial Variables ---
44+
param(
45+
[string[]]$AppArgs = $args
46+
)
47+
48+
$MinJavaVersion = 17
49+
50+
# Set OieHome to the script directory using PowerShell's built-in variable
51+
$OieHome = $PSScriptRoot
52+
# The engine expects it's working directory to be OieHome
53+
try {
54+
Set-Location -Path $OieHome -ErrorAction Stop
55+
}
56+
catch {
57+
Write-Error "Could not change to the OieHome directory: $OieHome"
58+
exit 1
59+
}
60+
$LauncherJar = Join-Path -Path $OieHome -ChildPath "mirth-server-launcher.jar"
61+
$script:Classpath = $LauncherJar # Use script scope to be modifiable by functions
62+
$script:VmOptions = [System.Collections.Generic.List[string]]::new()
63+
64+
# This will hold the validated path to the Java executable.
65+
$FinalJavaCmd = $null
66+
# This will temporarily hold the result from parsing the vmoptions file.
67+
$script:VmOptionsJavaCmd = $null
68+
$script:VmOptionsJavaCmdFile = $null
69+
70+
# --- Function to resolve a path to a canonical absolute path ---
71+
function Resolve-CanonicalPath {
72+
param(
73+
[string]$PathToResolve
74+
)
75+
76+
# Explicitly handle simple tilde expansion first (`~/` or `~`)
77+
if ($PathToResolve -match '^~(/|$)') {
78+
$homePath = $env:HOME
79+
if ([string]::IsNullOrWhiteSpace($homePath)) {
80+
$homePath = $env:USERPROFILE
81+
}
82+
$PathToResolve = ($PathToResolve -replace '^~/', "$($homePath)/") -replace '^~$', $homePath
83+
}
84+
85+
# If the path is not absolute, assume it's relative to OIE_HOME
86+
if (-not [System.IO.Path]::IsPathRooted($PathToResolve)) {
87+
$PathToResolve = Join-Path -Path $OieHome -ChildPath $PathToResolve
88+
}
89+
90+
try {
91+
return (Resolve-Path -LiteralPath $PathToResolve).Path
92+
}
93+
catch {
94+
return $PathToResolve
95+
}
96+
}
97+
98+
# --- Function to safely expand specific variable formats in a string ---
99+
function Expand-LineVariables {
100+
param(
101+
[string]$Line
102+
)
103+
$resultBuilder = [System.Text.StringBuilder]::new()
104+
$remainingLine = $Line
105+
106+
# This loop consumes the line from left to right, preventing recursive expansion.
107+
while ($remainingLine -match '\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}') {
108+
# Append the text before the match to our result.
109+
$prefix = $remainingLine.Substring(0, $matches[0].Index)
110+
$resultBuilder.Append($prefix) | Out-Null
111+
112+
# Get the variable name and its value.
113+
$varName = $matches[1]
114+
$varValue = (Get-Variable -Name $varName -Scope "global" -ErrorAction SilentlyContinue).Value
115+
if ($null -eq $varValue) {
116+
$varValue = (Get-Variable -Name "env:$varName" -ErrorAction SilentlyContinue).Value
117+
}
118+
$resultBuilder.Append($varValue) | Out-Null
119+
120+
# Update the line to be only the portion *after* the match.
121+
$remainingLine = $remainingLine.Substring($matches[0].Index + $matches[0].Length)
122+
}
123+
124+
# Append any remaining part of the line after the last match and return.
125+
$resultBuilder.Append($remainingLine) | Out-Null
126+
return $resultBuilder.ToString()
127+
}
128+
129+
# --- Function to validate Java version ---
130+
function Test-IsValidJavaVersion {
131+
param(
132+
[string]$JavaCmd
133+
)
134+
135+
# Check if the command is found and is executable
136+
if (-not (Get-Command $JavaCmd -ErrorAction SilentlyContinue)) {
137+
return $false
138+
}
139+
140+
# Execute 'java -version' and capture the output from stderr
141+
# Example output: openjdk version "17.0.2" 2022-07-19
142+
try {
143+
$versionOutput = & $JavaCmd -version 2>&1
144+
}
145+
catch {
146+
return $false
147+
}
148+
149+
if ($LASTEXITCODE -ne 0) {
150+
return $false
151+
}
152+
153+
# Extract the major version number. This works for formats like "1.8.0" and "17.0.2".
154+
$match = $versionOutput | Select-String -Pattern '"(\d+)\.'
155+
if ($match -and ($match.Matches[0].Groups[1].Value -as [int]) -ge $MinJavaVersion) {
156+
return $true
157+
} else {
158+
return $false
159+
}
160+
}
161+
162+
# --- Function to parse vmoptions file ---
163+
function Parse-VmOptions {
164+
param(
165+
[string]$File
166+
)
167+
168+
if (-not (Test-Path -LiteralPath $File -PathType Leaf)) {
169+
Write-Warning "VM options file not found: $File"
170+
return
171+
}
172+
173+
# Read the file line by line
174+
Get-Content -Path $File | ForEach-Object {
175+
$line = $_.Trim()
176+
177+
# Skip empty lines and comments
178+
if ([string]::IsNullOrWhiteSpace($line) -or $line.StartsWith('#')) {
179+
return
180+
}
181+
182+
$line = Expand-LineVariables -Line $line
183+
184+
if ($line -match '^-include-options\s+(.+)') {
185+
$includedFile = $matches[1].Trim()
186+
# Resolve relative paths to the current file's directory
187+
if (-not [System.IO.Path]::IsPathRooted($includedFile)) {
188+
$includedFile = Join-Path -Path (Split-Path -Path $File -Parent) -ChildPath $includedFile
189+
}
190+
Parse-VmOptions -File $includedFile
191+
}
192+
elseif ($line -match '^-classpath\s+(.+)') {
193+
$script:Classpath = $matches[1].Trim()
194+
}
195+
elseif ($line -match '^-classpath/a\s+(.+)') {
196+
$script:Classpath = "$($script:Classpath)$([System.IO.Path]::PathSeparator)$($matches[1].Trim())"
197+
}
198+
elseif ($line -match '^-classpath/p\s+(.+)') {
199+
$script:Classpath = "$($matches[1].Trim())$([System.IO.Path]::PathSeparator)$($script:Classpath)"
200+
}
201+
elseif ($line -match '^-java-cmd\s+(.+)') {
202+
# Store the path and the file it was found in. Validation is deferred.
203+
$script:VmOptionsJavaCmd = Resolve-CanonicalPath -PathToResolve $matches[1].Trim()
204+
$script:VmOptionsJavaCmdFile = $File
205+
}
206+
else {
207+
$script:VmOptions.Add($line) | Out-Null
208+
}
209+
}
210+
}
211+
212+
# --- Main Logic ---
213+
214+
# 1. Recursively parse the VM options file to populate vmoptions variables.
215+
Parse-VmOptions -File (Join-Path -Path $OieHome -ChildPath "oieserver.vmoptions")
216+
217+
# 2. Ensure the launcher JAR is always in the classpath.
218+
if ($script:Classpath -notmatch [regex]::Escape($LauncherJar)) {
219+
Write-Host "Info: Prepending mirth-server-launcher.jar to the classpath." -ForegroundColor Green
220+
$script:Classpath = "$($LauncherJar)$([System.IO.Path]::PathSeparator)$($script:Classpath)"
221+
}
222+
223+
# 3. Discover the Java executable using the documented priority order.
224+
225+
# Check OIE_JAVA_PATH (fail-fast on invalid).
226+
if (-not [string]::IsNullOrWhiteSpace($env:OIE_JAVA_PATH)) {
227+
$resolvedPath = Resolve-CanonicalPath -PathToResolve $env:OIE_JAVA_PATH
228+
if (Test-IsValidJavaVersion -JavaCmd $resolvedPath) {
229+
Write-Host "Info: Found suitable java version specified by the OIE_JAVA_PATH environment variable" -ForegroundColor Green
230+
$FinalJavaCmd = $resolvedPath
231+
} else {
232+
Write-Error "'$resolvedPath' is specified by the OIE_JAVA_PATH environment variable, which is not a valid Java executable of at least version $MinJavaVersion. Exiting."
233+
exit 1
234+
}
235+
}
236+
237+
# Check -java-cmd from vmoptions (fail-fast on invalid, only if not already found).
238+
if (-not $FinalJavaCmd -and -not [string]::IsNullOrWhiteSpace($script:VmOptionsJavaCmd)) {
239+
if (Test-IsValidJavaVersion -JavaCmd $script:VmOptionsJavaCmd) {
240+
Write-Host "Info: Found suitable java version specified by the -java-cmd directive in '$($script:VmOptionsJavaCmdFile)'" -ForegroundColor Green
241+
$FinalJavaCmd = $script:VmOptionsJavaCmd
242+
} else {
243+
Write-Error "'$($script:VmOptionsJavaCmd)' is specified by the -java-cmd directive in '$($script:VmOptionsJavaCmdFile)', which is not a valid Java executable of at least version $MinJavaVersion. Exiting."
244+
exit 1
245+
}
246+
}
247+
248+
# Check JAVA_HOME (no fail-fast).
249+
if (-not $FinalJavaCmd -and (Test-Path -Path $env:JAVA_HOME -PathType Container)) {
250+
$javaHomePath = Join-Path -Path $env:JAVA_HOME -ChildPath "bin\java"
251+
if (Test-IsValidJavaVersion -JavaCmd $javaHomePath) {
252+
Write-Host "Info: Found suitable java version specified by the JAVA_HOME environment variable" -ForegroundColor Green
253+
$FinalJavaCmd = $javaHomePath
254+
} else {
255+
Write-Warning "'$javaHomePath' is specified by the JAVA_HOME environment variable, which is not a valid Java executable of at least version $MinJavaVersion. Ignoring."
256+
}
257+
}
258+
259+
# Check system PATH (no fail-fast).
260+
if (-not $FinalJavaCmd) {
261+
if (Get-Command "java" -ErrorAction SilentlyContinue) {
262+
if (Test-IsValidJavaVersion -JavaCmd "java") {
263+
Write-Host "Info: Found suitable java version in the PATH" -ForegroundColor Green
264+
$FinalJavaCmd = "java"
265+
} else {
266+
Write-Warning "'java' does not exist in your PATH or is not a valid Java executable of at least version $MinJavaVersion."
267+
}
268+
}
269+
}
270+
271+
# 4. Final check for a valid Java path before execution.
272+
if (-not $FinalJavaCmd) {
273+
Write-Error "Could not find a Java $($MinJavaVersion)+ installation. Please configure -java-cmd in conf/custom.vmoptions, set OIE_JAVA_PATH, set JAVA_HOME, or ensure 'java' in your PATH is version $($MinJavaVersion) or higher."
274+
exit 1
275+
}
276+
277+
# 5. Assemble final arguments and launch the process.
278+
$javaOpts = [System.Collections.Generic.List[string]]::new()
279+
$javaOpts.AddRange($script:VmOptions)
280+
$javaOpts.Add("-cp")
281+
$javaOpts.Add(('"{0}"' -f ($script:Classpath -split "[:;]" -join [System.IO.Path]::PathSeparator)))
282+
$javaOpts.Add("com.mirth.connect.server.launcher.MirthLauncher")
283+
$javaOpts.AddRange($AppArgs)
284+
285+
# Launch Open Integration Engine
286+
Write-Host "Starting Open Integration Engine..." -ForegroundColor Green
287+
Write-Host "$FinalJavaCmd $($javaOpts -join ' ')"
288+
289+
& $FinalJavaCmd $javaOpts
290+
exit $LASTEXITCODE

0 commit comments

Comments
 (0)