# Modules standards

Cette documentation vous donne une description détaillée des modules standards suivants :

Les modules standards elo, tfer, addr, notify, exif, www sont décrits dans Javadoc de l'interface ELOas interne sous http://www.forum.elo.com/javadoc/as/21/ (opens new window).

# cnt: ELO Counter Access

Le module standard cnt met à disposition l'accès aux variables de compte du ELOam.

# cnt : fonctions disponibles

Créer un compteur : la fonction createCounter() crée un nouveau compteur et l'initialise avec une valeur de démarrage. Si le compte existe déjà, il est ré-initialisé.

createCounter: function (counterName, initialValue) {
    var counterInfo = new CounterInfo();
    counterInfo.setName(counterName);
    counterInfo.setValue(initialValue);
    var info = new Array(1);
    info[0] = counterInfo;
    ixConnect.ix().checkinCounters(info, LockC.NO);
},

Déterminer la valeur de compteur : la fonction getCounterValue() permet de déterminer la valeur actuelle du compteur indiqué. Si le paramètre autoIncrement est true, la valeur du compte est comptée en plus automatiquement.

getCounterValue: function (counterName, autoIncrement) {
    var counterNames = new Array(1);
    counterNames[0] = counterName;
    var counterInfo = ixConnect.ix().checkoutCounters(counterNames, autoIncrement, LockC.NO);
    return counterInfo[0].getValue();
},

Créer un numéro de traçage à partir du compteur: si l'on requiert un numéro courant et pouvant être reconnu automatiquement, alors l'on peut utiliser la fonction getTrackId(). Elle lit tout d'abord la prochaine valeur du compte et code un chiffre avec un préfixe et un chiffre de vérification. Le string créé ressemble à ceci <préfixe><numéro courant>C<chiffre de vérification> ("ELO1234C0")

getTrackId: function (counterName, prefix) {
    var tid = cnt.getCounterValue(counterName, true);
    return cnt.calcTrackId(tid, prefix)
},

Créer un numéro de traçage: si l'on requiert un numéro courant et pouvant être reconnu automatiquement, alors l'on peut utiliser la fonction calcTrackId(). Elle code un chiffre avec un préfixe et un numéro de vérification. Le string créé ressemble à ceci <préfixe><numéro courant>C<chiffre de vérification> ("ELO1234C0")

calcTrackId: function (trackId, prefix) {
    var chk = 0;
    var tmp = trackId;
    while (tmp > 0) {
        chk = chk + (tmp % 10);
        tmp = Math.floor(tmp / 10);
    }
    return prefix + "" + trackId + "C" + (chk %10);
},

Recherche le numéro de traçage dans le texte : la fonction findTrackId() recherche un numéro de traçage dans un texte. Le préfixe et la longueur du chiffre peuvent être dirigés par un paramètre. Si le chiffre possède une longueur variable, le paramètre de longueur peut être placé sur 0. Si aucun résultat n'est trouvé dans le texte, c'est le -1 qui est livré en retour. Sinon, c'est la valeur du chiffre qui est livrée (et non pas l'ID du Track).

findTrackId: function (text, prefix, length) {
    text = " " + text + " ";
    var pattern = "\\s" + prefix + "\\d+C\\d\\s";
    if (length > 0) {
        pattern = "\\s" + prefix + "\\d{" +
                  length + "}C\\d\\s";
    }
    var val = text.match(new RegExp(pattern, "g"));
    if (!val) {
        return -1;
    }
    for (var i = 0; i < val.length; i++) {
        var found = val[i];
        var number = found.substr(prefix.length + 1,
                                  found.length - prefix.length - 4);
        var checksum = found.substr(found.length - 2, 1);
        if (checkId(number, checksum)) {
            return number;
        }
    }
    return -1;
}

# db : DB Access

Le module standard DB Access met à disposition un accès simple aux bases de données externes. De façon standard, les bases de données ODBC, ainsi que Microsoft SQL et Oracle SQL sont supportés. Si l'accès aux autres bases de données se fait avec un pilote JDBC natif, les fichiers JAR correspondants doivent être copiés dans le répertoire LIB du service, et les importations et paramètres d'accès doivent être placés dans le module Imports. L'ordre des définitions de la base de données dans le module Imports définit la valeur du paramètre Numéro de connexion dans les appels suivants.

# db : fonctions disponibles

getColumn( Numéro de connexion, demande SQL);

Cet appel doit donner une demande SQL comme paramètre; celle-ci demande une colonne et livre seulement une ligne comme résultat.

Exemple :

„select USERNAME from CUSTOMERS where USERID = 12345

Par le biais du numéro de connexion, l'on détermine quelle connexion à la base de données est utilisée. La liste des connexions disponible est définie dans le module "Imports".

Exemple avec JavaScript Code:

var cmd = "select USERNAME from CUSTOMERS where USERID = 12345"
var res = getColumn(1, cmd)
log.debug(res)

Exemple dans le créateur GUI:

Créateur GUI

Illustr. : créateur GUI

Si la liste des résultats devait se composer de plusieurs lignes, seule la première valeur serait livrée. Tous les autres résultats sans ignorés sans message d'erreur.

getLine( Numéro de connexion, demande SQL );

En tant que résultat, cet appel donne en retour un objet JavaScript avec les valeurs de la première ligne de la demande SQL. La demande peut contenir un nombre illimité de colonnes, aussi un *. Les noms de colonnes doivent être univalents et être des désignateurs JavaScript valides. Attention aux minuscules et majuscules en ce qui concerne les désignateurs JavaScript.

Exemple :

"select USERNAME, STREET, CITY from CUSTOMERS where USERID = 12345"

Par le biais du numéro de connexion, l'on détermine quelle connexion à la base de données est utilisée. La liste des connexions disponible est définie dans le module "Imports".

Exemple avec JavaScript Code:

var cmd =
  "SELECT objshort, objidate, objguid FROM [elo20].[dbo].objekte where objid = 22"
