#!/bin/bash
### BEGIN REDHAT INFO
# chkconfig: 2345 99 20
# description: The Neo4J graph database server. See http://neo4j.org
### END REDHAT INFO
### BEGIN INIT INFO
# Provides:          neo4j-service
# Required-Start:
# Required-Stop:
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
### END INIT INFO
# Copyright (c) 2002-2014 "Neo Technology,"

# Network Engine for Objects in Lund AB [http://neotechnology.com]
#
# This file is part of Neo4j.
#
# Neo4j 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 3 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, see <http://www.gnu.org/licenses/>.

FRIENDLY_NAME="Neo4j Server"
LAUNCHD_NAME="org.neo4j.server"

function findBaseDirAndCdThere {
# This seems to not be safe to run at any time. If that
# is the case, it should be fixed to be so, if possible.
  SCRIPT=$0

  cd "`dirname "$SCRIPT"`"
  SCRIPT=`basename "$SCRIPT"`

  while [ -L "$SCRIPT" ]
  do
    SCRIPT=$( readlink "$SCRIPT" )
    cd "$(dirname "$SCRIPT")"
    SCRIPT=`basename "$SCRIPT"`
  done
  NEO4J_HOME=`cd $( dirname "$SCRIPT" )/.. && dirs -l +0`
  NEO4J_INSTANCE=$NEO4J_HOME
  NEO4J_CONFIG=$NEO4J_INSTANCE/conf
  NEO4J_LOG=$NEO4J_INSTANCE/data/log

  cd "$NEO4J_HOME"
}

function parseConfig {
  if [ ${BASH_VERSINFO[0]} -eq 3 ] ; then
    if [ ${BASH_VERSINFO[1]} -lt 2 ] ; then
      getconfigquoted "${NEO4J_CONFIG}/neo4j-wrapper.conf"
      getconfigquoted "${NEO4J_CONFIG}/neo4j-server.properties"
      return
    fi
  fi
  getconfig "${NEO4J_CONFIG}/neo4j-wrapper.conf"
  getconfig "${NEO4J_CONFIG}/neo4j-server.properties"
}

findBaseDirAndCdThere
source bin/utils
parseConfig

JAVA_OPTS="-server -XX:+DisableExplicitGC ${wrapper_java_additional}"
[ -z "${wrapper_java_initmemory}" ] || JAVA_OPTS="$JAVA_OPTS -Xms${wrapper_java_initmemory}m"
[ -z "${wrapper_java_maxmemory}" ] || JAVA_OPTS="$JAVA_OPTS -Xmx${wrapper_java_maxmemory}m"

#NEO4J_SERVER_PORT=`( egrep "^org.neo4j.server.webserver.port" $NEO4J_INSTANCE/conf/neo4j-server.properties || echo 7474 ) | sed -e 's/.*=//'`
NEO4J_SERVER_PORT=${org_neo4j_server_webserver_port:=7474}

LAUNCHD_NAME="${LAUNCHD_NAME}.${NEO4J_SERVER_PORT}"

HEADLESS=false

if [ -z "${wrapper_user}" ]; then
  NEO4J_USER=`id -un`
else
  NEO4J_USER=${wrapper_user}
fi

# Username to propose for neo4j user, can be overridden by -u USERNAME option
DEFAULT_USER='neo4j'

SCRIPT_NAME="${NEO4J_HOME}/bin/neo4j"
SERVICE_NAME=${wrapper_ntservice_name:=neo4j-service}
LAUNCHD_DIR=~/Library/LaunchAgents/

TIMEOUT=120

PID_FILE=${NEO4J_INSTANCE}/data/neo4j-service.pid
buildclasspath() {
  # confirm library jars
  LIBDIR="$NEO4J_HOME"/lib
  if [ ! -e "$LIBDIR" ] ; then
    echo "Error: missing Neo4j Library, expected at $LIBDIR"
    exit 1
  fi

  # confirm system jars
  SYSLIBDIR="$NEO4J_HOME"/system/lib
  if [ ! -e "$SYSLIBDIR" ] ; then
    echo "Error: missing Neo4j System Library, expected at $SYSLIBDIR"
    exit 1
  fi

  ALL_JARS=""
  for jar in "$LIBDIR"/*.jar "$SYSLIBDIR"/*.jar ; do
    [ -z "$ALL_JARS" ] && ALL_JARS="$jar" || ALL_JARS="$ALL_JARS":"$jar"
  done

  # add any plugin jars
  for jar in "$NEO4J_HOME"/plugins/*.jar ; do
    if [ -e "$jar" ] ; then
      ALL_JARS="$ALL_JARS":"$jar"
    fi
  done

  # add any plugin jars in nested folders
  for jar in "$NEO4J_HOME"/plugins/**/*.jar ; do
    if [ -e "$jar" ] ; then
      ALL_JARS="$ALL_JARS":"$jar"
    fi
  done

  CLASSPATH=${ALL_JARS}

  # add useful conf stuff to classpath - always a good idea
  CLASSPATH="$CLASSPATH":"$NEO4J_HOME"/conf/
}

