#!/bin/sh
#
#ident "@(#)smwebapp	1.22 05/03/03 SMI"
# Copyright (c) 2004 Sun Microsystems, Inc.
# All Rights Reserved.

################################################################################
##
## Script for creating, updating, and validating local Sun Java(TM) Web Console
## web application context files
##
################################################################################

umask 022


################################################################################
#
# 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

# 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

MANSECTION=1

# The minimum Java version we require
MIN_JAVA_VERSION="1.4.2"

# Location of default and configuration property files.
# Specific platforms may override these default locations.
DEFAULT_FILE=/etc/default/webconsole
CONFIG_FILE=/etc/opt/webconsole/webconsole

# Setup command environment for target OS.
if [ "${OS}" = "SunOS" ]; then
    PATH=/bin:/sbin:/usr/sbin
    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

elif [ "${OS}" = "Linux" ]; then
    PATH=/bin:/sbin:/usr/bin:/usr/sbin
    ECHO="/bin/echo -e"
    WHICH="which --skip-alias"
    DEFAULT_FILE=/etc/opt/default/webconsole

    # 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`
	DEFAULT_JAVA_HOME="$DEFAULT_JAVA_HOME /usr/java/`ls -A /usr/java | fgrep j2sdk${MIN_JAVA_VERSION} | sort | tail -1`"
    fi

elif [ "${OS}" = "HP-UX" ]; then
    PATH=/bin:/sbin:/usr/bin:/usr/sbin
    ECHO="/bin/echo"
    WHICH="/bin/ksh whence"
    DEFAULT_JAVA_HOME=/opt/java1.4

elif [ "${OS}" = "AIX" ]; then
    PATH=/bin:/sbin:/usr/bin:/usr/sbin
    ECHO="/bin/echo"
    WHICH="/bin/ksh whence"
    DEFAULT_JAVA_HOME=/usr/java
    MIN_JAVA_VERSION="1.4.1"

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


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

## Get the console home directory as an absolute pathname
savecwd=`pwd`
cd $PROGDIR/..
CONSOLE_HOME=`pwd`
cd $savecwd 

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

## 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/webconsole.
## 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/webconsole 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

## Useful constants
IMPORT_CMD="import"		# "import" subcommand
VALIDATE_CMD="validate"		# "validate" subcommand
PRODNAME_CMD="prodname"		# "prodname" subcommand
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
VERSION_FLAG_SHORT="-V"         # indicates the version should be printed
VERSION_FLAG_LONG="--version"   # indicates the version should be printed
APPXML_FLAG_SHORT="-a"		# indicates to validate the app.xml file
APPXML_FLAG_LONG="--appxml"	# indicates to validate the app.xml file
WEBXML_FLAG_SHORT="-w"		# indicates to validate the web.xml file
WEBXML_FLAG_LONG="--webxml"	# indicates to validate the weB.xml file
PRODTYPE_FLAG_LONG="--type"	# indicates product name type
PRODTYPE_FLAG_SHORT="-t"
PRODDIR_FLAG_LONG="--directory"	# indicates target directory for product files
PRODDIR_FLAG_SHORT="-d"
PRODRES_FLAG_LONG="--resources"	# indicates input resource properties file
PRODRES_FLAG_SHORT="-r"
PRODNAME_FLAG_LONG="--name"	# indicates product name
PRODNAME_FLAG_SHORT="-n"

# Special white space pattern
WS_PATTERN="_WxS_"