var res = getLine(1, cmd)
log.debug(res.objshort)
log.debug(res.objidate)
log.debug(res.objguid)

Si la liste des résultats contient plusieurs lignes, seules les valeurs de la première ligne seront livrées en retour. Toutes les autres lignes sont ignorées sans message d'erreur.

getMultiLine(numéro de connexion, commande SQL, nombre max. de ligne)

Cette commande travaille comme l'appel getLine. Attention : ce n'est pas un objet, mais un array d'objets qui est rendu. Chaque ligne de la liste des résultats crée une entrée dans le Array. Afin que la mémoire ne "déborde" pas s'il s'agit d'une base de données volumineuses, l'on peut limiter le nombre max. de lignes. Vous pouvez ignorer d'autres résultats.

Exemple :

var obj = db.getMultiLine(1, "select objshort, objid from [elo80].[dbo].objekte where objid < 100 order by objshort", 50);
    for (var lg = 0; lg < obj.length; lg++) {
        log.debug(obj[lg].objid + " : " + obj[lg].objshort);
    }
doUpdate(numéro de connexion, commande SQL)

L'on ne peut pas utiliser les appels getLine ou getColumn pour exécuter une modification dans la base de données. Ces commandes utilisent la commande JDBC en interne executeQuery – et celui-ci permet seulement les demandes SELECT.

Pour modifier une entrée, l'on peut utiliser l'appel doUpdate. Celui-ci transfère la commande SQL entrée à la commande JDBC executeUpdate – grâce à ceci, l'on peut modifier les entrées existantes ou ajouter de nouvelles entrées.

Information

Etant donné que tous les paramètres doivent être transférés sous forme de texte, l'on doit faire attention que d'éventuels guillemets soient codés correctement. Sinon, des messages d'erreur peuvent apparaître, au pire, une SQL Injection sur le serveur SQL.

# Importation

Le type et le volume des importations requises dépendent de la base de données; veuillez consulter la documentation correspondante pour tout complément d'information. Si nécessaire, les fichiers JAR utilisés doivent être copiés dans le répertoire du service ELOas.

Voici un exemple pour les importations nécessaires de la bridge JDBC-ODBC:

importPackage(Packages.sun.jdbc.odbc);

Dans le module Imports de ELOas Libraries 12, un système standard a été introduit. Le sélecteur du système standard a utilisé la valeur standard SordC.mbLean pour des raisons de performance et est utilisé pour le traitement des règles ELOas standards.

const EM_SYS_STDSEL = SordC.mbLean;

Par ailleurs, un sélecteur système du nom EM_SYS_SELECTOR a été introduit dans le module Imports. Le sélecteur système est configuré conformément à la valeur du sélecteur standard dans le module bt. Dans l'événement onStart, le sélecteur système peut utiliser et traiter les autres propriétés de l'entrée, mis à part l'ID et le nom.

EM_SYS_SELECTOR=SordC.mbAll;

De même, les constantes du processus ont été élargies en terme de sélecteur de proccessus du nom EM_WF_SELECTOR :

var EM_WF_SELECTOR = SordC.mbLean;

# Paramètres de connexion

Les paramètres de connexion à la base de données sont déposés dans le module Imports. Il existe une liste de connexions, qui peuvent être appelées ultérieurement avec leur numéro de connexion (commençant par 0).

var EM_connections = [
    {
        driver: 'sun.jdbc.odbc.JdbcOdbcDriver',
        url: 'jdbc:odbc:Driver={Microsoft Access Driver (*.mdb)};DBQ=C:\\Temp\\EMDemo.mdb',
        user: '',
        password: '',
        initdone: false,
        classloaded: false,
        dbcn: null
    },
    {
        driver: 'com.microsoft.sqlserver.jdbc.SQLServerDriver',
        url: 'jdbc:sqlserver://srvt02:1433',
        user: 'elodb',
        password: 'elodb',
        initdone: false,
        classloaded: false,
        dbcn: null
    }
];

Les informations suivantes doivent être déposées pour chaque connexion:

driver Nom de classe JDBC pour la connexion à la base de données Vous obtiendrez cette information par le fabricant du pilote JDBC ou par le créateur de la base de données.
url URL d'accès à la base de données. C'est ici que sont déposés les paramètres de connexion dépendants de la base de données, par exemple les chemins de fichiers pour les bases de données Access ou les noms de serveur et ports pour les bases de données SQL. Ces paramètres de connexion dépendent du fabricant et doivent être lus dans la documentation correspondante.
user Nom d'authentification pour l'accès à la base de données. Ce paramètre n'est pas utilisé par toutes les bases de données (par exemple par des bases de données Access qui ne sont pas protégées). Dans ce cas, le paramètre peut rester vide.
password Mot de passe pour l'authentification à la base de données.
initdone Variable interne pour la “lazy initialization”.
classloaded Variable interne permettant de contrôler si le fichier de classe a déjà été chargé.
dbcn Variable interne d'enregistrement de l'objet de connexion à la base de données.

# JavaScript-Code

La routine dbInit est seulement appelée à l'intérieur du module. Elle est appelée avant chaque accès à la base de données et vérifie si une connexion a déjà été établie; et la crée si nécessaire.

function dbInit(connectId) {
  if (EM_connections[connectId].initdone == true) {
    return
  }
  log.debug("Now init JDBC driver")
  var driverName = EM_connections[connectId].driver
  var dbUrl = EM_connections[connectId].url
  var dbUser = EM_connections[connectId].user
  var dbPassword = EM_connections[connectId].password
  try {
    if (!EM_connections[connectId].classloaded) {
      Class.forName(driverName).newInstance()
      log.debug("Register driver ODBC")
      DriverManager.registerDriver(new JdbcOdbcDriver())
      EM_connections[connectId].classloaded = true
    }
    log.debug("Get Connection")
    EM_connections[connectId].dbcn = DriverManager.getConnection(
      dbUrl,
      dbUser,
      dbPassword
    )
    log.debug("Init done.")
  } catch (e) {
    log.debug("ODBC Exception: " + e)
  }
  EM_connections[connectId].initdone = true
}

