Den T. rex in sieben Schritten zähmen

COBOL-Entwicklung für den Mainframe mit Eclipse

Thomas Zierer

@shutterstock/IvanC7

Großrechner? COBOL? Alles längst ausgestorben? Weit gefehlt: Banken und Versicherungen schätzen nach wie vor die strikte Abwärtskompatibilität und Ausfallsicherheit des Dinosauriers Großrechner: Steht doch das „z“ im Betriebssystem z/OS zurecht für „zero downtime“. IBM, wenn auch hier nicht gerade neutraler Beobachter, schätzt, dass 55 Prozent aller weltweiten Enterprise-Anwendungen in der einen oder anderen Weise COBOL-Code verwenden.

Geld am Automaten abheben oder überweisen, bei Amazon, Zalando oder eBay einkaufen – am Ende ist es fast immer COBOL-Code, der die Kontostände ausgleicht. Die Flugbuchung, die Sitzplatzreservierung im ICE etc. Ohne dass wir es merken, hat sich der Großrechner in unser tägliches Leben geschlichen. Doch viele, die seine Feinheiten beherrschen, stehen in den letzten Jahren ihres Berufslebens, und sowohl Banken als auch Versicherungen fürchten den Verlust an Know-how. Doch eine über Jahrzehnte gewachsene Kernapplikation, die einen Millionenwert an fachlicher Businesslogik darstellt, neu entwickeln? Dazu fehlen selbst Banken die Zeit und die Ressourcen. Nur, wie können diese Anwendungen am Leben erhalten und neuen Erfordernissen angepasst werden?

Für die Mainframeentwicklung existieren im Wesentlichen zwei Alternativen: Traditionell wird der integrierte TSO/ISPF-Editor verwendet. Von seinen Verächtern als „grün auf schwarz“ verspottet, steht er dem berüchtigten Unix-Editor vi an Befehlsfülle und Komplexität in kaum etwas nach. Eine weitere Möglichkeit sind dezentrale Lösungen von Rational und Micro Focus, wo eine Einzelplatzlizenz schnell mit 5 000 Euro und mehr zu Buche schlagen kann.

Hier soll ein dritter Weg aufgezeigt werden, nämlich wie mit geeigneten Third-Party-Plug-ins und etwas Java-Code Eclipse zu einer professionellen COBOL-IDE erweitert werden kann. 50 Entwickler bei der Bayerischen Landesbank arbeiten mit dieser z/Developer genannten Anwendung. Und sie kann sogar interessiertem Nachwuchs den Schrecken vor dem Dinosaurier Mainframe nehmen.

Schritt 1: Die Suche

Bevor man den Dinosaurier zähmen kann, muss man ihn zuerst einmal finden. Und anders als seine Verwandten aus dem Jurassic Park ist der Mainframe scheu: Er versteckt sich im Unterholz seines einzigartigen Filesystems, bestehend aus VSAM (Virtual Storage Access Method), PS (Physically Sequential), PDS (Partitioned Dataset). Weder Windows noch Unix kennen vergleichbare Dateitypen (Files heißen am Großrechner traditionell Datasets). Und als würde dies noch nicht genügen, ist sein Character Encoding EBCDIC (Extended Binary Coded Decimal Interchange Code) abseits des Mainframes völlig unbekannt, obwohl mittlerweile auch UTF-8 dort Einzug gehalten hat.

Filesystem und weitere Dienste sind mittels des z/OS Communications Servers zwar seit langem per FTP und Telnet zugänglich, aber nur mittels proprietärer Optionen. Das Target-Management-Projekt, in dem der bekannte Remote Systems Explorer aufging, unterstützt zwar auch z/OS als Zielsystem, ermöglicht jedoch nur den Zugriff auf dessen integriertes Unix-Filesystem OMVS bzw. USS. Da Sourcecode am Mainframe aber fast ausschließlich im nativen Filesystem unter kryptischen Namen wie DEVELPMT.COREBNKG.BCBS239.KREDIT(DL472FM) vorliegt, führt dieser Weg nicht weiter. Mit reinen Open-Source-Mitteln ist diesem T. rex nicht beizukommen.

Schritt 2: Finden

