#!/bin/sh
# ------------------------------------------------------------------------
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements.  See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License.  You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ------------------------------------------------------------------------
#
# This script controls standalone Apache ActiveMQ service processes.
# To ensure compatibility to macosx and cygwin we do not utilize
# lsb standard infrastructure for controlling daemons like
# "start-stop-daemon".
#
# See also http://activemq.apache.org/activemq-command-line-tools-reference.html
# for additional commandline arguments
#
# Authors:
# Marc Schoechlin <ms@256bit.org>
# Adapted for Puppet Enterprise by Puppet Labs

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

# pe-activemq   Apache ActiveMQ Middleware Service
#
# chkconfig:    345 24 76
#
# description:  Apache ActiveMQ Middleware Service (Part of Puppet Enterprise)
#
### BEGIN INIT INFO
# Provides:          pe-activemq
# Required-Start:    $remote_fs
# Required-Stop:     $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Start daemon at boot time
# Description:       Enable service provided by daemon.
### END INIT INFO
# CONFIGURATION
ACTIVEMQ_PROCESS="pe-activemq"
ACTIVEMQ_CONFIGS="/etc/sysconfig/pe-activemq"
ACTIVEMQ_HOME="/opt/puppetlabs/server/apps/activemq"
ACTIVEMQ_CONF="/etc/puppetlabs/activemq"
ACTIVEMQ_BASE="$ACTIVEMQ_HOME"
ACTIVEMQ_DATA="/opt/puppetlabs/server/data/activemq"
ACTIVEMQ_USER="pe-activemq"
ACTIVEMQ_OPTS_MEMORY="-Xms512m -Xmx512m"
ACTIVEMQ_PIDDIR="/var/run/puppetlabs/activemq"
ACTIVEMQ_PIDFILE="$ACTIVEMQ_PIDDIR/activemq.pid"
JAVA_HOME="/opt/puppetlabs/server/apps/java/lib/jvm/java/jre"
JAVACMD="$JAVA_HOME/bin/java"
LOCKFILE="/var/lock/subsys/pe-activemq"


# Backup invocation parameters
COMMANDLINE_ARGS="$@"


## START:DEFAULTCONFIG
# ------------------------------------------------------------------------
# Configuration file for running Apache Active MQ as standalone provider
#
# This file overwrites the predefined settings of the sysv init-script
#
# Active MQ installation dir


if [ -z "$ACTIVEMQ_TMP" ] ; then
  ACTIVEMQ_TMP="$ACTIVEMQ_BASE/tmp"
fi

# Location of the pidfile
if [ -z "$ACTIVEMQ_PIDFILE" ]; then
  ACTIVEMQ_PIDFILE="$ACTIVEMQ_DATA/activemq-`hostname`.pid"
fi

# Uncomment to enable audit logging
#ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS -Dorg.apache.activemq.audit=true"

# Set jvm jmx configuration
# This enables jmx access over a configured jmx-tcp-port.
# You have to configure the first four settings if you run a ibm jvm, caused by the
# fact that IBM's jvm does not support VirtualMachine.attach(PID).
# JMX access is needed for quering a running activemq instance to gain data or to
# trigger management operations.
#
# Example for ${ACTIVEMQ_CONF}/jmx.access:
# ---
# # The "monitorRole" role has readonly access.
# # The "controlRole" role has readwrite access.
# monitorRole readonly
# controlRole readwrite
# ---
#
# Example for ${ACTIVEMQ_CONF}/jmx.password:
# ---
# # The "monitorRole" role has password "abc123".
# # # The "controlRole" role has password "abcd1234".
# monitorRole abc123
# controlRole abcd1234
# ---
#
# ACTIVEMQ_SUNJMX_START="-Dcom.sun.management.jmxremote.port=11099 "
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.password.file=${ACTIVEMQ_CONF}/jmx.password"
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.access.file=${ACTIVEMQ_CONF}/jmx.access"
# ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote.ssl=false"
ACTIVEMQ_SUNJMX_START="$ACTIVEMQ_SUNJMX_START -Dcom.sun.management.jmxremote"

