#!/bin/sh
#
#
#ident "@(#)smreg	1.80 07/05/08 SMI"
# Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
# All Rights Reserved.

################################################################################
##
## This script registers objects with the Sun
## Java(TM) Web Console.
##
################################################################################

umask 022

################################################################################
#
# Platform prefix path variables
#
################################################################################

# These path prefixes are set on a per platform basis by the console build!
PLATFORM_CONF_PATH=/etc/webconsole
PLATFORM_BASE_PATH=/var/webconsole

################################################################################
#
# Globals Variables
#
################################################################################

## Return codes
EXIT_SUCCESS=0
EXIT_USAGE=1		# missing/malformed arguments
EXIT_FAILURE=2		# error in files or directories
EXIT_UNKNOWNOS=3	# can't determine OS we're running on
EXIT_BADOS=4		# detected OS not supported
EXIT_BADVERSION=4	# can't determine console version we're running

# 3.0: Define only the default console instance name.
#      All configuration properties files in console instance subdirectory.
#      Private version of Tomcat 5 included in the console.
INSTANCE="console"
DEFAULT_FILENAME=default.properties
SERVICE_FILENAME=service.properties
DEFAULT_TOMCAT_DIR=/usr/share/webconsole/private/container

# Must be able to determine target OS so can set up appropriate
# command environment.
OS=`uname -s`
if [ ! -n "${OS}" ]; then
    echo "Unable to determine operating system." 1>&2
    exit $EXIT_UNKNOWNOS
fi

# Setup command environment for target OS.
if [ "${OS}" = "SunOS" ]; then
    PATH=/bin:/sbin:/usr/sbin
    NAWK=nawk   # XPG4-compliant implementation of awk
    ECHO=echo
    WHICH="/bin/ksh whence"  # `which` is csh and can create problems under
			     # under certain conditions

    # Default locations for java runtime
    DEFAULT_JAVA_HOME=""
    if [ -d /usr/jdk ]; then
	DEFAULT_JAVA_HOME="/usr/jdk/`ls -A /usr/jdk | fgrep jdk1.5 | sort | tail -1`"
    fi
    if [ -d /usr/j2se ]; then
	DEFAULT_JAVA_HOME="$DEFAULT_JAVA_HOME /usr/j2se"
    fi

    MANSECTION=1M
    # DEFAULT_FILE=/etc/default/webconsole
    # DEFAULT_TOMCAT_DIR=/usr/apache/tomcat

elif [ "${OS}" = "Linux" ]; then
    PATH=/bin:/sbin:/usr/bin:/usr/sbin
    NAWK=awk    # is already XPG4-compliant
    ECHO="/bin/echo -e"
    WHICH="which --skip-alias"

    # Default locations for java runtime
    if [ -d /usr/java ]; then
	DEFAULT_JAVA_HOME=/usr/java/`ls -A /usr/java | fgrep jdk1.5 | sort | tail -1`
    fi

    MANSECTION=1
    # DEFAULT_FILE=/etc/opt/default/webconsole
    # DEFAULT_TOMCAT_DIR=/usr/apache/tomcat

elif [ "${OS}" = "HP-UX" ]; then
    PATH=/bin:/sbin:/usr/bin:/usr/sbin
    NAWK=awk  # is already XPG4-compliant
    ECHO="/bin/echo"
    MANSECTION=1
    # DEFAULT_FILE=/etc/default/webconsole
    # DEFAULT_TOMCAT_DIR=/usr/bin/tomcat

elif [ "${OS}" = "AIX" ]; then
    PATH=/bin:/sbin:/usr/bin:/usr/sbin
    NAWK=nawk  # is already XPG4-compliant
    ECHO="/bin/echo"
    WHICH="/bin/ksh whence"
    DEFAULT_JAVA_HOME=/usr/java
    MANSECTION=1
    # DEFAULT_FILE=/etc/default/webconsole
    # DEFAULT_TOMCAT_DIR=/usr/apache/jakarta-tomcat-5.0.16

else
    echo "Not supported on detected OS \"${OS}\"." 1>&2
    exit $EXIT_BADOS
fi

# The model employed in the script is to delegate argument
# parsing to subcommand functions.  Some arguments can take the
# form of 'name=value', where value can be enclosed in quotes
# in the case of multiple words seperated by white space.
# getopts(1) correctly parses this argument syntax in main script 
# code, but cannot parse it from within a function - the behavior is
# that the quotes are not recognized, and so only the initial quote
# character and the following word are recognized as an argument.
#
# So in order to preserve the argument delegation model, we replace 
# white space in every 'value' of a 'name=value' type of argument with a
# unique pattern.  Functions that process arguments which are expected
# to be in 'name=value' format MUST reverse this substitution before
# attempting to extract the 'name' and 'value'.  The unique pattern
# employed is available in the global variable WHITESPACE_KEY_PATTERN.
#
# After this pattern substitution, the main script code must NEVER
# use "$*" to reference the list of all arguments, but instead must
# use "$PROGARGS".  Additionally, it must NEVER reference specific
# arguments via "$1", "$2", etc.  To use these macros, best to do so
# in a function, where the args are passed in via $PROGARGS.
#
TIMESTAMP=`date -u +"%Y"%m"%d"%H"%M"%S""`
WHITESPACE_KEY_PATTERN="_${TIMESTAMP}_"
PROGARGS=""
while [ -n "$1" ]; do
    a=$1

    # Look for '=' character.  If found, replace all whitespace with
    # unique pattern.
    $ECHO $1 | grep "=" >/dev/null 2>&1
    if [ $? -eq 0 ]; then
	a=`$ECHO $1 | sed -e "s@ @$WHITESPACE_KEY_PATTERN@g"`
    fi

    # Rebuild program arguments
    PROGARGS="$PROGARGS $a"
    shift
done


## This script's directory path and name
PROGDIR=`dirname "$0"`
PROGNAME=`basename "$0"`

## The file name of the registered plugin list
REG_PLUGIN_LIST=registered_plugins

## The file name of the smloginmodule command list in CATALINA_BASE
JAAS_CONFIG_FILE=consolelogin.conf

## The file name of the pre-registered login modules
JAAS_PRECONFIG_FILE=.consolelogin

## The official product name that this program is a part of
PRODUCT_NAME="Oracle Java(TM) Web Console"

## The file name of the registered jar list
REG_JAR_LIST=registered_jars

## The file name of the registered login module list
REG_MODULE_LIST=registered_modules

## The file name of the registered product names list
REG_PRODNAME_LIST=ProductNames

## Temporary placeholder for properties that are needed by this program,
## but which cannot be made available as an environment variable or
## as a configuration property in $CONSOLE_CONFIG_DIR/service.properties.
## This is ONLY used when ALL the following conditions are true:
##    - installation is being performed via unbundled setup only.
##    - use of environment variables is precluded.
##    - this program is invoked from a pkg script
##    - $CONSOLE_CONFIG_DIR/webconsole does not exist
## 
## The reasons for these conditions are:
##    - $CONSOLE_CONFIG_DIR/service.properties might not exist because this smreg
##      script may not have been installed yet by the time the setup program
##      wants to set a property for smreg to use.  During OS install, 
##      smreg processing takes place during stage 2 of the 2-stage 
##      registration/deployment, at which time the proper runtime environment 
##      and properties file does exist.
##   -  During pkgadd on Solaris, we cannot simply export environment
##      variables to pkg scripts.  pkgadd completely sets the runtime 
##      environment for pkg scripts based on the pkginfo.
## If you change this file, you MUST also change it in the setup scripts
## for each platform!
PREREG=/var/tmp/_prereg.properties

## The first line of the registered plugin list
AUTOGENERATEDSTRING="### DO NOT EDIT - AUTOMATICALLY GENERATED ###"

## The version of the Java Servlet Specification the filter and filter-mapping
## tags adhere to
SERVLET_SPEC_VERSION=2.3

## The pluginName tags in the app.xml file
PLUGIN_NAME_START_TAG="<pluginName>"
PLUGIN_NAME_END_TAG="<\/pluginName>"

## The managementApp start tag in the app.xml file
MANAGEMENTAPP_START_TAG="<managementApp"

## The registrationInfo start tag in the app.xml file
REGINFO_START_TAG="<registrationInfo"

## The managementApp version attribute in the app.xml file
VERSION_ATTR="version"

## Filter tag info
APP_FILTER_NAME="SessionManagerFilter"
APP_FILTER_CLASS="com.sun.management.services.session.AppSessionManagerFilter"
CONSOLE_FILTER_NAME="CoreSessionManagerFilter"
CONSOLE_FILTER_CLASS="com.sun.management.services.session.WebConsoleSMFilter"
FILTER_START_TAG="<filter>"
FILTER_END_TAG="</filter>"
FILTER_NAME_START_TAG="<filter-name>"
FILTER_NAME_END_TAG="<\/filter-name>"
FILTER_CLASS_START_TAG="<filter-class>"
FILTER_CLASS_END_TAG="<\/filter-class>"

## TopologyServlet tag info
TOPOLOGYSERVLET_NAME="ccTopologyServlet"
TOPOLOGYSERVLET_CLASS="com.sun.web.ui.servlet.topology.CCTopologyServlet"
TOPOLOGYSERVLET_URL="/ccTopologyImage"

## TableServlet tag info
TABLESERVLET_NAME="tableServlet"
TABLESERVLET_CLASS="com.sun.web.ui.servlet.table.TableServlet"
TABLESERVLET_URL="/table/*"

## DateTimeServlet tag info
DATETIMESERVLET_NAME="dateTimeServlet"
DATETIMESERVLET_CLASS="com.sun.web.ui.servlet.datetime.DateTimeServlet"
DATETIMESERVLET_URL="/datetime/*"

## BadgingServlet tag info
BADGINGSERVLET_NAME="badgingServlet"
BADGINGSERVLET_CLASS="com.sun.web.ui.servlet.badging.BadgingServlet"
BADGINGSERVLET_URL="/badging/*"

## VersionServlet tag info
VERSIONSERVLET_NAME="versionServlet"
VERSIONSERVLET_CLASS="com.sun.web.ui.servlet.version.VersionServlet"
VERSIONSERVLET_URL="/ccversion/*"
 
## HelpServlet tag info
HELPSERVLET_NAME="helpServlet"
HELPSERVLET_CLASS="com.sun.web.ui.servlet.help.HelpServlet"
HELPSERVLET_URL="/cchelp/*"

## Help2Servlet tag info
HELP2SERVLET_NAME="help2Servlet"
HELP2SERVLET_CLASS="com.sun.web.ui.servlet.help2.Help2Servlet"
HELP2SERVLET_URL="/cchelp2/*"

## RegistrarServlet tag info
REGSERVLET_NAME="Registrar"
REGSERVLET_CLASS="com.sun.management.services.registration.servlet.WebConsoleRegistrarServlet"
REGSERVLET_URL="/Registrar/*"

# runlevel for registration servlet
REGSERVLET_LOAD_PRIORITY=3

# Servlet and servlet-mapping tags info
SERVLET_START_TAG="<servlet>"
SERVLET_END_TAG="</servlet>"
SERVLET_NAME_START_TAG="<servlet-name>"
SERVLET_NAME_END_TAG="</servlet-name>"
SERVLET_CLASS_START_TAG="<servlet-class>"
SERVLET_CLASS_END_TAG="</servlet-class>"
SERVLET_MAPPING_START_TAG="<servlet-mapping>"
SERVLET_MAPPING_END_TAG="</servlet-mapping>"
SERVLET_LOAD_ON_STARTUP_START_TAG="<load-on-startup>"
SERVLET_LOAD_ON_STARTUP_END_TAG="</load-on-startup>"
URL_PATTERN_START_TAG="<url-pattern>"
URL_PATTERN_END_TAG="</url-pattern>"

# Constant to let addServletTags know that it should not include
# load-on-startup tags in servlet mapping.
NO_LOAD_ON_STARTUP=-1



## Unique name spaces for tags and resources that can appear in each app's
## directory.
CCTAGS_NAMESPACE=com_sun_web_ui
JATO_NAMESPACE=com_iplanet_jato

## Name of unregistration script dropped into each app's directory.
## It contains commands to backout everything that was copied into the
## app's directory area during registration.
UNREG=.unregrc


## Useful constants
ADD_CMD="add"			# "add subcommand"
REMOVE_CMD="remove"		# "remove subcommand"
LIST_CMD="list"			# "list" subcommand
CHECK_CMD="check"		# "check" subcommand
NAME_FLAG_SHORT="-n"		# indicates the name of the plugin follows next
NAME_FLAG_LONG="--name"		# indicates the name of the plugin follows next
CONTEXT_FLAG_SHORT="-x"		# indicates the deployment context for an application
CONTEXT_FLAG_LONG="--context"	# indicates the deployment context for an application
DIR_FLAG_SHORT="-d"		# indicates the directory of the plugin follows next
DIR_FLAG_LONG="--directory"	# indicates the directory of the plugin follows next
HELP_FLAG_SHORT="-h"		# indicates to print the usage of this script
HELP_FLAG_SHORT2="-?"		# indicates to print the usage of this script
HELP_FLAG_LONG="--help"		# indicates to print the usage of this script
JAR_FLAG_SHORT="-j"             # indicates the fully qualified jar file follows next
JAR_FLAG_LONG="--jar"           # indicates the fully qualified jar file follows next
VERSION_FLAG_SHORT="-V"         # indicates the version should be printed
VERSION_FLAG_LONG="--version"   # indicates the version should be printed
SCOPE_FLAG_SHORT="-s"		# indicates scope of library jar
SCOPE_FLAG_LONG="--scope"	# indicates scope of library jar
APP_FLAG_SHORT="-a"		# object to register is an application
APP_FLAG_LONG="--application"	# object to register is an application
LIB_FLAG_SHORT="-l"		# object to register is a library jar
LIB_FLAG_LONG="--library"	# object to register is a library jar
LINK_FLAG_SHORT="-L"		# register library object as a symbolic link
LINK_FLAG_LONG="--link"		# register library object as a symbolic link
PROP_FLAG_SHORT="-p"		# objects to register are properties
PROP_FLAG_LONG="--properties"	# objects to register are properties
CONFIG_FLAG_SHORT="-c"		# indicates server configuration properties
CONFIG_FLAG_LONG="--configuration" # indicates server configuration properties
ENV_FLAG_SHORT="-e"		# indicates environment properties
ENV_FLAG_LONG="--environment"	# indicates environment properties
LM_FLAG_SHORT="-m"		# object to register is a login module
LM_FLAG_LONG="--module"		# object to register is a login module
BEH_FLAG_SHORT="-b"		# indicates JAAS behavior of login module 
				# follows next
BEH_FLAG_LONG="--behavior"	# indicates JAAS behavior of login module
				# follows next
OPTION_FLAG_SHORT="-o"		# indicates one option of the Loginmodule
				# follows next
OPTION_FLAG_LONG="--option"	# indicates one option of the Loginmodule
				# follows next
QUIET_FLAG_SHORT="-q"		# indicates status messaged are to be
				# suppressed
QUIET_FLAG_LONG="--quiet"	# indicates status messaged are to be
				# suppressed

# Initialize quiet flag to 0, off
qFlag=0

## Name of JATO files that we need to copy into each registered app's
## deployment area
JATO_TLD=jato.tld
JATO_JAR=jato.jar

# 3.0 prereg dir path prefix
PREREG_DIR=${PLATFORM_CONF_PATH}/console/prereg
# 3.0 types
WEBAPP=webapp
MODULE=loginmodule
JAR=jar
PROPERTY=property

# 3.0 regnot property names
# common regnot property names
TYPE_PROP=type

# 3.0 web app regnot property names
CONTEXT_PROP=context
LOCATION_PROP=location

# 3.0 login module regnot property names
CLASS_PROP=class
BEHAVIOR_PROP=behavior
SERVICE_PROP=service

# 3.0 property regnot property names


# 3.0 prefix for user defined options to login modules
OPTION_PREFIX="option_"

# 3.0 jars and login module regnots go into $PREREG_DIR/legacy directory
LEGACY_REGNOT_DIR=legacy

# 3.0 deferment file
PRIVATE_DIR=private/deferredRegistrations
DEFER_FILE=.reg