Hier ist der Punkt erreicht, wo es ohne Big Blue nicht mehr weitergeht, denn ausgerechnet IBM hat hierfür die Lösung: seine Explorer-Produktlinie. Dabei handelt es sich um eine Reihe von Eclipse-basierten Infoclients für diverse z/OS-Systemdienste wie die Transaktionsmonitore CICS und IMS, das Messaging System WebSphere MQ und weitere mehr. Eigentlich sind diese Clients als Stand-Alone-Anwendungen konzipiert, aber über eine Updatesite lassen sie sich auch in jede Eclipse-Installation integrieren. Empfohlen wird hierfür das Juno-Release, die Plug-ins erwiesen sich aber auch als Mars-kompatibel. Für unsere Zwecke benötigen wir den Explorer for z/OS.

Abb. 1: Die Plug-ins der Explorer-Familie

Abb. 1: Die Plug-ins der Explorer-Familie

Schritt 3: Einfangen

Die einfachste Möglichkeit ist natürlich, die Plug-ins über die Updatesite zu installieren (Abb. 1). Da aber der Client um Entwicklungsfeatures erweitert werden soll, definiert man besser eine Target Platform und setzt auf dieser auf (Abb. 2).

Abb. 2: Target Platform für den z/OS Explorer

Abb. 2: Target Platform für den z/OS Explorer

Leider benutzt die Updatesite das pre-p2-Format, das Tycho seit Version 0.17 nicht mehr unterstützt. Die Target Platform aus Abbildung 2 taugt somit nicht für Tycho Builds. Abhilfe bietet hier die „Features And Bundles Publisher Application“, die die Plug-ins einer Eclipse-Installation in ein p2 Repository exportiert (Listing 1).

java -jar <targetProductFolder>/plugins/org.eclipse.equinox.launcher_*.jar
-application org.eclipse.equinox.p2.publisher.FeaturesAndBundlesPublisher
-metadataRepository file:/<some location>/repository
-artifactRepository file:/<some location>/repository
-source /<location with a plugin and feature directory>
-configs gtk.linux.x86
-compress
-publishArtifacts

Das so entstandene p2 Repository ersetzt die Updatesite in der Target Platform, sodass sich diese dann auch in Tycho Builds verwenden lässt.

Schritt 4: Mit ihm spielen

Startet man nun den Explorer for z/OS, erweitert sich Eclipse um die z/OS-Perspektive. Der Zugriff auf den Host erfolgt über das ftp-Protokoll. Besonders praktisch: Die IP-Adressen der Hosts (üblicherweise gibt es mehrere, z. B. für Test, Integration und Produktion) können als XML-Dokument hinterlegt werden und lassen sich dann per HTTP z. B. aus dem Firmenintranet laden. Ein Beispiel ist in Abbildung 3 zu sehen.

Abb. 3: Die z/OS Perspektive des Explorers

Abb. 3: Die z/OS Perspektive des Explorers

Damit hat man Zugriff auf die wichtigsten Ressourcen, nämlich das native Filesystem und das Job Entry Subsystem (JES) zum Starten und Überwachen von Batchprozessen.

Nur eine Kleinigkeit, aber wichtig: Unter WINDOW | PREFERENCES | GENERAL | EDITORS | TEXT EDITOR sollte unbedingt die Option „Insert Spaces for Tabs“ aktiviert sein. Sonst wird die Zusammenarbeit mit den „Traditionalisten“ unter den Entwicklern schwierig, denn der Tabulator (HEX 05 in EBCDIC) ist am Mainframe völlig ungebräuchlich.

Schritt 5: Dressieren

Der Editor für Mainframe-Datasets des Explorer for z/OS ist eine simple Erweiterung von org.eclipse.ui.texteditor.AbstractDecoratedTextEditor und damit kaum besser als z. B. Notepad. Glücklicherweise gibt es auf eclipse.org ein hervorragendes Tutorial für die Entwicklung eigener Editoren, und es ist nicht schwierig, dieses für COBOL zu adaptieren: Zum Beispiel werden in COBOL Kommentare durch einen Asterisk in Spalte 7 gekennzeichnet. Eine org.eclipse.jface.text.rules.IRule teilt dem Scanner über ein org.eclipse.jface.text.rules.IToken mit, wenn sie einen Kommentar erkannt hat und auf welchen Textbereich (hier: die restliche Zeile) sich das Token bezieht (Listing 2).

