#!/bin/bash


#
# Copyright (c) 2025 Broadcom Inc. and its subsidiaries. All Rights Reserved.
#

########################################################################################################################
# Constants
########################################################################################################################

DEFAULT_DISKLESS_CONFIG="true"
DEFAULT_SSG_JVM_HEAP="2g"
DEFAULT_DERBY_ARGS="-Dderby.locks.deadlockTimeout=45 -Dderby.storage.pageCacheSize=7500 -Dderby.language.sequence.preallocator=2500 -Dderby.language.statementCacheSize=150 -Dderby.storage.pageSize=32768 -Dcom.l7tech.server.derbyPrefix=memory:"

# Default number of seconds that this script will wait for the Gateway database to be available.
DEFAULT_SSG_DATABASE_WAIT_TIMEOUT="300"

DEFAULT_SSG_GC_ARGS="-Xlog:gc*:/opt/SecureSpan/Gateway/node/default/var/logs/ssg_gc.log"

ADD_OPENS_ARGS="--add-opens jdk.crypto.ec/sun.security.ec=ALL-UNNAMED --add-opens java.base/java.lang=ALL-UNNAMED"
ADD_EXPORTS_ARGS="--add-exports java.security.jgss/sun.security.jgss=ALL-UNNAMED \
	--add-exports java.security.jgss/sun.security.jgss.krb5=ALL-UNNAMED \
	--add-exports java.security.jgss/sun.security.krb5=ALL-UNNAMED \
	--add-exports java.security.jgss/sun.security.krb5.internal=ALL-UNNAMED \
	--add-exports java.security.jgss/sun.security.krb5.internal.ktab=ALL-UNNAMED \
	--add-exports java.xml/com.sun.org.apache.xerces.internal.jaxp=ALL-UNNAMED \
	--add-exports java.base/sun.security.internal.spec=ALL-UNNAMED \
	--add-exports java.naming/com.sun.jndi.ldap=ALL-UNNAMED \
	--add-exports java.base/sun.security.provider.certpath=ALL-UNNAMED \
	--add-exports java.base/sun.security.ssl=ALL-UNNAMED \
	--add-exports java.base/sun.security.util=ALL-UNNAMED"
HAZELCAST_ARGS="--add-modules java.se --add-exports java.base/jdk.internal.ref=ALL-UNNAMED --add-opens java.base/java.nio=ALL-UNNAMED --add-opens java.base/sun.nio.ch=ALL-UNNAMED --add-opens java.management/sun.management=ALL-UNNAMED --add-opens jdk.management/com.sun.management.internal=ALL-UNNAMED -Dhazelcast.ignoreXxeProtectionFailures=true"

NODE_PROPERTIES_FILE_PATH="/opt/SecureSpan/Gateway/node/default/etc/conf/node.properties"
########################################################################################################################
# Functions
########################################################################################################################

error() {
	# Send errors to stderr in case these get handled differently by the container PaaS on which this runs
	echo "ERROR - ${1}" 1>&2
	exit 1
}

# While this looks redundant, it allows derived image to override where these messages go.
info() {
	echo "${1}"
}

generateRandomHexString() {
	BYTES_TO_GEN="$1"
	[ "${BYTES_TO_GEN}" == "" ] && error "In generateRandomHexString(): need to be given the number of bytes to generate."
	(echo "${BYTES_TO_GEN}" | grep '^[::digit:]]\+$' &> /dev/null) && error "In generateRandomHexString(): need to be given a number."
	
	dd if=/dev/urandom bs=1 count=${BYTES_TO_GEN} status=none | od -vt x1 -An | tr -d ' \n'
}

retrievePropertyValueFromNodePropertiesFile() {
  properties=$(cat "$NODE_PROPERTIES_FILE_PATH")
  echo "${properties}" | grep ${1} | tr -d ' ' | cut -d "=" -f2-
}