################################################################################
# 
# deprecationMsg
# smreg is being deprecated in 3.0
# This function prints a deprecation message
#
################################################################################
deprecationMsg() {
    cat - << EOF

    Warning: ${PROGNAME} is obsolete and is preserved only for
    compatibility with legacy console applications. Use wcadmin instead.

    Type "man wcadmin" or "wcadmin --help" for more information.

EOF

}
################################################################################
#
# Locate the console.config configuration file and execute it.  This will set
# certain variables which will tell us where various components are
# installed.
#
################################################################################
getConfigProperties() {

    # If already know where it is, execute it.
    if [ -n "${CONFIG_PROPS}" ]; then
	. ${CONFIG_PROPS}
	return
    fi

    # Where it should be found after pkg relocation.
    dir=${PLATFORM_CONF_PATH}/console/config.properties

    # Adjust default directory based on console pkg relocation and basedir.
    if [ "${OS}" = "SunOS" ]; then

	Rarg=""
	if [ -n "${PKG_INSTALL_ROOT}" ]; then
            Rarg="-R ${PKG_INSTALL_ROOT}"
	fi

	Aarg=""
	if [ -n "${ARCH}" ]; then
            Aarg="-a ${ARCH}"
	fi

	pkginfo=`pkginfo ${Rarg} ${Aarg} "SUNWmcon*" 2>/dev/null`
	if [ $? -eq 0 ]; then
	    # Determine the BASEDIR
	    # $PKG is the pkg that is being installed at this time
	    # it is a package environment variable.
	    if [ "$PKG" = "SUNWmcon" ]; then
		dir="${BASEDIR}${dir}"
	    else
		pkginst=`echo $pkginfo | awk '{print $2}'`
        	basedir=`env LANG=C LC_ALL=C \
		    pkgparam ${Rarg} $pkginst BASEDIR 2>/dev/null`
		dir="${PKG_INSTALL_ROOT}${basedir}${dir}"
	    fi
	else
            basedir=`env LANG=C LC_ALL=C \
		pkgparam SUNWmcon BASEDIR 2>/dev/null`
	    dir="${basedir}${dir}"
	fi

    elif [ "${OS}" = "Linux" ]; then
	basedir="/"
	dir="${basedir}${dir}"
    elif [ "${OS}" = "HP-UX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    elif [ "${OS}" = "AIX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    fi

    CONFIG_PROPS=`$ECHO ${dir} | sed -e 's@/*$@@' -e 's@//*@/@g'`

    if [ ! -f "$CONFIG_PROPS" ]; then
	$ECHO "Cannot find configuration \"console.config\" file." 1>&2
	exit $EXIT_FAILURE
    fi

    # Execute it.
    . ${CONFIG_PROPS}

} ## getConfigProperties


################################################################################
#
# regUsage
#
# Prints usage of this script to the screen.
#
# $1 = Exit code
#
################################################################################

regUsage() {

    cat - << EOF

    Usage: ${PROGNAME} [$QUIET_FLAG_SHORT] SUBCOMMAND ARGUMENTS
     or: ${PROGNAME} $HELP_FLAG_SHORT

    Manages the registration database for the ${PRODUCT_NAME}.

    The accepted values for SUBCOMMAND are:

    add        Registers objects
    remove     Unregisters objects
    list       Prints a list of registered objects
    check      Validate a application's web.xml

    $VERSION_FLAG_SHORT, $VERSION_FLAG_LONG
           Display console version information.

    $QUIET_FLAG_SHORT,   $QUIET_FLAG_LONG
	   Quiet mode, supress warnings and deprecation messages.

    $HELP_FLAG_SHORT, $HELP_FLAG_SHORT2, $HELP_FLAG_LONG
           Display this help list.

    For more information, see smreg($MANSECTION).
    
EOF

    exit $1

} ## end regUsage()


########################################################
#
# Function to resolve a link to it's target.
#
########################################################
resolve_link() {

    prg=$1

    if [ -h "${prg}" ]; then

	# Must cd to where the symbolic link is located as a starting point
	# to follow the link.
	cd `dirname ${prg}`

	# Resolve link to conclusion
	while [ -h "${prg}" ]
	do
	    prg=`ls -al ${prg} | awk '{print $NF}'`
	    cd `dirname ${prg}`
	done

	# Resolve to full path, in case it's relative.
	prg=`pwd`/`basename ${prg}`
    fi

    $ECHO $prg

} # resolve_link


########################################################
#
# Version to convert a version string in X.Y.Z or
# X.Y.X_NN format to XYZNN format so can be treated as a
# number.
#
# $1 = version string
# Returns numerical version
#
########################################################
versionString2Num () {

    # Minor and micro default to 0 if not specified.
    major=`$ECHO $1 | awk -F. '{print $1}'`
    minor=`$ECHO $1 | awk -F. '{print $2}'`
    if [ ! -n "$minor" ]; then
        minor="0"
    fi
    dash=`$ECHO $minor | grep "-"`
    if [ $? -eq 0 ]; then
	# Must be internal build, so drop the trailing variant.
	minor=`$ECHO $minor | awk -F- '{print $1}'`
	$ECHO $minor | grep -v '[^0-9]' >/dev/null
	if [ $? -ne 0 ]; then
	    minor="0"
	fi
    fi
    micro=`$ECHO $1 | awk -F. '{print $3}'`
    if [ ! -n "$micro" ]; then
        micro="0"
    fi

    # The micro version may further be extended to include a patch number.
    # This is typically of the form <micro>_NN, where NN is the 2-digit
    # patch number.  However it can also be of the form <micro>-XX, where
    # XX is some arbitrary non-digit sequence (eg., "rc").  This latter
    # form is typically used for internal-only release candidates or
    # development builds.
    #
    # For these internal builds, we drop the -XX and assume a patch number 
    # of "00".  Otherwise, we extract that patch number.
    #
    patch="00"
    dash=`$ECHO $micro | grep "-"`
    if [ $? -eq 0 ]; then
	# Must be internal build, so drop the trailing variant.
	micro=`$ECHO $micro | awk -F- '{print $1}'`
	$ECHO $micro | grep -v '[^0-9]' >/dev/null
	if [ $? -ne 0 ]; then
	    micro="0"
	fi
    fi

    underscore=`$ECHO $micro | grep "_"`
    if [ $? -eq 0 ]; then
	# Extract the seperate micro and patch numbers, ignoring anything
	# after the 2-digit patch.
	patch=`$ECHO $micro | awk -F_ '{print substr($2, 1, 2)}'`
	micro=`$ECHO $micro | awk -F_ '{print $1}'`
    fi

    # Strip off any alphabetic characters, in case anyone inserts things
    # like "beta".  We don't support such variants, but the test group
    # admits to needing this fixed for selfish reasons.  ;-)
    major=`echo $major | sed -e "s/[a-z]//g" -e "s/[A-Z]//g"`
    minor=`echo $minor | sed -e "s/[a-z]//g" -e "s/[A-Z]//g"`
    micro=`echo $micro | sed -e "s/[a-z]//g" -e "s/[A-Z]//g"`

    $ECHO "${major}${minor}${micro}${patch}"

} # versionString2Num



########################################################
#
# Function to try to find a suitable Java2 runtime
#
########################################################
findJava() {

    # JAVA_HOME environment variable overrides everything
    JAVA_LOC="${JAVA_HOME:+${JAVA_HOME}/bin/java}"

    # java.home property is where we think it should be.
    javahome_prop=`/usr/sbin/smreg list -p | grep "java.home="`
    if [ $? -eq 0 ]; then
	JAVA_LOC="$JAVA_LOC `echo $javahome_prop | cut -d"=" -f2`/bin/java"
    fi

    # Followed by along PATH and the standard location.
    defaultJavas=""
    for i in $DEFAULT_JAVA_HOME; do
	defaultJavas="$defaultJavas $i/bin/java"
    done
    javaOnPath=`${WHICH} java 2>&1`
    if [ $? -eq 0 ]; then
	JAVA_LOC="$JAVA_LOC ${javaOnPath} ${defaultJavas}"
    else
	JAVA_LOC="$JAVA_LOC ${defaultJavas}"
    fi

    # Followed by the special temporary placeholder for properties that are 
    # needed by this program, but which cannot be made available as an 
    # environment variable or as a configuration property.
    # See the definition of PREREG for a full explanation.
    if [ -f $PREREG ]; then
	javahome_prop=`cat $PREREG | grep "java.home="`
	if [ $? -eq 0 ]; then
	    JAVA_LOC="$JAVA_LOC `echo $javahome_prop | cut -d"=" -f2`/bin/java"
	fi
    fi

    JAVA_HOME=""
    for i in ${JAVA_LOC}
    do
	prog=`resolve_link ${i}`
	if [ -x ${prog} ]; then
	    JAVA_HOME=`dirname \`dirname ${prog}\``
	    break
	fi
    done

    if [ ! -n "${JAVA_HOME}" ]; then
	$ECHO "No suitable Java runtime found in any of the following directories:" 1>&2
	$ECHO "        \c" 1>&2
	for i in $JAVA_LOC; do $ECHO "${i} \c"; done; $ECHO 1>&2
	$ECHO "Please set the JAVA_HOME environment variable to point to a Java" 1>&2
	$ECHO "installation and run ${PROGDIR}/${PROGNAME} again." 1>&2
	exit 1
    fi

} # findJava


################################################################################
#
# getConsoleVersionNum
#
# get the console version and convert it to a "number" for version checking
#
################################################################################

getConsoleVersionNum() {

    # If CONSOLE_VERSION is empty extract it from version.txt
    if [ ! -n "${CONSOLE_VERSION}" ]; then
	# Extract console version and set the CONSOLE_VERSION
	# and CONSOLE_VERSION_NUM vars. If we get back the string "???"
	# exit with an error code
	CONSOLE_VERSION=`regVersion | head -1 | awk '{print $NF}'`
	if [ "${CONSOLE_VERSION}" != "???" ]; then
	    CONSOLE_VERSION="`echo ${CONSOLE_VERSION} | \
		sed  -e 's@ @@g' -e 's@[a-zA-Z\-]@@g'`"
	    CONSOLE_VERSION_NUM="`versionString2Num ${CONSOLE_VERSION}`"
	else
	    printOut "Error! Unable to determine console version." 1>&2
	    printOut "Does ${CONSOLE_INSTALL_DIR}/version.txt exist?" 1>&2
	    exit ${EXIT_BADVERSION}
	fi
    fi

} ## end getConsoleVersionNum

################################################################################
#
# regVersion
#
# Display version information.
#
################################################################################

regVersion() {

    # Extract console version.
    #
    getConsoleInstallDir
    versionFile=${CONSOLE_INSTALL_DIR}/version.txt
    if [ -f ${versionFile} ]; then
	version="`cat ${versionFile}`"
    else
	version="???"
    fi

    cat - << EOF
    ${PROGNAME} (${PRODUCT_NAME}) $version
    Copyright (c) 2011, Oracle and/or its affiliates. All rights reserved.
    All Rights Reserved.
EOF

} ## end regVersion


################################################################################
#
# isRoot
#
# Check the user ID to see if it matches root's (0).
# Return 0 if the user is root. Exit with status 1 otherwise.
#
################################################################################

isRoot() {

    USERID=`id | sed -e 's/uid=\([0-9]*\).*/\1/'`

    if [ $USERID -ne 0 ]; then
	printOut "Error! You must be \"root\" to run this command." 1>&2
	exit $EXIT_USAGE
    fi
    return 0

} ## end isRoot


################################################################################
#
# perms2mode
#
# Converts file permissions in format output from `ls -l' to absolute
# mode into form used by `chmod'.  Only does "simple" conversions so basic
# permissions on files we modified can be restored - no support for
# sticky bits and such.
#
# $1 = permissions for owner, group, world in standard 3-character
#      sequence for each (eg., "-rw-r--r--")
#
# Returns the absolute mode
#
################################################################################

perms2mode() {

    perms=$1

    owner=`$ECHO $perms | awk '{print substr($1, 2, 3)}'`
    group=`$ECHO $perms | awk '{print substr($1, 5, 3)}'`
    world=`$ECHO $perms | awk '{print substr($1, 8, 3)}'`

    perms=""
    for user in $owner $group $world
    do
	n=0
	r=`$ECHO $user | awk '{print substr($1, 1, 1)}'`
	w=`$ECHO $user | awk '{print substr($1, 2, 1)}'`
	x=`$ECHO $user | awk '{print substr($1, 3, 1)}'`
	if [ "$r" = "r" ]; then
	    n=4
	fi
	if [ "$w" = "w" ]; then
	    n=`(expr $n + 2)`
	fi
	if [ "$x" = "x" ]; then
	    n=`(expr $n + 1)`
	fi
	perms="${perms}${n}"
    done

    $ECHO ${perms}

} ## end perms2mode


################################################################################
#
# inMiniRoot
#
# Return "1" if this program is running from a relocatable root, "0" if not.
#
################################################################################
inMiniRoot() {

    # Check if the application's install pkg is relocateable
    if [ -n "${PKG_INSTALL_ROOT}" ]; then

	# Check if the console was also relocated to this location.
	if [ "${OS}" = "SunOS" ]; then
	    Aarg=""
	    if [ -n "$ARCH" ]; then
		Aarg="-a $ARCH"
	    fi
	    pkginfo ${Aarg} -R ${PKG_INSTALL_ROOT} "SUNWmcon*" >/dev/null 2>&1
	    if [ $? -eq 0 ]; then
		$ECHO "1"
		return
	    fi
	fi
    fi

    $ECHO "0"

} ## end inMiniRoot


################################################################################
#
# isNormalizeable
#
# Determine if a given path can be normalized to its absolute runtime
# location.  This is needed to account for the fact that when running
# running during install, paths are very likely to be mount points on 
# some install server, so we need to be able to determine if we can strip 
# off any leading BASEDIR.  However, we can NOT normalize if we find a BASEDIR 
# of /, /usr, or one starting with /opt, which are *real* BASEDIRs, and not 
# mount points.  We also can NOT normalize if the application pkg is relocatable
# but not to the same location as the console itself.
#
# $1 = the path to check
#
# Return "0" if the path should NOT be normalized, "1" if it can.
#
################################################################################

isNormalizeable() {

    # Check if the application's install pkg is relocateable
    if [ -n "${PKG_INSTALL_ROOT}" ]; then

	# Check if the console was also relocated to this location.
	# If not, then the path should not be normalized.
	if [ "${OS}" = "SunOS" ]; then
	    Aarg=""
	    if [ -n "$ARCH" ]; then
		Aarg="-a $ARCH"
	    fi
	    pkginfo ${Aarg} -R ${PKG_INSTALL_ROOT} "SUNWmcon*" >/dev/null 2>&1
	    if [ $? -ne 0 ]; then
		$ECHO "0"
		return
	    fi
	fi
    fi

    # Paths starting with /opt should not be normalized.
    opt=`$ECHO $1 | grep "^/opt/"`
    if [ -n "${opt}" ]; then
	$ECHO "0"

    # / and /usr should not be normalized, everything else can
    elif [ -n "${1}" -a "${1}" != "/"  -a "${1}" != "/usr" ]; then
	$ECHO "1"
    else
	$ECHO "0"
    fi

} ## isNormalizeable


################################################################################
#
# getConsoleInstallDir
#
# Get the install directory of the console and set it in CONSOLE_INSTALL_DIR.
# This is the directory containing shared data stores.
# The default is /usr/share/webconsole. 
# CONSOLE_INSTALL_DIR is relative to the machine on which the script is being
# run;  that is, the directory MUST be accessible from within the script during
# system install.
#
################################################################################

getConsoleInstallDir() {

    if [ -n "${CONSOLE_INSTALL_DIR}" ]; then
	return
    fi

    getConfigProperties
    dir=/usr/share/webconsole
    if [ -n "${console_home}" ]; then
	dir=${console_home}
    fi

    # Adjust default directory based on console pkg relocation and basedir.
    if [ "${OS}" = "SunOS" ]; then

	Rarg=""
	if [ -n "${PKG_INSTALL_ROOT}" ]; then
            Rarg="-R ${PKG_INSTALL_ROOT}"
	fi

	Aarg=""
	if [ -n "${ARCH}" ]; then
            Aarg="-a ${ARCH}"
	fi

	pkginfo=`pkginfo ${Aarg} ${Rarg} "SUNWmcon*" 2>/dev/null`
	if [ $? -eq 0 ]; then
	    if [ "$PKG" = "SUNWmcon" ]; then
		dir="${BASEDIR}${dir}"
	    else
		pkginst=`echo $pkginfo | awk '{print $2}'`
        	basedir=`env LANG=C LC_ALL=C \
		    pkgparam ${Rarg} $pkginst BASEDIR 2>/dev/null`
		dir="${PKG_INSTALL_ROOT}${basedir}${dir}"
	    fi
	else
            basedir=`env LANG=C LC_ALL=C \
		pkgparam SUNWmcon BASEDIR 2>/dev/null`
	    dir="${basedir}${dir}"
	fi

    elif [ "${OS}" = "Linux" ]; then
	basedir="/"
	dir="${basedir}${dir}"
    elif [ "${OS}" = "HP-UX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    elif [ "${OS}" = "AIX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    fi

    CONSOLE_INSTALL_DIR=`$ECHO ${dir} | sed -e 's@/*$@@' -e 's@//*@/@g'`

    if [ ! -d "$CONSOLE_INSTALL_DIR" ]; then
	printOut "Error! Installation directory \"$CONSOLE_INSTALL_DIR\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

} ## end getConsoleInstallDir


################################################################################
#
# getConsoleAppbaseDir
#
# Get the deployed web application base directory and set it in CONSOLE_APPBASE_DIR.
# This is the directory web applications are deployed into by registration.
# The default is ${PLATFORM_BASE_PATH}/webapps. 
# CONSOLE_APPBASE_DIR is relative to the machine on which the script is being
# run;  that is, the directory MUST be accessible from within the script during
# system install.
#
################################################################################

getConsoleAppbaseDir() {

    if [ -n "${CONSOLE_APPBASE_DIR}" ]; then
	return
    fi

    getConfigProperties
    dir=${PLATFORM_BASE_PATH}/webapps
    if [ -n "${console_appbase}" ]; then
	dir=${console_appbase}
    fi

    # Adjust default directory based on console pkg relocation and basedir.
    if [ "${OS}" = "SunOS" ]; then

	Rarg=""
	if [ -n "${PKG_INSTALL_ROOT}" ]; then
            Rarg="-R ${PKG_INSTALL_ROOT}"
	fi

	Aarg=""
	if [ -n "$ARCH" ]; then
	    Aarg="-a $ARCH"
	fi

	pkginfo=`pkginfo ${Aarg} ${Rarg} "SUNWmconr*" 2>/dev/null`
	if [ $? -eq 0 ]; then
	    if [ "$PKG" = "SUNWmconr" ]; then
		dir="${BASEDIR}${dir}"
	    else
		pkginst=`echo $pkginfo | awk '{print $2}'`
        	basedir=`env LANG=C LC_ALL=C \
		    pkgparam ${Rarg} $pkginst BASEDIR 2>/dev/null`
		dir="${PKG_INSTALL_ROOT}${basedir}${dir}"
	    fi
	else
            basedir=`env LANG=C LC_ALL=C \
		pkgparam SUNWmconr BASEDIR 2>/dev/null`
	    dir="${basedir}${dir}"
	fi

    elif [ "${OS}" = "Linux" ]; then
	basedir="/"
	dir="${basedir}${dir}"
    elif [ "${OS}" = "HP-UX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    elif [ "${OS}" = "AIX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    fi

    CONSOLE_APPBASE_DIR=`$ECHO ${dir} | sed -e 's@/*$@@' -e 's@//*@/@g'`

    if [ ! -d "$CONSOLE_APPBASE_DIR" ]; then
	printOut "Error! Deployment directory \"$CONSOLE_APPBASE_DIR\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

} ## end getConsoleAppbaseDir


################################################################################
#
# getConsoleBaseDir
#
# Get the console base directory and set it in CONSOLE_BASE_DIR.
# This is the directory where we maintain our configuration and registrations.
# The default is ${PLATFORM_BASE_PATH}. 
# CONSOLE_BASE_DIR is relative to the machine on which the script is being
# run;  that is, the directory MUST be accessible from within the script during
# system install.
#
################################################################################

getConsoleBaseDir() {

    if [ -n "${CONSOLE_BASE_DIR}" ]; then
	return
    fi

    getConfigProperties
    dir=${PLATFORM_BASE_PATH}
    if [ -n "${console_base}" ]; then
	dir=${console_base}
    fi

    # Adjust default directory based on console pkg relocation and basedir.
    if [ "${OS}" = "SunOS" ]; then

	Rarg=""
	if [ -n "${PKG_INSTALL_ROOT}" ]; then
            Rarg="-R ${PKG_INSTALL_ROOT}"
	fi

	Aarg=""
	if [ -n "$ARCH" ]; then
	    Aarg="-a $ARCH"
	fi

	pkginfo=`pkginfo ${Aarg} ${Rarg} "SUNWmconr*" 2>/dev/null`
	if [ $? -eq 0 ]; then
	    if [ "$PKG" = "SUNWmconr" ]; then
		dir="${BASEDIR}${dir}"
	    else
		pkginst=`echo $pkginfo | awk '{print $2}'`
        	basedir=`env LANG=C LC_ALL=C \
		    pkgparam ${Rarg} $pkginst BASEDIR 2>/dev/null`
		dir="${PKG_INSTALL_ROOT}${basedir}${dir}"
	    fi
	else
            basedir=`env LANG=C LC_ALL=C \
		pkgparam SUNWmconr BASEDIR 2>/dev/null`
	    dir="${basedir}${dir}"
	fi

    elif [ "${OS}" = "Linux" ]; then
	basedir="/"
	dir="${basedir}${dir}"
    elif [ "${OS}" = "HP-UX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    elif [ "${OS}" = "AIX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    fi

    CONSOLE_BASE_DIR=`$ECHO ${dir} | sed -e 's@/*$@@' -e 's@//*@/@g'`

    if [ ! -d "$CONSOLE_BASE_DIR" ]; then
	printOut "Error! directory \"$CONSOLE_BASE_DIR\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

} ## end getConsoleBaseDir


################################################################################
#
# getConsoleConfigDir
#
# Get the configuration directory of the console and set it in CONSOLE_CONFIG_DIR.
# The default is ${PLATFORM_CONF_PATH}/console.
# CONSOLE_CONFIG_DIR is local to the machine on which the script is being
# run;  that is, the directory MUST be accessible from within the script during
# system install.
#
################################################################################

getConsoleConfigDir() {

    if [ -n "${CONSOLE_CONFIG_DIR}" ]; then
	return
    fi

    dir=${PLATFORM_CONF_PATH}/${INSTANCE}

    # Adjust default directory based on console pkg relocation and basedir.
    if [ "${OS}" = "SunOS" ]; then

	Rarg=""
	if [ -n "${PKG_INSTALL_ROOT}" ]; then
            Rarg="-R ${PKG_INSTALL_ROOT}"
	fi

	Aarg=""
	if [ -n "$ARCH" ]; then
	    Aarg="-a $ARCH"
	fi

	pkginfo=`pkginfo ${Aarg} ${Rarg} "SUNWmconr*" 2>/dev/null`
	if [ $? -eq 0 ]; then
	    if [ "$PKG" = "SUNWmconr" ]; then
		dir="${BASEDIR}${dir}"
	    else
		pkginst=`echo $pkginfo | awk '{print $2}'`
        	basedir=`env LANG=C LC_ALL=C \
		    pkgparam ${Rarg} $pkginst BASEDIR 2>/dev/null`
		dir="${PKG_INSTALL_ROOT}${basedir}${dir}"
	    fi
	else
            basedir=`env LANG=C LC_ALL=C \
		pkgparam SUNWmconr BASEDIR 2>/dev/null`
	    dir="${basedir}${dir}"
	fi

    elif [ "${OS}" = "Linux" ]; then
	basedir="/"
	dir="${basedir}${dir}"
    elif [ "${OS}" = "HP-UX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    elif [ "${OS}" = "AIX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    fi

    CONSOLE_CONFIG_DIR=`$ECHO ${dir} | sed -e 's@/*$@@' -e 's@//*@/@g'`

    if [ ! -d "$CONSOLE_CONFIG_DIR" ]; then
	printOut "Error! Configuration directory \"$CONSOLE_CONFIG_DIR\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

} ## end getConsoleConfigDir


################################################################################
#
# getJatoInstallDir
#
# Get the install directory of JATO and set it in JATO_INSTALL_DIR.
# The default is /usr/share/lib/jato.
# JATO_INSTALL_DIR is relative to the machine on which the script is being;  
# run; that is, the directory MUST be accessible from within the script during
# system install.
#
################################################################################

getJatoInstallDir() {

    if [ -n "${JATO_INSTALL_DIR}" ]; then
	return
    fi

    getConfigProperties
    dir=/usr/share/lib/jato
    if [ -n "${jato_home}" ]; then
	dir=${jato_home}
    fi

    # Adjust default directory based on jato pkg relocation and basedir.
    if [ "${OS}" = "SunOS" ]; then

	Rarg=""
	if [ -n "${PKG_INSTALL_ROOT}" ]; then
            Rarg="-R ${PKG_INSTALL_ROOT}"
	fi

	Aarg=""
	if [ -n "${ARCH}" ]; then
            Aarg="-a ${ARCH}"
	fi

	# Check for a package for the specific architecture.
	pkginfo=`pkginfo ${Aarg} ${Rarg} "SUNWjato*" 2>/dev/null`
	if [ $? -ne 0 ]; then
	    # In this case, Jato was not installed with a specific architecture
	    # type. Instead, the ARCH type 'all' was used'.
	    if [ -n "${ARCH}" ]; then
        	Aarg="-a all"
	    fi
	    pkginfo=`pkginfo ${Aarg} ${Rarg} "SUNWjato*" 2>/dev/null`
	fi

	if [ $? -eq 0 ]; then
	    if [ "$PKG" = "SUNWjato" ]; then
		dir="${BASEDIR}${dir}"
	    else
		pkginst=`echo $pkginfo | awk '{print $2}'`
        	basedir=`env LANG=C LC_ALL=C \
		    pkgparam ${Rarg} $pkginst BASEDIR 2>/dev/null`
		dir="${PKG_INSTALL_ROOT}${basedir}${dir}"
	    fi
	else
	    basedir=`env LANG=C LC_ALL=C \
		pkgparam SUNWjato BASEDIR 2>/dev/null`
	    dir="${basedir}${dir}"
	fi

    elif [ "${OS}" = "Linux" ]; then
	basedir="/"
	dir="${basedir}${dir}"
    elif [ "${OS}" = "HP-UX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    elif [ "${OS}" = "AIX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    fi

    JATO_INSTALL_DIR=`$ECHO ${dir} | sed -e 's@/*$@@' -e 's@//*@/@g'`

    if [ ! -d "$JATO_INSTALL_DIR" ]; then
	printOut "Error! SunOne Presentation Framework installation directory \"$JATO_INSTALL_DIR\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

} ## end getJatoInstallDir


################################################################################
#
# getTomcatInstallDir
#
# Get the install directory of Tomcat and set it in TOMCAT_INSTALL_DIR.
# The default is /usr/apache/tomcat. 
# TOMCAT_INSTALL_DIR is relative to the machine on which the script is being
# run;  that is, the directory MUST be accessible from within the script during
# system install.
#
################################################################################

getTomcatInstallDir() {

    if [ -n "${TOMCAT_INSTALL_DIR}" ]; then
	return
    fi

    getConfigProperties
    dir=$DEFAULT_TOMCAT_DIR
    if [ -n "${container_home}" ]; then
	dir=${container_home}
    fi

    # Adjust default directory based on tomcat pkg relocation and basedir.
    # But Tomcat could have been installed in /opt, in which case we don't
    # need to account for pkg relocation.  This determination is based on
    # whether it's BASEDIR is normalizeable.
    #
    if [ "${OS}" = "SunOS" ]; then

	Rarg=""
	if [ -n "${PKG_INSTALL_ROOT}" ]; then
            Rarg="-R ${PKG_INSTALL_ROOT}"
	fi

	Aarg=""
	if [ -n "${ARCH}" ]; then
            Aarg="-a ${ARCH}"
	fi

	pkginfo=`pkginfo ${Aarg} ${Rarg} "SUNWtcatu*" 2>/dev/null`
	if [ $? -eq 0 ]; then
	    if [ "$PKG" = "SUNWtcatu" ]; then
		dir="${BASEDIR}${dir}"
	    else
		pkginst=`echo $pkginfo | awk '{print $2}'`
        	basedir=`env LANG=C LC_ALL=C \
		    pkgparam ${Rarg} $pkginst BASEDIR 2>/dev/null`
		if [ `isNormalizeable ${PKG_INSTALL_ROOT}${basedir}` = "1" ]; then
		    dir="${PKG_INSTALL_ROOT}${basedir}${dir}"
		fi
	    fi
	else
            basedir=`env LANG=C LC_ALL=C \
		pkgparam SUNWtcatu BASEDIR 2>/dev/null`
	    if [ `isNormalizeable ${basedir}` = "1" ]; then
		dir="${basedir}${dir}"
	    fi
	fi

    elif [ "${OS}" = "Linux" ]; then
	basedir="/"
	dir="${basedir}${dir}"
    elif [ "${OS}" = "HP-UX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    elif [ "${OS}" = "AIX" ]; then
        basedir="/"
        dir="${basedir}${dir}"
    fi

    TOMCAT_INSTALL_DIR=`$ECHO ${dir} | sed -e 's@/*$@@' -e 's@//*@/@g'`

    if [ ! -d "$TOMCAT_INSTALL_DIR" ]; then
	printOut "Error! Tomcat installation directory \"$TOMCAT_INSTALL_DIR\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

} ## end getTomcatInstallDir


################################################################################
#
# absPath
#
# Convert a path argument to an absolute path.
#
################################################################################
absPath() {

    # Record our CWD
    savecwd=`pwd`

    if [ -d $1 ]; then
	# It's a directory that exists, so we can cd to it and resolve
	# its full path.
	cd $1
	wd=`pwd`
	cd $savecwd
	echo $wd
    elif [ -f $1 ]; then
	# It's a file that exists, so we can cd to it's parent and resolve
	# its full path.
	cd `dirname $1`
	wd=`pwd`
	cd $savecwd
	echo $wd/`basename $1`
    else
	# Otherwise just return the original path
	echo $1
    fi

} ## absPath


################################################################################
#
# registerApp
#
# Registers an application plugin.
#
# $1 = directory in which the plugin application was installed, or
#      path to war file
# $2 = optional deployment context path
#
################################################################################

registerApp() {

    fullPath=`absPath $1`

    if [ `inMiniRoot` = "1" ]; then

	getConsoleInstallDir

	# Re-create the original command that got us here in the 1st place.
	#
	p=$1
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    p=`$ECHO $p | sed -e "s@^${BASEDIR}/@/@"`
	fi
	if [ -n "$2" ]; then
	    context=${2}
	else
	    context=`basename ${p}`
	fi

	# webapp deferment format
	# [webapp - ${location}]
	# context=
	# location=

	# initialize header
	properties="[${WEBAPP} - ${p}]\n"

	# context
	properties="${properties}${CONTEXT_PROP}=${context}\n"

	# location 
	properties="${properties}${LOCATION_PROP}=${p}\n\n"

	#
	# Write recored to defer file
	#
	deferFile=${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}/${DEFER_FILE}

	# if the private dir directory doesn't exist make it
	if [ ! -d ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR} ]; then
	    mkdir -p ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}
	fi

	# write the entry to the defer file
	$ECHO ${properties} >> ${deferFile}

	return
    fi

    # Make sure we have the console version num
    getConsoleVersionNum

    ## Create the new plugin list if it doesn't exist or if its size is 0
    getConsoleInstallDir
    getConsoleBaseDir
    if [ ! -s $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST ]; then
	doBanner $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST
    fi

    # Check for packed (war file) or unpacked application.
    suffix=`$ECHO $fullPath | \
	awk '{i=index($1, ".war")}{print substr($1, i, length($1)-i+1)}'`
    if [ $suffix = ".war" ]; then
	# 2.1 does not officially support war file deployment
	# we'll leave the code and just exit
	printOut "Error! Deployment of applications in web archive (.war) format is not supported."
	exit $EXIT_FAILURE
    fi


    # Unpacked application in a directory

    PLUGIN_DIR=$fullPath

    if [ ! -d $PLUGIN_DIR ]; then
	printOut "Error! \"$PLUGIN_DIR\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

    # Extract information from application descriptor.
    if [ -s $PLUGIN_DIR/WEB-INF/app.xml ]; then
	# Apps based on 2.1 or later should have descriptor in app's WEB-INF
	# directory, and the registrationInfo version should be set to the SDK
	# the app was built against, 2.1 or later.
	extractSDKversion $PLUGIN_DIR/WEB-INF/app.xml
	appVersion=`versionString2Num $SDK_VERSION`
	if [ "(" ${appVersion} -lt 21000 ")" -o "(" ${appVersion} -gt ${CONSOLE_VERSION_NUM} ")" ]; then
	    printOut "Error! The registrationInfo \"$VERSION_ATTR\" attribute in $PLUGIN_DIR/WEB-INF/app.xml must be at least 2.1 and no more than ${CONSOLE_VERSION}" 1>&2
	    exit $EXIT_FAILURE
	fi
	extractPluginName $PLUGIN_DIR/WEB-INF/app.xml
    elif [ -s $PLUGIN_DIR/app.xml ]; then
	# Pre-2.1 based apps have descriptor in top-level app directory.
	extractSDKversion $PLUGIN_DIR/app.xml
	if [ `versionString2Num $SDK_VERSION` -gt 20000 ]; then
	    printOut "Error! The registrationInfo \"$VERSION_ATTR\" attribute in $PLUGIN_DIR/app.xml must be less than 2.1" 1>&2
	    exit $EXIT_FAILURE
	fi
	extractPluginName $PLUGIN_DIR/app.xml

    else
	printOut "Error! No registration descriptor file (app.xml) found in $PLUGIN_DIR or $PLUGIN_DIR/WEB-INF." 1>&2
	exit $EXIT_FAILURE
    fi

    printOut "Registering $PLUGIN_NAME."

    ## If the plugin_name is registered, remove the original from the file
    isAppRegistered $PLUGIN_NAME
    if [ $? -eq 0 ]; then
	# get the app name we need for removal
	regAppInfo=`getRegAppBy pluginID $PLUGIN_NAME`
	app=`getRegAppValue $regAppInfo context`

	# remove the plugin
	removeRegAppBy pluginID $PLUGIN_NAME

	# remove the app's files in $CONSOLE_APPBASE_DIR
	getConsoleAppbaseDir
	/bin/rm -rf $CONSOLE_APPBASE_DIR/$app

    fi

    # Pre-2.1 based apps must have filter tags in web.xml.
    if [ `versionString2Num $SDK_VERSION` -lt 21000 ]; then

	checkForFilterTags $1
	if [ $? -ne 0 ]; then
	    printOut "Error! The web deployment descriptor in $PLUGIN_DIR/WEB-INF/web.xml does not contain the required <filter> and <filter-mapping> tags. This application is not registered." 1>&2
	    printOut "Run this script with the \"check\" subcommand to view the descriptor with these tags inserted." 1>&2
	    exit $EXIT_FAILURE
	fi
    fi

    # Apps must have tags-related files copied into their deployment area.
    installTags

    # normalize the path so that the client PLUGIN_DIR gets written out
    if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	PLUGIN_DIR=`$ECHO $PLUGIN_DIR | sed -e "s@^${BASEDIR}/@/@"`
    fi

    ## Remove trailing slashes (/) and double slashes (//) from the directory
    PLUGIN_DIR=`$ECHO $PLUGIN_DIR | sed -e 's@/*$@@' -e 's@//*@/@g'`

    # Context derived from app's directory name, but app's built with the
    # SDK version 2.1 or later can override
    if [ `versionString2Num $SDK_VERSION` -lt  21000 ]; then
	context=`basename $PLUGIN_DIR`
    else
	context=$2
	if [ ! -n "$context" ]; then
	    context=`basename $PLUGIN_DIR`
	fi
    fi

    params="unused"

    ## Append the unique plugin name to the registered plugin list
    $ECHO "$context|$PLUGIN_NAME|$PLUGIN_DIR|$SDK_VERSION|$params" \
	>> $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST

} ## end registerApp


################################################################################
#
# registerJar
#
# Registers a jar file, with the specified scope
#
# $1 = path to jar file
# $2 = scope under which the jar was registered .  This can be the
#      token "ALL", in which case the scope is global and the jar
#      is shared by all apps.  Alternatively, this can be an
#      application's registered name, which is <pluginName>_<version>,
#      where <pluginName> and <version> are as specified in the app's web.xml
# $3 = 1=register the jar via a symbolic link
#      0=register the jar via a file copy
# $4 = name by which to register the jar.  If not specified, the
#      default is `basename $1`
#
# Entries in the registration database are of the form:
#      scope@name   path
#
################################################################################

registerJar() {

    path=`absPath $1`
    path=`$ECHO $path | sed -e 's@/*$@@' -e 's@//*@/@g'`
    scope=$2
    linkFlag=$3
    name=$4

    if [ `inMiniRoot` = "1" ]; then
	getConsoleInstallDir

	# Re-create the original command that got us here in the 1st place.
	#
	p=$path
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    p=`$ECHO $path | sed -e "s@^${BASEDIR}/@/@"`
	fi

	# jar deferment format
	# [jar - ${location}]
	# location=

	# initialize header
	properties="[${JAR} - ${p}]\n"

	# location 
	properties="${properties}${LOCATION_PROP}=${p}\n\n"

	#
	# Write recored to defer file
	#
	deferFile=${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}/${DEFER_FILE}

	# if the private dir directory doesn't exist make it
	if [ ! -d ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR} ]; then
	    mkdir -p ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}
	fi

	# write the entry to the defer file
	$ECHO ${properties} >> ${deferFile}

	return
    fi

    getConsoleAppbaseDir
    getConsoleBaseDir

    # Must have ".jar" suffix.
    suffix=`$ECHO $path | \
	awk '{i=index($1, ".jar")}{print substr($1, i, length($1)-i+1)}'` 
    if [ $suffix != ".jar" ]; then
        printOut "Not a jar file!" 1>&2
        exit $EXIT_FAILURE
    fi

    # Default name to register the jar is basename of the path.
    if [ ! -n "$name" ]; then
	name=`basename $path`
    fi

    # Name must include .jar suffix, so add it if not provided.
    suffix=`$ECHO $name | \
	awk '{i=index($1, ".jar")}{print substr($1, i, length($1)-i+1)}'` 
    if [ $suffix != ".jar" ]; then
	name=${name}.jar
    fi
    
    $ECHO "    Registering $path\n    as $name for scope $scope\n"

    if [ "${scope}" != "ALL" ]; then
	# Scope is reference to registered app.  It must already be registered.
	isAppRegistered $scope
	if [ $? -eq 1 ]; then
	    printOut "Error! \"$scope\" has not been registered." 1>&2
	    exit $EXIT_FAILURE
	fi

	# Extract the basename of the app's install directory.  This
	# basename is also used to deploy the app in the console's
	# repository, where we install the jar to the app's WEB-INF/lib.
	#
	getConsoleAppbaseDir
	getConsoleBaseDir
	regAppInfo=`getRegAppBy pluginID $scope`
	dir=`getRegAppValue $regAppInfo path`
	libdir=${CONSOLE_APPBASE_DIR}/`basename $dir`/WEB-INF/lib
	if [ ! -d "${libdir}" ]; then
	    printOut "Error! \"${libdir}\" for scope \"$scope\" does not exist." 1>&2
	    exit $EXIT_FAILURE
	fi
	rm -f $libdir/$name >/dev/null 2>&1
	if [ $linkFlag -eq 0 ]; then
	    cp $path $libdir/$name
	    chmod 644 $libdir/$name
	else
	    ln -s $path $libdir/$name
	fi
    fi
    
    # Create the jar list file if it doesn't exist or if its size is 0
    if [ ! -s $CONSOLE_BASE_DIR/$REG_JAR_LIST ]; then
        doBanner $CONSOLE_BASE_DIR/$REG_JAR_LIST
    fi

    # normalize the path so that it gets written out relative to the client.
    if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	path=`$ECHO $path | sed -e "s@^${BASEDIR}/@/@"`
    fi

    ## Remove trailing slashes (/) and double slashes (//) from the path
    path=`$ECHO $path | sed -e 's@/*$@@' -e 's@//*@/@g'`


    # Append the jar name to the registered jar list, but only if
    # it does not already exists as registered ujnder the specified
    # scope.  This is to support registration overlays, without having
    # duplicate entries in the database.
    #
    regJarInfo=`getRegJarBy "$scope" "$name"`
    if [ ! -n "$regJarInfo" ]; then
	$ECHO "$scope|$name|$path" >> $CONSOLE_BASE_DIR/$REG_JAR_LIST
    fi
    
} ## end registerJar


################################################################################
#
# registerModule
#
# Registers a login module.  The specified login module is added to
# the specified login service.  Only the intermediate registered_modules
# file is changed, not the final JAAS config file - that gets re-written
# when the server is restarted based on the content of registered_modules.
#
# $1 = service type
# $2 = LoginModule class name 
# $3 = behavior
# $4, $5, ... = zero or more "name=value" pairs
#
################################################################################

registerModule() {

    service=$1
    moduleName=$2
    behavior=$3

    if [ `inMiniRoot` = "1" ]; then

	getConsoleInstallDir

	# Re-create the original command that got us here in the 1st place.
	# IMPORTANT:  Replace the pattern that signifies where a whitespace
	# should be, and replace it with a whitespace.  Also, enclose the 
	# value part in quotes, being careful not to leave it with pairs of 
	# double quotes in case the value already was enclosed in quotes.
	#
	props=""
	while [ -n "$4" ]; do
	    p=`$ECHO ${4} | sed -e "s@$WHITESPACE_KEY_PATTERN@ @" \
		-e 's/=/=\"/' -e 's/$/\"/' | sed -e "s/\"\"/\"/g"`
	    props="${props}${OPTION_PREFIX}${p}\n"
	    shift
	done

	# module deferment format
	# [format - ${class}]
	# class=
	# behavior=
	# service=
	# options1=
	# ...
	# optionsN=


	# initialize header
	properties="[${MODULE} - ${moduleName}]\n"

	# class
	properties="${properties}${CLASS_PROP}=${moduleName}\n"

	# behavior
	properties="${properties}${BEHAVIOR_PROP}=${behavior}\n"

	# service
	properties="${properties}${SERVICE_PROP}=${service}\n"

	# service
	properties="${properties}${props}\n"

	#
	# Write recored to defer file
	#
	deferFile=${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}/${DEFER_FILE}

	# if the private dir directory doesn't exist make it
	if [ ! -d ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR} ]; then
	    mkdir -p ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}
	fi

	# write the entry to the defer file
	$ECHO ${properties} >> ${deferFile}

	return
    fi

    printOut "Registering login module $moduleName"

    # Move all options into a single variable.
    # IMPORTANT:  For argument in 'name=value' format, replace the pattern
    # that signifies that signifies where a whitespace should be, and
    # replace it with a whitespace.  Also, enclose the value part in quotes,
    # being careful not to leave it with pairs of double quotes in case
    # the value already was enclosed in quotes.
    options=""
    while [ -n "$4" ]; do
	p=`$ECHO ${4} | sed -e "s@$WHITESPACE_KEY_PATTERN@ @" \
	    -e 's/=/=\"/' -e 's/$/\"/' | sed -e "s/\"\"/\"/g"`
	if [ -n "${options}" ]; then
	    options="${options} ${p}"
	else
	    options=${p}
	fi
	shift
    done

    getConsoleBaseDir

    # Read the registered modules file, one line at a time, searching for
    # a line which matches the specified service and module.  If a match is
    # found, the line is replaced with specified behavior and options.
    # If no match is found, the module is appended to the registered modules
    # file.  Note that we use a zero-length file as the "flag" to indicate
    # that a match is found - can't use variables inside the 'while' loop
    # which is a seperate process.
    #
    FILE=$CONSOLE_BASE_DIR/$REG_MODULE_LIST
    if [ ! -s $FILE ]; then
	doBanner $FILE
    fi
    tmp=${FILE}.$$
    found=/tmp/found.$$
    rm -f $tmp $found >/dev/null
    cat $FILE | \
    while read line
    do
	# Ignore empty lines or lines starting with a comment character.
	firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
	if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
	    $ECHO $line >> $tmp
	    continue
	fi

	# Extract the service and module
	s=`$ECHO $line | awk -F'|' '{print $1}'`
	m=`$ECHO $line | awk -F'|' '{print $2}'`

	# Found it, so replace with new entry.
	if [ "${s}" = "${service}" -a "${m}" = "${moduleName}" ]; then
	    $ECHO "${service}|${moduleName}|${behavior}|${options}" >> $tmp
	    touch $found
	    continue
	fi

	# Keep this one.
	$ECHO $line >> $tmp
    done

    # If not found, append it.
    if [ ! -f $found ]; then
	$ECHO "${service}|${moduleName}|${behavior}|${options}" >> $tmp
    fi

    # New registered modules file
    mv $tmp $FILE

    rm -f $found >/dev/null

    # Now, there is a requirement at this time that PamLoginModule be the
    # 1st login module and RbacRoleLoginModule be 2nd.  It is possible that
    # the database might not reflect this, such as after an upgrade, or in
    # the case where the webconsole was removed but a 3rd-party module was 
    # not unregistered.  So we have to re-construct the file such that the
    # aforementioned ordering is honored.
    #
    order=/tmp/order.$$
    notorder=/tmp/notorder.$$
    rm -f $order $notorder > /dev/null
    grep PamLoginModule $FILE > $order
    grep RbacRoleLoginModule $FILE >> $order
    grep -v PamLoginModule $FILE | grep -v RbacRoleLoginModule | grep -v "^#" > $notorder
    rm -f $FILE
    doBanner $FILE
    cat $order $notorder >> $FILE
    rm -f $order $notorder > /dev/null

} ## registerModule


################################################################################
#
# deferRegistration
#
# Handles management of registrations by deferring actual
# registration until the next server restart.  We do this by
# creating a command script which can be executed on the running client.  
# But we must implement a scheme to ensure that the script will only run once.  
# We can do this by timestamping the script, and having the script save it's 
# timestamp to a file on the client.  We have to save the timestamp in this 
# way because the command script will be created on the /usr partition which 
# may be read-only at client runtime (eg. diskless clients) and in which case 
# we may not be able to delete the script after it is run.
#
# $1 = the registration command to defer
#
################################################################################

deferRegistration() {

    cmd=$1
    getConsoleInstallDir

    # The name of the command script file to which the registration command 
    # is echoed.  The script must be unique, so we base it on a date/time
    # stamp, taking into consideration that consecutive registration commands
    # could have been requested within a 1-second interval yielding the
    # same date/time.  We solve this by appending a numeric suffix.
    #
    DATESTAMP=`date -u +"%Y"%m"%d"%H"%M"%S""`
    REG_DIR=$CONSOLE_INSTALL_DIR/lib/.reg
    mkdir -p $REG_DIR
    NNN=1
    script=${REG_DIR}/${DATESTAMP}-${NNN}
    while [ -s "$script" ]; do
        NNN=`(expr $NNN + 1)`
        script="${REG_DIR}/${DATESTAMP}-$NNN"
    done

    # Create self-timestamped script
    cat << \DRPEOF | sed -e "s/_datestamp_/${DATESTAMP}/" \
	-e "s/NNN/${NNN}/" > ${script}
#!/bin/sh

# THIS FILE IS AUTOMATICALLY GENERATED.  DO NOT EDIT.

DATESTAMP=_datestamp_
REG_DATE=0
REG_DIR=${PLATFORM_BASE_PATH}/.reg
REG_DATE_FILE=${REG_DIR}/_datestamp_-NNN
if [ -f ${REG_DATE_FILE} ]; then
    . ${REG_DATE_FILE}
fi
if [ `expr ${DATESTAMP} \> ${REG_DATE}` = "1" ]; then
DRPEOF

    # Insert the new registration command for this property.
    $ECHO "    $cmd" >> $script

    # Have command script output its timestamp to a file on the client.
    $ECHO "    mkdir -p \${REG_DIR}" >> $script
    $ECHO "    echo \"REG_DATE=\${DATESTAMP}\" > \${REG_DATE_FILE}" >> ${script}

    # Finish off 'if' clause that was started above.
    $ECHO "fi" >> ${script}
    $ECHO "exit 0" >> ${script}

    chmod 744 $script

} ## deferRegistration


################################################################################
#
# registerProperties
#
# Registers the specified properties.
#
# $1 = 0 means the properties are server configuration properties that must
#      be written to the configuration file service.properties.
#      1 means the properties are environment properties that must
#      be written to the environment file service.properties.
#      If the property already exists, it will be overwritten.
#
#      !!! WARNING !!! This flag is ignored for version 3.0!
#                      All properties are written to service.properties
#
# $2 = series of name=value pairs.
#
################################################################################

registerProperties() {

    typeFlag=$1
    shift 1

    if [ `inMiniRoot` = "1" ]; then

        getConsoleInstallDir

	# Initialize properties
	properties=""
	while [ -n "$1" ]; do
	    p=`$ECHO ${1} | sed -e "s@$WHITESPACE_KEY_PATTERN@ @g" \
		-e 's/=/=\"/' -e 's/$/\"/' | sed -e "s/\"\"/\"/g"`

	    # strip off the property name
	    propName=`$ECHO ${p} | awk -F= '{print $1}'`

	    # build a header for this property
	    header="[${PROPERTY} - ${propName}]"

	    # add it to the list of properties
	    properties="${properties}${header}\n${p}\n\n"

	    shift
	done

	#
	# Write properties to defer file
	#
	deferFile=${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}/${DEFER_FILE}

	# if the private dir directory doesn't exist make it
	if [ ! -d ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR} ]; then
	    mkdir -p ${CONSOLE_INSTALL_DIR}/${PRIVATE_DIR}
	fi

	# write the entry to the defer file
	$ECHO ${properties} >> ${deferFile}

	return

    else

	getConsoleConfigDir

	# The name of the config file in which to add the property
	# 3.0: only support service.properties
	# if [ $typeFlag -eq 0 ]; then
	    FILE=$CONSOLE_CONFIG_DIR/$SERVICE_FILENAME
	    title="Server configuration properties"
	    perms=644
	# else
	#    FILE=$CONSOLE_CONFIG_DIR/.webconsole
	#    title="Server environment properties"
	#    perms=400
	# fi

	TMPFILE=${FILE}.$$
	rm -f $TMPFILE >/dev/null 2>&1

	# Create the config file if it does not exist.
	if [ ! -s "$FILE" ]; then
	    # Prepend appropriate comment characters to the auto-generated
	    # header, and include optional 2nd line of header.
	    AUTOGENERATEDSTRING="${AUTOGENERATEDSTRING}"
	    doBanner $FILE "###  $title   ###\n\n"
	fi

	propErr=0
	numFailure=0;

	# Process each argument as a name=value pair.
	while [ -n "$1" ]; do
	    # IMPORTANT:  Replace the pattern that signifies where a 
	    # whitespace should be, and replace it with a whitespace.
	    p=`$ECHO ${1} | sed -e "s@$WHITESPACE_KEY_PATTERN@ @g"`

	    # Must be in "name=value" format
	    $ECHO ${p} | grep "=" >/dev/null 2>&1
	    if [ $? -ne 0 ]; then
		$ECHO "Invalid property format: $p"
		$ECHO "Properties must be in name=value format"
		numFailure=`(expr $numFailure + 1)`
		shift
		continue
	    fi

	    # Extract name and value
	    name=`$ECHO ${p} | cut -d"=" -f1`
	    value=`$ECHO ${p} | cut -d"=" -f2-`

	    # Environment names cannot have embedded periods (.)
	    if [ $typeFlag -eq 1 ]; then
		env_check=`$ECHO $name | cut -d"." -f1`
		if [ "$name" != "$env_check" ]; then
		    $ECHO "Invalid environment property name: $name.  \c"
		    $ECHO "No dots (.) allowed."
		    numFailure=`(expr $numFailure + 1)`
		    shift
		    continue
		fi
	    fi

	    # Property name cannot have embedded spaces
	    if [ `$ECHO $name | wc -w` -gt 1 ]; then
		$ECHO "Invalid environment property name: $name.  No spaces allowed"
		$ECHO ""
		numFailure=`(expr $numFailure + 1)`
		shift
		continue
	    fi

	    # Make sure name and value are valid
	    if [ ! -n "$name" -o ! -n "$value" ]; then

		# Show this once, even if multiple props are invalid
		# because we can't really determine users actual intent.
		if [ $propErr -eq 0 ]; then
		    $ECHO "Properties must be of the form name=value."
		    $ECHO "Property names cannot contain spaces."
		    $ECHO "If you wish to include spaces in the properties"
		    $ECHO "value, place quotes around the name value pair :"
		    $ECHO " \" name = value data \""

                    propErr=1
		    numFailure=`(expr $numFailure + 1)`
		fi
		shift
		continue
	    fi

	    # If the property exists, delete it.
	    sed -e "/^${name}=/d" $FILE > $TMPFILE

	    # Insert property to file
	    $ECHO "${name}=${value}" >> $TMPFILE
	    mv $TMPFILE $FILE

	    chmod $perms $FILE

	    shift
	done
	rm -f $TMPFILE >/dev/null 2>&1

	if [ $numFailure -ne 0 ]; then
	    exit $EXIT_USAGE 1>&2		
	fi

    fi

} # registerProperties