########################################################
#
# 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
    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}'`
    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

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

} # versionString2Num


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


    # Map to a number we can do a numerical comparison on.
    weWant=`versionString2Num $MIN_JAVA_VERSION`

    # 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
	    # Get version, and map to a number we can do a 
	    # numerical comparison on.
	    version=`${i} -version 2>&1 | head -1`
	    version=`echo $version | awk '{print $3}' | sed -e "s/\"//g"`
	    weHave=`versionString2Num $version`

	    if [ ${weHave} -ge ${weWant} ]; then
		JAVA_HOME=`dirname \`dirname ${prog}\``
		export JAVA_HOME
		break
	    fi

	fi
    done

    # It is possible we didn't find one if it was installed in a non-default
    # location and the user neglected to set JAVA_HOME or include it along
    # PATH.  In this case, we try to derive it by querying the pkg database.
    #
    if [ ! -n "${JAVA_HOME}" ] && [ "${OS}" = "SunOS" ]; then
	jdk=SUNWj5rt
	pkginfo $jdk >/dev/null 2>&1
	if [ "$?" -eq 0 ]; then
	    # Get version, and map to a number we can do a 
	    # numerical comparison on.
	    version=`env LANG=C LC_ALL=C pkgparam $jdk VERSION \
		| awk -F, '{print $1}'`
	    weHave=`versionString2Num $version`

	    if [ ${weHave} -ge ${weWant} ]; then
		j2basedir=`env LANG=C LC_ALL=C pkgparam ${jdk} BASEDIR`
		JAVA_HOME=${j2basedir}/jdk/jdk${version}
		export JAVA_HOME
	    fi
	fi
    fi
    if [ ! -n "${JAVA_HOME}" ] && [ "${OS}" = "SunOS" ]; then
	jdk=SUNWj3rt
	pkginfo $jdk >/dev/null 2>&1
	if [ "$?" -eq 0 ]; then
	    # Get version, and map to a number we can do a 
	    # numerical comparison on.
	    version=`env LANG=C LC_ALL=C pkgparam $jdk VERSION \
		| awk -F, '{print $1}'`
	    weHave=`versionString2Num $version`

	    if [ ${weHave} -ge ${weWant} ]; then
		j2basedir=`env LANG=C LC_ALL=C pkgparam ${jdk} BASEDIR`
		JAVA_HOME=${j2basedir}/j2se
		export JAVA_HOME
	    fi
	fi
    fi

    if [ ! -n "${JAVA_HOME}" ] && [ "${OS}" = "Linux" ]; then
	jdks="`rpm -qa | grep jdk` `rpm -qa | grep j2sdk`"
	for jdk in $jdks
	do
	    # Get version, and map to a number we can do a 
	    # numerical comparison on.
	    version=`env LANG=C LC_ALL=C rpm -qi $jdk \
		| grep "^Version" | awk '{print $3}'`
	    weHave=`versionString2Num $version`

	    if [ ${weHave} -ge ${weWant} ]; then
		bindir=`rpm -ql $jdk | grep "/bin$" | sort | head -1`
		JAVA_HOME=`dirname $bindir`
		export JAVA_HOME
		break
	    fi
	done
    fi

    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 $MIN_JAVA_VERSION" 1>&2
	$ECHO "installation and run ${PROGDIR}/${PROGNAME} again." 1>&2
	exit $EXIT_FAILURE
    fi

    # All executables that are relative to JAVA_HOME can be assigned here.
    JAVA=${JAVA_HOME}/bin/java



} # findJava


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

webappUsage() {

    cat - << EOF

    Usage: ${PROGNAME} SUBCOMMAND ARGUMENTS
     or: ${PROGNAME} $HELP_FLAG_SHORT
     or: ${PROGNAME} $VERSION_FLAG_SHORT

    SDK tool for developing applications for the ${PRODUCT_NAME}.

    The accepted values for SUBCOMMAND are:

    prodname   Generate product name image files

    validate   Validate the contents of the app.xml or web.xml file

    $VERSION_FLAG_SHORT, $VERSION_FLAG_LONG
           Display console version information.

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

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

    exit $1

} ## end webappUsage()


################################################################################
#
# webappVersion
#
# Display version information.
#
################################################################################

webappVersion() {

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

    cat - << EOF
    ${PROGNAME} (${PRODUCT_NAME}) $version
    Copyright 2004 Sun Microsystems, Inc.
    All Rights Reserved.
    Use is subject to license terms.
EOF

} ## end webappVersion


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

