32 Version A.04.02.a

32.1 Verschlüsselung im JAVA WSI

Aus der Server-Client-Architektur der Java-Version des IDM ergibt sich die Forderung nach einer Verschlüsselung der Kommunikation zwischen Server und Client. Da die Kommunikation zwischen beiden Teilen auch über eine Internetverbindung erfolgen kann, soll mit der Verschlüsselung erreicht werden, dass geheimzuhaltende Daten, wie z. B. Passwörter nicht im Klartext übers Netz gehen.

In dem Unterverzeichnis javassl befindet sich ein Beispiel einer IDM-Anwendung, die eine Verschlüsselungssoftware für die Kommunikation benützt.

Die Java-Version des IDM besteht aus Java-Server und Java-Client. Die Kommunikation zwischen beiden erfolgt über eine TCP/IP-Verbindung ohne Verschlüsselung, siehe folgende Abbildung.

In dem Beispiel in javassl wird sowohl auf Server- als auch auf Client-Seite noch eine Verschlüsselungssoftware dazwischengeschaltet, siehe folgende Abbildung.

Als Beispiel für den Einbau einer Verschlüsselung wurde die Software C/SSL v2.1 und J/SSL v2.0 der Firma Baltimore Technologies verwendet.

Informationen unter http://www.baltimore.com/products/jssl/sslintro.html

Die C/SSL-API ist in C geschrieben und wird für die Kommunikation auf Java-WSI-Server-Seite verwendet, die J/SSL-API liegt in Java vor und wird für die Kommunikation auf Java-WSI-Client-Seite eingesetzt.

Beide Softwarepakete entsprechen der Version 3.0 von SSL und bieten Schutz gegen eine PKCS#1 Attacke.

Getestet wurde die Software unter dem Betriebssystem UNIX, Sparc Solaris 2.6

32.1.1 Funktionsweise von SSL

SSL wurde von Netscape entwickelt.

SSL (Secure Sockets Layer) ist ein Kommunikationssystem, das Geheimhaltung garantiert, wenn es mit anderen SSL-fähigen Produkten kommuniziert. SSL ist ein Protokoll, das oberhalb des TCP/IP-Protokolls und unterhalb von Top-Level-Protokollen wie HTTP läuft. Zur Überprüfung und Bestätigung der Identität der Kommunikationspartner wird asymmetrische Verschlüsselung zusammen mit Zertifikaten verwendet. Für die eigentliche Kommunikation wird symmetrische Verschlüsselung benützt. Eine SSL-Verbindung kann nur zwischen einem SSL-fähigen Client und einem SSL-fähigen Server stattfinden.

Eine genaue Beschreibung des Datenaustausches mittels SSL kann unter http://developer.netscape.com/tech/security/ssl/howitworks.html nachgelesen werden.

In dieser Dokumentation ist beschrieben, welche Schritte notwendig sind, um eine Anwendung mit dem IDM zu erstellen, die innerhalb der Kommunikation der Java-Schnittstelle des IDM eine Verschlüsselungssoftware benützt. Zum Test wurde die Software C/SSL und J/SSL von Baltimore Technologies benutzt.

32.1.2 Verschlüsselung auf Server-Seite

Um die Verschlüsselungssoftware zu benützen, muss man eine Anwendung mit dem IDM bauen. In der Funktion AppMain muss die Funktion DM_InstallWSINetHandler zur Registrierung der benutzerdefinierten Funktionen aufgerufen werden.

Weiterhin müssen benutzerdefinierte Funktionen innerhalb der Anwendung definiert werden, die die notwendigen Verschlüsselungsroutinen aufrufen. Resultatwert und Parameter der benutzerdefinierten Funktionen sind vorgegeben.

32.1.3 Die Schnittstellenfunktion DM_InstallWSINetHandler

Mit dieser Funktion der DM-Schnittstelle werden die benutzerdefinierten Funktionen, in denen die Verschlüsselungssoftware aufgerufen wird, registriert.

Diese Funktion muss in AppMain vor DM_Initialize aufgerufen werden.

Resultatwert und Parameter der benutzerdefinierten Funktionen sind vorgegeben.

Syntax

DM_Boolean DML_default DM_EXPORT DM_InstallWSINetHandler
(

  DM_WSINetFunctions *wsinetfunctions,

  DM_Uint Operation,

  DM_Options Options

)

-> DM_ WSINetFunctions *wsinetfunctions

Struktur, die die Funktionszeiger auf die benutzerdefinierten Funktionen enthält. Sie hat folgende Form:

DM_WSINetFunctions

{

  DMAcceptProc,

  DM_SessionProc,

  DM_ShutDownProc,

  DM_OpenProc,

  DM_CloseProc,

  DM_SendProc,

  DM_ExistsMessageProc,

  DM_RecvProc,

  DM_FreeWarningProc
}

Die einzelnen Funktionstypen haben folgende Form:

int <name of DM_AcceptProc function>
  (int serverfd,void *cliaddr,void *addrlen,char *message)

 

void * <name of DM_SessionProc function>
  (int clientfd,void *support,char *message)

 

void<name of DM_ShutDownProc function>()

 

int<name of DM_OpenProc function
  (int *port,void **supportptr,char *message,char **warning)

 

int <name of DM_CloseProc function>
  (void *connptr,int *clientfd,char *message)

 

int <name of DM_SendProc function>
  (void *connptr,char *buffer,int length,char message)

 

int<name of DM_ExistsMessageProc function>
  (void *connptr,char *message)

 

int <name of DM_Recv function>
  (void *connptr,char *buffer,int count,char *message)

 

void<name of DM_FreeWarningProc function>
  (char *warning)

-> DM_Uint Operation

Eine von den zwei vordefinierten Konstanten:

  1. DMF_RegisterHandler zum Registrieren der benutzerdefinierten Funktionen.
  2. DMF_WithdrawHandler zum Deregistrieren der benutzerdefinierten Funktionen.

-> DM_Options Options

Wird nicht benutzt und ist mit 0 vorzubelegen:

Rückgabewert

TRUE