public class COBOLCommentRule implements IRule {
/** The token to be returned when this rule is successful */
private final IToken fToken;

public COBOLCommentRule(IToken fToken) {
super();
this.fToken = fToken;
}

@Override
public IToken evaluate(ICharacterScanner scanner) {
int c = scanner.read();
if (c == '*' && scanner.getColumn() == 7) {
do {
c = scanner.read();
} while (c != '\r');
scanner.unread();
return fToken;
}
scanner.unread();
return Token.UNDEFINED;
}
}

Andere IRules kümmern sich dann beispielsweise um Literale, numerische Konstanten oder Schlüsselworte. Ein ColorManager weist ihnen Farben im RGB-Schema zu. In Form eines Fragments lässt sich der Editor dann in die DataSetsExplorerView der z/OS-Perspektive integrieren (Abb. 4).

Abb. 4: Die z/OS-Perspektive mit dem angepassten COBOL-Editor

Abb. 4: Die z/OS-Perspektive mit dem angepassten COBOL-Editor

Bei COBOL-Programmen, die schnell 10 000 LOC und mehr umfassen können, ist eine Outline View zur schnelleren Navigation äußerst hilfreich. Man implementiert sie mit einem einfachen TreeViewer (Listing 3).

public CobolContentOutlinePage(ZEditor input) {
  this.input = input;
  parser = new CobolOutlineParser();
}
@Override
public void createControl(Composite parent) {
  super.createControl(parent);

  TreeViewer viewer = getTreeViewer();
  viewer.setContentProvider(new WorkbenchContentProvider());
  viewer.setLabelProvider(new WorkbenchLabelProvider());
  viewer.addSelectionChangedListener(this);
  viewer.setInput(getContentOutline(input.getEditorInput()));
}
private IAdaptable getContentOutline(IAdaptable adaptable) {
  if (adaptable instanceof ZOSObjectEditorInput) {
    ZOSObjectEditorInput zoei = (ZOSObjectEditorInput) adaptable;
    MarkElement[] mes = parser.parse(zoei, zoei.getContents());
    return new AdaptableList(mes);
  }
  return null;
}

Die MarkElements implemetieren das Interface org.eclipse.ui.model.IWorkbenchAdapter und erlauben dadurch die Navigation zwischen den Knoten des OutlineTrees und ihren erzeugenden Elementen im Editor. Anhand welcher Kriterien und in welcher Granularität man die MarkElements erzeugt, ist letztendlich Geschmackssache. Denkbar ist eine sehr grobe Strukturierung nur anhand der DIVISIONs, in die jedes COBOL-Programm unterteilt ist (IDENTIFICATION, DATA, LINKAGE, PROCEDURE), oder sehr fein bis hinunter zu Subroutinen, Embedded SQL und PERFORM-Schleifen. All das lässt sich z. B. durch Anwendung regulärer Ausdrücke auf den Code erkennen.

An dieser Stelle könnte man noch lange mit Erweiterungen des Editors weitermachen. Aber bald ist dann eine Grenze erreicht, nämlich wenn die nächste Schüchternheit des Mainframes zum Tragen kommt: Alles Tooling ist nur zentral vorhanden.

Angenommen, wir möchten die bei Java so beliebte Codevervollständigung für COBOL adaptieren: Dazu wäre eine so detaillierte Analyse des Codes nötig, wie sie letztlich nur der Compiler selbst liefern könnte. Zwar gibt es COBOL-Compiler für Windows und Unix-Systeme, doch sind diese teuer und noch nicht einmal zu 100 Prozent kompatibel. Die einzige Möglichkeit wäre, den COBOL-Compiler am Mainframe selbst zu benutzen. Wir werden im nächsten Abschnitt eine Möglichkeit kennenlernen, seinen Aufruf in einen Workbench-Prozess einzubetten. Doch sein umfangreicher Output ist selbst zwischen Minor-Releases starken Schwankungen im Format unterworfen. Auf diese Weise einen Syntaxgraphen aufzubauen, wäre von vorneherein zum Scheitern verurteilt. Aber für ein kleines Kunststückchen ist der T. rex durchaus zu haben.

