##@cooked comments # -*- coding: utf-8 mode: sh -*- vim:sw=4:sts=4:et:ai:si:sta:fenc=utf-8
## Gestion des services de webobjects (démarrage/arrêt), et de leur configuration
##@cooked nocomments
##@require base
##@require sysinfos
##@require javaproperties
uprovide webobjects
urequire base sysinfos javaproperties

################################################################################
# Préfixes

__webobjects_prefixes=
function __compute_webobjects_prefixes() {
    [ -n "$__webobjects_prefixes" ] && return
    if check_sysinfos -s darwin; then
        # valeurs par défaut de NEXT_ROOT, WOROOT et LOCALROOT sur MacOS X
        DEFAULT_NEXT_ROOT=
        function get_default_woroot_prefix() { echo "$NEXT_ROOT/System"; }
        function get_default_localroot_prefix() { echo "$NEXT_ROOT"; }
    else
        # valeurs par défaut de NEXT_ROOT, WOROOT et LOCALROOT sur les autres Unix
        DEFAULT_NEXT_ROOT=/opt/Apple
        function get_default_woroot_prefix() { echo "$NEXT_ROOT"; }
        function get_default_localroot_prefix() { echo "$NEXT_ROOT/Local"; }
    fi
    
    NEXT_ROOT="${NEXT_ROOT:-$DEFAULT_NEXT_ROOT}"
    WOROOT="${WOROOT:-$(get_default_woroot_prefix)}"
    LOCALROOT="${LOCALROOT:-$(get_default_localroot_prefix)}"
    SYSTEMFRAMEWORKS="$WOROOT/Library/Frameworks"
    WOEXTENSIONS="$LOCALROOT/Library/WebObjects/Extensions"
    WOFRAMEWORKS="$LOCALROOT/Library/WebObjects/Applications/Frameworks"
    WOAPPLICATIONS="$LOCALROOT/Library/WebObjects/Applications"
    WOCONFIGURATION="$LOCALROOT/Library/WebObjects/Configuration"
    WOAUTOSTART="$WOCONFIGURATION/AutoStart.txt"
    WOLOGS="/var/log/WebObjects"
    local versionfile="$SYSTEMFRAMEWORKS/JavaWebObjects.framework/Resources/version.plist"
    [ -f "$versionfile" ] && WOVERSION="$(grep -A 1 CFBundleShortVersionString "$versionfile" | tail -1 | sed 's/^.*<string>\(.*\)<\/string>.*$/\1/')" || WOVERSION=
    __webobjects_prefixes=1
}

UTOOLS_PREFIXES=("${UTOOLS_PREFIXES[@]}" NEXT_ROOT WOROOT LOCALROOT SYSTEMFRAMEWORKS WOEXTENSIONS WOFRAMEWORKS WOAPPLICATIONS WOCONFIGURATION WOAUTOSTART WOLOGS WOVERSION)

function compute_webobjects_prefixes() {
    __compute_webobjects_prefixes
}

function recompute_webobjects_prefixes() {
    __webobjects_prefixes=
    __compute_webobjects_prefixes
}

function get_NEXT_ROOT_prefix() {
    __compute_webobjects_prefixes
    echo "$NEXT_ROOT"
}
function get_WOROOT_prefix() {
    __compute_webobjects_prefixes
    echo "$WOROOT"
}
function get_LOCALROOT_prefix() {
    __compute_webobjects_prefixes
    echo "$LOCALROOT"
}
function get_SYSTEMFRAMEWORKS_prefix() {
    __compute_webobjects_prefixes
    echo "$SYSTEMFRAMEWORKS"
}
function get_WOEXTENSIONS_prefix() {
    __compute_webobjects_prefixes
    echo "$WOEXTENSIONS"
}
function get_WOFRAMEWORKS_prefix() {
    __compute_webobjects_prefixes
    echo "$WOFRAMEWORKS"
}
function get_WOAPPLICATIONS_prefix() {
    __compute_webobjects_prefixes
    echo "$WOAPPLICATIONS"
}
function get_WOCONFIGURATION_prefix() {
    __compute_webobjects_prefixes
    echo "$WOCONFIGURATION"
}
function get_WOAUTOSTART_prefix() {
    __compute_webobjects_prefixes
    echo "$WOAUTOSTART"
}
function get_WOLOGS_prefix() {
    __compute_webobjects_prefixes
    echo "$WOLOGS"
}
function get_WOVERSION_prefix() {
    __compute_webobjects_prefixes
    echo "$WOVERSION"
}