La fonction exitRuleset_DB_Access() est appelée automatiquement après la terminaison du traitement Ruleset. Elle vérifie si une connexion existe, puis la referme. Ce contrôle doit exister pour toutes les bases de données configurées.

function exitRuleset_DB_Access() {
  log.debug("dbExit")
  for (i = 0; i < EM_connections.length; i++) {
    if (EM_connections[i].initdone) {
      if (EM_connections[i].dbcn) {
        try {
          EM_connections[i].dbcn.close()
          EM_connections[i].initdone = false
          log.debug("Connection closed: " + i)
        } catch (e) {
          log.info("Error closing database " + i + ": " + e)
        }
      }
    }
  }
}

La fonction getLine() lit une ligne dans la base de données avec des colonnes quelconques et place les résultats dans un objet JavaScript. Cet objet contient, pour chaque colonne, une variable Member avec le nom de colonne.

function getLine(connection, qry) {
  // la sous-fonction crée un objet JavaScript avec
  // le contenu de la base de données ayant été enregistré
  function dbResult(connection, qry) {
    // Tout d'abord établir la connexion
    dbInit(connection)
    // puis créer un objet SQL Statement
    var p = EM_connections[connection].dbcn.createStatement()
    // et exécuter la requête
    var rss = p.executeQuery(qry)
    // rss contient la liste des résultats, la première
    // ligne est enregistrée
    if (rss.next()) {
      // le nombre de colonnes est déterminé via les métadonnées
      var metaData = rss.getMetaData()
      var cnt = metaData.getColumnCount()
      // Une member variable est créée pour chaque colonne
      // Celle-ci porte le nom du nom de la colonne SQL, et en tant que valeur
      // le contenu de la base de données qui a été enregistré.
      // La première colonne peut toujours être gérée via le nom
      // first.
      for (i = 1; i <= cnt; i++) {
        var name = metaData.getColumnName(i)
        var value = rss.getString(i)
        this[name] = value
        if (i == 1) {
          this.first = value
        }
      }
    }
    // Ensuite, la liste des résultats et le statement
    // SQL sont fermés.
    rss.close()
    p.close()
  }
  // voici le démarrage de la fonction. Un
  // objet JavaScript avec le contenu de la base de données
  // est exigé.
  var res = new dbResult(connection, qry)
  return res
}
// La fonction getColumn est uen variante spéciale de
// l'appel getLine. La requête SQL ne doit
// montrer qu'une colonne en tant que résultat. S'il existe
// d'autres colonnes, celles-ci sont ignorées,
// tout comme les lignes supplémentaires.
function getColumn(connection, qry) {
  var res = getLine(connection, qry)
  return res.first
}

# dex: Document Export

Le module Document Export peut exporter des documents dans le système de fichiers depuis l'archive. Cette exportation n'est pas un processus unique – si une nouvelle version de document est créée, le module écrit automatiquement un fichier actualisé. Les fichiers déjà publiés peuvent être supprimés. Pour des raisons de sécurité, les fichiers se trouvent seulement dans un chemin pré-configuré.

Un masque de dépôt doit être défini, qui contient le statut de document et une ou plusieurs cibles de dépôt dans le système de fichiers. En plus, le numéro de document de la dernière exportation est enregistré dans le masque.

Champ de statut dans le masque

Illustr. : champ de statut dans le masque

Le champ de statut détermine les actions devant être exécutées. Avec Actif: autorisé, le fichier est authentifié à l'exportation. Actif : prévu pour la suppression fait que le fichier est supprimé du système de fichiers et que le statut est placé sur Plus actif / supprimé. Tous les autres réglages de statut n'engendrent pas d'action de ELOas et sont prévus pour les documents internes ou les documents n'ayant pas encore été autorisés. Etant donné que cette valeur est demandée par le traitement interne, il est sensé de remplir cette ligne seulement à partir d'une liste de mots-clés pré-configurée.

Les champs Chemin de fichier 1..5 contiennent le chemin et le nom de fichier du document dans le système de fichiers. Il s'agit d'un chemin relatif, la partie de démarrage est définie dans le module JavaScript comme dexRoot et peut y être ajustée. Cette partie fixe est prévue par sécurité, sinon, des fichiers quelconques peuvent être écrasés par des saisies erronées.

Le champ Dernière exportation contient le numéro de document de la dernière version de fichier exportée. Si une nouvelle version de fichier a été créée après un traitement, le module reconnaît ceci et une copie du fichier est écrite dans le système de fichiers. Ensuite, ce champ est actualisé.

Si une erreur est apparue lors du traitement, le texte "ERROR" est déposé dans le champ Dernière exportation, grâce à la règle d'erreurs. L'on peut donc créer un registre dynamique dans ELO, celui-ci vérifie le champ quant à la valeur ERROR et peut afficher une liste actuelle de tous les documents qui ne peuvent pas être exportés.

Exemple pour un registre dynamique si le masque possède l'ID 22:

!+ , objkeys where objmask = 22 and objid = parentid and okeyname ='PDEXPORT
        and okeydata ='ERROR'

# dex : fonctions disponibles

Le module met à disposition seulement une fonction : processDoc. Celui reçoit l'objet SORD du serveur d'indexation en tant que paramètre et vérifie selon le statut si le fichier doit être exporté ou supprimé; puis il exécute l'action correspondante. Le nouvel identificateur de document est transféré en tant que valeur de retour. L'objet SORD actuel est disponible au sein d'un traitement de règle dans la variable JavaScript Sord.

Exemple dans le code XML Ruleset:

<rule>
    <name>Regel 1</name>
    <condition>(PDEXPORT != Sord.getDoc()) &amp;&amp; (PDEXPORT != "ERROR") ||
               (PDSTATUS == "Actif : suppression") </condition>
    <index>
    <name>PDEXPORT</name>
    <value>dex.processDoc(Sord)</value>
    </index>
