#!/bin/bash

#====================================================================
# Script for LDAP Synchronization Connector
#
# Launch synchronize task with correct classpath
#
#                  ==LICENSE NOTICE==
#
# Copyright (c) 2008-2010, LSC Project
# All rights reserved.
#
# Redistribution and use in source and binary forms, with or without
# modification, are permitted provided that the following conditions are met:

#    * Redistributions of source code must retain the above copyright
# notice, this list of conditions and the following disclaimer.
#     * Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in the 
# documentation and/or other materials provided with the distribution.
#     * Neither the name of the LSC Project nor the names of its 
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
# 
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 
# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER
# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
#                  ==LICENSE NOTICE==
#
#                (C) 2008-2010 LSC Project
#             Clement OUDOT <clem@lsc-project.org>
#             Jonathan CLARKE <jon@lsc-project.org>
#
#====================================================================
# Possible exit codes:
#	- 0: success, LSC finished running
#	- 1: LSC seems to be already running, aborting
#	- 2: 'java' executable not found on PATH or in JAVA_HOME, aborting
#====================================================================

# work out where LSC lives
LSC_HOME=$(dirname "${BASH_SOURCE}")/..
if [ ${LSC_HOME:0:1} != "/" ] ; then
	LSC_HOME="${PWD}/${LSC_HOME}"
fi

#====================================================================
# Configuration
#====================================================================

CFG_DIR="$LSC_HOME/etc"
LIB_DIR="$LSC_HOME/lib"
COMPILER_DIR="$LSC_HOME/lib-compiler"

