Start Page

Freeware und Snippets für AS/400

Diese Seite enthält derzeit Source Abschnitte, die weiter verwendet werden dürfen und sollen. Sie sollen auch als Anschauungsmaterial dienen für modernen Programmierstil mit CL, ILE RPG und auch Java. Es handelt sich dabei derzeit ausschließlich um kleinere Tools und Bausteine für Anwendungen.

Alle RPG Programme lassen sich am einfachsten mit meinem Pre-Compiler erstellen, den Sie ebenfalls auf dieser Seite finden.

Dieser Prototyp wird für weitere Programme benötigt und muss in einer Datei QRPGLEH zu finden sein. Alle Prototypen und andere Copystrecken sind in einer eigenen Quelldatei QRPGLEH abgelegt, dies ist an C Konventionen angelehnt und ermöglicht, dass zusammengehörende Quelldateien gleiche Membernamen haben dürfen; die häufiger anzutreffende Variante die Copystrecken dann mit einem H als Suffix zu versehen ist ein Fall für eine Büttenrede auf der Informatiker Fassenacht, insbesondere wenn von den kanppen 10 Buchstaben noch weiter für Prefixe und andere Suffixe vergeudet werden, hier versucht wohl mancher aus der 10 Buchstaben Not eine 5 Buchstaben Tugend zu machen. Ein weiterer gewünschter Nebeneffekt davon ist, dass alle Quellen, die nach Programmquellen aussehen auch wandelbar sind, was die Automatisierung von Compiles vereinfacht.

Eine kurzgefasste Blackbox Beschreibung der Programme und Serviceprogramme befindet sich oft in den Headerdateien bei den Prototypen. Die Compileanweisungen befinden sich als Kommentar in den Quellen der Implementierung und können zur automatischen Erstellung mit dem Precompiler verwendet werden. Alle Erstellungsbefehle sind in sich abgeschlossen, es werden keine Binderverzeichnisse und keine Binderquellen benötigt, alle Objekte werden in die Curlib des umwandelnden Jobs generiert. Als erstes installiert man sich am Besten den Precompiler und danach reicht es dann zur Installation einer der Komponenten aus sich die Quellen komplett per FTP auf seine Maschine zu transferieren, die Bibliothek mit den Quellen in der Libl und dem PreCompiler nach vorne zu platzieren, die Installationsbibliothek als Curlib festzulegen und alle wandelbaren Quellen (alles außer QRPGLEH) über den Precompiler zu jagen. Auf meiner AS400 (und auf einigen Kundenmaschinen) habe ich eine PDM Option angelegt, die die Quellen an den PreCompiler übergibt; wenn man das dann per SBMJOB macht und als Jobnamen den Namen der Quelldatei vergibt, dann kommt man auch aus dem SEU wie gewohnt an die Wandlungsliste dran.


Automatisches Erstellen und Binden von Modulen, Programmen und Serviceprogrammen

Folgendes Utilitie stellt einen kleinen Preprozessor dar, der universell Erstellungsbefehle aus Kommentaren von Quelldateien herauszieht und über C API system() ausführt. Siehe auch die Erstellungsbefehle in dieser Quelle selber. Dieses Tool hat sich bisher eher nach Art eines Virus verbreitet; wenn ich für einen Kunden Programme schreibe, installiere ich mir mein kleines Tool und werde meist gebeten es dann nicht zu löschen und es wird dann weiter verwendet, wechselt einer der Programmierer den Arbeitsplatz, wandert das Tool dann oft mir zum neuen Arbeitgeber.
Header für ILE Programmerstellungs Utility
Prototyp für API QMHSNDPM zum senden Programm Message
Prototyp für C API system()
ILE Programmerstellungs Utility


Generator FTP Batch Skripten

Dieses Utility erzeugt aus den Parametern (siehe Header Datei) ein FTP Skript und führt es im Batch aus. Geschreiben habe ich das mal als Fingerübung zu Beginn meiner CL ist überflüssig Phase. Wenn man das Resultat mit den zahlreichen Alternativen vergleicht, sieht man wie einfach das sein kann. Wenn ich dieses Geschäft ernsthaft zu betreiben hätte, würde ich die Java Variante vorziehen, wegen des wesentlich komfortableren Errorhandlings.
Header für Batch FTP Utility
Batch FTP Utility


