SAGA D.C. GmbH > SAGA.M31 - Galaxy
 

Erstellen einer Java Anwendung mit Hilfe des M31.Galaxy Eclipse Plugins

Dieses Tutorial beschreibt das erstellen einer Java-Anwendung, in die Daten aus einem SAGA.M31 Galaxy-Server integriert werden.

Anforderungen

Um dem Tutorial zu folgen muss...

  ... der Eclipse Plugin heruntergeladen und installiert werden. Das Paket steht unter http://galaxy.sagadc.com/ bereit und beinhaltet eine kurze Beschreibung der Installation

  ... entschieden werden, ob ein eigener Server aufgesetzt wird, oder unser Demo Server unter http://galaxy.sagadc.com/Galaxy/wui genutzt werden soll.

Im ersten Fall sind die folgenden Schritte erforderlich:

  • Herunterladen des Installationspaketes von http://galaxy.sagadc.com und folgen der Installationsanweisungen, die in dem Paket enthalten sind.
  • Dem FirstSteps Tutorial folgen, um die benötigten Tabellen und Conatiner zu erstellen

Erstellen der Beispielapplikation mit Eclipse

Dieser Abschnitt beschreibt den Aufbau der Beispielapplikation mit Hilfe des M31.Galaxy Eclipse Plugins.

Zunächst muss ein neues Java Projekt im Eclipse Workspace erstellt werden. Im Tutorial heißt das Projekt GalaxySampleApp, dieser Name kann allerdings frei gewählt werden

Als nächstes müssen die Galaxy Runtime Bibliotheken zum Klassenpfad des Projektes hinzugefügt werden. Diese finden sich im Installationspaket des Plugins in dem Archiv GalaxyRuntime.zip. Dieses muss in ein beliebiges Verzeichnis entpackt und die enthalten Bibliotheken zum Projekt hinzugefügt werden. Anschließend sollte das Projekt etwa so aussehen:

Add Libraries

Um nun die Funktionalität des Plugins in diesem Projekt zu nutzen, muss in seinem Kontextmenü der Eintrag "Add Galaxy support" ausgewählt werden:

Add Galaxy Support

Hier durch wird die Konfigurationsdatei "galaxy.cfg.xml" erstellt:

Support Created

Darüber hinaus wird der im Plugin enthaltene Editor geöffnet:

Galaxy Editor

Um die Funktionsweise des Editors verstehen zu können, wird zunächst die eigentliche GalaxyAPI sowie ihre Konfiguration beschrieben.

Die GalaxyAPI und ihre Konfiguration

M31.Galaxy stellt eine kleine Java API bereit, die den Zugriff auf M31.Galaxy Server erleichtert.

Sie übernimmt hierbei die folgenden Aufgaben:

  • Spezifizierung der benötigten eingehenden Felder
  • Erstellen der XML-Struktur für die Anfrage
  • Senden der Anfrage
  • Lesen der XML-Antwort
  • Übersetzen der Antwort in Java Strukturen

Auf diese Weise wird die Handhabung der XML-Strukturen, sowie die Kommunikation mit den Servern vereinfacht und der Quellcode eines Projektes kann sich auf seine eigentliche Aufgabe beschränken.

Funktionsweise der API

Im Großen und Ganzen gibt es zwei wichtige Java-Typen:

  • com.sagadc.galaxy.api.GalaxyRequest
  • com.sagadc.galaxy.api.GalaxyFactory

GalaxyRequest

Zunächst gibt es das Interface com.sagadc.galaxy.api.GalaxyRequest, das Methoden definiert, die zum Absetzen einer Containeranfrage benötigt werden.