detectrunning() {
  if [ $DIST_OS = "solaris" ] ; then
      ## SmartOS has a different lsof command line arguments
      newpid=$(lsof -o $NEO4J_SERVER_PORT | grep '::' | head -n1 | cut -d ' ' -f 1)
  else
      ## This could be achieved with filtering using -sTCP:LISTEN but this option is not available
      ## on lsof v4.78 which is the one bundled with some distros. So we have to do this grep below
      newpid=$(lsof -i :$NEO4J_SERVER_PORT -F T -Ts | grep -i "TST=LISTEN" -B1 | head -n1)
      newpid=${newpid:1}
  fi
}

startit() {

  detectos
  exitonnojava
  checkstatus
  checklimits

  checkjvmcompatibility

  detectrunning
  if [ $newpid ] ; then
	     echo "Another server-process is running with [$newpid], cannot start a new one. Exiting."
	     exit 2;
  fi

  echo "Using additional JVM arguments: " $JAVA_OPTS

  if [ $DIST_OS = "macosx" ] ; then
    getlaunchdpid
    if [ $LAUNCHDPID -eq 0 ] ; then
      echo "Detected installation in launchd, starting it..."
      launchctl start $LAUNCHD_NAME
      exit 0
    elif [ $LAUNCHDPID -gt 0 ] ; then
      echo "Instance already running via launchd with PID $LAUNCHDPID"
      exit 1
    fi
    # We fall through here since if there is no launchd install we start manually
  fi

  if [ -z $NEO4J_PID ] ; then
    printf "Starting $FRIENDLY_NAME..."

    buildclasspath
    checkclasspath
    checkandrepairenv

    CONSOLE_LOG="$NEO4J_LOG/console.log"

    if [ $UID == 0 ] ; then
      su $NEO4J_USER -c "\"$JAVACMD\" -cp '$CLASSPATH' $JAVA_OPTS \
        -Dneo4j.home=\"${NEO4J_HOME}\" -Dneo4j.instance=\"${NEO4J_INSTANCE}\" \
        -Dfile.encoding=UTF-8 \
        org.neo4j.server.Bootstrapper >> \"${CONSOLE_LOG}\" 2>&1 & echo \$! > \"$PID_FILE\" "
    else
      checkwriteaccess
      echo "WARNING: not changing user"
      "$JAVACMD" -cp "${CLASSPATH}" $JAVA_OPTS  \
        -Dneo4j.home="${NEO4J_HOME}" -Dneo4j.instance="${NEO4J_INSTANCE}" \
        -Dfile.encoding=UTF-8 \
        org.neo4j.server.Bootstrapper >> "${CONSOLE_LOG}" 2>&1 & echo $! > "${PID_FILE}"
    fi

    STARTED_PID=$( cat "$PID_FILE" )

    if [ "$org_neo4j_server_database_mode" = "HA" ] ; then
      if kill -0 $STARTED_PID 2>/dev/null ; then
        echo "HA instance started in process [$STARTED_PID]. Will be operational once connected to peers. See ${CONSOLE_LOG} for current status."
        exit 0
      else
        echo "HA instance was unable to start. See ${CONSOLE_LOG}."
        rm "$PID_FILE"
        exit 1
      fi
    fi

    echo -n "process [$STARTED_PID]"

	  if [ $WAIT = "true" ] ; then
	    echo -n "... waiting for server to be ready."
	    while kill -0 $STARTED_PID 2> /dev/null ; do
	      ## wait for start, pick up the server listening on the port
	      detectrunning
	      if [ $newpid ] ; then
	         break
	      fi

	      printf "."
	      sleep 1
	    done

	    if kill -0 $STARTED_PID 2>/dev/null ; then
	      if [ "$newpid" != "$STARTED_PID" ] ; then
		    rm "$PID_FILE"
	        kill -9 $STARTED_PID
	        echo " Failed to start within $TIMEOUT seconds."
	        echo "$FRIENDLY_NAME failed to start, please check the logs for details."
	        echo "If startup is blocked on a long recovery, use '$0 start-no-wait' to give the startup more time."
	        exit 2
	      fi

	      echo " OK."
        echo "http://localhost:$NEO4J_SERVER_PORT/ is ready."
	      exit 0
	    fi

	    echo " Failed to start within $TIMEOUT seconds."
	    echo "$FRIENDLY_NAME may have failed to start, please check the logs."
	    rm "$PID_FILE"
	    exit 1
    else
        echo "...Started the server in the background, returning..."
    fi
  else
    echo "$FRIENDLY_NAME already running with pid $NEO4J_PID"
    exit 0
  fi
}