Tool zur Formatierung von Journaleinträgen

Dieses Tool dient zur formatierten Anzeige von Journaleinträgen. Per Parameter gibt man die Datei, das Journal und 2 Timestamps zur zeitlichen Auswahl der Journaleinträge, sowie den gewünschten Namen der Ausgabedatei an. Per Programm wird dann eine passende Ausgabedatei erstellt und gefüllt, die die relevanten Felder der Journal Informationen und alle Felder der journalisierten Datei enthält, diese kann dann als Basis zur weiteren Auswertung mit SQL dient. Früher habe ich mir das alles per Hand zurecht gefummelt, aber irgendwann hat es mir gereicht und ich habe mir da was kleines, nettes geschrieben.

Für meine Praxis ist das ein echtes Arbeitspferd, überall wo das möglich ist - seltsamerweise gibt es immer noch AS400 Installationen mit echter Journalisierungs Allergie - setze ich (fast) alle produktiv genutzten Dateien und alle Objekte meiner Testumgebung flächendeckend unter Journalisierung, bei Fehler Abklärungen und bei Integrationstests extrahiere ich mir dann alle Journaleinträge nach Dateien getrennt und kann dann per SQL auswerten was genau von wem geschrieben wurde, welche Felder wie fortgeschrieben wurden und einiges mehr. Dieses Tool verbreitet sich meist mit größerer Verzögerung, zunächst wird mehr oder weniger Kopf schüttelnd verfolgt was ich da so treibe, dann kommt hin und wieder die Frage könntest Du mal da suchen, vielleicht findest du ja was im Journal und irgendwann hat das Tool dann wieder einen Rechner erobert.
Header für ANZJRN
Header für API system
Header für QMHSNDPM
Quelle ANZJRN


Break Message Handler

Break Message Handler sind ein kleines Zaubertool für Test und Debug Zwecke. Hiermit kann man aus einem interaktiven Job eine Auswertung im Batch erstellen und automatisch wieder interaktiv anzeigen, wenn der Batch fertig ist, oder sich aus einem Batch Job zur Laufzeit dessen QTEMP geben lassen, oder sich den LDA in einen Spool drucken lassen und das ganze interaktiv initiiert, oder sich in einem beliebigen interaktiven Programm zu beliebiger Zeit eine Command Line innerhalb des Jobs holen, oder auch nur einfach Kollegen damit ärgern ihren Job fern zu steuern. Gebrauchsanleitung folgt später einmal, für die, die diese Spielereien nicht kennen.
Break Message Handler
Command für Break Message Handler


Dynamischer Aufruf von Prozeduren

In Java kennt man den Begriff Reflection, damit meint man das dynamische Erzeugen von Objekten deren Klasse man erst zur Laufzeit kennt - also zum Beispiel aus einer Datei liest. Relative Java Anfänger verwenden diese Technik häufig beim registrieren des JDBC Treibers mit Class.forName() ohne sich was dabei zu denken. Beim gebundenen Aufruf von Prozeduren in ILE, hat man ein ähnliches Problem zu bewältigen, wie Java: alle Prozeduren müssen zur Übersetzungszeit bekannt sein. Es sei denn, man kennt die richtigen APIs.
Header für Errorhandling APIs
Header Konstanten Berechtigung
Header für Hilfsfunktion zur Konvertierung Objekttyp
Header für MI Aufruf zum Holen SysPointer auf Objekt
Header für APIs zum dynamischen laden und aufrufen von Prozeduren
Header für Serviceprogramm zum Holen von Procedure Pointer
ServiceProgramm, tauscht Namen gegen Procedure Pointer
Beispiel dynamischer Aufruf gebundener Prozedur aus RPG


Datenübertragung mit Java zwischen beliebigen Datenbanken

