Skip to content

Add oieserver launcher script #119

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 9 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
281 changes: 281 additions & 0 deletions server/basedir-includes/oieserver
Original file line number Diff line number Diff line change
@@ -0,0 +1,281 @@
#!/usr/bin/env bash
#
# SPDX-License-Identifier: MPL-2.0
# SPDX-FileCopyrightText: 2025 Tony Germano and Mitch Gaffigan
#

# =============================================================================
# Open Integration Engine Server Launcher Script
#
# Description:
# This script is the main launcher for the Open Integration Engine (OIE)
# server. It prepares the Java environment and executes the server launcher
# JAR file.
#
# The script automatically finds a compatible Java runtime (version 17+ by
# default) by searching for a valid executable in the following priority order:
# 1. The OIE_JAVA_PATH environment variable.
# 2. The -java-cmd directive in the oieserver.vmoptions file or included
# .vmoptions files. Must specify the path to the 'java' executable.
# This is the preferred way to declare the desired version for running
# the server and can be overridden by OIE_JAVA_PATH. Can be a relative
# path from the location of this script.
# 3. The JAVA_HOME environment variable.
# 4. The 'java' command available in the system's PATH.
#
# It also parses the 'oieserver.vmoptions' file to configure JVM options,
# system properties (-D...), and classpath modifications.
#
# Usage:
# ./oieserver.sh [app-arguments]
#
# All [app-arguments] are passed directly to the underlying Java application
# (com.mirth.connect.server.launcher.MirthLauncher).
#
# Configuration via Environment Variables:
# OIE_JAVA_PATH - (Highest priority) Set the full path to the 'java'
# executable to be used. Can be a relative path from the
# location of this script or a tilde path
# (e.g., ~/path/to/java).
# JAVA_HOME - Set the path to the root of a Java installation. The
# script will look for 'bin/java' within this path.
# =============================================================================

APP_ARGS=("$@")
MIN_JAVA_VERSION=17

# Set OIE_HOME to the script directory
OIE_HOME="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
# The engine expects it's working directory to be OIE_HOME
if ! cd "$OIE_HOME"; then
echo "Error: Could not change to the OIE_HOME directory: $OIE_HOME" >&2
exit 1
fi
LAUNCHER_JAR="$OIE_HOME/mirth-server-launcher.jar"
CLASSPATH="$LAUNCHER_JAR"
VMOPTIONS=()
# This will hold the validated path to the Java executable. It is intentionally left empty for now.
FINAL_JAVA_CMD=""
# This will temporarily hold the result from parsing the vmoptions file.
VMOPTIONS_JAVA_CMD=""
VMOPTIONS_JAVA_CMD_FILE=""


# --- Function to resolve a path to a canonical absolute path ---
# Resolves a given path, handling tilde, relative, and '..' components.
# @param $1: The path to resolve.
# @echo: The resolved, canonical absolute path.
resolve_canonical_path() {
local path_to_resolve="$1"

# Explicitly handle tilde expansion first
path_to_resolve=$(sed -E "s,^~(/|$),${HOME}\1," <<< "$path_to_resolve")

# If the path is not absolute, assume it's relative to OIE_HOME
if [[ ! "$path_to_resolve" =~ ^/ ]]; then
path_to_resolve="$OIE_HOME/$path_to_resolve"
fi

# Use cd and pwd to resolve '..' and '.' components for a canonical path.
if [[ -d "$(dirname "$path_to_resolve")" ]]; then
echo "$(cd "$(dirname "$path_to_resolve")" && pwd)/$(basename "$path_to_resolve")"
else
echo "$path_to_resolve"
fi
}