import_Usage() {

    # import is not a public API
    webappUsage $EXIT_USAGE

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

    cat - << EOF

    Usage: ${PROGNAME} import <path>
     or: ${PROGNAME} 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


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

validate_Usage() {

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

    cat - << EOF

    Usage: ${PROGNAME} validate  $APPXML_FLAG_SHORT | $WEBXML_FLAG_SHORT  <path>

    The validate subcommand verifies the syntax and contents of either
    the application registration deployment descriptor file (app.xml)
    or the web application deployment descriptor file (web.xml).
    The XML file is verified against its DTD definition file and
    checked for the existence of required console tags and their
    values.

    path
           The target web application directory containing the
           deployment descriptor file, or the path to the descriptor
           file itself.  If the former, the descriptor file is
           looked for in the <path>/WEB-INF subdirectory.

    $APPXML_FLAG_SHORT, $APPXML_FLAG_LONG
           Validate the app.xml file.

    $WEBXML_FLAG_SHORT, $WEBXML_FLAG_LONG
           Validate the web.xml file.

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

} ## validate_Usage

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

prodname_Usage() {

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

    cat - << EOF

    Usage: ${PROGNAME} prodname $PRODTYPE_FLAG_SHORT <type> $PRODNAME_FLAG_SHORT <name> $PRODDIR_FLAG_SHORT <path> [$PRODRES_FLAG_SHORT <resources>]
                                        $APPXML_FLAG_SHORT <xml_path>

    The prodname command generates one or more product name image files
    from specified product names.  The image file is written to the
    directory specified by the path argument.  The resources argument
    specifies an optional properties file containing settings for name
    image generation.  The product name can be explicitly specified or
    provided by tags in the web application app.xml file.

    $PRODTYPE_FLAG_SHORT, $PRODTYPE_FLAG_LONG <type>
           Specifies the type of product name image; that is, one of
           "primary", "secondary", "version", or "all".  If "all" is
           specified, all three product name image files are generated
           from the same product name.

    $PRODNAME_FLAG_SHORT, $PRODNAME_FLAG_LONG <name>
           The product name string value.  The value should be quoted
           if it contains white space.  A two line name is indicated
           by inserting the "(cr)" character sequence at the line break.
           This option is mutually exclusive with the xml file option.

    $APPXML_FLAG_SHORT, $APPXML_FLAG_LONG <xml_path>
           The product name string values should be obtained from the
           application deployment descriptor file. The xml_path specifies
           a directory path to the descriptor file, or a path to the
           web application installation directory (in which case the
           descriptor file is looked for in the WEB-INF subdirectory).

    $PRODDIR_FLAG_SHORT, $PRODDIR_FLAG_LONG <path>
           Specifies the output directory to contain the product name
           image files and accompanying properties file.  The image
           files have predefined file names.

    $PRODRES_FLAG_SHORT, $PRODRES_FLAG_LONG <resources>
           Specifies an optional resource properties file to be used
           by the image generation program.  Properties can override
           the default settings for image file names, font, font size,
           and colors.

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

} ## validate_Usage


################################################################################
#
# import
#
# 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().
#
################################################################################

import() {

    # 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/import.$$
    rm -f $errCatch >/dev/null 2>&1
    while getopts "h" c > $errCatch 2>&1; do
	case $c in
	    "h") import_Usage $EXIT_SUCCESS;;
	    \?)  msg=`sed -e "s@import@${PROGNAME} import@" $errCatch`
		 rm -f $errCatch
		 import_Usage $EXIT_USAGE "$msg" 1>&2
		 ;;
	esac
    done
    shift `expr $OPTIND - 1`

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

    # Target directory must be specified.
    targetDir=$1
    if [ ! -n "$targetDir" ]; then
	import_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.
    SRC_PATH=$CONSOLE_HOME/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

} ## import


################################################################################
#
# validate
#
# Handler for the "validate" subcommand.
#
# Syntax: validate {-a | -w} target_path [check_file}
#
# If the directory path ends with a directory (not WEB-XML),
# add the subpath "./WEB-INF" to this path and check for its existence.
# If the directory path ends with a file, check that the file is
# "app.xml" for the "a" option or "web.xml" for the "w" option.
# Check that the app.xml or web.xml file exists.
#
# The check_file argument is an optional, hidden parameter which
# allows checking the web.xml against an alternative check file.
# It is used by console developers to check console web applications.
# The check_file must be an existing file in the check file subdirectory.
#
# If validating the app.xml, run the AppXmlChecker java program
# specifying the path to the app.xml file.
# If validating the web.xml, run the WebXmlChecker java program
# specifying the path to the web.xml file and the check file.
#
################################################################################