</rule>

# dex : code JavaScript

En premier, le chemin de base docRoot est déterminé pour le dépôt de document. Le chemin cible est toujours déterminé à partir de ce réglage et à partir de l'entrée utilisateur dans le masque de dépôt. Il serait possible de laisser ce chemin de base vide, de façon à ce que l'utilisateur puisse entrer des chemins quelconques. Ce procédé risquerait d'engendre des problèmes de sécurité, étant donné que chaque utilisateur est en mesure d'écraser des fichiers quelconques dans la zone d'accès de ELOas.

var dexRoot = "c:\\temp\\"

La fonction processDoc est appelée à partir de la définition des règles. Ici, est vérifié le statut de l'objet SORD du serveur d'indexation et la fonction requise est appelée.

function processDoc(Sord) {
  log.debug("Statut: " + PDSTATUS + ", Name: " + NAME)
  if (PDSTATUS == "Actif : prévu pour la suppression") {
    return dex.deleteDoc(Sord)
  } else if (PDSTATUS == "actif : validé") {
    return dex.exportDoc(Sord)
  }
  return ""
}

Si le statut était placé sur "supprimer", la suppression des fichiers est déclenchée dans la fonction deleteDoc, et le statut est permuté en "supprimé".

function deleteDoc(Sord) {
  dex.deleteFile(PDPATH1)
  dex.deleteFile(PDPATH2)
  dex.deleteFile(PDPATH3)
  dex.deleteFile(PDPATH4)
  dex.deleteFile(PDPATH5)
  PDSTATUS = "Plus actif / supprimé"
  return Sord.getDoc()
}

La fonction deleteFile exécute la suppression. Elle vérifie tout d'abord si un nom de fichier est configuré et si le fichier existe, et le supprime dans le système de fichiers.

function deleteFile(destPath) {
  if (destPath == "") {
    return
  }
  var file = new File(docRoot + destPath)
  if (file.exists()) {
    log.debug("Delete expired version: " + docRoot + destPath)
    file["delete"]()
  }
}

S'il s'agit d'écrire une nouvelle version de fichier, la fonction interne exportDoc est appelée. Le fichier est cherché par le gestionnaire de documents et copié dans le classeur cible.

function exportDoc(Sord) {
  var editInfo = ixConnect
    .ix()
    .checkoutDoc(Sord.getId(), null, EditInfoC.mbSordDoc, LockC.NO)
  var url = editInfo.document.docs[0].getUrl()
  dex.copyFile(url, PDPATH1)
  dex.copyFile(url, PDPATH2)
  dex.copyFile(url, PDPATH3)
  dex.copyFile(url, PDPATH4)
  dex.copyFile(url, PDPATH5)
  return Sord.getDoc()
}

La fonction copyFile exécute le processus de copie dans le classeur cible. Il est tout d'abord vérifié s'il existe un nom du fichier cible et si une version ancienne éventuellement existante doit être supprimée. Ensuite, la nouvelle version est cherchée par le gestionnaire de documents et enregistrée dans le classeur cible.