Für DMF_RegisterHandler: Funktionen konnten registriert werden.

Für DMF_WithdrawHandler: Rückgabewert immer TRUE.

FALSE

Für DMF_RegisterHandler: Funktionen konnten nicht registriert werden.

32.1.4 Benutzerdefinierte Funktionen

Beschreibung der einzelnen Funktionen:

Reihenfolge des Aufrufs ist normalerweise

  1. DM_OpenProc function
  2. DM_FreeWarningProc function
  3. DM_AcceptProc function
  4. DM_SessionProc function
  5. DM_SendProc function, DM_Recv function, DM_ExistsMessageProc function im Wechsel
  6. DM_CloseProc function
  7. DM_ShutDownProc function

Falls eine eigene Verschlüsselung mit Hilfe der benutzerdefinierten Funktionen verwirklicht werden soll, muss beim Benützen der Parameter als Ein- und Ausgabe die vom IDM vorgegebene Reihenfolge der Aufrufe berücksichtigt werden.

32.1.5 Beispiel

Im Verzeichnis javassl ist in encode.c eine Anwendung mit dem IDM für Verschlüsselung auf Server-Seite zu finden. Es wird ein SSL-Socket auf Java-Server-Seite aufgebaut. Die Kommunikation wird mit Hilfe der Software-Pakete C/SSL und J/SSL der Firma Baltimore Technologies verschlüsselt.

32.1.5.1 Verschlüsselung auf Client-Seite

Die Verschlüsselung auf Client-Seite erfolgt über eine Java-Klasse, die einen Socket mit verschlüsselter Kommunikation aufbaut.

Der Name der Klasse ist frei wählbar und kann beim Starten des IDM auf Client-Seite mittels eines Parameters übergeben werden.

Der Name der Methode, die den verschlüsselten Socket aufbaut, muss CreateSocket sein mit folgender Syntax:

public void CreateSocket (String host, int port, boolean isapplet, URL url, String jsslpath, String certificate)

Parameter

-> host

Name des Hosts

-> port

Nummer des Ports

-> isapplet

true, wenn der Client als Applet gestartet wurde.

false, wenn der Client als Applikation gestartet wurde.

-> url

URL des Applets

-> jsslpath

String, der über den Parameter idm.jsslpath angegeben wurde.

-> certificate

String, der über den Parameter idm.certificate angegeben wurde.

Um eine IDM-Anwendung mit eigener Verschlüsselungsklasse zu bauen, muss man folgendes tun:

32.1.5.2 Beispiel

idmuser/EncodeClass.java

Diese Klasse ist ein Beispiel für den Aufbau eines SSL-Sockets auf Client-Seite mit Hilfe der Software J/SSL von Baltimore Technologies. Sie befindet sich im Verzeichnis javassl/idmuser. Diese Klasse wird beim Starten des Clients der IDM-Anwendung (siehe unten) mit Hilfe des Parameters idm.encode angegeben. Der Name des Packages und der Name der Klasse sind nicht festgelegt. Allerdings muss die Verschlüsselungsklasse neben dem Konstruktor zum Aufbau des Sockets eine Methode mit dem Namen CreateSocket enthalten.

Im Beispiel ist auskommentierter Programmcode für Client authentication, d.h. Beglaubigung des Clients, enthalten. Dieser Teil des Beispiels kann verwendet werden, er wurde aber nie ausgetestet.

32.1.5.2.1 Bauen des Beispiels zur Verschlüsselung

Um das Beispiel der IDM-Anwendung, bestehend aus encode.c und idmuser/EncodeClass.java, unter UNIX zu bauen, gibt es im Verzeichnis javassl den Makefile Makefile. Für den Bau der IDM-Anwendung unter Windows muss der Makefile entsprechend angepasst werden.

Vorgehensweise

  1. Anpassen der Variablen des Makefiles

    • CSSL_PATH

      Pfad für das Verzeichnis, in dem die Libraries für die Verschlüsselungssoftware für den Server liegen., z.B. /cssl/debug oder /cssl/release.

    • CSSL_PATHDATA

      Pfad für das Verzeichnis, in dem die Zertifikate liegen und in das Daten zwischengespeichert werden dürfen, also mit Schreibberechtigung, z.B./cssl/data.

    • CSSL_INCLUDE

      Pfad für das Verzeichnis, in dem sich die Include-Files  befinden.

    • JAVA_HOME

      Pfad für das Home-Verzeichnis für die Java-Bibliothek.

    • SWING_HOME

      Pfad für das Home-Verzeichnis für die Swing-Bibliothek.

    • JSSL_HOME

      Pfad für  das Verzeichnis, in dem die Verschlüsselungssoftware für den Client liegt, z.B. /jssl.

    • CLASS_NAME

      Package und Name der Java-Klasse, in der die Verschlüsselung auf Client-Seite  realisiert wird, z.B. idmuser/EncodeClass.

  2. IDM_HOMEDIR

    Der File IDM_HOMEDIR im übergeordneten Verzeichnis muss den richtigen Pfad für das Home-Verzeichnis des IDM enthalten.

  3. Bauen mit make

    Mit diesem Kommando wird ein ausführbarer Client gebaut.

    Für den Server werden aus dem ausgelieferten jar-File für den IDM die Klassen extrahiert, die eigene Klasse – im Beispiel EncodeClass.java – wird kompiliert und alle Klassen inklusive der eigenen werden zu einem neuen jar-File idm_encode.jar zusammengepackt.

    Voraussetzung

    Das Verzeichnis, in dem dieser Bauprozess durchgeführt wird, muss Schreibberechtigung haben, da ein Unterverzeichnis mit dem Namen idmjava und ein Unterverzeichnis mit dem Namen META-INF angelegt wird.

32.1.5.2.1.1 Erzeugung von Zertifikaten

Um das gebaute Beispiel starten zu können, ist es notwendig, ein Zertifikat für den Server zu besitzen. Für eine kommerzielle Anwendung ist es unbedingt notwendig, ein Zertifikat für den Server bei einer Zertifizierungsbehörde zu beantragen.

