#!/bin/bash
#
#  Script to invoke XSLT program that transforms the output from dCache's
#  info service into LDIF.  This conversion process is achieved using
#  Xylophone and is controlled by a configuration file.  The xylophone
#  config file is built from files in
#
#      /opt/d-cache/share/info-provider
#
#  and the site-specific configuration in
#
#      /opt/d-cache/etc/info-provider.xml


#  Apply sanity checks before launching the XSLT processor
sanityCheck()
{
    local dcacheConfFile

    dcacheConfFile="$(getProperty dcache.paths.etc)/dcache.conf"

    case $(getProperty info-provider.publish) in
	1.3 | 2.0 | both)
	    ;;
	*)
            printp "[ERROR] Value of info-provider.publish in wrong.  Allowed
                    values are '1.3', '2.0' or 'both'.  The current value is
                    \"$publish\""
            exit 1
	;;
    esac

    if [ ! -r "$xylophoneXMLFile" ]; then
        printp "[ERROR] Unable to read $xylophoneXMLFile. Try creating this
                file or adjusting the info-provider.configuration.dir property
                (currently \"$xylophoneConfigurationDir\") or
                info-provider.configuration.file (currently
                \"$xylophoneConfigurationFile\") in $dcacheConfFile"
        exit 1
    fi

    if [ ! -r "$xylophoneXSLTFile" ]; then
        printp "[ERROR] Unable to read $xylophoneXSLTFile.  If the file exists
                try editing the property info-provider.xylophone.dir
                (currently \"$xylophoneXSLTDir\") in $dcacheConfFile"
        exit 1
    fi
}


#  Build a temporary XML file containing entity definitions for
#  dCache's current configuration.  These entities are provided for
#  the XML data via an XML catalogue file that this function also
#  builds.
buildEntitiesFile() # in $1 entity file, $2 catalogue file.
{
    DCACHE_LOG=error bootLoader -q compile -xml > "$1"

    cat > "$2" <<EOF
<?xml version="1.0"?>
<!DOCTYPE catalog PUBLIC "-//OASIS//DTD Entity Resolution XML Catalog V1.0//EN"
                         "http://www.oasis-open.org/committees/entity/release/1.0/catalog.dtd">
<catalog xmlns="urn:oasis:names:tc:entity:xmlns:xml:catalog">
    <public publicId="-//dCache//ENTITIES dCache Properties//EN"
            uri="file://$1"/>
</catalog>
EOF
}

# Load libraries

getCanonicalPath() # $1 = path                              
{                                                           
local link                                              
link="$1"                                               
if readlink -f . > /dev/null 2>&1; then                 
RET="$(readlink -f $link)"                          
else                                                    
RET="$(cd $(dirname $link); pwd)/$(basename $link)" 
while [ -h "$RET" ]; do                             
link="$(ls -ld $RET | sed 's/.*-> //')"         
if [ -z "${link##/*}" ]; then                   
RET="${link}"                               
else                                            
link="$(dirname $RET)/${link}"              
RET="$(cd $(dirname $link); pwd)/$(basename $link)" 
fi                                              
done                                                
fi                                                      
}                                                           

[ -f /etc/default/dcache ] && . /etc/default/dcache         
[ -f /etc/dcache.env ] && . /etc/dcache.env                 

if [ -z "$DCACHE_HOME" ]; then                              
getCanonicalPath "$0"                                     
DCACHE_HOME="${RET%/*/*}"                                 
fi                                                          
if [ ! -d "$DCACHE_HOME" ]; then                            
echo "$DCACHE_HOME is not a directory"                    
exit 2                                                    
fi                                                          

DCACHE_CLASSPATH=${DCACHE_HOME}/share/classes/*             
DCACHE_DEFAULTS=${DCACHE_HOME}/share/defaults               
DCACHE_CACHED_CONFIG=${DCACHE_HOME}/var/config/cache        
. ${DCACHE_HOME}/share/lib/loadConfig.sh
. "$(getProperty dcache.paths.share.lib)/utils.sh"


xsltProcessor="$(getProperty info-provider.processor)"
xylophoneXMLFile="$(getProperty info-provider.configuration.location)"
host="$(getProperty info-provider.http.host)"
port="$(getProperty httpdPort)"
xylophoneXSLTDir="$(getProperty info-provider.xylophone.dir)"
saxonDir="$(getProperty info-provider.saxon.dir)"

#  Apply any environment overrides
if [ -n "$XSLT_PROCESSOR" ]; then
    xsltProcessor=$XSLT_PROCESSOR
fi

if [ -n "$HTTP_HOST" ]; then
    httpHost=$HTTP_HOST
fi

if [ -n "$HTTP_PORT" ]; then
    httpPort=$HTTP_PORT
fi


#  Build derived variables after allowing changes from default values
xylophoneXSLTFile="$xylophoneXSLTDir/xsl/xylophone.xsl"
uri="http://${host}:${port}/info"

sanityCheck

entities=$(mktemp)
catalog=$(mktemp)
buildEntitiesFile "$entities" "$catalog"

#  Generate LDIF
case $xsltProcessor in
  xsltproc)
        export XML_CATALOG_FILES="$catalog"
        xsltproc --xinclude --stringparam xml-src-uri "$uri" \
            "$xylophoneXSLTFile" "$xylophoneXMLFile"
        ;;

  saxon)
        #  Unfortunately, xerces (the XML parser in Java) doesn't support xpointer() scheme
        #  for the xpointer attribute in an xinclude statement.  The xpointer() scheme is
        #  needed to include subtrees.  This scheme is supported by xmllint and xsltproc
        #  but xerces project has no plans to implement support.  So we must preprocess
        #  the XML file using xmllint to process the xinclude statements and store the
        #  results in a temporary file.
        #
        #  The call to xmllint "pulls in" the dCache configuration
        #  entity definitions so the resulting file contains the
        #  XInclude material and the dCache configuration entities.
        #
        #  After the dCache configuration entities have been included,
        #  the "dCache-config" entity (which is the contents of the
        #  file containing the dCache configuration) is no longer
        #  needed.  Rather than adding support for catalogues, we
        #  simply filter out this entity definition line.
        #
        t=$(mktemp)
        export XML_CATALOG_FILES="$catalog"
        xmllint --xinclude $xylophoneXMLFile | grep -v dCache-config > $t
	"${JAVA}" -classpath "${saxonDir}/*" \
            com.icl.saxon.StyleSheet $t  \
	    "$xylophoneXSLTFile" xml-src-uri="$uri"
        rm $t
	;;

  *)
	printp "[ERROR] Unknown value of info-provider.processor (\"$xsltProcessor\")"
	printp "info-provider.processor must be either 'xsltproc' or 'saxon'" >&2
	exit 1
	;;
esac

rm -f $entities $catalog