Für die Übertragung von Datenbankdaten zwischen der AS/400 und anderen Datenbanksystemen werden zumeist Workarounds wie Client Access oder RPG Programme im Verbund mit FTP eingesetzt. Diese Lösungen sind dann instabil und erfordern zumeist ständigen manuellen Aufwand. Seltener werden automatische Lösungen eingesetzt, die oft teure Middleware erfordern.
Warum verwendet hierfür eigentlich kaum jemand Java??? Das ist einfach und schnell programmiert, funktioniert vollautomatisch, alles was man braucht kostet nichts (oder sagen wir lieber fast nichts), kann jede Datenbank mit jeder verknoten (oder sagen wir lieber fast jede) und läuft auf jedem Rechner (oder sagen wir lieber auf fast jedem).
Basisobjekt für Datentransfer, repräsentiert Datei, voll parametrisiert
Einstieg in die Anwendung, wird mit Parameter der Properties aufgerufen
Beispiel Properties für Quelldatei AS/400 mit Toolbox Treiber
Beispiel Properties für Zieldatei AS/400 mit native Treiber
Beispiel CL Programm zum Submit des Java Aufrufs


RPG Hashtable, dynamische Speicherverwaltung leicht gemacht

Dynamische Speicherverwaltung in RPG, ohne dass in allen Programmen mit Pointern gerechnet wird und unkontrolliert Speicher allokiert (und nur manchmal freigegeben) wird. In Java kann man sich anschauen, wie das geht, wenn man denn in den Compiler hineinschaut. Mit weniger Eleganz, aber immerhin, kann man das in RPG wenigstens zentralisieren.
Header für C Api memcpy zum kopieren von Speicher Bereichen
Header für ILE Api CEE4RAGE zum registrieren von ILE Exit Handler
Header für die RPG Implementierung der Hashtable
Hashtable in RPG, kapselt Pointer und Speicher Anforderung
Beispiel zur Pointerfreien dynamischen Speicherverwaltung

RPG Vector, wachsendes und schrumpfendes Array

Der kleine Bruder der Hashtable, hier werden die Einträge (bevorzugt Datenstrukturen) sequentiell in ein Array gestellt. Man kann sie auch mitten reinstellen, oder rauslöschen, dann machen die anderen Einträge Platz, oder rutschen nach. Der Vector merkt sich (im Unterschied zur Hashtable) die Länge der einzelnen Einträge selber. Man kann (und muss) sich selber erst einen Vector aktivieren, den man dann über das erhaltene Handle anspricht. Für jeden dieser Vektoren wird dann ein eigener Heap verwendet, der beim finalize wieder freigegeben wird.

Prototypen von VECTOR ala Java in RPG
ILE Exit Handler
User Heaps, dynamische Speicherverwaltung ala ILE
Speicher Verarbeitung mit C in RPG
throw Exception mit Escape Message
VECTOR a la Java in ILE RPG implementiert


Freeformat ohne /free und /end-free

Diesen kleinen Generator zum erzeugen der /free /end-free Einträge habe ich als kleine Fingerübung und als Studie für einen "richtigen" Generator geschrieben, der mal in meinem Model View Controller Framework Verwendung finden soll. Und ausserdem hatte ich keine Lust mehr zum 76. Mal /end-free auf die 17. Art falsch zu schreiben. Wenn es Ihnen genauso geht...
Header für Main Prototyp von GENFREE
Prototyp für API QMHSNDPM zum senden Programm Message
Prototyp für C API system()
Generator GENFREE zum erzeugen der /free /end-free Eintr�e


Programmgenerator für Serviceprogramm Rahmen

Momentan handelt es sich noch um eine Betaversion, die an meine Arbeitsweise angepasst ist.
Bei mir kommt vor der Programmierung das Design, das heißt, dass ich zuerst die Exporte eines Moduls festlege, also mit dem schreiben der Prototypen eines Moduls anfange. Für die Prototypen habe ich eine eigene Quelldatei, die bei mir QRPGLEH heißt. Für die Copystrecke mit den Prototypen, die Quelle für das Modul (und die Copystrecke für die Initialisierung, bei late bind zur Laufzeit) haben alle denselben Namen.

Nach den Prototypen schreibe ich dann ein Programm, das alle Prozedurexporte als Dummy Implementierung ohne Funktionalität enthält. Und genau das macht nun mein Generator, er generiert mir aus der Copystrecke mit den Prototypen eine Compile fertige Implementierung.

