#!/bin/sh # ============================================================================== # j3270 Setup Script (POSIX Shell) # Detects Java 11+ JDK and builds j3270 standalone executable JAR. # # Usage: # ./setup.sh [options] [-- run-arguments] # # Options: # -r, --run Launch j3270 immediately after successful build # -t, --test Run test suite after build # -c, --clean Clean build directory before compiling # -h, --help Show this help message # ============================================================================== set -e # Resolve directory of this script SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)" cd "$SCRIPT_DIR" # ANSI color codes (if output is to an interactive terminal) if [ -t 1 ]; then BOLD="\033[1m" GREEN="\033[1;32m" YELLOW="\033[1;33m" CYAN="\033[1;36m" RED="\033[1;31m" RESET="\033[0m" else BOLD="" GREEN="" YELLOW="" CYAN="" RED="" RESET="" fi log_info() { printf "%b[INFO]%b %s\n" "$CYAN" "$RESET" "$*"; } log_success() { printf "%b[OK]%b %s\n" "$GREEN" "$RESET" "$*"; } log_warn() { printf "%b[WARN]%b %s\n" "$YELLOW" "$RESET" "$*"; } log_error() { printf "%b[ERROR]%b %s\n" "$RED" "$RESET" "$*"; } show_help() { cat << EOF j3270 Terminal Emulator - Setup and Build Script Usage: ./setup.sh [options] [-- run-arguments] Options: -r, --run Build and immediately launch j3270 -t, --test Run automated unit tests after build -c, --clean Remove previous build artifacts before building -h, --help Show this help message Examples: ./setup.sh ./setup.sh --clean ./setup.sh --run ./setup.sh --run -- mainframe.example.com 23 4 ./setup.sh --test EOF } # Parse command line flags DO_RUN=0 DO_TEST=0 DO_CLEAN=0 RUN_ARGS="" while [ $# -gt 0 ]; do case "$1" in -r|--run) DO_RUN=1 shift ;; -t|--test) DO_TEST=1 shift ;; -c|--clean) DO_CLEAN=1 shift ;; -h|--help) show_help exit 0 ;; --) shift RUN_ARGS="$*" break ;; *) RUN_ARGS="$*" break ;; esac done printf "\n%b=== j3270 Setup & Build ===%b\n\n" "$BOLD" "$RESET" # ------------------------------------------------------------------------------ # 1. Java Version & JDK Toolchain Detection # ------------------------------------------------------------------------------ # Extracts the integer major version from a javac or java version string # Examples: "javac 11.0.19" -> 11, "javac 17.0.2" -> 17, "javac 1.8.0_292" -> 8 parse_major_version() { raw_str="$1" ver_token=$(echo "$raw_str" | sed -n \ -e 's/.*javac *\([0-9][0-9._]*\).*/\1/p' \ -e 's/.*version *"\([0-9][0-9._]*\)".*/\1/p' \ -e 's/.*version *\([0-9][0-9._]*\).*/\1/p' | head -n 1) if [ -n "$ver_token" ]; then echo "$ver_token" | sed -e 's/^1\.//' -e 's/[^0-9].*//' fi } # Checks if a given directory contains a valid JDK >= 11 # Sets JAVAC_BIN, JAR_BIN, JAVA_BIN, JAVA_VERSION if valid test_jdk_candidate() { cand_home="$1" cand_javac="" cand_jar="" cand_java="" if [ -n "$cand_home" ] && [ -d "$cand_home" ]; then if [ -x "$cand_home/bin/javac" ]; then cand_javac="$cand_home/bin/javac"; fi if [ -x "$cand_home/bin/jar" ]; then cand_jar="$cand_home/bin/jar"; fi if [ -x "$cand_home/bin/java" ]; then cand_java="$cand_home/bin/java"; fi fi if [ -z "$cand_javac" ] || [ -z "$cand_jar" ] || [ -z "$cand_java" ]; then return 1 fi # Verify that javac actually executes successfully if ! "$cand_javac" -version >/dev/null 2>&1; then return 1 fi raw_ver=$("$cand_javac" -version 2>&1) major_num=$(parse_major_version "$raw_ver") if [ -n "$major_num" ] && [ "$major_num" -ge 11 ] 2>/dev/null; then JAVAC_BIN="$cand_javac" JAR_BIN="$cand_jar" JAVA_BIN="$cand_java" JAVA_VERSION="$raw_ver" DETECTED_JAVA_HOME="$cand_home" return 0 fi return 1 } JAVAC_BIN="" JAR_BIN="" JAVA_BIN="" JAVA_VERSION="" DETECTED_JAVA_HOME="" log_info "Searching for a compatible Java Development Kit (JDK 11+)..." # Strategy A: Check user-specified JAVA_HOME if [ -n "$JAVA_HOME" ]; then if test_jdk_candidate "$JAVA_HOME"; then log_info "Found valid JDK in \$JAVA_HOME" fi fi # Strategy B: Check current PATH commands (handling potential macOS /usr/bin stubs) if [ -z "$JAVAC_BIN" ] && command -v javac >/dev/null 2>&1 && command -v jar >/dev/null 2>&1 && command -v java >/dev/null 2>&1; then if javac -version >/dev/null 2>&1; then raw_ver=$(javac -version 2>&1) major_num=$(parse_major_version "$raw_ver") if [ -n "$major_num" ] && [ "$major_num" -ge 11 ] 2>/dev/null; then JAVAC_BIN="$(command -v javac)" JAR_BIN="$(command -v jar)" JAVA_BIN="$(command -v java)" JAVA_VERSION="$raw_ver" log_info "Found valid JDK on system PATH" fi fi fi # Strategy C: macOS java_home utility if [ -z "$JAVAC_BIN" ] && [ -x /usr/libexec/java_home ]; then for v in 11 17 21 24 ""; do if [ -n "$v" ]; then mhome="$(/usr/libexec/java_home -v "$v+" 2>/dev/null || true)" else mhome="$(/usr/libexec/java_home 2>/dev/null || true)" fi if [ -n "$mhome" ] && test_jdk_candidate "$mhome"; then log_info "Found macOS JDK via /usr/libexec/java_home: $mhome" break fi done fi # Strategy D: Check standard package manager & OS installation directories if [ -z "$JAVAC_BIN" ]; then candidate_paths=" /opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home /opt/homebrew/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home /opt/homebrew/opt/openjdk@11/libexec/openjdk.jdk/Contents/Home /opt/homebrew/opt/openjdk /opt/homebrew/opt/openjdk@21 /opt/homebrew/opt/openjdk@17 /opt/homebrew/opt/openjdk@11 /usr/local/opt/openjdk/libexec/openjdk.jdk/Contents/Home /usr/local/opt/openjdk@21/libexec/openjdk.jdk/Contents/Home /usr/local/opt/openjdk@17/libexec/openjdk.jdk/Contents/Home /usr/local/opt/openjdk@11/libexec/openjdk.jdk/Contents/Home /usr/local/opt/openjdk /Library/Java/JavaVirtualMachines/*/Contents/Home $HOME/Library/Java/JavaVirtualMachines/*/Contents/Home /usr/lib/jvm/default-java /usr/lib/jvm/java-21-openjdk* /usr/lib/jvm/java-17-openjdk* /usr/lib/jvm/java-11-openjdk* /usr/lib/jvm/temurin-21* /usr/lib/jvm/temurin-17* /usr/lib/jvm/temurin-11* /usr/lib/jvm/semeru-21* /usr/lib/jvm/semeru-17* /usr/lib/jvm/semeru-11* /usr/lib/jvm/zulu-21* /usr/lib/jvm/zulu-17* /usr/lib/jvm/zulu-11* /usr/lib/jvm/* /usr/java/* /usr/local/openjdk21 /usr/local/openjdk17 /usr/local/openjdk11 /usr/local/openjdk* $HOME/.sdkman/candidates/java/current $HOME/.sdkman/candidates/java/* $HOME/.asdf/installs/java/* $HOME/.jenv/versions/* " for cand in $candidate_paths; do if [ -d "$cand" ] && test_jdk_candidate "$cand"; then log_info "Found compatible JDK at: $cand" break fi done fi # If no compatible JDK is found, provide OS-tailored installation help if [ -z "$JAVAC_BIN" ] || [ -z "$JAR_BIN" ] || [ -z "$JAVA_BIN" ]; then log_error "No compatible Java Development Kit (JDK 11+) was found on your system." printf "\n" printf "j3270 requires a Java Development Kit (JDK) version 11 or higher (LTS 11, 17, or 21).\n" printf "Note: A JRE (runtime only) is not sufficient; the compiler (javac) and archiver (jar) are required.\n\n" printf "%bTo install JDK 11+ on your system:%b\n\n" "$BOLD" "$RESET" UNAME_S="$(uname -s 2>/dev/null || echo "Unknown")" case "$UNAME_S" in Darwin) printf " • Using Homebrew:\n" printf " brew install openjdk@17\n" printf " sudo ln -sfn /opt/homebrew/opt/openjdk@17/libexec/openjdk.jdk /Library/Java/JavaVirtualMachines/openjdk-17.jdk\n\n" printf " • Or download Eclipse Temurin (Adoptium PKG installer):\n" printf " https://adoptium.net\n\n" ;; Linux) if command -v apt-get >/dev/null 2>&1; then printf " • Debian / Ubuntu / Linux Mint:\n" printf " sudo apt update && sudo apt install -y openjdk-17-jdk\n\n" elif command -v dnf >/dev/null 2>&1; then printf " • Fedora / RHEL / CentOS / Rocky / AlmaLinux:\n" printf " sudo dnf install -y java-17-openjdk-devel\n\n" elif command -v pacman >/dev/null 2>&1; then printf " • Arch Linux / Manjaro:\n" printf " sudo pacman -S jdk17-openjdk\n\n" elif command -v apk >/dev/null 2>&1; then printf " • Alpine Linux:\n" printf " sudo apk add openjdk17\n\n" elif command -v zypper >/dev/null 2>&1; then printf " • openSUSE:\n" printf " sudo zypper install -y java-17-openjdk-devel\n\n" else printf " • Install JDK 17 via your system package manager or SDKMAN:\n" printf " curl -s \"https://get.sdkman.io\" | bash\n" printf " sdk install java 17.0.10-tem\n\n" fi ;; FreeBSD|OpenBSD|NetBSD) printf " • BSD package manager:\n" printf " pkg install openjdk17\n\n" ;; *) printf " • Download Eclipse Temurin JDK:\n" printf " https://adoptium.net\n\n" ;; esac printf "After installing, re-run ./setup.sh\n\n" exit 1 fi if [ -n "$DETECTED_JAVA_HOME" ]; then export JAVA_HOME="$DETECTED_JAVA_HOME" fi log_success "JDK verified: $JAVA_VERSION" log_info "Java compiler: $JAVAC_BIN" log_info "JAR packager: $JAR_BIN" log_info "Java runtime: $JAVA_BIN" if [ -n "$JAVA_HOME" ]; then log_info "JAVA_HOME: $JAVA_HOME" fi printf "\n" # ------------------------------------------------------------------------------ # 2. Preparation & Clean # ------------------------------------------------------------------------------ BUILD_DIR="$SCRIPT_DIR/build" if [ "$DO_CLEAN" -eq 1 ]; then log_info "Cleaning build directory ($BUILD_DIR)..." rm -rf "$BUILD_DIR/lib3270j" "$BUILD_DIR/j3270" "$BUILD_DIR/MANIFEST.MF" "$BUILD_DIR/j3270.jar" fi mkdir -p "$BUILD_DIR/lib3270j" "$BUILD_DIR/j3270" # ------------------------------------------------------------------------------ # 3. Compile Core Protocol Engine (lib3270j) # ------------------------------------------------------------------------------ log_info "Compiling lib3270j core engine..." find "$SCRIPT_DIR/lib3270j/src/main/java" -name "*.java" | sed 's/^/"/;s/$/"/' > "$BUILD_DIR/lib_sources.txt" if [ ! -s "$BUILD_DIR/lib_sources.txt" ]; then log_error "No source files found in lib3270j/src/main/java" exit 1 fi "$JAVAC_BIN" -d "$BUILD_DIR/lib3270j" @"$BUILD_DIR/lib_sources.txt" rm -f "$BUILD_DIR/lib_sources.txt" log_success "lib3270j compiled successfully." # ------------------------------------------------------------------------------ # 4. Compile Desktop Application (j3270) # ------------------------------------------------------------------------------ log_info "Compiling j3270 terminal emulator..." find "$SCRIPT_DIR/j3270/src/main/java" -name "*.java" | sed 's/^/"/;s/$/"/' > "$BUILD_DIR/app_sources.txt" if [ ! -s "$BUILD_DIR/app_sources.txt" ]; then log_error "No source files found in j3270/src/main/java" exit 1 fi "$JAVAC_BIN" -cp "$BUILD_DIR/lib3270j" -d "$BUILD_DIR/j3270" @"$BUILD_DIR/app_sources.txt" rm -f "$BUILD_DIR/app_sources.txt" log_success "j3270 application compiled successfully." # Copy any resources if present if [ -d "$SCRIPT_DIR/j3270/src/main/resources" ]; then cp -r "$SCRIPT_DIR/j3270/src/main/resources/"* "$BUILD_DIR/j3270/" 2>/dev/null || true fi if [ -d "$SCRIPT_DIR/lib3270j/src/main/resources" ]; then cp -r "$SCRIPT_DIR/lib3270j/src/main/resources/"* "$BUILD_DIR/lib3270j/" 2>/dev/null || true fi # ------------------------------------------------------------------------------ # 5. Package Standalone Executable JAR # ------------------------------------------------------------------------------ log_info "Packaging standalone executable JAR..." cat << 'EOF' > "$BUILD_DIR/MANIFEST.MF" Manifest-Version: 1.0 Main-Class: haus.nightmare.j3270.J3270App Implementation-Title: j3270 Implementation-Version: 0.1.0 Created-By: j3270 setup.sh EOF "$JAR_BIN" cvfm "$BUILD_DIR/j3270.jar" "$BUILD_DIR/MANIFEST.MF" \ -C "$BUILD_DIR/lib3270j" . \ -C "$BUILD_DIR/j3270" . > /dev/null if [ ! -f "$BUILD_DIR/j3270.jar" ]; then log_error "Failed to create $BUILD_DIR/j3270.jar" exit 1 fi JAR_SIZE=$(ls -lh "$BUILD_DIR/j3270.jar" | awk '{print $5}') printf "\n%b=== Build Successful ===%b\n" "$BOLD" "$RESET" log_success "Executable JAR: $BUILD_DIR/j3270.jar ($JAR_SIZE)" printf "\n%bTo run j3270:%b\n" "$BOLD" "$RESET" printf " ./run.sh\n" printf " # Or directly:\n" printf " %s -jar \"%s/build/j3270.jar\"\n\n" "$JAVA_BIN" "$SCRIPT_DIR" # ------------------------------------------------------------------------------ # 6. Run Tests (if requested) # ------------------------------------------------------------------------------ if [ "$DO_TEST" -eq 1 ]; then printf "%b=== Running Unit Tests ===%b\n" "$BOLD" "$RESET" if [ -x "$SCRIPT_DIR/test_all.sh" ]; then sh "$SCRIPT_DIR/test_all.sh" elif [ -x "$SCRIPT_DIR/build_all.sh" ]; then sh "$SCRIPT_DIR/build_all.sh" test fi fi # ------------------------------------------------------------------------------ # 7. Launch Application (if requested) # ------------------------------------------------------------------------------ if [ "$DO_RUN" -eq 1 ]; then log_info "Launching j3270..." if [ "$(uname -s)" = "Darwin" ]; then # On macOS, enable native application menu bar exec "$JAVA_BIN" -Dapple.laf.useScreenMenuBar=true \ -Dapple.awt.application.name=j3270 \ -jar "$BUILD_DIR/j3270.jar" $RUN_ARGS else exec "$JAVA_BIN" -jar "$BUILD_DIR/j3270.jar" $RUN_ARGS fi fi