function copyFile(url, destPath) {
    if (destPath == "") {
        return;
    }
    log.debug("Path: " + docRoot + destPath);
    var file = new File(docRoot + destPath);
    if (file.exists()) {
        log.debug("Delete old version.");
        file["delete"](#ELODOC-D50FBC7EA85D4A709D2C12762E1B9F300);
}

# ix : Fonctions du serveur d'indexation

Le module ix contient un regroupement de plusieurs fonctions du serveur d'indexation, qui sont souvent requises dans les scripts. Il s'agit de simples wrapper placés autour de la commande du serveur d'indexation, il ne s'agit pas d'une nouvelle fonctionnalité complexe.

# ix : fonctions disponibles

Suppression d'une entrée SORD : la fonction deleteSord() est dotée de paramètre, à savoir les ID d'objet de l'entrée SORD qu'il s'agit de supprimer, ainsi que de l'entrée parent.

deleteSord: function (parentId, objId) {
    log.info("Delete SORD: ParentId = " + parentId + ", ObjectId = " + objId);
    return ixConnect.ix().deleteSord(parentId, objId, LockC.NO, null);
},

Rechercher une entrée : la fonction lookupIndex() détermine l'ID d'objet d'une entrée qui est trouvée via le chemin de dépôt. Le paramètre archivePath doit commencer par un tiret.

lookupIndex: function (archivePath) {
    log.info("Lookup Index: " + archivePath);
    var editInfo = ixConnect.ix().checkoutSord("ARCPATH:" + archivePath, EditInfoC.mbOnlyId, LockC.NO);
    if (editInfo) {
        return editInfo.getSord().getId();
    }   else {
        return 0;
    }
}

Rechercher une entrée: la fonction lookupIndexByLine() détermine l'ID d'objet d'une entrée selon la recherche d'une ligne d'indexation. Si le paramètre Mask IDest transféré avec un string vide, alors une recherche sur plusieurs masques est effectuée. Le nom de groupe et le terme de recherche doivent être transférés.

lookupIndexByLine : function(maskId, groupName, value) {
    var findInfo = new FindInfo();
    var findByIndex = new FindByIndex();
    if (maskId != "") {
        findByIndex.maskId = maskId;
    }
    var objKey = new ObjKey();
    var keyData = new Array(1);
    keyData[0] = value;
    objKey.setName(groupName);
    objKey.setData(keyData);
    var objKeys = new Array(1);
    objKeys[0] = objKey;
    findByIndex.setObjKeys(objKeys);
    findInfo.setFindByIndex(findByIndex);
    var findResult = ixConnect.ix().findFirstSords(findInfo, 1, SordC.mbMin);
    ixConnect.ix().findClose(findResult.getSearchId());
    if (findResult.sords.length == 0) {
        return 0;
    }
    return findResult.sords[0].id;
},

Lecture des informations plein texte : la fonction getFulltext() livre l'information plein texte actuelle pour un document. Le plein texte est rendu en tant que string.

Remarque

Il n'est pas possible de reconnaître s'il n'existe pas de plein texte, ou si le traitement du plein texte est complètement clos ou si l'action a été annulée avec une erreur. C'est le texte existant au moment de la demande qui est livré (s'il n'existe pas d'informations plein texte, il s'agit alors d'un string vide).

getFulltext: function(objId) {
    var editInfo = ixConnect.ix().checkoutDoc(objId, null,
                                              EditInfoC.mbSordDoc, LockC.NO);
    var url = editInfo.document.docs[0].fulltextContent.url
    var ext = "." + editInfo.document.docs[0].fulltextContent.ext
    var name = fu.clearSpecialChars(editInfo.sord.name);
    var temp = File.createTempFile(name, ext);
    log.debug("Temp file: " + temp.getAbsolutePath());
    ixConnect.download(url, temp);
    var text = FileUtils.readFileToString(temp, "UTF-8");
    temp["delete"]();
    return text;
}

Création d'une liste de classeur: la fonction createSubPath() vérifie si le chemin de classeur existe dans l'archive et crée automatiquement les parties manquantes si nécessaire.

createSubPath: function (startId, destPath, folderMask) {
    log.debug("createPath: " + destPath);
    try {
        var editInfo = ixConnect.ix().checkoutSord("ARCPATH:" + destPath,
                                                   EditInfoC.mbOnlyId, LockC.NO);
        log.debug("Path found, GUID: " + editInfo.getSord().getGuid() +
                  " ID: " + editInfo.getSord().getId());
        return editInfo.getSord().getId();;
    }   catch (e) {
        log.debug("Path not found, create new: " + destPath +
                  ", use foldermask: " + folderMask);
    }
    items = destPath.split("¶");
    var sordList = new Array(items.length - 1);
    for (var i = 1; i < items.length; i++) {
    log.debug("Split " + i + " : " + items[i]);
    var sord = new Sord();
    sord.setMask(folderMask);
    sord.setName(items[i]);
    sordList[i - 1] = sord;
    }
    log.debug("now checkinSordPath");
    var ids = ixConnect.ix().checkinSordPath(startId, sordList,
            new SordZ(SordC.mbName | SordC.mbMask));
    log.debug("checkin done: id: " + ids[ids.length - 1]);
    return ids[ids.length - 1];
}

# wf: Workflow Utils

Le module wf contient des accès plus faciles aux données de processus. Il existe deux groupes de fonctions.

Les fonctions 'high level' changeNodeUser et readActiveWorkflow sont à utiliser pour l'accès simple d'un traitement de processus en cours et travaillent avec le processus actuellement actif. Elles sont très simples à utiliser, mais elles exécutent seulement une fonction simple.

Les fonctions low leven readWorkflow, writeWorkflow, unlockWorkflow et getNodeByName peuvent être utilisées à partir de n'importe où. Si plusieurs modifications doivent être effectuées dans le même processus, l'on peut s'assurer que le processus est seulement lu et écrit une fois, et non pas x-fois pour chaque opération.

# wf : Fonctions disponibles

Modifier le nom utilisateur d'un noeud de personne : la fonction changeNodeUser(): permute, dans le processus actuel dans le noeud de processus du nom nodeName l'utilisateur avec un nouvel utilisateur nodeUserName

Etant donné que cet appel lit toujours le processus intégral, le modifie et le ré-écrit automatiquement, cet appel simple devrait n'être utilisé que si un seul noeud doit être modifié. Si plusieurs modifications sont nécessaires, les fonctions décrites ci-dessous devraient être utilisées pour lire, modifier et enregistrer un processus.Etant donné que cette fonction détermine l'ID du processus dans le processus actuellement actif, il peut seulement être appelé à partir de la recherche „WORKFLOW“. Lors de l'utilisation dans un TREEWALK ou une recherche normale, un ID de processus définie au hasard est utilisée.

changeNodeUser: function(nodeName, nodeUserName) {
    var diag = wf.readActiveWorkflow(true);
    var node = wf.getNodeByName(diag, nodeName);
    if (node) {
        node.setUserName(nodeUserName);
        wf.writeWorkflow(diag);
    }   else {
        wf.unlockWorkflow(diag);
    }
}

Copier le nom utilisateur d'un noeud: la fonction 'copyNodeUser()' est semblable à 'changeNodeUser', mais elle copie le nom utilisateur d'un noeud dans un autre noeud.

copyNodeUser: function(sourceNodeName, destinationNodeName) {
    var diag = wf.readActiveWorkflow(true);
    var sourceNode = wf.getNodeByName(diag, sourceNodeName);
    var destNode = wf.getNodeByName(diag, destinationNodeName);
    if (sourceNode && destNode) {
        var user = sourceNode.getUserName();
        destNode.setUserName(user);
        wf.writeWorkflow(diag);
        return user;
    }   else {
        wf.unlockWorkflow(diag);
        return null;
    }
}

Importer le processus actuel : la fonction readActiveWorkflow() permet d'importer le processus actif actuellement dans une variable locale, en vue d'un traitement. A la fin, il peut être écrit avec writeWorkflow, ou bien le verrouillage peut être autorisé avec unlockWorkflow.

readActiveWorkflow: function(withLock) {
    var flowId = EM_WF_NODE.getFlowId();
    return wf.readWorkflow(flowId, withLock);
    },

Importer le processus : la fonction readWorkflow() importe un processus dans une variable locale. Celui-ci peut être évalué et modifié. Si les modifications doivent être enregistrées, alors celles-ci peuvent être ré-écrites par writeWorkflow. Si le processus a été lu avec Lock, mais que les modifications ne doivent pas être enregistrées, le verrouillage peut être retiré avec unlockWorkflow.

readWorkflow: function(workflowId, withLock) {
    log.debug("Read Workflow Diagram, WorkflowId = " + workflowId);
    return ixConnect.ix().checkoutWorkFlow(String(workflowId),
                                           WFTypeC.ACTIVE,
                                           WFDiagramC.mbAll,
                                           (withLock) ? LockC.YES : LockC.NO);
},

Exporter le processus : la fonction writeWorkflow() exporte le processus depuis une variable locale dans la base de données. Un verrouillage d'écriture éventuellement existant est ré-initialisé automatiquement.

writeWorkflow: function(wfDiagram) {
    ixConnect.ix().checkinWorkFlow(wfDiagram, WFDiagramC.mbAll, LockC.YES);
},

Annuler le verrouillage de lecture : fonction unlockWorkflow(). Si un processus avec verrouillage de lecture a été lu, mais qu'il ne doit pas être modifié, l'on peut annuler le verrouillage grâce à unlockWorkflow.

unlockWorkflow: function(wfDiagram) {
    ixConnect.ix().checkinWorkflow(wfDiagram, WFDiagramC.mbOnlyLock, LockC.YES);
},

Rechercher un noeud de processus : la fonction 'getNodeByName()' recherche le noeud de processus pour un nom de noeud. Le nom doit être univalent, sinon, c'est le premier noeud trouvé qui est livré.

getNodeByName: function(wfDiagram, nodeName) {
    var nodes = wfDiagram.getNodes();
    for (var i = 0; i < nodes.length; i++) {
        var node = nodes[i];
        if (node.getName() == nodeName) {
            return node;
        }
    }
    return null;
},

Démarrer un processus depuis le modèle : la fonction startWorkflow() démarre un nouveau processus vers und ID d'objet ELO depuis un modèle de processus.

startWorkflow: function(templateName, flowName, objectId) {
    return ixConnect.ix().startWorkFlow(templateName, flowName, objectId);
}

# mail: Mail Utils

Ce module sert à envoyer des e-mails. A ces fins, il requiert un hôte SMTP par le biais duquel les mails peuvent être envoyés. Celui-ci doit être indiqué avant le premier envoi de mail par le biais de la fonction setSmtpHost. Ensuite, l'on peut envoyer des messages par SendMail ou SendMailWithAttachment. Le module se compose de deux parties, pour envoyer des messages et pour lire les boîtes de réception de messagerie.

# mail : Fonctions disponibles pour lire une boîte de réception

Dans le ruleset, vous pouvez définir que l'action de base n'est pas une recherche dans l'archive ELO ou dans la liste des tâches ELO, mais que c'est une boîte de réception qui doit être parcourue. Pour chaque type de boîte de réception, une routine d'authentification doit être déposée dans le module mail. Dans cette fonction, le serveur mail doit être contacté, le classeur Mail souhaité doit être recherché et la liste des messages lue. Ensuite, le traitement ELOas normal prend les commandes. Pour chaque mail, un document est préparé dans le classeur, défini dans SEARCHVALUE, puis le ruleset est exécuté (l'objet du message est automatiquement adopté dans la désignation). Si l'entrée n'est pas enregistrée à la fin, alors on ne trouve rien dans l'archive en conséquence. Seuls les mails enregistrés sont transférés dans l'archive.