Restriktionen

  1. Quelle wird in QRPGLESRC generiert
  2. Prototyp in anderer Quelle, gleicher Teildateiname
  3. Keine Like Definitionen für den Prozedur Rückgabetyp
  4. Für jeden Schlüsselwort Eintrag eine eigene Zeile
  5. EXTPROC Eintrag in der PR Zeile
Der Generator generiert eine Quelle unter dem Namen des Input Members in der QRPGLESRC (vorhandene wird ersetzt!!!). Es werden alle Prozedurexporte angelegt, ein wenig Struktur erzeugt, Compileanweisungen für meinen Preprozessor erzeugt und eine init Routine angelegt und eingebunden (die ich für Binden zur Laufzeit benötige). Die Quelle ist Compiler reif, wird aber (noch) nicht automatisch umgewandelt. (Meinen Copyright Eintrag in der generierten Quelle dürfen Sie löschen).
Header für Main Prototyp von GENFRAME
Prototyp für API QMHSNDPM zum senden Programm Message
Prototyp für C API system()
Generator GENFRAME zum erzeugen Quelle aus Prototypen
Beispiel: Header
Beispiel: generierte Rahmen Source

SQL als Programmiersprache

In dem kleinen Beispiel steckt mehr Substanz, als man auf den ersten Blick vermuten mag, zumal mancher sagen mag, das macht V5R2 ja automatisch, da kann man sich Schlüssel vom System generieren lassen.

Voraussetzung für den Einsatz dieses SQL Programms ist, wie für den Einsatz von SQL generell zu empfehlen, die Verwendung von Commit Steuerung. Am einfachsten erreicht man das dadurch, dass man seine Bibliothek mit CREATE SCHEMA erstellt und sich anschließend um Commit nicht mehr kümmert, außer in der Anwendung nach Abschluß einer Transaktion Commit zu sagen oder eben Rollback, falls man es nicht ernst gemeint hat. Um den Rest kümmern sich dann die entsprechenden Voreinstellungen des SQL Umfeldes, die allesamt in Richtung der Verwendung von Transaktionskontrolle gedreht sind.

Zu beachten ist in der Quelle auch, dass sofort ohne lesen geschrieben wird; dieser kleine Trick sorgt dafür, dass keine Sperrprobleme auftreten können, denn DB2 geht mit Satzsperren etwas lax um, was zuweilen zu Verklemmungen führen kann. Mittlerweile wird es die Besucher meiner Web Seite nicht mehr überraschen, daß zur Erstellung der UDF mein kleiner Pre Prozessor CRTCPP verwendet wird.

Verwenden lässt sich der Mechanismus zum generieren der Schlüssel direkt innerhalb von SQL Anweisungen, also mit:
INSERT INTO KUNDE VALUES(GET_KEY('KUNDE', 'KUNDE_ID'), 'Hugo', 'Hühnerkopf', ....)


SQL User Defined Function
SQL Script für Schlüssel Datei


Zip auf der AS/400

Seit V4R2 kann die AS400 Java und damit auch komprimieren und dekomprimieren im Standard ZIP Format und immer noch wird Geld verdient - mit unnötigen Tools. Da kann sich unsereins im Midrange Magazin die Finger wund schreiben, dass man für Zip Utilities kein Geld mehr ausgeben muss und immer wieder wird gefragt, wie man komprimieren kann. Java beinhaltet ein kleines Programm jar, mit dem man Zip Files verarbeiten kann und das ist auf allen AS400 fix und fertig installiert.

Falls die Qshell das Hindernis sein sollte, wofür gibt es meine Freeware Seite. Ich habe mich mal hingesetzt und einen kleinen Command geschrieben, der ein kleines CL bedient, das dann den Java Archiver per Qshell bedient und zum Download auf meine Seite gestellt. Den Command wandelt man sich am Besten mit meinem CRTCPP um, ansonsten muss man aufpassen, dass man als Command verarbeitendes Programm ZIPCPP angibt, sonst geht es zwar unheimlich flott, macht aber nichts.