console() {

  checkstatus
  checklimits

  if [ -z $NEO4J_PID ] ; then
    echo "Starting $FRIENDLY_NAME console-mode..."

    exitonnojava
    buildclasspath
    checkwriteaccess
    checkandrepairenv

    echo "Using additional JVM arguments: " $JAVA_OPTS

    "$JAVACMD" -cp "${CLASSPATH}" $JAVA_OPTS \
        -Dneo4j.home="${NEO4J_HOME}" -Dneo4j.instance="${NEO4J_INSTANCE}" \
        -Dfile.encoding=UTF-8 \
        org.neo4j.server.Bootstrapper

  else
    echo "$FRIENDLY_NAME already running with pid $NEO4J_PID"
    exit 1
  fi
}

# Modifies neo4j config to set the effective user when running as a service
# usage: modify_user_config <username> [true|false]
# pass in "true" for created to mark that the user was created (instead than pre-existing)
modify_user_config() {
  created=${2:-"false"}
  if `grep -q "wrapper\.user=" "$NEO4J_INSTANCE/conf/neo4j-wrapper.conf"` ; then
    sed -i -e "s/^.*wrapper\.user=.*$/wrapper\.user=$1/" "$NEO4J_INSTANCE/conf/neo4j-wrapper.conf"
  else
    echo "wrapper.user=$1" >> "$NEO4J_INSTANCE/conf/neo4j-wrapper.conf"
  fi

  if `grep -q "wrapper\.user\.created=" "$NEO4J_INSTANCE/conf/neo4j-wrapper.conf"` ; then
    sed -i -e "s/^.*wrapper\.user\.created=.*$/wrapper\.user\.created=${created}/" "$NEO4J_INSTANCE/conf/neo4j-wrapper.conf"
  else
    echo "wrapper.user.created=${created}" >> "$NEO4J_INSTANCE/conf/neo4j-wrapper.conf"
  fi
}

showinfo() {
  reportstatus

  exitonnojava
  buildclasspath

  echo "NEO4J_HOME:        $NEO4J_HOME"
  echo "NEO4J_SERVER_PORT: $NEO4J_SERVER_PORT"
  echo "NEO4J_INSTANCE:    $NEO4J_INSTANCE"
  echo "JAVA_HOME:         $JAVA_HOME"
  echo "JAVA_OPTS:         $JAVA_OPTS"
  echo "CLASSPATH:         $CLASSPATH"
}

# END FUNCTIONS
# BEGIN MAIN

# Parse option flags
while getopts "u:h" opt; do
  case $opt in
    h)
      echo "Running in headless (-h) mode" >&2
      HEADLESS=true
      ;;
    u)
      echo "Installing with user $OPTARG"
      DEFAULT_USER=$OPTARG
      ;;
    \?)
      echo "Invalid option: -$OPTARG" >&2
      exit 1
      ;;
    :)
      echo "Option -$OPTARG requires an argument." >&2
      exit 1
      ;;
  esac
done

case "${!OPTIND}" in
  console)
    console
    exit 0
    ;;

  start)
    WAIT=true
    startit
    ;;

  start-no-wait)
    WAIT=false
    startit
    exit 0
    ;;

  stop)
    stopit
    exit 0
    ;;

  restart)
    WAIT=true
    stopit
    startit
    exit 0
    ;;

  status)
    reportstatus
    exit 0
    ;;

  info)
    showinfo
    exit 0
    ;;
  install)
    echo "Legacy install now lives in the 'neo4j-installer' script"
    exit 1
    ;;
  remove)
    echo "Legacy remove now lives in the 'neo4j-installer' script"
    exit 1
    ;;
  *)
    echo "Usage: neo4j { console | start | start-no-wait | stop | restart | status | info | install | remove }"
    exit 0;;

esac

exit $?