# --- Function to expand environment variable in a string ---
# @param $1: The line to expand
# @echo: The expanded line
expand_line_variables() {
local line="$1"
local result_line=""

# This loop consumes the line from left to right, preventing recursive expansion.
while [[ "$line" =~ (\$\{([a-zA-Z_][a-zA-Z0-9_]*)\}) ]]; do
# Append the text before the match to our result.
result_line+="${line%%"${BASH_REMATCH[0]}"*}"

# Get the variable name and its value.
local var_name="${BASH_REMATCH[2]}"
# Use indirect expansion to get the variable's value. Do not replace if not set.
if [[ -v "$var_name" ]]; then
local var_value="${!var_name}"
result_line+="$var_value"
else
result_line+="${BASH_REMATCH[0]}"
fi

# Update the line to be only the portion *after* the match.
line="${line#*"${BASH_REMATCH[0]}"}"
done

# Append any remaining part of the line after the last match and return.
echo "$result_line$line"
}

# --- Function to validate Java version ---
# Checks if a given command points to a Java executable of the required minimum version.
# @param $1: The java command or path to check
# @return: 0 on success (is valid), 1 on failure.
is_valid_java_version() {
local java_cmd="$1"

# Check if the command is found and is executable
if ! command -v "$java_cmd" &> /dev/null || ! [[ -x "$(command -v "$java_cmd")" ]]; then
return 1
fi

# Execute 'java -version' and capture the output from stderr
# Example output: openjdk version "17.0.2" 2022-07-19
local version_output
version_output=$("$java_cmd" -version 2>&1)

# Check if the version command succeeded
if [[ $? -ne 0 ]]; then
return 1
fi

# Extract the major version number. This works for formats like "1.8.0" and "17.0.2".
local major_version
major_version=$(echo "$version_output" | head -n 1 | cut -d '"' -f 2 | cut -d '.' -f 1)

# Check if the extracted version is a number and meets the minimum requirement
if [[ "$major_version" =~ ^[0-9]+$ ]] && [[ "$major_version" -ge "$MIN_JAVA_VERSION" ]]; then
return 0 # Success
else
return 1 # Failure
fi
}

# Set Java options by parsing the vmoptions file
parse_vmoptions() {
local file="$1"

if [[ ! -f "$file" ]]; then
echo "Warning: VM options file not found: $file" >&2
return 1
fi

# Read the file line by line
while IFS= read -r line; do
# Trim leading/trailing whitespace
line=$(echo "$line" | sed 's/^[[:space:]]*//;s/[[:space:]]*$//')

# Skip empty lines and comments
if [[ -z "$line" || "$line" =~ ^# ]]; then
continue
fi

line=$(expand_line_variables "$line")

# Check for -include-options directive
if [[ "$line" =~ ^-include-options[[:space:]]+(.+) ]]; then
local included_file="${BASH_REMATCH[1]}"
# Resolve relative paths
if [[ ! "$included_file" =~ ^/ ]]; then # Not an absolute path
included_file="$(dirname "$file")/$included_file"
fi
# Recursively call parse_vmoptions for the included file
parse_vmoptions "$included_file"
elif [[ "$line" =~ ^-classpath[[:space:]]+(.+) ]]; then
# Handle -classpath directive
CLASSPATH="${BASH_REMATCH[1]}"
elif [[ "$line" =~ ^-classpath/a[[:space:]]+(.+) ]]; then
# Handle -classpath/a directive (append to existing classpath)
CLASSPATH="${CLASSPATH}:${BASH_REMATCH[1]}"
elif [[ "$line" =~ ^-classpath/p[[:space:]]+(.+) ]]; then
# Handle -classpath/p directive (prepend to existing classpath)
CLASSPATH="${BASH_REMATCH[1]}:${CLASSPATH}"
elif [[ "$line" =~ ^-java-cmd[[:space:]]+(.+) ]]; then
# Handle -java-cmd directive
# Store the path and the file it was found in. Validation is deferred.
VMOPTIONS_JAVA_CMD=$(resolve_canonical_path "${BASH_REMATCH[1]}")
VMOPTIONS_JAVA_CMD_FILE="$file"
else
# Add the option to the accumulated string
VMOPTIONS+=("$line")
fi
done < "$file"
return 0
}

# --- Main Logic ---

# 1. Recursively parse the VM options file to populate vmoptions variables.
parse_vmoptions "$OIE_HOME/oieserver.vmoptions"

# 2. Ensure the launcher JAR is always in the classpath.
case "$CLASSPATH" in
*"$LAUNCHER_JAR"*)
# It's already there, do nothing.
;;
*)
# Prepend the launcher JAR if a custom classpath was provided.
echo "Info: Prepending mirth-server-launcher.jar to the classpath."
CLASSPATH="$LAUNCHER_JAR:$CLASSPATH"
;;
esac