Als aktuelles Verzeichnis wird immer das Benutzer Verzeichnis angenommen, das beim Benutzerprofil eingetragen ist. Beim Zippen kann man ein verzeichnis angeben, dann wird nach Java Art rekursiv nach unten alles gezippt; alternativ kann man auch eine einzelne Datei oder eine Gruppe mit der Wildcard * angeben. Beim Entzippen wird in das aktuelle Verzeichnis alles entpackt. Wer auf den Geschmack kommt und mehr Komfort mag, kann den Command und das CL aufbohren - selbstredend freue ich mich über Feedback und stelle verbesserte Versionen gerne auf meine Freeware Seite.

Ach ja, wenn Ihr Browser nicht so will, wie Sie wollen, weil die Datei für den Command QCMDSRC.ZIP heißt, mit rechter Maustaste und speichern unter gehts trotzdem.
Command ZIP zum packen/entpacken
CL als Command Processing Programm für ZIP


Triggerprogramme AS400

Ich hätte eigentlich gedacht, dass das mit den Triggerprogrammen jedem bekannt ist, wie das geht. Es tauchen jedoch immer wieder einmal Fragen zu Triggerprogrammen in Mailinglisten und Newsgroups auf, die einen anderen Eindruck bei mir hinterlassen.

Nun habe ich momentan nicht die Muße und auch andere Schwerpunkte, um einen Artikel (gab es schonmal von mir, 1997 im Midrange Magazin) oder gar ein Tutorial über Triggerprogrammierung zu schreiben und so will ich wenigstens ein Beispiel dazu auf meine Freewareseite stellen. Mein Trigger Generator, den ich mal für eine Datenübernahme geschrieben habe, ist schon ein wenig in die Jahre gekommen und den möchte ich in dieser Form nicht veröffentlichen, aber ich habe wenigstens noch ein vorzeigbares Beispielprogramm gefunden.


Header für ILE RPG Trigger
Beispiel Trigger in ILE RPG


Schreiben in Streamfiles aus RPG

RPG auf der AS400 ist die einzige Programmiersprache der Welt bei der Lese- und Schreibanweisungen mit der Datenbank arbeiten (ja, ich weiss COBOL auch, aber das ist noch so eine Geschichte...); in allen anderen Umgebungen kann man nur mit SQL auf die Datenbank und die elementaren Anweisungen richten sich immer an sequentielle Haufen, die mancher auch Streamfiles nennt. Vor ILE Zeiten kam man nun an diese Dinger aus RPG garnicht ran, seit ILE geht das immerhin mit C APIs. Wer hätte denn bei dem Elan des Silverlake Projektes, seinerzeit bei der Entwicklung der /38 an einen Rckfall ins Zeitalter der sequentiellen Haufen gedacht. Heute ist das natürlich alles ganz anders, da heißt das dann XML, Webservice, Property-File oder heterogene Datenschnittstelle, aber wie auch immer, man muss ran an diese Dinger und wer kann schon C und RPG.

In Java käme keiner auf die Idee derartig komplizierte Schnittstellen anzubieten, wie in C, aber mit der Koexistenz von Java und RPG ist es nicht weit her, auch wenn da die Marketing Jungs und Mädels was anderes erzählen, ich habe jedenfalls in meinem kleinen Open Source Programm versucht ein wenig von der Eleganz von Java in RPG einzubringen, wohl wissend, dass das nur begrenzt gelingen kann, implementiert unter der Verwendung der C APIs. Eine ausführliche Beschreibung des Programmes findet sich im Midrange Magazin.


Header für C function access
Header für Streamfile APIs
Header für ILE RPG OUTSTREAM
Outstream a la Java in ILE RPG


Lesen von Streamfiles in RPG

Ich hatte früher mal einen Lehrer, der meine Einwände gegen Hausaufgaben nicht gelten lassen wollte, 'wenn man sie bewältigen kann, sind sie zu leicht', 'wenn sie schwerer sind, bringt sie keiner hin und alle schreiben ab von einem, für den sie zu leicht waren'; sein Hauptargument war, dass man ja beim abschreiben auch was lernt. Habe ich ihm damals nicht geglaubt, glaube ich heute auch noch nicht. Deshalb habe ich auch Beispiele aus meinen aktuelleren Artikeln in Midrange Magazin hier reingestellt.