loadFromNodeProperties() {
	echo "Retrieve values from node.properties"
	## Gateway values
	ssm_username=$(retrievePropertyValueFromNodePropertiesFile "admin.user")
	ssm_pass=$(retrievePropertyValueFromNodePropertiesFile "admin.pass")
	cluster_pass=$(retrievePropertyValueFromNodePropertiesFile "cluster.pass")

	## DB related values
	db_user=$(retrievePropertyValueFromNodePropertiesFile "node.db.config.main.user")
	db_pass=$(retrievePropertyValueFromNodePropertiesFile "node.db.config.main.pass")
	db_type=$(retrievePropertyValueFromNodePropertiesFile "node.db.type")
	db_jdbc_url=$(retrievePropertyValueFromNodePropertiesFile "l7.mysql.connection.url")

	if [ "${db_type}" == "derby" ] && [ "${db_user}" != '' ]; then
		db_jdbc_url=""
	elif [ "${db_type}" != "derby" ] && [ -n "${db_jdbc_url}" ]; then
		info 'l7.mysql.connection.url is non-empty'
	else
		error 'invalid node.properties'
	fi

}

validateStringVariableAgainstAllowedList() {
	[ -n "$(echo ${1} | tr -d '[:alnum:]!@.=\-_^+;:#,%')" ] && error $2' may only contain characters from the set "!@.=-_^+;:#,%" as well as alphanumeric ASCII characters.'
}

validateStringVariableContainsDigitFollowByUnit() {
	if [ -n "${1}" ]; then
		if (! echo "${1}" | grep '^[[:digit:]]\+[kKmMgG]$' &> /dev/null); then
			error "Invalid value provide for ${1}. It must be digits followed by one of the characters k, K, m, M, g, or G."
		fi
	fi
}

