Automatiserte Migration alter COBOL Programme in Java

Werbung
Automatiserte Migration alter COBOL Programme in Java
Harry M. Sneed
ANECON GmbH, Wien
Email: [email protected]
Zusammenfassung: Dieser Beitrag befasst sich mit einer
Fallstudie zur Software-Migration. Als ersten Teil einer
umfassenden Migration von Bull/IDS-COBOL zu Java/Oracle werden 93 Hauptprogramme und 41 Unterprogramme erst saniert und anschließend konvertiert. Die
Hauptarbeit besteht drin, ein automatisiertes Transformationswerkzeug zu entwickeln. Die anschließende Umsetzung
der Programme läuft voll automatisch ab. Dieser Praxisbericht schildert wie das Transformationswerkzeug funktioniert. Es handelt sich hier um eine Source zu Source Transformation ohne Reverse Engineering.
1
Ausgangssituation
Der hier betrachtete COBOL Code ist in einem speziellen
Dialekt verfasst. Die Daten sind in einer vernetzten CODASYL Datenbank gespeichert. Die Verbindung zur Benutzerschnittstelle und die Verwaltung der Online-Transaktionen
werden von einem Hersteller-spezifischen TP-Monitor aus
den 70er Jahren bewerkstelligt. Allerdings erreicht dieser
TP-Monitor eine sehr hohe Performanz, die von jedem
Nachfolgesystem nur schwer erreichbar ist. Die Architektur
des Altsystems entspricht klassischen Mainframe Applikationen. Die Data Division ist in fünf Speicherbereiche aufgeteilt: einen Datenbankbereich, eine Daten-Cache, einen
Eingabebereich, bzw. Linkage Section, einen Ausgabebereich, bzw. Communication Section und einen Arbeitsbereich, bzw. Working-Storage. Die Prozedur-Division besteht
aus mehreren hundert kleinen Codeblöcken, bzw. Absätzen,
bestehend aus 3 bis 30 Anweisungen, die auf die Felder in
der Data Division beliebig zugreifen und über GOTO Verzweigungen von einem Baustein zum Anderen hin und her
springen. Ein Durchschnittsprogramm hat ca. 5 Kilo Codezeilen davon 2 bis 3 Kilo Datendefinitionen, von denen die
Meisten nie benutzt werden. In der Regel allerdings verarbeitet ein Codebaustein die Daten von einem einzigen Datensatz. Dies gab den Anlass die Codebausteine den Datensätzen zuzuordnen die sie am meisten verarbeiten.
2
Alternative Lösungen
In einer solchen Situation hat der Anwender theoretisch
mehrere Alternativen:
a) Er kann die Altsysteme durch Standardsysteme ablösen
b) Er kann die alten Programme in COBOL erhalten und in
einer Java Umgebung kapseln
c) Er kann die COBOL Programme nachdokumentieren
und reimplementieren
d) Er kann den alten Code in die neue Sprache konvertieren
e) Er kann die Altsysteme an einen externen Dienstleister
in Pflege übergeben. Was er denn damit macht ist seine
Sache.
In diesem Falle wurde aus Zeit- und Kostengründen Alternative d) - Konversion gewählt Die COBOL Programme sollen
per Werkzeug automatisch in Java konvertiert und anschließend von Java Entwicklern refaktoriert werden. Der konvertierter Java Code sollte deshalb mit JavaDoc und XML gut
nachdokumentiert werden.
3
Spezifikation der Transformation
Für den Zweck der automatischen Konvertierung von einer
prozeduralen Struktur in eine objektorientierter Architektur
worden folgende 15 Grundregeln der Konversion zugrunde
gelegt:
(1) Alle Daten sollten in statischen “singleton” Objekten
enthalten sein, die zu Beginn einer Komponentenausführung
angelegt werden.
(2) Jede COBOL Datenstruktur, die auf der Stufe eins beginnt,
bildet ein „singleton“ Objekt. Einzelne Felder im COBOL
Programm die mit Stufe 1 oder 77 beginnen, sind durch den
Preprozessor in eine globale Struktur zu versetzen.
(3) Die COBOL Datensätze, bzw. Strukturen, werden in Java
als “character arrays” implementiert mit normierten Gettern
und Settern.
(4) Nur jene Daten, die in einer Komponente tatsächlich referenziert sind, werden sichtbar gemacht. Alle anderen Daten
sind zwar physikalisch vorhanden aber nicht sichtbar. Sie
haben keine Setter und Getter. Das Gleiche gilt für Sätze die
nicht adressiert sind. Sie bleiben gänzlich weg. Nur Sätze, die
verarbeitet werden, werden aufgenommen.
(5) Einzelne Datenfelder werden über ihre Anfangsposition
und Länge, sowie über ihren Typ identifiziert. Vektoren,
werden auch über Indizes identifiziert.
(6) Bedingungsdaten, bzw. 88 Felder,
bilden eigene
Enumerierungsklassen, die auf ihren Inhalt abgefragt werden
können
(7) Compiler-spezifische Felder wie Indexed by Felder werden am Ende der jeweiligen Klasse als Integer Daten angehängt.
(8) Jeder Absatz in der Procedure Division ist in eine Java
Methode umzuwandeln.
(9) Jede COBOL Anweisung ist in eine semantisch äquivalente Java Anweisung umzusetzen.
(10) Generierte Methoden werden Klassen aufgrund der Referenzhäufigkeit zugewiesen, d.h. eine Methode wird jener
Klasse zugewiesen deren Attribute am häufigsten angesprochen werden. Die anderen referenzierten Daten werden über
get Methoden aus den fremden Klassen geholt.
(11) Die GOTO Verzweigungen sind mit einer Labelvariable
zu ersetzen, die von der Controllerklasse interpretiert und
angesteuert wird. Dies entspricht einem endlichen Automaten.
(12) Die PERFORM Aufrufe werden als direkte Methodenaufrufe implementiert. Für PERFORM Sections und PERFORM
THRU werden Steuerungsklassen generiert, die eine
Methodenaufrufssequenz beinhalten.
(13) Die CODAYSL Datenbankaufrufe werden in SQL Anweisungen umgesetzt, die zu den Klassen gehören in denen
die Datenbanksätze gekapselt sind.
(14) Vor jeder Methode werden in einem JavaDoc Kommentarblock alle Daten die von der Methode verwendet werden,
mit der Art der Verwendung und HTML Links zu den Datendefinitionen, aufgelistet. Dies ermöglicht es dem Entwickler
den Datenfluss zu verfolgen.
(15) Nach jeder Methode werden ebenfalls in einem
JavaDoc Kommentarblock alle potentiellen Nachfolgemethoden mit der Art der Verzweigung, ob GOTO, CALL oder
PERFORM, sowie mit einem HTML Link zur nächsten
Methode, aufgelistet. Dies erlaubt es den Entwickler Ablaufpfade zu verfolgen.
4
Code Konvertierungsprozess
Der Code Transformationsprozess vollzieht sich in sechs
aufeinander folgenden Schritte:
Schritt 1: Nach dem Motto, erst sanieren, dann migrieren,
wird der COBOL Code bereinigt und restrukturiert. Der
Originalcode war aufgrund der schlechten Editierungsmöglichkeiten schlecht formatiert und unleserlich. Es gab in
einer Zeile mehrere Anweisungen. Verschachtelter Code
war nicht eingerückt. Die komplexen if Bedingungen sind
tief gegliedert und mit einem Punkt abgeschlossen. Es gibt
etliche Perform Thru und GOTO Depending on Anweisungen. Die prozeduralen Anweisungen enthalten jede Menge
eingebaute Datenwerte – Konstanten und Literale. Der
Zweck der Sanierung ist den alten Code auf einen minimalen Qualitätsstand zu bringen. Die Anweisungen werden
gespalten – eine pro Zeile, die If Anweisungen mit End-Ifs
abgeschlossen, den verschachtelten Code eingerückt, die
Perform Thrus und GoTo Depending Ons eliminiert und
festverdrahtete Daten entfernt.
Schritt 2: Hier wird der Source-Code eines jeden Programmes um die Copy Strecken expandiert und die Daten
restrukturiert. Einzelne Datenfelder werden in einer globalen
Datenstruktur gesammelt. Sofern sie vorhanden sind, werden die kurzen Datennamen durch lange sprechenden Namen ergänzt. Das Gleiche gilt für die Prozedurnamen.
Schritt 3: In diesem Schritt wird die Datenverwendung
analysiert und eine Datenquerverweistabelle erstellt. Darin
wird für jeden COBOL Codeblock seine Ein- und Ausgabendaten festgehalten.
Schritt 4: Für jede verwendete COBOL Datenstruktur wird
eine Klasse erzeugt. Das Objekt ist ein Character Array.
Jedes Feld ist ein Abschnitt dieser Zeichenfolge, identifiziert
über sein Startposition, Typ und Länge. Damit wird das
Problem der Redefinitionen, umgangen. Für jedes Datenfeld
wird eine set und eine get Methode erzeugt. Für 88 Felder
wird eine Enumerierungsklasse generiert. Für jedes Objekt
wird eine Konstruktor und eine Initialisierunsmethode angelegt. Das Ergebnis ist ein Klassenrahmen für jedes Objekt.
Schritt 5: Für jeden prozeduralen Codeblock wird eine Java
Methode erzeugt. In einem Vorkommentar werden die Einund Ausgabedaten als XML Elemente dokumentiert. Nach
jedem Codeblock werden in einem Nachkommentar die
Nachfolgemethoden ebenfalls als XML Elemente dokumentiert. Dazwischen ist jede COBOL Anweisung in eine entsprechende Java Anweisung umgesetzt. Die GOTO Anweisungen werden durch eine Zuweisung der Methodenname
zur Labelvariable mit Return ersetzt. Die wenigen Anweisungen, die nicht konvertiert werden, werden kommentiert.
Schritt 6: Die Methoden werden mit den Klassen zusammengeführt. Außerdem werden hier die angesprungenen
Methoden durch Klassennamen qualifiziert. Schließlich
werden Container Klassen für die Section Aufrufe erzeugt,
in denen die Methodenaufrufsequenzen enthalten sind.
Schritt 7: Hier werden HTML Links zwischen Daten und
Methoden (Datenfluss) sowie zwischen Methoden und
Methoden (Ablauffluss) hergestellt. Damit wird die JavaDoc
Dokumentation vollendet.
5
Code Konvertierungsergebniss
Das Ergebnis der Code-Konvertierung ist eine Menge Java
Klassen, eine für jede Stufe 1 COBOL Datenstruktur, die von
einer gemeinsamen Superklasse COBOLObjekt erben. Jede
Klasse hat eine Konstruktormethode um das singleton Objekt
zu Beginn eines Anwendungsfalles zu generieren und eine
Initialisierungsmethode um das Objekt mit den Initialwerten
zu belegen. Diese stammen aus den Value Klauseln der COBOL Datenvereinbarungen. Das Objekt selbst ist als Character
Array definiert. Für jedes benutzte Feld folgen Get und eine
Set Methoden. Bei alphanumerischen Zeichenfeldern wird ein
Objekt vom Typ String erzeugt bzw, in die Character Array
abgelegt. Bei numerischen Feldern wird entweder ein Integer
oder ein Double Wert erzeugt, bzw. abgelegt.
public static char[] R129LOCO;
public String getR129_SA1() {
return getString(R129LOCO,14,1000);
}
public void setR129_SA1(String inStr) {
setAsChar(R129LOCO,inStr,14,1000);
}
Auch in jeder Klasse ist eine Steuerungsmethode die die über
die Label-Variabel „xNextMethod“ die betroffene Methode
invokiert. Diese wird von der Controllerklasse überreicht.
Innerhalb der Verarbeitungsmethoden wird diese Variable
anhand der GOTO und PERFORM Anweisungen gesetzt.
public ProcessingInfo performOperation(ProcessingInfo
processingInfoIn) {
String methodId = processingInfoIn.getMethodId();
if (methodID.equals(“methodId01”) {
String xNextMethod = this.method.01();
ProcessingInfo processingInfoOut = new ProcessingInfo(xNextMethod);
return processingInfoOut;
}
Ein Zustandsautomat steuert den Ablauffluss über den Wert
der Label-Variabel. Es ist als recursive Prozedur implementiert.
public void runStateMachine(ProcessingInfo processingInfoIn) {
COBOLObject cobolObject =
this.getCOBOLObject(processingInfoIn);
processingInfoOut = cobolObject.performOperation(processingInfoIn);
runStateMachine(processingInfoOut);
}
Die Speicherklassen bilden eine Aggregation unter der
Kontrollerklasse. Sie sind in fünf Speicherbereiche entsprechend den Bereichen im COBOL Programm aufgeteilt: Database,Cache, Work, Input und Output
6
Stand der Migration
Mit dem Werkzeug COB2Java wurde bis jetzt das erste Paket
des Projektes mit 93 main programs, 41 sub programs, 200711
code lines, 160060 statements und 2908 function points automatisch konvertiert. Die manuelle Überarbeitung, bzw.
Reimplementierung, soll jetzt folgen. Die generierten Sourcen
– eine pro Klasse – sind in der Summe zweimal so groß wie
das ursprüngliche COBOL Source. Das liegt an den vielen
Kommentarblöcken sowie an der Set und Get Methoden die es
in COBOL nicht gegeben hat. Wahlweise wird der alte COBOL Code als Kommentar in den Java Methoden eingebettet.
Mit JavaDoc ist es möglich über HTML den Code zu betrachten und sowohl die Ablauflogik als auch den Datenfluss zu
verfolgen. Dies soll dem Java Entwickler helfen den Code
zwecks der Reimplementierung zu verstehen. Es geht hier
darum die volle Funktionalität der alten Programme in der
Java Welt zu bewahren.
Herunterladen