<search>
<name>"MAILBOX_GMAIL"</name>
<value>"ARCPATH:¶ELOas¶IMAP"</value>
<mask>2</mask>

Dans le ruleset, le nom doit être défini en tant que nom MAILBOX_<nom de la connexion> et en tant que valeur, le chemin d'archive ou le numéro du classeur cible. Par ailleurs, le masque à utiliser pour les nouveaux documents doit être défini.

Le mail est traité dans le script du ruleset. Ici aussi, le module mail propose quelques routines qui vous simplifient la vie. Dans l'exemple suivant, le corps du message est transféré dans le texte supplémentaire, l'expéditeur, le destinataire et l'ID du mail sont transférés dans les champs correspondants du masque e-mail :

OBJDESC = mail.getBodyText(MAIL_MESSAGE);
ELOOUTL1 = mail.getSender(MAIL_MESSAGE);
ELOOUTL2 = mail.getRecipients(MAIL_MESSAGE, "¶");
ELOOUTL3 = msgId;
EM_WRITE_CHANGED = true;

Si des valeurs ou informations complémentaires doivent être utilisées, un objet JavaMailMimeMessage Message est disponible dans la variable MAIL_MESSAGE.

Afin que les mails déjà traités ne soient pas transférés deux fois dans l'archive, une recherche de l'ID du mail doit être effectuée avant le traitement. Si le mail est déjà dans l'archive, la variable MAIL_ALLOW_DELETE est placée sur true, sinon, le mail est traité. En plaçant le flag de suppression, le mail est supprimé de la boîte de réception ou marqué comme traité.

var msgId = MAIL_MESSAGE.messageID;
if (ix.lookupIndexByLine(EM_SEARCHMASK, "ELOOUTL3", msgId) != 0) {
    log.debug("Le mail existe déjà dans l'archive, ignorer ou supprimer");
    MAIL_ALLOW_DELETE = true;
}   else {
    OBJDESC = mail.getBodyText(MAIL_MESSAGE);
    ELOOUTL1 = mail.getSender(MAIL_MESSAGE);
    ELOOUTL2 = mail.getRecipients(MAIL_MESSAGE, "¶");
    ELOOUTL3 = msgId;
    EM_WRITE_CHANGED = true;
}

Ce procédé lit un message deux fois (une fois pour le traitement normal, et une fois pour la suppression), mais cette méthode a l'avantage considérable que le mail est seulement supprimé de la boîte de réception s'il existe réellement dans l'archive.

Si vous souhaitez utiliser une boîte de réception pour la surveillance, les quatre fonctions suivantes sont requises dans la librairie JavaScript :

établir une connexion, ouvrir les répertoires de la boîte de réception : connectImap_<nom de la connexion>

Prochain message de la liste devant être traité : nextImap_<nom de la connexion>

Supprimer le message ou le marquer comme étant traité : finalizeImap_<om de la connexion>

Fermer la connexion : closeImap_<nom de la connexion>