Nur zu Testzwecken können Schlüssel und Zertifikate lokal mit entsprechender Software erzeugt werden. Dafür kann das von Baltimore Technologies mit der C/SSL-Software ausgelieferte UNIX-Shell-Script makecerts.sh oder das Script makecerts.bat für Windows benützt werden.

32.1.5.3 Start des Beispiels zur Verschlüsselung

  1. Start des Servers

    cd javassl

    encode <Optionen> <Dialogfile>

    Mit diesem Befehl wird der Server gestartet. Die Optionen sind dieselben wie beim Starten des Java-Servers mit dem Befehl idmjava.

    Zum Testen kann der Dialogfile IDM_HOMEDIR/lib/IDM/bestelldienst.idm verwendet werden.

  2. Start des Java-Clients als Applikation

    cd demos/javassl

    java –classpath ./idm_encode.jar:<JAVA_HOME>:<SWING_HOME>:<JSSL_HOME>/applet/jssl.jar:<JSSL_HOME>/applet/jcrypto.jar

      <Optionen>

      -Didm.encode=<Package . Name der Verschlüsselungsklasse>

      -Didm.jsslpath <Pfad für Zertifikat>

      -Didm.certificate <Name des Zertifikates>

    idmjava.idm

    Mit diesem Befehl wird der Client – die Klasse idmjava.idm - gestartet.

    JAVA_HOME, SWING_HOME, JSSL_HOME haben dieselbe Bedeutung wie die Variablen im Makefile Makefile für den Bau des Beispiels, siehe oben.

    Die Optionen <Optionen> sind dieselben wie beim Starten des Dialog Manager Java-Clients.

    Die Option:

    • idm.encode gibt den Pfad der Klasse an, die die Verschlüsselung erledigt. Wird die Klasse nicht gefunden, wird ein unverschlüsselter Socket aufgebaut, Beispiel für diesen Parameter idm.encode=“idmuser.EncodeClass“.
    • idm.jsslpath gibt den Pfad des Verzeichnisses an, in dem sich die Zertifikate und andere von der Verschlüsselungssoftware zwischengespeicherte Daten befinden, Beispiel /cssl/data.

      Achtung

      Dieser Pfad muss auf dasselbe Verzeichnis zeigen wie CSSL_PATHDATA im Makefile Makefile.

    • idm.certificate gibt den Namen des Zertifikat-Files an, Beispiel caCerts.pem.

    Wenn die Kommunikation zwischen Client und Server verschlüsselt ist, erscheint nach dem Start des Clients die Meldung Encoded connection auf dem Bildschirm.

  3. Start des Java-Clients als Applet

    Auf dem Web-Server müssen sich folgende Files befinden:

    • HTML-Seite, z.B. idmapplet.html (mit Veränderungen, siehe unten)
    • caCerts.pem aus C/SSL von Baltimore Technologies oder andere Identitätsfiles
    • idm_encode.jar
    • jcrypto.jar aus der Subdirectory applet der Software J/SSL von Baltimore Technologies
    • jssl.jar aus der Subdirectory applet der Software J/SSL von Baltimore Technologies

    Der <APPLET>-tag in der HTML-Seite sieht genauso aus wie beim Dialog Manager Java-Client mit folgenden Ausnahmen:

    ARCHIVE=idm_encode.jar; jcrypto.jar; jssl.jar

    <PARAM NAME =“idm.encode“ VALUE=“Package . Name der Verschlüsselungsklasse“>

    <PARAM NAME =“idm.jsslpath“ VALUE=“Pfad für Zertifikat“>

    <PARAM NAME =“idm.certificate“ VALUE=“Name des Zertifikates“>

    Die Bedeutung der Parameter ist dieselbe wie beim Starten des Clients als Applikation.

  4. Kommando, um Server und Client als Applikation zu starten

    Um Java-Server und Java-Client mit verschlüsselter Kommunikation zu starten, kann man das Kommando make run verwenden.

    Um Java-Server und Java-Client mit normaler, also unverschlüsselter Kommunikation zu starten, kann man das Kommando make normal verwenden.

32.2 Änderungen bei der Objektreferenzierung

Dieses Kapitel beschäftigt sich mit der Beziehung zwischen Objekten und ihren Bezeichnern sowie der Referenzierung von Objekten.

32.2.1 Hierarchie

Der IDM verwaltet Objekte eines Moduls hierarchisch. An oberster Stelle steht dabei das in der Datei definierte Modul. Importierte Objekte sind für das importierende Modul hierarchisch unterhalb des Imports gegliedert.

Beispiel: Folgendes Modul

module M                        => Hierarchie

export model pushbutton MPb {}     M

export window Wi {                 +-MPb

  export MPb Pb {}                 +-Wi

  MPb Pb2 {}                          +-Pb

}                                    +-Pb2

wird von einem Dialog verwendet. Rechterhand ist die Hierarchie der zugreifbaren Objekte aufgezeigt.

dialog D          => Hierarchie
import I “m.if”;  D

window Wi2        +-I
{                 | +-MPb
  MPb Pb {}       | +-Wi

}                 |   +- Pb
                  +-Wi2
                    +-Pb

32.2.2 Bezeichner

Jedes Objekt in einem Modul besitzt einen symbolischen Namen, einen Bezeichner. Der Bezeichner ist entweder durch den Anwender gesetzt worden oder vom Modell geerbt (Ausnahmen siehe Kapitel „Geerbte Bezeichner und Modularisierung“).

In der gleichen Hierarchieebene (Objekte mit dem gleichen Vater) können Objekte mit dem gleichen Bezeichner zwar existieren, es darf aber nur einer gesetzt sein (wird vom IDM sichergestellt). Ausnahmen, Problemstellen und Fehler siehe auch Kapitel „Hinweise auf Problemstellen und Probleme der Vorgängerversionen“ und „Bekannte Fehler/Probleme des IDM“.

Der Unterschied zwischen einem gesetzten und einem geerbten Bezeichner ist die Referenzierbarkeit. Ein geerbter Bezeichner muss durch einen Pfad referenziert werden, bei einem gesetzten eindeutigen Bezeichner kann dies auch nur durch den Bezeichner selbst geschehen.