# 3. Discover the Java executable using the documented priority order.

# Check OIE_JAVA_PATH (fail-fast on invalid).
if [[ -n "$OIE_JAVA_PATH" ]]; then
resolved_path=$(resolve_canonical_path "$OIE_JAVA_PATH")
if is_valid_java_version "$resolved_path"; then
echo "Info: Found suitable java version specified by the OIE_JAVA_PATH environment variable"
FINAL_JAVA_CMD="$resolved_path"
else
echo "Error: '$resolved_path' is specified by the OIE_JAVA_PATH environment variable, which is not a valid Java executable of at least version $MIN_JAVA_VERSION. Exiting." >&2
exit 1
fi
fi

# Check -java-cmd from vmoptions (fail-fast on invalid, only if not already found).
if [[ -z "$FINAL_JAVA_CMD" ]] && [[ -n "$VMOPTIONS_JAVA_CMD" ]]; then
if is_valid_java_version "$VMOPTIONS_JAVA_CMD"; then
echo "Info: Found suitable java version specified by the -java-cmd directive in '$VMOPTIONS_JAVA_CMD_FILE'"
FINAL_JAVA_CMD="$VMOPTIONS_JAVA_CMD"
else
echo "Error: '$VMOPTIONS_JAVA_CMD' is specified by the -java-cmd directive in '$VMOPTIONS_JAVA_CMD_FILE', which is not a valid Java executable of at least version $MIN_JAVA_VERSION. Exiting." >&2
exit 1
fi
fi

# Check JAVA_HOME (no fail-fast).
if [[ -z "$FINAL_JAVA_CMD" ]] && [[ -d "$JAVA_HOME" ]]; then
java_home_path="$JAVA_HOME/bin/java"
if is_valid_java_version "$java_home_path"; then
echo "Info: Found suitable java version specified by the JAVA_HOME environment variable"
FINAL_JAVA_CMD="$java_home_path"
else
echo "Warning: '$java_home_path' is specified by the JAVA_HOME environment variable, which is not a valid Java executable of at least version $MIN_JAVA_VERSION. Ignoring." >&2
fi
fi

# Check system PATH (no fail-fast).
if [[ -z "$FINAL_JAVA_CMD" ]]; then
if is_valid_java_version "java"; then
echo "Info: Found suitable java version in the PATH"
FINAL_JAVA_CMD="java"
else
echo "Warning: 'java' does not exist in your PATH or is not a valid Java executable of at least version $MIN_JAVA_VERSION." >&2
fi
fi

# 4. Final check for a valid Java path before execution.
if [[ -z "$FINAL_JAVA_CMD" ]]; then
echo "Error: Could not find a Java ${MIN_JAVA_VERSION}+ installation." >&2
echo "Please configure -java-cmd in conf/custom.vmoptions, set OIE_JAVA_PATH, set JAVA_HOME, or ensure 'java' in your PATH is version ${MIN_JAVA_VERSION} or higher." >&2
exit 1
fi

JAVA_OPTS=("${VMOPTIONS[@]}"
"-cp" "$CLASSPATH"
"com.mirth.connect.server.launcher.MirthLauncher"
"${APP_ARGS[@]}")

# Launch Open Integration Engine (as this PID with exec)
echo "Starting Open Integration Engine..."
echo "$FINAL_JAVA_CMD ${JAVA_OPTS[*]}"
exec "$FINAL_JAVA_CMD" "${JAVA_OPTS[@]}"
Loading