# Set jvm jmx configuration for controlling the broker process
# You only have to configure the first four settings if you run a ibm jvm, caused by the
# fact that IBM's jvm does not support VirtualMachine.attach(PID)
# (see also com.sun.management.jmxremote.port, .jmx.password.file and .jmx.access.file )
#ACTIVEMQ_SUNJMX_CONTROL="--jmxurl service:jmx:rmi:///jndi/rmi://127.0.0.1:1099/jmxrmi --jmxuser controlRole --jmxpassword abcd1234"
ACTIVEMQ_SUNJMX_CONTROL=""

# Specify the queue manager URL for using "browse" option of sysv initscript
if [ -z "$ACTIVEMQ_QUEUEMANAGERURL" ]; then
    ACTIVEMQ_QUEUEMANAGERURL="--amqurl tcp://localhost:61616"
fi

# Set additional JSE arguments
ACTIVEMQ_SSL_OPTS="$SSL_OPTS"

# Uncomment to enable YourKit profiling
#ACTIVEMQ_DEBUG_OPTS="-agentlib:yjpagent"

# Uncomment to enable remote debugging
#ACTIVEMQ_DEBUG_OPTS="-Xdebug -Xnoagent -Djava.compiler=NONE -Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=5005"

# ActiveMQ tries to shutdown the broker by jmx,
# after a specified number of seconds send SIGKILL
if [ -z "$ACTIVEMQ_KILL_MAXSECONDS" ]; then
    ACTIVEMQ_KILL_MAXSECONDS=30
fi

setCurrentUser(){
     CUSER=`whoami 2>/dev/null`
 }

## END:DEFAULTCONFIG

# ------------------------------------------------------------------------
# LOAD CONFIGURATION

# load activemq configuration
CONFIG_LOAD="no"
for ACTIVEMQ_CONFIG in $ACTIVEMQ_CONFIGS;do
   if [ -f "$ACTIVEMQ_CONFIG" ] ; then
     ( . $ACTIVEMQ_CONFIG >/dev/null 2>&1 )
     if [ "$?" != "0" ];then
      echo "ERROR: There are syntax errors in '$ACTIVEMQ_CONFIG'"
      exit 1
     else
       echo "INFO: Loading '$ACTIVEMQ_CONFIG'"
       . $ACTIVEMQ_CONFIG
      CONFIG_LOAD="yes"
     fi
   fi
done

# inform user that default configuration is loaded, no suitable configfile found
if [ "$CONFIG_LOAD" != "yes" ];then
    echo "INFO: Using default configuration";
    echo "No working configuration found."
    echo
    echo "INFO: Apply the pe_mcollective module to create a configuration file"
    echo
fi

if [ -z "$ACTIVEMQ_OPTS" ] ; then
    ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS_MEMORY -Djava.util.logging.config.file=logging.properties -Dhawtio.realm=activemq -Dhawtio.role=admins -Dhawtio.rolePrincipalClasses=org.apache.activemq.jaas.GroupPrincipal -Djava.security.auth.login.config=$ACTIVEMQ_CONF/login.config"
fi

echo "INFO: Using java '$JAVACMD'"

# Set default classpath
# Add instance conf dir before AMQ install conf dir to pick up instance-specific classpath entries first
ACTIVEMQ_CLASSPATH="${ACTIVEMQ_CONF};${ACTIVEMQ_CLASSPATH}"