################################################################################
#
# unregisterJar
#
# Unregisters the specified jar file from the specified scope.
#
# $1 = scope under which to register the jar.  This can be the
#      token "ALL", in which case the scope is global and the jar
#      is shared by all apps.  Alternatively, this can be an
#      application's registered name, which is <pluginName>_<version>,
#      where <pluginName> and <version> are as specified in the app's web.xml
# $2 = the registered name of the library
#
################################################################################

unregisterJar() {

    scope=$1
    name=$2

    if [ `inMiniRoot` = "1" ]; then

	getConsoleInstallDir

	# Normalize the path so that the command gets written out so that it
	# resolves relative to the client's runtime.
	command=${PROGDIR}/${PROGNAME}
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    command=`$ECHO $command | sed -e "s@^${BASEDIR}/@/@"`
	fi

	# Re-create the original command that got us here in the 1st place.
	#
	p=$1
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    p=`$ECHO $p | sed -e "s@^${BASEDIR}/@/@"`
	fi
	cmd="$command remove -l -s $scope $name"

	# Defer unregistration, and make it silent in the face of errors,
	# as there are scenarios during OS upgrades in which outputting an
	# an error when unregistration fails in 2-stage deployment does not
        # make sense.  Note: this is NOT a public API!.
	#
	deferRegistration "env SILENT_REMOVE=true $cmd"

	return
    fi
    
    getConsoleAppbaseDir
    getConsoleBaseDir
    
    # if registered jars list doesn't exist, we know it's not registered                                
    if [ ! -s $CONSOLE_BASE_DIR/$REG_JAR_LIST ]; then
        if [ "$SILENT_REMOVE" != "true" ]; then
            printOut "$1 is not registered!"
	fi
        return 1
    fi

    # Name must include .jar suffix, so add it if not provided.
    suffix=`$ECHO $name | awk '{i=index($1, ".jar")}{print substr($1, i, length($1)-i+1)}'` 
    if [ $suffix != ".jar" ]; then
	name=${name}.jar
    fi
    
    # Test if jar is actually registered under the specified scope
    regJarInfo=`getRegJarBy "$scope" "$name"`
    if [ ! -n "$regJarInfo" ]; then
        if [ "$SILENT_REMOVE" != "true" ]; then
            printOut "$name not registered for scope $scope!" 1>&2
	fi
        exit $EXIT_FAILURE
    fi
    
    printOut "Unregistering $name from scope $scope"

    if [ "${scope}" = "ALL" ]; then

	getTomcatInstallDir

	# It is possible Tomcat could be located on a shared read-only
	# filesystem.  On Solaris this could be within a zone.  So
	# only remove the jar if we have write access to the Tomcat area.
	#
	tiptoe=$TOMCAT_INSTALL_DIR/_.$$
	touch $tiptoe >/dev/null 2>&1
	if [ $? -eq 0 ]; then
	    rm -f $tiptoe

	    # Delete jar from Tomcat's lib directory
	    if [ "${OS}" = "AIX" ]; then
		rm -f ${TOMCAT_INSTALL_DIR}/shared/lib/$name >/dev/null 2>&1
	    else
		rm -f ${TOMCAT_INSTALL_DIR}/lib/$name >/dev/null 2>&1
	    fi
	fi

    else
	# Scope is reference to registered app.  It must already be registered.
	isAppRegistered $scope
	if [ $? -eq 1 ]; then
            if [ "$SILENT_REMOVE" != "true" ]; then
	        printOut "Error! \"$scope\" has not been registered." 1>&2
	    fi
	    exit $EXIT_FAILURE
	fi

	# Extract the basename of the app's install directory.  This
	# basename is also used to deploy the app in the console's
	# repository, where we delete the jar from the app's WEB-INF/lib.
	#
	getConsoleAppbaseDir
	getConsoleBaseDir
	regAppInfo=`getRegAppBy pluginID $scope`
	dir=`getRegAppValue $regAppInfo path`
	dir=${CONSOLE_APPBASE_DIR}/`basename $dir`
	rm -f $dir/WEB-INF/lib/$name >/dev/null 2>&1
    fi
    
    # Now update the list of registered jars
    removeRegJarBy $scope $name

} ## end unregisterJar


