#!/bin/sh -
#
#  $Id: runjava 5319 2006-12-20 14:12:38Z jgehlbach $
#
#
# Wrapper script for starting a JRE within OpenNMS.
# DJ Gregor
# Copyright (c) Daniel J. Gregor, Jr.
#    parts Copyright (c) The OpenNMS Group
# Tuesday, August 31, 2004
#
# Parts based on parseMib.sh, a Java MIB parser by David Hustace
# Copyright (c) The OpenNMS Group
# Friday, February 13, 2004
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#
# For more information contact:
#      OpenNMS Licensing       <license@opennms.org>
#      http://www.opennms.org/
#      http://www.opennms.com/
#
# put an '@' here so we don't break maven substition

opennms_home="@install.dir@"
searchdirs="/usr /opt /Library"
dryrun=0

java_conf="$opennms_home/etc/java.conf"
basename="`basename $0`"

die(){
    echo "${basename}: $*" >&2
    exit 1
}
warn(){
    echo "${basename}: $*" >&2
}
tell(){
    echo "${basename}: $*" >&3
}


#
# Function: printHelp()
# Give the user some basic help.
#
printHelp() {
    echo "usage: $basename [-f] [-n] [-q]"
    echo "       {-s | -S <JRE path> | -c | -r <java options> | -h}"
    echo ""
    echo "Exactly one of the following options is required:"
    echo ""
    echo "  -r <java options>"
    echo "      Exec the configured Java Runtime Environment (JRE) with"
    echo "      with <java options>."
    echo ""
    echo "  -s  Search for a suitable JRE and configure it, if found."
    echo ""
    echo "  -S <JRE path>"
    echo "      Store the JRE at <JRE path> as the configured JRE."
    echo ""
    echo "  -c  Check that the configured JRE is appropriate."
    echo ""
    echo "  -h  Print this help information."
    echo ""
    echo "Optional options:"
    echo ""
    echo "  -f  Force mode.  Ignores the JRE version check.  This option"
    echo "      only makes sense with the -r and -S options."
    echo ""
    echo "  -n  Dry run mode.  Don't change the configured JRE (-s or -S"
    echo "      options) or execute a JRE (-r option)."
    echo ""
    echo "  -q  Quiet mode.  Be fairly quiet."
    echo ""
    echo "The \"-s\" option chooses a JRE based on these factors:"
    echo ""
    echo "  1) If the JAVA_HOME environment variable is set and points at"
    echo "     an appropriate JRE, it \$JAVA_HOME/bin/java will be used."
    echo ""
    echo "  2) If \"which java\" returns an appropriate JRE, it will be used."
    echo ""
    echo "  3) Lastly, a few directories are searched to find an"
    echo "     appropriate JRE: \"$searchdirs\"."
    echo ""
    echo "If none of the above options work or if they don't find the JRE"
    echo "you want OpenNMS to use, use \"-S <JRE>\" to specify the JRE you"
    echo "want OpenNMS to use."
}

#
# Function: javaCheck()
# Requires: varible $JP (java path)
# This function verifies the version of the java
# command found in the javaPath() and the
# javaFind() functions.
#
javaCheck() {
    ret="`$JP -version 2>&1 | grep '^java version' | sed 's/^java version \"//;s/\".*//'`"
    if echo "$ret" | egrep '^1\.[5-9]\.' > /dev/null; then
	# Check for GNU gcj, which has bugs as of 2006-03-08 that break OpenNMS
	if $JP -version 2>&1 | egrep '^g[ci]j' > /dev/null; then
	    tell "$JP is GNU gcj, which is not supported"
	    return 1
	fi
	return 0
    else
	tell "$JP is not Java 1.5 or newer"
	return 1
    fi
}

#
# Function: javaPaths()
# This function attempts to find a path
# to a java executable.  It searchs for
# files (hopefully directories) that match
# the regex "^j2*" or "^java$" and appends "/bin/java".
# It then tests to see if this there is an
# executable file by this name.  This is not
# foolproof but should get us close.
#
javaPaths() {
    for searchdir in $searchdirs; do
        if [ ! -d "$searchdir" ]; then
            continue;
        fi
	# We search "j2*" for the Sun-supplied Java packages ("j2sdk"),
	# "java" for the Java installation shipped with SuSE, and "Home"
	# to catch /Library/Java/Home on Mac OS X.
	jdirs="`find \"$searchdir\" \\( -name \"j2*\" -o -name \"jdk*\" -o -name \"java\" -o -name \"Home\" \\) -maxdepth 2 -print`"
	for jdir in $jdirs; do
	    if [ -x $jdir/bin/java ]; then
		JP=$jdir/bin/java
		javaCheck && return 0
	    fi
	done
    done

    return 1
}

#
# Function: checkJavaHome()
# See if $JAVA_HOME/bin/java is a good JRE.
#
checkJavaHome() {
    tell "Checking for an appropriate JRE in JAVA_HOME..."
    if [ x"$JAVA_HOME" = x"" ]; then
	tell "skipping... JAVA_HOME not set"
	return 1
    fi

    if [ ! -d "$JAVA_HOME" ]; then
	tell "skipping... JAVA_HOME (\"$JAVA_HOME\") is not a directory"
	return 1
    fi
    
    if [ ! -x "$JAVA_HOME/bin/java" ]; then
	tell "skipping... \"$JAVA_HOME/bin/java\" does not exist or is not executable"
	return 1
    fi

    JP=$JAVA_HOME/bin/java
    if javaCheck; then
	tell "found: \"$JAVA_HOME/bin/java\" is an appropriate JRE"
	return 0
    else
	tell "\"$JAVA_HOME/bin/java\" is not an appropriate JRE"
	return 1
    fi
}

#
# Function: checkPath()
# Checks for a JRE in our path, using which(1).
#
checkPath() {
    JP="`which java`"
    if [ $? -eq 1 ]; then
	tell "did not find a JRE in user's path"
	return 1
    fi

    tell "Checking JRE in user's path: \"$JP\"..."
    if javaCheck; then
	tell "found an appropriate JRE in user's path: \"$JP\""
	return 0
    else
	tell "did not find an appropriate JRE in user's path: \"$JP\""
	return 1
    fi
}

#
# Function: findJava()
# A wrapper around javaPaths to give the user a clue about what is going on.
# 
findJava() {
    tell "searching for a good JRE..."
    if javaPaths; then
	tell "found a good JRE in \"$JP\""
	return 0
    else
	tell "did not find an appropriate JRE while searching for one"
	return 1
    fi
}


#
# Function: javaFind()
# This function first checks JAVA_HOME, then
# the current path for a java executable and then
# searches for one by calling javaPaths().
#
javaFind() {
    tell "Looking for an appropriate JRE..."

    checkJavaHome && return 0
    checkPath && return 0
    findJava && return 0

    warn "Could not find an appropriate JRE."
    warn "You can set a particular JRE by using"
    warn "\"$basename -S <JRE>\"."

    return 1
}

#
# Function: checkConfiguredJava()
# Verifies that the java configured in $java_conf looks good.
# Complains and returns 1 if it doesn't look good.
# Is quiet and returns 0 if things look good.
#
checkConfiguredJava() {
    mantra="run \"$opennms_home/bin/runjava -s\" to setup java.conf"

    if [ ! -f $java_conf ]; then
	warn "error: $java_conf file not found"
	warn "$mantra"

	return 1
    fi

    JP="`cat $java_conf`"

    if [ ! -x $JP ]; then
	warn "error: configured Java runtime environment not found"
	warn "\"$JP\" does not exist or is not executable"
	warn "$mantra"

	return 1
    fi

    javaCheck

    if [ $? -ne 0 ]; then
	warn "error: bad version for configured Java runtime environment"
	warn "\"$JP -version\" does not report that is version 1.5+"
	warn "$mantra"

	return 1
    fi

    return 0
}

#
# Function: runJava()
# Verifies that we have an appropriate JRE configured in $java_conf and
# execs it with the command-line arguments passed to us.
#
runJava() {
    checkConfiguredJava
    if [ $? -ne 0 ]; then
	if [ $force -gt 0 ]; then
	    warn "Ignoring Java warning due to '-f' option being used"
	else
	    return 1
	fi
    fi

    if [ $dryrun -eq 0 ]; then
	add_ld_path
	exec "$JP" "$@"
    else
	tell "Dry run mode is set.  Would have executed: $JP $*"
    fi
}

#
# Function: add_ld_path()
# Adds $opennms_home/lib to the linker path.
#
add_ld_path () {
    case "`uname`" in
	Darwin)
	    if echo "$DYLD_LIBRARY_PATH" | \
		grep -v "$opennms_home/lib" >/dev/null; then
		DYLD_LIBRARY_PATH="$DYLD_LIBRARY_PATH:$opennms_home/lib"
		export DYLD_LIBRARY_PATH
	    fi
	    return
	    ;;

	*)
	    if echo "$LD_LIBRARY_PATH" | \
		grep -v "$opennms_home/lib" >/dev/null; then
		LD_LIBRARY_PATH="$LD_LIBRARY_PATH:$opennms_home/lib"
		export LD_LIBRARY_PATH
	    fi
	    return
	    ;;
    esac
    
    return 1
}


#
# Function: setupJava()
# Calls javaFind and if successful, stores the location of the JRE in
# $java_conf.
#
setupJava() {
    if javaFind; then
	saveJava
	return $?
    else
	return 1
    fi
}

#
# Function: setJava()
# Calls javaFind and if successful, stores the location of the JRE in
# $java_conf.
#
setJava() {
    tell "checking specified JRE: \"$JP\"..."
    if [ ! -x "$JP" ]; then
	die "specified JRE \"$JP\" does not exist or is not executable"
    fi
    javaCheck
    if [ $? -ne 0 ]; then
	if [ $force -gt 0 ]; then
	    warn "JRE is not an appropriate version"
	    warn "Ignoring Java warning due to '-f' option being used"
	else
	    die "specified JRE \"$JP\" is not an appropriate JRE"
	fi
    else
	tell "specified JRE is good."
    fi

    saveJava
    return $?
}

saveJava() {
    if [ $dryrun -eq 0 ]; then
	echo "$JP" > $java_conf
	if [ $? -ne 0 ]; then
	    warn "error saving JRE to configuration file"
	    warn "configuration file: $java_conf"
	    die "exiting..."
	fi
	tell "value of \"$JP\" stored in configuration file"
    else
	tell "value of \"$JP\" would have been stored if not in dryrun mode"
    fi

    return 0
}

parseArgsAndDoStuff() {
    exclusive=0
    
    check=0
    force=0
    quiet=0
    run=0
    search=0
    location=""
    
    while getopts cfhnqrsS: c
    do
      case $c in
          c)
    	  check=1
    	  exclusive=`expr $exclusive + 1`
    	  ;;
    
          f)
	  force=1
          ;;
    
          h)
    	  printHelp
    	  exit 0
    	  ;;
    
          n)
    	  dryrun=1
    	  ;;
    
          q)
    	  quiet=1
    	  ;;
    
          r)
    	  run=1
    	  exclusive=`expr $exclusive + 1`
    	  ;;
    
          s)
    	  search=1
    	  exclusive=`expr $exclusive + 1`
    	  ;;

	  S)
    	  location="$OPTARG"
    	  exclusive=`expr $exclusive + 1`
    	  ;;
    
          \?)
              die "Invalid option.  Use \"-h\" for help."
    	  ;;
      esac
    done
    shift `expr $OPTIND - 1`
    
    if [ $exclusive -eq 0 ]; then
        warn "You must choose one of the command-line options."
        die "Use \"-h\" for help."
    fi
    
    if [ $exclusive -gt 1 ]; then
        warn "You must choose only one of the command-line options."
        die "Use \"-h\" for help."
    fi
    
    if [ $quiet -gt 0 ]; then
        exec 3>/dev/null
    else
        exec 3>&1
    fi
    
    if [ $check -gt 0 ]; then
        checkConfiguredJava
        exit $?
    fi
    
    if [ x"$location" != x"" ]; then
        JP="$location"
        setJava
        exit $?
    fi
    
    if [ $run -gt 0 ]; then
        runJava "$@"
        exit $?
    fi
    
    if [ $search -gt 0 ]; then
        setupJava
        exit $?
    fi
    
    die "internal error... got to end of script and shouldn't have"
}

parseArgsAndDoStuff "$@"
