#!/bin/bash

# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#
# Ldap Synchronization Connector provides tools to synchronize electronic
# identities from a list of data sources including any database with a JDBC
# connector, another LDAP directory, flat files...
#
# LSC automatically embeds HSQLDB library. So, this script can:
# - Create a table from a CSV file header in a HSQLDB database;
# - Inject CSV data into a HSQLDB database;
# - Read data from a HSQLDB database table.
#
# ---------------------------------------------------------------------------------
#
# Copyright (c) 2008 - 2025 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.
#
#       (c) 2008 - 2025 LSC Project
#   Sebastien Bahloul <seb@lsc-project.org>
#   Thomas Chemineau <thomas@lsc-project.org>
#   Jonathan Clarke <jon@lsc-project.org>
#   Remy-Christophe Schermesser <rcs@lsc-project.org>
#   David Coutadeur <david.coutadeur@gmail.com>
#
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

# ---------------------------------------------------------------------------------
# CONFIGURATION
# ---------------------------------------------------------------------------------

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

LSC_LIB_DIR="${SAMPLE_HOME}/../../lib"
LSC_BIN_DIR="${SAMPLE_HOME}/../../bin"

# HSQLDB jar file
[ -z "$HSQLDB_LIB" -a -e "${LSC_LIB_DIR}"/hsqldb*.jar ] && HSQLDB_LIB=$( readlink -f "${LSC_LIB_DIR}"/hsqldb*.jar )
[ -z "$HSQLDB_LIB" ] && echo "hsqldb driver (hsqldb*.jar) is missing" && exit 1
# Temporary directory so that HSQLDB server could store files
HSQLDB_DIR="/tmp/lsc/hsqldb"
# HSQLDB configuration file
HSQLDB_RC="${SAMPLE_HOME}/etc/hsqldb.rc"
# Table name
HSQLDB_TABLE="csvdata"
# Default CSV separator
CSV_SEPARATOR=";"

# ---------------------------------------------------------------------------------
# FUNCTIONS
# ---------------------------------------------------------------------------------

#
# Drop all data from the HSQLDB instance.
#
data_drop()
{
  hsqldb_sqlQuery "DROP TABLE $HSQLDB_TABLE; SHUTDOWN;"
}

#
# Create the SQL table into the HSQLDB database. All field are read from the first
# line of the CSV file passed in the first parameter. Once the table is created,
# data should be correctly imported.
#
data_import()
{
  # $1 : CSV fullpath
  # $2 : CSV separator
  HSQLDB_TABLEDEF=""
  IFSO=$IFS
  IFS=$2
  for field in `head -n 1 $1`; do
    if [ -n "$HSQLDB_TABLEDEF" ]; then
      HSQLDB_TABLEDEF="$HSQLDB_TABLEDEF, $field VARCHAR"
    else
      HSQLDB_TABLEDEF="$field VARCHAR"
    fi
  done
  IFS=$IOFS
	mkdir -p $HSQLDB_DIR
  if [ -n "$HSQLDB_TABLEDEF" ]; then
    hsqldb_sqlQuery "CREATE TEXT TABLE $HSQLDB_TABLE ($HSQLDB_TABLEDEF); SHUTDOWN;"
    if [ $? -eq 0 ]; then
	  echo "Table $HSQLDB_TABLE created"
      nblines=`cat $1 | wc -l`
      let nblines--
			
      tail -n $nblines $1 > $HSQLDB_DIR/`basename $1`
      sep=`hsqldb_checkCsvSeparator $2`
		encoding=`file $1  2> /dev/null | cut -d' ' -f2`
		if [ "x$encoding" == "xUTF-8" ] ; then
			hsqldb_sqlQuery "SET TABLE $HSQLDB_TABLE SOURCE \"`basename $1`;fs=$sep;encoding=UTF-8\"; SHUTDOWN;" > /dev/null 2>&1
		else
			hsqldb_sqlQuery "SET TABLE $HSQLDB_TABLE SOURCE \"`basename $1`;fs=$sep\"; SHUTDOWN;" > /dev/null 2>&1
		fi
	  if [ $? -eq 0 ]; then
		  echo "$nblines lines added to table $HSQLDB_TABLE"
		  return
	  fi
    fi
  fi
  exit 1
}