################################################################################
#
# unregisterApp
#
# Unregister the specified application.
#
# $1 = the registered name of the application
#
################################################################################

unregisterApp() {

    name=$1

    if [ `inMiniRoot` = "1" ]; then

	getConsoleInstallDir

	# Normalize the path so that the command gets written out so that it
	# resolves relative to the client's runtime.
	command=${PROGDIR}/${PROGNAME}
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    command=`$ECHO $command | sed -e "s@^${BASEDIR}/@/@"`
	fi

	# Re-create the original command that got us here in the 1st place.
	#
	p=$1
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    p=`$ECHO $p | sed -e "s@^${BASEDIR}/@/@"`
	fi
	cmd="$command remove -a $p"

	# Defer unregistration, and make it silent in the face of errors,
	# as there are scenarios during OS upgrades in which outputting an
	# an error when unregistration fails in 2-stage deployment does not
        # make sense.  Note: this is NOT a public API!.
	#
	deferRegistration "env SILENT_REMOVE=true $cmd"

	return
    fi

    printOut "Unregistering $name."

    getConsoleBaseDir
    getConsoleAppbaseDir

    # Check for remove by context and remove the app 
    # from the appbase directory.
    regAppInfo=`getRegAppBy context $name`
    if [ -n "$regAppInfo" ]; then
	dir=`getRegAppValue $regAppInfo path`
	removeAppRegnot $dir
	dir=${CONSOLE_APPBASE_DIR}/`basename $dir`
	rm -rf $dir >/dev/null 2>&1
	removeRegAppBy context $name
	return
    fi

    # Check for remove by pluginID and remove the app
    # from the appbase directory.
    regAppInfo=`getRegAppBy pluginID $name`
    if [ -n "$regAppInfo" ]; then
	dir=`getRegAppValue $regAppInfo path`
	removeAppRegnot $dir
	dir=${CONSOLE_APPBASE_DIR}/`basename $dir`
	rm -rf $dir >/dev/null 2>&1
	removeRegAppBy pluginID $name
	return
    fi

    # Shouldn't get here unless app was not already registered.
    if [ "$SILENT_REMOVE" != "true" ]; then
	printOut "Error! \"$name\" has not been registered." 1>&2
        exit $EXIT_FAILURE
    fi

} ## end unregisterApp


################################################################################
#
# unregisterModule
#
# Unregisters a login module.  The specified login module is removed from
# the specified login service.  Only the intermediate registered_modules
# file is changed, not the final JAAS config file - that gets re-written
# when the server is restarted based on the content of registered_modules.
#
# $1 = service type
# $2 = LoginModule class name 
#
################################################################################

unregisterModule() {

    service=$1
    moduleName=$2

    if [ `inMiniRoot` = "1" ]; then

	getConsoleInstallDir

	# Normalize the path so that the command gets written out so that it
	# resolves relative to the client's runtime.
	command=${PROGDIR}/${PROGNAME}
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    command=`$ECHO $command | sed -e "s@^${BASEDIR}/@/@"`
	fi

	# Re-create the original command that got us here in the 1st place.
	#
	cmd="$command remove -m -s $service $moduleName"

	deferRegistration "$cmd"

	return
    fi

    printOut "Unregistering login module $moduleName."

    getConsoleBaseDir

    # Read the registered modules file, one line at a time, tossing out
    # all lines which match the specified service and module and writing
    # everything else to a tmp file, which then becomes the new
    # registered modules.
    #
    FILE=$CONSOLE_BASE_DIR/$REG_MODULE_LIST
    tmp=${FILE}.$$
    rm -f $tmp >/dev/null
    cat $FILE | \
    while read line
    do
	# Ignore empty lines or lines starting with a comment character.
	firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
	if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
	    $ECHO $line >> $tmp
	    continue
	fi

	# Extract the service and module
	s=`$ECHO $line | awk -F'|' '{print $1}'`
	m=`$ECHO $line | awk -F'|' '{print $2}'`

	# Found it, so ignore it
	if [ "${s}" = "${service}" -a "${m}" = "${moduleName}" ]; then
	    continue
	fi

	# Keep this one.
	$ECHO $line >> $tmp
    done

    # New registered modules file
    mv $tmp $FILE

} ## unregisterModule


################################################################################
#
# unregisterProperties
#
# Unregisters the specified properties.
#
# $1 = 0 means the properties are server configuration properties that must
#      be deleted from the configuration file service.properties.
#      1 means the properties are environment properties that must
#      be deleted from the environment file service.properties.
#      If the property does not exist, who cares!
#
#      !!! WARNING !!! This flag is ignored for version 3.0!
#                      All properties are removed from services.properties
#
# $2 = series of named properties
#
################################################################################

unregisterProperties() {

    typeFlag=$1
    shift 1

    if [ `inMiniRoot` = "1" ]; then

	getConsoleInstallDir

	# Normalize the path so that the command gets written out so that it
	# resolves relative to the client's runtime.
	command=${PROGDIR}/${PROGNAME}
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    command=`$ECHO $command | sed -e "s@^${BASEDIR}/@/@"`
	fi

	# Re-create the original command that got us here in the 1st place.
	#
	if [ $typeFlag -eq 0 ]; then
	    cmd="$command remove -p -c $*"
	else
	    cmd="$command remove -p -e $*"
	fi

	deferRegistration "$cmd"

    else

	getConsoleConfigDir

	# The name of the config file from which to remove the property
	# 3.0: Only support service.properties
	# if [ $typeFlag -eq 0 ]; then
	    FILE=$CONSOLE_CONFIG_DIR/$SERVICE_FILENAME
	    title="Server configuration properties"
	    perms=644
	# else
	#     FILE=$CONSOLE_CONFIG_DIR/.webconsole
	#     title="Server environment properties"
	#     perms=400
	# fi

	# If the file does not exist, no property to delete.
	if [ ! -s "$FILE" ]; then
	    return
	fi

	TMPFILE=${FILE}.$$
	rm -f $TMPFILE >/dev/null 2>&1

	numFailure=0;
	# Process each argument as a property name.
	while [ -n "$1" ]; do
	    name=$1
	    # Property names cannot have equals (=)
	    $ECHO $1 | grep "[=]" >/dev/null 2>&1
	    if [ $? -eq 0 ]; then 
		$ECHO "Invalid property name: $name.  \c"
		$ECHO "No equals (=) allowed."
		numFailure=`(expr $numFailure + 1)`
		shift
		continue
	    fi		

	    # Environment names cannot have embedded periods (.)
	    if [ $typeFlag -eq 1 ]; then
		env_check=`$ECHO $name | cut -d"." -f1`
		if [ "$name" != "$env_check" ]; then
		    $ECHO "Invalid environment property name: $name.  \c"
		    $ECHO "No dots (.) allowed."
		    numFailure=`(expr $numFailure + 1)`
		    shift
		    continue
		fi
	    fi

	    # If the property exists, delete it.
	    sed -e "/^${name}=/d" $FILE > $TMPFILE 
	    mv $TMPFILE $FILE

	    chmod $perms $FILE

	    shift
	done
	rm -f $TMPFILE >/dev/null 2>&1

	if [ $numFailure -ne 0 ]; then
	    exit $EXIT_USAGE 1>&2		
	fi

    fi

} # unregisterProperties


################################################################################
#
# checkForServletTags
#
# Check to make sure the app has the correct servlet tags for the
# specified servlet.
#
# $1 = the full path (including filename) of the web.xml file
# $2 = servlet name
# $3 = servlet class
# $4 = servlet URL
#
# Returns a pair of boolean string values (either "true" or "false"), to
# to indicate whether the <servlet> and <servlet-mapping> tags for specified
# servlet should be added to the web.xml.
#
################################################################################

checkForServletTags() {

    ##
    ## Check for an existing web.xml file.
    ##
    WEB_XML=$1
    if [ ! -s $WEB_XML ]; then
	printOut "Error! \"$WEB_XML\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

    SERVLET_NAME=$2
    SERVLET_CLASS=$3
    SERVLET_URL=$4

    # Flags that indicate whether or not servlet tags should be added to 
    # the web.xml file.  We assume true both and prove otherwise.
    add_servlet=true
    add_servlet_mapping=true


    ##
    ## Enforce that the starting char sequence of a comment is preceeded with
    ## white space, and the ending char sequence is followed by white space. 
    ## Also, enforcing that this will ensure that each comment beginning and 
    ## ending will be treated as a word separate from the tags in the file.
    ##
    WEB_XML_CONTENT=`cat $WEB_XML \
	| sed -e 's@<!--@ <!--@g' -e 's@-->@--> @g' -e 's@><@> <@g'`
    for word in $WEB_XML_CONTENT; do
	case $word in

	"<!--"* )
	    IN_COMMENT="true"
	    ;;
	*"-->" )
	    IN_COMMENT="false"
	    ;;

	$SERVLET_START_TAG* )
	    IN_SERVLET_TAG="true"
	    ;;

	$SERVLET_END_TAG* )
	    IN_SERVLET_TAG="false"

	    ## Check the contents of the servlet-name and servlet-class 
	    ## tags here.
	    if [ "$SERVLET_NAME_CONTENT" = "$SERVLET_NAME" \
		-a "$SERVLET_CLASS_CONTENT" = "$SERVLET_CLASS" ]; then
		add_servlet=false
	    fi
	    ;;

	$SERVLET_MAPPING_START_TAG* )
	    IN_SERVLET_MAPPING_TAG="true"
	    ;;

	$SERVLET_MAPPING_END_TAG* )
	    IN_SERVLET_MAPPING_TAG="false"

	    ## Check the contents of the servlet-name and url-pattern \
	    ## tags here.
	    if [ "$SERVLET_NAME_CONTENT" = "$SERVLET_NAME" \
		-a "$URL_PATTERN_CONTENT" = "$SERVLET_URL" ]; then
		add_servlet_mapping=false
	    fi
	    ;;

	$URL_PATTERN_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_SERVLET_MAPPING_TAG" != "true" ] && continue

	    ## Attempt to extract the url-pattern content from the line.
	    URL_PATTERN_CONTENT=`$ECHO $word \
		| sed -e 's@.*'$URL_PATTERN_START_TAG'@@' \
		| sed -e 's@'$URL_PATTERN_END_TAG'.*@@' \
		| sed -e 's@\"@@g' -e "s@^\'@@"`

	    ##
	    ## If URL_PATTERN_CONTENT is not empty, we have our data. Otherwise,
	    ## the start/end tags and tag content span multiple "words". Set 
	    ## a flag to indicate the tag content will be the next word read.
	    ##
	    if [ "$URL_PATTERN_CONTENT" = "" ]; then
		URL_PATTERN_START_TAG_FOUND="true"
	    fi
	    ##
	    ;;

	$SERVLET_NAME_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_SERVLET_TAG" != "true" \
		-a "$IN_SERVLET_MAPPING_TAG" != "true" ] && continue

	    ## Attempt to extract the servlet-name content from the line.
	    SERVLET_NAME_CONTENT=`$ECHO $word \
		| sed -e 's@.*'$SERVLET_NAME_START_TAG'@@' \
		| sed -e 's@'$SERVLET_NAME_END_TAG'.*@@' \
		| sed -e 's@\"@@g' -e "s@^\'@@"`

	    ##
	    ## If SERVLET_NAME_CONTENT is not empty, we have our data. Otherwise,
	    ## the start/end tags and tag content span multiple "words". Set 
	    ## a flag to indicate the tag content will be the next word read.
	    ##
	    if [ "$SERVLET_NAME_CONTENT" = "" ]; then
		SERVLET_NAME_START_TAG_FOUND="true"
	    fi
	    ##
	    ;;

	$SERVLET_CLASS_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_SERVLET_TAG" != "true" ] && continue

	    ## Attempt to extract the servlet-class content from the line.
	    SERVLET_CLASS_CONTENT=`$ECHO $word \
		| sed -e 's@.*'$SERVLET_CLASS_START_TAG'@@' \
		| sed -e 's@'$SERVLET_CLASS_END_TAG'.*@@' \
		| sed -e 's@\"@@g' -e "s@^\'@@"`

	    ##
	    ## If SERVLET_CLASS_CONTENT is not empty, we have our data. Otherwise,
	    ## the start/end tags and tag content span multiple "words". Set 
	    ## a flag to indicate the tag content will be the next word read.
	    ##
	    if [ "$SERVLET_CLASS_CONTENT" = "" ]; then
		SERVLET_CLASS_START_TAG_FOUND="true"
	    fi
	    ;;

	* )
	    [ "$IN_COMMENT" = "true" ] && continue

	    ##
	    ## We're in the middle of reading in the servlet-name content. The
	    ## next word will be the content.
	    ##
	    if [ "$SERVLET_NAME_START_TAG_FOUND" = "true" ]; then
		SERVLET_NAME_CONTENT=`$ECHO $word \
		    | sed -e 's@'$SERVLET_NAME_END_TAG'.*@@' \
		    | sed -e 's@\"@@g' -e "s@^\'@@"`
		SERVLET_NAME_START_TAG_FOUND="false"
	    fi

	    ##
	    ## We're in the middle of reading in the servlet-class content. The
	    ## next word will be the content.
	    ##
	    if [ "$SERVLET_CLASS_START_TAG_FOUND" = "true" ]; then
		SERVLET_CLASS_CONTENT=`$ECHO $word \
		    | sed -e 's@'$SERVLET_CLASS_END_TAG'.*@@' \
		    | sed -e 's@\"@@g' -e "s@^\'@@"`
		SERVLET_CLASS_START_TAG_FOUND="false"
	    fi

	    ##
	    ## We're in the middle of reading in the url-pattern content. The
	    ## next word will be the content.
	    ##
	    if [ "$URL_PATTERN_START_TAG_FOUND" = "true" ]; then
		URL_PATTERN_CONTENT=`$ECHO $word \
		    | sed -e 's@'$URL_PATTERN_END_TAG'.*@@' \
		    | sed -e 's@\"@@g' -e "s@^\'@@"`
		URL_PATTERN_START_TAG_FOUND="false"
	    fi
	    ;;

	esac

    done

    echo "$add_servlet $add_servlet_mapping"

} ## end checkForServletTags


################################################################################
#
# addServletTags
#
# Add the servlet and servlet-mapping tags required by the console to the app's
# web.xml file. The final web.xml will be printed to stdout, and can be
# redirected to another file to save the output.
#
# NOTE: the checkForServletTags function should be called before this one to be
# sure that we actually need to add the tags.
#
# $1 = the full path (including filename) of the web.xml file
# $2 = true or false, indicates whether the <servlet> tag for the
#      specified servlet should be added to the web.xml file.
# $3 = true or false, indicates whether the <servlet-mapping> tag for the 
#      specified servlet should be added to the web.xml file.
# $4 = servlet name
# $5 = servlet class
# $6 = servlet URL
# $7 = servlet load on startup priority
#
################################################################################