Schritt 6: Kunststückchen beibringen

Wer jemals unter TSO/ISPF entwickelt hat, kennt die Sisyphusarbeit, COBOL-Code überhaupt einmal fehlerfrei zu kompilieren:

  1. Editiere den Sourcecode.
  2. Kompiliere ihn mittels eines Compile-Skripts, geschrieben in JCL (Job Control Language).
  3. Kontrolliere das Compile Listing, notiere im Geiste die Zeilennummern mit Fehlern.
  4. Wechsle zurück zum Sourcecode, korrigiere die Fehler und beginne von vorne.

Dieses Vorgehen ist wahrhaft steinzeitlich, und spätestens hier wirft der Mainframeneuling das Handtuch, ist er von Eclipse doch anderes gewohnt. Dort gibt es die Problem-View, wo man sich komfortabel von einem Fehler zum nächsten klicken und diesen korrigieren kann; der Editor ist mit Markern dekoriert, die jede Compiler-Meldung anzeigen; Hovers verweisen direkt in die Dokumentation, und, und, und. All das ermöglichen die Java Development Tools, die letztendlich einen eigenen Java-Compiler darstellen.

Wie oben erwähnt, ist der originäre Output des COBOL-Compilers fast unmöglich zu analysieren. Aber alle Compiler (COBOL, PL/I, C++, ja sogar Assembler) unterstützen Optionen, mit denen sich zumindest Teile des Compileroutputs im XML-Format erzeugen lassen. Für COBOL lautet die Option EXIT(ADEXIT(ELAXMGUX)). So sieht dann eine Fehlermeldung wegen eines Typos bei einer Variablen wie in Listing 4 aus.

<MESSAGE>
<MSGNUMBER>IGYPS2121-S</MSGNUMBER>
<MSGLINE>24</MSGLINE>
<MSGFILE>1</MSGFILE>
<MSGTEXT>
&quot;PRINREC&quot; was not defined as a data-name. The statement was discarded
</MSGTEXT>
</MESSAGE>

Das sind alle Informationen, die nötig sind, die Problem-View damit zu bevölkern. Clientseitig geht man dazu so vor:

  1. Allokiere ein temporäres Dataset am Host.
  2. Generiere lokal einen String mit einem Compile-Skript, geschrieben in Job Control Language.
  3. Transferiere das Skript an den Host und führe es aus (Submit Job).
  4. Lade nach Beendigung des Jobs den Compileroutput als XML-Dokument und parse es.
  5. Pro gefundener Compile-Meldung platziere je einen Marker in die Problem View und in das IAnnotationModel des EditorDocumentProviders.
  6. Lösche das temporäre Dataset.

Im Unterschied zu den Java Development Tools muss diese Syntaxcheckfunktionalität vom Benutzer durch eine eigene Action angestoßen werden, aber das ist ein geringer Preis. Bei der Umsetzung erweist es sich als praktisch, dass sämtliche Operationen in der Klasse ZOSConnectable gebündelt sind (Listing 5).

DataSetBuilder dsb = new DataSetBuilder(xmlInfoDatasetName);
// On z/OS we have to specify a lot of attributes to create a dataset
// The following attributes are suitable for XML data
dsb.recordLength = 16383; // Maximum width
dsb.datasetType = NewDatasetType.PS; // Physically sequential
dsb.directoryBlocks = 0; // No members
dsb.format = RecordFormat.VB; // Variable record length
dsb.spaceUnits = SpaceUnits.TRACKS; // Varies, but approx. 1 track == 50kb
dsb.primaryAllocation = 10; // So, 500 kb primary should be okay
dsb.secondaryAllocation = 10; // Up to 15 extents make a total of 8 Mb
dsb.volume = "WRK";
DataSet xmlInfoDataset = ZOSConnectable.getSingleton().create(dsb);

IJobDetails jobd = ZOSConnectable.getSingleton().submitJob(jcl);

ByteArrayOutputStream bos = ZOSConnectable.getSingleton().getContents(xmlInfoDataset, FileType.EBCDIC);