#
# Show data from the HSQLDB instance.
#
data_show()
{
  hsqldb_sqlQuery "SELECT * FROM $HSQLDB_TABLE;"
}

#
# Return the CSV separator used by hsqldb.
#
hsqldb_checkCsvSeparator()
{
  # $1 : A separator
  case "$1" in
    ";")
      echo -n "\semi"
      ;;
    "\"")
      echo -n "\quote"
      ;;
    " ")
      echo -n "\space"
      ;;
    "'")
      echo -n "\apos"
      ;;
    *)
      echo -n $1
      ;;
  esac
}

#
# Remove all data on disk that have been created by an hsqldb server. No checks
# on a running process are performed, so be carefull.
#
hsqldb_cleanData()
{
  oldpwd=`pwd`
  cd ${HSQLDB_DIR} > /dev/null 2>&1
  if [ $? -eq 0 ]; then
    rm -f *
    cd ..
    rmdir `basename "${HSQLDB_DIR}"`
  fi
  cd ${oldpwd}
}

#
# Perform a SQL query on the running HSQLDB instance. No checks on a running
# process are performed, so be carefull.
#
hsqldb_sqlQuery()
{
  # $1 : sql query

	# check if we have java executable
	get_java

	"${JAVA_COMMAND}" -jar "$HSQLDB_LIB" --rcFile "$HSQLDB_RC" --sql "$1" lscdb
}

# 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
    log "No java executable found on PATH or in JAVA_HOME! Aborting."
    log "Define JAVA_HOME or adjust your PATH variable to include java."
    exit 2
}

run_java_command()
{
	# check if we have java executable
	get_java

	for jar in "${LSC_LIB_DIR}"/*.jar; do
		LDAPCP="$LDAPCP:$jar"
	done

	"${JAVA_COMMAND}" \
		-cp "$LDAPCP" \
		--add-exports java.base/sun.security.tools.keytool=ALL-UNNAMED \
		--add-exports java.base/sun.security.x509=ALL-UNNAMED $1
}

start_ldap() {
	echo "Starting LDAP server on ldap://localhost:33389/ ..."
	run_java_command "org.lsc.opendj.LdapServer -a -f ${CONFIGPATH}"
}

run() {
	command="\"${LSC_BIN_DIR}/lsc\" --config \"$CONFIGPATH\" --synchronize all --clean all"
	echo "Running $command"
	eval "${command}"
}

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

# -- Check script parameters --

ACTIONS=""

case "$1" in
  "--drop")
    ACTIONS="$ACTIONS dropdata"
    shift
    ;;
  "--import")
    shift
    CSV_FILE="$1"
    shift
    if [ "$1" != "" ]; then
      CSV_SEPARATOR="$1"
      shift
    fi
    ACTIONS="$ACTIONS cleandata importdata"
    ;;
  "--show")
    ACTIONS="$ACTIONS showdata"
    shift
    ;;
  "--start-ldap-server")
    ACTIONS="$ACTIONS startldap"
	shift
	;;
  "--run")
	run
	shift
	;;
  "--clean")
	ACTIONS="$ACTIONS cleandata cleanldapdata"
	shift
	;;
  "--help"|*)
    echo ""
    echo " $0 <option>"
    echo ""
    echo " One option from available options is:"
    echo "   --import <file> [<separator>]    Import data from CSV file"
    echo "   --show    Show data from database"
    echo "   --drop    Drop the table $HSQLDB_TABLE from database"
    echo "   --start-ldap-server    Launch an embedded OpenDJ LDAP server"
    echo "   --run     Run the synchronization task"
	echo "   --clean   Remove all files from disk"
    echo "   --help    Print informations"
    echo ""
    exit 1
    ;;
esac

# -- Run actions --

for action in $ACTIONS; do
  case "$action" in
    "dropdata")
      data_drop
      ;;
    "importdata")
      if [ ! -e "$CSV_FILE" ]; then
        echo " Error - file '$1' not found"
        exit 1
      fi
      data_import "$CSV_FILE" "$CSV_SEPARATOR"
      ;;
    "showdata")
      data_show
      ;;
    "startldap")
      start_ldap
      ;;
    "cleandata")
      hsqldb_cleanData
      ;;
    "cleanldapdata")
      rm -rf /tmp/opendj-test
      ;;
  esac
done