# Start the ActiveMQ JAR
#
#
# @ARG1 : the name of the PID-file
#         If specified, this function starts the java process in background as a daemon
#         and stores the pid of the created process in the file.
#         Output on stdout/stderr will be supressed if this parameter is specified
# @RET  : If unless 0 something went wrong
#
# Note: This function uses a lot of globally defined variables
# - if $ACTIVEMQ_USER is set, the function tries starts the java process whith the specified
#   user
invokeJar(){
   PIDFILE="$1"
   RET="1"

   if [ ! -f "${ACTIVEMQ_HOME}/bin/activemq.jar" ];then
    echo "ERROR: '${ACTIVEMQ_HOME}/bin/activemq.jar' does not exist"
    exit 1
   fi

   setCurrentUser

   if ( [ -z "$ACTIVEMQ_USER" ] || [ "$ACTIVEMQ_USER" = "$CUSER" ] );then
      DOIT_PREFIX="sh -c "
      DOIT_POSTFIX=";"
   elif [ "`id -u`" = "0" ];then
      DOIT_PREFIX="su -s /bin/bash -c "
      DOIT_POSTFIX=" - $ACTIVEMQ_USER"
      echo "INFO: changing to user '$ACTIVEMQ_USER' to invoke java"
   fi
   # Execute java binary
   if [ -n "$PIDFILE" ] && [ "$PIDFILE" != "stop" ];then
      $DOIT_PREFIX "$JAVACMD $ACTIVEMQ_OPTS $ACTIVEMQ_DEBUG_OPTS \
              -Dactivemq.classpath=\"${ACTIVEMQ_CLASSPATH}\" \
              -Dactivemq.home=\"${ACTIVEMQ_HOME}\" \
              -Dactivemq.base=\"${ACTIVEMQ_BASE}\" \
              -Dactivemq.conf=\"${ACTIVEMQ_CONF}\" \
              -Dactivemq.data=\"${ACTIVEMQ_DATA}\" \
              -jar \"${ACTIVEMQ_HOME}/bin/activemq.jar\" $COMMANDLINE_ARGS >/dev/null 2>&1 &
              RET=\"\$?\"; APID=\"\$!\";
              echo \$APID > $PIDFILE;
              echo \"INFO: pidfile created : '$PIDFILE' (pid '\$APID')\";exit \$RET" $DOIT_POSTFIX
      RET="$?"
   elif [ -n "$PIDFILE" ] && [ "$PIDFILE" = "stop" ];then
          PID=`cat $ACTIVEMQ_PIDFILE`
          $DOIT_PREFIX "$JAVACMD $ACTIVEMQ_OPTS $ACTIVEMQ_DEBUG_OPTS \
              -Dactivemq.classpath=\"${ACTIVEMQ_CLASSPATH}\" \
              -Dactivemq.home=\"${ACTIVEMQ_HOME}\" \
              -Dactivemq.base=\"${ACTIVEMQ_BASE}\" \
              -Dactivemq.conf=\"${ACTIVEMQ_CONF}\" \
              -Dactivemq.data=\"${ACTIVEMQ_DATA}\" \
              -jar \"${ACTIVEMQ_HOME}/bin/activemq.jar\" $COMMANDLINE_ARGS --pid $PID &
              RET=\"\$?\"; APID=\"\$!\";
              echo \$APID > $ACTIVEMQ_DATA/stop.pid; exit \$RET" $DOIT_POSTFIX
      RET="$?"
   else
      $DOIT_PREFIX "$JAVACMD $ACTIVEMQ_OPTS $ACTIVEMQ_DEBUG_OPTS \
              -Dactivemq.classpath=\"${ACTIVEMQ_CLASSPATH}\" \
              -Dactivemq.home=\"${ACTIVEMQ_HOME}\" \
              -Dactivemq.base=\"${ACTIVEMQ_BASE}\" \
              -Dactivemq.conf=\"${ACTIVEMQ_CONF}\" \
              -Dactivemq.data=\"${ACTIVEMQ_DATA}\" \
              -jar \"${ACTIVEMQ_HOME}/bin/activemq.jar\" $COMMANDLINE_ARGS" $DOIT_POSTFIX
      RET="$?"
   fi
   return $RET
}

# Check if ActiveMQ is running
#
# @RET  : 0 => the activemq process is running
#         1 => process id in $ACTIVEMQ_PIDFILE does not exist anymore
#         2 => something is wrong with the pid file
#
# Note: This function uses globally defined variables
# - $ACTIVEMQ_PIDFILE : the name of the pid file


checkRunning(){
    if [ -f "$ACTIVEMQ_PIDFILE" ]; then
        if  [ -z "`cat $ACTIVEMQ_PIDFILE`" ];then
            echo "ERROR: Pidfile '$ACTIVEMQ_PIDFILE' exists but contains no pid"
            return 1
        fi
        PID=`cat $ACTIVEMQ_PIDFILE`
        RET=`ps -p $PID|grep java`
        if [ -n "$RET" ];then
            return 0;
        else
            return 1;
        fi
    # If we don't have a pidfile, but there is a process, create one
    elif PID=$(pgrep -f "$ACTIVEMQ_HOME"/bin/activemq.jar) ; then
        if [ $( echo $PID | wc -w ) -eq 1 ] ; then
            echo "$PID" > "$ACTIVEMQ_PIDFILE"
            return 0
        else
            echo "ERROR: Pidfile '$ACTIVEMQ_PIDFILE' does not exist, but there are multiple processes: '$PID'"
            return 4
        fi
    else
        return 1;
    fi
}

checkStopRunning(){
    PID=$ACTIVEMQ_DATA/stop.pid
    if [ -f "$PID" ]; then
       if  [ -z "`cat $PID`" ];then
        echo "ERROR: Pidfile '$PID' exists but contains no pid"
        return 1
       fi
       THEPID=`cat $PID`
       RET=`ps -p $THEPID|grep java`
       if [ -n "$RET" ];then
         return 0;
       else
         return 1;
       fi
    else
         return 1;
    fi
}

# Check if ActiveMQ is running
#
# @RET  : 0 => the activemq process is running
#         1 => the activemq process is not running
#
# Note: This function uses globally defined variables
# - $ACTIVEMQ_PIDFILE : the name of the pid file


invoke_status(){
    if ( checkRunning );then
         PID=`cat $ACTIVEMQ_PIDFILE`
         echo "$ACTIVEMQ_PROCESS is running (pid '$PID')"
         exit 0
    fi
    echo "$ACTIVEMQ_PROCESS not running"
    exit 1
}

# Start ActiveMQ if not already running
#
# @RET  : 0 => is now started, is already started
#         !0 => something went wrong
#
# Note: This function uses globally defined variables
# - $ACTIVEMQ_PIDFILE      : the name of the pid file
# - $ACTIVEMQ_OPTS         : Additional options
# - $ACTIVEMQ_SUNJMX_START : options for JMX settings
# - $ACTIVEMQ_SSL_OPTS     : options for SSL encryption

invoke_start(){
    if ! [ -d "$ACTIVEMQ_PIDDIR" ]; then
      /bin/mkdir -p "$ACTIVEMQ_PIDDIR"
      /bin/chown "$ACTIVEMQ_USER" "$ACTIVEMQ_PIDDIR"
      /bin/chgrp "$ACTIVEMQ_USER" "$ACTIVEMQ_PIDDIR"
    fi

    if ( checkRunning );then
      PID=`cat $ACTIVEMQ_PIDFILE`
      echo "INFO: Process with pid '$PID' is already running"
      exit 0
    fi

    ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS $ACTIVEMQ_SUNJMX_START $ACTIVEMQ_SSL_OPTS -Djava.awt.headless=true -Djava.io.tmpdir=\"${ACTIVEMQ_TMP}\""

    echo "INFO: Starting - inspect logfiles specified in logging.properties and log4j.properties to get details"
    invokeJar $ACTIVEMQ_PIDFILE
    RET="$?"
    [ $RET -eq 0 ] && touch "${LOCKFILE}"
    exit "$RET"
}

# Start ActiveMQ in foreground (for debugging)
#
# @RET  : 0 => is now started, is already started
#         !0 => something went wrong
#
# Note: This function uses globally defined variables
# - $ACTIVEMQ_PIDFILE      : the name of the pid file
# - $ACTIVEMQ_OPTS         : Additional options
# - $ACTIVEMQ_SUNJMX_START : options for JMX settings
# - $ACTIVEMQ_SSL_OPTS     : options for SSL encryption

invoke_console(){
    if ( checkRunning );then
      echo "ERROR: $ACTIVEMQ_PROCESS is already running"
      exit 1
    fi

    ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS $ACTIVEMQ_SUNJMX_START $ACTIVEMQ_SSL_OPTS -Djava.awt.headless=true -Djava.io.tmpdir=\"${ACTIVEMQ_TMP}\""

    COMMANDLINE_ARGS="start `echo $COMMANDLINE_ARGS|sed 's,^console,,'`"
    echo "INFO: Starting in foreground, this is just for debugging purposes (stop process by pressing CTRL+C)"
    invokeJar
    exit "$?"
}

# Stop ActiveMQ
#
# @RET  : 0 => stop was successful
#         !0 => something went wrong
#
# Note: This function uses globally defined variables
# - $ACTIVEMQ_PIDFILE         : the name of the pid file
# - $ACTIVEMQ_KILL_MAXSECONDS : the number of seconds to wait for termination of broker after sending
#                              shutdown signal by jmx interface