addServletTags() {

    # If both tags already exist, then nothing to do.
    if [ "${2}" = "false" -a "${3}" = "false" ]; then
	return
    fi

    SERVLET_NAME=$4
    SERVLET_CLASS=$5
    SERVLET_URL=$6

    # make sure we have a value for load priority
    if [ -n "$7" ]; then
        SERVLET_LOAD_PRIORITY=$7
    else
        SERVLET_LOAD_PRIORITY=$NO_LOAD_ON_STARTUP
    fi

    ##
    ## Write out the new web.xml file with the servlet and servlet-mapping tags
    ## for servlet inserted in the designated place. NOTE: The 'sed' 
    ## statement below performs the following task: if a end tag/comment 
    ## char ">" and a start tag/comment char "<" occur on the same line, force
    ## them onto two separate lines. This helps ensure that the servlet and 
    ## servlet-mapping tags don't get inserted in a weird place.
    ##
    WEB_XML_FILE=$1
    TMP_WEBXML=${WEB_XML_FILE}.$$
    rm ${TMP_WEBXML} >/dev/null 2>&1
    touch ${TMP_WEBXML}
    sed -e 's/> */>/g' -e 's/></>\
</g' $WEB_XML_FILE | ${NAWK} 'BEGIN {
	FS=" "
	IN_COMMENT=""
	ADD_SERVLET_TAG=""
	ADD_SERVLET_MAPPING_TAG=""
	SERVLET_ADDED=""
	SERVLET_MAPPING_ADDED=""
	PRINT_LINE="true"
    }

    /<!--/			{ IN_COMMENT="true" }
    /-->/			{ IN_COMMENT="false" }
    /<web-app>/			{ }
    /<icon>/			{ }
    /<display-name>/		{ }
    /<description>/		{ }
    /<distributable>/		{ }
    /<context-param>/		{ }
    /<filter>/			{ }
    /<filter-mapping>/		{ }
    /<listener>/		{ }
    /<servlet>/			{ ADD_SERVLET_TAG="'${2}'"; }
    /<servlet-mapping>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<session-config>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<mime-mapping>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<welcome-file-list>/	{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<error-page>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<taglib>/			{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<resource-env-ref>/	{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<resource-ref>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<security-constraint>/	{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<login-config>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<security-role>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<env-entry>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<ejb-ref>/			{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<ejb-local-ref>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }
    /<\/web-app>/		{ ADD_SERVLET_TAG="'${2}'"; 
				  ADD_SERVLET_MAPPING_TAG="'${3}'" }


    ############################################################################
    #
    # This function adds the servlet components <servlet> tag required by the 
    # console to the web.xml file in the required location.
    #
    ############################################################################

    function addServletTag() {
	print "  <servlet>"
	print "    <servlet-name>'$SERVLET_NAME'</servlet-name>"
	print "    <servlet-class>"
	print "      '$SERVLET_CLASS'"
	print "    </servlet-class>"
	if ('$SERVLET_LOAD_PRIORITY' != '$NO_LOAD_ON_STARTUP') {
	    print "  <load-on-startup>"
	    print "      '$SERVLET_LOAD_PRIORITY'"
	    print "  </load-on-startup>"
	}
	print "  </servlet>"

    } ## end addServletTag


    ############################################################################
    #
    # This function adds the application <servlet-mapping> tag required by the
    # console to the web.xml file in the required location.
    #
    ############################################################################

    function addServletMappingTag() {
	print "  <servlet-mapping>"
	print "    <servlet-name>'$SERVLET_NAME'</servlet-name>"
	print "    <url-pattern>'$SERVLET_URL'</url-pattern>"
	print "  </servlet-mapping>"

    } ## end addServletMappingTag


    ############################################################################
    #
    # main function
    #
    ############################################################################

    {
	## Add in our servlet tag if they have not been added already
	if (ADD_SERVLET_TAG == "true") {
	    if (SERVLET_ADDED != "true") {
		if (IN_COMMENT == "true") {
		    print
		    print "-->"
		}
		addServletTag()
		SERVLET_ADDED="true"
		if (IN_COMMENT == "true") {
		    print "<!--"

		    # This flag indicates the line was already printed
		    PRINT_LINE="false"
		}
	    }
	}

	## Add in our servlet-mapping tag if they have not been added already
	if (ADD_SERVLET_MAPPING_TAG == "true") {
	    if (SERVLET_MAPPING_ADDED != "true") {
		if (IN_COMMENT == "true") {
		    print
		    print "-->"
		}
		addServletMappingTag()
		SERVLET_MAPPING_ADDED="true"
		if (IN_COMMENT == "true") {
		    print "<!--"

		    # This flag indicates the line was already printed
		    PRINT_LINE="false"
		}
	    }
	}

	##
	## If the line was not already printed above, print it now. Otherwise
	## reset the PRINT_LINE flag to true
	##
	if (PRINT_LINE == "true") {
	    print
	} else {
	    PRINT_LINE="true"
	}
    }

    END {}' > ${TMP_WEBXML}

    # Get original permissions
    ownership=`ls -l ${WEB_XML_FILE} | awk '{print $1 " " $3 " " $4}'`

    ## Now replace the previous web.xml with the new one containing
    ## the tags for servlet.
    rm -f ${WEB_XML_FILE}
    mv ${TMP_WEBXML} ${WEB_XML_FILE}

    # Restore original permissions
    perms=`$ECHO $ownership | awk '{print $1}'`
    owner=`$ECHO $ownership | awk '{print $2}'`
    group=`$ECHO $ownership | awk '{print $3}'`
    chown ${owner}:${group} ${WEB_XML_FILE} >/dev/null 2>&1
    chmod `perms2mode ${perms}` ${WEB_XML_FILE}

} ## end addServletTags


################################################################################
#
# createDir
#
# Create directory components of file path that do not exist.
#
# $1 = relative path under $2 that needs to exist
# $2 = full path to application registration directory relative to install.
#      That is, it must be accessible now in the face of pkg relocation.
# $3 = full path to application registration directory relative to client.
#      That is, it must be accessible when the client is running.
# $4 = path to file to log the backout commands to remove created dirs.
#
################################################################################

createDir() {

    target=""

    # Strip out delimiters to obtain each component of the path.
    for component in `$ECHO $1 | sed -e "s@^\.@@" -e "s@/@ @g"`
    do
	# Recursively accumulate each component, building up the 
	# original path.
	if [ -n "${target}" ]; then
	    target=${target}/${component}
	else
	    target=${component}
	fi

	# Create the path if it does not already exist, and record a backout
	# command in the log.
        dst=${2}/${target}
	if [ ! -d "${dst}" ]; then
	    mkdir -p ${dst}
	    $ECHO "rm -rf \${BASEDIR}${3}/${target}" >> $4
	fi
    done

} ## end createDir

################################################################################
#
# installTags
#
# Install the necessary tags files to run the app.
#
################################################################################

installTags() {

    # PLUGIN_DIR refers to the install time application installation directory.
    # regPluginDir is the directory where the application must exist in order
    # to be registered to run - that is, it's location in the repository
    # but accessible now in the face of pkg relocation
    #
    getConsoleAppbaseDir
    regPluginDir=${CONSOLE_APPBASE_DIR}/`basename ${PLUGIN_DIR}`

    # Deploy the app to CONSOLE_APPBASE_DIR.
    #
    getConsoleInstallDir
    cd ${PLUGIN_DIR}/..
    find `basename $PLUGIN_DIR` -print \
	| cpio -pdmu $CONSOLE_APPBASE_DIR >/dev/null 2>&1

    # Import tags-related files into the deployed app.
    smwebappImport $regPluginDir

    # The next section involves fixing up pre-2.2 apps. smreg should add
    # help, help2 and version servlet entries in the application's web.xml 
    # if they are not present. This is because from 2.2 onwards these 
    # servlets will execute from each application's own context and not 
    # the shared (com_sun_web_ui) application.

    if [ `versionString2Num $SDK_VERSION` -lt 22000 ]; then
      # Version
      ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
        $VERSIONSERVLET_NAME $VERSIONSERVLET_CLASS $VERSIONERVLET_URL`
      addServletTags ${regPluginDir}/WEB-INF/web.xml \
        `echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
        $VERSIONSERVLET_NAME $VERSIONSERVLET_CLASS $VERSIONSERVLET_URL \
	$NO_LOAD_ON_STARTUP
 
      # Help
      ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
        $HELPSERVLET_NAME $HELPSERVLET_CLASS $HELPSERVLET_URL`
      addServletTags ${regPluginDir}/WEB-INF/web.xml \
        `echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
        $HELPSERVLET_NAME $HELPSERVLET_CLASS $HELPSERVLET_URL \
	$NO_LOAD_ON_STARTUP
 
      # Help2
      ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
        $HELP2SERVLET_NAME $HELP2SERVLET_CLASS $HELP2SERVLET_URL`
      addServletTags ${regPluginDir}/WEB-INF/web.xml \
        `echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
        $HELP2SERVLET_NAME $HELP2SERVLET_CLASS $HELP2SERVLET_URL \
	$NO_LOAD_ON_STARTUP

    fi

    # registration servlet must be added for all pre 3.0 apps
    if [ `versionString2Num $SDK_VERSION` -lt 30000 ]; then
	# Registrar
	ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
	    $REGSERVLET_NAME $REGSERVLET_CLASS $REGSERVLET_URL`
	addServletTags ${regPluginDir}/WEB-INF/web.xml \
	    `echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
	$REGSERVLET_NAME $REGSERVLET_CLASS $REGSERVLET_URL \
 	    $REGSERVLET_LOAD_PRIORITY
    fi

    # Everything below here involves fixing up pre-2.1 apps.  We do not
    # do this for apps built with the 2.1 or later SDK, as we expect the
    # developer tools to be used to verify web.xml, jsps, etc. are.
    # correct.
    if [ `versionString2Num $SDK_VERSION` -ge 21000 ]; then
	return
    fi

    # The import command only copies files needed for building apps
    # built with the 2.1 or later SDK.  See the smwebapp function for details
    # on what it copies, but it copies much less than what is needed to
    # support pre-2.1 apps.  So we have to copy the rest of the files.
    # Note that we get them from the /com_sun_web_ui web application.
    #
    cd ${console_home}/webapps/com_sun_web_ui

    target=$CONSOLE_APPBASE_DIR/`basename $PLUGIN_DIR`/com_sun_web_ui
    for dir in js images dtd css
    do
	find $dir -print | cpio -pdmu $target >/dev/null 2>&1
    done

    # Check for the existence of servlet and servlet-mapping tags for
    # various components in the web.xml, and add them if they do not exist.
    # Only apps that use these components really need these tags.

    # Table
    ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
	$TABLESERVLET_NAME $TABLESERVLET_CLASS $TABLESERVLET_URL`
    addServletTags ${regPluginDir}/WEB-INF/web.xml \
	`echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
	$TABLESERVLET_NAME $TABLESERVLET_CLASS $TABLESERVLET_URL \
	$NO_LOAD_ON_STARTUP

    # Topology
    ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
	$TOPOLOGYSERVLET_NAME $TOPOLOGYSERVLET_CLASS $TOPOLOGYSERVLET_URL`
    addServletTags ${regPluginDir}/WEB-INF/web.xml \
	`echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
	$TOPOLOGYSERVLET_NAME $TOPOLOGYSERVLET_CLASS $TOPOLOGYSERVLET_URL \
	$NO_LOAD_ON_STARTUP


    # Date Time popup        
    ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
	$DATETIMESERVLET_NAME $DATETIMESERVLET_CLASS $DATETIMESERVLET_URL`
    addServletTags ${regPluginDir}/WEB-INF/web.xml \
	`echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
	$DATETIMESERVLET_NAME $DATETIMESERVLET_CLASS $DATETIMESERVLET_URL \
	$NO_LOAD_ON_STARTUP

    # Badging
    ans=`checkForServletTags ${regPluginDir}/WEB-INF/web.xml \
	$BADGINGSERVLET_NAME $BADGINGSERVLET_CLASS $BADGINGSERVLET_URL`
    addServletTags ${regPluginDir}/WEB-INF/web.xml \
	`echo $ans | awk '{print $1}'` `echo $ans | awk '{print $2}'` \
	$BADGINGSERVLET_NAME $BADGINGSERVLET_CLASS $BADGINGSERVLET_URL \
	$NO_LOAD_ON_STARTUP

    # Ensure that all jsps and the web.xml have the correct paths to the 
    # jato and cc tlds.
    #
    files=`find ${regPluginDir} -name "*.jsp"`
    files="${files} ${regPluginDir}/WEB-INF/web.xml"
    for i in ${files}
    do
	tmp=${i}.tmp

	# Get original permissions
	ownership=`ls -l ${i} | awk '{print $1 " " $3 " " $4}'`

	sed -e "s@WEB-INF/lib/${JATO_TLD}@WEB-INF/tld/${JATO_NAMESPACE}/${JATO_TLD}@" \
	    -e "s@WEB-INF/lib/cc.tld@WEB-INF/tld/${CCTAGS_NAMESPACE}/cc.tld@" \
	    ${i} > ${tmp}

	# Only update the file if any of the paths were changed, restoring
	# original permissions.
	diffs=`diff ${i} ${tmp} > /dev/null 2>&1`
	if [ $? -ne 0 ]; then
	    perms=`$ECHO $ownership | awk '{print $1}'`
	    owner=`$ECHO $ownership | awk '{print $2}'`
	    group=`$ECHO $ownership | awk '{print $3}'`
	    mv ${tmp} ${i}
	    chown ${owner}:${group} ${i} >/dev/null 2>&1
	    chmod `perms2mode ${perms}` ${i}
	    if [ $qFlag -eq 0 ]; then
		$ECHO "Warning: obsolete path to ${JATO_TLD} or cc.tld detected in"
		$ECHO "${i}."
		$ECHO "The correct path has been applied.\n"
	    fi
	else
	    rm ${tmp}
	fi

    done

} ## end installTags


################################################################################
#
# listApps
# 
# List all registered applications.
#
################################################################################

listApps() {

    ## Make sure the list of registered apps exists
    getConsoleBaseDir
    if [ -s $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST ]; then

	## Check to make sure plugins have been registered
	LIST=`grep -v "^#" $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST`
	if [ "$LIST" != "" ]; then

	    ## Ignore lines that begin with the comment character '#'
	    printOut "The list of registered plugin applications:"
    
	    cat $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST | \
	    while read line
	    do
		# Ignore empty lines or lines starting with a comment character.
		firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
		if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
		    continue
		fi

		pluginID=`$ECHO $line | awk -F'|' '{print $2}'`
		path=`$ECHO $line | awk -F'|' '{print $3}'`
		$ECHO "\t$pluginID\t$path"
	    done
        else
            printOut "No plugin applications have been registered."
	fi
    else
        printOut "No plugin applications have been registered."
    fi

} ## end listApps


################################################################################
#
# listLibraries
# 
# List all registered jar libraries.
#
################################################################################

listLibraries() {

    ## Make sure the list of registered apps exists
    getConsoleBaseDir
    if [ -s $CONSOLE_BASE_DIR/$REG_JAR_LIST ]; then

	## Check to make sure jars have been registered
	LIST=`grep -v "^#" $CONSOLE_BASE_DIR/$REG_JAR_LIST`
	if [ "$LIST" != "" ]; then

	    ## Ignore lines that begin with the comment character '#'
	    printOut "The list of registered jar files:"
    
	    cat $CONSOLE_BASE_DIR/$REG_JAR_LIST | \
	    while read line
	    do
		# Ignore empty lines or lines starting with a comment character.
		firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
		if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
		    continue
		fi

		scope=`$ECHO $line | awk -F'|' '{print $1}'`
		name=`$ECHO $line | awk -F'|' '{print $2}'`
		path=`$ECHO $line | awk -F'|' '{print $3}'`

 	        if [ -h "${path}" ]; then
                    $ECHO "\t $name scoped to $scope as a symbolic link"
                else
	            $ECHO "\t $name scoped to $scope"
	        fi
	    done
        else
            printOut "No jar files have been registered."
	fi
    else
        printOut "No jar files have been registered."
    fi

} ## end listLibraries


################################################################################
#
# listModules
# 
# List all registered login modules.
#
################################################################################

listModules() {

    getConsoleBaseDir
    if [ ! -s $CONSOLE_BASE_DIR/$REG_MODULE_LIST ]; then
        printOut "No login modules have been registered."
	return
    fi

    # There can be multiple service definitions that need to be written
    # out.  And while the modules list is not sorted by service, the set
    # of modules for any given service are in the correct order.  So we
    # create a seperate temp file for each service containing the modules
    # for that service, and then print all the temp files to stdout.

    serviceDir=/tmp/services.$$
    rm -rf $serviceDir > /dev/null
    mkdir -p $serviceDir

    cat $CONSOLE_BASE_DIR/$REG_MODULE_LIST | \
    while read line
    do
	# Ignore empty lines or lines starting with a comment character.
	firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
	if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
	    continue
	fi

	# Extract the fields, delimited by the '|' character.
	service=`$ECHO $line | awk -F'|' '{print $1}'`
	module=`$ECHO $line | awk -F'|' '{print $2}'`
	behavior=`$ECHO $line | awk -F'|' '{print $3}'`
	options=`$ECHO $line | awk -F'|' '{print $4}'`

	if [ ! -f $serviceDir/$service ]; then
	    touch $serviceDir/$service
	fi
	if [ -n "${options}" ]; then
	    $ECHO "\t${module} ${behavior}" >> $serviceDir/$service
	    $ECHO "\t\t${options};" >> $serviceDir/$service
	else
	    $ECHO "\t${module} ${behavior};" >> $serviceDir/$service
	    $ECHO "" >> $serviceDir/$service
	fi

    done

    for service in $serviceDir/*
    do
	printOut "The list of registered login modules for service `basename $service`:"
	cat $service
    done
    rm -rf $serviceDir > /dev/null

} ## end listModules


################################################################################
#
# listProperties
# 
# List all registered properties.
#
################################################################################

listProperties() {

    getConsoleConfigDir

    CFG_PROPS="The list of registered server configuration properties:"
    NO_CFG_PROPS="No server configuration properties have been registered."
    CONF_FILE=$CONSOLE_CONFIG_DIR/$SERVICE_FILENAME
    DFLT_FILE=$CONSOLE_CONFIG_DIR/$DEFAULT_FILENAME

    # Server configuration properties
    if [ -s $CONF_FILE -a -s $DFLT_FILE ]; then

	# Print properties from default file, but allow config file
	# to override.  Preserve order of properties in the face of
	# overrides so that groups of related properties are listed
	# together.

	printOut "$CFG_PROPS"

	cat $DFLT_FILE | grep -v "^#" | grep "=" |
	while read dline; do	
	    name=`$ECHO $dline | cut -d"=" -f1`
	    value=`$ECHO $dline | cut -d"=" -f2-`
	    cline=`grep "^${name}" $CONF_FILE`
	    if [ $? -eq 0 ]; then
		name=`$ECHO $cline | cut -d"=" -f1`
		value=`$ECHO $cline | cut -d"=" -f2-`
	    fi
	    $ECHO "	${name}=${value}"
	done

	# Print properties from service file which do NOT override properties
	# found in default file (because overrides were already list above).

	cat $CONF_FILE | grep -v "^#" | grep "=" |
	while read cline; do	
	    name=`$ECHO $cline | cut -d"=" -f1`
	    value=`$ECHO $cline | cut -d"=" -f2-`
	    dline=`grep "^${name}" $DFLT_FILE`
	    if [ $? -eq 0 ]; then
		# Property overrides default - already listed above so ignore.
		continue
	    fi
	    $ECHO "	${name}=${value}"
	done

    elif [ -s $CONF_FILE -a ! -s $DFLT_FILE ]; then
	printOut "$CFG_PROPS"
	grep -v "^#" $CONF_FILE | grep "=" | sed -e "s/^/	/"

    elif [ ! -s $CONF_FILE -a -s $DFLT_FILE ]; then
	printOut "$CFG_PROPS"
	grep -v "^#" $DFLT_FILE | grep "=" | sed -e "s/^/	/"

    else
        printOut "$NO_CFG_PROPS"
    fi


    # Environment Properties
    # 3.0: Environment properties no longer supported in separate file.
    #
    # NO_ENV_PROPS="No environment properties have been registered."
    # ENV_FILE=${CONSOLE_CONFIG_DIR}/.webconsole
    # if [ -s $ENV_FILE ]; then
    #	LIST=`grep -v "^#" $ENV_FILE`
    #	if [ "$LIST" != "" ]; then
    #	    ## Ignore lines that begin with the comment character '#'
    #	    printOut "The list of registered environment properties:"
    #	    grep -v "^#" $ENV_FILE | grep "=" | sed -e "s/^/	/"
    #	else
    #        printOut "$NO_ENV_PROPS"
    #	fi
    # else
    #   printOut "$NO_ENV_PROPS"
    # fi

} ## end listProperties


################################################################################
#
# printOut
#
# Prints the given string in user-friendly format.
#
################################################################################

printOut() {
    if [ $qFlag -eq 0 ]; then
    cat - << EOF

    $1

EOF
    fi
} ## end printOut


################################################################################
#
# doBanner
#
# Write out banner at the top of the file to warn users not to manually edit it.
#
# $1 = the file to output to write to.
# $2 = optional 2nd line to output, eg., a description of what the file is for
#
################################################################################

doBanner() {

    if [ ! -s "$1" ]; then
	mkdir -p `dirname $1`
	touch $1
	$ECHO "$AUTOGENERATEDSTRING" >> $1
	if [ -n "$2" ]; then
	    $ECHO "$2" >> $1
	fi
    fi
    return 0

} ## end doBanner


################################################################################
#
# isAppRegistered
#
# Check to see if the plugin name exists in the list of registered apps.
#
# $1 = the plugin name to check
#
# Return 0 if the name is registered; 1 otherwise
#
################################################################################

isAppRegistered() {

    getConsoleBaseDir
    if [ ! -s $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST ]; then
	return 1
    fi

    if [ "$1" = "" ]; then
	return 1
    fi

    regAppInfo=`getRegAppBy pluginID $1`
    pluginID=`getRegAppValue $regAppInfo pluginID`
    if [ "$pluginID" = "$1" ]; then
	return 0
    fi
    return 1

} ## end isAppRegistered


################################################################################
#
# getRegAppBy
#
# Return the line from the registered plugin list whose value in the
# specified column match the specified data.
#
# Retrieval can be done via context, pluginID, or path.
#
################################################################################

getRegAppBy() {

    columnName=$1
    data=$2
    
    cat $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST | \
    while read line
    do
	# Ignore empty lines or lines starting with a comment character.
	firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
	if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
	    continue
	fi

	# Extract the field associated with the named column.
	result=`getRegAppValue $line $columnName`

	# If a match, return the line
	if [ "$result" = "$data" ]; then
	    $ECHO $line
	    return
	fi
    done

    # No match, so just return an empty string
    $ECHO ""

} ## end getRegAppBy


################################################################################
#
# removeRegAppBy
#
# Remove the line from the registered plugin list whose value in the
# specified column matches the specified data.
#
# Removal can be done via context, pluginID, or path.
#
################################################################################

removeRegAppBy() {

    columnName=$1
    data=$2
    
    cat $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST | \
    while read line
    do
	# Ignore empty lines or lines starting with a comment character.
	firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
	if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
	    $ECHO $line
	    continue
	fi

	# Extract the field associated with the named column.
	result=`getRegAppValue $line $columnName`

	# If not a match, ignore it.
	if [ "$result" != "$data" ]; then
	    $ECHO $line
	fi
    done > $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST.$$

    mv $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST.$$ \
	$CONSOLE_BASE_DIR/$REG_PLUGIN_LIST

} ##  end removeRegAppBy


################################################################################
#
# getRegAppValue
#
# Given an entry in the proper format in the registered plugin list,
# return the value of the specified column.  The entry argument should
# be the output from the getRegAppBy() function.
#
# The format of the line is:
#  context|pluginID|path|version|params
#
# Return the value of the column.
#
################################################################################

getRegAppValue() {

    line=$1
    columnName=$2

    if [ "$columnName" = "context" ]; then
	result=`$ECHO $line | awk -F'|' '{print $1}'`
    elif [ "$columnName" = "pluginID" ]; then
	result=`$ECHO $line | awk -F'|' '{print $2}'`
    elif [ "$columnName" = "path" ]; then
	result=`$ECHO $line | awk -F'|' '{print $3}'`
    elif [ "$columnName" = "version" ]; then
	result=`$ECHO $line | awk -F'|' '{print $4}'`
    elif [ "$columnName" = "params" ]; then
	result=`$ECHO $line | awk -F'|' '{print $5}'`
    else
	result=""
    fi

    $ECHO $result

} ## end getRegAppValue


################################################################################
#
# getRegJarBy
#
# Return the line from the registered jars list whose scope and name
# values match the specified data.
#
################################################################################

getRegJarBy() {

    scope=$1
    name=$2
    
    cat $CONSOLE_BASE_DIR/$REG_JAR_LIST | \
    while read line
    do
	# Ignore empty lines or lines starting with a comment character.
	firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
	if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
	    continue
	fi

	# Extract the fields associated with the scope and name columns.
	resultScope=`getRegJarValue $line scope`
	resultName=`getRegJarValue $line name`

	# If a match, return the line
	if [ "$resultScope" = "$scope" -a "$resultName" = "$name" ]; then
	    $ECHO $line
	    return
	fi
    done

    # No match, so just return an empty string
    $ECHO ""

} ## end getRegJarBy


################################################################################
#
# removeRegJarBy
#
# Remove the line from the registered jars list whose scope and name
# values matches the specified data.
#
################################################################################

removeRegJarBy() {

    scope=$1
    name=$2
    
    cat $CONSOLE_BASE_DIR/$REG_JAR_LIST | \
    while read line
    do
	# Ignore empty lines or lines starting with a comment character.
	firstChar=`$ECHO $line | awk '{print substr($1, 1, 1)}'`
	if [ ! -n "${firstChar}" -o "${firstChar}" = "#" ]; then
	    $ECHO $line
	    continue
	fi

	# Extract the fields associated with the scope and name columns.
	resultScope=`getRegJarValue $line scope`
	resultName=`getRegJarValue $line name`

	# If not a match, ignore it.
	if [ "$resultScope" != "$scope" -o "$resultName" != "$name" ]; then
	    $ECHO $line
	fi
    done > $CONSOLE_BASE_DIR/$REG_JAR_LIST.$$

    mv $CONSOLE_BASE_DIR/$REG_JAR_LIST.$$ \
	$CONSOLE_BASE_DIR/$REG_JAR_LIST

} ##  end removeRegJarBy


################################################################################
#
# getRegJarValue
#
# Given an entry in the proper format in the registered jars list,
# return the value of the specified column.  The entry argument should
# be the output from the getRegJarBy() function.
#
# The format of the line is:
#  scope|name|path
#
# Return the value of the column.
#
################################################################################

getRegJarValue() {

    line=$1
    columnName=$2

    if [ "$columnName" = "scope" ]; then
	result=`$ECHO $line | awk -F'|' '{print $1}'`
    elif [ "$columnName" = "name" ]; then
	result=`$ECHO $line | awk -F'|' '{print $2}'`
    elif [ "$columnName" = "path" ]; then
	result=`$ECHO $line | awk -F'|' '{print $3}'`
    else
	result=""
    fi

    $ECHO $result

} ## end getRegJarValue


################################################################################
#
# extractSDKversion
#
# Extract the SDK version the app was built against from the registration 
# descriptor file and save the name into SDK_VERSION.
# Note that we are hijacking the version attribute from the registrationInfo
# tag - this was never really used, and so can now serve to tell us which
# version of the console the app was built with.
# Note also that "1.0" is mapped to "2.0" as we eventually will need to
# distinguish between apps built against 2.1 and later vs. pre-2.1.
# Apps built against the format will have this value set automatically
# when they are created by the SDK tools.
#
# $1 = path to application descriptor file
#
################################################################################
extractSDKversion() {

    appxml=$1

    # Make sure we have a registrationInfo start tag
    reginfoStartTag=`grep $REGINFO_START_TAG $appxml 2>&1`
    if [ $? -ne 0 ]; then
	printOut "Error! The registrationInfo start tag \"$REGINFO_START_TAG\" not found in $appxml." 1>&2
	exit $EXIT_FAILURE
    fi

    reginfoVersionFound=0

    ##
    ## Enforce that the starting char sequence of a comment is preceeded with white
    ## space, and the ending char sequence is followed by white space. This will
    ## ensure that each comment beginning and ending will be treated as a word
    ## separate from the tags in the file.
    ##
    APP_XML_CONTENT=`cat $appxml | sed -e 's/<!--/ <!--/g' -e 's/-->/--> /g' -e 's/></> </g' -e 's/\">/\" >/'`
    for word in $APP_XML_CONTENT; do
	case $word in

	"<!--"* )
	    IN_COMMENT="true"
	    ;;
	*"-->" )
	    IN_COMMENT="false"
	    ;;

	$REGINFO_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    IN_REGINFO_TAG="true"
	    ;;

	$VERSION_ATTR | $VERSION_ATTR=* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_REGINFO_TAG" != "true" ] && continue

	    reginfoVersionFound=1

	    ## The version attribute value may contain the string "version"
	    if [ "$APP_VERSION" != "" -o "$IN_VERSION" = "true" ]; then
		getVersion $word
		continue
	    fi

	    ##
	    ## Remove the "version" attribute name and the equal sign. If there
	    ## is still info to parse, call getVersion. Otherwise, set a flag to
	    ## indicate we're in the middle of parsing.
	    ##
	    TMP_APP_VERSION=`$ECHO $word \
		| sed -e "s/^$VERSION_ATTR//" \
		| sed -e 's/^=//'`
	    if [ "$TMP_APP_VERSION" != "" ]; then
		getVersion $TMP_APP_VERSION
		if [ "$IN_VERSION" != "true" ]; then
		    break
		fi
	    else
		IN_VERSION="true"
	    fi
	    ;;

	* )
	    [ "$IN_COMMENT" = "true" ] && continue

	    if [ "$IN_REGINFO_TAG" = "true" ]; then
		if [ $reginfoVersionFound -eq 0 ]; then
		    break
		fi
	    fi

	    ##
	    ## We're in the middle of reading in the version word(s). Continue
	    ## to read words until a closing quote is read.
	    ##
	    if [ "$IN_VERSION" = "true" ]; then
		getVersion $word
		if [ "$IN_VERSION" != "true" ]; then
		    break
		fi
		break
	    fi
	    ;;

	esac
    done

    # Make sure the tag includes a version attribute specification.
    if [ $reginfoVersionFound -eq 0 ]; then
	printOut "Error! The registrationInfo \"$VERSION_ATTR\" attribute element not found in $appxml." 1>&2
	exit $EXIT_FAILURE
    fi

    SDK_VERSION=$APP_VERSION
    if [ ! -n "$SDK_VERSION" ]; then
	printOut "Error! The registrationInfo \"$VERSION_ATTR\" attribute value has not been specified in $appxml." 1>&2
	exit $EXIT_FAILURE
    fi

    if [ `versionString2Num $SDK_VERSION` -lt 21000 ]; then
	SDK_VERSION="2.0"
    fi

    # Since these are global, used by getVersion() when invoked for other
    # version tags, reset them to initial states.
    APP_VERSION=""
    IN_VERSION=""

} ## extractSDKversion


################################################################################
#
# extractPluginName
#
# Extract the pluginName from the registration descriptor file and save the
# name into PLUGIN_NAME.
#
# $1 = path to application descriptor file
#
################################################################################

extractPluginName() {

    appxml=$1

    ##
    ## Enforce that the starting char sequence of a comment is preceeded with white
    ## space, and the ending char sequence is followed by white space. This will
    ## ensure that each comment beginning and ending will be treated as a word
    ## separate from the tags in the file.
    ##
    APP_XML_CONTENT=`cat $appxml | sed -e 's/<!--/ <!--/g' -e 's/-->/--> /g' -e 's/></> </g'`
    for word in $APP_XML_CONTENT; do
	case $word in

	"<!--"* )
	    IN_COMMENT="true"
	    ;;
	*"-->" )
	    IN_COMMENT="false"
	    ;;

	$MANAGEMENTAPP_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    IN_MANAGEMENT_APP_TAG="true"
	    ;;

	$VERSION_ATTR | $VERSION_ATTR=* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_MANAGEMENT_APP_TAG" != "true" ] && continue

	    ## The version attribute value may contain the string "version"
	    if [ "$APP_VERSION" != "" -o "$IN_VERSION" = "true" ]; then
		getVersion $word
		continue
	    fi

	    ##
	    ## Remove the "version" attribute name and the equal sign. If there
	    ## is still info to parse, call getVersion. Otherwise, set a flag to
	    ## indicate we're in the middle of parsing.
	    ##
	    TMP_APP_VERSION=`$ECHO $word \
		| sed -e "s/^$VERSION_ATTR//" \
		| sed -e 's/^=//'`
	    if [ "$TMP_APP_VERSION" != "" ]; then
		getVersion $TMP_APP_VERSION
	    else
		IN_VERSION="true"
	    fi
	    ;;

	$PLUGIN_NAME_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_MANAGEMENT_APP_TAG" != "true" ] && continue

	    ## Attempt to extract the plugin name from the line.
	    PLUGIN_NAME=`$ECHO $word \
		| sed -e 's/.*'$PLUGIN_NAME_START_TAG'//' \
		| sed -e 's/'$PLUGIN_NAME_END_TAG'.*//' \
		| sed -e 's/\"//g' -e "s/^\'//"`

	    ##
	    ## If PLUGIN_NAME is not empty, we have our data. Otherwise, the
	    ## start/end tags and tag content span multiple "words". Set a flag
	    ## to indicate the tag content will be the next word read.
	    ##
	    if [ "$PLUGIN_NAME" != "" ]; then
		TMP_PLUGIN_NAME=${PLUGIN_NAME}_${APP_VERSION}
		PLUGIN_NAME=$TMP_PLUGIN_NAME
	    else
		PLUGIN_START_TAG_FOUND="true"
	    fi
	    ;;

	* )
	    [ "$IN_COMMENT" = "true" ] && continue

	    ##
	    ## We're in the middle of reading in the version word(s). Continue
	    ## to read words until a closing quote is read.
	    ##
	    if [ "$IN_VERSION" = "true" ]; then
		getVersion $word
		continue
	    fi

	    ##
	    ## We're in the middle of reading in the pluginName content. The
	    ## next word will be the content.
	    ##
	    if [ "$PLUGIN_START_TAG_FOUND" = "true" ]; then
		PLUGIN_NAME=`$ECHO $word \
		    | sed -e 's/'$PLUGIN_NAME_END_TAG'.*//' \
		    | sed -e 's/\"//g' -e "s/^\'//"`
		TMP_PLUGIN_NAME=${PLUGIN_NAME}_${APP_VERSION}
		PLUGIN_NAME=$TMP_PLUGIN_NAME
		PLUGIN_START_TAG_FOUND="false"
	    fi
	    ;;
	esac
    done

    ## Check the plugin name for validity. Format: <pluginName>_<managementApp_version>
    if [ "$PLUGIN_NAME" = "" ]; then
	printOut "Error! The managementApp \"$VERSION_ATTR\" attribute and \"pluginName\" element values could not be determined." 1>&2
	exit $EXIT_FAILURE
    fi

    $ECHO $PLUGIN_NAME | grep "_" >/dev/null
    if [ $? -ne 0 ]; then
	printOut "Error! The managementApp \"$VERSION_ATTR\" attribute and \"pluginName\" element values could not be determined." 1>&2
	exit $EXIT_FAILURE
    fi

    tmp=`$ECHO $PLUGIN_NAME | sed -e 's/_.*//'`
    if [ "$tmp" = "" ]; then
	printOut "Error! The \"pluginName\" element value has not been specified in the application descriptor file." 1>&2
	exit $EXIT_FAILURE
    fi

    tmp=`$ECHO $PLUGIN_NAME | sed -e 's/.*_//'`
    if [ "$tmp" = "" ]; then
	printOut "Error! The managementApp \"$VERSION_ATTR\" attribute value has not been specified in the application descriptor file." 1>&2
	exit $EXIT_FAILURE
    fi

    # Since these are global, used by getVersion() when invoked for other
    # version tags, reset them to initial states.
    APP_VERSION=""
    IN_VERSION=""

} ## end extractPluginName


################################################################################
#
# getVersion
#
# This function extracts the managementApp tag's version attribute value. The
# version may be formatted in several ways:
#	version="1.0beta"
#	version="1.0 beta"
#	version = "1.0beta"
#	version=" 1.0 beta "
#
# This function handles all types of input by removing the equal sign, and
# reading (perhaps over several calls to this function) the value(s) contained
# within the quotes. The final version is concatenated into a single word if
# necessary, and stored in the VERSION variable.
#
# $1 = the version value to extract, or the portion of the value
#
# Outputs 2 global variables:
#    IN_VERSION = tells whether we are still in the middle of extracting
#                 the version value.
#    APP_VERSION = the (possibly not fully extracted) version value.
#
#    It is VERY important that users of this function reset these variable
#    to empty strings when they are done extracting the value of their
#    version tag!!!
#
################################################################################

# A "static" variable, private to this function.
STRIPPED_FIRST_QUOTE=""
getVersion() {

    versionArg=$1

    ##
    ## Strip off the equal sign, if it exists.  Also globally replace
    ## all instances of single-quote with double-quote, as some OS
    ## sed implementations have trouble with end-of-line edit patterns
    ## involving the single-quote.
    ##
    versionArg=`$ECHO $versionArg | sed -e 's/^=//' -e "s/'/\"/g"`

    ##
    ## Strip off the opening quote (make sure this is only done once)
    ##
    if [ "$STRIPPED_FIRST_QUOTE" != "true" ]; then
	firstChar=`$ECHO $versionArg | awk '{print substr($1, 1, 1)}'`
	if [ "${firstChar}" = "\"" -o "${firstChar}" = "\'" ]; then
	    versionArg=`$ECHO $versionArg | sed -e 's/^\"//' -e "s/^\'//"`
	    STRIPPED_FIRST_QUOTE="true"
	fi
    fi

    ##
    ## If the remaining word is a quote only (that is, the closing quote if we
    ## have made it this far), end the search for APP_VERSION
    ##
    if [ "$versionArg" = "\"" -o "$versionArg" = "'" ]; then
	IN_VERSION="false"
	STRIPPED_FIRST_QUOTE=""
	return
    fi

    ##
    ## Ignore the versionArg if it only contains: =
    ##
    if [ "$versionArg" = "" ]; then
	IN_VERSION="true"
	STRIPPED_FIRST_QUOTE=""
	return
    fi

    ##
    ## If the version continues over more than 1 word (ie "1.0 beta"), save what
    ## we have and continue until we find the closing quote. NOTE: This format
    ## will result in the words being concatenated to "1.0beta".
    ##
    lastChar=`$ECHO $versionArg | awk '{print substr($1, length($1), 1)}'`
    if [ "${lastChar}" != "\"" -a "${lastChar}" != "\'" ]; then
	APP_VERSION=${APP_VERSION}${versionArg}
	IN_VERSION="true"
	return
    fi

    APP_VERSION=${APP_VERSION}`$ECHO $versionArg | sed -e 's/\".*//'`
    IN_VERSION="false"
    STRIPPED_FIRST_QUOTE=""

} ## end getVersion


################################################################################
#
# checkForFilterTags
#
# Check to make sure the app has the correct filter tags.
#
# $1 = the full path to (including filename) web.xml, or app directory
#
# Return 0 if it has the correct tags, 1 otherwise
#
################################################################################

checkForFilterTags() {

    path=$1
    
    ## Remove trailing slashes (/) and double slashes (//) from the directory
    path=`$ECHO $path | sed 's/\/*$//' | sed 's/\/\/*/\//g'`

    ## Append WEB-INF/web.xml if just given path to app
    if [ -d "${path}" ]; then
	WEB_XML=${path}/WEB-INF/web.xml
    else
	WEB_XML=${path}
    fi

    ##
    ## Check for an existing web.xml file
    ##
    if [ ! -s $WEB_XML ]; then
	printOut "Error! \"$WEB_XML\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi


    ##
    ## Enforce that the starting char sequence of a comment is preceeded with white
    ## space, and the ending char sequence is followed by white space. Also, enforcing
    ## that This will
    ## ensure that each comment beginning and ending will be treated as a word
    ## separate from the tags in the file.
    ##
    WEB_XML_CONTENT=`cat $WEB_XML | sed -e 's/<!--/ <!--/g' -e 's/-->/--> /g' -e 's/></> </g'`
    for word in $WEB_XML_CONTENT; do
	case $word in

	"<!--"* )
	    IN_COMMENT="true"
	    ;;
	*"-->" )
	    IN_COMMENT="false"
	    ;;

	$FILTER_START_TAG* )
	    IN_FILTER_TAG="true"
	    ;;

	$FILTER_END_TAG* )
	    IN_FILTER_TAG="false"

	    ## Check the contents of the filter-name and filter-class tags here
	    if [ "$FILTER_NAME_CONTENT" = "$APP_FILTER_NAME" -a "$FILTER_CLASS_CONTENT" = "$APP_FILTER_CLASS" ]; then
		return 0
	    fi
	    if [ "$FILTER_NAME_CONTENT" = "$CONSOLE_FILTER_NAME" -a "$FILTER_CLASS_CONTENT" = "$CONSOLE_FILTER_CLASS" ]; then
		return 0
	    fi
	    ;;

	$FILTER_NAME_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_FILTER_TAG" != "true" ] && continue

	    ## Attempt to extract the filter-name content from the line.
	    FILTER_NAME_CONTENT=`$ECHO $word \
		| sed -e 's/.*'$FILTER_NAME_START_TAG'//' \
		| sed -e 's/'$FILTER_NAME_END_TAG'.*//' \
		| sed -e 's/\"//g' -e "s/^\'//"`

	    ##
	    ## If FILTER_NAME_CONTENT is not empty, we have our data. Otherwise, the
	    ## start/end tags and tag content span multiple "words". Set a flag
	    ## to indicate the tag content will be the next word read.
	    ##
	    if [ "$FILTER_NAME_CONTENT" = "" ]; then
		FILTER_NAME_START_TAG_FOUND="true"
	    fi
	    ;;

	$FILTER_CLASS_START_TAG* )
	    [ "$IN_COMMENT" = "true" ] && continue
	    [ "$IN_FILTER_TAG" != "true" ] && continue

	    ## Attempt to extract the filter-class content from the line.
	    FILTER_CLASS_CONTENT=`$ECHO $word \
		| sed -e 's/.*'$FILTER_CLASS_START_TAG'//' \
		| sed -e 's/'$FILTER_CLASS_END_TAG'.*//' \
		| sed -e 's/\"//g' -e "s/^\'//"`

	    ##
	    ## If FILTER_CLASS_CONTENT is not empty, we have our data. Otherwise, the
	    ## start/end tags and tag content span multiple "words". Set a flag
	    ## to indicate the tag content will be the next word read.
	    ##
	    if [ "$FILTER_CLASS_CONTENT" = "" ]; then
		FILTER_CLASS_START_TAG_FOUND="true"
	    fi
	    ;;

	* )
	    [ "$IN_COMMENT" = "true" ] && continue

	    ##
	    ## We're in the middle of reading in the filter-name content. The
	    ## next word will be the content.
	    ##
	    if [ "$FILTER_NAME_START_TAG_FOUND" = "true" ]; then
		FILTER_NAME_CONTENT=`$ECHO $word \
		    | sed -e 's/'$FILTER_NAME_END_TAG'.*//' \
		    | sed -e 's/\"//g' -e "s/^\'//"`
		FILTER_NAME_START_TAG_FOUND="false"
	    fi

	    ##
	    ## We're in the middle of reading in the filter-class content. The
	    ## next word will be the content.
	    ##
	    if [ "$FILTER_CLASS_START_TAG_FOUND" = "true" ]; then
		FILTER_CLASS_CONTENT=`$ECHO $word \
		    | sed -e 's/'$FILTER_CLASS_END_TAG'.*//' \
		    | sed -e 's/\"//g' -e "s/^\'//"`
		FILTER_CLASS_START_TAG_FOUND="false"
	    fi
	    ;;

	esac

    done
    return 1

} ## end checkForFilterTags


################################################################################
#
# addFilterTags
#
# Add the filter and filter-mapping tags required by the console to the app's
# web.xml file. The final web.xml will be printed to stdout, and can be
# redirected to another file to save the output.
#
# NOTE: the checkForFilterTags function should be called before this one to be
# sure that we actually need to add the tags.
#
# $1 = the full path to (including filename) web.xml, or app directory
#
################################################################################

addFilterTags() {

    WEB_XML_FILE=$1

    ## Remove trailing slashes (/) and double slashes (//) from the directory
    WEB_XML_FILE=`$ECHO $WEB_XML_FILE | sed 's/\/*$//' | sed 's/\/\/*/\//g'`

    ## Append WEB-INF/web.xml if just given path to app
    if [ -d "${WEB_XML_FILE}" ]; then
	WEB_XML_FILE=${WEB_XML_FILE}/WEB-INF/web.xml
    fi

    ##
    ## Check for an existing web.xml file
    ##
    if [ ! -s $WEB_XML_FILE ]; then
	printOut "Error! \"$WEB_XML_FILE\" does not exist." 1>&2
	exit $EXIT_FAILURE
    fi

    ##
    ##
    ## Write out the new web.xml file with the filter and filter-mapping tags
    ## inserted in the designated place. NOTE: The 'sed' statement below
    ## performs the following task: if a end tag/comment char ">" and a start
    ## tag/comment char "<" occur on the same line, force them onto two separate
    ## lines. This helps ensure that the filter and filter-mapping tags don't
    ## get inserted in a weird place.
    ##
    sed -e 's/> */>/g' -e 's/></>\
</g' $WEB_XML_FILE | ${NAWK} 'BEGIN {
	FS=" "
	IN_COMMENT=""
	ADD_FILTER_TAG=""
	ADD_FILTER_MAPPING_TAG=""
	FILTER_ADDED=""
	FILTER_MAPPING_ADDED=""
	PRINT_LINE="true"
    }

    /<!--/			{ IN_COMMENT="true" }
    /-->/			{ IN_COMMENT="false" }
    /<web-app>/			{ }
    /<icon>/			{ }
    /<display-name>/		{ }
    /<description>/		{ }
    /<distributable>/		{ }
    /<context-param>/		{ }
    /<filter>/			{ ADD_FILTER_TAG="true" }
    /<filter-mapping>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<listener>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<servlet>/			{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<servlet-mapping>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<session-config>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<mime-mapping>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<welcome-file-list>/	{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<error-page>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<taglib>/			{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<resource-env-ref>/	{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<resource-ref>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<security-constraint>/	{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<login-config>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<security-role>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<env-entry>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<ejb-ref>/			{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<ejb-local-ref>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }
    /<\/web-app>/		{ ADD_FILTER_TAG="true"; ADD_FILTER_MAPPING_TAG="true" }


    ################################################################################
    #
    # This function adds the application <filter> tag required by the console to the
    # web.xml file in the required location.
    #
    ################################################################################

    function addFilterTag() {

	print "  <filter>"
	print "    <filter-name>'$APP_FILTER_NAME'</filter-name>"
	print "    <filter-class>"
	print "      '$APP_FILTER_CLASS'"
	print "    </filter-class>"
	print "    <init-param>"
	print "      <param-name>ignore-paths</param-name>"
	print "      <param-value>"
	print "        /images/*"
	print "      </param-value>"
	print "    </init-param>"
	print "  </filter>"

    } ## end addFilterTag


    ################################################################################
    #
    # This function adds the application <filter-mapping> tag required by the
    # console to the web.xml file in the required location.
    #
    ################################################################################

    function addFilterMappingTag() {

	print "  <filter-mapping>"
	print "    <filter-name>'$APP_FILTER_NAME'</filter-name>"
	print "    <url-pattern>/*</url-pattern>"
	print "  </filter-mapping>"

    } ## end addFilterMappingTag


    ################################################################################
    #
    # main function
    #
    ################################################################################

    {
	## Add in our filter tag if they have not been added already
	if (ADD_FILTER_TAG == "true") {
	    if (FILTER_ADDED != "true") {
		if (IN_COMMENT == "true") {
		    print
		    print "-->"
		}
		addFilterTag()
		FILTER_ADDED="true"
		if (IN_COMMENT == "true") {
		    print "<!--"

		    # This flag indicates the line was already printed
		    PRINT_LINE="false"
		}
	    }
	}

	## Add in our filter-mapping tag if they have not been added already
	if (ADD_FILTER_MAPPING_TAG == "true") {
	    if (FILTER_MAPPING_ADDED != "true") {
		if (IN_COMMENT == "true") {
		    print
		    print "-->"
		}
		addFilterMappingTag()
		FILTER_MAPPING_ADDED="true"
		if (IN_COMMENT == "true") {
		    print "<!--"

		    # This flag indicates the line was already printed
		    PRINT_LINE="false"
		}
	    }
	}

	##
	## If the line was not already printed above, print it now. Otherwise
	## reset the PRINT_LINE flag to true
	##
	if (PRINT_LINE == "true") {
	    print
	} else {
	    PRINT_LINE="true"
	}
    }

    END {}'

} ## end addFilterTags()


################################################################################
#
# regAdd_Usage
#
# Usage method for the "add" subcommand
#
# $1 = Exit code
# $2 = optional error message to display before the usage.
#
################################################################################

regAdd_Usage() {

    if [ -n "$2" ]; then
	$ECHO $2
    fi

    cat - << EOF

    Usage: ${PROGNAME} add $APP_FLAG_SHORT [$CONTEXT_FLAG_SHORT <context>] <path>
     or: ${PROGNAME} add $DIR_FLAG_SHORT <path>
     or: ${PROGNAME} add $LIB_FLAG_SHORT [$LINK_FLAG_SHORT] [$NAME_FLAG_SHORT <lib_name>] -s ALL | <app_name> <path>
     or: ${PROGNAME} add $PROP_FLAG_SHORT $CONFIG_FLAG_SHORT | $ENV_FLAG_SHORT  name=value [name=value ...]
     or: ${PROGNAME} add $LM_FLAG_SHORT $OPTION_FLAG_SHORT <name=value> $OPTION_FLAG_SHORT ... $BEH_FLAG_SHORT <behavior> <class_name>
     or: ${PROGNAME} add $HELP_FLAG_SHORT

    Registers objects for the ${PRODUCT_NAME}.

    $APP_FLAG_SHORT,  $APP_FLAG_LONG
           Object type is an application.

    $DIR_FLAG_SHORT path,  $DIR_FLAG_LONG path
           Object type is an application.  This option functions the same as
           $APP_FLAG_SHORT but is deprecated and is preserved only for
           compatibility with existing 1.0-based applications.

    $CONTEXT_FLAG_SHORT context,  $CONTEXT_FLAG_LONG context
           The deployment context path for an application.  This option is
           used to register applications built with the SDK version 2.1 or
           greater.  If not provided and the application is unpacked, the
           context is the parent directory of the application's WEB-INF
           directory. This option is ignored when registering applications
           built with an SDK version prior to 2.1.

    $LIB_FLAG_SHORT,  $LIB_FLAG_LONG
           Object type is a library jar.

    $PROP_FLAG_SHORT,  $PROP_FLAG_LONG
           Object type is series of properties.

    $LM_FLAG_SHORT,   $LM_FLAG_LONG
           Object type is a login module

    $NAME_FLAG_SHORT lib_name,  $NAME_FLAG_LONG lib_name
           The name by which a library is known to the registration service.
           Should include .jar suffix.  If not provided, it is automatically
           appended.

    $SCOPE_FLAG_SHORT ALL | <app_name>,  $SCOPE_FLAG_LONG ALL | <app_name>
           Specify the sharing scope for the library.  A scope of ALL means to
           make the library available to all applications.  A scope of 
           <app_name> means to make the library available only to the
           application already register as <app_name>.

    $OPTION_FLAG_SHORT name=value,   $OPTION_FLAG_LONG name=value
           Options specific to the login module. The options are specified
           as name=value pairs, each preceeded with the $OPTION_FLAG_SHORT
           option.  If value contains spaces, it should be enclosed in quotes.

    $BEH_FLAG_SHORT behavior,   $BEH_FLAG_LONG behavior
           Controls the overall behavior as authentication proceeds
           down the stack of multiple authentication modules.
           The following values are allowed:
               required | requisite | sufficient | optional

    $CONFIG_FLAG_SHORT,   $CONFIG_FLAG_LONG
           Specify the type of properties as server configuration properties.
           This option is assumed if no properties type option is specified.

    $ENV_FLAG_SHORT,   $ENV_FLAG_LONG
           Specify the type of properties as environment properties.

    $LINK_FLAG_SHORT,   $LINK_FLAG_LONG
	   Specifies to register the library as a symbolic link rather
           than as a file copy.  This option is ignored on operating systems
	   which do not support symbolic links.

    path
           The directory in which the application or library has 
           been installed.  

    class_name
           Login module class name, expressed as a fully qualified package
           path name.

    $HELP_FLAG_SHORT, $HELP_FLAG_SHORT2, $HELP_FLAG_LONG
           Display this help list.

    For more information, see smreg($MANSECTION).
    
EOF
    exit $1

} ## regAdd_Usage


################################################################################
#
# regList_Usage
#
# Usage method for the "list" subcommand
#
# $1 = Exit code
# $2 = optional error message to display before the usage.
#
################################################################################

regList_Usage() {

    if [ -n "$2" ]; then
	$ECHO $2
    fi

    cat - << EOF

    Usage: ${PROGNAME} list [$APP_FLAG_SHORT | $LIB_FLAG_SHORT | $PROP_FLAG_SHORT | $LM_FLAG_SHORT ]

    Lists objects of the specified type registered with the 
    ${PRODUCT_NAME}.
    If no types are specified, all objects are listed.

    $APP_FLAG_SHORT,  $APP_FLAG_LONG
           Object type is application.

    $LIB_FLAG_SHORT,  $LIB_FLAG_LONG
           Object type is library jar.

    $PROP_FLAG_SHORT,  $PROP_FLAG_LONG
           Object type is properties.

    $LM_FLAG_SHORT,   $LM_FLAG_LONG
           Object type is login module

    $HELP_FLAG_SHORT, $HELP_FLAG_SHORT2, $HELP_FLAG_LONG
           Display this help list.

    For more information, see smreg($MANSECTION).
    
EOF
    exit $1

} ## regList_Usage


################################################################################
#
# regRemove_Usage
#
# Usage method for the "remove" subcommand
#
# $1 = Exit code
# $2 = optional error message to display before the usage.
#
################################################################################

regRemove_Usage() {

    if [ -n "$2" ]; then
	$ECHO $2
    fi

    cat - << EOF

    Usage: ${PROGNAME} remove $APP_FLAG_SHORT <app_name> | <context>
     or: ${PROGNAME} remove $NAME_FLAG_SHORT <app_name>
     or: ${PROGNAME} remove $DIR_FLAG_SHORT <path>
     or: ${PROGNAME} remove $LIB_FLAG_SHORT $SCOPE_FLAG_SHORT ALL | <app_name> <lib_name>
     or: ${PROGNAME} remove $PROP_FLAG_SHORT $CONFIG_FLAG_SHORT | $ENV_FLAG_SHORT  name [name ...]
     or: ${PROGNAME} remove $LM_FLAG_SHORT <class_name>
     or: ${PROGNAME} remove $HELP_FLAG_SHORT

    Unregisters objects from the ${PRODUCT_NAME}.

    $APP_FLAG_SHORT,  $APP_FLAG_LONG
           Object type is an application.

    $NAME_FLAG_SHORT,  $NAME_FLAG_LONG
           Object type is an application.  This option functions the same as
           $APP_FLAG_SHORT but is deprecated and is preserved only for
           compatibility with existing 1.0-based applications.

    $DIR_FLAG_SHORT path,  $DIR_FLAG_LONG path
           The directory in which the application was originally installed.
           This option is deprecated and is preserved only for
           compatibility with existing 1.0-based applications.

    $LIB_FLAG_SHORT,  $LIB_FLAG_LONG
           Object type is a library jar.

    $PROP_FLAG_SHORT,  $PROP_FLAG_LONG
           Object type is series of properties.

    $LM_FLAG_SHORT,   $LM_FLAG_LONG
           Object type is a login module

    $SCOPE_FLAG_SHORT ALL | <app_name>,  $SCOPE_FLAG_LONG ALL | <app_name>
           The sharing scope of the library to unregister.  A scope of ALL
           means to unregister the library so that is no longer available
           to all applications.  A scope of <app_name> means to unregister
           the library so that it is no longer available to the application
           registered as <app_name>.

    $CONFIG_FLAG_SHORT,   $CONFIG_FLAG_LONG
           Specify the type of properties as server configuration properties.
           This option is assumed if no properties type option is specified.

    $ENV_FLAG_SHORT,   $ENV_FLAG_LONG
           Specify the type of properties as environment properties.

    app_name
           The name by which the application was registered.

    context
           The deployment context path for an application.  This is used to
           unregister applications built with the SDK version 2.1 or greater.
           Context should be the value specified via the -x option when the
           application was registered, or the default if -x was not used.

    lib_name
           The name by which the library was registered.
           Should include .jar suffix.  If not provided, it is automatically
           appended.

    class_name
           Login module class name, expressed as a fully qualified package
           path name.

    $HELP_FLAG_SHORT, $HELP_FLAG_SHORT2, $HELP_FLAG_LONG
           Display this help list.

    For more information, see smreg($MANSECTION).
    
EOF
    exit $1

} ## regRemove_Usage


################################################################################
#
# regCheck_Usage
#
# Usage method for the "check" subcommand
#
# $1 = Exit code
# $2 = optional error message to display before the usage.
#
################################################################################

regCheck_Usage() {

    if [ -n "$2" ]; then
	$ECHO $2
    fi

    cat - << EOF

    Usage: ${PROGNAME} check [$DIR_FLAG_SHORT] <path>

    Parses a web.xml file to make sure that it has the filter and
    filter-mapping tags, which are required tags in order to run
    an application in the ${PRODUCT_NAME}.

    path
           Can be either the path to an application deployment directory
           or any path to a web.xml file.  If a directory, the file is
           assumed to be at <path>/WEB-INF/web.xml.

    $DIR_FLAG_SHORT path,  $DIR_FLAG_LONG path
           This option has no effect, but is preserved only for compatibility
           with older applications.

    $HELP_FLAG_SHORT, $HELP_FLAG_SHORT2, $HELP_FLAG_LONG
           Display this help list.

    For more information, see smreg($MANSECTION).
EOF
    exit $1

} ## regCheck_Usage


################################################################################
#
# regAdd
#
# Handler for the "add" subcommand.
#
# Arguments should be $*, minus the subcommand
#
################################################################################

regAdd() {

    isRoot
    aFlag=0
    dFlag=0
    lFlag=0
    LFlag=0
    mFlag=0
    nFlag=0
    sFlag=0
    bFlag=0
    oFlag=0
    pFlag=0
    cFlag=0
    eFlag=0
    xFlag=0
    path=""
    name=""
    scope=""
    behavior=""
    properties=""
    context=""

    # When getopts prints errors, it includes the name of the function.
    # So we catch the error msg output into a file so we can replace the
    # function name with the overall script name and subcommand.
    #
    errCatch=/tmp/regAdd.$$
    rm -f $errCatch >/dev/null 2>&1
    while getopts "hadlLmpcen:s:b:o:x:" c > $errCatch 2>&1; do
	case $c in
	    "a") aFlag=1
		 ;;
	    "d") dFlag=1
		 ;;
	    "l") lFlag=1
		 ;;
	    "L") LFlag=1
		 ;;
	    "p") pFlag=1
		 ;;
	    "m") mFlag=1
		 ;;
	    "n") nFlag=1
		 name=${OPTARG}
		 ;;
	    "s") sFlag=1
		 scope=${OPTARG}
		 ;;
	    "b") bFlag=1
		 behavior=${OPTARG}
		 ;;
	    "c") cFlag=1
		 ;;
	    "e") eFlag=1
		 ;;
	    "o") oFlag=1   # name=value argument
		 properties="$properties ${OPTARG}"
		 ;;
	    "x") xFlag=1
		 context=${OPTARG}
		 ;;
	    "h") regAdd_Usage $EXIT_SUCCESS;;
	    \?)  msg=`sed -e "s@regAdd@${PROGNAME} add@" $errCatch`
		 rm -f $errCatch
		 regAdd_Usage $EXIT_USAGE "$msg" 1>&2
		 ;;
	esac
    done
    shift `expr $OPTIND - 1`

    rm -f $errCatch >/dev/null 2>&1

    aOptions=`expr $aFlag + $xFlag`
    dOptions=$dFlag
    lOptions=`expr $lFlag + $nFlag + $sFlag + $LFlag`
    mOptions=`expr $mFlag + $bFlag + $sFlag`
    pOptions=`expr $cFlag + $eFlag`
    majorOptions=`expr $aFlag + $lFlag + $mFlag + $pFlag + $dFlag`

    # Must specify either -a or -l or -m or -p or -d
    if [ $majorOptions -eq 0 ]; then
	regAdd_Usage $EXIT_USAGE 1>&2
    fi

    # -a and -l and -m and -p and -d are mutually exclusive
    if [ $majorOptions -ne 1 ]; then
	regAdd_Usage $EXIT_USAGE "-a, -l, -m, -p, and -d are mutually exclusive" 1>&2
    fi

    # -n requires -l
    if [ $nFlag -ne 0 ] && [ $lFlag -eq 0 ]; then
	regAdd_Usage $EXIT_USAGE "${NAME_FLAG_SHORT} requires ${LIB_FLAG_SHORT}" 1>&2
    fi

    # -L requires -l
    if [ $LFlag -ne 0 ] && [ $lFlag -eq 0 ]; then
	regAdd_Usage $EXIT_USAGE "${LINK_FLAG_SHORT} requires ${LIB_FLAG_SHORT}" 1>&2
    fi

    # -b requires -m
    if [ $bFlag -ne 0 ] && [ $mFlag -eq 0 ]; then
	regAdd_Usage $EXIT_USAGE "${BEH_FLAG_SHORT} requires ${LM_FLAG_SHORT}" 1>&2
    fi

    # -d is deprecated.  Map to -a with appropriate warning.
    if [ $dFlag -ne 0 ] && [ $qFlag -eq 0 ]; then
	$ECHO "WARNING! -d is deprecated and will be unavailable in a future"
	$ECHO "release.  Please change to using the -a option."
	dFlag=0
	aFlag=1
    fi

    # For application registration
    if [ $aFlag -ne 0 ]; then
	# First position-dependent argument must be path to app.
	if [ ! -n "$1" ]; then
	    regAdd_Usage $EXIT_USAGE "No <path> specified" 1>&2
	fi
	registerApp $1 $context
	
	# create a 3.0 registration notification file
	# $1 is the path to the application
	createAppRegnot $1 $context
    fi

    # For library registration
    if [ $lFlag -ne 0 ]; then

	# -l requires -s
	if [ ! -n "${scope}" ]; then
	    # This can happen if position argument embedded within
	    # position-independent options.
	    regAdd_Usage $EXIT_USAGE "No <scope> specified" 1>&2
	fi

	# First position-dependent argument must be path to lib.
	if [ ! -n "$1" ]; then
	    regAdd_Usage $EXIT_USAGE "No <path> specified" 1>&2
	fi
	registerJar $1 $scope $LFlag $name

	# create a 3.0 registration notification file
	# $1 is the path to the library
	# scope will be ALL for 3.0 jars so it is not passed
	if [ "${scope}" = "ALL" ]; then
	    createJarRegnot $1
	fi
    fi

    # For login module registration
    if [ $mFlag -ne 0 ]; then

	# -m requires -b
	if [ ! -n "${behavior}" ]; then
	    # This can happen if position argument embedded within
	    # position-independent options.
	    regAdd_Usage $EXIT_USAGE "No <behavior> specified" 1>&2
	fi

	# -m requires <scope>, but if not specified, we assume ConsoleLogin
	# for compatibility sake.
	if [ ! -n "${scope}" ]; then
	    scope="ConsoleLogin"
	fi

	# Behavior must be required | requisite | sufficient | optional
	if [ "${behavior}" != "required" ] \
	    && [ "${behavior}" != "requisite" ] \
	    && [ "${behavior}" != "sufficient" ] \
	    && [ "${behavior}" != "optional" ]; then
	    regAdd_Usage $EXIT_USAGE "Illegal value specified <behavior>" 1>&2
	fi

	# First position-dependent argument must be class name.
	if [ ! -n "$1" ]; then
	    regAdd_Usage $EXIT_USAGE "No <class_name> specified" 1>&2
	fi

	registerModule $scope ${1} ${behavior} ${properties}

	# create a 3.0 registration notification file
	# $1 is the class e.g. <javaPackage>.<javaclass>
        # quotes around ${properties} will preserve quotes around
	# the value of the name="value" pairs that ${properties} holds
	createModuleRegnot $scope ${1} ${behavior} ${properties}
    fi

    # For properties registration
    if [ $pFlag -ne 0 ]; then

	# -c and -e are mutually exclusive
	if [ $pOptions -gt 1 ]; then
	    regAdd_Usage $EXIT_USAGE "-c and -e are mutually exclusive" 1>&2
	fi

	# Must be at least one position-dependent name=value argument.
	if [ ! -n "$1" ]; then
	    regAdd_Usage $EXIT_USAGE "No name=value properties specified" 1>&2
	fi

	registerProperties $eFlag $*
    fi

} ## regAdd