De ces quatre fonctions, seule une doit être implémentée dans les cas simples : établir la connexion – connectImap_<nom de la connexion>. Etant donné qu'une multitude d'actions spécifiques aux projets existent (paramètres d'authentification, rechercher le classeur cible), il n'existe pas d'intégration standard. Les trois autres fonctions existent déjà avec une fonction standard dans le système. Elles doivent seulement être intégrées si l'on souhaite exécuter des fonctions complémentaires.

Connecter à IMAP Server : la fonction connectImap_<nom de la connexion>() doit établir une connexion au serveur de messagerie et extraire les informations dans la boîte de réception souhaitée. Les messages existants sont déposés dans la variable MAIL_MESSAGES. Le store Mail doit être enregistré dans les variables MAIL_STORE et le classeur lu dans la variable MAIL_INBOX. Ces deux variables sont requises à la fin du traitement pour fermer la connexion. La variable MAIL_DELETE_ARCHIVED détermine si l'on peut effectuer des suppressions dans la boîte de réception. Si elle est placée sur 'false', les exigences de suppression du ruleset sont ignorées. Cette fonction n'est pas directement appelée par le biais d'un script, elle est activée dans ELOas (pour la recherche MAILBOX, dans l'exemple MAILBOX_GMAIL).

connectImap_GMAIL: function() {
    var props = new Properties();
    props.setProperty("mail.imap.host", "imap.gmail.com");
    props.setProperty("mail.imap.port", "993");
    props.setProperty("mail.imap.connectiontimeout", "5000");
    props.setProperty("mail.imap.timeout", "5000");
    props.setProperty("mail.imap.socketFactory.class",
                      "javax.net.ssl.SSLSocketFactory");
    props.setProperty("mail.imap.socketFactory.fallback", "false");
    props.setProperty("mail.store.protocol", "imaps");
    var session = Session.getDefaultInstance(props);
    MAIL_STORE = session.getStore("imaps");
    MAIL_STORE.connect("imap.gmail.com", "<<<USERNAME>>>@gmail.com",
                       "<<<PASSWORT>>>");
    var folder = MAIL_STORE.getDefaultFolder();
    MAIL_INBOX = folder.getFolder("INBOX");
    MAIL_INBOX.open(Folder.READ_WRITE);
    MAIL_MESSAGES = MAIL_INBOX.getMessages();
    MAIL_POINTER = 0;
    MAIL_DELETE_ARCHIVED = false;
},

Fermer la connexion : la fonction closeImap_<nom de la connexion'> est en option et permet de fermer la connexion actuelle vers le serveur IMAP. S'il n'existe pas de tâches spécifiques lors de la fermeture, vous ne devez pas implémenter cette fonction. Au lieu de cela, l'implémentation standard 'cloImap()' de la library est utilisée. Celle-ci ferme le classeur et le store.

closeImap_GMAIL: function() {
    // ici, vous pouvez exécuter vos propres actions avant la fermeture
    // action standard, refermer le classeur et le store.
    MAIL_INBOX.close(true);
    MAIL_STORE.close();
},

Marquer le message comme traité ou le supprimer : la fonction finalizeImap_<nom de la connexion>() est en option et supprime le message actuel ou le marque comme déjà traité d'une autre manière. Si elle n'est pas intégrée, ELOam utilise l'intégration standard qui supprime un mail traité dans le classeur.

L'exemple ne supprime pas l'e-mail, mais le marque comme "lu".

finalizeImap_GMAIL: function() {
    if (MAIL_DELETE_ARCHIVED && MAIL_ALLOW_DELETE) {
        message.setFlag(Flags.Flag.SEEN, true);
    }
},

Traiter le prochain message de la liste : la fonction nextImap_<nom de connexion> : cette fonction est en option et livre au ruleset le prochain message de la boîte de réception sélectionnée en vue d'un traitement. Si la fonction n'est pas intégrée, ELOas utilise l'intégration standard qui donne chaque document en traitement.

L'exemple montre une intégration qui traite seulement les mails non-lus. Elle peut être utilisée dans l'intégration finalizelmap nommée ci-dessus, elle ne supprime pas les mails traités, mais qui les marque comme étant lus.

Remarque

Si vous travaillez avec cette méthode, vous devez vous assurer que la boîte de réception ne soit pas trop volumineuse (par exemple par une suppression automatique après une durée précise).

nextImap_GMAIL: function() {
    if (MAIL_POINTER > 0) {
        mail.finalizePreviousMessage(MAIL_MESSAGE);
    }
    for (;;) {
        if (MAIL_POINTER >= MAIL_MESSAGES.length) {
            return false;
        }
        MAIL_MESSAGE = MAIL_MESSAGES[MAIL_POINTER];
        var flags = MAIL_MESSAGE.getFlags();
        if (flags.contains(Flags.Flag.SEEN)) {
            MAIL_POINTER++;
            continue;
        }
        MAIL_ALLOW_DELETE = false;
        MAIL_POINTER++;
        return true;
    }
    return false;
},

Lire le texte du corps du message : la fonction getBodyText() reçoit le message en tant que paramètre (disponible dans le script par le biais de la variable MAIL_MESSAGE) et livre le corps du mail en tant que paramètre de retour. Le premier MIME Part du type TEXT/PLAIN est recherché. S'il n'existe pas de partie correspondante, un string vide est livré.

getBodyText: function(message) {
    var content = message.content;
    if (content instanceof String) {
        return content;
    }   else if (content instanceof Multipart) {
        var cnt = content.getCount();
        for (var i = 0; i < cnt; i++) {
            var part = content.getBodyPart(i);
            var ct = part.contentType;
            if (ct.match("^TEXT/PLAIN") == "TEXT/PLAIN") {
                return part.content;
            }
        }
    }
    return "";
},

Déterminer l'expéditeur : la fonction 'getSender()' livre l'adresse e-mail de l'expéditeur.

getSender: function(message) {
    var adress = message.sender;
    return adress.toString();
},