Wichtig sind hierbei vor allen:

  • addInputItem(String itemName, Object itemValue)

    Eingabefelder, die bei einer Containeranfrage benötigt werden, müssen mit Hilfe dieser Methode spezifiziert werden. Der Parameter itemName definiert hierbei den Namen des Eingabefeldes, der Parameter itemValue den Wert für dieses Feld.

  • doRequest()

    Setzt die Anfrage gegen den M31.Galaxy Server ab. Hierbei wird zunächst eine XML-Struktur erstellt, an den Server gesendet und die empfangene Antwort in eine Objektstruktur aus Maps und Listen umgesetzt.

  • getReturnCode() und getMessage()

    Nach Aufruf der Methode doRequest() kann über diese Methoden abgefragt werden, ob der Container erfolgreich abgearbeitet wurde.

    Wenn getReturnCode() den Wert 0 zurückliefert, so sind keine Felher während der Anfrage aufgetreten. Die zurückgelieferten Felder können gelesen werden. Wird ein Wert > 0 zurückgegeben, ist es während der Ausführung zu einem Fehler gekommen. Die Methode getMessage() liefert dann detailliertere Informationen zu dem aufgetretenen Fehler.

    Der Returncode sollte nach jedem Request abgefragt werden, um die korrekte Funktionsweise einer Applikation sicherzustellen.

  • getOutputItem(String itemName)

    Nachdem doRequest() ordnungsgemäß durchlaufen wurde, kann über diese Methode auf die zurückgelieferten Ausgabefelder zugegriffen werden. Mit dem Parameter itemName wird der Name des gewünschten Feldes definiert, der Rückgabewert repräsentiert den Inhalt des Feldes. Das zurückgelieferte Objekt kann, abhängig von der Definition des Containerfeldes unterschiedlichen Typs sein. In dieser Version existieren die folgenden Containerfeldtyen zur Verfügung:

    • String

      Der Rückgabewert ist vom Typ java.lang.String

    • Tabelle

      Der Rückgabewert ist vom Typ java.util.List wobei jedes Element der Liste eine Zeile der Tabelle repräsentiert. Jede Zeile wiederum ist eine Instanz des Typs java.util.Map. Jeder Schlüssel der Map steht für eine Spalte der Tabelle, und der zugeordnete Wert für den Inhalt der entsprechenden Zelle.

  • getOutputItems()

    Gibt eine Instanz des Interfraces java.util.Map zurück, die alle zurückgelieferten Felder beinhaltet. Die Schlüssel der Map repräsentieren hierbei die Feldnamen, die zugeordneten Werte entsprechen den Inhalten der Felder. Diese Methode stellt lediglich einen alternativen Zugriff auf die zurückgelieferten Felder dar, der Aufruf getOutputItem("aItem") liefert hierbei exakt das selbe Ergebnis wie getOutputItems().get("aItem").

Die anderen Methoden des Interfaces GalaxyRequest werden im Normalfall nicht benötigt, sie werden intern von der Factory genutzt, um den Request zu initialisieren.

GalaxyFactory

Der zweite Typ der API ist com.sagadc.galaxy.api.GalaxyFactory, eine Factory, die Instanzen des GalaxyRequests erstellt.

Die Klasse stellt eine statische Methode, getFactoryInstance(), zur Verfügung, um eine Referenz auf eine Instanz der Klasse zu beziehen. Auf diesem Wege ist es nicht nötig, Referenzen auf die Factory im eigenen Quellcode zu halten. Die Implementierung dieser Funktion bedient sich der so genannten lazy instantiation, was heißt, dass nur der erste Aufruf der Funktion wirklich eine Instanz der Klasse erzeugt und die Konfigurationdatei ließt. Bei allen weiteren Aufrufen wird diese Instanz erneut zurückgeliefert.

Bei erstellen der Instanz versucht die Factory, die Galaxy-Konfigurationsdatei zu laden. Im Normalfall heißt diese "galaxy.cfg.xml", und wird an der Wurzel des Klassenpfades gesucht. Beim Auswählen des Menüpunktes "Add Galaxy Support" wurde genau diese Datei erstellt.

Die Konfigurationsdatei (galaxy.cfg.xml)

Bevor wir näher auf die Funktionalität der Factory eingehen, wird hier kurz der Inhalt der Kofigurationsdatei beschrieben:

[1] <galaxy-factory>
[2]    <servers>

        <server id="SampleServer">
          <url>http://an.m31.server.de/Galaxy</url>
          <username>admin</username>
          <password>e03239b27e34a5f7f3bde739459dd537</password>

        </server>

        [... more servers here ...]

      </servers>
[3]   <requests>
        <request id="TestRequest" target="SampleServer">
          <containername>ContainerLDAP</containername>

        </request>

        [... more requests here ...]

      </requests>
    </galaxy-factory>
    

Beispiel der Datei galaxy.cfg.xml