################################################################################
#
# regList
#
# Handler for the "list" subcommand.
#
# Arguments should be $*, minus the subcommand
#
################################################################################

regList() {

    aFlag=0
    lFlag=0
    mFlag=0
    pFlag=0

    # When getopts prints errors, it includes the name of the function.
    # So we catch the error msg output into a file so we can replace the
    # function name with the overall script name and subcommand.
    #
    errCatch=/tmp/regList.$$
    rm -f $errCatch >/dev/null 2>&1
    while getopts "halmp" c > $errCatch 2>&1; do
	case $c in
	    "a") aFlag=1
		 ;;
	    "l") lFlag=1
		 ;;
	    "p") pFlag=1
		 ;;
	    "m") mFlag=1
		 ;;
	    "h") regList_Usage $EXIT_SUCCESS;;
	    \?)  msg=`sed -e "s@regList@${PROGNAME} list@" $errCatch`
		 rm -f $errCatch
		 regList_Usage $EXIT_USAGE "$msg" 1>&2
		 ;;
	esac
    done
    shift `expr $OPTIND - 1`

    rm -f $errCatch >/dev/null 2>&1

    # No option means display all registered objects.
    majorOptions=`expr $aFlag + $lFlag + $mFlag + $pFlag`
    if [ $majorOptions -eq 0 ]; then
	aFlag=1;
	lFlag=1;
	mFlag=1;
	pFlag=1;
    fi

    # For applications
    if [ $aFlag -eq 1 ]; then
	listApps
    fi

    # For library jars
    if [ $lFlag -eq 1 ]; then
	listLibraries
    fi

    # For login modules
    if [ $mFlag -eq 1 ]; then
	listModules
    fi

    # For properties
    if [ $pFlag -eq 1 ]; then
	listProperties
    fi

} ## regList


################################################################################
#
# regRemove
#
# Handler for the "remove" subcommand.
#
# Arguments should be $*, minus the subcommand
#
################################################################################

regRemove() {

    isRoot
    aFlag=0
    nFlag=0
    dFlag=0
    lFlag=0
    mFlag=0
    sFlag=0
    pFlag=0
    cFlag=0
    eFlag=0
    scope=""
    moduleName=""

    # When getopts prints errors, it includes the name of the function.
    # So we catch the error msg output into a file so we can replace the
    # function name with the overall script name and subcommand.
    #
    errCatch=/tmp/regRemove.$$
    rm -f $errCatch >/dev/null 2>&1
    while getopts "handlmpces:" c > $errCatch 2>&1; do
	case $c in
	    "a") aFlag=1
		 ;;
	    "n") nFlag=1
		 ;;
	    "d") dFlag=1
		 ;;
	    "l") lFlag=1
		 ;;
	    "p") pFlag=1
		 ;;
	    "m") mFlag=1
		 moduleName=${OPTARG}
		 ;;
	    "s") sFlag=1
		 scope=${OPTARG}
		 ;;
	    "c") cFlag=1
		 ;;
	    "e") eFlag=1
		 ;;
	    "h") regRemove_Usage $EXIT_SUCCESS;;
	    \?)  msg=`sed -e "s@regRemove@${PROGNAME} remove@" $errCatch`
		 rm -f $errCatch
		 regRemove_Usage $EXIT_USAGE "$msg" 1>&2
		 ;;
	esac
    done
    shift `expr $OPTIND - 1`

    rm -f $errCatch >/dev/null 2>&1

    aOptions=$aFlag
    nOptions=$nFlag
    dOptions=$dFlag
    lOptions=`expr $lFlag + $sFlag`
    mOptions=$mFlag
    pOptions=`expr $cFlag + $eFlag`
    majorOptions=`expr $aFlag + $lFlag + $mFlag + $pFlag + $nFlag + $dFlag`

    # Must specify either -a or -l or -m or -p or -n or -d
    if [ $majorOptions -eq 0 ]; then
	regRemove_Usage $EXIT_USAGE 1>&2
    fi

    # -a and -l and -m and -p and -n and -d are mutually exclusive
    if [ $majorOptions -ne 1 ]; then
	regRemove_Usage $EXIT_USAGE "-a, -l, -m, -p, -n, and -d are mutually exclusive" 1>&2
    fi

    # -n is deprecated.  Map to -a with appropriate warning.
    if [ $nFlag -ne 0 ] && [ $qFlag -eq 0 ]; then
	$ECHO "WARNING! -n is deprecated and will be unavailable in a future"
	$ECHO "release.  Please change to using the -a option."
	nFlag=0
	aFlag=1
    fi

    # For application unregistration
    if [ $aFlag -ne 0 ]; then
	# First position-dependent argument app's registered name
	if [ ! -n "$1" ]; then
	    regRemove_Usage $EXIT_USAGE "No <app_name> specified" 1>&2
	fi
	unregisterApp $1
    fi

    # -d is deprecated, remove by original install directory.
    if [ $dFlag -ne 0 ]; then

	$ECHO "WARNING! -d is deprecated and will be unavailable in a future"
	$ECHO "release.  Please change to using the -a option."

	# First position-dependent argument must be path to app.
	if [ ! -n "$1" ]; then
	    regRemove_Usage $EXIT_USAGE "No <path> specified" 1>&2
	fi
	path=$1

	# Normalize the path so that it is relative to the client
	if [ `isNormalizeable ${BASEDIR}` = "1" ]; then
	    path=`$ECHO $path | sed -e "s@^${BASEDIR}/@/@"`
	fi

	# Remove trailing slashes (/) and double slashes (//) from the path
	path=`$ECHO $path | sed 's@/*$@@' | sed 's@//*@/@g'`	

	# Check to make sure the path exists in the file
	getConsoleBaseDir
	status=0
	if [ ! -s $CONSOLE_BASE_DIR/$REG_PLUGIN_LIST ]; then
	    status=1
	fi
	if [ $status -eq 0 ]; then
	    regAppInfo=`getRegAppBy path $path`
	    p=`getRegAppValue $regAppInfo path`
	    if [ "$p" = "$path" ]; then
		status=0
	    else
		status=1
	    fi
	fi
	if [ $status -ne 0 ]; then
	    printOut "Error! \"$path\" has not been registered." 1>&2
	    exit $EXIT_FAILURE
	fi

	# Extract name associated with the path.
	name=`getRegAppValue $regAppInfo pluginID`

	unregisterApp $name

    fi

    # For library unregistration
    if [ $lFlag -ne 0 ]; then

	# -l requires -s
	if [ ! -n "${scope}" ]; then
	    # This can happen if position argument embedded within
	    # position-independent options.
	    regRemove_Usage $EXIT_USAGE 1>&2
	fi

	# First position-dependent argument jar's registered name
	if [ ! -n "$1" ]; then
	    regRemove_Usage $EXIT_USAGE "No <lib_name> specified" 1>&2
	fi
	unregisterJar $scope $1

        # remove the jar's regnot
	# $1 is the name the jar was registered under
	removeJarRegnot $1

    fi

    # For login module unregistration
    if [ $mFlag -ne 0 ]; then

	# First position-dependent argument must be class name.
	if [ ! -n "$1" ]; then
	    regRemove_Usage $EXIT_USAGE "No <class_name> specified" 1>&2
	fi

	# -m requires <scope>, but if not specified, we assume ConsoleLogin
	# for compatibility sake.
	if [ ! -n "${scope}" ]; then
	    scope="ConsoleLogin"
	fi

	unregisterModule $scope $1

	# remove modules regnot if it exists
	# $1 is the modules class name
	removeModuleRegnot $1

    fi

    # For properties unregistration
    if [ $pFlag -ne 0 ]; then

	# -c and -e are mutually exclusive
	if [ $pOptions -gt 1 ]; then
	    regRemove_Usage $EXIT_USAGE "-c and -e are mutually exclusive" 1>&2
	fi

	# Must be at least one position-dependent name argument.
	if [ ! -n "$1" ]; then
	    regRemove_Usage $EXIT_USAGE "No named properties specified" 1>&2
	fi

	unregisterProperties $eFlag $*
    fi

} ## regRemove