dialog D

model pushbutton MPb {}  // Bezeichner MPb ist gesetzt, verweist auf Modell
window Wi {

  child MPb Pb1 {}       // Gesetzter Bezeichner
  child MPb {}          // Vom Modell geerbt, nur über Pfad referenzierbar

}
window Wi2 {
  child pushbutton Pb1 {} // Gesetzter Bezeichner, Pb1 ist nun mehrdeutig
  child MPb Pb2 {}        // Gesetzter Bezeichner

  child MPb Pb2 {}      // Nicht möglich, da auf gleicher Hierarchieebene.
                          // Warnung wird erzeugt, dass der Bezeichner nicht
                          // gesetzt werden kann => man erhält den
                          // geerbten Bezeichner MPb.
  child MPb {}
}

on dialog start {
  MPb.text:=“Ok”;       // Bezeichner eindeutig, ergibt Modell
  Wi.MPb.text:=“Okay”;  // Obj. mit geerbtem Bezeichner (Pfad verwenden)
  Pb1.text:=“Exit”;     // Erzeugt einen Fehler da Pb1 mehrdeutig ist
  Wi.Pb1.text:=“Exit”;  // Eindeutiger Zugriff über Pfade möglich

  Wi2.Pb1.text:=“Beenden”;

  Wi2.Pb2.text:=”Start”;// Zugriff auf ersten Pb2
  Wi2.MPb.text:=”Stop”; // Zugriff auf Objekt mit nicht setzbarem Bez.
  Wi2.MPb:[2].text:=”Aus”; // Zugriff auf 2. Obj. mit gleichem Bezeichner
  exit();
}

Nicht nur Objekte werden durch einen Bezeichner benannt, sondern auch benutzerdefinierte Attribute. Allerdings kann ein Attribut nicht referenziert werden, sondern es kann nur auf seinen Inhalt zugegriffen werden. Die Regel „In einer Hierarchieebene darf ein Bezeichner nur einmal gesetzt sein“ schließt nicht nur Kindobjekte sondern auch Attribute und Methoden mit ein!

dialog D
window Wi {
  integer Pb := 123;
  // pushbutton Pb {} // FEHLER – Bezeichner existiert schon an Wi
}
window Wi2 {
  pushbutton Pb {} // Keine Mehrdeutigkeit mit Attribut .Pb an Wi
}
on dialog start {
  print Pb;   // eindeutig das Objekt Wi2.Pb
  print Wi.Pb; // Zugriff auf den Wert des Attributes .Pb
  print Wi2.Pb; // Referenzierung des Kindobjektes
  exit();
}

Das Modularisierungskonzept des IDM beschränkt nur die Referenzierungen von Objekten von außen, nicht den Zugriff auf benannte Attribute und Methoden. Aus diesem Grund können/müssen Attribute nicht exportiert werden.

32.2.3 Eindeutigkeit und Mehrdeutigkeit

Der Bezeichner des Moduls ist immer eindeutig. Mehrdeutigkeit besteht, wenn mehrere Objekte in der Hierarchie (gemäß „Hierarchie“ auch importierte Objekte) den gleichen Bezeichner gesetzt haben.

module M                               // M ist immer eindeutig das Modul
export function string Func(integer);  // Im Modul eindeutig
export window Wi {                     // Wi ist eindeutig
  export pushbutton Pb {}
}
export window Wi2 {                    // Wi2 nach außen eindeutig
export pushbutton Pb {}               // Pb schon im Interface mehrdeutig
window Wi2 {}                         // Wi2 im Modul mehrdeutig
}
on module start {
  print Func(987);
  M.Wi2.Wi2 := “Wi2 privat”;           // Zugriff auf Wi2 nur über Pfad
}

Besteht eine Mehrdeutigkeit, so können die Objekte mit mehrdeutigen Bezeichnern durch eindeutige Pfade referenziert werden. Das muss in diesem Beispiel für den Pushbutton Pb der Fenster Wi und Wi2 und WiMain geschehen.

dialog D                              // D ist immer eindeutig der Dialog
import I “m.if”;                      // I ist eindeutig
export function integer Func(string); // Func ist mehrdeutig
window WiMain {                       // WiMain ist eindeutig
  pushbutton Pb {}                    // Pb ist mehrdeutig(1.Pb aus import)
}
on dialog start {
  print D.Func(“Hello”);            // Zugriffe auf Func über Pfad
  print I.Func(123);
  WiMain.Pb:=”Ok”;                  // Zugriff über Pfad, da Pb mehrdeutig
  Wi.title:=”Wi”;                   // Zugriffe nur über Bezeichner
  Wi.Pb:=”Ok”;
  Wi2:=”Wi2”;

// Pb.text := “PB”;
// FEHLER: Mehrdeutiger Zugriff, auskommentiert, da Fehlermeldung kommen
// wuerde und Dialog nicht ladbar wird.

  exit();
}

32.2.4 Referenzierung und Referenzierungsfehler

Innerhalb eines Moduls ist ein Zugriff, z.B. in Regeln oder bei der statischen Instanziierung, auf benannte Objekt durch deren Bezeichner oder durch einen Pfad möglich. Referenzierbar in diesem Sinne sind aber nur Objekte innerhalb des Moduls bzw. importierte Objekte.

Ein Pfad ist dabei eine Kette von Bezeichnern, angefangen von einem eindeutigen Bezeichner (z.B. durch den Modul-Namen). Ist in einer Hierarchieebene ein Bezeichner mehrfach verwendet worden so ist der Zugriff auf die Objekte mit geerbtem Bezeichner durch ein Suffix der Form „:[I]“ möglich,  wobei 1<I<A (A=Anzahl Objekte mit gleichem Bezeichner & Vater) ist. Grundsätzlich kann aber auch ein eindeutig bezeichenbares Objekt mit einem Pfad referenziert werden.

Pfade werden erst am Ende des Ladevorganges eines Moduls aufgelöst. Stimmt der Bezeichner nicht, erhält man eine Fehlermeldung in der Form „Cannot Resolve...“.