Die Konfigurationsdatei ist in zwei Abschnitte unterteilt, die unterhalb des Abschnittes "galaxy-factory" [1] angesiedelt sind.

Im ersten Abschnitt [2] werden alle Server aufgelistet, auf die von dieser Konfiguration aus zugegriffen werden kann. Die folgenden Eigenschaften sind für jeden Server definiert:

id Ein sprechender Name für den Server, der von der Request-Sektion [3] referenziert wird
url Die Basis URL des Servers, hieraus wird später die URL für den Endpunkt des XML-Services erstellt
username Der Benutzername, der genutzt wird, um sich gegenüber des Server zu identifizieren
password Die MD5 Checksumme des Passwortes das den Benutzer authentifiziert

Der zweite Abschnitt[3] definiert die Anfragen die später innerhalb des Projektes genutzt werden können. Jede Anfrage definiert die folgenden Eigenschaften;

id Der Name der Anfrage. Innerhalb des Quellcodes wird dieser Name genutzt, um die Anfrage einzubinden
target Die id des Servers, gegen den die Anfrage abgewickelt werden soll
containername Das Handle des Containers der mit dieser Anfrage angesprochen werden soll

Eine Instanz eines GalaxyRequest über die Factory beziehen

Nachdem die Struktur der Konfiguration erläutert wurde, sollte auch die Funktion der Factory leicht nachzuvollziehen sein:

Im Quellcode wird die Factory nach der Instanz einer Anfrage gefragt, und liefert eine initialisierte Instanz des GalaxyRequests zurück. Dies geschieht mit Hilfe der Methode getRequest(String requestName) wobei der Name der gewünschten Anfrage als requestName übergeben wird.

Die Factory schaut nun in ihrer Konfiguration nach, ob eine Anfrage mit dem übergebenen Namen existiert. Wenn dies der Fall ist, so wird eine Instanz des GalaxyRequests erstellt und mit dem Containernamen initialisiert. Anschließend wird der Server gesucht, der dieser Anfrage zugeordnet ist. Seine Eigenschaften url, username und password werden dem erstellten GalaxyRequest-Objekt zugewiesen.

Nun, da das erstellte Objekt die Basisadresse des Server kennt (url), wie es sich authentifizieren muss (username and password) und was es tun soll (containername), ist es bereit, zurückgegeben und genutzt zu werden.

Genug der Theorie, wie funktioniert das ganze jetzt?

Geduld, es müssen nur noch die Anfragen konfiguriert werden, die in unserem Beispiel genutzt werden sollen

Dies geschieht mit Hilfe des Galaxy-Editors, der Bestandteil des Plugins ist. Hier besteht sowohl die Möglichkeit, Anfragen und Server über ein Benutzerinterface zu definieren, als auch die Konfigurationsdatei in der Quellansicht direkt zu editieren. Links unten am Editor kann zwischen diesen beiden Ansichten gewechselt werden

Zunächst muss ein Server definiert werden, dies geschieht über das Kontextmenü des "Explore Servers" Bereiches:

Add Server

Nach Auswahl des Punktes "Add Server", öffnet sich der folgende Dialog:

Add Server Dialog

Hier muss ein Name für den Server vergeben sowie die benötigten Parameter Base URL (Die Adresse des M31.Galaxy Servers), username und password angegeben werden. Anschließend wird der Server mit einem Klick auf OK hinzugefügt.

Sollte kein eigener Server zur Verfügung stehen, so kann über die folgenden Einstellungen unser Demoserver angesprochen werden:

Base URL: http://galaxy.sagadc.com/Galaxy
Username: sample
Password: sample

Dieser Server stellt alle benötigten Container zur Verfügung, um die Beispielappliktion auszuführen

Der Name des Servers erscheint als erweiterbarer Eintrag innerhalb der Serverliste. Beim erweitern dieses Eintrages werden alle auf diesem Server verfügbaren Container aufgelistet, die dem definierten Benutzer zur Verfügung stehen. Durch erneutes erweitern der Container können deren Eingabe- und Ausgabefelder angezeigt werden.

Um nun eine Anfrage zu erstellen befindet sich im Kontextmenü der Container der Eintrag "Create Request". Dieser Muss nun für den Container "All Users TSC Inc." ausgewählt werden.

