6286F5AEA6C04F0E98E89747A5A921A2
  • Holm Gehre
  • 20.08.2018
  • DE

Erstellen von Iolets und Weblets

Wer mit dem OTWSM Delivery Server arbeitet, wird früher oder später (in den meisten Fällen aber doch früher) auf Schlagworte wie: Iolet, Weblet, OpenAPI treffen und versuchen den Einstieg in diese Materie zu finden - meist aber nur mit sehr sehr kleinem oder mäßigem Erfolg.

Die Ursachen für diese "Misserfolge" sind sicherlich vielschichtig. So wird, zumindest ist das meine Auffassung, in der Dokumentation zur OpenAPI ganz rudimentär auf die Entwicklung eigener Iolets oder Weblets eingegangen, da der Hauptfokus dieser Dokumentation in der Beschreibung zur Verfügung stehender Klassen, deren Eigenschaft und Methoden liegt und sich somit eher an erfahrene Javaentwickler wendet.
Youtube-Videos, Usergroup-Workshops oder bestenfalls Bücher mit dem Titel: "OTWSM Delivery Server OpenAPI für Neu- oder Quereinsteiger" sucht man leider vergebens.

Die nachfolgende "Schritt für Schritt" - Anleitung zeigt die Entwicklung und Implementierung von "Hello World" als Iolet und Weblet.
 

Allgemeines Vorab - Überblick

Die Ein-/Anbindung von Weblets und/oder Iolets erfordert das lizenzierte OpenAPI - Modul.

Iolet und Weblet unterscheiden sich hauptsächlich darin, dass Weblets direkt über einen URL-Pfad (z.B. /cps/[rde]/exampleweblet) aufgerufen, Iolets hingegen über das Iolet-Dynament angesprochen, werden.
Ein weiterer Untschied ist der Zugriff auf Backend-Komponenten, der den Iolets vorbehalten ist bzw. vorbehalten sein sollte, auch wenn euch alle Java-Ressourcen bei der Entwicklung von Weblets zur Verfügung stehen.

Für die Erstellung/Entwicklung von Iolets oder Weblets sind die oben genannte Lizenz, grundlegende Java-Kenntnisse und eine betriebsbereite Java-Entwicklungsumgebung (IDE) (z.B Eclipse, IntelliJ, NetBeans) sowie der erlaubte Zugriff, sowohl auf das Dateisystem als auch auf die Weboberfläche, des OTWSM-Delivery Servers Voraussetzung. Bei der Entwicklung von Weblets kann es u.U. dazu kommen, dass der OTWSM Delivery Server (z.B. Windowsdienst) neu gestartet werden muss.


Hinweis: Um die nachfolgenden Beispiele in einer eigenen Umgebung "nachzubauen" ist eine Anbindung der OpenAPI Java-Bibliotheken erforderlich. Ihr könnt diese entweder vom OTWSM Delivery Server kopieren oder als Netzlaufwerk referenzieren.
Die beiden Java-Bibliotheken: "rdls-rde-[OTWSM-DS-Release].jar" und "rdls-openapi-[OTWSM-DS-Version].jar" aus dem Verzeichnis: "..\webapps\cps\WEB-INF\lib\", sowie die Bibliothek "javax.servlet-api-[Version].jar" aus dem Verzeichnis "..\webapps\cps\WEB-INF\helper\lib" (für die Entwicklung von Weblets), sind für das Kompilieren zwingend erforderlich.


Weblets

Weblets sind direkt über einen URL-Pfad aufrufbar und werden daher sehr häufig für die Bereitstellung von Services (z.B. Zieladresse für das Hochladen von Dateien, Seitenweiterleitungen, RESTfull API) eingesetzt. Innerhalb des Weblet-Codes können auch Iolets aufgerufen und diesem Paramter übergeben werden.

Wenn ihr in eurer IDE ein Projekt erstellt und die oben genannten Bibliotheken angebunden habt, solltet ihr das nachfolgende Beispiel fehlerfrei kompilieren können.

package org.owug.otwsm.weblets;

import de.reddot.api.web.io.*;
import de.reddot.api.web.weblet.*;
import de.reddot.api.common.session.CoaSession;

public class ExampleWeblet extends WebletAdapter {

    public final void handleRequest(CoaSession session,
                                    WebletRequest request,
                                    WebletResponse response) throws Exception {

        response.getHttpServletResponse().setStatus(200);
        StringBuilder sb = new StringBuilder();
        sb.append("<HTML>\n<BODY>\n");
        sb.append("Hello World\n");
        sb.append("</BODY>\n</HTML>\n");
        response.printString(sb.toString(), false, "text/html");
    }
}