Ist ein Bezeichner oder der erste Bezeichner eines Pfades mehrdeutig, so erhält man einen Hinweis auf die Mehrdeutigkeit mit „Cannot Resolve ... Label is not unique“.

Bei solchen Fehlermeldungen muss zuerst der Fehler durch Richtigstellung des Bezeichners oder durch Auflösung der Mehrdeutigkeit mittels eindeutigem Pfad korrigiert werden.

Beim Schreiben eines Dialoges/Moduls, z.B. aus dem Editor heraus oder beim Binärformat, wird immer der kleinste eindeutige Pfad herausgeschrieben/verwendet.

Neben diesen absoluten Pfaden ist es auch möglich relative Pfade, die z.B. vom this-Objekt oder einer lokalen Variablen oder einem Parameter ausgehen, anzugeben. Die Auflösung dieser Pfade kann erst zur Ausführungszeit geschehen. Insofern kann beim Ladevorgang keine Fehlermeldung oder Warnung für solche Pfadangaben gebracht werden, da sie u.U. erst zur Laufzeit gültig sind.

dialog D
model pushbutton MPb {}
window Wi {
  pushbutton Pb {}
  MPb Pb2 {}

}
window Wi2 {
  MPb Pb2 {}
  MPb {}              // Erhält geerbten Namen MPb vom Modell
  MPb {
     record R1 {}
  }
  checkbox {}         // Erhält geerbten Default-Namen CHECKBOX
}

on dialog start {
  Wi.title:=”Wi”;     // Zugriff über eindeutigen Bezeichner
  D.Wi.title:=”WI”;   // Ebenso Zugriff über Pfad möglich
  D.WI.title:=”WI”;   // FEHLER – Kann nicht aufgelöst werden!
  this.Wi.title:=”wi”;// Relativer Zugriff, Auflösung zur Laufzeit
  this.WI.title:=”WI”;// Relativer Zugriff, Semantisch Falsch, aber Ladbar.
  Wi.Pb2.text:=”Ok1”; // Pfad notwendig da mehrdeutig
  D.Wi2.Pb2.text:=”Ok2”; // Pfad ist übereindeutig, D kann man weglassen
  Wi2.MPb.text:=”Ok1”;// Zugriff
  exit();
}

32.2.5 Geerbte Bezeichner und Modularisierung

Wenn exportierte Objekte einen geerbten Bezeichner haben, so wird normalerweise diese „Vererbung“ auch nach außen in die importierenden Module getragen. dass heißt konkret, dass ein exportiertes Objekt mit geerbtem Bezeichner nur durch einen Pfad referenziert werden kann.

Nun kann nach außen hin diese „Vererbung“ des Bezeichners gestoppt werden, indem das Modell des exportierten Objektes nicht ebenso vom Modul exportiert wird. Das hat nun aber zur Folge das solch ein exportiertes Kind ebenfalls eine Referenzierung aufweist und damit sofort eine Mehrdeutigkeit besteht, da Modell und Kind den gleichen Bezeichner haben und unterschiedliche Objekte referenzieren.

Diese Konstellation ist im folgenden Modul mit dem Modell MPb und dessen Instanzierungen als hierarchische Kinder nachgestellt.

module M

export model pushbutton MPb {}
export model radiobutton MRb {}
model checkbox MCb {}
export model groupbox MGb {

  child MPb {}          // #1
  export child MPb {}   // #2
  export child MRb {}

}
export model MGb2 {
  export .MPb {}    // Damit wird ist #1 gemeint

  export child MCb {}
}

Die Auswirkungen, dass das MPb zwar innerhalb des Moduls, aber nicht nach außen hin eindeutig ist, wird aber erst in der Verwendung zu erkennen. Am Kind MCb wird gezeigt, dass ein Objekt mit einem geerbten Bezeichner nach außen hin einen „gesetzten“ Bezeichner besitzt und damit über seinen Namen ansprechbar wird.

dialog D

import I “m.if”;
on dialog start
{

  print MRb;  // Eindeutig da exportiertes Kind MGb.MRb einen geerbten
              // Bezeichner hat (da ja das Modell ebenfalls exportiert ist)
 
  // print MPb;  FEHLER – Mehrdeutig da Bezeichner MPb auch MGb2.MPb
  // referenzier da dessen Modell nicht exportiert ist.
  print I.MPb;  // Referenziert das Modell
  print MGb.MPb; // Referenziert #2 vom Modell MGb

  print MGb2.MPb; // Referenziert #1 vom Modell MGb2

  print MCb; // Referenziert Kind von MGb2 absolut trotz des geerbten
             // Bezeichners, da das Modell nicht exportiert wurde.

  exit();
}

Es ist grundsätzlich sinnvoll, exportierten Kindern einen Namen zu geben, der sich vom Modell unterscheidet, um den dargelegten Problematiken aus dem Weg zu gehen.

32.2.6 Exportierte Imports

Imports, die wieder exportiert werden erfahren eine Sonderbehandlung. Die Bezeichner dieser Imports werden nach außen hin wie geerbte Bezeichner behandelt. Zusätzlich erhält ein importierendes Modul alle exportierten Imports der importierten Module direkt unterhalb des Moduls/Dialoges.

Ziel ist es, Import nicht als Hierarchie erscheinen zu lassen sondern alle direkt als „Kinder“ des Dialoges, selbst wenn sie über „export import“ aus einem importierten Modul stammen.

Folgendes Beispiel veranschaulicht die Situation.

module M1
export import I2 “m2.if”;

export model pushbutton MPb {}

M1 Exportiert ebenso die Objekte aus M2.

module M2;

export model window MWi {}

Im M1 importierenden Dialog ist ein Zugriff auf die exportierten Objekte aus M2 ebenfalls möglich.

dialog D

import I1 “m1.if”;
MWi Wi { MPb {} }
window I2 {}  // WARNUNG – Bezeichner kann nicht gesetzt werden,
              //           da durch I1 der Bezeichner I2 schon als
              //           import I2 unterhalb des Dialoges herkommt.