################################################################################
# Bundles

function is_wobundle() {
    # Tester si $1 a un nom de bundle valide, c'est à dire avec l'extension .woa
    # ou .framework
    local bundle="$(basename "$(abspath "$1")")"
    [ "${bundle%.woa}" != "$bundle" -o "${bundle%.framework}" != "$bundle" ]
}

function is_woappdir() {
    # Tester si $1 est un répertoire d'application webobjects. Le test est
    # effectué sur le contenu du bundle, pas sur le nom (utiliser is_wobundle()
    # pour cela)

    # existence du répertoire
    [ -d "$1" ] || return 1
    # répertoires de resources
    [ -d "$1/Contents/Resources" ] || return 1
    # répertoires de classpath
    [ -d "$1/Contents/UNIX" ] || return 1
    [ -d "$1/Contents/MacOS" ] || return 1
    [ -d "$1/Contents/Windows" ] || return 1
    # fin des tests
    return 0
}

function is_wofwkdir() {
    # Tester si $1 est un répertoire de framework webobjects. Le test est
    # effectué sur le contenu du bundle, pas sur le nom (utiliser is_wobundle()
    # pour cela)
    
    # existence du répertoire
    [ -d "$1" ] || return 1
    # répertoires de resource
    [ -d "$1/Resources" -o -d "$1/WebServerResources" ] || return 1
    # fin des tests
    return 0
}