# Get configuration directory from command line
cfg_dir="${CFG_DIR}" # default value
while getopts "f:-:" opt > /dev/null 2>&1; do
  case "${opt}" in
    f)  cfg_dir=${OPTARG}
      ;;
    -)
        case "${OPTARG}" in
            config)
                cfg_dir="${!OPTIND}"; OPTIND=$(( $OPTIND + 1 ))
                ;;
            config=*)
                cfg_dir=${OPTARG#*=}
                ;;
        esac
        ;;
  esac
done

# Check if $cfg_dir is a file (/path/to/lsc/lsc.xml)
if [ -f "$cfg_dir" ]; then
    # get parent directory
    cfg_dir=$( dirname $cfg_dir )
fi

# Get logdir property from logback.xml
# Check if xmllint exists
if command -v xmllint >/dev/null 2>&1; then
    # Get logdir property from XML file by parsing it
    logdir=$( xmllint --xpath 'string(/configuration/property[@name="logdir"]/@value)' "${cfg_dir}/logback.xml" )
else
    # if xmllint not present, try to read the property anyway
    logdir=$( grep 'property[ ]\+name="logdir"' "${cfg_dir}/logback.xml" | grep -Fv '<!--' | sed -e 's/^.*value="\([^"]*\)".*$/\1/' )
fi
if [ "${logdir}" = "\${TMP_DIR}" ] || [ "${logdir}" = "\$TMP_DIR" ]; then
	# Create temp directory
	LOG_DIR="$( mktemp -d /tmp/lsc-$(date +%Y-%M-%d-%T).XXXXXXXXXX )"
	echo "Using temporary log directory: ${LOG_DIR}"
	# Pass LOG_DIR java system property with the temp directory value
	JAVA_OPTS="${JAVA_OPTS} -DTMP_DIR=${LOG_DIR}"
elif [ "${logdir}" = "" ]; then
	echo "WARN: empty log dir in logback.xml, using LOG_DIR=/tmp"
	LOG_DIR="/tmp"
else
	# Just use static value of logdir from logback.xml
	LOG_DIR="${logdir}"
	echo "Use static log directory: ${LOG_DIR}"
fi
LOG_FILE="$LOG_DIR/lsc.log"

# Create LOG_DIR in case LOG_DIR has been defined statically above
mkdir -p "$LOG_DIR"
if [ ! -d ${LOG_DIR} ]; then
	echo "ERROR: LOG_DIR ${LOG_DIR} does not exist!"
fi

PARAMETERS="$*"

#====================================================================
# Functions
#====================================================================
function log() {
	echo "$(date "+${DATE_FORMAT:-%Y/%m/%d %T}") [lsc] $1" >> "$LOG_FILE"
}

function fatal() {
	log $1
	echo "$(date "+${DATE_FORMAT:-%Y/%m/%d %T}") [lsc] $1" 1>&2
}

# Determine where the java exectuable is
function get_java() {
	# Do we have a JAVA_HOME environment variable?
	if [ "z" != "z${JAVA_HOME}" ]; then
		JAVA_COMMAND="${JAVA_HOME}/bin/java"
		return
	fi

	# Try java command on PATH as an alternative
	JAVA_COMMAND="$(which java 2>/dev/null)"
	if [ -e "$JAVA_COMMAND" ]; then return; fi

	# Nothing seems approprite, warn and exit
	fatal "No java executable found on PATH or in JAVA_HOME! Aborting."
	fatal "Define JAVA_HOME or adjust your PATH variable to include java."
	exit 2
}

function build_classpath() {
	# Force SLF4J API library before anything else !
	CLASSPATH="$CLASSPATH:.:$(ls $LIB_DIR/slf4j-api*.jar)"
	for jar in "$LIB_DIR"/*.jar
	do
		CLASSPATH="$CLASSPATH:$jar"
	done

	# is this Cygwin? if so, convert path to Windows format for the JVM
	CYGPATH_COMMAND="$(which cygpath 2>/dev/null)"
	if [ -e "$CYGPATH_COMMAND" ]; then
		CLASSPATH=$(cygpath -p -w "$CLASSPATH")
	fi

	export CLASSPATH
}

function build_parameters() {
	# Force configuration directory if no -f option
	echo "$PARAMETERS" | grep -- '-f ' > /dev/null 
	if [ $? != 0 ]; then
		PARAMETERS="$PARAMETERS -f $CFG_DIR"
	fi

	export PARAMETERS
}

# Function to know if the command will run a task
function is_run_command() {
	echo "$PARAMETERS" | grep -- '-c \|-s \|-a ' > /dev/null 
	if [ $? -eq 0 ]
	then
		return 1
	else
		return 0
	fi
}

# Java options for GraalVM
function build_graal_parameters() {

	JAVA_MAJOR_VERSION=$( ${JAVA_COMMAND} -version 2>&1 \
		| head -1 \
		| cut -d'"' -f2 \
		| sed 's/^1\.//' \
		| cut -d'.' -f1 )

	GRAAL_OPTS=""

	for jar in compiler compiler-management; do
		GRAAL_UPGRADE_MODULE_PATH="${GRAAL_UPGRADE_MODULE_PATH}:$( readlink -f ${COMPILER_DIR}/${jar}-[0-9.]*.jar )"
	done

	# Java >= 21
	if [ "${JAVA_MAJOR_VERSION}" -ge 21 ]; then

		GRAAL_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI"

		for jar in collections compiler compiler-management polyglot truffle-api truffle-compiler word; do
			GRAAL_MODULE_PATH="${GRAAL_MODULE_PATH}:$( readlink -f ${COMPILER_DIR}/${jar}-[0-9.]*.jar )"
		done

	else # Java 11, 17

		GRAAL_OPTS="-XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI -XX:+UseJVMCICompiler"

		for jar in graal-sdk truffle-api; do
			GRAAL_MODULE_PATH="${GRAAL_MODULE_PATH}:$( readlink -f ${COMPILER_DIR}/${jar}-[0-9.]*.jar )"
		done

	fi

	GRAAL_OPTS="${GRAAL_OPTS} --module-path=${GRAAL_MODULE_PATH}"
	GRAAL_OPTS="${GRAAL_OPTS} --upgrade-module-path=${GRAAL_UPGRADE_MODULE_PATH}"

	export GRAAL_OPTS

}

#====================================================================
# Main
#====================================================================

# check if we have java executable
get_java

# Do we reaaly run a task?
is_run_command
run_status=$?

# LSC start message
if [ $run_status -eq 1 ]
then
	log "Starting LSC"
fi

build_graal_parameters
JAVA_OPTS="$JAVA_OPTS ${GRAAL_OPTS}"

# JMX
for param in $PARAMETERS; do
	if [ "$param" == "-a" ]; then
		if [ -n "$LSC_JMXPORT" ]; then
			export JAVA_OPTS="$JAVA_OPTS -Dcom.sun.management.jmxremote=true -Dcom.sun.management.jmxremote.port=$LSC_JMXPORT -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false"
			log "Using JMX port $LSC_JMXPORT"
		else
			echo "LSC: to control your asynchronous task(s), consider setting the LSC_JMXPORT "
			echo "environment variable to a positive value to bind the JMX interface to that "
			echo "TCP port."
			log "JMX not activated"
		fi
	fi
done

build_classpath
build_parameters
"${JAVA_COMMAND}" $JAVA_OPTS -cp "$CLASSPATH" org.lsc.Launcher $PARAMETERS

status=$?

# LSC stop message
if [ $run_status -eq 1 ]
then
	log "LSC finished running"
fi

echo "LSC has used LOG_DIR=\"${LOG_DIR}\""

#====================================================================
# Exit
#====================================================================
exit $status