on dialog start {
  print I1;   // Referenziert den Import D.I1, Bezeichner I1 ist eindeutig
  print I1;   // Referenziert den Import D.I2, Bezeichner I2 ist eindeutig
  print D.I1;   // Referenziert den Import I1
  print D.I2;   // Referenziert den Import I2
  print I1.I2   // Referenzierung über Pfad ebenfalls möglich
  exit;
}

32.2.7 Überlagerung durch lokale Bezeichner

Innerhalb einer Regel überlagern Bezeichner von lokalen Variablen und Parametern die Objekt-Bezeichner und unterbinden somit die Mehrdeutigkeit.

dialog D
window W {}
rule void Rule(object W) {
  variable integer D:=123;
  print “D=”+D;
  print “W=”+W;

}
on dialog start {
  Rule(D);  //  => Ausgabe  “D=123”
  exit();   //              “W=D”
}

32.2.8 Hinweise auf Problemstellen und Probleme der Vorgängerversionen

Folgenden Hinweise sollen zum Erkennen & Vermeiden von Problemstellen in vorhandenen Dialogen helfen. Die Vorgängerversionen des IDM hatten folgende Problemstellen:

Beispiel

dialog D
function string F1();

function integer F1();  // wurde noch mit A.04.01.c akzeptiert