Create Request

Nach der Auswahl wird ein Dialog geöffnet, in den der Name des Containers einzutragen ist, im Falle des Beispieles "TSOUserList". Nach Betätigung des Buttons "OK" ist die erstellte Anfrage in der Anfragenliste zu sehen.

Unter Wiederholung der letzten Schritte muss nun noch eine weiter Anfrage mit dem Namen "TSOUserDetails" erstellt werden, diesmal basierend auf dem Container "User Contact Details TSC Inc." .

Die Requestliste sollte nun zwei Einträge enthalten:

Configured Requests

Nach Speichern der Konfigurationsdatei mit Ctrl-S, ist die GalaxyFactory fertig konfiguriert und wir können uns der Beispielapplikation zuwenden.

Die Beispielapplikation

Nach Abschluss der Konfigurationsarbeiten kann mit der Umsetzung der Applikation begonnen werden.

Die Quelle die auf dieser Seite gezeigt wird, wurde auf die wesentlichen Abschnitte reduziert, die die Funktionsweise der API demonstrieren. Die Methoden getUserSelection() und checkReturncode() werden hier nicht gezeigt, sind aber in der kompletten Quelle der Beispielapplikation aufgeführt

Werfen wir einen Blick auf die Implementierung des Beispieles:

public class GalaxySample
{

    //Input/Output fields, defined by Galaxy
    private static final String OUT_LASTNAME = "LastName";
    private static final String OUT_FIRSTNAME = "FirstName";
    private static final String CONTACTID = "ContactId";
    
    //Request names, defined by galaxy.cfg.xml
    private static final String REQUEST_TSC_USERLIST = "TSCUserList";
    private static final String REQUEST_TSC_DETAILS = "TSCUserDetails";

    public static void main(String[] args) {
        /*
         * [1] Get the request called REQUEST_TSC_USERLIST from the factory
         */
        GalaxyRequest listRequest = GalaxyFactory
                                        .getFactoryInstance()
                                        .getRequest(REQUEST_TSC_USERLIST);

        /*
         * [2] Run the request (No input fields are required)
         */
        listRequest.doRequest();
        checkReturncode(listRequest);


        /*
         * [3] Get the item, which represents the user table
         */
        List userTable = (List) listRequest.getOutputItem("UserTSCInc");

        /*
         * Print the list of user
         */

        System.out.println("List of all users:");
        System.out.println("------------------");
        for(int i = 0; i &lt; userTable.size(); i++)
        {
            Map currentRow = (Map) userTable.get(i);
            System.out.println(i + ": "
                                 + currentRow.get(OUT_FIRSTNAME)
                                 + " "
                                 + currentRow.get(OUT_LASTNAME));
        }
        System.out.println("------------------");

        /*
         * [4] Get the users selection
         */
        int selection = getUserSelection(userTable.size());

        /*
         * [5] Fetch the ID and shoot another request to get the details of the selected user
         */
        Map selectedUser = (Map) userTable.get(selection);
        Object selectedUsersId = selectedUser.get(CONTACTID);

        /*
         * [6] Get the Request called REQUEST_TSC_DETAILS
         */
        GalaxyRequest detailRequest = GalaxyFactory
                                            .getFactoryInstance()
                                            .getRequest(REQUEST_TSC_DETAILS);

        /*
         * [7] Add the selected users id as inputItem
         */
        detailRequest.addInputItem(CONTACTID, selectedUsersId);

        /*
         * Trigger the request (see [2])
         */
        detailRequest.doRequest();
        checkReturncode(detailRequest);

        /*
         * [8] Print out all outcomming items for the selected user
         */
        Map userDetails = detailRequest.getOutputItems();
        Iterator keys = userDetails.keySet().iterator();

        System.out.println();
        System.out.println("Details for selected User:");
        System.out.println("--------------------------");
        while(keys.hasNext())
        {
            String currentKey = keys.next().toString();
            System.out.println(currentKey + ": " + userDetails.get(currentKey));
        }
        System.out.println("--------------------------");

    }
    [...]
}

        

Comments

[1] Erstellen der Anfrage "TSCUserList"mit Hilfe der Factory (Get the request called "TSCUserList" from the factory)