Ich lasse in der Regel das Kompilierungsergebnis (CLASS-Datei/en) zu einem JAR-File (Archiv) zusammenpacken. Das hat den Vorteil, dass ich nicht mehrere CLASS-Dateien in verschiedenen Ordnern auf den OTWSM Delivery Server kopieren und via "Hot Deployment" ansprechen muss.
Die Ablage im Ordner "modules" ist bei mir ein Relikt aus der Zeit des "Reddot LiveServers" und nicht zwingend notwenig.

Die anschließende "Hot Deployment" - Anbindung des Weblets sollte keine große Hürde mehr darstellen. Falls doch - ein Blick in die OTWSM Delivery Server Hilfe lohnt an dieser Stelle.

Sollte der anschließende Testaufruf von: http(s)://[otwsm-ds-url]/cps/ExampleWeblet nicht das nachfolgende Bild zeigen, kann es hilfreich sein, den OTWSM Delivery Server neu zu starten.

Ausgabe des Weblets
 


Iolets

Iolets haben direkten Zugriff auf Backend-Komponenten (z.B. externe Datenbanken, LDAPs, Warenwirtschafts- oder CRM-Systeme etc.). Weiterhin können Iolets auf das Repository des OTWSM Delivery Servers zugreifen, um bespielsweise Benutzer- oder Inhaltsdaten zu lesen oder zu schreiben. Sie werden in der Regel über das Iolet-Dynament angesprochen.

Für Iolets gilt: Jede Methode muss mit dem Präfix "do" beginnen. Der Dynamentaufruf einer Methode des Iolets erfolgt hingegen ohne das "do".

Das nachfolgende Iolet "ExampleIolet" enthält die 3 Methoden "doSayHelloWold", "doSayHelloWoldParam" und "doSayHelloWoldLog".

  • doSayHelloWold:
    • erwartet keine Parameter
    • Rückgabe: "<h1>Hello World!</h1>"
  • doSayHelloWoldParam:
    • 2 Parameter können übergeben werden
    • Rückgabe: "<h1>Hello World! for [PARAMETER_1] [PARAMETER_2]</h1>"
  • doSayHelloWoldLog:
    • 2 Paramter können übergeben werden
    • Rückgabe: "<h1>Hello World! for [PARAMETER_1] [PARAMETER_2]</h1>"
    • schreibt einen Eintrag ins OTWSM DS Logfile (Kategorie: info)
package org.owug.otwsm.iolets;

import de.reddot.api.app.io.*;
import de.reddot.api.app.iolet.IoletAdapter;
import de.reddot.api.common.session.CoaSession;

import org.owug.otwsm.services.LogServices;

public class ExampleIolet extends IoletAdapter {

    // declare log services
    private static final LogServices log = LogServices.getInstance("SayHelloWorldLogIolet");

    public IoletResponse doSayHelloWorld(CoaSession session, 
                                         IoletRequest req) throws Exception
    {
        String result = "<h1>Hello World!</h1>";
        IoletResponse response = IoletResponseFactory.getIoletResponse( result );
        return( response );
    }

    public IoletResponse doSayHelloWorldParam(CoaSession session, 
                                              IoletRequest req) throws Exception
    {
        String value1 = req.getParameter("param1" );
        String value2 = req.getParameter("param2" );

        String result = "<h1>Hello World! for " + value1 + " " + value2 +"</h1>";
        IoletResponse response = IoletResponseFactory.getIoletResponse( result );
        return( response );
    }

    public IoletResponse doSayHelloWorldLog(CoaSession session, 
                                            IoletRequest req) throws Exception
    {
        String value1 = req.getParameter("param1" );
        String value2 = req.getParameter("param2" );

        String result = "<h1>Hello World! for " + value1 + " " + value2 +"</h1>";
        IoletResponse response = IoletResponseFactory.getIoletResponse( result );
        log.info("SayHelloWorldLog has been called");
        return( response );
    }
}

Für das Logging wird eine eigene Klasse, in meinem Beispiel die Klasse "LogService", benötigt. Nachfolgend der Quellcode dieser Klasse.

package org.owug.otwsm.services;

import de.reddot.logging.api.*;
import de.reddot.logging.model.Level;
import de.reddot.logging.model.LoggerId;

public class LogServices {
    private static String LOG_LINE_PREFIX = "*** OWUG OTWSM DS-Extention - ";
    private static String LOG_LINE_SUFFIX = " ***";
    private static LogServices instance = null;

    private Logger logger;