ZOSConnectable.getSingleton().delete(xmlInfoDataset);

Den Code verpackt man als runner in ein org.eclipse.jface.operation.IRunnableWithProgress und führt es als Prozess mit Fortschrittsbalken in der Workbench aus (Listing 6).

PlatformUI
.getWorkbench()
.getProgressService()
.runInUI(PlatformUI.getWorkbench().getProgressService(), runner, ResourcesPlugin.getWorkspace().getRoot());
}

Den Editor dekoriert man über das org.eclipse.jface.text.source.IAnnotationModel, die Problem-View durch ResourcesPlugin.getWorkspace().getRoot().createMarker(IMarker.PROBLEM), wie in Abbildung 5 zu sehen.

Abb. 5: Die Problem-View und der Editor mit dem Ergebnis eines COBOL-Compiles

Abb. 5: Die Problem-View und der Editor mit dem Ergebnis eines COBOL-Compiles

Ein org.eclipse.swt.events.MouseListener, der bei Doppelklick auf einen Marker den Cursor in die Zeile platziert, die der Compiler als fehlerhaft ausgemacht hat – fertig ist ein (fast) identisches Verhalten zu den Java Development Tools!

Schritt 7: Manege frei!

Für einen Einsatz als IDE fehlt noch eine Schnittstelle zu industriellen Versionskontroll- und Build-Systemen (die am Mainframe üblicherweise zusammenfallen). Die führenden Produkte sind SCLM (IBM), PVCS (Serena) und Endevor (Computer Associates). Ihre Schnittstellen sind teilweise durchaus modern (Endevor unterstützt seit Kurzem SOAP als Protokoll), aber immer proprietär. Gemeinsam ist ihnen ein Batch-Interface, das sich analog zum Syntaxcheck aus dem vorhergehenden Beispiel ansprechen lässt, wie sich so überhaupt jede länger laufende Interaktion mit dem Mainframe innerhalb der Workbench synchron ausführen lässt. Die Job Control aus Listing 6 checkt ein Element für Endevor ein. Fertig ist eine moderne COBOL IDE.

//ZDEV200 EXEC NDVSTAN
//BSTIPT01 DD *
add element SCDBT00
  from dsname 'Y08577.DV.COBOL'
  to environment DEVELOP system ANWENTW subsystem SC
    type PGM
  options update
// 

Ausblick

Der Explorer for z/OS wurde ausgewählt, weil er nur einen z/OS Mainframe mit Communications Server, aber keine weiteren Hostprodukte benötigt. Die Bayerische Landesbank setzt außer dem Explorer noch das Debug Tool Plug-in ein, das über dieselbe Updatesite installiert wird. Es funktioniert nur im Zusammenspiel mit dem (kostenpflichtigen) IBM-Debugger. Aber Assembler-Code mit einem Eclipse-GUI step by step zu debuggen, Variableninhalte oder die Werte der Basisregister manipulieren zu können, das begeistert selbst hartgesottene Hosttraditionalisten!

Fazit

Einer Industrielösung wie dem Developer for System/z von Rational oder dem Enterprise Developer von Micro Focus kann ein solchermaßen erweiterter Explorer for z/OS natürlich nicht das Wasser reichen. Dafür verursacht er keinerlei Lizenzkosten, ist einfach zu erweitern und an individuelle Erfordernisse anpassbar. Vor allem aber erspart er Mainframeneulingen den steinigen Weg, die Geheimnisse des ISPF-Editors erkunden zu müssen, indem er ihnen das von Eclipse gewohnte Handling schenkt.

Aufmacherbild: T-Rex Laptop Background von Shutterstock / Urheberrecht: IvanC7

Verwandte Themen:

Geschrieben von
Thomas Zierer
Thomas Zierer
Thomas Zierer ist technischer Architekt bei der Bayerischen Landesbank in München. Als Mainframe- und Eclipse-Enthusiast sucht er Mittel und Wege, Technologien aus siebzig Jahren IT zu verknüpfen.
Kommentare

Hinterlasse einen Kommentar

Hinterlasse den ersten Kommentar!

avatar
400
  Subscribe  
Benachrichtige mich zu: