#! /bin/sh

# Copyright (c) 1999, 2006 Tanuki Software Inc.
#
# Java Service Wrapper sh script.  Suitable for starting and stopping
#  wrapped Java applications on UNIX platforms.

# Get the fully qualified path to the script
case $0 in
    /*)
        SCRIPT="$0"
        ;;
    *)
        PWD=`pwd`
        SCRIPT="$PWD/$0"
        ;;
esac

# Resolve the true real path without any sym links.
CHANGED=true
while [ "X$CHANGED" != "X" ]
do
    # Change spaces to ":" so the tokens can be parsed.
    SAFESCRIPT=`echo $SCRIPT | sed -e 's; ;:;g'`
    # Get the real path to this script, resolving any symbolic links
    TOKENS=`echo $SAFESCRIPT | sed -e 's;/; ;g'`
    REALPATH=
    for C in $TOKENS; do
        # Change any ":" in the token back to a space.
        C=`echo $C | sed -e 's;:; ;g'`
        REALPATH="$REALPATH/$C"
        # If REALPATH is a sym link, resolve it.  Loop for nested links.
        while [ -h "$REALPATH" ] ; do
            LS="`ls -ld "$REALPATH"`"
            LINK="`expr "$LS" : '.*-> \(.*\)$'`"
            if expr "$LINK" : '/.*' > /dev/null; then
                # LINK is absolute.
                REALPATH="$LINK"
            else
                # LINK is relative.
                REALPATH="`dirname "$REALPATH"`""/$LINK"
            fi
        done
    done

    if [ "$REALPATH" = "$SCRIPT" ]
    then
        CHANGED=""
    else
        SCRIPT="$REALPATH"
    fi
done

# Save the startup directory 
STARTUP_DIR=`pwd`

# Change the current directory to the location of the script
cd "`dirname "$REALPATH"`"
REALDIR=`pwd`

######################################################################
# Customized for Mule
######################################################################

# Check for MULE_HOME
if [ -z "$MULE_HOME" ] ; then
    # REALDIR points to $MULE_HOME/bin now, strip off the bin part so
    # we get a proper MULE_HOME instead of a relative path
    MULE_HOME="`dirname "${REALDIR}"`"
fi

# strip a potential trailing slash in MULE_HOME. This is required to build a
# valid path for WRAPPER_CMD below which is used when running the stop
# command
MULE_HOME=`echo ${MULE_HOME} | sed -e 's/\/$//'`
export MULE_HOME
echo "MULE_HOME is set to ${MULE_HOME}"

# If MULE_BASE is not set, set it to MULE_HOME
if [ -z "$MULE_BASE" ] ; then
    MULE_BASE=$MULE_HOME
fi
export MULE_BASE

# Application
if [ "$MULE_APP" = "" ]
then
    MULE_APP="mule"
fi
export MULE_APP
if [ "$MULE_APP_LONG" = "" ]
then
    MULE_APP_LONG="Mule"
fi
export MULE_APP_LONG
APP_NAME=${MULE_APP}
APP_LONG_NAME=${MULE_APP_LONG}

# Wrapper
WRAPPER_CMD="${MULE_HOME}/lib/boot/exec/wrapper"
WRAPPER_CONF="${MULE_BASE}/conf/wrapper.conf"

# add XML compatibility jars
MULE_ENDORSED=-M-Djava.endorsed.dirs="${MULE_HOME}/lib/endorsed"

MULE_OPTS="wrapper.working.dir=\"$STARTUP_DIR\" \
           wrapper.app.parameter.1=$2 \
           wrapper.app.parameter.2=$3 \
           wrapper.app.parameter.3=$4 \
           wrapper.app.parameter.4=$5 \
           wrapper.app.parameter.5=$6 \
           wrapper.app.parameter.6=$7 \
           wrapper.app.parameter.7=$8 \
           wrapper.app.parameter.8=$9 \
           wrapper.app.parameter.9=$10"

# Configure remote Java debugging options here
# Setting suspend=y will wait for you to connect before proceeding
JPDA_OPTS="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"

######################################################################

# Priority at which to run the wrapper.  See "man nice" for valid priorities.
#  nice is only used if a priority is specified.
PRIORITY=

# Location of the pid file.
PIDDIR="."

# If uncommented, causes the Wrapper to be shutdown using an anchor file.
#  When launched with the 'start' command, it will also ignore all INT and
#  TERM signals.
#IGNORE_SIGNALS=true

# If specified, the Wrapper will be run as the specified user.
# IMPORTANT - Make sure that the user has the required privileges to write
#  the PID file and wrapper.log files.  Failure to be able to write the log
#  file will cause the Wrapper to exit without any way to write out an error
#  message.
# NOTE - This will set the user which is used to run the Wrapper as well as
#  the JVM and is not useful in situations where a privileged resource or
#  port needs to be allocated prior to the user being changed.
#RUN_AS_USER=

# The following two lines are used by the chkconfig command. Change as is
#  appropriate for your application.  They should remain commented.
# chkconfig: 2345 20 80
# description: Mule

#-----------------------------------------------------------------------------

LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MULE_HOME/lib/native/profiler

# If the PIDDIR is relative, set its value relative to the full REALPATH to avoid problems if
#  the working directory is later changed.
FIRST_CHAR=`echo $PIDDIR | cut -c1,1`
if [ "$FIRST_CHAR" != "/" ]
then
    PIDDIR=$REALDIR/$PIDDIR
fi
# Same test for WRAPPER_CMD
FIRST_CHAR=`echo $WRAPPER_CMD | cut -c1,1`
if [ "$FIRST_CHAR" != "/" ]
then
    WRAPPER_CMD=$REALDIR/$WRAPPER_CMD
fi
# Same test for WRAPPER_CONF
FIRST_CHAR=`echo $WRAPPER_CONF | cut -c1,1`
if [ "$FIRST_CHAR" != "/" ]
then
    WRAPPER_CONF=$REALDIR/$WRAPPER_CONF
fi

# Process ID
ANCHORFILE="$PIDDIR/$APP_NAME.anchor"
######################################################################
# Patched for Mule
######################################################################
PIDFILE="$PIDDIR/.$APP_NAME.pid"
######################################################################
LOCKDIR="/var/lock/subsys"
LOCKFILE="$LOCKDIR/$APP_NAME"
pid=""

# Resolve the location of the 'ps' command
PSEXE="/usr/ucb/ps"
if [ ! -x "$PSEXE" ]
then
    PSEXE="/usr/bin/ps"
    if [ ! -x "$PSEXE" ]
    then
        PSEXE="/bin/ps"
        if [ ! -x "$PSEXE" ]
        then
            echo "Unable to locate 'ps'."
            echo "Please report this message along with the location of the command on your system."
            exit 1
        fi
    fi
fi
PSKEYWORD="args"

# Resolve the os
DIST_OS=`uname -s | tr [:upper:] [:lower:] | tr -d [:blank:]`
case "$DIST_OS" in
    'sunos')
        DIST_OS="solaris"
        ;;
    'hp-ux' | 'hp-ux64')
        DIST_OS="hpux"
        ;;
    'darwin')
        DIST_OS="macosx"
        PSKEYWORD="command"
        ;;
    'unix_sv')
        DIST_OS="unixware"
        ;;
    'aix')
        DIST_OS="aix"
        ;;
esac

######################################################################
# Patched for Mule (MULE-1288, MULE-1322, MULE-1337, MULE-1396)
######################################################################

# Resolve the architecture
UNAME_PROC_OPTION="-m"
if [ "$DIST_OS" = "aix" ]; then
    UNAME_PROC_OPTION="-p"
fi

PROC_ARCH=`uname $UNAME_PROC_OPTION | tr [:upper:] [:lower:] | tr -d [:blank:]`

# The previous approach was this:
# If a 32-bit wrapper binary exists then it will work on 32 or 64 bit
# platforms, if the 64-bit binary exists then the distribution most
# likely wants to use long names.
DIST_BITS="32"

while :
do
    case "$PROC_ARCH" in
        'amd64' | 'athlon' | 'i386' | 'i486' | 'i586' | 'i686' | 'i86pc')
            DIST_ARCH="x86"
            break;;
        'x86_64')
            DIST_ARCH="x86"
            # on 64 bit Linuxes the 32 bit subsystem may not be installed so
            # let's use the 64 bit wrapper
            DIST_BITS="64"
            break;;
        'ia32' | 'ia64')
             DIST_ARCH="ia"
            break;;
        'ip27')
            DIST_ARCH="mips"
            break;;
        'power' | 'powerpc' | 'power_pc' | 'ppc64' | 'powermacintosh')
            DIST_ARCH="ppc"
            break;;
        'pa_risc' | 'pa-risc')
            DIST_ARCH="parisc"
            break;;
        'sun4u' | 'sun4us' | 'sun4v' | 'sparcv9' | 'sparc')
            DIST_ARCH="sparc"
            break;;
        '9000/800')
            DIST_ARCH="parisc"
            break;;
        *)
            echo "Your machine's hardware type (uname $UNAME_PROC_OPTION) was not recognized by the Service Wrapper as a supported platform."
            echo "Please report this message along with your machine's processor/architecture."
            exit 1
            ;;
    esac
done
######################################################################

outputFile() {
    if [ -f "$1" ]
    then
        echo "  $1 (Found but not executable.)";
    else
        echo "  $1"
    fi
}

WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-$DIST_BITS"
if [ -x "$WRAPPER_TEST_CMD" ]
then
    WRAPPER_CMD="$WRAPPER_TEST_CMD"
else
    if [ "$DIST_OS" = "macosx" ]
    then
        WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-universal-32"
        if [ -x "$WRAPPER_TEST_CMD" ]
        then
            WRAPPER_CMD="$WRAPPER_TEST_CMD"
        else
            WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-64"
            if [ -x "$WRAPPER_TEST_CMD" ]
            then
                WRAPPER_CMD="$WRAPPER_TEST_CMD"
            else
                WRAPPER_TEST_CMD="$WRAPPER_CMD-$DIST_OS-universal-64"
                if [ -x "$WRAPPER_TEST_CMD" ]
                then
                    WRAPPER_CMD="$WRAPPER_TEST_CMD"
                else
                    if [ ! -x "$WRAPPER_CMD" ]
                    then
                        echo "Unable to locate any of the following binaries:"
                        outputFile "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32"
                        outputFile "$WRAPPER_CMD-$DIST_OS-universal-32"
                        outputFile "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-64"
                        outputFile "$WRAPPER_CMD-$DIST_OS-universal-64"
                        outputFile "$WRAPPER_CMD"
                        exit 1
                    fi
                fi
            fi
        fi
    else
        if [ ! -x "$WRAPPER_CMD" ]
        then
            echo "Unable to locate any of the following binaries:"
            outputFile "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-32"
            outputFile "$WRAPPER_CMD-$DIST_OS-$DIST_ARCH-64"
            outputFile "$WRAPPER_CMD"
            exit 1
        fi
    fi
fi

# Build the nice clause
if [ "X$PRIORITY" = "X" ]
then
    CMDNICE=""
else
    CMDNICE="nice -$PRIORITY"
fi

# Build the anchor file clause.
if [ "X$IGNORE_SIGNALS" = "X" ]
then
   ANCHORPROP=
   IGNOREPROP=
else
   ANCHORPROP=wrapper.anchorfile=\"$ANCHORFILE\"
   IGNOREPROP=wrapper.ignore_signals=TRUE
fi

# Build the lock file clause.  Only create a lock file if the lock directory exists on this platform.
LOCKPROP=
if [ -d $LOCKDIR ]
then
    if [ -w $LOCKDIR ]
    then
        LOCKPROP=wrapper.lockfile=\"$LOCKFILE\"
    fi
fi

checkUser() {
    # $1 touchLock flag
    # $2 command

    # Check the configured user.  If necessary rerun this script as the desired user.
    if [ "X$RUN_AS_USER" != "X" ]
    then
        # Resolve the location of the 'id' command
        IDEXE="/usr/xpg4/bin/id"
        if [ ! -x "$IDEXE" ]
        then
            IDEXE="/usr/bin/id"
            if [ ! -x "$IDEXE" ]
            then
                echo "Unable to locate 'id'."
                echo "Please report this message along with the location of the command on your system."
                exit 1
            fi
        fi

        if [ "`$IDEXE -u -n`" = "$RUN_AS_USER" ]
        then
            # Already running as the configured user.  Avoid password prompts by not calling su.
            RUN_AS_USER=""
        fi
    fi
    if [ "X$RUN_AS_USER" != "X" ]
    then
        # If LOCKPROP and $RUN_AS_USER are defined then the new user will most likely not be
        # able to create the lock file.  The Wrapper will be able to update this file once it
        # is created but will not be able to delete it on shutdown.  If $2 is defined then
        # the lock file should be created for the current command
        if [ "X$LOCKPROP" != "X" ]
        then
            if [ "X$1" != "X" ]
            then
                # Resolve the primary group
                RUN_AS_GROUP=`groups $RUN_AS_USER | awk '{print $3}' | tail -1`
                if [ "X$RUN_AS_GROUP" = "X" ]
                then
                    RUN_AS_GROUP=$RUN_AS_USER
                fi
                touch $LOCKFILE
                chown $RUN_AS_USER:$RUN_AS_GROUP $LOCKFILE
            fi
        fi

        # Still want to change users, recurse.  This means that the user will only be
        #  prompted for a password once. Variables shifted by 1
        su -m $RUN_AS_USER -c "\"$REALPATH\" $2"

        # Now that we are the original user again, we may need to clean up the lock file.
        if [ "X$LOCKPROP" != "X" ]
        then
            getpid
            if [ "X$pid" = "X" ]
            then
                # Wrapper is not running so make sure the lock file is deleted.
                if [ -f "$LOCKFILE" ]
                then
                    rm "$LOCKFILE"
                fi
            fi
        fi

        exit 0
    fi
}

getpid() {
    if [ -f "$PIDFILE" ]
    then
        if [ -r "$PIDFILE" ]
        then
            pid=`cat "$PIDFILE"`
            if [ "X$pid" != "X" ]
            then
                # It is possible that 'a' process with the pid exists but that it is not the
                #  correct process.  This can happen in a number of cases, but the most
                #  common is during system startup after an unclean shutdown.
                # The ps statement below looks for the specific wrapper command running as
                #  the pid.  If it is not found then the pid file is considered to be stale.
                ######################################################################
                # TODO MULE-2052: ps -o args gets truncated to 80 columns on Solaris which makes
                # this test fail if the path is too long.
                # http://sourceforge.net/tracker/index.php?func=detail&aid=1664303&group_id=39428&atid=425187
                ######################################################################
                if [ "$DIST_OS" = 'solaris' ]
                then
                    # on Solaris, both /usr/ucb/ps and /usr/bin/ps accept the ww option.
                    # Use it to overcome the truncation issue mentioned above
                    pidtest=`$PSEXE ww $pid | grep "$WRAPPER_CMD" | tail -1`
                else
                    pidtest=`$PSEXE -p $pid -o $PSKEYWORD | grep "$WRAPPER_CMD" | tail -1`
                fi

                if [ "X$pidtest" = "X" ]
                then
                    # This is a stale pid file.
                    rm -f "$PIDFILE"
                    echo "Removed stale pid file: $PIDFILE"
                    pid=""
                fi
            fi
        else
            echo "Cannot read $PIDFILE."
            exit 1
        fi
    fi
}

testpid() {
    if [ "$DIST_OS" = 'solaris' ]
    then
        # on Solaris, both /usr/ucb/ps and /usr/bin/ps accept the ww option.
        pid=`$PSEXE ww $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1`
    else
        pid=`$PSEXE -p $pid | grep $pid | grep -v grep | awk '{print $1}' | tail -1`
    fi

    if [ "X$pid" = "X" ]
    then
        # Process is gone so remove the pid file.
        rm -f "$PIDFILE"
        pid=""
    fi
}

console() {
    echo "Running $APP_LONG_NAME..."
    getpid
    if [ "X$pid" = "X" ]
    then
        # The string passed to eval must handle spaces in paths correctly.
        COMMAND_LINE="$CMDNICE \"$WRAPPER_CMD\" \"$WRAPPER_CONF\" wrapper.syslog.ident=$APP_NAME wrapper.pidfile=\"$PIDFILE\" $ANCHORPROP $LOCKPROP"
        ######################################################################
        # Customized for Mule
        ######################################################################
        eval $COMMAND_LINE $MULE_OPTS
        ######################################################################
    else
        echo "$APP_LONG_NAME is already running."
        exit 1
    fi
}

start() {
    echo "Starting $APP_LONG_NAME..."
    getpid
    if [ "X$pid" = "X" ]
    then
        # The string passed to eval must handles spaces in paths correctly.
        COMMAND_LINE="$CMDNICE \"$WRAPPER_CMD\" \"$WRAPPER_CONF\" wrapper.syslog.ident=$APP_NAME wrapper.pidfile=\"$PIDFILE\" wrapper.daemonize=TRUE $ANCHORPROP $IGNOREPROP $LOCKPROP"
        ######################################################################
        # Customized for Mule
        ######################################################################
        eval $COMMAND_LINE $MULE_OPTS
        ######################################################################
    else
        echo "$APP_LONG_NAME is already running."
        exit 1
    fi
}

stopit() {
    echo "Stopping $APP_LONG_NAME..."
    getpid
    if [ "X$pid" = "X" ]
    then
        echo "$APP_LONG_NAME was not running."
    else
        if [ "X$IGNORE_SIGNALS" = "X" ]
        then
            # Running so try to stop it.
            kill $pid
            if [ $? -ne 0 ]
            then
                # An explanation for the failure should have been given
                echo "Unable to stop $APP_LONG_NAME."
                exit 1
            fi
        else
            rm -f "$ANCHORFILE"
            if [ -f "$ANCHORFILE" ]
            then
                # An explanation for the failure should have been given
                echo "Unable to stop $APP_LONG_NAME."
                exit 1
            fi
        fi

        # We can not predict how long it will take for the wrapper to
        #  actually stop as it depends on settings in wrapper.conf.
        #  Loop until it does.
        savepid=$pid
        CNT=0
        TOTCNT=0
        while [ "X$pid" != "X" ]
        do
            # Show a waiting message every 5 seconds.
            if [ "$CNT" -lt "5" ]
            then
                CNT=`expr $CNT + 1`
            else
                echo "Waiting for $APP_LONG_NAME to exit..."
                CNT=0
            fi
            TOTCNT=`expr $TOTCNT + 1`

            sleep 1

            testpid
        done

        pid=$savepid
        testpid
        if [ "X$pid" != "X" ]
        then
            echo "Failed to stop $APP_LONG_NAME."
            exit 1
        else
            echo "Stopped $APP_LONG_NAME."
        fi
    fi
}

status() {
    getpid
    if [ "X$pid" = "X" ]
    then
        echo "$APP_LONG_NAME is not running."
        exit 1
    else
        echo "$APP_LONG_NAME is running ($pid)."
        exit 0
    fi
}

dump() {
    echo "Dumping $APP_LONG_NAME..."
    getpid
    if [ "X$pid" = "X" ]
    then
        echo "$APP_LONG_NAME was not running."

    else
        kill -3 $pid

        if [ $? -ne 0 ]
        then
            echo "Failed to dump $APP_LONG_NAME."
            exit 1
        else
            echo "Dumped $APP_LONG_NAME."
        fi
    fi
}

checkAdditionalJvmParams() {
    # The string passed to eval must handle spaces in paths correctly.
    "$MULE_HOME/bin/launcher" \"$MULE_HOME/bin/additional.groovy\" \"$WRAPPER_CONF\" \"$JPDA_OPTS\" \"$MULE_ENDORSED\" $@
    EXIT_STATUS=$?

    if [ "$EXIT_STATUS" -ne "0" ] ; then        
        exit $EXIT_STATUS
    fi
}

case "$1" in

    'console')
        checkUser touchlock $1
        checkAdditionalJvmParams $*
        console
        ;;

    'start')
        checkUser touchlock $1
        checkAdditionalJvmParams $*
        start
        ;;

    'stop')
        checkUser "" $1
        stopit
        ;;

    'restart')
        checkUser touchlock $1
        stopit
        start
        ;;

    'status')
        checkUser "" $1
        status
        ;;

    'dump')
        checkUser "" $1
        dump
        ;;

    *)
        ######################################################################
        # Customized for Mule
        ######################################################################
        echo "Running in console (foreground) mode by default, use Ctrl-C to exit..."

        # Change back to the original startup directory.
        cd "$STARTUP_DIR"

        # Call this script recursively with the "console" parameter.
        "$REALPATH" console $*
        ######################################################################
        ;;
esac

exit 0