validate() {
    
    aflag=0
    wflag=0
    targetPath=""
    targetOpt=""
    
    # find Java
    findJava

    # 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/validate.$$
    rm -f $errCatch >/dev/null 2>&1
    while getopts "ahw" c > $errCatch 2>&1; do
	case $c in
	    "a") aflag=1; targetOpt="app";;
	    "w") wflag=1; targetOpt="web";;
	    "h") validate_Usage $EXIT_SUCCESS;;
	    \?)  msg=`sed -e "s@validate@${PROGNAME} validate@" $errCatch`
		 rm -f $errCatch
		 validate_Usage $EXIT_USAGE "$msg" 1>&2
		 ;;
	esac
    done
    shift `expr $OPTIND - 1`

    targetPath=$1
    hiddenFile=$2

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

    majorOptions=`expr $aflag + $wflag`

    # Must specify either -a or -w
    if [ $majorOptions -eq 0 ]; then
	validate_Usage $EXIT_USAGE
    fi

    # -a and -w are mutually exclusive
    if [ $majorOptions -ne 1 ]; then
	validate_Usage $EXIT_USAGE "-a and -w are mutually exclusive"
    fi

    # Target path must be specified.
    if [ ! -n "${targetPath}" ]; then
	validate_Usage $EXIT_USAGE "No target path specified".
    fi

    # Ensure target path exists.  It might be a directory.
    if [ -d "${targetPath}" ]; then
	temp=`basename ${targetPath}`
	if [ "${temp}" != "WEB-INF" ]; then
	    targetPath="${targetPath}/WEB-INF"
	fi
	targetPath="${targetPath}/${targetOpt}.xml"
    fi

    # Ensure target XML file exists.
    if [ ! -f "${targetPath}" ]; then
	$ECHO "Target XML file \"${targetPath}\" not found"
	exit $EXIT_FAILURE
    fi

    # Ensure target XML is one we can parse.
    temp=`basename ${targetPath}`
    if [ "$temp" != "${targetOpt}.xml" ]; then
	$ECHO "Target file \"${targetPath}\" is not a ${targetOpt}.xml file we can validate"
	exit $EXIT_FAILURE
    fi

    if [ "${targetOpt}" = "app" ]; then
	CMD="com.sun.web.util.AppXmlChecker"
	CHKFILE=""
    else
	CMD="com.sun.web.util.WebXmlChecker"
	CHKFILE="${CONSOLE_HOME}/extra/system/app_checkfile"
	if [ "${hiddenFile}" != "" ]; then
	    CHKFILE="${CONSOLE_HOME}/extra/system/${hiddenFile}"
	    $ECHO "Using alternate checkfile: ${CHKFILE}"
	fi
    fi

    CLASSPATH=${CONSOLE_HOME}/lib/consoleutil.jar:${CONSOLE_HOME}/lib/serviceapi.jar:${CONSOLE_HOME}/lib/serviceimpl.jar
    $JAVA -classpath ${CLASSPATH} \
	-D"com.sun.web.console.home=${CONSOLE_HOME}" \
	-D"webconsole.default.file=${DEFAULT_FILE}" \
	-D"webconsole.config.file=${CONFIG_FILE}" \
	${CMD} validate ${targetPath} ${CHKFILE}

    errcode=$?
    stat=$EXIT_SUCCESS
    if [ ${errcode} -eq 1 ]; then
	$ECHO "One or more warning errors occurred."
    fi
    if [ ${errcode} -eq 2 ]; then
	$ECHO "One or more serious errors occurred."
	stat=$EXIT_FAILURE
    fi

    if [ $stat -eq $EXIT_SUCCESS ]; then
	$ECHO "$targetPath has successfully validated."
    fi

    exit ${stat}

} ## validate

################################################################################
#
# prodname
#
# Handler for the "prodname" subcommand.
#
# Syntax: prodname -t type {-n name} -d outpath [-r resource]
#                          {-a path}
#
# Call the Java program for generating the product images.
# The program will validate the arguments.
#
################################################################################