Durch Aufruf der statischen Methode getFactoryInstance() der GalaxyFactory wird eine Referenz auf eine Instanz der GalaxyFactory zurückgegeben, welche seine Konfiguration aus der Datei "galaxy.cfg.xml" ließt. Auf dieser Instanz wird über die Methode getRequest() eine Instanz der Anfrage "TSCUserList" angefordert.

[2] Auslösen der Anfrage (Run the request (No input fields are required))

Die Methode doRequest() löst die Containerabfrage am SAGA.M31 - Galaxy Server aus. Da der Container "TSCUserList" ohne Eingabefelder funktioniert, ist es nicht notwendig, vorher solche über die Methode addInputItem() zu definieren (Siehe Kommentar 17)

[3] Feld lesen, das die Benutzertabelle beinhaltet (Get the item, which represents the user table)

Da wir von der Containerdefinition wissen, dass der Typ des Feldes "UserTSCInc" eine Tabelle ist, können wir das zurückgelieferte Objekt sicher in eine java.util.List casten (Eine Liste repräsentiert die Galaxy Tabellen).

Jedes Element dieser Liste wird vom Typ java.util.Map (repräsentiert eine Tabellenzeile) sein, wobei die Schlüssel/Wertpaare die einzelnen Zellen repräsentieren. Wir können nun einfach über diese Liste iterieren und dabei jeweils den Wert zum Schlüssel "FirstName" und "LastName" der entsprechenden Map auf der Konsole ausgeben.

[4] Benutzereingabe lesen (Get the users selection)

Die Methode wird hier nicht näher besprochen, sie dient lediglich dazu die Eingabe des Benutzers entgegenzunehmen.

[5] Id des selektierten Eintrages lesen und an einen weiteren Container übergeben, um details eines Benutzers zu lesen (Fetch the ID and shoot another request to get the details of the selected user)

An diesem Punkt kommt die Eingabe des Benutzers ins Spiel. Das ausgewählte Element (der Typ ist eine Map) wird aus der Liste gelesen und dessen Wert zum Schlüssel "ContactId" zwischengespeichert. Da dieser Lediglich an die Methode addInputItem() weitergegeben wird, die ein java.lang.Object entgegennimmt, kann er auch als ein solches gespeichert werden.

[6] Anfrage "TSCDetails" erstellen lassen (Get the Request called "TSCDetails")

Erneut wird mit Hilfe der Factory eine Anfrage erstellt, diesmal um die Detaildaten des Benutzers zu lesen.

[7] Benötigte Eingabefelder definieren (Add the selected users id as inputItem)

Diesmal werden vom Container Eingabefelder benötigt, nämlich die Id des Benutzers, dessen Details ausgelesen werden sollen. Dieser wurde vorher vom Benutzer bestimmt. Eingabefelder werden mit Hilfe der Funktion addInputItem() definiert. Der erste Parameter steht hierbei für den Namen des Eingabefeldes, der zweite für seinen Wert (die ID des ausgewählten Benutzers)

[8] Ausgabe aller zurückgegebenen Felder (Print out all returned items for the selected user)

Per getOutputItems() werden alle zurückgelieferten Felder als Map ausgelesen. Da die Felder diesmal keine Tabellen enthalten, kann einfach über die Schlüssel der Map iteriert werden und dabei sowohl der Schlüssel, als auch der assoziierte Wert ausgegeben werden. Hierdurch werden alle Felder, die der Container geliefert hat ausgegeben.

Test der Beispielapplikation

Nach dem der Quellcode fertig gestellt ist, kann das Programm in der Eclipse Umgebung über "Run"->"Run as"->"Java application" gestartet werden. Wenn die Applikation nach der Nummer des Benutzers fragt, muss ein gültiger Wert eingegeben werden, und die Applikation wird die Detaildaten für diesen Benutzer auflisten:

Run the sample

Gratulation, Sie haben soeben Ihre erste SAGA M31.Galaxy gestützte Applikation entwickelt.

Sollten beim durcharbeiten dieses Tutorials Fragen oder Probleme auftreten, oder gibt es Anregungen zu unserem Produkt so sind wir entweder über galaxy@sagadc.com oder unsere Website http://www.sagadc.de/de/aboutus/contact.php jederzeit für Sie da.