diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 151611be6..892893e01 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -26,17 +26,232 @@ git checkout -b feature/your-feature-name ``` ### 5. Install Tooling -OIE specifies the working versions of Java and Ant in [.sdkmanrc](./.sdkmanrc). To take advantage of this, install [SDKMAN](https://sdkman.io/) and run `sdk env install` -in the project's root directory. -### 6. Implement your changes +#### Java Version Requirements + +The current Open Integration Engine has different Java version requirements for **build time** and **runtime**: + +- **Build SDK**: Java 8 (to maintain compatibility with the current codebase) +- **Runtime**: Java 17 or higher (required for server and client execution) + +#### Install Java Versions with SDKMAN + +Install [SDKMAN](https://sdkman.io/) and use it to manage both Java versions: + +```bash +# Install SDKMAN (if not already installed) +curl -s "https://get.sdkman.io" | bash +source "$HOME/.sdkman/candidates/java/current/bin/java" + +# Install Java 8 for building +sdk install java 8.0.442.fx-zulu + +# Install Java 17 with JavaFX for runtime (required for client GUI) +sdk install java 17.0.17.fx-zulu + +# Install Apache Ant +sdk install ant 1.10.14 +``` + +**Set build-time Java:** +```bash +sdk use java 8.0.442.fx-zulu +``` + +**Verify versions:** +```bash +java -version # Should show Java 8 +ant -version # Should show Ant 1.10.14 +``` + +> **Important:** After building with Java 8, you'll need Java 17+ with JavaFX (`17.0.17.fx-zulu` or higher) to run the server and client. The runtime Java is specified in `conf/custom.vmoptions` for the server and `oieclient.vmoptions` for the client. + +### 6. How To Build + +The project uses **Apache Ant** as the build system. All build orchestration is managed from the `server` directory. + +#### 6.1 Build Commands + +**Full Build (Development)** +```bash +cd server +ant -f mirth-build.xml -DdisableSigning=true +``` + +> **Note:** This build takes approximately 2 minutes 20 seconds on a MacBook Pro M4 Pro. + +This will: +- Build Donkey (message processing engine) +- Build Server extensions +- Build Client +- Build Manager +- Build CLI (Command Line Interface) +- Run all tests +- Create the complete setup in `server/setup/` + +**Fast Build (Skip Tests)** +```bash +cd server +ant -f mirth-build.xml -DdisableSigning=true -DdisableTests=true +``` + +> **Note:** This build takes approximately 10-11 seconds on a MacBook Pro M4 Pro. + +Use this for faster builds during development when you don't need to run the full test suite. + +**Full Build (Signed - for releases)** +```bash +cd server +ant -f mirth-build.xml +``` + +**Create Distribution Package** +```bash +cd server +ant -f mirth-build.xml dist +``` + +### 7. How To Run + +After building, the complete application is available in `server/setup/`. + +#### Running the Server + +The server is the core integration engine that processes messages and manages channels: + +```bash +cd server/setup +./oieserver +``` + +You should see output similar to this: + +```bash +Info: Found suitable java version specified by the -java-cmd directive in '/Users/michel/Developer/misc/engine/server/setup/conf/custom.vmoptions' +Starting Open Integration Engine... +INFO 2025-11-10 09:49:41.028 [Main Server Thread] com.mirth.connect.server.Mirth: Open Integration Engine 4.5.2 (Built on novembre 10, 2025) server successfully started. +INFO 2025-11-10 09:49:41.030 [Main Server Thread] com.mirth.connect.server.Mirth: This product was developed by NextGen Healthcare (https://www.nextgen.com) and its contributors (c)2005-2024. +INFO 2025-11-10 09:49:41.030 [Main Server Thread] com.mirth.connect.server.Mirth: Open Integration Engine contributors (c)2025. +INFO 2025-11-10 09:49:41.030 [Main Server Thread] com.mirth.connect.server.Mirth: Running OpenJDK 64-Bit Server VM 17.0.17 on Mac OS X (15.6.1, aarch64), derby, with charset UTF-8. +INFO 2025-11-10 09:49:41.031 [Main Server Thread] com.mirth.connect.server.Mirth: Web server running at http://192.168.1.16:8080/ and https://192.168.1.16:8443/ +``` + +By default, the server requires Java 17 or higher. The runtime is configured via `conf/custom.vmoptions`. + +**Server VM Options:** +- `oieserver.vmoptions` - Main configuration file (includes other files) +- `conf/base_includes.vmoptions` - Base JVM settings +- `conf/default_modules.vmoptions` - Java 9+ module exports/opens +- `conf/custom.vmoptions` - User customizations (add your `-java-cmd` here) + +#### Running the Client + +The Administrator client is the GUI for managing the integration engine: + +```bash +cd server/setup +./oieclient +``` + +You should see output similar to this: + +```bash +Info: Found suitable java version specified by the -java-cmd directive in '/Users/michel/Developer/misc/engine/server/setup/oieclient.vmoptions' +Starting Open Integration Engine Administrator Client... +``` +After loadingm the client, you will see the login screen: +![Open Integration Engine login screen](login_screen.png) + +After logging in (default username/password: `admin/admin`), you will see the main dashboard: +![Open Integration Engine dashboard fresh install](dashboard_fresh_install.png) + +You can view the About window from the Help menu: +![Open Integration Engine About window](about_window.png) + + +**Note:** The client was previously launched via Java Web Start (`.jnlp` files), which was deprecated in Java 9 and removed in Java 11. The `oieclient` script replaces this mechanism, avoiding the need for third-party tools like OpenWebStart while providing better control over the Java runtime and JVM options. + +The client requires Java 17+ with JavaFX support to run the GUI. The runtime is configured via `oieclient.vmoptions`. + +**Client VM Options:** +- `oieclient.vmoptions` - Configuration file (add your `-java-cmd` and JVM options here) + +**Note:** Both scripts automatically discover Java in this priority order: +1. `OIE_JAVA_PATH` environment variable (override) +2. `-java-cmd` directive in respective `.vmoptions` file (preferred) +3. `JAVA_HOME` environment variable +4. `java` command in system PATH + +#### Packaging + +After building, you can create a distribution tarball: + +**On Linux (with GNU tar):** +```bash +tar czf openintegrationengine.tar.gz -C server/ setup --transform 's|^setup|openintegrationengine/|' +``` + +**On macOS (BSD tar - no --transform support):** +```bash +cd server +tar czf ../openintegrationengine.tar.gz setup +``` + +Or, to rename the directory in the tarball: +```bash +cd server +cp -r setup openintegrationengine +tar czf ../openintegrationengine.tar.gz openintegrationengine +rm -rf openintegrationengine +``` + +Alternatively, install GNU tar on macOS: +```bash +brew install gnu-tar +gtar czf openintegrationengine.tar.gz -C server/ setup --transform 's|^setup|openintegrationengine/|' +``` + +#### Build Individual Components + +If needed, you can build specific components separately: + +```bash +# Build Donkey only +cd donkey +ant build + +# Build Server only +cd server +ant compile + +# Build Client only +cd client +ant -f ant-build.xml build + +# Build CLI only +cd command +ant build + +# Build Manager only +cd manager +ant -f ant-build.xml build +``` + +#### Build Output + +After a successful build, you'll find: +- **`server/setup/`** - Complete application setup ready to run +- **`server/build/`** - Build artifacts +- **`server/dist/`** - Distribution packages (if you ran the `dist` target) + +### 8. Implement your changes Implement the necessary changes, ensuring they align with the project’s coding standards and practices. -### 7. Test Your Changes +### 9. Test Your Changes Before submitting your changes, please ensure that all tests pass and that your changes work as expected in your local environment. -### 8. Submit a Pull Request +### 10. Submit a Pull Request Once your changes are ready, push them to your fork and create a **draft pull request (PR)** from your branch to the `main` branch of the project. Draft PRs help indicate that the work is in progress. Mark the PR as **"Ready for review"** only when it is actually complete and ready for feedback. Include a brief description of the changes and reference the related issue. diff --git a/about_window.png b/about_window.png new file mode 100644 index 000000000..9a3194b28 Binary files /dev/null and b/about_window.png differ diff --git a/dashboard_fresh_install.png b/dashboard_fresh_install.png new file mode 100644 index 000000000..984ff0aa5 Binary files /dev/null and b/dashboard_fresh_install.png differ diff --git a/login_screen.png b/login_screen.png new file mode 100644 index 000000000..49e387009 Binary files /dev/null and b/login_screen.png differ diff --git a/server/basedir-includes/oieclient b/server/basedir-includes/oieclient new file mode 100644 index 000000000..560d3a9a2 --- /dev/null +++ b/server/basedir-includes/oieclient @@ -0,0 +1,296 @@ +#!/usr/bin/env bash +# +# SPDX-License-Identifier: MPL-2.0 +# SPDX-FileCopyrightText: 2025 Tony Germano and Mitch Gaffigan +# + +# ============================================================================= +# Open Integration Engine Client Launcher Script +# +# Description: +# This script is the launcher for the Open Integration Engine (OIE) +# Administrator client GUI. It prepares the Java environment and executes +# the client application. +# +# 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 oieclient.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 client 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 'oieclient.vmoptions' file to configure JVM options, +# system properties (-D...), and classpath modifications. +# +# Usage: +# ./oieclient [app-arguments] +# +# All [app-arguments] are passed directly to the underlying Java application +# (com.mirth.connect.client.ui.Mirth). +# +# 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 client 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 + +# Build the client classpath +CLASSPATH="$OIE_HOME/client-lib/mirth-client.jar" + +# Add all client-lib JARs to classpath +for jar in "$OIE_HOME/client-lib"/*.jar; do + if [[ -f "$jar" ]] && [[ "$jar" != *"mirth-client.jar" ]]; then + CLASSPATH="$CLASSPATH:$jar" + fi +done + +# Add extension JARs to classpath +for extension_dir in "$OIE_HOME/extensions"/*; do + if [[ -d "$extension_dir" ]]; then + for jar in "$extension_dir"/*.jar; do + if [[ -f "$jar" ]]; then + CLASSPATH="$CLASSPATH:$jar" + fi + done + fi +done + +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 [[ -n "${!var_name+x}" ]]; 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 (if exists). +if [[ -f "$OIE_HOME/oieclient.vmoptions" ]]; then + parse_vmoptions "$OIE_HOME/oieclient.vmoptions" +fi + +# 2. 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 + +# 3. 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 create oieclient.vmoptions with -java-cmd, set OIE_JAVA_PATH, set JAVA_HOME, or ensure 'java' in your PATH is version ${MIN_JAVA_VERSION} or higher." >&2 + exit 1 +fi + +# Build JVM options with necessary module exports for macOS and reflection access +JAVA_OPTS=( + "--add-exports=java.desktop/com.apple.eawt=ALL-UNNAMED" + "--add-exports=java.desktop/com.apple.eio=ALL-UNNAMED" + "--add-opens=java.base/java.util=ALL-UNNAMED" + "${VMOPTIONS[@]}" + "-cp" "$CLASSPATH" + "com.mirth.connect.client.ui.Mirth" + "${APP_ARGS[@]}" +) + +# Launch Open Integration Engine Administrator Client +echo "Starting Open Integration Engine Administrator Client..." +exec "$FINAL_JAVA_CMD" "${JAVA_OPTS[@]}" diff --git a/server/basedir-includes/oieclient.vmoptions b/server/basedir-includes/oieclient.vmoptions new file mode 100644 index 000000000..94757350e --- /dev/null +++ b/server/basedir-includes/oieclient.vmoptions @@ -0,0 +1,36 @@ +# Open Integration Engine Client VM Options +# +# This file allows you to specify JVM options for the OIE Administrator Client. +# +# Directives: +# -java-cmd - Specify the Java executable to use (preferred method) +# -include-options - Include another vmoptions file +# -classpath - Replace the default classpath +# -classpath/a - Append to the classpath +# -classpath/p - Prepend to the classpath +# +# Standard JVM options (memory, GC, debugging, etc.) can be specified directly. +# +# Example: Specify Java version +# -java-cmd /usr/lib/jvm/java-21-openjdk/bin/java +# +# Example: Increase maximum heap memory +# -Xmx1024m +# +# Example: Enable remote debugging +# -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=*:5005 + +# Use Java 17+ with JavaFX for the client GUI +# This matches the runtime requirement (Java 17.0.17.fx-zulu) +# Specify the Java command to use (optional) +# If not specified, the script will attempt to find Java automatically +-java-cmd ${HOME}/.sdkman/candidates/java/17.0.17.fx-zulu/bin/java + +# Default memory settings (can be overridden below) +-Xms128m +-Xmx512m + +# Disable JavaFX hardware acceleration (fixes QuantumRenderer errors) +# The client uses Swing, not JavaFX for the main UI +-Dprism.order=sw +-Dprism.verbose=false diff --git a/server/basedir-includes/oieserver b/server/basedir-includes/oieserver index e8f7b6374..e76a46e91 100755 --- a/server/basedir-includes/oieserver +++ b/server/basedir-includes/oieserver @@ -277,5 +277,4 @@ JAVA_OPTS=("${VMOPTIONS[@]}" # 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[@]}" diff --git a/server/build.xml b/server/build.xml index 6fb6f316d..1a1e5913a 100644 --- a/server/build.xml +++ b/server/build.xml @@ -1007,8 +1007,9 @@ - + + diff --git a/server/conf/custom.vmoptions b/server/conf/custom.vmoptions index ab1f51fc0..8773a913e 100644 --- a/server/conf/custom.vmoptions +++ b/server/conf/custom.vmoptions @@ -22,3 +22,7 @@ # # Any lines which do not match the special directives above will be passed through directly as # arguments to the java binary. + +# Use the Java version specified in .sdkmanrc (located in project root) +# This ensures server runtime matches the build environment +-java-cmd ${HOME}/.sdkman/candidates/java/17.0.17.fx-zulu/bin/java