invoke_stop(){
    RET="1"
    if ( checkRunning );then
       ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS $ACTIVEMQ_SSL_OPTS"
       COMMANDLINE_ARGS="$COMMANDLINE_ARGS $ACTIVEMQ_SUNJMX_CONTROL"
       invokeJar "stop"
       RET="$?"
       PID=`cat $ACTIVEMQ_PIDFILE`
       echo "INFO: Waiting at least $ACTIVEMQ_KILL_MAXSECONDS seconds for regular process termination of pid '$PID' : "
       FOUND="0"
       i=1
       while [ $i != $ACTIVEMQ_KILL_MAXSECONDS ]; do

         if [ ! checkStopRunning ];then
            if [ ! checkRunning ]; then
               echo " FINISHED"
               FOUND="1"
            fi
            break
         fi

         if (checkRunning);then
            sleep 1
            printf  "."
         else
            echo " FINISHED"
            FOUND="1"
            break
         fi
         i=`expr $i + 1`
       done
       if [ "$FOUND" -ne "1" ];then
         echo
         echo "INFO: Regular shutdown not successful,  sending SIGKILL to process with pid '$PID'"
         kill -KILL $PID
         RET="1"
       fi
    elif [ -f "$ACTIVEMQ_PIDFILE" ];then
       echo "ERROR: No or outdated process id in '$ACTIVEMQ_PIDFILE'"
       echo
       echo "INFO: Removing $ACTIVEMQ_PIDFILE"
    else
       echo "$ACTIVEMQ_PROCESS not running"
       exit 0
    fi
    rm -f $ACTIVEMQ_PIDFILE >/dev/null 2>&1
    rm -f $ACTIVEMQ_DATA/stop.pid >/dev/null 2>&1
    rm -f $LOCKFILE >/dev/null 2>&1
    exit $RET
}

# Invoke a task on a running ActiveMQ instance
#
# @RET  : 0 => successful
#         !0 => something went wrong
#
# Note: This function uses globally defined variables
# - $ACTIVEMQ_QUEUEMANAGERURL : The url of the queuemanager
# - $ACTIVEMQ_OPTS            : Additional options
# - $ACTIVEMQ_SUNJMX_START    : options for JMX settings
# - $ACTIVEMQ_SSL_OPTS        : options for SSL encryption
invoke_task(){
    # call task in java binary
    if ( checkRunning );then
      if [ "$1" = "browse" ] && [ -n "$ACTIVEMQ_QUEUEMANAGERURL" ];then
         ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS $ACTIVEMQ_SSL_OPTS"
         COMMANDLINE_ARGS="$1 $ACTIVEMQ_QUEUEMANAGERURL `echo $COMMANDLINE_ARGS|sed 's,^browse,,'`"
      elif [ "$1" = "query" ]  && [ -n "$ACTIVEMQ_QUEUEMANAGERURL" ];then
         ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS $ACTIVEMQ_SSL_OPTS"
         COMMANDLINE_ARGS="$1 $ACTIVEMQ_SUNJMX_CONTROL `echo $COMMANDLINE_ARGS|sed 's,^query,,'`"
      else
         ACTIVEMQ_OPTS="$ACTIVEMQ_OPTS $ACTIVEMQ_SSL_OPTS"
         COMMANDLINE_ARGS="$COMMANDLINE_ARGS $ACTIVEMQ_SUNJMX_CONTROL"
      fi
      invokeJar
      exit $?
    else
      invokeJar
      exit 1
    fi
}

show_help() {
  invokeJar
  RET="$?"
  cat << EOF
Tasks provided by the sysv init script:
    restart         - stop running instance (if there is one), start new instance
    console         - start broker in foreground, useful for debugging purposes
    status          - check if activemq process is running


Configuration of this script:
    The configuration of this script is contained in $ACTIVEMQ_CONFIGS, which is
    managed by the pe_mcollective puppet module.

EOF
  exit $RET
}

# ------------------------------------------------------------------------
# MAIN

# show help
if [ -z "$1" ];then
 show_help
fi

case "$1" in
  status)
      invoke_status
    ;;
  restart)
    if ( checkRunning );then
      $0 stop
    fi
    $0 status
    $0 start
    $0 status
    ;;
  start)
    invoke_start
    ;;
  console)
    invoke_console
    ;;
  stop)
    invoke_stop
    ;;
  *)
    invoke_task
esac