function get_app_winclspth() {
    # calculer la valeur de Contents/Windows/CLSSPATH.txt pour l'application $1
    local found
    if [ ! -f "$1/Contents/Windows/CLSSPATH.txt" ]; then
        local clspth
        array_from_lines clspth "$(list_files "$1/Contents/Windows" | grep -i clsspath.txt)"
        if [ ${#clspth[*]} -eq 1 ]; then
            echo "Contents/Windows/$clspth"
            found=1
        fi
    fi
    # pas trouvé, prendre la valeur par défaut
    [ -n "$found" ] || echo Contents/Windows/CLSSPATH.txt
}

function get_infofile() {
    # Obtenir le chemin vers le fichier Info.plist dans le répertoire de
    # resource du bundle $1
    local bundle="$(abspath "$1")" resdir
    if endswith "$bundle" .woa; then
        resdir="$bundle/Contents"
    elif endswith "$bundle" .framework; then
        resdir="$bundle/Resources"
    else
        # on a donné directement resdir
        resdir="$bundle"
    fi
    echo "$resdir/Info.plist"
}

function read_infofile() {
    # Lire la version et le numéro de release dans le fichier $1 (chemin vers
    # Info.plist) et les placer dans les variables $2(=version) et $3(=release)
    # Retourner 1 si un erreur s'est produite, par exemple si le fichier $1
    # n'existe pas ou n'est pas accessible en lecture
    [ -f "$1" -a -r "$1" ] || return 1
    set_var "${2:-version}" "$(grep -A 1 CFBundleShortVersionString "$1" | tail -1 | sed 's/^.*<string>\(.*\)<\/string>.*$/\1/')"
    set_var "${3:-release}" "$(grep -A 1 CFBundleVersion "$1" | tail -1 | sed 's/^.*<string>\(.*\)<\/string>.*$/\1/')"
}

function write_infofile() {
    # Ecrire $2 (la version) et $3 (le numéro de release) dans le fichier $1
    # (chemin vers Info.plist)
    # Retourner 1 si un erreur s'est produite, par exemple si le fichier $1
    # n'existe pas
    local status tmpfile
    ac_set_tmpfile tmpfile
    <"$1" >"$tmpfile" cawkrun version="$2" release="$3" '
      /<key>CFBundleShortVersionString<\/key>/ {
        print; getline
        sub(/<string>.*<\/string>/, "<string>" version "</string>")
        print; next
      }
      /<key>CFBundleVersion<\/key>/ {
        print; getline
        sub(/<string>.*<\/string>/, "<string>" release "</string>")
        print; next
      }
      { print }
    ' && cat "$tmpfile" >"$1"
    status=$?
    ac_clean "$tmpfile"
    return $status
}

function get_jawotoolsfile() {
    # Obtenir le chemin vers le fichier jawotools.properties dans le bundle $1
    local default="$1/jawotools.properties" file
    for file in "$default" "$1/build_infos.txt"; do
        if [ -f "$file" ]; then
            echo "$file"
            return
        fi
    done
    echo "$default"
}

function read_jawotoolsfile() {
    # lire le fichier de propriété $1 et placer les valeurs dans les variables
    # $2(=version), $3(=releaseDate), $4(=description)
    local filename="$(basename "$1")"
    if [ "$filename" == "build_infos.txt" ]; then
        # legacy
        read_property "$1" version "${2:-version}"
        read_property "$1" date "${3:-releaseDate}"
        read_property "$1" desc "${4:-description}"
    else
        read_property "$1" version "${2:-version}"
        read_property "$1" releaseDate "${3:-releaseDate}"
        read_property "$1" description "${4:-description}"
    fi
}

function save_jawotoolsfile() {
    # écrire le fichier de propriété $1 avec les valeurs version ($2),
    # releaseDate ($3) et description ($4)
    [ -e "$1" ] || touch "$1"
    write_property "$1" version "$2"
    write_property "$1" releaseDate "$3"
    write_property "$1" description "$4"
}

function get_versionfile() {
    # Obtenir le chemin vers le fichier VERSION.txt dans le répertoire de
    # resource du bundle $1
    local bundle="$(abspath "$1")" resdir
    if endswith "$bundle" .woa; then
        resdir="$bundle/Contents/Resources"
    elif endswith "$bundle" .framework; then
        resdir="$bundle/Resources"
    else
        # on a donné directement resdir
        resdir="$bundle"
    fi
    local default="$resdir/VERSION.txt" file
    for file in "$default" "$1/version.txt"; do
        if [ -f "$file" ]; then
            echo "$file"
            return
        fi
    done
    echo "$default"
}

function get_configfile() {
    # obtenir le chemin vers le fichier de configuration du répertoire de
    # resource du bundle
    # $1=bundle ou resdir (appdir/Contents/Resources ou fwkdir/Resources)
    local bundle="$(abspath "$1")" resdir
    if endswith "$bundle" .woa; then
        resdir="$bundle/Contents/Resources"
    elif endswith "$bundle" .framework; then
        resdir="$bundle/Resources"
    else
        # on a donné directement resdir
        resdir="$bundle"
    fi
    local configs
    array_lsfiles configs "$resdir" "*.config"
    if [ ${#configs[*]} -eq 0 ]; then
        array_lsfiles configs "$resdir" "config.xml"
    fi
    echo "${configs:-$resdir/Properties}"
}

function searchreplace_classpath() {
    # Dans les fichiers classpath de l'application $1, remplacer $2 par $3. Si
    # $3 est vide, la ligne est supprimée
    local bundle="$1" search="$2" replace="$3" scriptunx scriptwin clspth

    [ -n "$search" ] || return 1
    search="${search//\//\\/}"; replace="${replace//\//\\/}"
    if [ -n "$replace" ]; then
        scriptunx="s/${search}/${replace}/g"
    else
        scriptunx="/${search}/d"
    fi
    search="${search//\\\//\\\\}"; replace="${replace//\\\//\\\\}"
    if [ -n "$replace" ]; then
        scriptwin="s/${search}/${replace}/g"
    else
        scriptwin="/${search}/d"
    fi

    clspth="$bundle/Contents/UNIX/UNIXClassPath.txt"
    nl2lf "$clspth"; sedi "$scriptunx" "$clspth"
    clspth="$bundle/Contents/MacOS/MacOSClassPath.txt"
    nl2lf "$clspth"; sedi "$scriptunx" "$clspth"
    clspth="$bundle/$(get_app_winclspth "$bundle")"
    nl2lf "$clspth"; sedi "$scriptwin" "$clspth"; nl2crlf "$clspth"
}

function dump_jars() {
    # Afficher les jars des frameworks utilisés par l'application $1
    local clspth
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        clspth="Contents/MacOS/MacOSClassPath.txt"
    else
        clspth="Contents/UNIX/UNIXClassPath.txt"
    fi
    cat "$1/$clspth" | _nl2lf | grep '\.framework' | grep -v "^#" | grep -v "APPROOT/" | grep -v "WOROOT/" | awk '{
      if (match($0, /[^\/]*\.framework/) != 0) {
        print
      }
    }' | sort -u
}

function dump_frameworks() {
    # Afficher les frameworks utilisés par l'application $1
    dump_jars "$1" | awk '{
      if (match($0, /[^\/]*\.framework/) != 0) {
        print substr($0, RSTART, RLENGTH)
      }
    }'
}

function remove_framework() {
    # supprimer le framework $2 (nom de base) des fichiers de classpath du
    # bundle d'application $1
    local bundle="$1" framework="$2" frameworks

    endswith "$framework" .framework || framework="$framework.framework"
    array_from_lines frameworks "$(dump_frameworks "$bundle")"
    if array_contains frameworks "$framework"; then
        searchreplace_classpath "$bundle" "^LOCALROOT/.*/$framework/"
    fi
}

function add_framework() {
    # s'il n'y existe pas déjà, ajouter le framework $2 (nom de base ou chemin
    # absolu) aux fichiers de classpath du bundle d'application $1
    local bundle="$1" framework="$2" frameworks jars jar line
    local winclspth="$(get_app_winclspth "$bundle")"

    endswith "$framework" .framework || framework="$framework.framework"
    array_from_lines frameworks "$(dump_frameworks "$bundle")"
    if ! array_contains frameworks "$framework"; then
        if beginswith "$framework" /; then
            # on a donné un chemin absolu
            array_lsfiles jars "$framework/Resources/Java" "*.jar"
            if [ -z "${jars[*]}" ]; then
                eerror "Impossible de trouver les fichiers du framework $framework
dans $WOFRAMEWORKS"
                return 1
            else
                for jar in "${jars[@]}"; do
                    echo "$jar" >>"$bundle/Contents/UNIX/UNIXClassPath.txt"
                    echo "$jar" >>"$bundle/Contents/MacOS/MacOSClassPath.txt"
                    echo "${jar//\//\\}" >>"$bundle/$winclspth"
                done
            fi
        else
            # on a donné juste le nom du framework
            array_from_lines jars "$(list_files "$WOFRAMEWORKS/$framework/Resources/Java" "*.jar")"
            if [ -z "${jars[*]}" ]; then
                eerror "Impossible de trouver les fichiers du framework $framework
dans $WOFRAMEWORKS"
                return 1
            else
                for jar in "${jars[@]}"; do
                    line="LOCALROOT/Library/WebObjects/Applications/Frameworks/$framework/Resources/Java/$jar"
                    echo "$line" >>"$bundle/Contents/UNIX/UNIXClassPath.txt"
                    echo "$line" >>"$bundle/Contents/MacOS/MacOSClassPath.txt"
                    echo "${line//\//\\}" >>"$bundle/$winclspth"
                done
            fi
        fi
    fi
}

function fix_jars_case() {
    # Vérifier que la casse des jars de tous les frameworks utilisés par
    # l'application $1 est conforme au système de fichier
    local bundle="$1" clspth jars jar fwkdir fwkname jarname jarnamefs
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        clspth="Contents/MacOS/MacOSClassPath.txt"
    else
        clspth="Contents/UNIX/UNIXClassPath.txt"
    fi
    array_from_lines jars "$(dump_jars "$bundle")"
    for jar in "${jars[@]}"; do
        { endswith "$jar" .jar || endswith "$jar" .zip; } || continue

        if beginswith "$jar" LOCALROOT; then
            fwkname="${jar##*/Frameworks/}"; fwkname="${fwkname%%/*}"
            fwkdir="$WOFRAMEWORKS"
        else
            fwkdir="${jar%/*.framework/*}"
            fwkname="${jar##/*.framework/}";
            fwkname="${jar:0:$((${#jar}-${#fwkname}-1))}"; fwkname="${fwkname##*/}"
        fi
        jarname="${jar##*/}"

        if [ ! -d "$fwkdir/$fwkname" ]; then
            eerror "$(basename "$bundle"): $fwkname: ce framework n'existe pas"
            continue
        fi

        array_from_lines jarnamefs "$(list_files "$fwkdir/$fwkname/Resources/Java" "*.jar" | grep -i "^$jarname")"
        if [ ${#jarnamefs[*]} -eq 0 ]; then
            eerror "$(basename "$bundle"): $fwkname: $jarname n'existe pas"
        elif [ ${#jarnamefs[*]} -gt 1 ]; then
            eerror "$(basename "$bundle"): $fwkname: il existe plusieurs jars $jarname"
        else
            if [ "$jarname" != "$jarnamefs" ]; then
                einfo "$(basename "$bundle"): $fwkname: $jarnamefs"
                searchreplace_classpath "$bundle" "$fwkname/Resources/Java/$jarname" "$fwkname/Resources/Java/$jarnamefs"
            fi
        fi
    done
}

function verifix_bundle() {
    # vérifier et corriger le bundle $1. Pour une application, on vérifie que le
    # script est exécutable. Pour un framework, on vérifie que le framework est
    # conforme au modèle des framework générés par WebObjects.
    local bundle="$1"
    if is_woappdir "$bundle"; then
        local script="$bundle/$(basename "$bundle" .woa)"
        if [ ! -x "$script" ]; then
            chmod +x "$script"
        fi

    elif is_wofwkdir "$bundle"; then
        [ -L "$bundle/Resources" ] && return

        local filename

        if [ ! -L "$bundle/Resources" ]; then
            rm -rf "$bundle/Versions/A/Resources"
            cpdir "$bundle/Resources" "$bundle/Versions/A/Resources"
            rm -rf "$bundle/Resources"
        fi
        if [ ! -L "$bundle/WebServerResource" ]; then
            rm -rf "$bundle/Versions/A/WebServerResources"
            cpdir "$bundle/WebServerResources" "$bundle/Versions/A/WebServerResources"
            rm -rf "$bundle/WebServerResources"
        fi
        local cwd="$(pwd)"
        cd "$bundle/Versions"
        if [ -e Current ]; then
            if [ ! -L Current -a -d Current ]; then
                rm -rf Current
            else
                rm -f Current
            fi
        fi
        ln -s A Current
        cd ..
        ln -s Versions/Current/Resources Resources
        ln -s Versions/Current/WebServerResources WebServerResources
        cd "$cwd"
    fi
}

function compute_fapps() {
    # Placer dans le tableau $1(=fappnames) la liste des noms de bundle
    # d'applications qui dépendent du framework $2
    # Cette opération est faite à partir des informations sur le système de
    # fichier. Elle ne peut donc concerner qu'une installation locale.
    local -a __cf_fappnames
    local __cf_fwknames __cf_fwkname __cf_appnames __cf_appname

    __cf_fwkname="$2"
    [ "${__cf_fwkname%.framework}" != "$__cf_fwkname" ] || __cf_fwkname="$__cf_fwkname.framework"
    __cf_fwkname="$(basename "$__cf_fwkname")"

    array_from_lines __cf_appnames "$(list_dirs "$WOAPPLICATIONS" "*.woa")"
    for __cf_appname in "${__cf_appnames[@]}"; do
        array_from_lines __cf_fwknames "$(dump_frameworks "$WOAPPLICATIONS/$__cf_appname")"
        if array_contains __cf_fwknames "$__cf_fwkname"; then
            array_set __cf_fappnames "$__cf_appname"
        fi
    done
    array_copy "${1:-fappnames}" __cf_fappnames
}

################################################################################
# Applications et instances

WORAURL_USE_PROXY= # faut-il passer par un proxy?
WORAURL_DATA=
function woraurl() {
    # Faire une requête avec la méthode $1 sur l'url $2 avec le payload $3 (par
    # exemple pour la méthode POST). la réponse est disponible dans le fichier
    # $WORAURL_DATA, $4(=http_code) contient le code de réponse.
    # Retourner 0 en cas de succès, ou une valeur différente de zéro si un
    # erreur se produit (typiquement, 3 pour une erreur du serveur, 1 pour une
    # réponse applicative, comme par exemple si l'application n'existe pas)
    # Les codes de réponse 2xx et 417 sont des succès
    # Les autres codes (à priori 4xx ou 5xx) sont des erreurs
    # note: le code 417 est utilisé par le moniteur pour répondre "Non", par
    # opposition à 200 utilisé pour répondre "OUI"
    local _status _http_code _args
    [ -n "$WORAURL_DATA" ] || ac_set_tmpfile WORAURL_DATA
    _args=(-s -X "${1:-GET}" ${3:+-d "$3"} -w '%{http_code}' -o "$WORAURL_DATA")
    [ -z "$WORAURL_USE_PROXY" ] && _args=("${_args[@]}" -x "")
    _http_code="$(curl "${_args[@]}" "$2")"
    case "$_http_code" in
    2*|417) _status=0;;
    4*) _status=1;;
    5*) _status=3;;
    *) _status=11;;
    esac
    set_var "${4:-http_code}" "$_http_code"
    return $_status
}
function wogeturl() { woraurl GET "$@"; }

function splitins() {
    # Analyser le nom $1, qui peut être de forme '', 'Name.woa',
    # 'Name.framework', 'App' ou 'Instance-N' (où N est un nombre), et
    # initialiser les variables $2(=type) et $3(=name)
    # Si $1=="", type=all et name=""
    # Si $1==Name.woa, type=woa et name=Name.woa
    # Si $1==Name.framework, type=fwk et name=Name.framework
    # Si $1==App, type=app et name=App
    # si $1==App-N, type=ins et name=App-N
    if [ -z "$1" ]; then
        set_var "${2:-type}" all
        set_var "${3:-name}"
    elif [ "${1%.woa}" != "$1" ]; then
        set_var "${2:-type}" woa
        set_var "${3:-name}" "$1"
    elif [ "${1%.framework}" != "$1" ]; then
        set_var "${2:-type}" fwk
        set_var "${3:-name}" "$1"
    elif [[ "$1" == *-* ]]; then
        local __si_name __si_num
        __si_name="${1%-*}"
        __si_num="${1##*-}"
        if [ -z "${__si_num//[0-9]/}" ]; then
            set_var "${2:-type}" ins
            set_var "${3:-name}" "$1"
        else
            set_var "${2:-type}" app
            set_var "${3:-name}" "$1"
        fi
    elif [ -n "$1" ]; then
        set_var "${2:-type}" app
        set_var "${3:-name}" "$1"
    fi        
}

################################################################################
# Environnement

function create_wodirs_maybe() {
    mkdir -p "$WOAPPLICATIONS"
    mkdir -p "$WOFRAMEWORKS"
}

function check_autostart() {
    # vérifier la présence du fichier $WOAUTOSTART. Si ce n'est pas le cas, le
    # créer avec le contenu du tableau $1
    if [ ! -f "$WOAUTOSTART" -a -n "$1" ]; then
        array_to_lines "$1" | csort >"$WOAUTOSTART" || return 1
        enote "Le fichier $(ppath "$WOAUTOSTART") a été créé avec la liste suivante:
$(<"$WOAUTOSTART")"
    fi
}

function get_autostart_order() {
    # Initialiser le tableau $1 avec la liste donnée dans le fichier
    # $WOAUTOSTART
    array_from_lines "$1" "$(<"$WOAUTOSTART" filter_comment)"
}

function apply_autostart_order() {
    # Réordonner les valeurs $3..* selon la liste donnée dans le tableau $2,
    # puis placer le résultat dans le tableau $1. $2 doit être construit avec
    # get_autostart_order(). Si $2 n'est pas spécifié, la liste est construite
    # localement.
    # Si le tableau contient des lignes de délai @N, replacer les délais après
    # les applications appropriées
    local __aa_reverse
    if [ "$1" == "-r" ]; then
        __aa_reverse=1
        shift
    fi
    local -a __aa_oapps __aa_src
    local __aa_dest="$1" __aa_oapp; shift
    local __found
    if [ -n "$1" ]; then
        array_copy __aa_oapps "$1"
    else
        get_autostart_order __aa_oapps
    fi
    shift
    set_array __aa_src @ "$@"
    array_new "$__aa_dest"
    for __aa_oapp in "${__aa_oapps[@]}"; do
        if [[ "$__aa_oapp" == @* ]]; then
            # Si on trouve une ligne @N, et que la précédente ligne a été
            # sélectionnée, alors inclure le délai aussi dans la liste des
            # valeurs à prendre en compte
            [ -n "$__aa_found" ] && array_add "$__aa_dest" "$__aa_oapp"
            __aa_found=
        elif array_contains __aa_src "$__aa_oapp"; then
            array_add "$__aa_dest" "$__aa_oapp"
            array_del __aa_src "$__aa_oapp"
            __aa_found=1
        else
            __aa_found=
        fi
    done
    array_extend "$__aa_dest" __aa_src
    [ -n "$__aa_reverse" ] && array_reverse "$__aa_dest"
}

function __unix_woservices() {
    if [ -x /etc/init.d/WOServices ]; then
        /etc/init.d/WOServices "$@"
    else
        eerror "Ce script ne sait pas piloter wotaskd/javamonitor sur cette plateforme"
        return 1
    fi
}

SERVICE_OVERRIDE_wotaskd_stop=wotaskd_stop
function wotaskd_stop() {
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        launchctl unload /System/Library/LaunchDaemons/com.apple.wotaskd.plist
    else
        __unix_woservices stop
    fi
}

SERVICE_OVERRIDE_wotaskd_start=wotaskd_start
function wotaskd_start() {
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        launchctl load /System/Library/LaunchDaemons/com.apple.wotaskd.plist
    else
        __unix_woservices start
    fi
}

SERVICE_OVERRIDE_javamonitor_stop=javamonitor_stop
SERVICE_OVERRIDE_womonitor_stop=javamonitor_stop
function javamonitor_stop() {
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        launchctl unload /System/Library/LaunchDaemons/com.apple.womonitor.plist
    else
        __unix_woservices stop
    fi
}
function womonitor_stop() { javamonitor_stop "$@"; }

SERVICE_OVERRIDE_javamonitor_start=javamonitor_start
SERVICE_OVERRIDE_womonitor_start=javamonitor_start
function javamonitor_start() {
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        launchctl load /System/Library/LaunchDaemons/com.apple.womonitor.plist
    else
        __unix_woservices start
    fi
}
function womonitor_start() { javamonitor_start "$@"; }

SERVICE_OVERRIDE_woservices_stop=woservices_stop
function woservices_stop() {
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        javamonitor_stop
        wotaskd_stop
    else
        __unix_woservices stop
    fi
}

SERVICE_OVERRIDE_woservices_start=woservices_start
function woservices_start() {
    if [ "$UNAME_SYSTEM" == "Darwin" ]; then
        wotaskd_start
        javamonitor_start
    else
        __unix_woservices start
    fi
}