Déterminer le destinataire : la fonction getRecipients() livre une liste de tous les destinataires (TO et CC). S'il existe plus d'un destinataire, la liste est livrée au format de l'index de colonne, si l'on transfère le symbole de séparation ELO ¶ dans le paramètre delimiter.

getRecipients: function(message, delimiter) {
    var adresses = message.allRecipients;
    var cnt = 0;
    if (adresses) { cnt = adresses.length; }
    var hasMany = cnt > 1;
    var result = "";
    for (var i = 0; i < cnt; i++) {
        if (hasMany) { result = result + delimiter; }
        result = result + adresses[i].toString();
    }
    return result;
}

# Fonctions disponibles pour l'envoi de mails

La fonction envoyer n'est pas utilisée directement par ELOas. Il s'agit de fonctions permettant de simplifier la programmation de script pour masquer la complexité de l'API JavaMail devant le développeur de script.

Authentifier le serveur SMTP : la fonction setSmtpHost() indique à la librairie l'hôte SMTP devant être utilisé. Il est utilisé pour l'envoi mail. Cette fonction doit être activée avant le premier appel sendMail.

setSmtpHost: function(smtpHost) {
    if (MAIL_SMTP_HOST != smtpHost) {
        MAIL_SMTP_HOST = smtpHost;
        MAIL_SESSION = undefined;
    }
},

Envoyer un mail : la fonction sendMail() envoie un e-mail. En tant que paramètre, les adresses des expéditeurs et destinataires sont livrés, ainsi que l'objet et le texte du mail.

sendMail: function(addrFrom, addrTo, subject, body) {
    mail.startSession();
    var msg = new MimeMessage(MAIL_SESSION);
    var inetFrom = new InternetAddress(addrFrom);
    var inetTo = new InternetAddress(addrTo);
    msg.setFrom(inetFrom);
    msg.addRecipient(Message.RecipientType.TO, inetTo);
    msg.setSubject(subject);
    msg.setText(body);
    Transport.send(msg);
},

Envoyer un mail avec pièce-jointe : la fonction sendMailWithAttachment() envoie un mail. En tant que paramètre, l'adresse de l'expéditeur et du destinataire sont livrés, ainsi que l'objet, le texte du mail et l'ID d'objet pour la pièce de l'archive ELO. La pièce-jointe est enregistrée en tant que fichier temporaire dans le chemin temp, il doit donc y avoir assez d'espace.

sendMailWithAttachment: function(addrFrom, addrTo, subject, body, attachId) {
    mail.startSession();
    var temp = fu.getTempFile(attachId);
    var msg = new MimeMessage(MAIL_SESSION);
    var inetFrom = new InternetAddress(addrFrom);
    var inetTo = new InternetAddress(addrTo);
    msg.setFrom(inetFrom);
    msg.addRecipient(Message.RecipientType.TO, inetTo);
    msg.setSubject(subject);
    var textPart = new MimeBodyPart();
    textPart.setContent(body, "text/plain");
    var attachFilePart = new MimeBodyPart();
    attachFilePart.attachFile(temp);
    var mp = new MimeMultipart();
    mp.addBodyPart(textPart);
    mp.addBodyPart(attachFilePart);
    msg.setContent(mp);
    Transport.send(msg);
    temp["delete"]();
}

# fu: File Utils

Les fonctions de la section File Utils assistent l'utilisateur ELOas lors d'opérations de fichier.

# Fonctions disponibles

Purger le nom de fichier : lorsqu'un nom de fichier doit être créé à partir de la désignation, alors celui-ci peut contenir des caractères qui peuvent engendrer des problèmes dans le répertoire des fichiers (par exemple :,\, &). Voilà pourquoi la fonction 'clearSpecialChars' remplace tous les caractères par un underscore, sauf les chiffres et les lettres).

clearSpecialChars: function(fileName) {
    var newFileName = fileName.replaceAll("\\W", "_");
    return newFileName;
},

Charger le fichier document : la fonction getTempFile() charge le fichier document de l'objet ELO indiqué dans le système de fichiers local (dans le classeur temp de ELOas). Si le fichier n'est plus requis, il doit être supprimé par le développeur de script par le biais de la fonction deleteFile. Sinon, il reste sur le disque dur.

Remarque

Il ne s'agit pas d'un nom de fichier, mais d'un objet Java File qui est retourné.

getTempFile: function(sordId) {
    var editInfo = ixConnect.ix().checkoutDoc(sordId, null,
                                              EditInfoC.mbSordDoc, LockC.NO);
    var url = editInfo.document.docs[0].url;
    var ext = "." + editInfo.document.docs[0].ext;
    var name = fu.clearSpecialChars(editInfo.sord.name);
    var temp = File.createTempFile(name, ext);
    log.debug("Temp file: " + temp.getAbsolutePath());
    ixConnect.download(url, temp);
    return temp;
},

Supprimer le fichier : la fonction deleteFile() attend un objet Java File comme paramètre (pas de string) et supprime ce fichier.

deleteFile: function(delFile) {
    delFile["delete"]();
}

# run: Runtime Utilities

Ce module contient des routines permettant d'accéder à Java Runtime. A partir de là, vous pouvez démarrer des processus externes ou demander des informations sur l'état actuel de la mémoire.

Démarrer le processus :: la commande execute(command) permet de démarrer un processus externe. ELOas attend la clôture de cet appel et poursuit ensuite le traitement. Ainsi, vous pouvez évaluer les actions de ce processus.

log.debug("Process: " + NAME );
run.execute("C:\\ Tools\\BAT\\dirlist.bat");
log.debug("Read Result");
var txt = dex.asString("dirlist.txt");

Demander une mémoire libre et disponible : les commandes freeMemory() et maxMemory() servent à afficher la mémoire actuellement disponible et la mémoire disponible au maximum.

log.debug "freeMemory: " + run.freeMemory() +
        ", maxMemory: " + run.maxMemory());
Dernière mise à jour: 26 septembre 2023 à 07:46