configureGateway() {
	# When checking certain env vars below, rather than using grep we used tr to remove illegal characters and checked for equality
	# This was done to avoid having to use a heavily escaped regular expression

	# Check the heap size for the Gateway's JVM
	if [ -n "${SSG_JVM_HEAP}" ]; then
		info "SSG_JVM_HEAP has been deprecated! Please use SSG_JVM_MIN_HEAP and SSG_JVM_MAX_HEAP going forward."
		validateStringVariableContainsDigitFollowByUnit ${SSG_JVM_HEAP}
	fi
	validateStringVariableContainsDigitFollowByUnit ${SSG_JVM_MIN_HEAP}
	validateStringVariableContainsDigitFollowByUnit ${SSG_JVM_MAX_HEAP}


	if [ -z "${SSG_JVM_MIN_HEAP}" ]; then
		SSG_JVM_MIN_HEAP="${SSG_JVM_HEAP:-${DEFAULT_SSG_JVM_HEAP}}"
	fi
	info "SSG_JVM_MIN_HEAP will be ${SSG_JVM_MIN_HEAP}"
	if [ -z "${SSG_JVM_MAX_HEAP}" ]; then
		SSG_JVM_MAX_HEAP="${SSG_JVM_HEAP:-${DEFAULT_SSG_JVM_HEAP}}"
	fi
	info "SSG_JVM_MAX_HEAP will be ${SSG_JVM_MAX_HEAP}"

	if [ -z "${env_jdbc_url}" ]; then
		info "Using Derby database"
		export SSG_DATABASE_TYPE="derby"
		DERBY_ARGS="${DEFAULT_DERBY_ARGS}"
	else
		info "Using MySQL database ${env_jdbc_url}"
		# SSG_DATABASE_TYPE (derby or mysql, mysql default)
		export SSG_DATABASE_TYPE="mysql"
		# Set DERBY_ARGS to empty when using mysql
		DERBY_ARGS=""
		# How long to wait for the MySQL server to be available (in seconds)
		SSG_DATABASE_WAIT_TIMEOUT="${SSG_DATABASE_WAIT_TIMEOUT:-${DEFAULT_SSG_DATABASE_WAIT_TIMEOUT}}"
		info "SSG_DATABASE_WAIT_TIMEOUT set to ${SSG_DATABASE_WAIT_TIMEOUT} seconds."
		# set UTF8 related settings if the user doesn't provide them
		( echo "${env_jdbc_url}" | grep '?' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}?characterEncoding=UTF8&characterSetResults=UTF8"
		( echo "${env_jdbc_url}" | grep '?$' &> /dev/null ) && env_jdbc_url="${env_jdbc_url}characterEncoding=UTF8&characterSetResults=UTF8"
		( echo "${env_jdbc_url}" | grep 'characterEncoding' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&characterEncoding=UTF8"
		( echo "${env_jdbc_url}" | grep 'characterSetResults' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&characterSetResults=UTF8"
		# set useSSL to false if not specified, due to excessive warnings logged after mysql connector upgrade
		( echo "${env_jdbc_url}" | grep 'useSSL' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&useSSL=false"
		( echo "${env_jdbc_url}" | grep 'openTelemetry' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&openTelemetry=DISABLED"
	fi

	# Check the Gateway admin settings if provided
	if [ -n "${env_ssm_username}" ]; then
		validateStringVariableAgainstAllowedList ${env_ssm_username} 'Gateway admin user'
	fi
	if [ -n "${env_ssm_pass}" ]; then
		validateStringVariableAgainstAllowedList ${env_ssm_pass} 'Gateway admin user pass'
	fi

	if [ "${SSG_DATABASE_TYPE}" = "mysql" ]; then
		[ -z ${env_db_user} ] && error "Database user not declared."
		[ -z ${env_db_pass} ] && error "Database user pass not declared ."
		validateStringVariableAgainstAllowedList ${env_db_user} 'Database user'
		validateStringVariableAgainstAllowedList ${env_db_pass} 'Database user pass'

		[ -z "${SSG_DATABASE_WAIT_TIMEOUT}" ] && info "SSG_DATABASE_WAIT_TIMEOUT not set."
		(echo "${SSG_DATABASE_WAIT_TIMEOUT}" | grep '^[[:digit:]]*$' &>/dev/null) || error "Value provided for SSG_DATABASE_WAIT_TIMEOUT is not an integer"
		(echo "${env_jdbc_url}" | grep -F 'characterEncoding=UTF8' &> /dev/null ) || error "Value provided for node.db.config.main.host does not set the characterEncoding to UTF8"
		(echo "${env_jdbc_url}" | grep -F 'characterSetResults=UTF8'&> /dev/null ) || error "Value provided for node.db.config.main.host does not set the characterSetResults to UTF8"
	fi

	# Check Gateway cluster_pass settings
	[ "${SSG_DATABASE_TYPE}" = "mysql" ] && [ -z "${env_cluster_pass}" ] && error "cluster pass must be set when using a MySQL database."

	# Only do string validation for allowed symbols when the cluster password comes from the ENV. Ignore when it comes from node.properties
	if [ -n "${SSG_CLUSTER_PASSWORD}" ]; then
		validateStringVariableAgainstAllowedList ${SSG_CLUSTER_PASSWORD} 'SSG_CLUSTER_PASSWORD'
	fi

	setClusterHost

	# tests for compliance with hostnames as defined in RFC 952 and section 2.1 of RFC 1123
	[ -z "${SSG_CLUSTER_HOST}" ] && error "SSG_CLUSTER_HOST environment variable not set. This is required when the SSG_DATABASE_JDBC_URL env var is used."
	(echo "${SSG_CLUSTER_HOST}" | grep -E '^(([[:alnum:]]|[[:alnum:]][[:alnum:]\-]*[[:alnum:]])\.)*([[:alnum:]]|[[:alnum:]][[:alnum:]\-]*[[:alnum:]])$' &>/dev/null) || error "SSG_CLUSTER_HOST doesn't look like a hostname or FQDN"
	createAndUpdateMySQLDatabase $SSG_DATABASE_TYPE $env_jdbc_url $env_db_user $env_db_pass

	# JDBC url is the only user supplied ENV that we modify. Here we are making sure the latest url value is properly reflected in SSG_DATABASE_JDBC_URL when DISKLESS_CONFIG='true'
	if [ "${DISKLESS_CONFIG}" == "true" ]; then
		export SSG_DATABASE_JDBC_URL="${env_jdbc_url}"
	fi
}

setEnvVars() {
	# Set local ENV variables based on the ENV
	env_ssm_username=${SSG_ADMIN_USERNAME}
	env_ssm_pass=${SSG_ADMIN_PASSWORD}
	env_db_user=${SSG_DATABASE_USER}
	env_db_pass=${SSG_DATABASE_PASSWORD}
	env_cluster_pass=${SSG_CLUSTER_PASSWORD}
	env_jdbc_url=${SSG_DATABASE_JDBC_URL}
	export DISKLESS_CONFIG="${DISKLESS_CONFIG:-${DEFAULT_DISKLESS_CONFIG}}"

	# When DISKLESS_CONFIG is false, use the node.properties to override the local ENV
	# NOTE: moved some of the setEnvVars ops here. When node.properties is mounted via secretstore csi driver or secret mount it will not be writable.
	if [ "${DISKLESS_CONFIG}" == "false" ]; then
		loadFromNodeProperties
		env_ssm_username=$ssm_username
		env_ssm_pass=$ssm_pass
		env_db_user=$db_user
		env_db_pass=$db_pass
		env_cluster_pass=$cluster_pass
		env_jdbc_url=$db_jdbc_url
	fi

	# Check if EXTRA_JAVA_ARGS contains any arguments from DEFAULT_SSG_GC_ARGS
	extraHasSsgDefaultGcArg=false
	for defaultSsgGcArg in $DEFAULT_SSG_GC_ARGS; do
		case "$EXTRA_JAVA_ARGS" in
			*$defaultSsgGcArg*)
				extraHasSsgDefaultGcArg=true
				break
			;;
		esac;
	done

	# If EXTRA_JAVA_ARGS has no duplicate argument (needed for backwards compatibility and to avoid unexpected jvm behaviour)
	if [ "${extraHasSsgDefaultGcArg}" == false ]; then
		# If SSG_GC_ARGS is empty (so user can optionally override). Set to " " (single space) to turn off ssg gc defaults (e.g. revert to jvm defaults)
		if [ -z "${SSG_GC_ARGS}" ]; then
			SSG_GC_ARGS="${DEFAULT_SSG_GC_ARGS}"
		fi
	fi
	info "SSG_GC_ARGS will be ${SSG_GC_ARGS}"
}

setFIPSMode() {
      	# Turn on fips mode if com.l7tech.security.fips.enabled=true is found in EXTRA_JAVA_ARGS or system.properties
    	fips_enabled=false

    	for extra_java_arg in $EXTRA_JAVA_ARGS; do
      		if [ "$(echo "${extra_java_arg}" | tr '[:upper:]' '[:lower:]')" == "-dcom.l7tech.security.fips.enabled=true" ]; then
        		info "The system property 'com.l7tech.security.fips.enabled' has been set to true in the EXTRA_JAVA_ARGS environment variable."
        		fips_enabled=true
        		break
      		fi
    	done

  	SYSTEM_PROPERTIES_FILE=$GATEWAY_DIR/node/default/etc/conf/system.properties
  	if grep -qi "^\s*com.l7tech.security.fips.enabled\s*=\s*true\s*$" "$SYSTEM_PROPERTIES_FILE"; then
  	  	info "The system property 'com.l7tech.security.fips.enabled' has been set to true in the system.properties file."
  	  	fips_enabled=true
  	fi

  	if $fips_enabled; then
  	  	info "Enabling FIPS mode."
      		export BC_LIBRARY_PATH=$GATEWAY_DIR/runtime/bcfips
    	else
    	  	info "The system property 'com.l7tech.security.fips.enabled' has not been set to true in either the EXTRA_JAVA_ARGS environment variable or the system.properties file."
      	  	info "Disabling FIPS mode."
      		export BC_LIBRARY_PATH=$GATEWAY_DIR/runtime/bc
  	fi
}

createAndUpdateMySQLDatabase() {
	ADMIN_CONFIGURED="true"
		
	if [ "${SSG_DATABASE_TYPE}" == "mysql" ]; then
		echo "Creating MySQL Database"
		# these settings are just used for the code below (waiting for the database to come up and the Liquibase calls)
		( echo "${env_jdbc_url}" | grep 'autoReconnect' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&autoReconnect=false"
		( echo "${env_jdbc_url}" | grep 'createDatabaseIfNotExist' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&createDatabaseIfNotExist=true"
		( echo "${env_jdbc_url}" | grep 'socketTimeout' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&socketTimeout=600000"
		( echo "${env_jdbc_url}" | grep 'connectTimeout' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&connectTimeout=10000"
		# This is required to retrieve public key in case of MySQL8 'caching_sha2_password' authentication plugin is used.
		( echo "${env_jdbc_url}" | grep 'allowPublicKeyRetrieval' &> /dev/null ) || env_jdbc_url="${env_jdbc_url}&allowPublicKeyRetrieval=true"
		LIQUIBASE_JAR=`ls ${GATEWAY_DIR}/runtime/lib/liquibase-*jar`
		MYSQL_CONNECTOR_JAR=`ls ${GATEWAY_DIR}/runtime/lib/mysql-connector-j*jar`
		LOG_BACK_JARS=`ls ${GATEWAY_DIR}/config/etc/db/lib/logback-*jar`
		SLF4J_JAR=`ls ${GATEWAY_DIR}/runtime/lib/slf4j-api-*jar`
		PICOCLI_JAR=`ls ${GATEWAY_DIR}/runtime/lib/picocli-*.jar`
		SNAKEYAML_JAR=`ls ${GATEWAY_DIR}/runtime/lib/snakeyaml-*.jar`
		OPENCSV_JAR=`ls ${GATEWAY_DIR}/runtime/lib/opencsv-*.jar`
		# temporary working directory, to be deleted afterwards
		LIQUIBASE_WORK_DIR=/tmp/liquibaseTemp
		mkdir -p ${LIQUIBASE_WORK_DIR}/lib
		mkdir -p ${LIQUIBASE_WORK_DIR}/internal/lib # newer liquibase expected directory structure
		LIQUIBASE_WORK_JAR=${LIQUIBASE_WORK_DIR}/internal/lib/liquibase-core.jar
		cp ${LIQUIBASE_JAR} ${LIQUIBASE_WORK_JAR}
		cp ${LOG_BACK_JARS} ${LIQUIBASE_WORK_DIR}/lib/
		cp ${SLF4J_JAR} ${LIQUIBASE_WORK_DIR}/lib/
		cp ${MYSQL_CONNECTOR_JAR} ${LIQUIBASE_WORK_DIR}/lib/
		cp ${PICOCLI_JAR} ${LIQUIBASE_WORK_DIR}/lib/ # required for liquibase CLI commands
		cp ${SNAKEYAML_JAR} ${LIQUIBASE_WORK_DIR}/lib/ # required for liquibase log-level
		cp ${OPENCSV_JAR} ${LIQUIBASE_WORK_DIR}/lib/ # required for liquibase log-level

		cd ${LIQUIBASE_WORK_DIR}
		LIQUIBASE_JARS_CP=$(ls -1 "${LIQUIBASE_WORK_DIR}/lib"/*.jar 2>/dev/null | paste -sd:)
		LIQUIBASE_CP="${LIQUIBASE_JARS_CP}:${GATEWAY_DIR}/config/etc/db"
		LIQUIBASE="java -jar ${LIQUIBASE_WORK_JAR} --driver=com.mysql.cj.jdbc.Driver \
			--classpath=${LIQUIBASE_CP} \
			--changeLogFile=ssg.xml \
			--url=${env_jdbc_url} \
			--username=${env_db_user} \
			--password=${env_db_pass} \
			${LIQUIBASE_ARGS}"

		export LIQUIBASE_HOME="${LIQUIBASE_WORK_DIR}"

		# Append logLevel when env var is non-zero length
		if [ -n "${LIQUIBASE_LOG_LEVEL}" ]; then
			LIQUIBASE="$LIQUIBASE --logLevel=${LIQUIBASE_LOG_LEVEL}"
		fi

		# Wait until any of the MySQL servers are available
		info "Waiting for one of the databases to come up..."
		TIMEOUT_TIMESTAMP=$(date --date="${SSG_DATABASE_WAIT_TIMEOUT} sec" '+%s')
		until $LIQUIBASE listLocks &>/dev/null; do
			CURRENT_TIMESTAMP=$(date '+%s')
			if [ "${CURRENT_TIMESTAMP}" -gt "${TIMEOUT_TIMESTAMP}" ]; then
				error "Timed out while waiting for database to come up"
			fi
			/bin/sleep 1
		done
		### Determine if admin user needs to be created ###
		UNRUN_CHANGESETS=$($LIQUIBASE status --verbose)
		for CHANGESET in ${UNRUN_CHANGESETS}; do
			# look for changeset id "1408665436018-7", which adds the admin user to the internal_user table
			if [[ $CHANGESET == *"ssg-data.xml::1408665436018-7::gateway" ]]; then
				ADMIN_CONFIGURED="false"
				break
			fi
		done
		### Do update ###
		$LIQUIBASE update
		if [ "$?" != "0" ]; then
			error "Failed to create or update the Gateway's database"
		fi
		cd
		rm -rf ${LIQUIBASE_WORK_DIR}
	else
		ADMIN_CONFIGURED="false"
	fi
}


acceptLicense(){
	[ "${ACCEPT_LICENSE}" == "true" ] || error "License not accepted (environment variable ACCEPT_LICENSE=${ACCEPT_LICENSE})"
}

configureAdminUser() {
	### Ensure the admin user is configured ###
	if [ "${ADMIN_CONFIGURED}" == "false" ]; then
		# Override the built-in admin user
		DEF_PASS=$(generateRandomHexString 64)
		env_ssm_pass="${env_ssm_pass:-${DEF_PASS}}"

		DEF_ADMIN_USERNAME=$(generateRandomHexString 64)
		env_ssm_username="${env_ssm_username:-${DEF_ADMIN_USERNAME}}"

		UPDATE_ADMIN_TEMPLATE=$(sed -e "s~SSG_ADMIN_USERNAME~${env_ssm_username}~g" -e "s~SSG_ADMIN_PASSWORD~${env_ssm_pass}~g" /opt/docker/rc.d/base/update_admin_user.xml)
		echo "${UPDATE_ADMIN_TEMPLATE}" > ${GATEWAY_DIR}/node/default/etc/bootstrap/bundle/001_update_admin_user.xml.req.bundle
	fi
}

# When SSG_DATABASE_TYPE='derby' and SSG_CLUSTER_HOST is not declared, a default value is set
# set the cluster hostname to the hostname of the container, not the host on which it runs in
# Do nothing when SSG_DATABASE_TYPE is 'mysql'
setClusterHost() {
	if [ "${SSG_DATABASE_TYPE}" = "derby" ]; then
		SSG_CLUSTER_HOST="${SSG_CLUSTER_HOST:-$(uname -n)}"
	fi
	info "SSG_CLUSTER_HOST will be ${SSG_CLUSTER_HOST}"
}

updateClusterHost() {
	UPDATE_CLUSTER_HOSTNAME=$(sed -e "s~CLUSTER_HOST_VALUE~${SSG_CLUSTER_HOST}~g" /opt/docker/rc.d/base/update_cluster_host.xml)
	echo "${UPDATE_CLUSTER_HOSTNAME}" > ${GATEWAY_DIR}/node/default/etc/bootstrap/bundle/010_update_cluster_host.xml.req.bundle
}

expandGW7Packages() {
	for i in /opt/docker/rc.d/*.gw7; do
		if [ -r "${i}" ]; then
			info "Expanding GW7 Package ${i}"
			/bin/tar zx --no-overwrite-dir -f  ${i}
			if [ $? -ne 0 ]; then
				error "Failed expanding GW7 package: ${i}"
			fi
		fi
	done
	unset i
}

runGatewayPreBootScripts() {
	# Let derived images tweak stuff before Gateway starts by dropping scripts into /opt/docker/rc.d/
	for i in /opt/docker/rc.d/*.sh; do
		if [ -r "${i}" ]; then
			info "Running script ${i}"
			/bin/sh ${i}
			if [ $? -ne 0 ]; then
				error "Failed executing the script: ${i}"
			fi
		fi
	done
	unset i
}

startGateway() {
	info "Starting gateway in foreground"
	touch /opt/SecureSpan/Gateway/node/default/var/preboot
	cd "${GATEWAY_DIR}/runtime"
	# sun.net.inetaddr.ttl and java.util.Arrays.useLegacyMergeSort are system properties that are read during
	# JVM start up and need to be specified as command line args to make sure the values are used.
	# DE471594: fixed by redirecting STDERR to STDOUT (2>&1) in container
	exec java \
		-Xms${SSG_JVM_MIN_HEAP} \
		-Xmx${SSG_JVM_MAX_HEAP} \
		-XX:+TieredCompilation \
		-Dcom.l7tech.disklessConfig=${DISKLESS_CONFIG} \
		-Dcom.l7tech.server.sm.noSecurityManager=true \
		-Dcom.l7tech.server.log.console=true \
		-Dcom.l7tech.server.log.console.extraCats="AUDIT,LOG" \
		-Dfile.encoding='UTF-8' \
		-Djava.net.preferIPv4Stack=true \
		-Djava.security.egd=file:/dev/./urandom \
		-Dcom.l7tech.server.defaultClusterHostname="${SSG_CLUSTER_HOST}" \
		-Dcom.l7tech.gateway.remoting.connectionTimeout=500 \
		-classpath "${JAVA_HOME}/lib/ext/*:${GATEWAY_DIR}/runtime/lib/ext/*:${GATEWAY_DIR}/runtime/Gateway.jar:${BC_LIBRARY_PATH}/*" \
		-Dcom.l7tech.server.components=uddi \
		-Dcom.l7tech.bootstrap.env.sslkey.enable=true \
		-Dcom.l7tech.bootstrap.license.require=true \
		-Dcom.l7tech.server.disableFileLogsinks=true \
		-Dsun.net.inetaddr.ttl=30 \
		-Djava.util.Arrays.useLegacyMergesort=true \
		-Djava.security.properties="${GATEWAY_DIR}/runtime/etc/ssg.security" \
		${ADD_OPENS_ARGS} \
		${ADD_EXPORTS_ARGS} \
		${HAZELCAST_ARGS} \
		${SSG_GC_ARGS} \
		${DERBY_ARGS} \
		${EXTRA_JAVA_ARGS} \
		com.l7tech.server.boot.GatewayMain \
	2>&1
}

########################################################################################################################
# Main
########################################################################################################################

acceptLicense
setEnvVars
setFIPSMode
configureGateway
configureAdminUser
updateClusterHost
expandGW7Packages
runGatewayPreBootScripts
startGateway