window Wi {

groupbox Gb {
    pushbutton Pb { .text “#1”; }

  }
}

model window MWi {
  groupbox Gb {
    pushbutton Pb {.text “#2”; }

  }
}
on dialog start
{
  print Pb.text; // ergibt #1, obwohl Pb mehrdeutig.
  // Nach speichern (mit –writedialog) und erneutem Simulieren => #2

  exit();
}

32.2.9 Auswirkungen für IDM-Anwendungen (also für die Kunden)

Wegen den geschilderten Problemen in „Hinweise auf Problemstellen und Probleme der Vorgängerversionen“ können Dialoge zunächst nicht ladbar sein. Zuerst müssen die Mehrdeutigkeiten aufgelöst werden. Dies kann entweder von Hand geschehen oder unter Zuhilfenahme des IDM-Simulationsprogramms.

32.2.10 Startoptionen und Umgebung

Für Notfälle gibt es noch für eine gewisse Zeit die Umgebungsvariable IDM_LABEL_STRICT. Wird diese auf false gesetzt, wird die Erkennung der Mehrdeutigkeit ausgeschaltet (Zu beachten – diese wird nur einmal initial ausgewertet). Dadurch können Dialoge mit Mehrdeutigkeiten ladbar gemacht werden.

Um bei vorhandenen Mehrdeutigkeiten in den Dialogen/Modulen eine Anwendung zu einer eindeutigen Referenzierung zu migrieren kann die Option ‑slack beim Simulationsprogramm IDM verwendet werden. Dadurch wird vor dem Laden des Dialoges die Erkennung von Mehrdeutigkeiten ausgeschaltet (altes Verhalten). Nach dem Laden wird wieder entsprechend dem Wert der Umgebungsvariablen IDM_LABEL_STRICT die Erkennung ein/ausgeschaltet.

Durch Kombination von ‑slack mit ‑writedialog kann ein solches Modul mit unaufgelösten Mehrdeutigkeiten in ein Modul mit eindeutiger Referenzierung überführt werden.

32.2.11 Bekannte Fehler/Probleme des IDM

Es gibt Operationen, wie z.B. das Anlegen eines benannten Objektes, Setzen des Bezeichners oder Umhängen zu einem andern Vater, für die es notwendig wird, festzustellen, ob dieser Bezeichner schon in der Hierarchieebene existiert. Diese Überprüfung berücksichtigt die Vererbung des Bezeichners nicht.

Das hat zur Folge, dass, wie in folgendem Beispiel aufgezeigt, im Fall (a) der Bezeichner MPb (#3) nicht gesetzt werden kann, da der Bezeichner durch ein geerbtes hierarchisches Kind in der Instanz Wi vorhanden ist. Im Fall (b) ist wiederum der Normalfall aufgezeigt (kein geerbter Bezeichner vorhanden), bei dem die Setzung des Bezeichners möglich ist.

dialog D
model pushbutton MPb {};
model window MWi {
  MPb {}                  // #1

}
MWi Wi {                  // Wi erbt ueber MWi das Kind MPb (#2)
  pushbutton MPb {}       // #3 – WARNING - Bezeichner MPb an Wi schon
                          // vorhanden ueber das geerbt. hier. Kind .MPb

}
window Wi2 {
  MPb MPb {}   // #4
  D.MPb {}     // #5
}
on dialog start {

  // (a)
  print Wi.MPb;        // referenziert #2.
  print Wi.PUSHBUTTON; // referenziert #3.
  // (b)
  print Wi2.MPb;       // referenziert #4
  print Wi2.MPb:[1];   // referenziert #5
  exit();
}

32.3 Die Layoutbox

Sehr oft hat man das Problem, dass Objekte oder Bausteine von Objekten angeordnet werden müssen.

Dies ist von Hand zwar möglich, jedoch

falls sich irgendwelche Objekte in ihrer Größe oder Position ändern.

Hier schafft die Layoutbox Abhilfe, Sie ist ein Containerobjekt, in das die anzuordnenden Objekte/Bausteine einfach hineingeworfen werden können. Diese werden automatisch, überschneidungsfrei angeordnet.

Die Layoutbox versucht, die Objekte nacheinander anzuordnen, passt ein Objekt nicht mehr in eine Zeile / Spalte, so wird es in die Nächste platziert.

Es wird außerdem dafür gesorgt, dass alle Objekte erreichbar sind, d.h. wenn ein Objekt nicht mehr sichtbar dargestellt werden kann (z.B. weil das Vaterfenster zu klein ist), werden Scrollbars eingefügt.Die virtuellen Größen der Layoutbox werden (solange wrap true ist) immer gesetzt. Sie können nicht beeinflusst werden, können jedoch abgefragt werden um die Arbeitsfläche herauszubekommen, d.h. die virtuellen Größen können kleiner oder größer sein als die wirklichen Größen.

Eine Spaltenbreite oder Zeilenhöhe wird immer nach dem größten Objekt der jeweiligen Spalte/Zeile bestimmt. Alle anderen Objekte richten sich dann entsprechend aus.

Falls zeilenweise ausgerichtet wird, wird yauto auf die Zeilenhöhe bezogen. xauto hat keine Bedeutung, da die Objekte grundsätzlich im gleichen Abstand nacheinander angeordnet werden.

32.3.1 Objektdefinition

Definition

{export} layoutbox {<Identifikator>}
{
  <Attributklassen>
}

Ereignisse

extevent

dbselect

help

hscroll

key

paste

scroll

select

vscroll

Kinder

Canvas

Checkbox

Combobox

Control

Editierbarer Text

Groupbox

Bild

Layoutbox

Listbox

Menübox

Notebook

Pushbutton

Radiobutton

Record

Rectangle

Scrollbar

Spinbox

Splitbox

Statictext

Tablefield

Treeview

Vater

Dialog

Fenster

Groupbox

Layoutbox

Module

Splitbox

Toolbar

Notepage

Control

Menü

Popup

32.3.2 Attribute

32.3.2.1 Neue Attribute

Attribut

Datentyp

Wertebereich

Eigenschaften

Kurzbeschreibung

direction

integer

1 .. 2

SGCI

Die Ausrichtung der auszurichtenden Objekte kann mit .direction = 2 zeilenweise oder mit .direction = 1 spaltenweise gewählt werden. Der Defaultwert ist 2.

wrap

boolean

true/false

SGCI

Bestimmt, ob eine Neuberechnung der Kinder stattfinden muss, wenn die Layoutbox die Größe ändert (z.B. durch ein Resize).

mincolwidth

integer

0..65536

SGCI

Gilt für spaltenweise ausgerichtet: Gibt die Mindestbreite für ein Objekt mit .xauto = 0 an, falls sich kein anderes Objekt oder nur noch weitere Objekte mit .xauto = 0 in der jeweiligen Spalte befinden.

Dieses Attribut wird für zeilenweise ausgerichtet ignoriert.

minrowheight

integer

0..65536

SGCI

Gilt für zeilenweise ausgerichtet: Gibt die Mindesthöhe für ein Objekt mit .yauto = 0 an, falls sich kein anderes Objekt oder nur noch weitere Objekte mit .yauto = 0 in der jeweiligen Zeile befinden.

Dieses Attribut wird für spaltenweise ausgerichtet ignoriert.

xmargin

integer

0..65536

SGCI

Gibt den rechten und linken Rand innerhalb der Layoutbox an.

ymargin

integer

0..65536

SGCI

Gibt den oberen und unteren Rand innerhalb der Layoutbox an.

xspacing

integer

0..65536

SGCI

Gibt den horizontalen Abstand der Kindobjekte untereinander an.

yspacing

integer

0..65536

SGCI

Gibt den vertikalen Abstand der Kindobjekte untereinander an.

32.3.3 Detailbeschreibung Attribute

32.3.3.1 Neue Attribute

32.3.3.1.1 direction
 

Regelsprache

C

COBOL

Eigenschaften

Identifikator

direction

AT_direction

AT-direction

SGCI

Datentyp

integer

DT_integer

DT-integer

 

Wertebereich:

1..2

Defaultwert:

2 (Zeilenweise)

Klassifizierung:

Objektspezifisches Attribut

Mit diesem Attribut kann die Ausrichtungsart festgelegt werden.

Es stehen 2 Möglichkeiten zur Auswahl:

32.3.3.1.2 wrap
 

Regelsprache

C

COBOL

Eigenschaften

Identifikator

wrap

AT_wrap

AT-wrap

SGCI

Datentyp

boolean

DT_boolean

DT-boolean

 

Wertebereich:

true/false

Defaultwert:

true

Klassifizierung:

Objektspezifisches Attribut

Mit diesem Attribut kann der Umbruch ein- und ausgeschaltet werden.

Umbruch heißt, dass bei einer Größenänderung oder Änderung des visible-Attributs der Layoutbox die Kinder gegebenenfalls neu sortiert werden, damit die Kinder alle sichtbar, bzw. erreichbar bleiben.

Wenn der Umbruch ausgeschaltet wird, werden keine Änderungen mehr durchgeführt (z.B. Änderungen an den Attributen der Layoutbox direction, .ymargin, .xmargin...  oder deren Kindern).

Falls der Umbruch von Anfang an ausgeschaltet ist, werden die Objekte von der Layoutbox nicht angeordnet.

32.3.3.1.3 xspacing
 

Regelsprache

C

COBOL

Eigenschaften

Identifikator

xspacing

AT_xspacing

AT-xspacing

SGCI

Datentyp

integer

DT_integer

DT-integer

 

Wertebereich:

0..65536

Defaultwert:

0

Klassifizierung:

Objektspezifisches Attribut

Mit diesem Attribut kann der horizontale Abstand zwischen den Kindern der Layoutbox angegeben werden.

32.3.3.1.4 yspacing
 

Regelsprache

C

COBOL

Eigenschaften

Identifikator

yspacing

AT_yspacing

AT-yspacing

SGCI

Datentyp

integer

DT_integer

DT-integer

 

Wertebereich:

0..65536

Defaultwert:

0

Klassifizierung:

Objektspezifisches Attribut

Mit diesem Attribut kann der vertikale Abstand zwischen den Kindern der Layoutbox angegeben werden.

32.3.3.1.5 xmargin
 

Regelsprache

C

COBOL

Eigenschaften

Identifikator

xmargin

AT_xmargin

AT-xmargin

G

Datentyp

Integer

DT_integer

DT-integer

 

Wertebereich:

0..65536

Defaultwert:

0

Klassifizierung:

Objektspezifisches Attribut

Mit diesem Attribut kann der rechte und linke Abstand zwischen der Layoutbox und den Kindern angegeben werden.

32.3.3.1.6 ymargin
 

Regelsprache

C

COBOL

Eigenschaften

Identifikator

ymargin

AT_ymargin

AT-ymargin

SGCI

Datentyp

integer

DT_integer

DT-integer

 

Wertebereich:

0..65536

Defaultwert:

0

Klassifizierung:

Objektspezifisches Attribut

Mit diesem Attribut kann der obere und untere Abstand zwischen der Layoutbox und den Kindern angegeben werden.

32.3.4 Hinweise

Es ändern sich für die Kinder der Layoutbox die Bedeutung einiger Attribute:

Attribut

Datentyp

Wertebereich

Eigenschaften

Kurzbeschreibung

.xauto

short

-1 .. 1

 

Bei spaltenweise angeordnet: das Objekt wird in der jeweiligen Spalte angeordnet, deren Breite sich nach dem breitesten Objekt richtet. Für -1 vom linken Rand der Spalte, für 1 vom rechten Rand der Spalte, für 0 wird es auf die Spaltenbreite aufgezogen. Falls nur Objekte mit .xauto = 0 in einer Spalte sein sollten, bekommen sie den Wert .mincolwidth zugewiesen.

Für zeilenweise hat dieses Attribut keine Bedeutung.

.yauto

short

-1 .. 1

 

Bei zeilenweise angeordnet: das Objekt wird in der jeweiligen Zeile angeordnet, deren Höhe sich nach dem größten Objekt richtet. Für -1 vom unteren Rand der Zeile, für 1 vom oberen Rand der Zeile, für 0 wird es auf die Zeilenhöhe aufgezogen. Falls nur Objekte mit .yauto = 0 in einer Zeile sein sollten, bekommen sie den Wert .minrowheight zugewiesen.

Für spaltenweise hat dieses Attribut keine Bedeutung.

32.3.4.1 Posrastering

Das Posrastering von Kindern der Layoutbox wird zwar unterstützt, macht aber wenig Sinn.

Es wird nur aus Gründen des Editierens eines Dialoges unterstützt.

Wenn man mit dem Editor ausprobieren möchte, ob sich die Layoutbox besser als Container eignet als die Groupbox, würde das Posraster-Attribut sonst an allen Kindern gelöscht werden. Wenn dem Anwender die Groupbox dann doch besser erscheinen würde, müsste dieser die Attribute von Hand an allen Kindern wieder neu setzen.

Wenn Posrastering für die Kinder der Layoutbox eingesetzt wird, kann das Ergebnis schlechter als erwartet aussehen, da das Auf- bzw. Abrunden von beim Positionieren von verschiedenen angegeben Objekten (mit und ohne Border) zur ungleichmäßigen Ausrichtung von Objekten führt.

32.3.4.2 Virtuelle Größen

Die Layoutbox berechnet die virtuelle Breite und Höhe selber. Sie kann zwar vom Benutzer gesetzt und ausgelesen werden, Setzungen vom Benutzer werden jedoch ignoriert.

Die virtuellen Größen geben immer den Arbeitsbereich an, d.h. die Rechteckfläche, die die Kinder der Layoutbox mit ihren Rändern (Margin) umfassen.

32.3.5 Beispiel

Eine simple Verwendung des Layoutbox-Objektes kann wie folgt aussehen:

dialog Dialog { }

 

color Black “black”

 

window W

{

    .title "Layoutbox-Demo";

    .width  400;

    .height 400;

    child layoutbox Lb {

        .xauto  0;

        .yauto  0;

        .xleft  5;

        .xright 5;

        .ytop   5;

        .ybottom 50;

        .xspacing 10;

        .yspacing 10;

        .xmargin 20;

        .ymargin 20;

        .wrap true;

 

        child pushbutton Pb1 {

            .text "Pushbutton1";

        }

 

        child statictext St1 {

            .text "Statictext";

        }

 

        child groupbox Gb1{

  .bgc Black;

            .xauto  1;

            .yauto  1;

            .width 100;

            .height 100;

        }

 

    }

    on close {exit();}

}

32.4 Neues Objekt Combobox für Motif

Für die Plattform Motif 2.1 unterstützt der Poptext jetzt auch das .style-Attribut mit allen Werten (poptext, edittext und listbox) und das Attribut .showitem.

Weitere Einzelheiten zum Poptext sind dem Kapitel „poptext (Combobox)“ in der „Objektreferenz“ zu entnehmen. Die Anmerkungen für Motif in diesem Kapitel gelten jetzt nur noch für Motif 1.2.

Die Implementation basiert auf einem neuen Oberflächenobjekt (Widget), das ab Motif 2 verfügbar ist. Aus diesem Grund ergaben sich allerdings geringfügige Änderungen, die sich

auch auf .style = poptext auswirken, wie zum Beispiel:

Der Poptext unter Motif 2.1 lässt sich jetzt zusätzlich per Tastatur mittels Strg + Cursor Abwärts oder Strg + Cursor Aufwärts auf- bzw. zuklappen.

32.5 Toggelbares Image für Motif und Microsoft Windows NT

Das Image Objekt ist jetzt um ein zusätzliches ".style" Attribut erweitert und kann zwei Zustände (aktiv/inaktiv) bekommen. Das .style Attribut kann auch zwei Werte erhalten:

Zwischen den Zuständen (aktiv/inaktiv) wird bei der ".style" Einstellung 'Checkbox' umgeschaltet. Jedem Zustand kann ein Bild zugeordnet werden. Dazu ist auch das Image-Attribut ".picture" indiziert worden:

Bei der Einstellung Pushbutton ist das Umschalten zwischen den Zuständen nicht möglich, das Objekt bekommt das für picture[0] zugewiesene Bild. Das Verhalten in diesem Fall entspricht dem Verhalten früherer Versionen.

Das Image Objekt unterstützt jetzt auch GIF-Bilder (89A Format), die transparente Farben enthalten.

32.6 Microsoft Windows NT

32.7 JAVA-Window-Interface

32.8 DM-Kern

32.9 Debugger

Der Debugger unter Motif besitzt nun die gleiche Oberfläche wie der unter MS-Windows.

Einschränkungen

32.10 Motif