Wo es einen Outstream gibt, da ist hoffentlich auch ein Instream, sonst hätte man die Daten eigentlich garnicht schreiben brauchen. Wenn der Outstream sich an Java anlehnt, dann wird es nicht überraschen, dass sich der Instream auch an Java anlehnt. Wobei ich an dieser Stelle auch mal schreiben muss, dass RPG bei weitem nicht an Java ranreicht; am meisten nervt mich, dass es die RPG Pseudo Objekte immer nur einmal gibt und wenn ich mir die Klimmzüge anschaue, die manche schlauen Leute da veranstalten - zum Abgewöhnen, oder positiv formuliert: zum Angewöhnen (von Java versteht sich). Eine ausführliche Beschreibung des Programmes findet sich im Midrange Magazin.


Header für Streamfile APIs
Header für ILE RPG INSTREAM
Instream a la Java in ILE RPG


Properties ala Java

In Java ist es allgemeiner Brauch alles Mögliche an Programmen konfigurierbar zu machen. Die Konfigurationen legt man dann einfach in Streamfiles ab, die man mit jedem Editor pflegen kann. Es gibt eine allgemein verwendete Syntx für solche Dateien, die aus wenigen Elementen besteht.
Verwendung von Namens Parametern
qualified names mit Punkt als Trenner
Knast Zeichen als Kommentar

Meine Properties verwenden selbstredend meine Streamfile Service Programme zum verarbeiten der Streamfiles.


Header für Properties
Properties a la Java in ILE RPG


List APIs einfach gemacht

Was sich auf der AS/400 API nennt, nutzt meistens einen UserSpace für die Ausgabe, was die Handhabung eher verkompliziert als vereinfacht. RPG Programmierer kopieren dann immer wieder Codestrecken zur Modifizierung von einer Quelle in die andere, oder programmieren das extrahieren der Einträge aus dem Userspace immer wieder aufs Neue, jedesmal ein wenig anders, manchmal richtig, manchmal eben nur fast. Mir war das alles zu kompliziert und auch lästig, also habe ich versucht das einmal ordentlich zu machen.


Header für APILIST
Quelle APILIST ServiceProgramm
Header CEE4RAGE
Header QMHSNDPM
Header UserSpace
Am einfachsten sieht man immer an einem Beispiel wie ein ServiceProgramm verwendet wird. Dieses Beispiel verwendet das API QEZLSGNU, das interaktive Jobs ausliest.
Quelle TSTAPILIST kleines Testprogramm
Header System
Header für API QEZLSGNU


Starten von Never ending Programms oder Der Unkaputtbare - revisited

Hin und wieder braucht man sogenannte Listener, Programme die auf ankommende Events warten. AppServer4RPG braucht das und mich hat es schon immer gestört, dass man das über Workmanagement sicherstellen muss. Einfacher geht das mit einem Unkaputtbaren, der einfach als letzte Aktion ein neues Exemplar von sich selber ins Leben setzt. Technisch geht das über einen sogenannten Exithandler (CEE4RAGE lässt grüßen). Fix und fertig habe ich das in ein kleines Programm (STRNEP) rauszentralisiert. Selbiges hat dann 4 Parameter: Name des aufzurufenden Programms, Bibliothek des Programms, Name der JOBQ, Bibliothek der JOBQ. Jetzt muss man nur noch eine JOBQ haben, die die Jobs reinlässt. Ich bevorzuge ein eigenes Subsystem für die NEPs mit einer JOBQ, die unbegrenzt reinlässt. Zum schlafen legen fährt man das Subsystem runter und alle NEPs setzen sich beim Ende wieder in die JOBQ rein, sodass sie nach STRSBS bin schon da rufen, deswegen fiel mir da immer der Wettlauf zwischen Hase und Igel ein. Überleben tut das Ganze dann selber PWRDWNSYS *immed, falls das Subsystem aus QSTRUP gestartet wird - und finden tut man das ganze hier:
QRPGLEH.CEE4RAGE
QRPGLEH.SYSTEM
QRPGLEH.QMHSNDPM
QRPGLESRC.STRNEP
Bequem umwandeln kann man sich das dann wieder mit CRTCPP, ebenfalls zu finden in diesem Theater.


Hier sollen später weitere Open Source Programme und Teile enthalten sein!