prodname() {
    
    tflag=0
    nflag=0
    dflag=0
    rflag=0
    aflag=0
    type=""
    odir=""
    resfile=""
    name=""
    xdir=""

    # find Java
    findJava

    # 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/prodname.$$
    rm -f $errCatch >/dev/null 2>&1
    while getopts "t:n:a:d:r:h" c > $errCatch 2>&1; do
	case $c in
	    "t") tflag=1; type="${OPTARG}";;
	    "n") nflag=1; name="${OPTARG}";;
	    "a") aflag=1; xdir="${OPTARG}";;
	    "d") dflag=1; odir="${OPTARG}";;
	    "r") rflag=1; resfile="${OPTARG}";;
	    "h") prodname_Usage $EXIT_SUCCESS;;
	    \?)  msg=`sed -e "s@prodname@${PROGNAME} prodname@" $errCatch`
		 rm -f $errCatch
		 prodname_Usage $EXIT_USAGE "$msg" 1>&2
		 ;;
	esac
    done
    shift `expr $OPTIND - 1`
    rm -f $errCatch >/dev/null 2>&1

    if [ "${tflag}" = "0" -o "${type}" = "" ]; then
	printf "Type argument must be specified\n"
	exit $EXIT_FAILURE
    fi
    if [ "${nflag}" = "0" -a "${aflag}" = "0" ]; then
	printf "Name or xml path argument must be specified\n"
	exit $EXIT_FAILURE
    fi
    if [ "${dflag}" = "0" -o "${odir}" = "" ]; then
	printf "Output directory argument must be specified\n"
	exit $EXIT_FAILURE
    fi
    if [ "${nflag}" = "1" -a "${aflag}" = "1" ]; then
	printf "Cannot specify both name and xml path arguments\n"
	exit $EXIT_FAILURE
    fi

    if [ "${nflag}" = "1" -a "${name}" = "" ]; then
	printf "Name value must be specified\n"
	exit $EXIT_FAILURE
    fi
    if [ "${aflag}" = "1" -a "${xdir}" = "" ]; then
	printf "Xml file path must be specified\n"
	exit $EXIT_FAILURE
    fi

    # Process arguments for Java command
    if [ "${aflag}" = "1" ]; then
	optn="xml"
	src2=`$ECHO ${xdir} | sed -e "s@$WS_PATTERN@ @g"`
	if [ -d "${src2}" ]; then
	    temp=`basename ${src2}`
	    if [ "${temp}" != "WEB-INF" ]; then
		src2="${src2}/WEB-INF"
	    fi
	    src2="${src2}/app.xml"
	fi
    fi
    if [ "${nflag}" = "1" ]; then
	optn="name"
	src2=`$ECHO ${name} | sed -e "s@$WS_PATTERN@ @g"`
    fi

    CMD=com.sun.web.util.ProductImageUtility
    CLASSPATH=${CONSOLE_HOME}/lib/consoleutil.jar:${CONSOLE_HOME}/lib/serviceapi.jar:${CONSOLE_HOME}/lib/serviceimpl.jar

    $JAVA -classpath ${CLASSPATH} -D"java.awt.headless=true" \
	-D"com.sun.web.console.home=${CONSOLE_HOME}" \
	${CMD} ${optn} ${type} "${src2}" ${odir} ${resfile}

    errcode=$?
    exit ${errcode}

} ## prodname

################################################################################
#
# Main command processing
#
################################################################################

# This section is NOT a function so that quoted arguments come through
# as a single argument value.

    SUB_COMMAND=$1
    case "$SUB_COMMAND" in

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

    "$VERSION_FLAG_SHORT" | "$VERSION_FLAG_LONG")
	webappVersion
	;;

    "$IMPORT_CMD")
	shift 1
	args=`$ECHO $* | sed \
	    -e "s/${HELP_FLAG_SHORT2}/${HELP_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_LONG}/${HELP_FLAG_SHORT}/"`
	import $args
	;;

    "$VALIDATE_CMD")
	shift 1
	args=`$ECHO $* | sed \
	    -e "s/${HELP_FLAG_SHORT2}/${HELP_FLAG_SHORT}/" \
	    -e "s/${HELP_FLAG_LONG}/${HELP_FLAG_SHORT}/" \
	    -e "s/${APPXML_FLAG_LONG}/${APPXML_FLAG_SHORT}/" \
	    -e "s/${WEBXML_FLAG_LONG}/${WEBXML_FLAG_SHORT}/"`
	validate $args
	;;

    "$PRODNAME_CMD")
	shift 1
	args=""
	while [ $# -gt 0 ]; do
	    # Prepend a character to avoid echo options, then cut if off.
	    # Required for Linux, which has option arguments for echo.
	    # Enclose argument in quotes to preserve whitespace in names.
	    tmp=`$ECHO "x$1" | cut -c2- | sed \
	    -e "s@ @$WS_PATTERN@g" \
	    -e "s@${HELP_FLAG_SHORT2}@${HELP_FLAG_SHORT}@" \
	    -e "s@${HELP_FLAG_LONG}@${HELP_FLAG_SHORT}@" \
	    -e "s@${PRODTYPE_FLAG_LONG}@${PRODTYPE_FLAG_SHORT}@" \
	    -e "s@${APPXML_FLAG_LONG}@${APPXML_FLAG_SHORT}@" \
	    -e "s@${PRODDIR_FLAG_LONG}@${PRODDIR_FLAG_SHORT}@" \
	    -e "s@${PRODNAME_FLAG_LONG}@${PRODNAME_FLAG_SHORT}@" \
	    -e "s@${PRODRES_FLAG_LONG}@${PRODRES_FLAG_SHORT}@"`
	    args="${args} ${tmp}"
	    shift 1
	done
	prodname $args
	;;

    *)
	webappUsage $EXIT_USAGE 1>&2
	;;

    esac

    exit $EXIT_SUCCESS

##  DO NOT ADD ANY CODE BELOW HERE!!