    private LogServices(String loggerName) {
        LoggerId loggerId = new LoggerId(loggerName);
        logger = LoggerFactory.getLogger(loggerId);
    }
    public static LogServices getInstance(String loggerName) {
        if(LogServices.instance == null) {
            LogServices.instance = new LogServices(loggerName);
        }
        return instance;
    }
    public void log(String msg) {
        logger.log(Level.INFO, LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX);
    }
    public void log(String msg, Throwable e) {
        logger.log(Level.INFO, LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX, e);
    }
    public void fatal(String msg) {
        logger.fatal(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX);
    }
    public void fatal(String msg, Throwable e) {
        logger.fatal(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX, e);
    }
    public void error(String msg) {
        logger.error(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX);
    }
    public void error(String msg, Throwable e) {
        logger.error(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX, e);
    }
    public void warn(String msg) {
        logger.warn(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX);
    }
    public void warn(String msg, Throwable e) {
        logger.warn(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX, e);
    }
    public void info(String msg) {
        logger.info(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX);
    }
    public void info(String msg, Throwable e) {
        logger.info(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX, e);
    }
    public void debug(String msg) {
        logger.debug(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX);
    }
    public void debug(String msg, Throwable e) {
        logger.debug(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX, e);
    }
    public void trace(String msg) {
        logger.trace(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX);
    }
    public void trace(String msg, Throwable e) {
        logger.trace(LOG_LINE_PREFIX + msg + LOG_LINE_SUFFIX, e);
    }
}

Aufgerufen werden die Iolets in der OTWSM Delivery Server Seite "iolet.htm".

<html>
  <head>
    <title>Test</title>
  </head>
  <body>
    <!-- Aufruf von doSayHelloWorld -->
    <p>Das Ergebnis aus dem Iolet "SayHelloWorld" lautet:</p>
    <rde-dm:iolet name="ExampleIolet" method="SayHelloWorld" response-prefix="" tag="notag" result-attribute="err">
    </rde-dm:iolet>
    <!-- Aufruf von doSayHelloWorldParam -->
    <p>Das Ergebnis aus dem Iolet "SayHelloWorldParam" lautet:</p>
    <rde-dm:iolet name="ExampleIolet" method="SayHelloWorldParam" response-prefix="" tag="notag" result-attribute="err">
      <rde-rd:parameters>
        <rde-rd:parameter name="param1">[#request:var1#Holm#]</rde-rd:parameter>
        <rde-rd:parameter name="param2">[#request:var2#Gehre#]</rde-rd:parameter>
      </rde-rd:parameters>
    </rde-dm:iolet>
    <!-- Aufruf von doSayHelloWorldLog -->
    <p>Das Ergebnis aus dem Iolet "SayHelloWorldLog" lautet:</p>
    <rde-dm:iolet name="ExampleIolet" method="SayHelloWorldLog" response-prefix="" tag="notag" result-attribute="err">
      <rde-rd:parameters>
        <rde-rd:parameter name="param1">[#request:var3#LogEntry#]</rde-rd:parameter>
        <rde-rd:parameter name="param2">[#request:var4#]</rde-rd:parameter>
      </rde-rd:parameters>
    </rde-dm:iolet>
  </body>
</html>

Das Ergebnis der Iolet-Aufrufe:

Ausgabe Iolet

Für das Schreiben von Einträgen in das Logfile habe ich mich auf die Logkategorie (Loglevel) "Info" beschränkt.

log.info("SayHelloWorldLog has been called");

Um die Logeinträge auch im Logfile aufzuführen, ist (in der Log-Konfiguration das OTWSM Delivery Servers) das Level für diesen benannten Service entsprechend zu konfigurieren.

LogServices.getInstance("SayHelloWorldLogIolet");

Die nachfolgenden Einträge zum Aufruf des Iolets können dann erst im "rde.log" gefunden werden.

Logfile


Fazit

Bei Weblets, Iolets und Inlinefunktionen handelt es sich um in Java programmierte Erweiterungen. Bei der Entwicklung dieser Erweiterungen sollte immer beachtet werden, dass die verwendete Java-Version für die Kompilierung der des OTWMSM Delivery Servers entspricht und nicht überschreitet.

Bei der Entwicklung von Iolets ist zu beachten, dass alle Methoden, die später aufgerufen werden können bzw.sollen, den Präfix "do" tragen.

Abschließend sollte bei einem Update oder Upgrade des OTWSM Delivery Servers immmer geprüft werden, ob alle Erweiterungen vorhanden und lauffähig sind. Auch gibt es immer mal wieder Änderungen in der OpenAPI, so dass manche Klassen oder Methoden als "deprecated" gekennzeichnet und in späteren Versionen ganz entfernt werden.


Über den Autor:
Holm Gehre

Holm Gehre ist seit Mitte 2017 Senior Softwareentwickler und Projektleiter bei CHEFS CULINAR und betreut dort mit seinem Team die Opentext-Plattform. Seit dem Jahr 2001 und bis Mitte des Jahres 2017 betreute und entwickelte er Opentext- (vormals RedDot-) basierte Webseiten nationaler und internationaler Kunden auf Basis von Management und Delivery Server.