################################################################################
#
# regCheck
#
# Handler for the "check" subcommand.
#
# Arguments should be $*, minus the subcommand
#
################################################################################

regCheck() {

    path=""

    # When getopts prints errors, it includes the name of the function.
    # So we catch the error msg output into a file so we can replace the
    # function name with the overall script name and subcommand.
    #
    errCatch=/tmp/regCheck.$$
    rm -f $errCatch >/dev/null 2>&1
    while getopts "hd:" c > $errCatch 2>&1; do
	case $c in
	    "d") path=${OPTARG};;
	    "h") regCheck_Usage $EXIT_SUCCESS;;
	    \?)  msg=`sed -e "s@regCheck@${PROGNAME} check@" $errCatch`
		 rm -f $errCatch
		 regCheck_Usage $EXIT_USAGE "$msg" 1>&2
		 ;;
	esac
    done
    shift `expr $OPTIND - 1`

    rm -f $errCatch >/dev/null 2>&1

    # If path not provided via -d, then provided as 1st positional argument
    if [ ! -n "${path}" ]; then
	path=$1
    fi

    # Error if no path
    if [ ! -n "${path}" ]; then
	regCheck_Usage $EXIT_USAGE 1>&2
    fi

    ## $path can be the full path to a web.xml file or
    ## the path to an application directory.
    ## If the path is not a dir to the app strip off
    ## WEB-INF/web.xml so we can find the apps app.xml
    if [ -f "${path}" ]; then
	appDir=`$ECHO ${path} | sed 's@/WEB-INF/web.xml@@g'`
    else
	appDir=${path}
    fi

    # We need the apps SDK version, look
    # for app.xml in the appropriate places
    if [ -s ${appDir}/WEB-INF/app.xml ]; then
	# Apps based on 2.1 or later should have descriptor in app's WEB-INF
	# directory, and the registrationInfo version should be set to the SDK
	# the app was built against, 2.1 or later.
	getConsoleVersionNum
	extractSDKversion ${appDir}/WEB-INF/app.xml
	appVersion=`versionString2Num $SDK_VERSION`
	if [ "(" ${appVersion} -lt 21000 ")" -o "(" ${appVersion} -gt ${CONSOLE_VERSION_NUM} ")" ]; then
	    printOut "Error! The registrationInfo \"$VERSION_ATTR\" attribute in ${appDir}/WEB-INF/app.xml must be at least 2.1 and no more than ${CONSOLE_VERSION}" 1>&2
	    exit $EXIT_FAILURE
	fi
    elif [ -s ${appDir}/app.xml ]; then
	# Pre-2.1 based apps have descriptor in top-level app directory.
	extractSDKversion ${appDir}/app.xml
	appVersion=`versionString2Num $SDK_VERSION`
	if [ ${appVersion} -gt 20000 ]; then
	    printOut "Error! The registrationInfo \"$VERSION_ATTR\" attribute in ${appDir}/app.xml must be less than 2.1" 1>&2
	    exit $EXIT_FAILURE
	fi
    else
	printOut "Error! No registration descriptor file (app.xml) found in ${appDir} or ${appDir}/WEB-INF." 1>&2
	exit $EXIT_FAILURE
    fi

    if [ ${appVersion} -lt 21000 ]; then
        checkForFilterTags $path
	if [ $? -eq 0 ]; then
	    printOut "INFO: This application's descriptor has the correct <filter> and <filter-mapping> tags."
	else
	    printOut "WARNING! ${path} does not have the correct <filter> and <filter-mapping> tags, and will not register successfully. This descriptor should look as follows:" 1>&2
	    addFilterTags ${path}
	    exit $EXIT_FAILURE
	fi
    fi

} ## regCheck

################################################################################
#
# createAppRegnot
#
# Write regnot to the prereg directory
#
# $1 is the path to the application
# $2 is the context path name
#
# properties for a webapp regnot
# type
# context
# location
#
################################################################################

createAppRegnot() {

    # do not create regnots in miniRoot
    if [ `inMiniRoot` = "1" ]; then
	return
    fi

    # store params in more meaningful variable names
    appPath=$1 

    # if context is not defined it defaults to 
    # the basename of the path to the application
    if [ ! -n "${2}" ]; then
	context=`basename ${appPath}`
    else
	context=$2
    fi

    # the identity is the name of the regnot 
    # it will always be the last directory in the appPath
    identity=`basename ${appPath}`
    
    # build path to this regnot file
    regnotDir=${PREREG_DIR}/${LEGACY_REGNOT_DIR}
    regnotFile=${regnotDir}/${identity}.reg

    #
    # build properties for regnot
    #

    # set properties to the empty string
    properties=""

    # type 
    properties="${properties}${TYPE_PROP}=${WEBAPP}\n"

    # context
    properties="${properties}${CONTEXT_PROP}=${context}\n"

    # location 
    getConsoleAppbaseDir
    location=${CONSOLE_APPBASE_DIR}/${context}
    properties="${properties}${LOCATION_PROP}=${location}"

    #
    # Write the regnot to disk
    #

    # does the regnot file exists
    if [ -d ${regnotFile} ]; then
	# it's a directory error and exit
	$ECHO Regnot file is an existing directory
    fi

    # if the regnot file exists remove it
    if [ -f ${regnotFile} ]; then
	rm -f ${regnotFile}
    fi

    # if the regnot dir directory doesn't exist make it
    if [ ! -d ${regnotDir} ]; then
	mkdir -p ${regnotDir}
    fi

    # write the regnot
    $ECHO ${properties} > ${regnotFile}

} ## createAppRegnot

################################################################################
#
# removeAppRegnot
#
# remove an apps regnot from the prereg directory if it exists
#
# $1 is the applications name
#
################################################################################

removeAppRegnot() {

    # do not remove regnots in miniRoot
    if [ `inMiniRoot` = "1" ]; then
	return
    fi

    # store params in more meaningful variable names
    appPath=$1 

    # the identity is the name of the regnot 
    # it will always be the last directory in the appPath
    identity=`basename ${appPath}`
    
    # build path to this regnot file
    regnotFile=${PREREG_DIR}/${LEGACY_REGNOT_DIR}/${identity}.reg

    # if the file exists remove it
    if [ -f ${regnotFile} ]; then
	rm -f ${regnotFile}
    fi

} ## removeAppRegnot

################################################################################
#
# createJarRegnot
#
# Write regnot to the prereg directory
#
# $1 is the path to jar
#
# type=jar
# location=(location is variable)
# 
# identity will be the name of the jar file minus the .jar suffix
# /a/b/c/dog.jar -> dog
################################################################################
createJarRegnot() {

    # do not create regnots in miniRoot
    if [ `inMiniRoot` = "1" ]; then
	return
    fi

    # store params in more meaningful variable names
    location=$1 

    # the identity is the name of the regnot 
    # it will always be he last element in location
    identity=`basename $location`


    # the regnot name shouldn't include the .jar suffix
    # remove it if it is there
    identity=`$ECHO ${identity} | sed -e 's@\.jar$@@'`

    # build path to this regnot file
    regnotDir=${PREREG_DIR}/${LEGACY_REGNOT_DIR}
    regnotFile=${regnotDir}/${identity}.reg

    #
    # build properties for regnot
    # 

    # set properties to the empty string
    properties=""

    # type 
    properties="${properties}${TYPE_PROP}=${JAR}\n"

    # location
    properties="${properties}${LOCATION_PROP}=${location}"
   
    #
    # Write the regnot to disk
    #

    # does the regnot file exists
    if [ -d ${regnotFile} ]; then
	# it's a directory error and exit
	$ECHO Regnot file is an existing directory
    fi

    # if the regnot file exists remove it
    if [ -f ${regnotFile} ]; then
	rm -f ${regnotFile}
    fi

    # if the regnot dir directory doesn't exist make it
    if [ ! -d ${regnotDir} ]; then
	mkdir -p ${regnotDir}
    fi

    # write the regnot
    $ECHO ${properties} > ${regnotFile}

} ## createJarRegnot

################################################################################
#
# removeJarRegnot
#
# remove a jars regnot from the prereg directory if it exists
#
# $1 location
#
################################################################################

removeJarRegnot() {

    # do not remove regnots in miniRoot
    if [ `inMiniRoot` = "1" ]; then
	return
    fi

    # store params in more meaningful variable names
    location=$1 

    # regnot filename is based on the name of jar
    identity=`basename $location`

    # the regnot name shouldn't include the .jar suffix
    # remove it if it is there
    identity=`$ECHO ${identity} | sed -e 's@\.jar$@@'`

    regnotFile=${PREREG_DIR}/${LEGACY_REGNOT_DIR}/${identity}.reg

    # if the file exists remove it
    if [ -f ${regnotFile} ]; then
	rm -f ${regnotFile}
    fi

} ## removejarRegnot

################################################################################
#
# createModuleRegnot
#
# Write regnot to the prereg directory
#
# $1 is the scope 
# $2 is the class 
# $3 is the behavior
# $4 begins the system properties that the user has defined for the login module
#
# type=loginmodule
# behavior=
# class=
# service=
# option_{userOption1}=
# option_{userOption2}=
# option_{userOption3}=
# ...
# option_{userOptionN}=
#
# IDENTITY will be the class name of the module with . replcaed by _
# a.b.c.dog becomes a_b_c_dog
#
################################################################################

createModuleRegnot() {

    # do not create regnots in miniRoot
    if [ `inMiniRoot` = "1" ]; then
	return
    fi

    # store params in more meaningful variable names
    scope=$1 
    class=$2
    behavior=$3
    
    # the identity is the name of the regnot 
    # it will be  the class with . replaced by _
    identity=`$ECHO ${class} | sed 's@\.@_@g'`

    # build path to this regnot file
    regnotDir=${PREREG_DIR}/${LEGACY_REGNOT_DIR}
    regnotFile=${regnotDir}/${identity}.reg

    #
    # build properties for regnot
    #

    # set properties to the empty string
    properties=""

    # type
    properties="${properties}${TYPE_PROP}=${MODULE}\n"

    # class
    properties="${properties}${CLASS_PROP}=${class}\n"

    # behavior
    properties="${properties}${BEHAVIOR_PROP}=${behavior}\n"

    # servicename
    properties="${properties}${SERVICE_PROP}=${scope}"

    #
    # user properties are of the form name="value" need
    # to be placed one property line, prefixed with option_,
    # and stripped of quotes.
    #
    # IMPORTANT:  For argument in 'name=value' format, find the pattern
    # that signifies that signifies where a whitespace should be and
    # replace it with a whitespace. Quotes are not needed in regnots so
    # they are also removes.
    userProps=""
    while [ -n "$4" ]; do
	p=`$ECHO ${4} | sed -e "s@$WHITESPACE_KEY_PATTERN@ @g" -e 's@\"@@g'`
	if [ -n "${userProps}" ]; then
	    userProps="${userProps}${OPTION_PREFIX}${p}\n"
	else
	    userProps="${OPTION_PREFIX}${p}\n"
	fi
	shift
    done

    #
    # Write the regnot to disk
    #

    # does the regnot file exists
    if [ -d ${regnotFile} ]; then
	# it's a directory error and exit
	$ECHO Regnot file is an existing directory
    fi

    # if the regnot file exists remove it
    if [ -f ${regnotFile} ]; then
	rm -f ${regnotFile}
    fi

    # if the regnot dir directory doesn't exist make it
    if [ ! -d ${regnotDir} ]; then
	mkdir -p ${regnotDir}
    fi

    # write the regnot
    $ECHO ${properties} > ${regnotFile}
    $ECHO ${userProps} >> ${regnotFile}

} ## createModuleRegnot

################################################################################
#
# removeModuleRegnot
#
# remove a login modules regnot from the prereg directory if it exists
#
# $1 = LoginModule class name 
#
################################################################################

removeModuleRegnot() {

    # do not remove regnots in miniRoot
    if [ `inMiniRoot` = "1" ]; then
	return
    fi

    # store params in more meaningful variable names
    class=$1

    # the identity is the name of the regnot 
    # it will be  the class with . replaced by _
    identity=`$ECHO ${class} | sed 's@\.@_@g'`

    # build path to this regnot file
    regnotDir=${PREREG_DIR}/${LEGACY_REGNOT_DIR}/${identity}.reg

    # if the file exists remove it
    if [ -f ${regnotFile} ]; then
	rm -f ${regnotFile}
    fi

} ## removeModuleRegnot

################################################################################
#
# smwebappImport
#
# It is forbidden to run a JVM during installation, we still have to import
# so the mport function from the smwebapp script has been inserted into smreg
#
#
# Handler for the "import" subcommand.
#
# Command to import management web application local files needed
# by the common components.  Management web applications must be
# self-contained, thus must have copies of these local files within
# their WAR file or unpacked subdirectory structure.  This command
# can be run as part of the web application's build; that is, it
# can be run repeatedly in builds.
#
# Copy local files into the management web application directory structure
# with the following layout:
#
# ./WEB-INF/lib/*
# ./WEB-INF/tld/com_iplanet_jato/*.tld
# ./WEB-INF/tld/com_sun_web_ui/*.tld
# ./com_sun_web_ui/*
# 
# A copy of the auto registration servlet jar file is
# added to the WEB-INF/lib subdirectory. A copy of the local management
# files is copied into the ./com_sun_web_ui subdirectory. The JATO and
# common components TLD files are copied into the ./WEB-INF/tld
# subdirectory.
#
# Source files are obtained from the installed console import subdirectory.
#
# Arguments should be $*, minus the subcommand
# For complete syntax, see import_Usage().
#
################################################################################

smwebappImport() {

    # Target directory must be specified.
    targetDir=$1
    if [ ! -n "$targetDir" ]; then
	smwebappImport_Usage $EXIT_USAGE "No target directory specified".
    fi

    # Ensure target path exists
    if [ ! -d "${targetDir}" ]; then
	$ECHO "Target directory \"${targetDir}\" does not exist."
	exit $EXIT_FAILURE
    fi

    # We assume the import directory is relative to where the command is 
    # located.
    getConfigProperties
    
    SRC_PATH=${console_home}/private/import
    if [ ! -d ${SRC_PATH} ]; then
	$ECHO "Import source directory \"${SRC_PATH}\" does not exist"
	exit $EXIT_FAILURE
    fi

    # Ensure target path is absolute in the face of cd'ing
    saveCWD=`pwd`
    cd $targetDir
    targetDir=`pwd`
    cd $saveCWD

    cd ${SRC_PATH}

    # com_sun_web_ui
    mkdir -p ${targetDir}/WEB-INF
    find com_sun_web_ui -print | cpio -pdmu ${targetDir} >/dev/null 2>&1
    if [ $? -ne 0 ]; then
	$ECHO "Unable to copy $SRC_PATH/com_sun_web_ui to $targetDir"
    fi

    # tld files
    find tld -print | cpio -pdmu $targetDir/WEB-INF >/dev/null 2>&1
    if [ $? -ne 0 ]; then
	$ECHO "Unable to copy $SRC_PATH/tld to $targetDir/WEB-INF"
    fi

    # Library jars
    find lib -print | cpio -pdmu ${targetDir}/WEB-INF >/dev/null 2>&1
    if [ $? -ne 0 ]; then
	$ECHO "Unable to copy $SRC_PATH/lib to $targetDir/WEB-INF"
    fi

} ## smwebappImport

################################################################################
#
# smwebappImport_Usage
#
# It is forbidden to run a JVM during installation, we still have to import
# so the import function from smwebapp has been inserted into smreg
#
# Usage method for the "import" subcommand
#
# $1 = Exit code
# $2 = optional error message to display before the usage.
#
################################################################################

smwebappImport_Usage() {

    # import is not a public API
    webappUsage $EXIT_USAGE
    
    # function name
    FUNCNAME="smwebappImport"
    if [ -n "$2" ]; then
	$ECHO $2
    fi

    cat - << EOF

    Usage: ${FUNCNAME} import <path>
     or: ${FUNCNAME} import $HELP_FLAG_SHORT

    Import management web application local files needed
    by the common components.  Management web applications must be
    self-contained, thus must have copies of these local files within
    their WAR file or unpacked subdirectory structure.  This command
    can be run as part of the web application's build; that is, it
    can be run repeatedly in builds.

    path
           The target web application directory to install local files.

    $HELP_FLAG_SHORT, $HELP_FLAG_SHORT2, $HELP_FLAG_LONG
           Display this help list.

    For more information, see smwebapp($MANSECTION).
    
EOF

} ## import_Usage

################################################################################
#
# Main function area for register
#
# Parameters work as follows:
#
# $1 = SUBCOMMAND ARGUMENTS | -h | -V
#
################################################################################

main() {


    SUB_COMMAND=$1

    # Check for quiet mode, if we have a -q then set qFlag to 1
    # and set SUB_COMMAND to $2
    if [ "$SUB_COMMAND" = "${QUIET_FLAG_SHORT}" ] \
	|| [ "$SUB_COMMAND" = "${QUIET_FLAG_LONG}" ]; then
	qFlag=1
        SUB_COMMAND=$2
	shift 1
    else
	# not quiet mode, print deprecation message
	deprecationMsg
    fi

    case "$SUB_COMMAND" in

    "$HELP_FLAG_SHORT" | "$HELP_FLAG_SHORT2" | "$HELP_FLAG_LONG" )
	regUsage $EXIT_SUCCESS
	;;

    "$VERSION_FLAG_SHORT" | "$VERSION_FLAG_LONG")
	regVersion
	;;

    "$ADD_CMD")
	shift 1
	args=`$ECHO $* | sed \
	    -e "s/${APP_FLAG_LONG}/${APP_FLAG_SHORT}/" \
	    -e "s/${DIR_FLAG_LONG}/${DIR_FLAG_SHORT}/" \
	    -e "s/${CONTEXT_FLAG_LONG}/${CONTEXT_FLAG_SHORT}/" \
	    -e "s/${LIB_FLAG_LONG}/${LIB_FLAG_SHORT}/" \
	    -e "s/${LINK_FLAG_LONG}/${LINK_FLAG_SHORT}/" \
	    -e "s/${PROP_FLAG_LONG}/${PROP_FLAG_SHORT}/" \
	    -e "s/${LM_FLAG_LONG}/${LM_FLAG_SHORT}/" \
	    -e "s/${ENV_FLAG_LONG}/${ENV_FLAG_SHORT}/" \
	    -e "s/${CONFIG_FLAG_LONG}/${CONFIG_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_SHORT2}/${HELP_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_LONG}/${HELP_FLAG_SHORT}/" \
	    -e "s/${NAME_FLAG_LONG}/${NAME_FLAG_SHORT}/" \
	    -e "s/${SCOPE_FLAG_LONG}/${SCOPE_FLAG_SHORT}/" \
	    -e "s/${OPTION_FLAG_LONG}/${OPTION_FLAG_SHORT}/" \
	    -e "s/${BEH_FLAG_LONG}/${BEH_FLAG_SHORT}/"`
	regAdd $args
	;;

    "$REMOVE_CMD")
	shift 1
	args=`$ECHO "$*" | sed \
	    -e "s/${APP_FLAG_LONG}/${APP_FLAG_SHORT}/" \
	    -e "s/${DIR_FLAG_LONG}/${DIR_FLAG_SHORT}/" \
	    -e "s/${NAME_FLAG_LONG}/${NAME_FLAG_SHORT}/" \
	    -e "s/${LIB_FLAG_LONG}/${LIB_FLAG_SHORT}/" \
	    -e "s/${PROP_FLAG_LONG}/${PROP_FLAG_SHORT}/" \
	    -e "s/${LM_FLAG_LONG}/${LM_FLAG_SHORT}/" \
	    -e "s/${ENV_FLAG_LONG}/${ENV_FLAG_SHORT}/" \
	    -e "s/${CONFIG_FLAG_LONG}/${CONFIG_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_SHORT2}/${HELP_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_LONG}/${HELP_FLAG_SHORT}/" \
	    -e "s/${SCOPE_FLAG_LONG}/${SCOPE_FLAG_SHORT}/" \
	    -e "s/${BEH_FLAG_LONG}/${BEH_FLAG_SHORT}/"`
	regRemove $args
	;;

    "$LIST_CMD")
	shift 1
	args=`$ECHO $* | sed \
	    -e "s/${APP_FLAG_LONG}/${APP_FLAG_SHORT}/" \
	    -e "s/${LIB_FLAG_LONG}/${LIB_FLAG_SHORT}/" \
	    -e "s/${PROP_FLAG_LONG}/${PROP_FLAG_SHORT}/" \
	    -e "s/${LM_FLAG_LONG}/${LM_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_SHORT2}/${HELP_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_LONG}/${HELP_FLAG_SHORT}/"`
	regList $args
	;;

    "$CHECK_CMD")
	shift 1
	args=`$ECHO $* | sed \
	    -e "s/${DIR_FLAG_LONG}/${DIR_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_SHORT2}/${HELP_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_LONG}/${HELP_FLAG_SHORT}/"`
	regCheck $args
	;;

    *)
	regUsage $EXIT_USAGE 1>&2
	;;
    esac

    exit $EXIT_SUCCESS

} ## main

main ${PROGARGS}
##  DO NOT ADD ANY CODE BELOW HERE!!
