Die Reihe Xpert.press vermittelt Professionals in den Bereichen Softwareentwicklung, Internettechnologie und IT-Management aktuell und kompetent relevantes Fachwissen über Technologien und Produkte zur Entwicklung und Anwendung moderner Informationstechnologien.
Ulrich Gellert · Ana Daniela Cristea
Praxishandbuch Web Dynpro ABAP
123
Ulrich Gellert c/o S+P LION AG Robert-Bosch-Str. 9 68542 Heddesheim Deutschland
[email protected] Ana Daniela Cristea c/o S+P LION AG Robert-Bosch-Str. 9 68542 Heddesheim Deutschland
[email protected] ISSN 1439-5428 ISBN 978-3-642-11386-4 e-ISBN 978-3-642-11387-1 DOI 10.1007/978-3-642-11387-1 Springer Heidelberg Dordrecht London New York Die Deutsche Nationalbibliothek verzeichnet diese Publikation in der Deutschen Nationalbibliografie; detaillierte bibliografische Daten sind im Internet über http://dnb.d-nb.de abrufbar. © Springer-Verlag Berlin Heidelberg 2011 Dieses Werk ist urheberrechtlich geschützt. Die dadurch begründeten Rechte, insbesondere die der Übersetzung, des Nachdrucks, des Vortrags, der Entnahme von Abbildungen und Tabellen, der Funksendung, der Mikroverfilmung oder der Vervielfältigung auf anderen Wegen und der Speicherung in Datenverarbeitungsanlagen, bleiben, auch bei nur auszugsweiser Verwertung, vorbehalten. Eine Vervielfältigung dieses Werkes oder von Teilen dieses Werkes ist auch im Einzelfall nur in den Grenzen der gesetzlichen Bestimmungen des Urheberrechtsgesetzes der Bundesrepublik Deutschland vom 9. September 1965 in der jeweils geltenden Fassung zulässig. Sie ist grundsätzlich vergütungspflichtig. Zuwiderhandlungen unterliegen den Strafbestimmungen des Urheberrechtsgesetzes. Die Wiedergabe von Gebrauchsnamen, Handelsnamen, Warenbezeichnungen usw. in diesem Werk berechtigt auch ohne besondere Kennzeichnung nicht zu der Annahme, dass solche Namen im Sinne der Warenzeichen- und Markenschutz-Gesetzgebung als frei zu betrachten wären und daher von jedermann benutzt werden dürften. Einbandentwurf: KuenkelLopka GmbH, Heidelberg Gedruckt auf säurefreiem Papier Springer ist Teil der Fachverlagsgruppe Springer Science+Business Media (www.springer.com)
Vorwort
Getreu Albert Einsteins Motto „Example isn’t another way to teach, it is the only way to teach“ haben wir uns das Ziel gesetzt, mit diesem Buch dem Leser Web Dynpro ABAP Schritt für Schritt zu erklären. Anhand von praktischen Beispielen tauchen Sie von Kapitel zu Kapitel tiefer in die Web-Dynpro-ABAP-Welt ein. Aber auch Zusammenhänge mit anderen Bereichen werden Ihnen in Beispielen nahegebracht. In Kap. 1 erklären wir, was Web Dynpro, integriert in der SAP-NetWeaverPlattform, eigentlich ist. Kapitel 2 beschäftigt sich mit dem einfachen Einstieg „Easy Access“ in SAP. In Kap. 3 beschreiben wir den Modus anhand eines Beispiels in dem eine WebDynpro-Component erstellt wird, erklären alle Elemente einer View und zeigen, wie man mit dem ABAP Debugger Anwendungen diagnostiziert. Kapitel 4 behandelt das ABAP Dictionary in dem alle Entwicklungsobjekte erstellt werden, die wir als Basis für unsere Beispiele benutzen. Sie können schnell die nötigen Kenntnisse erwerben, wie Ihnen Entwicklungsobjekte (die im ABAP Dictionary erstellt sind) bei der Erstellung von Web-Dynpro-Applikationen helfen können. In Kap. 5 präsentieren wir Context-Knoten und Context-Attribute und erklären deren Wichtigkeit für Web Dynpro. Wir erörtern die Möglichkeiten der Erstellung, Benutzung, des Ausfüllens mit Werten und des Lesens der Inhalte. In Kap. 6 gehen wir auf Datenbindung, Context-Mapping und InterfaceMethoden ein. Zu diesem Zweck zeigen wir in einfachen Beispielen die Datenbindung. Dieses Beispiel wandeln wir stufenweise um, damit der Leser ein klares Bild vom Context-Mapping erhält (sowohl in interner als auch in externer Form – Direct Mapping und Reverse Mapping). Das Kap. 7 behandelt die View-Controller-Methoden, beginnend mit Beispielen einiger Hook-Methoden bis zu den Benutzerdefinierten Methoden und den Eventhandler-Methoden. Jede Methode wird durch ein Beispiel erläutert. Kapitel 8 widmet sich dem Layout der UI-Elemente. Im größten Kapitel (Kap. 9) werden die UI (User-Interface)-Elemente ausgiebig beschrieben. Jedes UI-Element wird durch ein Beispiel erläutert. Gleichzeitig zeigen wir für jedes UI-Element die dynamische Programmierung. Wir stellen
v
vi
Vorwort
jedoch nicht nur die UI-Elemente vor, sondern bieten dem Leser weitere Zusatzinformationen. Das Kap. 10 beinhaltet Nachrichten und Ausnahmen. Wir beginnen mit der Schaffung der nötigen Klassen (Nachrichtenklassen, Ausnahmeklassen und Assistance-Klassen) und zeigen, wie sie im Rahmen der Web-DynproKomponenten zu benutzen sind und wie damit solide Applikationen erstellt werden. Kapitel 11 beschäftigt sich mit dem Erstellen von mehrsprachigen Applikationen auf der Ebene der Interfaces und der Ebene der Stammdaten. Wir präsentieren auch den Modus, mit dem wir mit diesen Daten in Web-Dynpro-Komponenten arbeiten können. In Kap. 12 werden verschiedene Web-Dynpro-Modelle vorgestellt. Wir zeigen nicht nur die Art, in der eine Assistance-Klasse, ein Web Service und ein BAPI als Modell verwendet wird, sondern auch den Modus, in dem man Multi Component Applikationen erstellen kann. Das Kap. 13 widmet sich dem ALV (ABAP List Viewer) und den SO (Select Options). Wir fangen wieder mit einfachen Beispielen an und bauen diese stufenweise bis zu einer ALV-Output-Konfiguration und der Kombination mit SOs aus. In Kap. 14 wird die Integration der Web-Dynpro-Applikationen in das SAP-NetWeaver-Portal beschrieben. Wir präsentieren die Verbindung mit dem Backend-ABAP-System und kommen bis zu WD-Applikationen, die ein Portal Event senden und auf ein Portal Event reagieren können. Das vorletzte Kapitel (Kap. 15) handelt von Web Dynpro und Berechtigungen. Wir präsentieren kurz RBAC (Role Based Access Control) und beschreiben das SAP-NetWeaver-Berechtigungskonzept. Im letzten Kapitel (Kap. 16) präsentieren wir, wie ein Mind Map uns helfen kann Web Dynpro schneller zu lernen. Wir haben ein Mind Map entworfen, das alle lernenden Web-Dynpro-Elemente enthält und sich weiterentwickeln lässt. Die Beispiele für unser Buch wurden auf einem SAP System mit SAP NetWeaver 7.00 mit Support Package 17 erstellt. Bei SDN (www.sdn.sap.com) gibt es eine SAP-NetWeaver-Trial-Version mit ABAP und mit SAP GUI, die kostenfrei für Testzwecke genutzt werden kann. Die meisten Übungen lassen sich damit machen. Die Konfigurations-Steps sind auch bei SDN zu finden. Um mit dem SAP Interacktive Forms by ADOBE zu arbeiten, braucht man beide NetWeaver-TrialVersionen (ABAP und Java), da ADS integraler Bestandteil der SAP-NetWeaverJava-Version ist. Zusätzlich braucht man auch den ADOBE LiveCycle Designer aus dem SAP-Service-Marktplatz. Die Konfigurations-Steps sind im SAP Press-Buch SAP Interactive Forms by Adobe (Hauser et al.) beschrieben. Um mit dem Portal arbeiten zu können braucht man die SAP-NetWeaver-Java-Trial-Version. Alle Software- und Hardwareanforderungen und die Konfigurations-Steps sind im SAP Press Buch Developer’s Guide to SAP NetWeaver Portal Applications (Banner et al.) beschrieben. Die Erstellung eines Buches ist ein weiter Weg. Viele Diskussionen mit Studenten und Entwicklern haben bei uns die Idee reifen lassen, ein Praxisbuch zum Thema Web Dynpro ABAP zu erarbeiten. Wichtigster Punkt war dabei, die Leserin oder
Vorwort
vii
den Leser Schritt für Schritt anhand von praktischen Beispielen in das Themengebiet einzuarbeiten. Viele Wochenenden, Urlaube und Abende wurden investiert und die positive Unterstützung unserer Kollegen hat uns immer wieder neue Energie gegeben.
Danksagung
Bedanken wollen wir uns vor allem bei unseren Korrekturlesern Dieter Schmitt und Heinz-Jürgen Gebhardt, die uns durch ihre Hinweise und Anmerkungen eine große Hilfe waren. Ulrich Gellert möchte sich zuerst bei allen Kollegen der S + P LION AG bedanken, die ihn stets unterstützt haben. Danken will ich meinem leider viel zu früh verstorbenen Vater Gerhard Gellert, der mich 1983 in die Welt der IT eingeführt hat und ohne den unsere Firma nie das geworden wäre, was sie heute ist. Auch meiner Mutter, Gabriele Gellert, gilt mein besonderer Dank, da sie mich bis heute aktiv unterstützt und die gute Seele unseres Unternehmens ist. Ich danke meiner lieben Frau Carmen und meinen Kindern Alexa und Marc ohne ihre Unterstützung hätte ich dieses Buch nie mitgestalten können. Ana Daniela Cristea bedankt sich zuerst bei NWCON Technology Consulting, vor allem bei Thomas Muschalik, und der S + P LION AG, die mir geholfen und mich unterstützt haben. Bei dieser Gelegenheit möchte ich jenen danken, die meine Schritte während meiner Doktorarbeit begleitet haben, insbesondere zwei außergewöhnlichen Menschen: Octavian Prostean und Mircea Vladutiu. Nicht vergessen will ich auch diejenigen, die mich ermutigt haben meine ersten Bücher und Artikel zu veröffentlichen: Poanta Aron und Panoiu Caius, denen ich auf diesem Weg für ihre wertvollen Ratschläge danke. Nicht zuletzt will ich mich bei meiner Familie und Freunden bedanken. Besonders bei meiner Mutter Sabina Cristea und bei Susanne und Edgar Hammes, die mich nach Kräften unterstützt haben, damit ich die nötige Zeit hatte dieses Buch mitzugestalten. Heidelberg, Deutschland Juli 2010
Ulrich Gellert Ana Daniela Cristea
ix
Inhaltsverzeichnis
1 Was ist Web Dynpro? . . . . . . . . . . . . . . . . . . . . . . . . .
1
2 SAP Easy Access . . . . . . . . . . . . . . . . . . . 2.1 Ändern des SAP Easy Access . . . . . . . . . . 2.2 Favoriten-Liste . . . . . . . . . . . . . . . . . 2.3 Festlegen einer Transaktion als Starttransaktion 2.4 Erstellen einer Verknüpfung . . . . . . . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
5 6 6 8 9
3 Designen einer Web-Dynpro-Komponente . . . . 3.1 View . . . . . . . . . . . . . . . . . . . . . . 3.1.1 View-Layout . . . . . . . . . . . . . 3.1.2 Context-View . . . . . . . . . . . . 3.1.3 Aktionen . . . . . . . . . . . . . . . 3.1.4 Methoden . . . . . . . . . . . . . . 3.1.5 Eigenschaften . . . . . . . . . . . . 3.1.6 Attribute . . . . . . . . . . . . . . . 3.2 Componentcontroller . . . . . . . . . . . . . 3.3 Window . . . . . . . . . . . . . . . . . . . . 3.4 Web-Dynpro-Anwendung . . . . . . . . . . . 3.5 ABAP Debugger . . . . . . . . . . . . . . . 3.6 Konfiguration der Web Dynpro Anmeldeseite
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
. . . . . . . . . . . . .
11 14 14 17 18 20 21 22 23 24 25 28 31
4 ABAP Dictionary . . . 4.1 Datenelement . . 4.2 Domäne . . . . . 4.3 Struktur . . . . . 4.4 Tabelle . . . . . . 4.5 Suchhilfe . . . . 4.6 Datenbank-View . 4.7 Tabellentyp . . . 4.8 Sperrobjekt . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
35 36 37 40 42 47 50 53 54
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
. . . . . . . . .
5 Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt 57 5.1 Context-Attribute . . . . . . . . . . . . . . . . . . . . . . . . 58 5.2 Context-Knoten . . . . . . . . . . . . . . . . . . . . . . . . . 61 xi
xii
Inhaltsverzeichnis
5.2.1 5.2.2
Erzeugen eines Knotens unter Verwendung eines ABAP-Dictionary-Repository-Objekts . . . . . Arbeiten mit Kindknoten . . . . . . . . . . . . . . .
61 67
6 Datenbindung, Context-Mapping und Interface-Methoden 6.1 Datenbindung (Data binding) . . . . . . . . . . . . . . 6.2 Context-Mapping . . . . . . . . . . . . . . . . . . . . 6.2.1 Internes Context-Mapping . . . . . . . . . . . 6.2.2 Externes Context-Mapping . . . . . . . . . . 6.3 Interface-Methoden . . . . . . . . . . . . . . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
71 72 76 77 80 88
7 View-Controller-Methoden . . . . . . . . 7.1 Hook-Methoden . . . . . . . . . . . 7.1.1 wdDoInit . . . . . . . . . . 7.1.2 wdDoExit . . . . . . . . . 7.1.3 wdDoModifyView . . . . . 7.1.4 wdDoBeforeAction . . . . 7.1.5 wdDoOnContextMenu . . . 7.2 Supply-Funktion-Methoden . . . . . 7.3 Benutzerdefinierte Instanzmethoden 7.4 Fire-Methoden . . . . . . . . . . . . 7.5 Eventhandler-Methoden . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
. . . . . . . . . . .
93 93 94 97 98 104 105 110 110 113 116
8 Layout-UI-Elemente 8.1 FlowLayout . . 8.2 GridLayout . . 8.3 MatrixLayout . 8.4 RowLayout . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
121 122 124 126 128
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung . . . . . . . . . . . . . . 9.1 Action . . . . . . . . . . . . . . . . . . . . . . . . 9.1.1 TimedTrigger . . . . . . . . . . . . . . . 9.1.2 ButtonChoice – Druckknopfauswahl . . . 9.2 Selection . . . . . . . . . . . . . . . . . . . . . . . 9.2.1 DropDownByKey . . . . . . . . . . . . . 9.2.2 DropDownByIndex . . . . . . . . . . . . 9.2.3 RadioButtonGroupByIndex . . . . . . . . 9.3 Layout . . . . . . . . . . . . . . . . . . . . . . . . 9.3.1 ViewContainerUIElement . . . . . . . . . 9.3.2 TabStrip . . . . . . . . . . . . . . . . . . 9.3.3 PageHeader . . . . . . . . . . . . . . . . 9.3.4 ContextualPanel . . . . . . . . . . . . . . 9.3.5 Tray-UI-Element . . . . . . . . . . . . . . 9.3.6 MessageArea . . . . . . . . . . . . . . . . 9.4 Complex . . . . . . . . . . . . . . . . . . . . . . . 9.4.1 Table . . . . . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
. . . . . . . . . . . . . . . . .
131 132 132 135 141 141 144 147 149 150 156 160 164 165 171 174 174
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
. . . . .
Inhaltsverzeichnis
. . . . . . . . . .
. . . . . . . . . .
183 191 198 203 211 212 215 220 220 229
10 Nachrichten, Ausnahmen und Web Dynpro ABAP . . . . . . . . 10.1 Nachrichtenbehandlung . . . . . . . . . . . . . . . . . . . . 10.1.1 Dynamische Texte – gespeichert im Textpool der Assistance-Klasse . . . . . . . . . . . . . . . . 10.1.2 Text aus der Datenbanktabelle T100 . . . . . . . . . 10.2 Ausnahmebehandlung . . . . . . . . . . . . . . . . . . . . . 10.2.1 Ausnahmeklasse mit OTR Text . . . . . . . . . . . 10.2.2 Ausnahmeklasse mit Text aus der Nachrichtenklasse
. .
235 236
. . . . .
236 239 242 243 247
. . . . . . . .
251 253
. . . .
254
. . . . . . . .
255 255
. . . .
. . . .
258 260 262 262
. . . .
264
. . . .
269
. . . . . .
273
. . . . . . .
274 289 289 294 297 300 302
9.5
9.6
9.4.2 RoadMap . . . . . . . . . . . . . . . 9.4.3 PhaseIndicator . . . . . . . . . . . . 9.4.4 Tree – Sequentielle Implementierung 9.4.5 DateNavigator . . . . . . . . . . . . Graphic . . . . . . . . . . . . . . . . . . . . 9.5.1 Image . . . . . . . . . . . . . . . . . 9.5.2 BusinessGraphics . . . . . . . . . . Integration . . . . . . . . . . . . . . . . . . . 9.6.1 InteractiveForms . . . . . . . . . . . 9.6.2 FileUpload . . . . . . . . . . . . . .
xiii
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
. . . . . . . . . .
11 Erstellen mehrsprachiger Applikationen . . . . . . . . . . 11.1 Erstellung von mehrsprachigen User Interfaces . . . . 11.1.1 Internationalisierung der in ABAP Dictionary definierten Datenelemente . . . . . . . . . . . 11.1.2 Internationalisierung von in ABAP Dictionary definierten Domänen . . . . . . . . . . . . . . 11.1.3 Internationalisierung von Text aus OTR . . . . 11.1.4 Internationalisierung von Texten einer Assistance-Klasse . . . . . . . . . . . . . . . 11.1.5 Internationalisierung von Meldungen . . . . . 11.2 Mehrsprachige Datensätze in der Datenbank . . . . . . 11.2.1 Unser Beispiel . . . . . . . . . . . . . . . . . 11.2.2 Erstellung von Tabellen-Strukturen und Internationalisierung von Datensätzen . . 11.2.3 Verwendung von internationalisierten Datensätzen in Web Dynpro . . . . . . . . . . 12 Web-Dynpro-Modell . . . . . . . . . . . . . . . . . . . 12.1 Assistance-Klasse als Modell für eine Multikomponenten-Applikation . . . . . . . . . . 12.2 BAPI als Modell . . . . . . . . . . . . . . . . . . . 12.2.1 Erzeugen eines BAPI . . . . . . . . . . . 12.2.2 Verwenden des erzeugten BAPI als Modell 12.3 Web Service . . . . . . . . . . . . . . . . . . . . . 12.3.1 Erstellen des Web Service . . . . . . . . . 12.3.2 Web-Service-Konfiguration . . . . . . . .
. . . . . . .
. . . . . . . . . .
. . . . . . .
. . . . . . . . . .
. . . .
. . . . . . .
. . . .
. . . . . . .
. . . . . . .
xiv
Inhaltsverzeichnis
12.3.3 12.3.4
Testen des Web Service . . . . . . . . . . . . . . . . Inanspruchnahme des Web Service in Web Dynpro . .
13 ALV und Select Options . . . . . . . . . 13.1 SAP List Viewer . . . . . . . . . . . 13.1.1 Einfaches ALV Beispiel . . 13.1.2 ALV-Konfigurationsmodell 13.2 Select Options . . . . . . . . . . . . 13.3 ALV und Select Options . . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
. . . . . .
304 305
. . . . . .
311 311 311 314 323 330
14 Integration einer Web-Dynpro-Applikation SAP-NetWeaver-Portal . . . . . . . . . . . . . . . . . . . . . . . . 14.1 Anlegen eines Ordners . . . . . . . . . . . . . . . . . . . . . 14.2 Verbindung zum Backend-ABAP-System . . . . . . . . . . . 14.3 Anlegen einer iView . . . . . . . . . . . . . . . . . . . . . . . 14.4 Anlegen einer Rolle und Rollenzuordnung . . . . . . . . . . . 14.5 Ausführen der Applikation innerhalb des Portals . . . . . . . . 14.6 Triggern eines Portalereignisses . . . . . . . . . . . . . . . . 14.7 Reaktion auf ein Portalereignis . . . . . . . . . . . . . . . . . 14.8 Anlegen einer Seite (Page) . . . . . . . . . . . . . . . . . . . 14.9 Ausführen der Anwendung, die die Portalereignisse verarbeitet
333 334 335 338 340 342 343 347 348 350
15 Web Dynpro und Berechtigung . . . . . . . . . . . . . . . . . . . 15.1 Rollenbasierte Zugriffskontrollmodell – RBAC . . . . . . . . 15.2 Berechtigung Objektklasse . . . . . . . . . . . . . . . . . . . 15.3 Berechtigungsobjekt . . . . . . . . . . . . . . . . . . . . . . 15.4 Berechtigungsfeld . . . . . . . . . . . . . . . . . . . . . . . . 15.5 Erzeugen einer Einzelrolle und ändern seiner Berechtigungdaten 15.6 Anlegen der Web-Dynpro-Component . . . . . . . . . . . . . 15.6.1 Prüfen der Autorisierung des aktuellen Benutzers . . . 15.6.2 Anbinden der Benutzer-Rolle und Ausführen der Applikation . . . . . . . . . . . . . . . . . . . .
353 355 356 357 357 362 363 366
16 Web Dynpro ABAP Mind Map . . . . . . . . . . . . . . . . . . . . 16.1 Erstellung einer Mind Map . . . . . . . . . . . . . . . . . . . 16.2 Web Dynpro ABAP Mind Map . . . . . . . . . . . . . . . . .
371 371 372
Abkürzungsverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . .
373
Die Autoren . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
375
Bibliografie . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
377
Sachverzeichnis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
379
368
Kapitel 1
Was ist Web Dynpro?
Logic will get you from A to B. Imagination will take you everywhere. Albert Einstein
Zusammenfassung In diesem Kapitel präsentieren wir Lokalisierung und Rolle des Web Dynpro innerhalb der SAP-NetWeaver-Plattform. Entsprechend beginnen wir mit den Schichten (Layers) der SAP-NetWeaver-Plattform, fahren dann mit der Wichtigkeit des Application Platform Layers fort, und schließen mit Lokalisierung und Rolle von Web Dynpro (ABAP and Java) innerhalb des ABAP-Anwendungsservers (Application Server ABAP) und, entsprechend, des Java-Anwendungsservers (Application Server Java) ab. Um die in der Überschrift gestellte Frage beantworten zu können, müssen wir uns die SAP-NetWeaver-Technologie-Plattform ansehen (Abb. 1.1). Wie wir sehen können, gibt es vier Bereiche (Layers): Application Platform, Process Integration, Information Integration und People Integration. Die Application Platform stellt die technische Basis für fast alle anderen SAPProdukte dar. Daher spielt sie eine zentrale Rolle im SAP NetWeaver. Die Application Platform bietet uns im Wesentlichen zwei Programm-Interfaces: ABAP und Java (J2EE). ABAP ist das Programm-Interface für Application Server (AS), ABAP und Java das Programm Interface für AS Java. Zur Entwicklung von ABAP- und Java-Applikationen haben wir zwei unterschiedliche Entwicklungsumgebungen: Die ABAP Workbench für ABAP und das SAP NetWeaver Developer Studio für Java. Beide Entwicklungsumgebungen geben uns die Möglichkeit, web-basierte Anwendungen durch die Nutzung von DECLARATIVEN PROGRAMMTECHNIKEN, die auf dem Model View Controller basieren, zu erzeugen. Das SAP NetWeaver Developer Studio ist die SAP-eigene Entwicklungsumgebung, um Java-basierte MULTILAYER BUSINESS APPLICATIONS zu erzeugen. Die Entwicklungsumgebung basiert auf Eclipse und gibt uns eine WEB DYNPRO PERSPECTIVE zur Erstellung von Web-Dynpro-Java-Applikationen (Abb. 1.2).
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_1,
1
2
Abb. 1.1 SAP-NetWeaver-Technologie-Plattform [SAP]
Abb. 1.2 SAP NetWeaver Developer Studio – Web Dynpro Perspective
1
Was ist Web Dynpro?
1
Was ist Web Dynpro?
3
Alle Werkzeuge, die wir zur Erstellung von Web-Dynpro-Java-Anwendungen brauchen, finden wir im SAP NetWeaver Developer Studio. Die ABAP Workbench ist die SAP-eigene Entwicklungsumgebung um ABAPbasierte MULTILAYER BUSINESS APPLICATIONS zu entwickeln. Diese Entwicklungsumgebung bietet uns den Web Dynpro Explorer um Web-DynproABAP-Komponenten zu erzeugen (Abb. 1.3).
Abb. 1.3 ABAP Workbench – Web Dynpro Explorer
In der folgenden Abbildung zeigen wir die Struktur des ABAP Application Servers. Die meisten AS ABAP-Komponenten lassen sich in drei Ebenen aufteilen: • Präsentations-Ebene • Business-Ebene • PERSISTENCE-Ebene Web Dynpro ABAP ist Teil der Präsentations-Ebene und Standard-UITechnologie von SAP, um WEB BUSINESS APPLICATIONS ohne HTML- oder Java-Script-Kenntnisse zu entwickeln. Web Dynpro ABAP bietet viele Vorteile, zum Beispiel: • • • • •
Genaue Trennung von Layout und Geschäftsdaten; Wiederverwertbarkeit und größere Wartungsfreundlichkeit; Automatische Input-Prüfung; Automatische Datenübermittlung durch Data Binding; WYSIWYG (What You See Is What You Get) View Editor.
4
1
Was ist Web Dynpro?
Abb. 1.4 AS ABAP [SAP]
Web Dynpro ABAP und Web Dynpro Java bieten überwiegend die gleichen Funktionalitäten. Natürlich gibt es dennoch einige Unterschiede zwischen beiden; zum Beispiel: • Anders als Web Dynpro ABAP verfügt Web Dynpro JAVA über ein ViewSet, welches uns durch die Verwendung von bestimmten vor-definierten Layouts erlaubt, mehr Views in ein Bild zu integrieren. Unter diesem Gesichtspunkt ist ihre Gemeinsamkeit das ViewContainer-UI-Element. • Anders als Web Dynpro ABAP bietet Web Dynpro Java grafische Tools, die das Programmieren erleichtern; wie zum Beispiel den Navigation Manager und Diagram View. Web Dynpro ABAP hingegen verfügt nur über ein Tool zur Visualisierung und Definition der Window-Struktur. Web Dynpro ABAP ist der Gegenstand dieses Buches. Mehr Informationen über Web Dynpro Java finden Sie in dem Buch Inside Web Dynpro for Java von Chris Whealy.
Kapitel 2
SAP Easy Access
The way to get started is to quit talking and begin doing. Walt Disney
Zusammenfassung Dieses Kapitel präsentiert das SAP Easy Access, wobei einige Aspekte aus der täglichen Arbeit besonders hervorgehoben werden. So zeigen wir, wie Standardeinstellungen geändert werden können, wie man häufig verwendete Transaktionen der Favoritenliste hinzufügt und wie eine Verknüpfung (Shortcut) auf der Benutzeroberfläche (Desktop) erzeugt wird. Der SAP Easy Access wird automatisch nach der Anmeldung im SAP-System gestartet. Auf der linken Seite wird das Benutzermenü angezeigt. In diesem Menü befinden sich alle zum Arbeiten benötigten Funktionen (Abb. 2.1).
SAP Easy User Menu
Abb. 2.1 SAP Easy Access
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_2,
5
6
2
SAP Easy Access
2.1 Ändern des SAP Easy Access Über die Menüpunkte Zusätze -> Einstellungen können wir das Easy-AccessMenü durch Spezifizieren folgender Einstellungen verändern: • Die Platzierung der Favoriten; • Die Ausgabe des Menüs; • Das Easy-Access-Bild auf der rechten Seite des Bildschirms ein- oder ausblenden; • Die technischen Namen ein- oder ausblenden (Abb. 2.2).
Abb. 2.2 Einstellungen
2.2 Favoriten-Liste Das „User-Menü“ wird im Allgemeinen von den Administratoren festgelegt, wir können jedoch unsere eigene Favoriten-Liste definieren. Unsere eigene FavoritenListe kann Bestandteile wie Transaktionen, Dateien, Web-Adressen oder andere Objekte enthalten. Um neue Transaktionen zur Favoriten-Liste hinzuzufügen, benutzen wir das Menü Favoriten -> Transaktion einfügen (Abb. 2.3).
Abb. 2.3 Einfügen einer Transaktion in die Favoriten-Liste
2.2
Favoriten-Liste
7
Als Resultat erscheint das neue Element in der Favoriten-Liste (Abb. 2.4).
Abb. 2.4 Favoriten-Liste
Die Liste der SAP-Transaktionen finden wir in der Tabelle TSTC. Neben den im SAP-System vordefinierten Transaktionen können wir auch unsere eigenen Transaktionen erstellen (z.B. mithilfe der Transaktion SE93), die in die Tabelle eingefügt werden. Jedes Mal, wenn wir eine Transaktion benutzen, prüft das System, ob sie in der Tabelle eingetragen ist und ob wir die entsprechende Berechtigung haben die Transaktion zu benutzen. Zur Unterstützung unserer täglichen Aufgaben haben wir hier einige Transaktionen hinzugefügt, die wir in diesem Buch benutzen (Abb. 2.5).
Abb. 2.5 Gebräuchliche Transaktionen
Um andere Objekte hinzuzufügen, können wir diese aus dem Menü Favoriten -> Sonstige Objekte einfügen (Abb. 2.6) auswählen. Im folgenden Beispiel fügen wir eine Webadresse ein, um eine SDN-Seite zu öffnen (Abb. 2.7). Wir benutzen den Menüpunkt Favoriten -> Download auf PC um alle in unserem Favoriten-Ordner enthaltenen Objekte auf unserem Computer zu speichern. Um diese Liste in ein SAP-System zu laden, wird die Funktion Favoriten -> Upload vom PC benutzt.
8
2
SAP Easy Access
Abb. 2.6 Einfügen neuer Objekte in die Favoriten-Liste
Abb. 2.7 Einfügen einer Webadresse
2.3 Festlegen einer Transaktion als Starttransaktion Wir haben die Möglichkeit in Zusätze -> Starttransaktion festlegen (Abb. 2.8) eine Transaktion als Starttransaktion zu definieren. In diesem Fall wird die gewünschte Transaktion (hier die SE80-Transaktion) automatisch nach dem Anmelden im SAP-System ausgeführt. Dadurch wird das SAP-Easy-Access-Menü nicht mehr angezeigt.
Abb. 2.8 Einstellung des „Starttransaktion festlegen“-Dialogfensters
2.4
Erstellen einer Verknüpfung
9
2.4 Erstellen einer Verknüpfung Nachdem wir den SAP GUI installiert haben, erscheint ein SAP Login Icon auf unserem Bildschirm. Wenn wir dieses Icon benutzen, können wir uns im SAPSystem anmelden. Zusätzlich können wir eine Verknüpfung erstellen. Auch durch diese werden wir im System angemeldet, allerdings müssen wir dadurch nicht die ganzen Einträge in der SAP-Anmeldemaske vornehmen. Die Verknüpfung ermöglicht uns aber nicht nur einen schnellen Einstieg in das System. Wir können z.B. auch SAP-Transaktionen starten, einen Report anstoßen oder einen Systembefehl ausführen. Um z.B. eine Verknüpfung auf unserem Bildschirm zu erzeugen, die die Transaktion SE80 startet, können wir den WIZARD benutzen, der sich im LayoutMenü befindet, indem wir das entsprechende Icon in der Funktionsliste anklicken (Abb. 2.9).
Abb. 2.9 Erstellen einer Verknüpfung auf dem Desktop
Eine weitere Möglichkeit eine Verknüpfung zu erzeugen ist, eine Transaktion oder ein anderes Objekt unserer Favoriten-Liste auszuwählen und das Menü Bearbeiten -> Verknüpfung erstellen auf dem Desktop zu benutzen.
Kapitel 3
Designen einer Web-Dynpro-Komponente
Experience is something you don’t get until just after you need it Steven Wright
Zusammenfassung Das vorliegende Kapitel ist den grundlegenden Elementen einer Web-Dynpro-Component gewidmet. Darüber hinaus zeigen wir, wie der ABAP Debugger dazu verwendet werden kann, eine Web-Dynpro-Anwendung zeilen- oder abschnittsweise auszuführen, und wie das neue vom ABAP Debugger angebotene Werkzeug zu nutzen ist um an die Werte der Context-Attribute zu gelangen. Um eine Web-Dynpro-ABAP-Komponente zu entwickeln, müssen wir die ABAP Workbench des ABAP Application Servers öffnen. Wir müssen allerdings als Entwickler autorisiert sein oder einen Entwicklerschlüssel besitzen, um mit der ABAP Workbench arbeiten zu können. Wenn wir die SAP-NetWeaver-ABAPTrial-Version benutzen, können wir den BCUSER benutzen, der automatisch als Entwickler definiert ist. WebDynpro ist ab der NetWeaver-Version 2004 verfügbar. Nachdem wir uns am ABAP Application Server angemeldet haben, können wir die Transaktion SE80 verwenden, um den Object Navigator (Abb. 3.1) aufzurufen. Für alle Objekte, die wir mit dem ABAP Workbench Tool entwickeln, benutzen wir den Object Navigator. Im Object Navigator können wir nicht nur Web-Dynpro-Anwendungen entwickeln, sondern auch andere Objekte wie z.B. Reports, Datenbanktabellen, Datenelemente, Klassen, Funktionsbausteine, etc.). Die Objekte, die wir als Kunde erstellen, haben an erster Stelle ein „y“ oder „z“. Daher haben wir eine Web-Dynpro-Component mit dem Namen „y_wd_ component“ erstellt. Alle mit dem ABAP Workbench Tool erstellten Objekte müssen wir in ein Paket übertragen. Wir können das Standardpaket „$TMP“ verwenden, um TestProgramme ohne Transporte zu erstellen, oder wir verwenden eigene Pakete. Im folgenden Beispiel haben wir ein eigenes Paket mit dem Namen Y_WEBDYNPRO erstellt (Abb. 3.2).
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_3,
11
12
3 Designen einer Web-Dynpro-Komponente
Abb. 3.1 Object Navigator
Abb. 3.2 Erstellung des Paketes Y_WEBDYNPRO
Wir haben den Pakettyp „Kein Hauptpaket“ benutzt, da dieses Paket nur Entwicklungsobjekte und keine anderen Pakete beinhaltet. Nachdem wir das Paket erstellt haben, erzeugen wir wie folgt eine Web-DynproKomponente: Rechte Maustaste auf dem Paketnamen drücken und im Kontextmenü Anlegen -> Web Dynpro -> Web-Dynpro-Component auswählen. Wir müssen den Komponenten-Namen, eine kurze Beschreibung, den zu erstellenden Typ, den Window-Namen und den View-Namen angeben (Abb. 3.3). unsere Eingaben bestätigt haben, Nachdem wir mit dem grünen Häkchen müssen wir die neue Komponente einem Paket zuordnen (Abb. 3.4). Die Resultate, das Paket Y_WEBDYNPRO und unsere erste Web-DynproComponent, können wir im Objekt-Navigator sehen (Abb. 3.5). Das Entwicklungsobjekt, das in blau gekennzeichnet ist, ist noch nicht aktiv. Nachdem wir die Web-Dynpro-Component erstellt haben, müssen wir sie aktivieren (Abb. 3.6).
3
Designen einer Web-Dynpro-Komponente
Abb. 3.3 Anlegen einer Web-Dynpro-Component
Abb. 3.4 Paketzuordnung einer Web-DynproComponent
Abb. 3.5 Der Inhalt unseres Paketes
13
14
3 Designen einer Web-Dynpro-Komponente
GELLERT GELLERT GELLERT GELLERT GELLERT
Abb. 3.6 WD-Component: Aktivierung
3.1 View Jede Web-Dynpro-Applikation hat mindestens eine View. Jede View hat ein View-Layout, in dem unterschiedliche UI-Elemente (User-Interface-Elemente) wie zum Beispiel Texteingabefelder, Tabellen oder Buttons definiert sind. Einige UI-Elemente können auch weitere UI-Elemente enthalten. Die Position der UIElemente erfolgt durch die Nutzung des Layouts und des Data Layouts. Jede View hat einen View-Controller, der automatisch erzeugt wird, und verschiedene Tabreiter (Eigenschaften, Layout, Inbound-Plugs, Outbound-Plugs, Context, Attribute, Aktionen und Methoden). Dies zeigt, dass die View aus vielen einzelnen Teilen besteht.
3.1.1 View-Layout Der Bildschirminhalt einer View wird im Tabreiter „Layout“ designt. Das ViewLayout ist in 3 Bereiche unterteilt: • UI-Elemente-Bibliothek; • View Designer; • Kontext-Menü, UI-Element-Eigenschaften und UI-Element-Hierachie (Abb. 3.7) Die UI-Elemente befinden sich in einer Bibliothek und können über das View Layout eingestellt werden. Wir haben verschiedene Möglichkeiten, um ein UIElement in das View-Layout einzufügen. Zum Beispiel: • durch das Betätigen der rechten Maustaste auf dem Feld ROOTUIELEMENTCONTAINER (Abb. 3.8); • durch Drag & Drop (Abb. 3.9).
3.1
View
15
Tipp Falls ein Fehler passiert und wir im View-Layout die UI Element Library und den View Designer nicht sehen, müssen wir die IP-Adresse auf den Hostnamen mappen, weil Web Dynpro ABAP einen vollqualifizierten Domänennamen FQDN verwendet; schließlich werden die URLs, die die IP-Adressen enthalten, nicht unterstützt. Zur Umsetzung des Mappings tragen wir in der HOSTS-Datei (C:/Windows/system32/ drivers/etc) die IP-Adresse und den Hostnamen, getrennt durch mindestens ein Leerzeichen, ein. Falls der Fehler „URL http://hostname:port/sap/bc/wdvd call was terminated because the corresponding service is not available“ auftritt, müssen wir den entsprechenden Dienst (service) über die SICF-Transaktion aktivieren.
View Designer Context Menus UI-Elemente UI-Element Bibliothek
UI-Elemente Eigenschaften
Abb. 3.7 View-Layout
Abb. 3.8 Einfügen eines UI-Elements in eine View
16
3 Designen einer Web-Dynpro-Komponente
Drag & Drop
Abb. 3.9 Einfügen eines UI-Elements in eine View
Alle UI-Elemente, die wir in einem Bildschirm erzeugen, sind „Kinder“ des Knotens ROOTUIELEMENTCONTAINER und sind in einer Hierarchie, in der ROOTUIELEMENTCONTAINER das oberste Element ist. Mit dem Befehl „Root Element austauschen“ haben wir die Möglichkeit, den ROOTUIELEMENTCONTAINER von einem TransparentContainer in ein anderes UI-Element (Table, FlashIsland, Group, etc.) umzuwandeln. In diesem Fall können wir z.B. das FlashIsland-UI-Element benutzen, um Adobe Flex in unsere Web-DynproComponent zu integrieren. Die Umwandlung ist nur möglich, wenn der ROOTUIELEMENTCONTAINER keine „Kinder“-UI-Elemente hat. In unserem ROOTUIELEMENTCONTAINER haben wir ein GROUPUI-Element, ein INPUTFIELD-UI-Element, ein LABEL-UI-Element, ein TEXTVIEW-UI-Element und ein BUTTON-UI-Element eingefügt (Abb. 3.10). Group Label InputField Button TextView
Abb. 3.10 View-Layout
Wenn wir individuelle UI-Elemente im Layout einer View auswählen, werden ihre Eigenschaften in Bereich Eigenschaften angezeigt. Hier können wir die Eigenschaften von jedem Element verändern. Wir haben in unserem Beispiel die Eigenschaft Design des Button-UI-Elements und die Eigenschaft State des InputField-UI-Elements geändert (Abb. 3.11).
3.1
View
17
Abb. 3.11 Eigenschaften der UI-Elemente
Als Ergebnis der Änderung der Eigenschaft state des InputField-UI-Elements von NORMAL zu REQUIRED wird das mit diesem UI-Element assoziierte Label mit einem roten Stern gekennzeichnet, sodass der Anwender erkennen kann, dass dieses Eingabefeld ein Pflichtfeld ist. Für eine Eigenschaft können wir feste Zeichenketten erstellen, aus einer Liste wählen oder Eigenschaften an Context-Knoten oder Attribute mit Hilfe des BindingButtons binden. Für die text-Eigenschaft eines UI-Element-Buttons, haben wir eine feste Zeichenkette „Speichern“ erstellt. Für die design-Eigenschaft haben wir aus der Liste eines der unterstützten Designs ausgewählt. Es ist notwendig, die value-Eigenschaft des UI-Elements InputField und die text Eigenschaft des UI-Elements TextView zu binden. Dafür erzeugen wir zwei Context-Attribute. Unter Verwendung von „Context Menus“ haben wir die Möglichkeit, für eine Applikation unsere eigenen Kontextmenüs anzulegen, die dann im Browser angezeigt werden, wenn der Benutzer einen Rechtsklick auf ein UI-Element macht. Im Standardmodus bietet das Web-Dynpro-Framework die Standardmenüs mit bestimmten Funktionalitäten an, z.B. das Verstecken eines UI-Elements im Browser. Nach Ausführung der Anwendung können wir diesen Standardmodus durch Rechtsklick auf das inputField-UI-Element testen.
3.1.2 Context-View Die Daten sind im Context gespeichert, und die UI-Elemente sind die einzigen Objekte, mit denen der Benutzer interagiert.
18
3 Designen einer Web-Dynpro-Komponente
Jede View hat eine Context-View, wo wir Context-Knoten und Context-Attribute erstellen können. Via Datenbindung (data binding) bietet der Context eines ViewControllers eine View mit allen benötigten Daten. Für unsere Applikation erzeugen wir zwei Context-Attribute namens NAME und GREETING, vom Typ string (Abb. 3.12).
Abb. 3.12 Erstellung eines Attributs in der Context-View
Um die Daten auf den Bildschirm zu bringen und Daten vom Benutzer zu lesen, verbinden wir die passenden UI-Elementeigenschaften mit Attributen oder Knoten. In unserem Fall verbinden wir die Eigenschaft value vom InputField-UI-Element mit dem NAME-Attribut. Um eine Begrüßung für den Benutzer zu erstellen und diese anzuzeigen, nachdem der Benutzer den Speichern-Button klickt, verbinden wir die Eigenschaft text des UI-Element TextView mit dem GREETING-Attribut. Diese Verbindungen sind als Datenbindungen bekannt (Abb. 3.13). Der Effekt der Bindung ist, dass zur Laufzeit alle Datenänderungen in beide Richtungen transportiert werden und diese Änderungen alle Eigenschaften betreffen, die an dieses Element gebunden wurden.
3.1.3 Aktionen Einige der UI-Elemente haben spezielle Ereignisse, die mit den Benutzeraktionen verknüpft sind. Der UI-Element-Button ist einer dieser UI-Elemente und deswegen müssen wir eine Aktion erstellen, die auf die Interaktion des Benutzers reagiert. Dafür verwenden wir den Tabreiter „Aktionen“ (Abb. 3.14).
3.1
View
19
Abb. 3.13 Datenbindung (Data binding)
Abb. 3.14 Erstellen einer Aktion
Wie wir sehen, hat jede Aktion eine korrespondierende Eventhandler-Methode (Ereignisbehandler), die automatisch vom Framework generiert wird. Eine Eventhandler-Methode ist eine spezielle Methode eines View-Controllers, der das ONACTION-Präfix hat, gefolgt vom Aktionsnamen. Für die SPEICHERN-Aktion generiert das Framework den ONACTIONSPEICHERN-Eventhandler. Nach Erstellen einer Aktion können wir diese einem UI-Element zuweisen, das mit einem Ereignis verbunden ist (Abb. 3.15).
Abb. 3.15 Zuweisen einer Aktion zu einem UI-Element
20
3 Designen einer Web-Dynpro-Komponente
Nach Generierung ist diese Methode zunächst leer, aber wir können sie im Tabreiter „Methoden“ mit Sourcecode füllen.
3.1.4 Methoden Im Tabreiter „Methoden“ einer View können wir einige Typen von Methoden finden (z.B. Eventhandler-Methoden, Hook-Methoden, benutzerdefinierte InstanzMethoden). In unserem Fall können wir im Tabreiter „Methoden“ die Hook-Methoden finden, vom Framework automatisch generiert, sowie unsere Eventhandler-Methode onactionspeichern (Abb. 3.16).
Abb. 3.16 Tabreiter „Methoden“
Mit Doppelklick auf den Methodennamen öffnen wir den ABAP-Editor (Abb. 3.17). Auf diese Weise können wir den Sourcecode einfügen.
Abb. 3.17 ABAP-Editor
Der Benutzer trägt seinen Namen ein, den wir für das Anzeigen der Begrüßungsnachricht mit der Hilfe des TextView-UI-Element verwenden. Um eine
3.1
View
21
Begrüßung für den Anwender zu erzeugen, verknüpfen wir seinen Namen mit der Zeichenkette ‘WILLKOMMEN’ und übergeben diesen String-Wert an das Attribut GREETING. Anschließend setzen wir das InputField-UI-Element zurück. Um das zu tun, übergeben wir eine leere Zeichenkette an das NAME-Attribut, welches an das korrespondierende UI-Element gebunden ist (Listing. 3.1). METHOD onactionspeichern. DATA: lv_name TYPE string, lv_greeting TYPE string. wd_context->get_attribute( EXPORTING name =‘NAME‘ IMPORTING value = lv_name ). CONCATENATE ‘willkommen’ lv_name INTO lv_greeting SEPARATED BY space. wd_context->set_attribute( name = ’GREETING’ value = lv_greeting ). CLEAR lv_name. wd_context->set_attribute( name = ’NAME’ value = lv_name ). ENDMETHOD.
Listing 3.1 Eventhandler-Methode onactionspeichern
Für weitere Details zu Methoden verweisen wir auf das Kapitel „ViewController-Methoden“.
3.1.5 Eigenschaften Im Tabreiter „Eigenschaften“ können wir einen Beschreibungstext für unsere View anlegen und finden Informationen über die View und über die Person, die diese View angelegt und geändert hat. In diesem Tab können wir auch die Lebensdauer der View setzen: • framework controlled – durch das Framework kontrolliert; • when visible – Lebensdauer auf Sichtbarkeit limitiert. Ein View Controller wird immer gelöscht, sobald die korrespondierende View nicht länger auf dem User Interface angezeigt wird. Es wird benutzt, wenn eine View einmalig und nicht wiederholt angezeigt wird. Zusätzlich bietet der Tabreiter „Eigenschaften“ die Möglichkeit, die Verwendbarkeit zu definieren (Abb. 3.18).
22
3 Designen einer Web-Dynpro-Komponente
Controller-Verwendung anlegen
Abb. 3.18 Tabreiter „Eigenschaften“
Wir können eine Verwendbarkeit definieren, um auf die Methoden eines anderen internen Controllers oder auf einen anderen Interface Controller zuzugreifen, wenn die Verwendbarkeit für eine externe Komponente definiert ist. Um eine neue Verwendbarkeit in der „Verwendete Controller/Components“-Tabelle zu erstellen, müssen wir den Button „Controller-Verwendung anlegen“ wählen. Die Tabelle „Verwendete Controller/Components“ beinhaltet eine Liste aller globalen Controller unserer eigenen Komponente. Falls wir Verwendbarkeiten definieren, enthält diese Liste auch die externe Komponente und deren Interface Controller. In unserem Fall verwenden wir keine externen Komponenten. In der Liste haben wir lediglich den globalen Controller COMPONENTCONTROLLER. Wir müssen spezifizieren, dass die Verwendbarkeit des korrespondierenden ComponentControllers für jeden View Controller automatisch erzeugt wird.
3.1.6 Attribute Jeder View-Controller beinhaltet einige Attribute, die automatisch vom Framework generiert werden (Abb. 3.19).
Abb. 3.19 Tabreiter “Attribute”
3.2
Componentcontroller
23
Das Attribut WD_COMP_CONTROLLER ist eine Referenzvariable vom Typ IG_COMPONENTCONTROLLER, die wir benutzen können, um auf alle öffentlich zugänglichen Methoden der Component global generated interface des korrespondierenden Component-Controller zuzugreifen. Das Attribut WD_THIS ist eine Selbstreferenz zum lokalen Controller-Interface. Diese Selbstreferenz arbeitet ähnlich wie die Selbstreferenz (ME), die wir in ABAP Objects finden. Wir können sie zum Beispiel benutzen, um eine benutzerdefinierte Methode aufzurufen. Das Attribut WD_CONTEXT ist eine Referenz auf den Controller-Context. Die IF_WD_CONTEXT_NODE-Schnittstelle liefert zahlreiche Methoden, die uns dazu befähigen, Lese- und Schreibzugriffe auf einen Context-Knoten vorzunehmen. Zusätzlich können wir unsere eigenen Attribute erstellen. Diese Attribute werden dazu benutzt, die Anwendungsdaten zu speichern, die für die UI-Elemente nicht relevant sind und die wir nicht im Context speichern. Um auf diese Attribute zuzugreifen, benutzen wir die Selbstreferenz: wd_this->attribute_name
3.2 Componentcontroller Standardmäßig hat jede Web-Dynpro-Komponente einen Component-Controller, der als zentrale Controller-Instanz in der gesamten Komponente agiert (Abb. 3.20).
Abb. 3.20 Componentcontroller
Daten, die über verschiedene Views benötigt werden, können in diesem Kontext gespeichert werden. Neben dem Tabreiter „Context“ bietet jeder COMPONENTCONTROLLER die Tabs: Eigenschaften, Attribute, Ereignisse und Methoden. Nachfolgend sehen wir in unseren Beispielen, wie wir über Komponentengrenzen (Cross-Component) auf die hier definierten Methoden und Attribute zugreifen können.
24
3 Designen einer Web-Dynpro-Komponente
3.3 Window Ein Window ist eine Einheit, in die wir alle Views einfügen, die wir für die Konstruktion des Endanwender-Screens benötigen. Wenn Anwender und View interagieren, wird durch diese Interaktion eine Anfrage an den Server gesandt. Als Antwort wird ein oder werden mehrere Views, die das aktuelle Screen bilden, durch andere Views ersetzt. Dies wird durch Navigations-Links zwischen den verschiedenen Views im Window ermöglicht. Jede Web-Dynpro-Component kann mehrere Windows haben. Wir haben nur ein Window namens W-default erstellt. Im Allgemeinen sind in einem Window ein oder mehrere Views eingebettet. Die erste bei Erstellung der Web-Dynpro-Component generierte View ist direkt im Window enthalten. Um andere Views in ein Window einzufügen, können wir entweder Drag & Drop nutzen oder, um zwischen Einbau eines Empty View oder des von uns erstellten Views wählen zu können, den Rechtsklick auf den Window-Namen (Abb. 3.21).
Abb. 3.21 View einbetten
Der Empty View ist ein spezieller View-Typ, dargestellt im ViewContainerUIElement-Beispiel. In jedem Window ist zumindest eine View als default gekennzeichnet. Eine Default View ist die erste View, die beim Aufruf des Windows angezeigt wird. Die erste eingebettete View ist zwar als default gekennzeichnet, aber wir können dies ändern. Um eine View als default zu kennzeichnen, wählen wir nach Rechtsklick auf den View-Namen „Als Default setzen“ aus dem Kontextmenü. Mittels Verwendung von Inbound-Plugs und Outbound-Plugs definieren wir die Navigation zwischen Views oder Windows. Für ein Window können diese Plugs
3.4
Web-Dynpro-Anwendung
25
vom Typ Standard, Startup oder Resume sein. Wie wir sehen können, generiert das Framework für jedes Window ein Inbound-Plug vom Typ Startup und eine EventHandler-Methode (Abb. 3.22). Durch die Anwendung dieser EventHandlerMethode können wir z.B. die URL-Parameter von einer Web-Dynpro-Applikation lesen.
Abb. 3.22 Default Inbound-Plug für ein Window
Für eine View besteht keine Möglichkeit einen bestimmten Plug-Typ zu definieren.
3.4 Web-Dynpro-Anwendung Nach der Entwickung einer Web-Dynpro-Component müssen wir den Anwendern Zugriff auf ihre Funktionalitäten zur Verfügung stellen. Hierzu müssen wir eine Web-Dynpro-Anwendung kreieren (Abb. 3.23).
Abb. 3.23 Erstellung einer Web-Dynpro-Anwendung
26
3 Designen einer Web-Dynpro-Komponente
Für jede Anwendung generiert das Framework eine URL. Wir finden diese URL im Tabreiter „Eigenschaften“ (Abb. 3.24).
Abb. 3.24 URL der Anwendung
Gleichzeitig können wir hier festlegen, wie Meldungen behandelt werden: • „Message Component bei Bedarf einblenden“ – die Meldungs-Komponente wird nur angezeigt, wenn wir eine Meldung haben; • „Message Component immer einblenden“ – die Meldungs-Komponente wird immer angezeigt, auch dann, wenn wir keine Meldungen haben. Durch Verwendung des Tabreiters „Parameters“ können wir unsere eigenen Parameter für die Anwendung definieren oder können aus den Parametern wählen, die uns das Web Dynpro Framework bietet (Abb. 3.25). Um die Anwendung laufen zu lassen, können wir den Testen/Ausführenverwenden oder wir können die URL kopieren und in den Browser einfügen (Abb. 3.26). Wenn der Anwender mit dem Screen interagiert, werden spezielle AdapterTechniken angewendet um Daten und Events als Teil des Anfrage-Antwort-Zyklus in die Browserformate wie HTML, JavaScript oder XML zu konvertieren. In Abb. 3.27 können wir den generierten Sourcecode für unsere Web-Dynpro-Component sehen.
3.4
Web-Dynpro-Anwendung
27
Abb. 3.25 Anwendungsparameter-Liste
Standard Context Menus
Abb. 3.26 Starten der Anwendung
28
3 Designen einer Web-Dynpro-Komponente
Abb. 3.27 Generierte Source-Datei
3.5 ABAP Debugger Wenn in unseren Web-Dynpro-Komponenten irgendwelche Fehler auftreten, können wir den ABAP Debugger verwenden, um die WD-Komponente zeilen- oder abschnittsweise auszuführen. Um mit dem Debugger zu arbeiten, können wir an den Stellen, an denen das Programm pausieren soll, Unterbrechungspunke (breakpoints) festlegen (Abb. 3.28). Wir starten die Anwendung und in dem Moment, wenn der Programmfluss den definierten Breakpoint erreicht, wird der ABAP Debugger geöffnet (Abb. 3.29). In „Process Information“, der Hauptkomponente des ABAP Debugger, ist ersichtlich, dass wir eine http-Anwendung debuggen. Der Zusatz „exklusiv“ bezieht sich darauf, dass die Anwendung, die wir debuggen, einen „Work Process“ des Application Servers belegt. Durch Verwendung der Buttons der Befehlszeile können wir den Programmablauf kontrollieren. Zum Beispiel können wir uns dafür entscheiden, das Programm Zeile für Zeile ablaufen zu lassen
(Einzelschritt F5), oder wir führen das
Programm bis zum nächsten Breakpoint aus (Fortsetzen F8). Wir können die Werkzeuge des ABAP Debugger verwenden, um Informationen über die Variable zu erhalten (Abb. 3.30). , können wir ein Auswahlfenster öffMit dem „Neues Werkzeug“-Button nen, das die Möglichkeit bietet, auf zusätzliche Funktionalitäten zuzugreifen. Im
3.5
ABAP Debugger
29
Click
Abb. 3.28 Setzen von Breakpoints
Abb. 3.29 ABAP Debugger
Abschnitt Spezialwerkzeuge finden wir das für ein verbessertes Debugging der Web-Dynpro-Komponenten erstellte Werkzeug (Abb. 3.31). Wie aus Abb. 3.32 ersichtlich, bietet sich uns die Möglichkeit, Zugriff auf alle individuellen Elemente der Web-Dynpro-Komponente zu haben. Wir können die View-Attribute, das View-Layout, die UI-Elemente und die Datenbindung, die Context-Struktur und ihre Attribute etc. sehen.
30
3 Designen einer Web-Dynpro-Komponente
Abb. 3.30 Werkzeug des ABAP Debugger
Abb. 3.31 ABAP Debugger – „Neues Werkzeug“ Auswahl-Fenster
Wir können nicht nur die Context-Struktur sehen, sondern können auch das Laufzeit-Objekt anzeigen, indem wir aus dem Kontextmenü „Laufzeit-Objekt anzeigen“ wählen. (Abb.3.33). Dies sind nur einige der Fähigkeiten des ABAP Debugger, die zusammen mit anderen Performance Tools (z.B. die Transaktionen WD_TRACE_TOOLS, S_MEMORY_INSPECTOR) eingesetzt werden können, um uns bei der Entwicklung von Web-Dynpro-Anwendungen zu unterstützen.
3.6
Konfiguration der Web Dynpro Anmeldeseite
31
Abb. 3.32 Der ABAP Debugger _ Web-Dynpro-Werkzeug
Abb. 3.33 Anzeige des Laufzeit-Objekts
3.6 Konfiguration der Web Dynpro Anmeldeseite Wie wir sehen konnten, erscheint, wenn unsere Anwendung läuft, eine Anmeldeseite, auf der wie folgt einige Werte einzutragen sind: Anmelde-Sprache, Mandant, Benutzer, usw. (Abb. 3.34). Wir können die Art und Weise, wie die Anmeldeseite aussieht, verändern und ebenso die Art, mit der die Benutzer-Authentifizierung realisiert wird, indem wir die
32
3 Designen einer Web-Dynpro-Komponente
Abb. 3.34 Beispiel einer Anmeldeseite einer Web-Dynpro-Anwendung
Transaktion SICF (Pflege des HTTP-Service-Baums) anwenden. In der webdynpro -> sap hierarchy verweist jede Web-Dynpro-Anwendung auf einen zugehörigen Eintrag. Unter Verwendung dieser Transaktion suchen wir nach alle Einträgen, die mit Y_WD∗ beginnen und von unserem Test-User Gellert erstellt wurden. (Abb. 3.35).
Abb. 3.35 Mit Transaktion SICF einen Service suchen
Wir finden den Eintrag, der der von uns erstellten Web-Dynpro-Anwendung zugeordnet ist (Abb. 3.36). Mit einem Doppelklick ist es uns möglich, diesen Service anzusehen und/oder zu ändern. Im unteren Teil des Tabs Fehlerseiten finden wir den „Konfiguration“Button für die Systemanmeldung. Hier können wir unsere eigenen Einstellungen durch Auswahl aus der Liste definieren oder wir können die globalen Einstellungen verwenden (Abb. 3.37).
3.6
Konfiguration der Web Dynpro Anmeldeseite
Abb. 3.36 Der zu der von uns erstellten Web-Dynpro-Anwendung gehörende Eintrag
Abb. 3.37 Konfiguration Systemanmeldung
33
34
3 Designen einer Web-Dynpro-Komponente
Abb. 3.38 Anmeldeseite
Als Resultat unserer Änderungen müssen in der Anmeldeseite nur noch Benutzer und Kennwort im Pop-up-Fenster eingetragen werden, und wir sind in der Lage unser Anmelde-Kennwort zu ändern (Abb. 3.38)
Kapitel 4
ABAP Dictionary
Mystery creates wonder and wonder is the basis of man’s desire to understand. Neil Armstrong
Zusammenfassung Die folgende Lektion führt das ABAP Dictionary einzeln auf und beschreibt es. Der Hauptzweck dieses Kapitels ist es, zu zeigen, wie man all die Entwicklungsobjekte realisiert, um sie für die zukünftigen Web-DynproAnwendungen zu nutzen. Daher stellen wir nicht nur die Art und Weise dar, wie die verschiedenen Entwicklungsobjekte angelegt werden, sondern auch, wie sie in der Praxis in Web-Dynpro-Anwendungen eingesetzt werden. Wir können Entwicklungsobjekte im ABAP Dictionary mit der Transaktion SE11 (ABAP Dictionary: Einstieg) oder mit dem Object Navigator erstellen (Abb. 4.1).
Abb. 4.1 Entwicklungsobjekte erstellen mit der Transaktion SE11
Die Programmiersprache ABAP bietet 10 elementare Datentypen, die wir in unseren Programmen benutzen können. Wenn wir globale Datentypen erstellen möchten, verwenden wir die eingebauten Datentypen im ABAP Dictionary. U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_4,
35
36
4
ABAP Dictionary
Diese vordefinierten Typen unterscheiden sich von den elementaren Datentypen. Wir brauchen sie aus Gründen der Kompatibilität zu den externen Datentypen. In Abb. 4.2 zeigen wir einige eingebaute Datentypen im ABAP Dictionary und die korrespondierenden elementaren ABAP-Datentypen.
Dictionary – ABAP Typ Beispiele CHAR Å c DATS Å d INT4 Å i NUMC Å n STRING Å string TIMS Å t RAW - x RAWSTRING- xstring FLTP - f DEC - p Abb. 4.2 Einige eingebaute ABAP-Dictionary-Datentypen und die zugehörigen elementaren ABAP-Datentypen
4.1 Datenelement Ein Datenelement definiert einen elementaren Datentyp und hat bestimmte Eigenschaften. Wir erzeugen ein Datenelement YGEBURTSTAG (Abb. 4.3).
Abb. 4.3 Definition eines Datenelements
4.2
Domäne
37
Im Tabreiter „Datentyp“ können wir zwischen dem elementaren und dem referenzierten Typ wählen. Der elementare Typ kann eine Domäne oder ein eingebauter Typ sein. In unserem Fall haben wir den eingebauten Typ DATS gewählt, der ein vordefiniertes Format (JJJJMMDD) und eine vordefinierte Länge von 8 aufweise. Im Tabreiter „Feldbezeichner“ können wir den automatisch angezeigten Feldbezeichner oder die Überschrift eines UI-Elementes wählen, das an die Eigenschaft dieses Typs gebunden ist. Für ein Datenelement können wir mit Springen -> Dokumentation -> Ändern eine F1-Hilfe erstellen. Diese Dokumentation wird auf dem Bildschirm nicht angezeigt, wenn das Attribut WDHIDEMOREFIELDHELPASDEFAULT für die Web-Dynpro-Anwendung auf ABAP_TRUE gesetzt ist. Wir erzeugen einen Text, der den Inhalt unseres Datenelements beschreibt (Abb. 4.4).
Abb. 4.4 Erzeugen einer F1-Hilfe für ein Datenelement
4.2 Domäne Eine Domäne definiert einen Wertebereich. Um eine Domäne in einer WebDynpro-Anwendung, in einem anderen Repository-Objekt, als Parameter in der GUI-Programmierung etc., zu nutzen, müssen wir sie einem Datenelement zuordnen (Abb. 4.5). Wir erzeugen eine Domäne namens Y_LAND_DOMAENE, die die Namen aller EU-Mitgliedsstaaten enthält, mit der passenden Abkürzung. Im „Definition”Tabreiter müssen wir Eigenschaften wie Datentypen, Anzahl Zeichen oder Ausgabelänge bestimmen (Abb. 4.6). In „Wertebereich” haben wir drei Möglichkeiten: • Einzelwerte; • Intervalle; • Wertetabelle.
38
4
ABAP Dictionary
Abb. 4.5 Datenelemente und Domänen
Abb. 4.6 Definition einer Domäne – Tabreiter „Definition“
Wir beginnen mit der ersten Möglichkeit, „Einzelwerte“. Wir definieren die festen Werte der Domäne – die ganzen Abkürzungen der EU-Länder und ein kurzer Text – die zugehörigen Ländernamen (Abb. 4.7). Wie wir schon festgelegt haben, müssen wir zur Verwendung einer Domäne diese einem Datenelement zuordnen. Zu diesem Zweck erzeugen wir ein neues Datenelement und wählen Elementarer Typ – Domäne (Abb. 4.8). Wenn wir dieses Datenelement in unserer Web-Dynpro-Component benutzen, zum Beispiel um einen Parameter oder ein Context-Attribut zu definieren, darf der Benutzer lediglich aus dem Wertebereich wählen, den wir in der Domäne definiert haben.
4.2
Domäne
39
Abb. 4.7 Definition einer Domäne – Tabreiter „Wertebereich“
Abb. 4.8 Zuordnen einer Domäne zu einem Datenelement
Zur Erläuterung der nächsten Möglichkeit („Intervalle”) nehmen wir ein Beispiel, bei dem wir das Alter zwischen 18 und 45 in einer Tabellenspalte abspeichern. In diesem Fall können wir ein Intervall verwenden, um die Werte, die der Benutzer eingeben kann, zu limitieren (Abb. 4.9). Wir benutzen dieses Intervall in der Datenbanktabelle YPERSONEN, nachstehend definiert. Hierfür ordnen wir es einem Datenelement Y_DEALTERSBEREICH zu. Um die letzte Möglichkeit („Wertetabelle”) zu erklären, verwenden wir eine im System definierte Domäne: WAERS (Abb. 4.10). Es ist empfehlenswert, eine Wertetabelle zu verwenden, wenn wir viele feste Werte haben. In unserem Fall haben wir die Systemtabelle TCURC genutzt. Diese Tabelle enthält alle im System verwendbaren Währungen.
40
4
ABAP Dictionary
Abb. 4.9 Definition einer Domäne – Intervall
Abb. 4.10 Domäne WAERS – Wertetabelle
Wir nutzen diese Wertetabelle in der Datenbanktabelle YEU_LAENDER, nachfolgend definiert. Dazu ordnen wir es einem Datenelement Y_DEWAERUNG zu.
4.3 Struktur Strukturen bestehen aus Kombinationen von Datentypen des ABAP Dictionary. In Abb. 4.11 zeigen wir eine Struktur mit drei Komponenten: VORNAME, NACHNAME und GEBURTSTAG. Für jede Komponente ist ein Komponententyp definiert, das kann ein Datenelement, eine andere Struktur, ein Tabellentyp etc. sein. Als Komponententyp für eine Struktur können wir entweder einen bereits im ABAP Dictionary definierten Typ auswählen oder einen neuen Typ erzeugen. Die Komponente GEBURTSTAG hat zum Beispiel den Datentyp YGEBURTSTAG. Dieser Datentyp ist bereits angelegt. Wenn wir einen neuen Typ für eine Komponente erzeugen wollen, müssen wir dessen Namen eingeben (zum Beispiel YVORNAME) und anschließend können wir mit einem Doppelklick den neuen Typ auswählen (Abb. 4.12).
4.3
Struktur
41
Abb. 4.11 Definition einer Struktur
Abb. 4.12 Erzeugen eines neuen Komponententyps
Nachdem wir eine Struktur kreiert haben, müssen wir die Erweiterungskategorie pflegen: dazu Zusätze -> Erweiterungskategorie aus dem Menü aufrufen. Falls wir die Komponentenstruktur nicht mehr erweitern wollen, wählen wir „nicht erweiterbar“ (Abb. 4.13).
Abb. 4.13 Pflegen der Erweiterungskategorie
Zur Erzeugung der Context-Struktur für eine Web-Dynpro-Component können wir die im ABAP Dictionary definierten Strukturen benutzen.
42
4
ABAP Dictionary
4.4 Tabelle Wir erstellen zwei transparente Tabellen, YPERSONEN und YEU_LAENDER. Diese Tabellen werden wir später für unsere Web-Dynpro-Beispiele brauchen. In der YPERSONEN Tabelle möchten wir die Wettbewerbsteilnehmer speichern. Alle Kandidaten sollen zwischen 18 und 45 Jahre alt sein und in einem EU-Staat leben. Nach dem Erzeugen der Tabelle müssen wir eine kurze Beschreibung eingeben, zusammen mit den Daten zur Auslieferung und Pflege (Abb. 4.14).
Abb. 4.14 Tabellenpflege
Wir setzen „Data Browser/Tabellensicht-Pflege“ -> „Anzeige/Pflege erlaubt“, um die Tabelle über „Einträge erfassen“, aus dem Menü (Hilfsmittel -> Tabelleninhalt) mit Werten füllen zu können. Danach werden wir unsere Tabellenstruktur definieren. Dafür wählen wir den Tabreiter „Felder“ aus und geben die Tabellenspalten (Abb. 4.15) ein. Für die Felder MANDT und ID_PERSON haben wir die Option „Key“ markiert, was bedeutet, dass sie Tabellenschlüssel sind. Das Feld MANDT bezeichnet das SAPMandantenfeld, eine dreistellige Kunden-ID. Das Feld ID_PERSON repräsentiert die ID des Kandidaten, die jeden Wettbewerbsteilnehmer eindeutig identifiziert.
Abb. 4.15 Tabellenstruktur
Wie zu erkennen ist, haben wir die vorher erzeugten Datenelemente verwendet: YVORNAME, YNACHNAME, Y_DEALTERSBEREICH, Y_DEFU-
4.4
Tabelle
43
ERDOMAENE. Wenn wir ein neues Datenelement erzeugen möchten, schreiben wir seinen Namen und aktivieren dann mit einem Doppelklick die Vorwärtsnavigation. Wenn das Datenelement noch nicht existiert, werden wir gefragt, ob wir es neu anlegen wollen (Abb. 4.16).
Abb. 4.16 Datenelement anlegen
Bevor wir in der Lage sind, diese Tabelle zu aktivieren, müssen wir „Technische Einstellungen“ pflegen (Abb. 4.17).
Abb. 4.17 Pflegen der technischen Einstellungen für die Tabelle YPERSONEN
Wir wählen als Größenkategorie 0, weil wir nicht viele Datensätze benötigen. Wir müssen dann die Erweiterungskategorie pflegen: Zusätze -> Erweiterungskategorie vom Menü. Wir entscheiden uns für „Pufferung nicht erlaubt“, weil wir die Tabellenstruktur nicht mehr erweitern möchten. Anschließend können wir unsere Tabelle aktivieren und die zweite Tabelle namens YEU_LAENDER erzeugen. Hier halten wir wie folgt alle Informationen zu den EU-Mitgliedsstaaten bereit: Ländername, Jahr des EU-Beitritts, politisches System, Hauptstadt, Währung und den Namen des Flaggenbildes. Die Struktur dieser Tabelle ist in Abb. 4.18 dargestellt.
44
4
ABAP Dictionary
Abb. 4.18 Tabellenstruktur
Anschließend müssen wir einen Fremdschlüssel für das Feld CHECK_CUR definieren. Zu diesem Zweck klicken wir auf den Button „Fremdschlüssel“. Wir werden dann gefragt, ob wir die Wertetabelle TCURC als Prüftabelle verwenden möchten (Abb. 4.19).
Abb. 4.19 Erzeugen eines Fremdschlüssels
Wir benötigen TCURC als Prüftabelle, weil wir ihre Tabelleninhalte brauchen, insbesondere die Währungsschlüssel (Abb. 4.20). Nachdem wir die Technischen Einstellungen und die Erweiterungskategorie gepflegt haben, aktivieren wir das Gleiche für die Tabelle YPERSONEN. Die Kandidaten können nur in genau einem EU-Land wohnen. Entsprechend erzeugen wir eine 1:CN-Beziehung zwischen den Tabellen.
4.4
Tabelle
45
Abb. 4.20 Währungsschlüssel
Das Feld ID_LAND aus der Tabelle YPERSONEN wird als Fremdschlüsselfeld eingetragen (Abb. 4.21).
Abb. 4.21 Erzeugen eines Fremdschlüssels
46
4
ABAP Dictionary
Das System gibt uns eine grafische Sicht der Beziehungen zwischen den Tabellen, die wir definiert haben. Mit Drücken des Buttons „Grafik“ lassen wir uns die Grafik anzeigen (Abb. 4.22).
Abb. 4.22 Fremdschlüssel-Beziehungen
Wir erkennen in der Grafik unsere Tabellen YEU_LAENDER, YPERSONEN sowie die 1:CN-Beziehung. Die Tabelle TCURC dient als Prüftabelle für die Tabelle YEU_LAENDER. Um auch diese Beziehung zu sehen, müssen wir YEU_LAENDER auswählen und den Button „Prüftabellen“ drücken (Abb. 4.23).
Abb. 4.23 Fremdschlüssel-Beziehungen
Wir können Inhalte mit Hilfsmittel -> Tabelleninhalte -> Einträge erfassen aus dem Menü erzeugen (Abb. 4.24). Zum Anzeigen des Inhalts: Hilfsmittel -> Tabelleninhalte -> Anzeigen aus dem Menü (Abb. 4.25).
4.5
Suchhilfe
47
Abb. 4.24 Inhalte einfügen in die Tabelle YEU_LAENDER
Abb. 4.25 Anzeigen des Tabelleninhaltes YEU_LAENDER
Tipp Mit Hilfsmittel -> Datenbankobjekt -> Datenbank-Utility, oder per Transaktion SE14, erreichen wir das Datenbank-Utility, mit dem wir eine Datenbanktabelle aktivieren und anpassen können, falls wir deren Struktur geändert haben und ein Aktivierungsfehler angezeigt wurde. Wir können das Datenbank-Utility nicht nur zum Aktivieren und Anpassen einer Datenbank verwenden, sondern auch für andere Basisfunktionen, wie zum Erstellen oder Löschen einer Datenbanktabelle.
Mit den im ABAP Dictionary erzeugten transparenten Tabellen ist es uns möglich, die Context-Struktur einer Web-Dynpro-Component zu erzeugen.
4.5 Suchhilfe ABAP Dictionary bietet die Möglichkeit, eine Elementare Suchhilfe und eine Sammelsuchhilfe zu erstellen.
48
4
ABAP Dictionary
Um eine Suchhilfe zu erstellen, können wir das Kontextmenü unseres Pakets nutzen (Abb. 4.26).
Abb. 4.26 Erzeugen eines Entwicklungsobjekts im ABAP Dictionary unter Verwendung des Object Navigator
Wir erzeugen eine Elementare Suchhilfe YSUCHH_ID_PERSON für die Spalte ID_PERSON der Tabelle YPERSONEN (Abb. 4.27).
Abb. 4.27 Erzeugen einer Elementaren Suchhilfe
Wie aus „Datenbeschaffung -> Selektionsmethode“ ersichtlich, haben wir die Tabelle YPERSONEN verwendet. Das heißt, dass alle benötigten Daten aus unserer Tabelle YPERSONEN stammen. Eine Suchhilfe kann die folgenden Parameter haben: „import parameters“, „export parameters“ or „no import“ and „no export“. Wir
4.5
Suchhilfe
49
haben ID_PERSON als Exportparameter verwendet, weil dessen Wert dem Eingabeschema zurückgegeben werden soll. LPos repräsentiert die Parameterposition in der Trefferliste: VORNAME hat die Position 1 und wird zuerst in der Trefferliste angezeigt, und NACHNAME hat die Position 2, angezeigt nach VORNAME. Wir können eine Suchhilfe testen (Abb. 4.28).
Abb. 4.28 Testen einer Suchhilfe
Anschließend möchten wir diese Suchhilfe in einer Web-Dynpro-Component ausprobieren. Wir erstellen zunächst eine Suchoption für einen Wettbewerber. Der Benutzer muss dann die ID des Wettbewerbers in eine Suchmaske eingeben. Die Liste der IDs ist durch die Anzahl der Wettbewerber begrenzt. Falls der Benutzer die ID des Wettbewerbers nicht kennt, bedient er sich der Suchhilfe und kann dort den Namen des Wettbewerbers wählen. Der Inhalt des ID_PERSON-Parameters wird an die Suchmaske zurückgegeben, sobald der Benutzer eine Zeile aus der Trefferliste in der Eingabeliste ausgewählt hat. In dieser Weise erleichtern wir die Eingabe. Wir können diese Suchhilfe auch benutzen, wenn wir sie mit der Spalte ID_PERSON der YPERSONEN-Tabelle verknüpfen. Hierzu selektieren wir die Spalte ID_PERSON und drücken den Button „Suchhilfe“ (Abb. 4.29). Nachdem wir den Suchhilfenamen eingegeben haben, müssen wir die Suchhilfeanbindung erstellen, die Tabelle speichern und aktivieren (Abb. 4.30). Auf diesem Weg haben wir eine einfache Suchhilfe für die Spalte ID_PERSON der Tabelle YPERSONEN erzeugt. Wenn wir diese Spalte in Web Dynpro nutzen, erzeugt das Framework ein spezielles Icon für den Aufruf der Eingabehilfe zur Laufzeit. Darüber hinaus gibt es die Taste F4 auf der Tastatur, um die Eingabehilfe aufzurufen. Um in der Lage zu sein, auf eine Suchhilfe von einer WD-Komponente aus zuzugreifen, muss der dazugehörige Wertehilfe-Modus für Context-Attributeigenschaften „Automatic“ oder „Dictionary Search Help“ gesetzt werden.
50
4
ABAP Dictionary
Abb. 4.29 Suchhilfe für das Feld ID_PERSON
Abb. 4.30 Erstellen der Suchhilfeanbindung für die Spalte ID_PERSON
4.6 Datenbank-View Unter Verwendung einer View können wir auf mehrere Tabellen verteilte Daten kombinieren. Für ein besseres Verständnis erzeugen wir eine View basierend auf den Tabellen YPERSONEN und YEU_LAENDER. Beim Erstellen einer View können wir eine von vier Viewtypen auswählen (Abb. 4.31). Wir entscheiden uns für eine Datenbank-View namens YVIEW_WETBEWERB. Zu Anfang der „View Definition“, müssen wir eine View-Basistabelle selektieren (in unserem Fall ist das die Tabelle YPERSONEN). Nach der Definition der Basistabelle verknüpfen wir diese Tabelle durch Anlegen der Joinbedingungen. Hierfür drücken wir auf den Button „Beziehungen“ (Abb. 4.32). Dies bewirkt, dass die Joinbedingungen generiert werden (Abb. 4.33).
4.6
Datenbank-View
51
Abb. 4.31 Viewtypen
Abb. 4.32 Anlegen einer View
Abb. 4.33 Joinbedingungen
Im nächsten Schritt müssen wir die Felder auswählen, die wir in unserer View benötigen. Entweder geben wir jedes Feld manuell ein oder wir behelfen uns mit dem Button „Tabellenfelder“ (Abb. 4.34).
52
4
ABAP Dictionary
Abb. 4.34 Tabellenfelder
Nach der Aktivierung sehen wir den Inhalt unserer View unter Benutzung des „Inhalt“-Buttons (Abb. 4.35).
Abb. 4.35 Viewinhalt
Auf diese Weise haben wir eine Datenbank-View auf Basis der Tabellen YPERSONEN und YEU_LAENDER erzeugt (Abb. 4.36).
Abb. 4.36 Viewdefinition auf der Datenbank
4.7
Tabellentyp
53
Unter Verwendung dieser View können wir die Context-Knotenstruktur für unsere Web-Dynpro-Component erzeugen und so gleichzeitig die logisch verknüpften Daten aus zwei Tabellen auswählen.
4.7 Tabellentyp Wir erzeugen einen Tabellentyp namens YTABELLENTYP, wobei wir für den Zeilentyp unsere YPERSONEN-Tabelle nehmen (Abb. 4.37).
Abb. 4.37 Erstellen eines Tabellentyps
Für den Zeilentyp können wir einen existierenden Typ (Tabelle, Struktur, View . . .) benutzen oder alternativ den Datentyp, die Länge und Anzahl Dezimalstellen angeben. Typischerweise wird der Tabellentyp für die Deklaration einer internen Tabelle genutzt. Ein weiteres Beispiel für die Benutzung von Tabellentypen ist das Befüllen eines Context-Knotens mit Werten via Supply-Funktion-Methode. Um dies nachzuvollziehen, erzeugen wir einen Tabellentyp namens YTT_STRUKTUR mit dem Zeilentyp der Struktur YSTRU_PERSON (Abb. 4.38).
Abb. 4.38 Tabellentyp – Zeilentypstruktur
Im nächsten Kapitel zeigen wir, wie wir diesen Tabellentyp zum Befüllen eines Context-Knotens nutzen können.
54
4
ABAP Dictionary
4.8 Sperrobjekt Wir erzeugen ein Sperrobjekt für die Datenbanktabelle YPERSONEN (Abb. 4.39). Der Name des Sperrobjekts muss mit dem Präfix E beginnen (von „Enqueue“).
Abb. 4.39 Sperrobjekt
Abb. 4.40 Funktionsbaustein für das Setzen einer Sperre
4.8
Sperrobjekt
55
Unser Fall besteht aus genau einer Tabelle, und der Sperrparameter ist der Primärschlüssel dieser Tabelle. Der Sperrmodus ist auf „Schreibsperre“ gesetzt, kann aber überschrieben werden. Nach der Aktivierung des Sperrobjekts generiert das ABAP Dictionary zwei Funktionsbausteine, die ENQUEUE_ und DEQUEUE_ heißen. Der Funktionsbaustein mit dem enqueue-Präfix hilft uns eine Sperre zu setzen, und der Funktionsbaustein mit dequeue-Präfix hilft uns die Sperren zu lösen. Mit der Transaktion SE37 können wir die zwei generierten Funktionsbausteine ENQUEUE_EYPERSONEN und DEQUEUE_EYPERSONEN sehen. Abb. 4.40 zeigt die Struktur des Funktionsbausteins, den wir zum Setzen einer Sperre benötigen. SAP bietet einen Sperrmechanismus an, der gebraucht wird, wenn zwei Transaktionen gleichzeitig dieselben Daten in der Datenbank bearbeiten. Die Sperrtabelle repräsentiert eine Tabelle im Speicher des enqueue-Servers, mit der alle Sperren im System verwaltet werden. Diese Sperrtabelle wird jedes Mal geprüft, wenn der enqueue-Server eine Sperranforderung erhält. Ein Programm sendet die Schlüssel der Datenbankeinträge, die es bearbeiten möchte, an die Sperrtabelle; ist nicht schon eine Sperre gesetzt, wird die Anforderung akzeptiert und die neue Sperre in die Sperrtabelle geschrieben. Ist bereits eine Sperre gesetzt, kollidiert die Anforderung mit einer existierenden Sperre und die Anforderung wird abgelehnt.
Kapitel 5
Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt
Well done is better than well said. Benjamin Franklin
Zusammenfassung Dieses Kapitel konzentriert sich hauptsächlich auf die statisch zur Entwurfszeit realisierten Context-Knoten und Context-Attribute. Insofern erklären wir nicht nur Rolle und Art und Weise der Erstellung von Context-Knoten und Attributen, sondern auch die Modalität des Zugriffs auf die in den Attributen der Knoten gespeicherten Werte. Ein Context-Attribut ist eine Kontextentität, die bestimmte Eigenschaften besitzt und direkt im Wurzelknoten CONTEXT erstellt werden kann, oder als Kind für einen anderen Knoten. Üblicherweise wird ein Knoten verwendet, um mehrere Context-Attribute zusammenzufassen, die zusammengehören. In Abb. 5.1 zeigen wir ein Context-Beispiel, das in einem View-Context erstellt wurde.
Unabhängiger Knoten Attribute des STUDENT-Knotens Unabhängiger Knoten Abhängiger oder Kind-Knoten für HOCHSCHULE Attribute des ADRESSE-Knotens Attribute desHOCHSCHULE Knotens Attribute erstellt im Wurzelknoten CONTEXT
Abb. 5.1 Beispiel der Struktur eines View-Context
Ein Context-Knoten kann Context-Attribute oder andere Context-Knoten beinhalten. Aber ein Context-Attribut kann keine anderen Attribute oder Knoten haben. Wir erstellen ein hierarchisches Gefüge, das den Wurzelknoten CONTEXT als Ausgangspunkt hat. Dieser wird automatisch erzeugt, wenn der Controller initialisiert wird, und alle Knoten und Attribute, die wir erstellen, sind Kinder dieses Wurzelknotens. U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_5,
57
58
5 Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt
Die Daten, die in den Context-Attributen gehalten werden, sind kurzlebig (transient). Sie existieren nur zur Laufzeit des Controllers. Danach sind alle Daten verloren, wenn wir sie nicht in einem Speichermedium (z.B. Datenbanktabelle) abspeichern.
5.1 Context-Attribute Um ein Context-Attribut zu erzeugen, müssen wir den Knoten auswählen, in den das Attribut eingefügt werden soll (in diesem Fall den Wurzelknoten CONTEXT), und durch einen Rechtsklick der Maus das Kontextmenü öffnen (Abb. 5.2).
Abb. 5.2 Erzeugen eines Attributes
Wir müssen die Attributeigenschaften eingeben – Name und Typ sind erforderlich, die anderen Einstellungen sind optional (Abb. 5.3).
Abb. 5.3 Definieren der Attributeigenschaften
Als Datentyp für ein Attribut können wir String, XString, D, I oder einen im ABAP Dictionary definierten Datentyp verwenden. In unserem Beispiel ist der
5.1
Context-Attribute
59
Attributtyp YGEBURTSTAG, ein Datenelement das im ABAP Dictionary definiert ist. Im System finden wir eine Liste mit allen Datentypen, die wir für ein Attribut verwenden können. (Abb. 5.4).
Abb. 5.4 Suche nach dem Datentyp eines Attributs
Das Coding aus dem Listing 5.1 zeigt, wie wir über eine Methode Zugriff auf den Wert des Context-Attributs haben, das im Wurzelknoten Context erzeugt wurde. DATA lv_geburtstag type ygeburtstag. wd_context->get_attribute( EXPORTING name = ’GEBURTSTAG’ IMPORTING value = lv_geburtstag) Listing 5.1 Zugriff auf ein Attribut aus dem Wurzelknoten Context
Wir haben eine lokale Variable namens lv_geburtstag vom Typ YGEBURTSTAG definiert, vom gleichen Datentyp wie das Context-Attribut. Wir übergeben den Wert des Attributes GEBURTSTAG an unsere lokale Variable durch Verwendung der Methode get_attribute des Interface if_wd_context_node. Das Interface if_wd_context_node hat viele Methoden, die wir für die Arbeit mit Context-Knoten verwenden können. Wir können alle zur Verfügung stehenden Methoden dieses Interface sehen, wenn wir einen Doppelklick auf die Methode get_attribute machen. Um einem Attribut einen Wert zuzuweisen, können wir die Methode set_attribute des gleichen Interface verwenden. Wie wir in Abb. 5.4 sehen, wird die Eigenschaft „Wertehilfe-Modus“ auf „automatisch“ gesetzt. Das bedeutet, dass die Suchhilfe verwendet wird, die dem Datentyp im ABAP Dictionary des Context-Attributs zugewiesen ist. Wenn wir
60
5 Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt
ein Datenelement vom Typ D haben, werden wir grundsätzlich die Eingabehilfe KALENDER anbieten (Abb. 5.5).
Abb. 5.5 Kalender als Eingabehilfe
Wird die Nur-Lesen (read-only)-Eigenschaft des Attributes auf „NEIN“ gesetzt, bedeutet es, dass das Context-Attribut nicht schreibgeschützt ist. Um Daten auf den Bildschirm zu bringen und Eingaben des Anwenders lesen zu können, verbinden wir die passenden UI-Element-Eigenschaften mit den ContextAttributen oder Context-Knoten. Die Daten werden in den Context-Attributen gehalten. Die UI-Elemente sind die einzigen Objekte, mit denen der Anwender interagiert. In unserem Beispiel haben wir das UI-Element InputField, in welches der Anwender sein Geburtsdatum eingibt. Das Web-Dynpro-Framework übergibt diese Daten von dem UI-Element an das Attribut GEBURTSTAG, wenn der Anwender den SPEICHERN (SAVE)-Button drückt, nachdem er einen Wert eingegeben hat. Das Attribut hält diesen Wert für künftige Verwendungen. Damit wir den Wert dieses Attributes unseren Methoden zuweisen können, müssen wir den Wert an eine lokale Variable (lv_geburtstag) übergeben. Diesen Wert können wir verwenden oder ändern und den neuen Wert zurückgeben in den Context (Abb. 5.6). Dieser Wert wird im Context für die gesamte Laufzeit des Controllers
Abb. 5.6 Verbindung zwischen Context-Attribut, ABAP Dictionary, Methode und UI-Element
5.2
Context-Knoten
61
gehalten. Danach sind diese Daten verloren, wenn wir sie nicht gespeichert haben.
5.2 Context-Knoten Wir können einen Context-Knoten direkt im Context-Wurzelknoten oder als Kind eines anderen Knotens erzeugen. In Abb. 5.7 zeigen wir, wie wir einen Knoten erzeugen können.
Abb. 5.7 Erzeugen eines Knotens
Für jeden Context-Knoten, den wir erzeugen, müssen wir einige Eigenschaften festlegen wie Kardinalität, Singleton etc. Wir können jedes individuelle Attribut eines Knotens erstellen oder wir können einige Repository-Objekte des ABAP Dictionary verwenden. Wir können zum Beispiel mit Tabellen, Strukturen oder Views arbeiten, die im ABAP Dictionary definiert sind. Diese können wir verwenden, um unsere Knoten zu definieren, und die dazugehörigen Attribute werden automatisch generiert.
5.2.1 Erzeugen eines Knotens unter Verwendung eines ABAP-Dictionary-Repository-Objekts Wir erzeugen einen Context-Knoten, der die ABAP-Dictionary-Struktur YSTRU_PERSON verwendet (Abb. 5.8). Der Button „Attribute aus Struktur hinzufügen“ erlaubt es uns, alle oder nur ausgewählte Komponenten der Struktur hinzuzufügen (Abb. 5.9). Da wir für alle diese Strukturkomponenten jeweils ein passendes ContextAttribut benötigen, wählen wir alle aus. Als Ergebnis haben wir einen Knoten erzeugt und die Attribute wurden automatisch generiert – entsprechend den von uns ausgewählten Komponenten der Struktur (Abb. 5.10). Die von uns ausgewählten Eigenschaften des Knotens sind: Kardinalität 0. . .n, Singleton – JA und Init. Lead-Selection – JA.
62
5 Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt
Abb. 5.8 Knoteneigenschaften
Abb. 5.9 Auswahl der Komponenten der Struktur Abb. 5.10 Kontextknoten STUDENT zum Entwicklungszeitpunkt
Die Eigenschaften der Kardinalität sind sehr wichtig, weil sie uns sagen, wie viele Elemente ein Context-Knoten zur Laufzeit haben darf. Wir haben vier mögliche Werte: • 1. . .1 exakt ein Context-Element ist instanziiert. • 0. . .1 maximal ein Context-Element ist instanziiert.
5.2
Context-Knoten
63
• 0. . .n null oder mehr Context-Elemente sind instanziiert. • 1. . .n ein oder mehr Context-Elemente sind instanziiert. Die Singleton Eigenschaft kann auf JA oder NEIN gesetzt werden. Wenn ein Knoten zur Laufzeit Singleton ist, haben wir nur eine Instanz dieses Knotens. Als Verwendungsbeispiel für einen Nicht-Singleton-Knoten können wir eine ContextStruktur für ein Tree UI Element aufführen – sequentielle Implementation. Die Lead-Selection-Initialisierungseigenschaft bestimmt, ob die Lead-Selection automatisch gesetzt oder programmiert werden soll. In unserem Fall ist die Eigenschaft auf „JA“ gesetzt. Das bedeutet, dass die Lead-Selection automatisch agiert und das erste Element dieses Knotens automatisch selektiert wird. Weitere Einzelheiten zur Lead-Selection: siehe Abschnitt über das Table-UI-Element. Für unseren Knoten haben wir die Supply-Funktion supply_student definiert. Jeder Knoten kann für sich eine Supply-Funktion definiert haben, welche automatisch durch das Web-Dynpro-Framework aufgerufen wird. Der Sinn der Verwendung von Supply Funktionen ist die Versorgung der Context-Knoten mit Daten. In bestimmten Fällen können wir die bereitgestellte Methode wdDoInit anstelle einer SupplyFunktion verwenden. Mehr Einzelheiten dazu entnehmen Sie bitte dem Kapitel über bereitgestellte Methoden. Das Coding aus Listing 5.2 zeigt, wie wir die Supply-Funktion nutzen können, um den Context-Knoten STUDENT mit drei Werten zu versorgen. METHOD supply_student. DATA ls_student TYPE if_view_name=>element_student. DATA lt_student LIKE TABLE OF ls_student. ls_student-vorname = ’Ionescu’. ls_student-nachname = ’Ana Maria’. ls_student-geburtstag = ’19700309’. APPEND ls_student TO lt_student. ls_student-vorname = ’Marinescu’. ls_student-nachname = ’Loredana’. ls_student-geburtstag = ’19800523’. APPEND ls_student TO lt_student. ls_student-vorname = ’Marton’. ls_student-nachname = ’Luminita’. ls_student-geburtstag = ’19831108’. APPEND ls_student TO lt_student. node->bind_table( new_items = lt_student). ENDMETHOD.
Listing 5.2 Beispiel einer Supply-Funktion
Wir haben zwei Variable definiert: ls_student und lt_student. Ls_student ist vom Typ if_view_name=>element_student, wobei „view_name“ den von uns vergebenen Viewnamen darstellt und „student“ den Knotennamen. „if_view_name“ stellt
64
5 Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt
das programmierbare Interface für unseren View Controller dar. Durch Doppelklick auf seinen Namen oder durch einen Klick auf das Symbol „Controller Interface anzeigen“ , können wir das Coding des Interface ansehen. Das Listing 5.3 zeigt einen Codingteil des Context-Knotens STUDENT .... constants: wdctx_Student type string value ‘STUDENT‘. types: Element_Student type YSTRU_PERSON, Elements_Student type standard table of Element_Student with default key. ....
Listing 5.3 Beispiel eines programmierbaren Interface des View-Controller
Wie zu sehen ist, hat Element_Student den Typ YSTRU_PERSON (unsere definierte ABAP-Dictionary-Struktur). Wenn wir aber den Context-Knoten manuell ohne die Dictionary Struktur erzeugen, wird im programmierbaren Interface des View Controller eine neue Struktur erzeugt. (Listing 5.4) .... types: begin of Element_hochschule, HOCHSCHULE_NAME type String, GEBIET type String, end of Element_hochschule, ....
Listing 5.4 Beispiel eines programmierbaren Interfaces des View Controller
Aus diesem Grund verwenden wir die folgende Form, um Werte hinzuzufügen: ls_student- vorname=’lonescu’
Der Weg, um Werte einer ABAP-Struktur hinzuzufügen, ist folgender: structure_name-component_name=value
Mit der Deklaration „DATA lt_student LIKE TABLE OF ls_student“, erzeugen wir eine interne Tabelle. Wir verwenden das APPEND Statement, um neue Zeilen am Ende der internen Tabelle hinzuzufügen. Zum Schluss verwenden wir die bind_structure-Methode, um den Knoten mit den Werten zu versorgen
5.2
Context-Knoten
65
Anstelle der Deklaration DATA ls_student TYPE if_view_name=>element_student. können wir verwenden: DATA ls_student TYPE wd_this->element_student. In diesem Fall benötigen wir den Viewnamen nicht mehr, da wir die wd_thisSelbstreferenz nutzen. Die Laufzeitstruktur ist dargestellt in Abb. 5.11. Wurzelknoten Knoten STUDENT Ionescu Ana Maria Element 1 19700309 Marinescu Loredana Element 2 19800523 Marton Element 3 Luminita 19831108
Abb. 5.11 Die Laufzeitstruktur
Der Knoten STUDENT war auf Singleton gesetzt und hat daher zur Laufzeit nur eine Instanz. Die Kardinalität ist auf 0. . .n gesetzt, was zur Laufzeit bedeutet, dass wir von Null bis n Elemente haben können. Da die Lead-Selection auf „JA“ gesetzt war, wurde das erste Element des Knotens ausgewählt. Um einen Context-Knoten oder ein Context-Attribut zu lesen, zu setzen oder hinzuzufügen, können wir den Web Dynpro Code Wizard (Abb. 5.12) nutzen.
Abb. 5.12 Web Dynpro Code Wizard – liest einen Context-Knoten oder ein Context-Attribut
66
5 Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt
Die Möglichkeit „als Tabellenoperation“ kann in Verbindung mit der Option Lesen, Setzen oder Hinzufügen für einen Knoten verwendet werden, der diese Kombination erlaubt. Wir können z.B. den kompletten Context-Knoten STUDENT in eine interne Tabelle einlesen. DATA lt_student TYPE wd_this->elements_student. lr_node->get_static_attributes_table( IMPORTING table = lt_student ).
In diesem Fall hat der Wizard eine Variable lt_student vom Typ wd_this>elements_student erzeugt. Aus dem Listing erkennen wir, dass im Interface Controller neben der Definition der Variable (Element_Student) das Framework ebenso die Variable Elements_Student definiert, mit der Form: Elements_Student type standard table of Element_Student with default key.
Das ist der Grund, warum der Wizard die Möglichkeit bietet, alle Werte aus dem STUDENT-Knoten in die variable lt_student einzulesen. Wie bereits im letzten Kapitel erwähnt, können wir einen Tabellentyp verwenden, um einen Context-Knoten mit Daten über eine Supply-Funktion zu versehen. Unser Knoten STUDENT hat seine Attribute von der Struktur YSTRU_PERSON. Der Tabellentyp YTT_STRUKTUR, definiert im ABAP Dictionary, hat die gleiche YSTRU_PERSON-Struktur als Zeilentyp. Listing 5.5 zeigt, wie wir einen Tabellentyp verwenden können, um einen Context-Knoten mit Daten zu füllen. METHOD supply. DATA: lt_student TYPE ytt_struktur. DATA: ls_student TYPE ystru_person. ls_student-vorname = ’Ionescu’. ls_student-nachname = ’Ana Maria’. ls_student-geburtstag = ’19700309’. APPEND ls_student TO lt_student. ls_student-vorname = ’Marinescu’. ls_student-nachname = ’Loredana’. ls_student-geburtstag = ’19800523’. APPEND ls_student TO lt_student. node->bind_table( new_items = lt_student). ENDMETHOD.
Listing 5.5 Beispiel einer Supply-Funktion
5.2
Context-Knoten
67
5.2.2 Arbeiten mit Kindknoten Wir erzeugen die Context-Struktur – dargestellt in Abb. 5.13.
Abb. 5.13 Beispiel eines Kindknotens
Es hat einen Context-Knoten HOCHSCHULE, Kardinalität 1. . .1, Singleton mit Kindknoten ADDRESSE, (Kardinalität 1. . .1, Singleton) und zwei Attribute HOCHSCHULE_NAME Typ STRING und FACHGEBIET Typ STRING. Wir lesen die Daten der Attribute des Knotens ADRESSE als einen Kindknoten von HOCHSCHULE. Listing 5.6 zeigt eine mögliche Methode, diese Attributeigenschaften zu lesen. DATA: lr_node TYPE REF TO if_wd_context_node, lr_subnode TYPE REF TO if_wd_context_node. DATA: lv_strasse TYPE string, lv_nummer TYPE y_char, lv_stadt TYPE string. lr_node = wd_context->get_child_node( ’HOCHSCHULE’). lr_subnode = lr_node->get_child_node( ’ADRESSE’). lr_subnode->get_attribute( EXPORTING name = ’STRASSE’ IMPORTING value = lv_strasse). lr_subnode->get_attribute( EXPORTING name = ’NUMMER’ IMPORTING value = lv_nummer). lr_subnode->get_attribute( EXPORTING name = ’STADT’ IMPORTING value = lv_stadt). Listing 5.6 Lesen der Attributwerte des Kindknotens „ADRESSE“
Mit der ersten Datendefinition erzeugen wir die zwei Variablen lr_node und lr_subnode vom Typ if_wd_context_node. Mit der zweiten Datendefinition erzeugen wir drei Variablen mit dem gleichen Datentyp wie die Context-Attribute, die wir lesen wollen. Datentype Y_CHAR stellt ein Datenelement aus dem ABAP Dictionary vom Typ CHAR in der Länge 6 dar. Anstelle der Deklaration: lr_node = wd_context->get_child_node( ’HOCHSCHULE’).
68
5 Context-Knoten und Context-Attribute zum Entwicklungszeitpunkt
können wir folgende Form verwenden: lr_node = wd_context->get_child_node( name = wd_this-> wdctx_HOCHSCHULE ).
Im ersten Fall müssen wir den Knotennamen in Großbuchstaben schreiben. Im zweiten Fall nutzen wir die Konstante wdctx_HOCHSCHULE mit dem Typ String. Diese Konstante wurde erzeugt durch das Framework des Interface Controllers mit der Form: constants: wdctx_HOCHSCHULE type string value ‘HOCHSCHULE‘.
Durch die Verwendung der get_child_node-Methode des if_wd_context_nodeInterface greifen wir erfolgreich auf die Knoten HOCHSCHULE und ADRESSE zu. Durch die Verwendung der Methode get_attribute übergeben wir die Werte der Attribute an unsere lokalen Variablen. Eine andere Möglichkeit, die Werte des Context-Attributes des ADRESSEKindknotens zu lesen, wird im Listing 5.7 dargestellt. DATA: lr_node TYPE REF TO if_wd_context_node, lr_subnode TYPE REF TO if_wd_context_node, ls_subnode type wd_this->element_adresse. DATA: lv_strasse LIKE ls_subnode-strasse, lv_nummer LIKE ls_subnode-nummer, lv_stadt LIKE ls_subnode-stadt. lr_node = wd_context->get_child_node( ’HOCHSCHULE’ ). lr_subnode = lr_node->get_child_node( ’ADRESSE’ ). lr_subnode->get_static_attributes( IMPORTING static_attributes = ls_subnode ). lv_strasse = ls_subnode-strasse. lv_nummer = ls_subnode-nummer. lv_stadt = ls_subnode-stadt. Listing 5.7 Lesen der Werte der Context-Attribute des Kindknotens „ADRESSE“
In diesem Fall haben wir die Methode get_static_attributes verwendet, die eine Kopie mit allen statischen Attributen des ADRESSE Kindknotens versorgt. Danach sind wir in der Lage, auf die Attributwerte über die lokale Struktur „ls_subnode“ zuzugreifen. Listing 5.8 zeigt, wie wir die Attribute des ADRESSE-Kindknotens mit Werten füllen können.
5.2
Context-Knoten
DATA: lr_node TYPE REF TO if_wd_context_node, lr_subnode TYPE REF TO if_wd_context_node, ls_subnode TYPE wd_this->element_adresse. lr_node = wd_context->get_child_node( ’HOCHSCHULE’ ). lr_subnode = lr_node->get_child_node( ’ADRESSE’ ). ls_subnode-strasse = ’Pforzheimer’. ls_subnode-nummer = ’106A’. ls_subnode-stadt = ’Pforzheim’. lr_subnode->set_static_attributes( ls_subnode ).
Listing 5.8 Füllen der Context-Attribute des ADRESSE-Knotens mit Werten
69
Kapitel 6
Datenbindung, Context-Mapping und Interface-Methoden
You can’t stay in your corner of the forest waiting for others to come to you. You have to go to them sometimes. A. A. Milne
Zusammenfassung Dieses Kapitel beginnt mit der Vorstellung des in Web Dynpro als Datenbindung (Data binding) bezeichneten Mechanismus, mit dem die Daten zwischen den Context-Attributen und UI-Elementen manipuliert werden. Wir fahren fort mit dem Mechanismus zur gemeinsamen Nutzung von Daten zwischen den diversen Controllern, die durch die Benutzung unterschiedlicher Varianten des Context-Mapping realisiert wird. Abschließend heben wir die Wichtigkeit der Schnittstellenmethoden hervor, die benötigt werden, um über Komponentengrenzen (cross-component) auf sie zuzugreifen. Im letzten Kapitel haben wir einen Context-Knoten und Context-Attribute im Context-View erstellt. Ein Knoten oder Attribut kann in jedem Context erzeugt werden. Wenn wir ein Attribut in einem Context-View anlegen, ist dieser Wert nur in diesem Context-View sichtbar. Die Mechanismen zum Austausch von Daten unter den verschiedenen Controllern sind bekannt als „Context Mapping“. Das Context-Mapping kann intern stattfinden, wenn die gemappten Knoten sich innerhalb der gleichen Komponenten befinden, und es kann extern sein, wenn es komponentenübergreifend fungiert. Um Daten auf den Bildschirm zu bringen und um Eingaben des Anwenders einlesen zu können, müssen wir die UI-Elementeigenschaften mit den passenden Context-Attributen verbinden. Dieser Prozess wird Datenbindung genannt. Alle über das Web Dynpro dem Anwender gezeigten oder von ihm eingegebenen Daten, die wir einlesen, werden durch die Context-Knoten und die Context-Attribute manipuliert.
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_6,
71
72
6 Datenbindung, Context-Mapping und Interface-Methoden
6.1 Datenbindung (Data binding) Jedes UI-Element hat bestimmte Eigenschaften. Durch die Datenbindung definieren wir, welcher Knoten oder welches Attribut aus dem Context als Bezugsquelle für eine UI-Elementeigenschaft fungiert. Um beispielhaft zu zeigen, wie der Datenbindungsmechanismus funktioniert, erzeugen wir eine Web-Dynpro-Komponente mit Namen Y_DATABINDING mit einer View namens V_BIND und einem Window W_DEFAULT (Abb. 6.1). Abb. 6.1 Struktur der Y_DATABINDINGKomponente
In der Context View erzeugen wir den Context-Knoten STUDENT mit der gleichen Dictionary-Struktur YSTRU_PERSON (Abb. 6.2).
Abb. 6.2 Struktur des STUDENT Knotens
Wir erstellen eine Web-Dynpro-Komponente, welche die Anwendereingaben in den Attributen VORNAME, NACHNAME und GEBURTSTAG einliest. Wenn der Anwender den „ANZEIGEN“-Button drückt, werden diese Daten mittels des TextView-UI-Elements angezeigt (Abb. 6.3). Wir haben viele Möglichkeiten die Datenbindung durchzuführen. Wir können zum Beispiel: a) ein „Container-Formular“ für einen Context-Knoten erzeugen; b) den Web Dynpro Wizard nutzen; c) die Datenbindung für jedes Attribut separat erstellen. zu (a) Um ein „Container-Formular“ zu kreieren, fügen wir ein Group-UIElement hinzu. Dann öffnen wir durch einen Rechtsklick das Kontextmenü und wählen „Container-Formular erzeugen“ (Abb. 6.4).
6.1
Datenbindung (Data binding)
VIEW V_BIND
73
View-Layout
View-Controller
Datenbindung
Abb. 6.3 Beispiel für Datenbindung
Abb. 6.4 Erzeugen des Container-Formulars
Danach können wir wählen, welchen Context-Knoten wir für die Datenbindung verwenden und welcher Typ von UI-Element mit welchem Context-Attribut verknüpft ist (Abb. 6.5). Als Ergebnis generiert das Framework für jedes Context-Attribut ein InputFieldUI-Element und ein dazugehörendes Label, und es macht die Datenbindung zwischen jedem UI-Element Eigenschaft (Wert) und dem Context-Attribut vor (Abb. 6.6). Um ein „Container-Formular“ zu erzeugen, können wir jedes UI-Element vom Typ Container verwenden. zu (b) Um eine Datenbindung zu erzeugen, können wir den Web-Dynproverwenden (Abb. 6.7). Wir können die Form-Option wählen. Wizard-Button Das Framework generiert dann ein TransparentContainer UI-Element, welches die UI-Elemente beinhaltet, die wir – wie unter Punkt a) gezeigt – auswählen müssen.
74
6 Datenbindung, Context-Mapping und Interface-Methoden
Abb. 6.5 Datenbindung
Abb. 6.6 Datenbindung zwischen dem InputField-UI-Element und den Context- Attributen
Abb. 6.7 Verwendung des Wizard zur Erzeugung eines Formulars und der passenden Datenbindung
zu c) Um die Datenbindung manuell für jedes Context-Attribut vorzunehmen, müssen wir ein passendes UI-Element einfügen und die Datenbindung zwischen einer UI-Elementeigenschaft und einem Context-Attribut erstellen. Dazu fügen wir drei TextView-UI-Elemente und drei Label-UI-Elemente ein (Abb. 6.8). Wir müssen die Datenbindung zwischen jeder Texteigenschaft der TextView-UIElemente und der dazugehörigen Context-Attribute herstellen (Abb. 6.9).
6.1
Datenbindung (Data binding)
75
Abb. 6.8 Layoutstruktur
Bindungs-Button
Abb. 6.9 Datenbindung
Wir wiederholen diesen Schritt, bis die Datenbindung zwischen den Texteigenschaften aller drei UI-Elemente und den dazugehörenden Context-Attributen hergestellt sind. Dann fügen wir einen Button UI-Element in der Group GRP_STUDENT_SCHREIBEN ein und versehen diesen mit einem Ereignis (Abb. 6.10). In diesem Fall brauchen wir kein Coding zur generierten Eventhandler-Methode onactionanzeigen hinzuzufügen. Nachdem wir noch eine Anwendung für unsere Komponente erzeugt haben, sind wir bereit, sie auszuführen. Das Ergebnis ist in Abb. 6.11 dargestellt. Zur Laufzeit sind die Context-Attribute leer. Nachdem der Anwender Werte eingegeben und den ANZEIGEN-Button gedrückt hat, werden die Context-Attribute
76
6 Datenbindung, Context-Mapping und Interface-Methoden
Abb. 6.10 Einfügen eines Buttons und Hinzufügen eines Ereignisses
Abb. 6.11 Ausführen der Applikation
mit diesen Werten bestückt. Zum Entwurfszeitpunkt stellen wir eine Datenbindung zwischen den TextView-UI-Elementen und den gleichen Context-Attributen (VORNAME, NACHNAME und GEBURTSTAG) her. Aus diesem Grund zeigen diese UI-Elemente die Werte, welche der Anwender in die Eingabefelder eingegeben hat.
6.2 Context-Mapping Bis jetzt haben wir nur Context-Attribute, die wir innerhalb des View-Context definiert haben, verwendet. Wenn wir Daten zwischen verschiedenen Controllern austauschen möchten, müssen wir ein Context-Mapping definieren. Ein Context-Mapping kann intern oder extern sein. Eine interne Mappingbeziehung kann zwischen jedem Controllerpaar innerhalb der gleichen WD-Komponente erzeugt werden. Hingegen stellen die externen Mappings Beziehungen über die Grenzen einer WD-Komponente hinaus her.
6.2
Context-Mapping
77
6.2.1 Internes Context-Mapping Wie bereits erwähnt, wird der Mechanismus zum Austausch von Daten zwischen verschiedenen Controllern innerhalb der gleichen WD-Komponente als internes Context-Mapping bezeichnet. Zum besseren Verständnis dieses Mechanismus erstellen wir das gleiche Beispiel aus der Datenbindung noch einmal. Diesmal aber erstellen wir die zwei Group UI-Elemente GRP_STUDENT_LESEN und GRP_STUDENT_SCHREIBEN in verschiedenen Views. Zur Laufzeit zeigen wir die View V_VIEW1. Wenn der Anwender den Button „ANZEIGEN“ drückt, zeigen wir die zweite View V_VIEW2 auch. Diese WD-Komponentenstruktur ist in Abb. 6.12 dargestellt. Abb. 6.12 WD-Komponentenstruktur
Wir können den Context-Knoten nicht im Context-View erzeugen, weil wir die Werte dieser Attribute nicht nur in der View V_VIEW1 benötigen, sondern auch in der View V_VIEW2. Daher erstellen wir den Knoten STUDENT im Context des COMPONENTCONTROLLER. Auf diese Weise können wir auf den Context des COMPONENTCONTROLLER mittels Context-Mapping über einen ViewController zugreifen. Context-Mapping führt nicht zu einer Duplizierung der Daten. Die Knoten im View-Controller halten nur eine Referenz des gemappten Context-Knotens aus dem COMPONENTCONTROLLER (Abb. 6.13). Zuerst erstellen wir den Context-Knoten des COMPONENTCONTROLLER. Danach erfolgt das Context-Mapping zwischen dem Context aus View V_VIEW1 und dem Context-Knoten des COMPONENTCONTROLLER. Als Ergebnis ist der gesamte Context-Knoten STUDENT gemappt (Abb. 6.14, Abb. 6.15). Auf gleiche Weise erstellen wir den Context für V_VIEW2 mithilfe des Contexts des COMPONENTCONTROLLER. Anschließend müssen wir das View-Layout für die Views V_VIEW1 und V_VIEW2 und die Datenbindung erstellen. Daten, die im Context des COMPONENTCONTROLLER gespeichert werden, können in einer View verwendet werden, wenn wir zuerst ein Context-Mapping durchgeführt haben (siehe die schematische Darstellung dazu in Abb. 6.16).
78
6 Datenbindung, Context-Mapping und Interface-Methoden
V_VIEW1 controller
Component-Controller
V_VIEW2 controller
Abb. 6.13 Internes Context-Mapping
Drag & Drop
Abb. 6.14 Context-Mapping
Abb. 6.15 Das Mapping-Ergebnis
6.2
Context-Mapping
V_VIEW1 Layout
79 V_VIEW1 controller Component-Controller
ViewContainerUIElement V_VIEW2 Layout
V_VIEW2 contr oller
Internes ContextMapping Datenbindung
Abb. 6.16 Internes Context-Mapping, Datenbindung
Die Linien zwischen den Controllern symbolisieren das Context-Mapping. Die Linien zwischen den View_Controllern und den View_Layouts symbolisieren die Datenbindungen. In der View V_VIEW1 erstellen wir die Group UI-Element GRP_ STUDENT_SCHREIBEN und dann können wir die Context-View verwenden, um ein „Container-Formular“ zu erzeugen. Weil wir beide Views im gleichen Fenster (Window) zeigen möchten (nachdem der Anwender den Button „ANZEIGEN“ gedrückt hat), verwenden wir ein ViewContainerUIElement (Abb. 6.17).
Abb. 6.17 View-Layout für V_VIEW1
In Abb. 6.18 zeigen wir die Struktur von View V_VIEW2. Wir müssen den View V_VIEW2 in das ViewContainerUIElement einfügen (Abb. 6.19). Nach der Erstellung einer Anwendung können wir das Ergebnis sehen. Zur Laufzeit ist das User Interface identisch mit dem zur Datenbindung (Beispiel Abb. 6.10). Der Unterschied ist das Context-Mapping. In diesem Fall ist der Context nicht
80
6 Datenbindung, Context-Mapping und Interface-Methoden
Abb. 6.18 View-Layout für V_VIEW2
Abb. 6.19 Eingebettete View V_VIEW2
im Context-View definiert, sondern im Context des COMPONENTCONTROLLER und der Zugriff darauf erfolgt über das Context-Mapping. Die Daten befinden sich im Context-Knoten des COMPONENTCONTROLLER, und der Context-Knoten des View-Controllers hält nur eine Referenz darauf.
6.2.2 Externes Context-Mapping Externes Mapping ist ein übergreifendes Mapping und kann ein direktes oder umgedrehtes Mappen sein. Wir können ein externes Context-Mapping erzeugen, wenn wir zuerst eine Verwendung für die Komponente deklariert haben, welche den betreffenden Context enthält, und wenn der entsprechende Context-Knoten als Interface gekennzeichnet wurde. 6.2.2.1 Direktes Mapping Als kurze Beschreibung dieser Art von Mapping können wir sagen, dass externes Mapping der direkten Art ein übergreifendes Mapping ist, in welchem die Hauptkomponenten direkten Zugriff auf die Daten der verwendeten Komponenten haben (dargestellt durch die Context-Struktur). Zum besseren Verständnis dieser Art Mapping erzeugen wir das gleiche Beispiel wie für das interne Mapping, aber diesmal erstellen wir zwei Web-DynproKomponenten (Abb. 6.20). Die Y_EM_CONTEXT ist eine gesichtslose Komponente, die keinen visuellen Teil besitzt – weder ein Window noch eine View. In dem COMPONENT-
6.2
Context-Mapping
81
Abb. 6.20 WD-Komponenten-Struktur
CONTROLLER dieser Web-Dynpro-Komponente erzeugen wir den Knoten STUDENT. Diese Komponente benötigt keinen visuellen Teil, da wir die Komponente Y_EM_LAYOUT verwenden, um das Layout zu implementieren. In der Praxis ist eine gesichtslose Komponente nützlich, wenn verschiedene Komponenten Zugriff auf die gleichen Datensätze haben. Diese Art von Komponenten kann genutzt werden, um ein Modell für eine Multikomponenten-Applikation zu erzeugen. Dazu erstellen wir den Context-Knoten im COMPONENTCONTROLLER der Komponente Y_EM_CONTEXT. Wir behalten den gleichen Context-Knoten STUDENT, aber in diesem Fall erzeugen wir einen Interfaceknoten. Wenn dieser Knoten den Interfacetyp nicht definiert hat, können wir von anderen Komponenten aus auch nicht darauf zugreifen (Abb. 6.21).
Abb. 6.21 Context-Knotenstruktur
82
6 Datenbindung, Context-Mapping und Interface-Methoden
Die Komponente Y_EM_LAYOUT hat zwei Views verwendet, um das User Interface zu erzeugen. Um die Daten zu halten, die der Anwender eingegeben hat, verwenden wir den Context-Knoten STUDENT. Um Zugriff auf diesen Context-Knoten zu haben, müssen wir eine Component-Verwendung definieren. Im WD definiert die Komponente Y_EM_LAYOUT die Verwendung der Komponente Y_EM_CONTEXT (Abb. 6.22).
Abb. 6.22 Definieren der Component-Verwendung
Nachdem die Verwendung festgelegt wurde, müssen wir die ControllerVerwendung im COMPONENTCONTROLLER erzeugen. Dazu müssen wir die Komponente Y_EM_CONTEXT verwenden (in unserem Beispiel CONTEXT genannt) und benötigen daher den INTERFACECONTROLLER (Abb. 6.23).
Abb. 6.23 Controller-Verwendung definieren
Als nächstes müssen wir ein Mapping definieren. In diesem Beispiel ist es ein externes Mapping, da der Knoten, den wir verwenden um das Mapping zu definieren, sich außerhalb der Komponente befindet (Abb. 6.24)
6.2
Context-Mapping
83
Drag & Drop
Abb. 6.24 Definieren eines externen Mapping
Abb. 6.25 Das Mapping-Ergebnis
Als Ergebnis ist der gesamte Context-Knoten gemappt (Abb. 6.25). Unter dem Tabreiter „Methoden“ müssen wir in der wdDolnit()-Hook-Methode überprüfen, ob die von uns verwendete Komponente eine Instanz besitzt. Das Listing 6.1 zeigt, wie wir dies überprüfen können und wie eine Instanz erstellt werden kann, wenn sie noch nicht existiert.
METHOD wddoinit . DATA: lr_cmp_usage TYPE REF TO if_wd_component_usage. lr_cmp_usage = wd_this->wd_cpuse_context( ). IF lr_cmp_usage->has_active_component( ) IS INITIAL. lr_cmp_usage->create_component( component_name = ’Y_EM_CONTEXT’ ). ENDIF. ENDMETHOD.
Listing 6.1 Überprüfen der Instanz der verwendeten Komponente
Durch die Verwendung der Methode HAS_ACTIVE_COMPONENT der IF_WD_COMPONENT_USAGE überprüfen wir, ob die Verwendung eine aktive
84
6 Datenbindung, Context-Mapping und Interface-Methoden
Komponente besitzt. Wenn die Komponente bereits initialisiert wurde, geht die Logik weiter. Anderenfalls erzeugen wir eine Instanz der Komponente durch die Verwendung der CREATE_COMPONENT-Methode des gleichen Interface. Wir müssen sicherstellen, dass die externe Komponente instanziiert wurde, bevor der Interfacecontroller darauf zugreift. Es wird empfohlen, eine Verwendung für die Komponente nur in dem Moment zu erzeugen, wenn wir sie benötigen. In unserem kleinen Beispiel müssen wir die Verwendung in der wdDoInit-Methode erzeugen. Aber falls wir die NavigationsPlugs nutzen möchten, um zu einer vorhandenen Komponente zu navigieren, ist es empfehlenswert, die Verwendung in der Methode zu erzeugen, welche den entsprechenden Plug abfeuert. Als nächstes können wir wie in dem vorhergehenden Beispiel fortfahren. Wir erzeugen ein internes Mapping zwischen dem Context-Knoten des COMPONENTCONTROLLER und dem Context der Views V_VIEW1 und V_VIEW2. Danach können wir die Datenbindung erstellen. Dies alles wird schematisch in Abb. 6.26 dargestellt.
Y_EM_CONTEXT
Y_EM_LAYOUT V_VIEW1 Layout
V_VIEW1 controller
Component-Controller
ViewContainerUIElement V_VIEW2 Layout
V_VIEW2 controller
Externes Mapping Internes Mapping Datenbindung
Abb. 6.26 Schematische Darstellung eines externen direkten Mapping
Die Linien zwischen den WD-Komponenten symbolisieren das externe direkte Context-Mapping. Die Linien zwischen dem COMPONENTCONTROLLER und den View-Controllern stellen das interne Mapping dar. Die Linien zwischen den View-Controllern und den View-Layouts zeigen die Datenbindung.
6.2
Context-Mapping
85
6.2.2.2 Umgedrehtes Mapping (Reverse Mapping) Als Kurzfassung zu dieser Art Mapping können wir sagen, dass das externe Mapping vom umgedrehten Typ ein übergreifendes Mapping ist, in welchem die uns zur Verfügung gestellten Daten (dargestellt durch die Context-Struktur) durch die Hauptkomponente übergeben werden. Um den Bildschirm zu erzeugen, der darauf basiert, nutzen wir die Interface-View der verwendeten Komponente. Zum besseren Verständnis dieser Art Mapping erstellen wir das gleiche Beispiel wie für das direkte Mapping und ändern nur den Implementierungsteil. Wir erzeugen zwei Web-Dynpro-Komponenten namens Y_EM_CONTEXT_RM und Y_EM_LAYOUT_RM. Die WD-Komponenten Struktur ist dargestellt in Abb. 6.27.
Abb. 6.27 WD-Komponentenstruktur
Wir definieren in der Komponente Y_EM_CONTEXT_RM den ContextKnoten STUDENT. Diese Komponente hat keine View, weil wir hier den Interface-View der Komponente Y_EM_LAYOUT_RM einbetten. Die Komponente Y_EM_LAYOUT_RM implementiert das User Interface unter Verwendung der Komponente Y_EM_CONTEXT_RM, welche benötigt wird, um Zugriff auf den Knoten STUDENT zu haben. Schematisch wird dies alles in Abb. 6.28 dargestellt. Zuerst erzeugen wir einen Context-Knoten in dem Component-Controller der Komponente Y_EM_CONTEXT_RM unter Verwendung des gleichen ContextKnotens STUDENT und des Interface-Knotens (Abb. 6.29). Die Komponente Y_EM_LAYOUT_RM implementiert das User Interface. Im Component-Controller erzeugen wir einen Knoten namens STUDENT mit der gleichen Struktur wie der Knoten STUDENT des Component-Controller der Komponente Y_EM_CONTEXT_RM (Abb. 6.30). Nach der Erzeugung des Knotens machen wir ein internes Mapping, wir erzeugen das User Interface und sorgen für die Datenbindung. Eine andere Lösung ist die Komponente Y_EM_LAYOUT zu kopieren und die entsprechenden Änderungen vorzunehmen. Wir kopieren diese Komponente durch einen Rechtsklick auf den Komponentennamen und Auswahl des Punktes „Kopieren“ aus dem Kontextmenü. Wir müssen dann einen Namen für die neue Komponente vergeben und das Paket bestimmen, in welchem wir diese Komponente speichern wollen.
86
6 Datenbindung, Context-Mapping und Interface-Methoden
Y_EM_CONTEXT_RM Embedded Interface -View
Y_EM_LAYOUT_RM V_VIEW1 Layout
V_VIEW1 controller
Component -Controller
ViewContainerUIElement V_VIEW2 Layout
V_VIEW2 controller
Umgedrehtes Mapping Internes M apping Datenbindung
Abb. 6.28 Schematische Darstellung eines externen umgedrehten Mapping
Abb. 6.29 Interface Knoten
Wir definieren die Verwendung der Komponente Y_EM_CONTEXT_RM und erzeugen ein externes umgedrehtes Mapping (Abb. 6.31). Nachdem das notwendige Coding eingegeben wurde, das nötig ist, um zu verifizieren, ob es sich um eine Instanz der verwendeten Komponente handelt, können wir speichern und aktivieren. Als nächster Schritt gehen wir zurück zur Komponente Y_EM_CONTEXT_RM, in welcher wir die Verwendung der Komponente Y_EM_LAYOUT_RM definieren müssen. Dies ist nötig, um ihre Interface View einzubetten (Abb. 6.32). Danach können wir die Interface View der Komponente einbetten, für welche wir nur die Verwendung definiert haben. Das Framework generiert eine entsprechende Interface View, wenn wir ein Window erzeugen. Dieses Interface kann durch eine andere Komponente eingebettet werden, nachdem die Verwendung definiert wurde. Um die Interface View oder das Window der Komponente Y_EM_LAYOUT
6.2
Context-Mapping
87
Abb. 6.30 Interface-Knoten, Input-Element
Abb. 6.31 Kontextstruktur nach der Verwendung und dem Mapping
einzubetten, verfahren wir in der gleichen Weise wie für das Einbetten der Views (Abb. 6.33). Nachdem das notwendige Coding eingegeben wurde, um zu prüfen, ob eine Instanz der verwendeten Komponente existiert, können wir speichern, aktivieren und die Applikation starten. Als Beispiel für die Verwendung eines umgedrehten Mapping können wir eine ALV (SAP List Viewer)-Komponente erwähnen, die wir in Kap. 13 verwenden werden.
88
6 Datenbindung, Context-Mapping und Interface-Methoden
Abb. 6.32 Definieren der Verwendung
Abb. 6.33 Eingebettete Operation
6.3 Interface-Methoden Eine Methode eines Component-Controllers kann als Interface markiert werden. Auf diese Weise ist es möglich, den Zugriff übergreifend zu gestatten. Diese Option ist nur für die Methoden möglich, die dem Component-Controller zugeordnet sind. Methoden aus den Views oder Windows können nicht als Interface markiert werden. Zum besseren Verständnis dieser Art von Methoden erweitern wir das vorhergehende Beispiel. Nachdem der Anwender Daten eingegeben und den „ANZEIGEN“Button gedrückt hat, werden in diesem Beispiel die Context-Attribute des Knotens STUDENT der Komponente Y_EM_CONTEXT_RM mit diesen Werten versorgt. Wenn wir prüfen möchten, ob der Anwender einen Vornamen eingegeben hat, müssen wir eine Interface-Methode im Component-Controller dieser Komponente definieren. In dieser Methode wird geprüft, ob das Context-Attribut einen
6.3
Interface-Methoden
89
Wert enthält oder leer ist. Dazu erzeugen wir eine Interface-Methode namens ueberpruefen_vorname() (Abb. 6.34).
Abb. 6.34 Markieren einer Component-Controller-Methode als Interface
Wir erzeugen diese Methode in der Komponente Y_EM_CONTEXT_RM, weil dort der Context-Knoten ist, in welchen die Werte transferiert werden, nachdem der Anwender den „ANZEIGEN“-Button gedrückt hat. Das Coding aus dem Listing 6.2 zeigt die Implementierung dieser Methode. METHOD ueberpruefen_vorname . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_node TYPE if_componentcontroller=>element_student. DATA lv_vorname TYPE string. DATA lr_api_controller TYPE REF TO if_wd_controller. DATA lr_message_manager TYPE REF TO if_wd_message_manager. lr_node = wd_context->get_child_node( ’STUDENT’ ). lr_node->get_attribute( EXPORTING name = ’VORNAME’ IMPORTING value = lv_vorname ). IF lv_vorname IS INITIAL. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). lr_message_manager->report_error_message( message_text = ’Das Vornamemfeld ist leer!’). ENDIF. ENDMETHOD.
Listing 6.2 Implementierung der Methode ueberpruefen_vorname
Wir lesen den Wert des Attributes VORNAME in die lokale Variable lv_ vorname. Danach prüfen wir, ob diese Variable einen Wert beinhaltet oder leer ist. Falls es initial ist, möchten wir eine Meldung mit dem String ,Das Vornamenfeld ist leer!‘ ausgeben. Dafür haben wir die Methode REPORT_ERROR_MESSAGE des Interface IF_WD_MESSAGE_MANAGER genutzt. Um eine Meldung zu erzeugen, können wir den Web Dynpro Code Wizard (Abb. 6.35) verwenden.
90
6 Datenbindung, Context-Mapping und Interface-Methoden
Abb. 6.35 Anwendung des Web Dynpro Code Wizard
Diese Art der Programmierung wird nicht empfohlen, wenn sprachspezifische Textelemente in den Quelltext eingegeben werden. Im vorliegenden Fall haben wir den einfachen, aber nicht den besten Weg gewählt. In Kap. 10 wird erläutert, wie wir ganz einfach eine Meldung erstellen und diese ohne weiteren Programmieraufwand verwenden und übersetzen können. Nachdem diese Methode implementiert ist, müssen wir zur Komponente Y_EM_LAYOUT_RM zurückkehren. Wenn der Anwender den „ANZEIGEN“Button drückt, müssen wir die Methode ueberpruefen_vorname() aus der Komponentenverwendung aufrufen. Wenn eine Methode als Interface markiert ist, können wir komponentenübergreifend darauf zugreifen. Das bedeutet, wir können sie von unserer onactionanzeigenEventhandler-Methode aus aufrufen, nachdem wir die Verwendung auf der ViewEbene definiert haben (Abb. 6.36).
Abb. 6.36 Verwendungsdefinition
Das Coding aus dem Listing 6.3 zeigt die Implementierung der onactionanzeigen-Eventhandler-Methode.
6.3
Interface-Methoden
91
METHOD onactionanzeigen. DATA: lr_interfacecontroller TYPE REF TO yiwci__em_context_rm . lr_interfacecontroller = wd_this->wd_cpifc_context( ). lr_interfacecontroller-> ueberpruefen_vorname( ). ENDMETHOD
Listing 6.3 Methodenaufruf im verwendeten Controller
Wir können den Web Dynpro Code Wizard nutzen, um dieses Coding zu generieren (Abb. 6.37).
Abb. 6.37 Web Dynpro Code Wizard
In Abb. 6.38 stellen wir das Ergebnis vor.
Abb. 6.38 Zur Laufzeit
Kapitel 7
View-Controller-Methoden
When it is dark enough, you can see the stars Ralph Waldo Emerson
Zusammenfassung Wie wir in den vorangegangenen Kapiteln gesehen haben, finden wir im Methoden-Tab einer View diverse Typen von vom Framework generierten Methoden, und wir können auch unsere eigenen Methoden erstellen. Der Zweck dieses Kapitels ist es, zu zeigen, wie diverse vom Framework generierte Methoden verwendet werden und wie wir unsere eigenen Methoden realisieren können. Jede View hat genau einen View-Controller. Der View-Controller kann Methoden für Datenabfragen oder Benutzereingabenverarbeitung beinhalten. Wie wir gesehen haben, hat jede View einen Methoden-Tabreiter, in dem wir unsere eigenen benutzerdefinierten Methoden erstellen oder die vom Framework generierten Methoden finden können. In jedem Methoden-Tabreiter einer View können wir drei Methodentypen finden oder erzeugen: • Eventhandler – diese Art Methoden reagiert auf Aktionen oder Ereignisse (Events). Ein Beispiel für ein solche Methode wird vom Framework generiert, wenn wir einen Inbound-Plug zu einer View definieren. Ein weiteres Beispiel ist die Methode, die vom Framework generiert wird, wenn wir eine Aktion erzeugen. • Methode – wir können diese Art Methoden verwenden, um benutzerdefinierte Instanzmethoden zu erstellen. Weitere Beispiele stellen die Hook-Methoden dar, die vom Framework generiert werden. • Supply-Funktion – wenn wir einen Knoten erstellen und eine Supply-Funktion für diesen definieren, generiert das Framework eine zugehörige Methode für die Supply-Funktion, mit dem Zweck, den Context-Knoten mit Daten zu füllen.
7.1 Hook-Methoden Diese Methoden können nicht gelöscht werden und repräsentieren die Schnittstelle zwischen dem Framework und unserer Anwendung. Die Hook-Methoden werden in einer bestimmten Reihenfolge gemäß dem Phasenmodell aufgerufen. Nach der U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_7,
93
94
7 View-Controller-Methoden
Generierung sind diese Methoden zunächst leer, aber sie können mit Sourcecode gefüllt werden, wenn wir in einem bestimmten Schritt dieses Phasenmodells eingreifen möchten. Tabelle 7.1 zeigt die Hook-Methoden in verschiedenen Controllern Tabelle 7.1 Hook-Methoden Hook-methoden
Component controller
View controller
Window controller
Custom controller
wddoinit( ) wddoexit( ) wddobeforenavigation( ) Wddopostprocessing( ) wddomodifyview( ) wddoafteraction( ) wddobeforeaction( ) Wddooncontextmenu( ) wddoapplicationstatechange() wddoonopen( ) wddoonclose( )
Yes Yes Yes Yes – – – – Yes – –
Yes Yes – – Yes Yes Yes Yes – – –
Yes Yes – – – – – – – Yes Yes
Yes Yes – – – – – – – – –
Wie wir sehen, sind die Hook-Methoden wdDoInit und wdDoExit für alle Controller üblich. Die Abb. 7.1 zeigt, welche Hook-Methoden in einer View zu finden sind.
Abb. 7.1 Hook-Methoden in einer View
7.1.1 wdDoInit Diese Methode kann als Konstruktor des Controllers betrachtet werden. Sie wird automatisch aufgerufen, wenn der Controller das erste Mal initialisiert wird. Es gibt viele Beispiele, wo wir diese Methode verwenden können: Setzen der Initialwerte des Contexts eines Controllers, dynamische Erstellung von Context-Knoten und Context-Attributen, Füllen von Context-Knoten. Außerdem
7.1
Hook-Methoden
95
kann diese Methode auch anstelle einer Supply-Funktion eingesetzt werden (um einen Context-Knoten mit Werten zu füllen), aber nur, wenn wir sicherstellen können, dass der Context nur einmal gefüllt ist und nicht hinterher auf ungültig gesetzt wird. Wir erzeugen eine WD-Komponente, die eine wdDoInit Hook-Methode nutzt, um den Context-Knoten mit Werten zu füllen. Die Komponentenstruktur und das View-Layout sind in Abb. 7.2 dargestellt.
Abb. 7.2 WD Komponentenstruktur, View-Layout
In der Kontext-View legen wir einen Kontextknoten namens STUDENT mit derselben Struktur wie beim Datenbindungsbeispiel an – Dictionarystruktur YSTRU_PERSON, Kardinalität 1. . .1, Singleton, ohne Supply-Funktion (Abb. 7.3).
Abb. 7.3 Context-Struktur
Mit Hilfe der wdDoInit-Hook-Methode bestücken wir diesen Knoten mit Werten (Listing 7.1). Sobald wir die Anwendung das erste Mal aufrufen, füllt dann die wdDoInit-Hook-Methode den Knoten STUDENT mit allen hier gesetzten Elementen (Abb. 7.4).
96
7 View-Controller-Methoden
METHOD wddoinit DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE if_v_view=>element_student. lr_node = wd_context->get_child_node( ’STUDENT’ ). ls_data-vorname = ’Antonia Maria’. ls_data-nachname = ’Keller’. ls_data-geburtstag = ’19800306’. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 7.1 Die wdDoInit-Hook-Methode Abb. 7.4 Laufzeit
Die wdDoInit-Hook-Methode kann dazu dienen, den Context-Knoten STUDENT dynamisch zu erzeugen und ihn mit Werten zu füllen (Listing 7.2).
METHOD wddoinit. DATA: lr_node TYPE REF TO if_wd_context_node, lr_node_info TYPE REF TO if_wd_context_node_info, lr_child_node_info TYPE REF TO if_wd_context_node_info. lr_node_info = wd_context->get_node_info( ). lr_child_node_info = lr_node_info->add_new_child_node( name = ’STUDENT’ is_singleton = abap_true is_multiple = abap_false is_mandatory = abap_true static_element_type = ’YSTRU_PERSON’ ). lr_node = wd_context->get_child_node( ’STUDENT’ ). DATA ls_data TYPE ystru_person. ls_data-vorname = ’Antonia Maria’. ls_data-nachname = ’Keller’. ls_data-geburtstag = ’19800306’. lr_node->bind_structure( EXPORTING new_item = ls_data ). ENDMETHOD.
Listing 7.2 Die wdDoInit-Hook-Methode
7.1
Hook-Methoden
97
Um den Context-Knoten „STUDENT“ dynamisch zu erstellen, haben wir die Methode ADD_NEW_CHILD_NODE des IF_WD_CONTEXT_NODE_INFOInterface genutzt, die ihrerseits ein Info-Objekt erzeugt und es als Lower-Level-Knoten zum CONTEXT-Wurzelknoten hinzufügt. Die Methode CREATE_NODEINFO_FROM_STRUCT der Klasse CL_WD_DYNAMIC_TOOL ist veraltet, und deswegen ist es empfehlenswert, if_wd_context_node_info>add_new_child_node zu verwenden. ADD_NEW_CHILD_NODE hat viele Importparameter, von denen wir im Bereich unseres Beispiels einige benutzt haben: • NAME vom Typ STRING – der Name des generierten Context-Knotens; • IS_SINGLETON vom Typ ABAP_BOOL, Standardwert ABAP_FALSE – setzt die Knoteneigenschaft SINGLETON. In unserem Beispiel muss der Knoten STUDENT singleton sein, und darum haben wir den Wert auf ABAP_TRUE gesetzt; • IS_MULTIPLE vom Typ ABAP_BOOL, Standardwert ABAP_TRUE – setzt die Knoteneigenschaft CARDINALITY. In unserem Beispiel hat der Knoten STUDENT die Kardinalität 1. . .1, und deswegen haben wir diesen Wert auf ABAP_FALSE gesetzt; • IS_MANDATORY vom Typ ABAP_BOOL, Standardwert ABAP_FALSE – setzt die Knoteneigenschaft CARDINALITY. Wir brauchen den Wert ABAP_TRUE, weil der Kontextknoten zur Laufzeit exakt ein Context-Element benötigt; • STATIC_ELEMENT_TYPE vom Typ STRING – damit definieren wir die Eigenschaft DICTIONARY_STRUKTUR für unseren Context-Knoten. Auch wenn der Knoten zur Entwurfszeit erzeugt wird, können wir die Namen der im ABAP Dictionary erstellten Entwicklungsobjekte (als Struktur oder View) verwenden.
7.1.2 wdDoExit Diese Methode kann man als Controller Destruktor betrachten. Sie wird automatisch beim Verlassen des Controllers aufgerufen und kann entsprechend zum Ausführen von abschließenden Programmanweisungen eingesetzt werden. Im ABAP Dictionary haben wir eine Sperre für die Datenbanktabelle YPERSONEN definiert. Die Hook-Methode wdDoExit lässt sich zum Lösen einer Sperre einsetzen, die für diese Tabelle gesetzt wurde, um den Zugriff mehrerer WDAnwendungen auf dieselben Daten zu synchronisieren. Zu diesem Zweck nutzen wir den generierten Funktionsbaustein DEQUEUE_EYPERSONEN (Listing 7.3). Hier haben wir den Funktionsbaustein direkt von unserer WD-Methode aus aufgerufen, aber wir können auch eine Methode in einer Klasse erzeugen, die als Modell für die WD-Komponente dient. Wenn wir den zugehörigen Funktionsbaustein DEQUEUE_EYPERSONEN nicht zum Lösen des durch
98
7 View-Controller-Methoden
METHOD wddoexit. DATA lv_id_bewerber TYPE yperson-id_person. DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_bewerber. lr_node = wd_context->get_child_node(’BEWERBER’). lr_node->get_attribute( EXPORTING name = ’ID_PERSON’ IMPORTING value = lv_id_bewerber CALL FUNCTION ’DEQUEUE_EYPERSONEN’ EXPORTING id_person = lv_id_bewerber. ENDMETHOD.
).
Listing 7.3 Die wdDoExit-Hook-Methode
ENQUEUE_EYPERSONEN gesperrten Datenbanksatzes aufrufen, wird die Sperre generell zum Ende der Transaktion entfernt.
7.1.3 wdDoModifyView Diese Methode wird hauptsächlich in der dynamischen Programmierung angewandt. Es ist eine Methode für das Modifizieren einer View vor dem Rendern. Für die dynamische Programmierung der UI-Elemente stehen uns viele Klassen und Methoden zur Verfügung, die uns als Anwendungsentwickler beim dynamischen Modifizieren einer View unterstützen. Um das zu veranschaulichen, bauen wir ein Beispiel, eine WD-Komponente, bei der wir diese Hook-Methode zum dynamischen Erstellen eines InputFields, eines Labels, eines TextView und eines LinkToAction-UI-Elementes einsetzen. Die WD-Komponentenstruktur und der Context-Knoten sind in Abb. 7.5 dargestellt.
Abb. 7.5 WD Komponentenstruktur und Context-Knoten
7.1
Hook-Methoden
99
Für dieses Beispiel importieren wir in den MIME (Multipurpose Internet Mail Extensions)-Ordner ein Bild: next.JPG, das wir für das linkToAction-UI-Element benötigen. Um eine Datei in diesen Ordner zu importieren, machen wir einen Rechtsklick auf den Namen der WD-Komponente und wählen aus dem Kontextmenü Anlegen->Mime Objekt -> Importieren. Der Context-Knoten PERSON hat die Kardinalität 1. . .1, Singleton. Seine Context-Attribute sind NAME und GREETING, vom Typ String. Wir können fast dasselbe Beispiel benutzen wie für unsere erste Übung. In diesem Fall erstellen wir zur Entwurfszeit nur die UI Element Group, die anderen UI-Elemente werden dynamisch mittels der wdDoModifyView-Hook-Methode erzeugt. Das View-Layout wird in Abb. 7.6 gezeigt.
Abb. 7.6 View-Layout
Listing 7.4 zeigt den Inhalt der wdDoModifyView-Hook-Methode METHOD wddomodifyview . DATA lv_bind_name TYPE string. DATA lv_bind_greeting TYPE string. DATA lr_link_to_action TYPE REF TO cl_wd_link_to_action. DATA lr_container TYPE REF TO cl_wd_group. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_input_field TYPE REF TO cl_wd_input_field. DATA lr_text_view TYPE REF TO cl_wd_text_view. DATA lr_label TYPE REF TO cl_wd_label. IF first_time EQ abap_true. lr_label = cl_wd_label=>new_label( id = ’LBL_NAME’ label_for = ’NAME’ text = ’NAME’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_label ). lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( lr_label ). lv_bind_name = ’PERSON.NAME’. lr_input_field = cl_wd_input_field=>new_input_field( id = ’NAME’ bind_value = lv_bind_name ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_input_field ). lr_container->add_child( lr_input_field ). lr_link_to_action = cl_wd_link_to_action=>new_link_to_action( id = ’LTA_LINKTOACTION’
100
7 View-Controller-Methoden
on_action = ’NEXT’ image_source = ’NEXT.JPG’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_link_to_action ). lr_container->add_child( lr_link_to_action ). lv_bind_greeting = ’PERSON.GREETING’. lr_text_view = cl_wd_text_view=>new_text_view( id = ’TXV_NAME’ bind_text = lv_bind_greeting ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_text_view ). lr_container->add_child( lr_text_view ). ENDIF. ENDMETHOD.
Listing 7.4 Die WdDoModifyView-Hook-Methode
Beim Verwenden des FIRST_TIME Parameters vom Typ WDY_BOOLEAN prüfen wir, ob wdDoModifyView zum ersten Mal aufgerufen wird. Falls dieser Parameter ABAP_TRUE (first time) ist, erstellen wir ein UI-Element Label lr_label = cl_wd_label=>new_label( id = ’LBL_NAME’ label_for = ’NAME’ text = ’NAME’ ).
Dazu verwenden wir die Methode NEW_LABEL aus der CL_WD_LABEL Klassenschnittstelle (Abb. 7.7).
Abb. 7.7 Klassenschnittstelle CL_WD_LABEL
7.1
Hook-Methoden
101
Die Methode NEW_LABEL hat viele obligatorische und optionale Parameter (Abb. 7.8).
Abb. 7.8 Parameter für die Methode NEW_LABEL
Wir benutzten LABEL_FOR, TEXT und ID, um die Haupteigenschaften für das Label-UI-Element zu setzen. Der TEXT-Parameter hilft uns beim Setzen des Labeltexts. Der LEBEL_FOR-Parameter bestimmt das UI-Element, zu dem das Label gehört. Um die UI-Elemente in den Entwurf einzubetten, müssen wir die Anordnung dieser Elemente spezifizieren. Hierzu haben wir das FlowLayout-Layout verwendet: lr_flow_data = cl_wd_flow_data=>new_flow_data( element =
lr_label ).
Die Group UI-Element hat dasselbe Layout. Nach dem Erstellen des UI-Elements und des Layouts müssen wir diese an das ROOTCONTAINERUIELEMENT oder an einen anderen Container anbinden. In unserem Fall heften wir unser neues Label an die Group UI-Element mit der GRP ID. lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( lr_label ).
Das ermöglicht uns die Methode add_child( ). Danach erzeugen wir das UI-Element InputField lr_input_field = cl_wd_input_field=>new_input_field( id = ’NAME’ bind_value = lv_bind_name ).
Wir benutzen die Methode new_input_field( ) aus der cl_wd_input_field Klassenschnittstelle. Der Parameter bind_value repräsentiert die Eigenschaft „value“ für die UI-Elementeigenschaft. In diesem Fall erzeugen wir dynamisch eine Datenbindung (data binding) für diese Eigenschaft beim Context-Knoten PERSON, Context-Attribut NAME. Bis jetzt konnten wir eine Datenbindung zur Entwurfszeit vornehmen. In diesem Fall ist das jedoch nicht möglich, weil dieses UI-Element zur Entwurfszeit nicht existiert. Entsprechend muss es dynamisch zur Laufzeit erzeugt werden.
102
7 View-Controller-Methoden
Zur dynamischen Erstellung einer Datenbindung der Eigenschaft value mit dem Attribut NAME müssen wir den absoluten Pfad dieses Context-Attributs angeben. lv_bind_name = ’PERSON.NAME’.
Im nächsten Schritt erstellen wir dynamisch ein LinkToAction-UI-Element:lr_link_to_action = cl_wd_link_to_action=>new_link_to_action( id = ’LTA_LINKTOACTION’ on_action = ’NEXT’ image_source = ’NEXT.JPG’ ).
Wir verwenden die Methode new_link_to_action der cl_wd_link_to_actionKlassenschnittstelle. Dem UI-Element ist ein Ereignis assoziiert. Wir haben den Parameter on_action zur Definition der Aktion benutzt, die das Framework triggert, wenn der Benutzer mit diesem UI-Element interagiert. Für ein linkToAction-UI-Element definieren wir einen Hypertextlink oder ein Bild anstelle eines Textes. In unserem Fall haben wir den Parameter image_source benutzt, um den Namen des Bildes zu spezifizieren. Dann bestimmen wir das Layout und heften es an unsere Group UI-Element mit derselben ID: GRP. Zum Schluss erstellen wir dynamisch ein TextView-UI-Element unter Verwendung der new_text_view Methode der cl_wd_text_view Klassenschnittstelle. lr_text_view = cl_wd_text_view=>new_text_view( id = ’TXV_NAME’ bind_text = lv_bind_greeting ).
Die Datenbindung an das Context-Attribut GREETING wird dynamisch erzeugt. Nach der Erstellung des UI-Elements bestimmen wir das Layout und hängen es an unsere Group UI-Element mit derselben ID: GRP. Alles was wir noch zu tun haben, ist eine Aktion namens Next (Abb. 7.9) anzulegen.
Abb. 7.9 Aktion Next
Wenn der Benutzer das linkToAction-UI-Element anklickt, triggert das Framework die Eventhandler-Methode onactionnext. In Abb. 7.10 stellen wir das Ergebnis vor.
7.1
Hook-Methoden
103
Abb. 7.10 Laufzeit METHOD onactionnext. DATA: lv_name TYPE string, lv_greeting TYPE string. DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_person. lr_node = wd_context->get_child_node( ’PERSON’ ). lr_node->get_attribute( EXPORTING name = ’NAME’ IMPORTING value = lv_name ). CONCATENATE ’Willkommen’ lv_name INTO lv_greeting SEPARATED BY space. ls_data-greeting = lv_greeting. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 7.5 Die onactionnext-Eventhandler-Methode
Falls wir die „state“ Eigenschaft des Input-UI-Elements auf „required“ setzen wollen, brauchen wir nur eine zusätzliche Codezeile: lr_input_field = cl_wd_input_field=>new_input_field( id = ’NAME’ state = cl_wd_input_field=>e_state-required bind_value = lv_bind_name ).
Der „state“-Parameter wird benutzt, um die Eigenschaft mit demselben Namen beim InputField-UI-Element zu setzen. Wenn wir diesen optionalen Parameter nicht verwenden, wird der Standardwert gesetzt: CL_WD_INPUT_FIELD=>E_STATENORMAL.
Tipp WdDoModifyView sollte nur für UI-Manipulationen, aber nicht für die dynamische Erstellung von Context-Knoten und Context-Attributen eingesetzt werden.
104
7 View-Controller-Methoden
7.1.4 wdDoBeforeAction Diese Methode erlaubt es, unsere eigene Validierung durchzuführen, bevor eine Aktion getriggert wird. Um dies zu veranschaulichen, erstellen wir eine Web-Dynpro-Komponente namens Y_WDDOBEFOREACTION mit einer View V_VIEW und einem Window W_DEFAULT. In der Context-View erzeugen wir den wohlbekannten Context-Knoten STUDENT mit derselben Dictionary-Struktur YSTRU_PERSON, Kardinalität 1. . .1, Singleton, ohne Supply-Funktion. Unsere Aufgabe ist es, zu prüfen, ob der Benutzer in allen inputFields UI Elements Werte einträgt, abhänging von den Attributen des Context-Knotens Student. Das View-Layout ist in Abb. 7.11 dargestellt.
Abb. 7.11 Das View-Layout
In der wdDoBeforeAction Hook-Methode verwenden wir die statische Methode CHECK_MANDATORY_ATTR_ON_VIEW der Klasse CL_WD_ DYNAMIC_TOOL zur Prüfung, ob der Benutzer in allen obligatorischen Feldern Werte eingetragen hat (die state-Eigenschaft des inputField-UI-Elements ist auf required gesetzt) (Listing 7.6).
METHOD wddobeforeaction. DATA lr_api_controller TYPE REF TO if_wd_view_controller. DATA lr_action TYPE REF TO if_wd_action. lr_api_controller = wd_this->wd_get_api( ). lr_action = lr_api_controller->get_current_action( ). IF lr_action IS BOUND. CASE lr_action->name. WHEN ’ANZEIGEN’. cl_wd_dynamic_tool=>check_mandatory_attr_on_view( view_controller = lr_api_controller ). ENDCASE. ENDIF. ENDMETHOD
Listing 7.6 Die wdDoBeforeAction-Hook-Methode
7.1
Hook-Methoden
105
Wenn der Benutzer den „Anzeigen“-Button drückt, prüft das Web-DynproFramework zuerst mittels der wdDoBeforeAction-Hook-Methode, ob alle erforderlichen Felder ausgefüllt sind. Sollte der Benutzer nicht in allen diesen Feldern Werte eingetragen haben, werden alle Operationen, die nach dem Drücken des „Anzeigen“-Buttons stattfinden müssen, durchgeführt, und der Benutzer wird durch Fehlermeldungen und Hervorheben der Fehler verursachenden UI-Elemente darüber informiert. Daher müssen wir nicht jedes Pflichtfeld manuell prüfen. Zur Laufzeit haben wir (Abb. 7.12):
Abb. 7.12 Laufzeit
7.1.5 wdDoOnContextMenu Diese Methode unterstützt hierarchische Kontextmenüs in Web-Dynpro-Views. In unserem ersten Beispiel haben wir schon das Standard-Kontextmenü gesehen, das vom Web-Dynpro-Framework angezeigt wird, wenn der Benutzer einen Rechtsklick auf ein UI-Element macht. Wir können ein Kontextmenü zur Entwurfszeit erstellen, indem wir die Wurzel „CONTEXT_MENUS“ verwenden. Oder auch dynamisch durch das Kodieren der wdDoOnContextMenu-Hook-Methode. Um zu veranschaulichen, wie wir diese Methode zur dynamischen Erstellung von Kontextmenüs anwenden, benutzen wir das Beispiel von der wdDoBeforeAction-Hook-Methode. In diesem Fall bieten wir dem Benutzer die Möglichkeit, die Felder zu personalisieren, die er als Mussfelder haben möchte. Er ist in der Lage, zu wählen, ob sein vorname oder sein nachname Pflichtfeld sein soll. Wenn er vorname als Pflichtfeld wählt, markieren wir das zugehörige Feld mit einem roten Stern, entsprechend wird bei Wahl von nachname das zugehörige Feld mit einem roten Stern gekennzeichnet. Im Standardmodus ist vorname Pflichtfeld.
106
7 View-Controller-Methoden
Für dieses Beispiel müssen wir in der vorigen Anwendung einige Modifikationen vornehmen. Diesmal setzen wir die Statuseigenschaften der zwei inputField-UIElementen dynamic, korrespondierend zu vorname und nachname. Um das umzusetzen, müssen wir in der Context-View zwei zusätzliche Context-Attribute vom Typ WDUI_STATE erstellen, um diese Context-Attribute mit den entsprechenden Eigenschaften zu verbinden (Abb. 7.13).
Abb. 7.13 Context-Struktur und Datenbindung
Auf diese Weise sind die zwei inputField-UI-Elemente zur Entwurfszeit nicht als Pflichtfelder gekennzeichnet. Um im Standardmodus vorname als Pflichtfeld zu setzen, bedienen wir uns der wdDoInit-Hook-Methode, über die wir uns gerade informiert haben ( Listing 7.7). METHOD wddoinit . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-vorname = cl_wd_input_field=>e_state-required. ls_data-nachname = cl_wd_input_field=>e_state-normal. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 7.7 Das Setzen der Initialwerte für unseren Context-Knoten DYNAMISCH
Um dem Benutzer die Möglichkeit zu geben, dynamisch zu entscheiden, welchen Wert er aus zwei optionalen Werten zum Pflichtfeld macht, müssen wir die wdDoOnContextMenu-Hook-Methode kodieren (Listing 7.8). Mit der ersten DATA-Anweisung erzeugen wir eine lokale Referenz zu der CL_WD_MENU-Klasse und zwei lokale Referenzen zu CL_WD_MENU_ ACTION_ITEM, die wir zur dynamischen Erstellung unseres Menüs brauchen, sowie zwei Menü-Optionen (Typ MenuActionItem). Wir brauchen diese zwei Menü-Optionen, um dem Benutzer die Möglichkeit zu bieten, zwischen zwei Optionen auszuwählen: Vorname ist pflichtangabe or Nachname ist pflichtangabe.
7.1
Hook-Methoden
107
METHOD wddooncontextmenu . DATA: lr_menu TYPE REF TO cl_wd_menu, lr_menu_item1 TYPE REF TO cl_wd_menu_action_item, lr_menu_item2 TYPE REF TO cl_wd_menu_action_item. DATA: lr_node TYPE REF TO if_wd_context_node, lv_vorname TYPE wdui_state, lv_nachname TYPE wdui_state. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). lr_node->get_attribute( EXPORTING name = ’VORNAME’ IMPORTING value = lv_vorname ). lr_node->get_attribute( EXPORTING name = ’NACHNAME’ IMPORTING value = lv_nachname ). lr_menu = cl_wd_menu=>new_menu( id = ’CONTEXT_MENU’ ). IF lv_vorname = 01 AND lv_nachname = 00. lr_menu_item1 = cl_wd_menu_action_item=>new_menu_action_item( id = ’MAI_NACHNAME’ on_action = ’NN_PFLICHT’ text = ’Nachname ist pflichtangabe’). lr_menu_item2 = cl_wd_menu_action_item=>new_menu_action_item( id = ’MAI_VORNAME’ on_action = ’VN_PFLICHT’ text = ’Vorname ist pflichtangabe’ enabled = abap_false ). ELSEIF lv_vorname = 00 AND lv_nachname = 01. lr_menu_item2 = cl_wd_menu_action_item=>new_menu_action_item( id = ’MAI_VORNAME’ on_action = ’VN_PFLICHT’ text = ’Vorname ist pflichtangabe’). lr_menu_item1 = cl_wd_menu_action_item=>new_menu_action_item( id = ’MAI_NACHNAME’ on_action = ’NN_PFLICHT’ text = ’Nachname ist pflichtangabe’ enabled = abap_false ). ENDIF. lr_menu->add_item( the_item = lr_menu_item1 ). lr_menu->add_item( the_item = lr_menu_item2 ). menu = lr_menu. ENDMETHOD.
Listing 7.8 Das wdDoOnContextMenu-Beispiel
Mit der zweiten DATA-Anweisung erzeugen wir zwei lokale Variablen, die wir benötigen, um aus den Context-Attributen diejenigen Statuseigenschaften zu lesen, die mit den zwei inputFields-UI-Elementen (vorname, nachname) korrespondieren, und eine lokale Referenz für den Zugriff auf unseren Context-Knoten. Zuerst erzeugen wir ein Kontextmenü mit Hilfe der statischen Methode NEW_MENU der CL_WD_MENU_KLASSE. Unter Verwendung der statischen Methode NEW_MENU_ACTION_ITEM der cl_wd_menu_action_item-Klasse erstellen wir die zwei benötigten Menü-Optionen. Von den Parametern dieser Klasse haben wir folgende benutzt:
108
7 View-Controller-Methoden
• id – um die ID des View-Elements zu setzen; • on_action – um die Aktion zuzuweisen, die getriggert wird, wenn der Benutzer den entsprechenden Button drückt; • text – der Text, der für die entsprechende Menü-Option angezeigt wird; • enabled – um diese Option aktiv oder inaktiv zu setzen. Im Standard-Modus ist dieser Parameter ABAP_TRUE, entsprechend enabled. Die lokalen Variablen, die der Übergabe der beiden Attribute (vorname und nachname) dienen, sind vom selben Typ wie die Attribute: WDUI_STATE. Beim Doppelklick auf TYPE wird die Vorwärtsnavigation geöffnet und wir sehen ein Datenelement mit einer Domäne als elementarem Datentyp. Diese Domäne hat zwei feste Werte: 00 für Normal item and 01 für required. Bevor wir darangehen, die zwei Menüoptionen tatsächlich zu erstellen, müssen wir prüfen, welche der beiden state-Eigenschaften auf required und welche auf normal gesetzt ist. Falls vorname required und nachname normal ist, erstellen wir zwei Menüoptionen mit „Nachname ist pflichtangabe“ als aktiv und „Vorname ist pflichtangabe “ als inaktiv. Falls der vorname normal und der nachname required ist, erstellen wir zwei Menüoptionen mit „Nachname ist pflichtangabe“ inaktiv und „Vorname ist pflichtangabe“ aktiv. Dann fügen wir die zwei erstellten Menü-Optionen des Typs menuActionItem zu unserem Kontextmenü hinzu und zeigen das entsprechende Menü mittels der wdDoOnContextMenu-Hook-Methode an, wobei der Parameter namens menu zurückgegeben wird. Wir entnehmen Abb. 7.13, dass wir für unsere InputFields UI-Element folgende Eigenschaften haben: • contextMenuBehaviour – unterstützt, erbt aber nicht vom Container; • contextMenuId – gesetzt mit den IDs unserer Kontextmenü Optionen. Alles was wir noch zu tun haben, ist das Anlegen der passenden Aktionen: VN_PFLICHT und NN_PFLICHT-Aktionen, die das Framework triggert, wenn der Benutzer unsere Menü-Aktions-Items drückt. Die onactionnn_pflicht-Eventhandler-Methode wird in Listing 7.9 gezeigt. METHOD onactionnn_pflicht . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-vorname = cl_wd_input_field=>e_state-required. ls_data-nachname = cl_wd_input_field=>e_state-normal. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 7.9 Eventhandler-Methode, für die Menüoption mit MAI_NACHNAME ID getriggert
7.1
Hook-Methoden
109
Falls der Benutzer nachname als Pflichtfeld wählt, müssen wir die Eigenschaft state des zugehörigen UI-Elements auf required setzen und die Eigenschaft state des zu vorname korrespondierenden UI-Elements auf normal (Abb. 7.14).
Abb. 7.14 Laufzeit
Die onactionvn_pflicht-Eventhandler-Methode ist in Listing 7.10 abgebildet.
METHOD onactionvn_pflicht . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-vorname = cl_wd_input_field=>e_state-normal. ls_data-nachname = cl_wd_input_field=>e_state-required.. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 7.10 Eventhandler-Methode, getriggert für die Menüoption mit MAI_VORNAME ID
Falls der Benutzer vorname als Pflichtfeld wählt, müssen wir die Eigenschaft state des zugehörigen UI-Elements auf required setzen und die Eigenschaft state des zu nachname korrespondierenden UI-Elements auf normal (Abb. 7.15).
Abb. 7.15 Laufzeit
110
7 View-Controller-Methoden
7.2 Supply-Funktion-Methoden Wir haben diese Art Methoden jedes Mal benutzt, wenn wir eine Supply- Funktion einem Context-Knoten zugewiesen haben, und jedes Mal hatten wir die ContextAttribute der Context-Knoten mit Initialwerten per Supply-Funktion gefüllt. Wenn ein Controller aufgerufen wird, werden diese Methoden zuerst ausgeführt. Wir haben gesehen, dass eine Supply-Funktion jedem Context-Knoten eines Controllers zugewiesen werden kann (Abb. 7.16).
Abb. 7.16 Context-Knoten und Supply-Funktion
Das Framework generiert eine korrespondierende Supply-Funktion-Methode (Abb. 7.17).
Abb. 7.17 Supply-Funktion
Eine Alternative zu den Supply-Funktion-Methoden kann die wdDoInit-HookMethode darstellen, wenn wir wissen, dass der Context nur einmal bei der Initialisierung gefüllt und hinterher auch nicht invalidiert wird.
7.3 Benutzerdefinierte Instanzmethoden Im Methoden-Tabreiter können wir unsere eigenen, benutzerdefinierten Methoden mit oder ohne Parameter definieren. Nach der Erstellung einer benutzerdefinierten Methode können wir diese im selben Controller aufrufen, indem wir die wd_thisSelbstreferenz benutzen.
7.3
Benutzerdefinierte Instanzmethoden
111
Für diesen Fall kopieren wir unser Beispiel der wdDoModifyView-Hook- Methode und erzeugen zwei zusätzliche benutzerdefinierte Methoden: • Eine Methode namens GREETING , die zwei Importparameter hat; • Eine Methode namens PERFORM_VALIDATION mit einem Importparameter. In der ONACTIONNEXT-Eventhandler-Methode prüfen wir, ob das Attribut NAME initial ist, entsprechend ob der Benutzer seinen Namen nicht eingegeben hat. Falls das Context-Attribut initial ist, rufen wir unsere selbstdefinierte PERFORM_VALIDATION-Methode auf. Unter Verwendung dieser Methode zeigen wir eine Fehlermeldung an. Sollte das Context-Attribut nicht leer sein, rufen wir unsere selbstdefinierte GREETING-Methode auf, um den Endbenutzer zu begrüßen. Abbildung 7.18 zeigt die benutzerdefinierte GREETING-Methode. Wie wir sehen, hat diese Methode einen Import-Parameter namens P_NAME vom Typ STRING and einen Importparameter namens P_NODE vom Bezugstyp if_wd_context_node definiert. Der P_NAME-Parameter hält den Wert des NAMEContext-Attributes.
Abb. 7.18 Benutzerdefinierte GREETING-Methode
Abbildung 7.19 zeigt die benutzerdefinierte PERFORM_VALIDATIONMethode. Diese Methode besitzt einen Import-Parameter namens P_ELEMENT, zurückzuführen auf das Interface IF_WD_CONTEXT_ELEMENT. In diesem Fall haben wir die Methode REPORT_ATTRIBUTE_ ERROR_MESSAGE des Interface IF_WD_MESSAGE_MANAGER benutzt, um eine Web-Dynpro-Fehlermeldung an ein Context-Attribut weiterzuleiten.
112
7 View-Controller-Methoden
Abb. 7.19 Benutzerdefinierte PERFORM_VALIDATION-Methode
Das Listing 7.11 zeigt die ONACTIONNEXT-Eventhandler-Methode.
METHOD onactionnext . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_person. DATA lv_name TYPE string. DATA lr_element TYPE REF TO if_wd_context_element. lr_node = wd_context->get_child_node( ’PERSON’ ). lr_element = lr_node->get_element( ). lr_node->get_attribute( EXPORTING name = ’NAME’ IMPORTING value = lv_name ). IF lv_name IS INITIAL. wd_this->perform_validation( EXPORTING p_element = lr_element ELSE. wd_this->greeting( EXPORTING p_name = lv_name p_node = lr_node ). ENDIF. ENDMETHOD.
).
Listing 7.11 Die onactionnext-Eventhandler-Methode
Wie wir sehen, enthält die lokale Variable lv_name den Wert des NAMEAttributs. Ist das Attribut leer, müssen wir eine Fehlermeldung anzeigen. Dafür benutzen wir unsere selbstdefinierte PERFORM_VALIDATION-Methode. wd_this->perform_validation(EXPORTING
p_element = lr_element ).
7.4
Fire-Methoden
113
Zur Laufzeit haben wir (Abb. 7.20):
Abb. 7.20 Laufzeit
7.4 Fire-Methoden Eine Fire-Methode ist eine spezielle Art Methode, die vom Framework generiert wird, wenn wir einen Outbound-Plug definieren. Wir benötigen Inbound- Plugs und Outbound-Plugs, um die Navigation zwischen zwei Views zu definieren. Diese Plugs sind der Eingangs- (entry) und der Ausgangspunkt (exit) für jede View. Wir erzeugen als Beispiel eine WD-Komponente, die zwei Views enthält. Die WD-Komponentenstruktur ist in Abb. 7.21 dargestellt. Abb. 7.21 WD-Komponentenstruktur
In diesem Fall möchten wir von der View V_VIEW1 zur View V_VIEW2 navigieren, wenn das Framework eine Eventhandler-Methode triggert, entsprechend wenn der Benutzer einen Button drückt. Im COMPONENTCONTROLLER legen wir einen Context-Knoten PERSON an, Kardinalität 1. . .1, Singleton, und ein Attribut NAME vom Typ string (Abb. 7.22).
114
7 View-Controller-Methoden
Abb. 7.22 Context-Struktur
Die Daten, die im Context des Komponenten-Controller gespeichert sind, werden innerhalb der zwei Views V_VIEW1 und V_VIEW2 über Context-Mapping verwendet. Das Layout für den View V_VIEW1 ist in Abb. 7.23 dargestellt.
Abb. 7.23 Layout für View V_VIEW1
Das Layout für die View V_VIEW2 ist in Abb. 7.24 dargestellt.
Abb. 7.24 Layout für View V_VIEW2
Wenn der Benutzer den Weiter-Button drückt, möchten wir von der View V_VIEW1 zur View V_VIEW2 navigieren. Die View V_VIEW1 wird durch die View V_VIEW2 ersetzt. Diese Navigation wird durch einen Navigationslink zwischen den Views im Window ermöglicht (Abb. 7.25). Um die Navigation zwischen unseren Views aufzusetzen, müssen wir einen Inbound-Plug für die View V_VIEW2 und einen Outbound-Plug für V_VIEW1 erstellen. Im Outbound-Plugs-Tabreiter des View V_VIEW1 erzeugen wir einen Outbound- Plug namens OP_TO_V_VIEW2 (Abb. 7.26).
7.4
Fire-Methoden
115
Window: W_DEFAULT
Outbound Plug
Navigation Link
Inbound Plug
Abb. 7.25 Plugs und Navigation
Abb. 7.26 Outbound-Plug
Im Tabreiter Inbound-Plug der View V_VIEW2 erstellen wir einen Inbound-Plug namens IP_V_VIEW2 (Abb. 7.27).
Abb. 7.27 Inbound-Plug
Wenn der Benutzer den Weiter-Button drückt, triggert das Framework die Eventhandler-Methode onactionweiter. Jedes Mal, wenn wir einen Outbound-Plug für eine View anlegen, wird eine spezielle Methode zu deren Interface hinzugefügt. Diese Methode hat die Anweisung FIRE_NAME_OUTBOUND_PLUG>_PLG. Um diese Methode abzufeuern, bedienen wir uns des Web Dynpro Code Wizard oder wir selektieren einen Outbound Plug, wenn wir eine Aktion erzeugen (Abb. 7.28).
116
7 View-Controller-Methoden
Abb. 7.28 Erzeugen einer Aktion
Die Eventhandler-Methode enthält die folgende Anweisung: Alle Views innerhalb eines Windows lassen sich miteinander durch Navigationslinks verbinden. Für die Erstellung der Navigation betten wir die Views ins Window ein, anschließend ziehen wir den Outbound-Plug per drag & drop in den InboundPlug. Auch können wir die Navigation über einen Rechtsklick auf den Namen des Output-Plug (Abb. 7.29) erzeugen.
Abb. 7.29 Erzeugen eines Navigations-Links
Zur Laufzeit, wenn der Benutzer mit der View V_VIEW1 interagiert, löst dies eine Anforderung an den Server aus. Als Antwort wird die View V_VIEW1 durch die View V_VIEW2 ersetzt. Dies ist durch den Navigations-Link möglich, der zwischen den Views definiert ist.
7.5 Eventhandler-Methoden Eine Eventhandler-Methode (Ereignisbehandler) reagiert auf Aktionen oder Ereignisse. Wir haben diese Art Methoden jedes Mal verwendet, wenn wir eine Aktion an ein UI-Element angeheftet haben. Diese Art Methoden sind spezielle Methoden
7.5
Eventhandler-Methoden
117
eines View-Controllers, die das Präfix ONACTION gefolgt vom Aktions-Namen haben. Wie wir gesehen haben, ist die Aktion im Aktionen-Tabreiter definiert und die zugehörige Eventhandler-Methode vom Framework generiert (Abb. 7.30).
Abb. 7.30 Aktion und Eventhandler-Methode
Wir können eine Aktion einem UI-Element zuweisen, das ein Ereignis hat, unabhängig davon, ob dieses UI-Element dynamisch oder zur Entwurfszeit erzeugt wurde (Abb. 7.31).
.
.
Abb. 7.31 Aktion und UI-Element
Wir wollen nun ein Beispiel erstellen, in dem wir eine Eventhandler-Methode benutzen, die implementiert ist, um auf Ereignisse von Inbound-Plugs zu reagieren!
118
7 View-Controller-Methoden
Wir haben erkannt, dass die Outbound-Plugs den Startzeitpunkt der Navigation darstellen, und in irgendeiner Methode des View-Controllers durch die folgende Anweisung aufgerufen wird: wd_this->FIRE__PLG( ).
Diese Methode erlaubt auch Parametertransfer wd_this->FIRE__PLG( PARAMETER = ’value’).
In diesem Fall muss der PARAMETER in der Parametertabelle des ViewControllers eingetragen werden. Zum besseren Verständnis erstellen wir das gleiche Beispiel wie für die FireMethoden, aber diesmal zeigen wir eine Fehlermeldung an, wenn der Benutzer keinen Wert in das inputField UI-Element eingibt. Wir wollen eine Referenz an den Message Manager übergeben, von einer View zur anderen View, via Outbound Parameter. Für die View_1 fügen wir in der Parametertabelle, im Tabreiter „OutboundPlugs“, einen Parameter namens P_MM ein (Abb. 7.32).
Abb. 7.32 Definition des Parameters für einen Outbound-Plug
Wenn der Benutzer den Weiter Button klickt, triggert das Framework die Eventhandler-Methode onactionweiter (Listing.7.12). Die View V_VIEW2 hat den Inbound-Plug IP_V_VIEW2 (Abb. 7.33). Wir haben keine Möglichkeit, einen Parameter für einen Inbound-Plug zu erstellen. In diesem Fall benutzen wir die Eventhandler-Methode HANDLEIP_V_VIEW2, um den Wert des P_MM Parameters einzulesen. Wenn ein Inbound-Plug aufgerufen wird, wird die ihm eindeutig zugewiesene Handler-Methode aufgerufen. Diese Methode wird automatisch im View Controller generiert, wenn der Inbound-Plug erzeugt wird. Wir finden diese Methode im Methoden-Tabreiter der View V_VIEW2 (Abb. 7.34).
7.5
Eventhandler-Methoden
119
METHOD onactionweiter . DATA: lr_api_controller TYPE REF TO if_wd_controller, lr_api_manager TYPE REF TO if_wd_message_manager. lr_api_controller?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). wd_this->fire_op_to_v_view2_plg( p_mm = lr_message_manager ). ENDMETHOD.
Listing 7.12 Eventhandler-Methode
Abb. 7.33 Inbound-Plug
Abb. 7.34 Eventhandler-Methode (Ereignisbehandler)
Abb. 7.35 Eventhandler-Methode. Implementierung
120
7 View-Controller-Methoden
Der Wert des Parameters P_MM wird durch den Outbound-Plug OP_TO_ V_VIEW2 übergeben. Um den Wert des Parameters lesen zu können, fügen wir den Parameter P_MM der Signatur der mit dem Inbound-Plug verbundenen Eventhandler-Methode hinzu, das heißt der HANDLEIP_V_VIEW2-EventhandlerMethode (Abb. 7.35). Auf diese Weise ist der Wert des P_MM-Parameters der Eventhandler-Methode bekannt und kann benutzt werden, um eine Meldung zu versenden, falls der Benutzer keinen Wert ins InputField UI-Element einträgt. Tipp Diese Art Eventhandler-Methoden werden nicht für die Übergabe von Anwendungsdaten verwendet.
Kapitel 8
Layout-UI-Elemente
In matters of style, swim with the current. In matters of principle, stand like a rock. Thomas Jefferson
Zusammenfassung Der folgende Abschnitt gibt eine detaillierte Beschreibung des Layouts der UI-Elemente. Hier präsentieren wir die verschiedenen Typen existenter Layouts und die Art und Weise, wie sie entweder in statischer oder dynamischer Variante zu benutzen sind. Das Layout hilft uns, die UI-Elemente innerhalb ihres Parent Containers anzuordnen. Alle UI-Elemente innerhalb einer View sind hierarchisch geordnet. Der Knoten ROOTUIELEMENTCONTAINER ist die Wurzel der Hierarchie und alle UIElemente innerhalb einer View sind Kindern dieses Wurzelcontainers. Er ist vom Typ TransparenterContainer und zunächst dem FlowLayout zugeordnet. In unserem ersten Beispiel haben wir gesehen, dass wir die Möglichkeit haben, es von einem TransparentenContainer in ein anderes UI-Element zu ändern, sofern dieses keine Kinder hat. Tabelle 8.1 zeigt die zu Verfügung stehenden Layout-UI-Elemente, mit welchen die UI-Elemente in einer View dargestellt werden können, und die dazugehörenden LayoutDaten. Tabelle 8.1 Layout und LayoutDaten Layout-UI-Element
LayoutDaten-UI-Element
FlowLayout GridLayout RowLayout MatrixLayout
FlowData GridData RowData MatrixData
Das Layout ist die abstrakte Basisklasse aller Layout-UI-Elemente innerhalb des Web Dynpro und hat die Laufzeitklasse CL_WD_LAYOUT. U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_8,
121
122
8
Layout-UI-Elemente
Die Layout-Daten eines UI-Elements werden verwendet um die Position innerhalb eines Containers zu spezifizieren; sie haben die Laufzeitklasse CL_WD_LAYOUT_DATA.
8.1 FlowLayout Wenn wir das FlowLayout verwenden, werden alle UI-Elemente in einer Zeile dargestellt. Durch Verwendung der Eigenschaft WRAPPING des Containers, in welchen das UI-Element integriert werden soll, können wir die Art und Weise beeinflussen, in der diese UI-Elemente auf den Ausgabebildschirm gebracht werden. Wenn diese Eigenschaft auf ABAP_TRUE gesetzt ist, werden die UI-Elemente, die nicht in die erste Zeile passen, nach unten in eine andere Zeile gesetzt und automatisch an den Client-Bildschirm angepasst. Falls die Eigenschaft auf ABAP_FALSE gesetzt ist, werden die UI-Elemente nicht automatisch an den Client-Bildschirm angepasst. Zum besseren Verständnis erzeugen wir eine Registrierungsform mit drei Feldern: Vorname, Nachname und Geburtsdatum. Die WD-Komponentenstruktur und das View-Layout sind dargestellt in Abb. 8.1.
Abb. 8.1 WD-Komponentenstruktur und View-Layout
Im Context-View erzeugen wir den gleichen wohlbekannten Context-Knoten STUDENT mit der Dictionary Struktur YSTRU_PERSON. Der ROOTUIELEMENTCONTAINER und das UI-Element-Group sind beide vom Typ Container, welche das FlowLayout als Layout-Voreinstellung haben (Abb. 8.2).
8.1
FlowLayout
123
Abb. 8.2 Layout und LayoutDaten
Jedes UI-Element referenziert zu einem LayoutDaten-Objekt und jedes in einen Container eingefügte UI-Element muss das Daten-Layout haben, das zu dem entsprechenden Container passt. Zur Laufzeit haben wir (Abb. 8.3):
Abb. 8.3 Laufzeit – Wrapping ABAP_TRUE
124
8
Layout-UI-Elemente
Wie wir sehen können, sind die UI-Elemente in einer Linie angeordnet. Weil die Attribute des Context-Knotens STUDENT leer sind, werden die an diese Attribute gebundenen Eingabefelder nicht angezeigt. Nachdem der Anwender den „Anzeigen“ Button gedrückt hat, zeigen wir alle Daten, die der User in die UI-Element Eingabefelder eingegeben hat. In diesem Fall passen nicht mehr alle UI-Elemente in eine Zeile, weil der ClientBildschirm dafür zu klein ist. Die nicht mehr in die erste Zeile passenden Elemente werden in einer anderen Zeile dargestellt und automatisch an den Client-Bildschirm angepasst. Wir haben gesehen, dass wir für die LayoutDaten zwei Eigenschaften bestimmen können: cellDesign (beschreibt den Abstand zwischen den Reihen) und vGutter (gibt die zusätzliche Distanz zum linken Rand an). Die Voreinstellung für diese Werte ist: cellDesign – padless (es gibt keinen Abstand zwischen der Reihe und dem Rand); vGutter – none (keine zusätzliche Distanz). Falls die Wrapping-Eigenschaft auf ABAP_FALSE eingestellt ist, werden die UI-Elemente, die nicht in die erste Zeile passen, nicht in einer anderen Zeile dargestellt. Sie sind nicht mehr sichtbar (Abb. 8.4).
Abb. 8.4 Laufzeit – Wrapping ABAP_FALSE
Zur dynamischen Änderung können wir die Laufzeitklasse CL_WD_ FLOW_DATA nutzen um die UI-Elemente in einen Container einzubinden, der als Layout ein FlowLayout hat. Ein Beispiel zur Nutzung dieser Klasse haben wir in dem wdDoModifyView-Beispiel gesehen.
8.2 GridLayout Wenn wir das GridLayout nutzen, werden alle in einem Container enthaltenen UIElemente in einem tabellarischen Grid mit einer fixen Anzahl Spalten angeordnet. Wir können die Anzahl der Spalten in der Tabelle durch die Eigenschaft colCount bestimmen. Die Anzahl der Reihen hängt von der Anzahl der UI-Elemente in dem Container ab. Wir erstellen das gleiche Beispiel wie zuvor, jedoch verwenden wir diesmal als Layout das GridLayout für den Container Group (Abb. 8.5). Wir arrangieren alle UI-Elemente der UI-Element Group GRP in zwei Spalten. In diesem Fall haben wir zur Laufzeit (Abb. 8.6):
8.2
GridLayout
125
Abb. 8.5 UI-Element Group – GridLayout
Abb. 8.6 Laufzeit
Wie zu sehen ist, haben wir nun zwei Spalten und die Anzahl der Reihen beträgt fünf. Wir möchten aber, dass der Anzeigen-Button allein in seiner Zeile ist. Um das zu erreichen, müssen wir ein unsichtbares Element (InvisibleElement) verwenden (Abb. 8.7). Dieses UI-Element ist auf dem Bildschirm ein unsichtbares Element und kann genutzt verwendet werden, um eine leere Zelle in dem GridLayout zu füllen. Zur dynamischen Änderung können wir die Laufzeitklasse CL_WD_GRID_DATA verwenden, um die UI-Elemente in den GRP Container einzubinden, der als Layout ein GridLayout hat (Listing 8.1)
126
8
Layout-UI-Elemente
METHOD wddomodifyview. DATA lv_bind_attribute TYPE string. DATA lr_input_field TYPE REF TO cl_wd_input_field. DATA lr_container TYPE REF TO cl_wd_group. DATA lr_label TYPE REF TO cl_wd_label. DATA lr_grid_data TYPE REF TO cl_wd_grid_data. IF first_time EQ abap_true. lr_label = cl_wd_label=>new_label( id = ’LBL_VORNAME’ label_for = ’VORNAME’ ). lr_grid_data = cl_wd_grid_data=>new_grid_data( element = lr_label ). lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( index = 1 the_child = lr_label ). lv_bind_attribute = ’STUDENT.VORNAME’. lr_input_field = cl_wd_input_field=>new_input_field( id = ’VORNAME’ bind_value = lv_bind_attribute ). lr_grid_data = cl_wd_grid_data=>new_grid_data( element = lr_input_field ). lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( index = 2 the_child = lr_input_field ). ENDIF. ENDMETHOD.
Listing 8.1 Implementierung wdDoModifyView-Hook-Methode
In diesem Beispiel erstellen wir dynamisch die ersten zwei UI-Elemente: Eingabefeld Vorname für den Anwender (InputField UI-Element) und das dazugehörende Label. Um dieses UI-Element in den Container GRP (GridLayout) einzubinden, nutzen wir das dazugehörende Layout GridData.
8.3 MatrixLayout Wenn wir das MatrixLayout verwenden, werden alle UI-Elemente eines Containers in Spalten angeordnet. Mit dem MatrixLayout können wir einen Grid mit einer variablen Anzahl von Spalten für jede Reihe erstellen. Jedes UI-Element aus einem Container mit MatrixLayout enthält entweder ein MatrixData-Objekt oder ein MatrixHeadData-Objekt (Abb. 8.8). Ein UI-Element, das als Daten-Layout ein MatrixHeadData-Objekt hat, beginnt eine neue Zeile und das UI-Element, das als Daten-Layout das MatrixData-Objekt hat, wird solange in der gleichen Zeile dargestellt, bis ein anderes UI-Element als MatrixHeadData-Objekt gesetzt wird. Dadurch wird eine neue Zeile erstellt (Abb. 8.9).
8.3
MatrixLayout
Abb. 8.7 InvisibleElement und GridLayout
Abb. 8.8 Layout und LayoutDaten
Abb. 8.9 UI-Elemente in einem Container, dargestellt durch MatrixLayout
127
128
8
Layout-UI-Elemente
Zur dynamischen Änderung können wir die Laufzeitklassen CL_WD_MATRIX_HEAD_DATA und CL_WD_MATRIX_DATA nutzen um UI-Elemente in den Container GRP einzubinden, der als Layout das MatrixLayout hat (Listing 8.2)
METHOD wddomodifyview. DATA lv_bind_attribute TYPE string. DATA lr_input_field TYPE REF TO cl_wd_input_field. DATA lr_container TYPE REF TO cl_wd_group. DATA lr_label TYPE REF TO cl_wd_label. DATA lr_matrix_head_data TYPE REF TO cl_wd_matrix_head_data. DATA lr_matrix_data TYPE REF TO cl_wd_matrix_data. IF first_time EQ abap_true. lr_label = cl_wd_label=>new_label( id = ’LBL_VORNAME’ label_for = ’VORNAME’ ). lr_matrix_head_data = cl_wd_matrix_head_data=>new_matrix_ head_data( element = lr_label ). lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( index = 1 the_child = lr_label ). lv_bind_attribute = ’STUDENT.VORNAME’. lr_input_field = cl_wd_input_field=>new_input_field( id = ’VORNAME’ bind_value = lv_bind_attribute ). lr_matrix_data = cl_wd_matrix_data=>new_matrix_ data( element = lr_input_field ). lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( index = 2 the_child = lr_input_field ). ENDIF. ENDMETHOD.
Listing 8.2 Implementierung wdDoModifyView-Hook Methode
8.4 RowLayout Wenn wir das Layout RowLayout verwenden, werden alle UI-Elemente eines Containers in horizontalen Zeilen dargestellt. Jedes UI-Element, das in einen Container eingefügt ist und das Layout RowLayout besitzt, enthält entweder ein RowData-Objekt oder ein RowHeadData-Objekt (Abb. 8.10). Diese Layoutart ist hilfreich, wenn wir unsere UI-Elemente in horizontalen Zeilen darstellen wollen, aber keine vertikale Anordnung zwischen den daraus entstehenden Spalten benötigen – siehe Abb. 8.11.
8.4
RowLayout
129
Abb. 8.10 Layout und LayoutDaten
Abb. 8.11 UI-Elemente in einem Container – dargestellt durch das Layout RowLayout
Zur dynamischen Änderung können wir die Laufzeitklassen CL_WD_ ROW_HEAD_DATA und CL_WD_ROW_DATA verwenden, um die UI-Elemente in den Container GRP einzubinden, der das Layout RowLayout hat (Listing 8.3)
130
8
Layout-UI-Elemente
METHOD wddomodifyview. DATA lv_bind_attribute TYPE string. DATA lr_input_field TYPE REF TO cl_wd_input_field. DATA lr_container TYPE REF TO cl_wd_group. DATA lr_label TYPE REF TO cl_wd_label. DATA lr_row_head_data TYPE REF TO cl_wd_row_head_data. DATA lr_row_data TYPE REF TO cl_wd_row_data. IF first_time EQ abap_true. lr_label = cl_wd_label=>new_label( id = ’LBL_VORNAME’ label_for = ’VORNAME’ ). lr_row_head_data = cl_wd_row_head_data=>new_row_head_data( element = lr_label ). lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( index = 1 the_child = lr_label ). lv_bind_attribute = ’STUDENT.VORNAME’. lr_input_field = cl_wd_input_field=>new_input_field( id = ’VORNAME’ bind_value = lv_bind_attribute ). lr_row_data = cl_wd_row_data=>new_row_data( element = lr_input_field ). lr_container ?= view->get_element( ’GRP’ ). lr_container->add_child( index = 2 the_child = lr_input_field ). ENDIF. ENDMETHOD.
Listing 8.3 Implementierung wdDoModifyView-Hook Methode
Kapitel 9
User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
A goal is a dream with a deadline. Napoleon Hill
Zusammenfassung Die UI-Elemente, die wir in Web Dynpro ABAP benutzen können, sind in verschiedene Kategorien aufgeteilt. In diesem Kapitel präsentieren wir einige der UI-Elemente aus den Kategorien: action, selection, layout, complex, graphic und integration. Jedes UI-Element wird durch ein Beispiel illustriert, das die Art und Weise zeigt, es entweder in statischer oder dynamischer Variante zu benutzen. Ein UI-Element ist ein User-Interface-Element, das wir nutzen, um für den Anwender eine Bildschirmausgabe zu erstellen. Die UI-Elemente sind in Gruppen kategorisiert, auf die wir über das View-Layout zugreifen können. Jedes UI-Element hat folgende Eigenschaften: • gemeinsame mit anderen UI-Elementen, geerbt von Superklassen; • spezielle, nur für ein UI-Element. Nachstehende Eigenschaften sind z.B. geerbt: • Tooltip – zeigt einen Kurzinformationstext, wenn der Anwender mit dem Mauszeiger über ein UI-Element fährt; • Visible – legt fest, ob ein UI-Element auf dem Bildschirm angezeigt wird oder nicht; • Enabled – beschreibt, ob ein UI-Element aktiv oder inaktiv ist. Durch Verwendung des ClassBuilder Transaktion SE24 können wir die verschiedenen Klassen sowie ihre Vererbungen und Attribute sehen. Die Klasse CL_WD_ELEMENT zum Beispiel ist die Superklasse für alle UI-Elemente, die wir im ABAP Web Dynpro verwenden. Als Superklasse hat diese Klasse CL_WD_VIEW_ELEMENT.
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_9,
131
132
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.1 zeigt die Eigenschaften Tooltip, visible und enable für ein InputField UI-Element.
Abb. 9.1 UI-Elementeigenschaften
Die meisten der UI-Elementeigenschaften können an verschiedene ContextKnoten oder Context-Attribute gebunden werden. Auf diese Weise können wir das UI-Element mittels der im Context gehaltenen Daten ändern. Jede anbindbare Eigenschaft eines UI-Elements hat einen bestimmten Typ. Die enabled-Eigenschaft kann zum Beispiel an ein Attribut vom Typ WDY_BOOLEAN gebunden werden. Wird dieses Attribut auf ABAP_TRUE gesetzt, ist das dazugehörende UI-Element aktiv. Wird dieses Attribut auf ABAP_FALSE gesetzt, ist das dazugehörende UI-Element inaktiv. Die UI-Elemente zusammen mit ihrer Aggregation bestimmen die Darstellung und das Verhalten der UI-Elemente auf dem Bildschirm. Die Web-Dynpro-UIElemente sind in Kategorien eingeteilt. Nachstehend stellen wir einige dieser Kategorien vor.
9.1 Action Die UI-Elemente, die eine Aktion beinhalten, sind in dieser Kategorie enthalten. Einige dieser UI-Elemente haben wir bereits verwendet (Button, LinkToAction).
9.1.1 TimedTrigger Dieses UI-Element stößt automatisch und periodisch ein Ereignis an. Um die Periodeneigenschaften festzulegen, müssen wir seine delay-Eigenschaft nutzen. Wie bereits vorstehend erwähnt, können die meisten UI-Elementeigenschaften gebunden werden. Nachstehend zeigen wir eine Tabelle mit einigen dieser TimedTrigger Eigenschaften, die gebunden werden können, und den dazugehörigen Attributtyp, falls die Eigenschaft bindungsfähig ist (Tabelle 9.1).
9.1
Action
133 Tabelle 9.1 Einige der TimedTrigger-UI-Elementeigenschaften Name
Typ
Initialwert
Bindungsfähig
Delay Enabled Visible Tooltip
I WDY_BOOLEAN WDUI_VISIBILITY Text
0 true visible
yes yes yes yes
Wir erzeugen eine WD-Komponente mit der Struktur wie in Abb. 9.2. dargestellt. Abb. 9.2 WD-Komponentenstruktur
Alle 5 Sekunden stoßen wir ein Event an, das einen Funktionsbaustein verwendet, um eine Zufallszahl kleiner 1000 zu erzeugen. Im Context-View erzeugen wir einen Knoten namens COUNTER, Kardinalität 1. . .1, Singleton, welcher das Context-Attribut COUNTER_TT vom Typ i hat. Das View-Layout ist in Abb. 9.3 dargestellt.
Abb. 9.3 View-Layout
Wir haben eine Aktion namens TRIGGER verwendet, um die Aktion festzulegen, die nach der angegebenen Verzögerung – delay 5 – angestoßen wird (Listing 9.1).
134
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD onactiontrigger. DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this>element_counter. DATA lv_step TYPE i. lr_node = wd_context->get_child_node( ’COUNTER’ ). CALL FUNCTION ’GENERAL_GET_RANDOM_INT’ EXPORTING range = 1000 IMPORTING random = lv_step. ls_data-counter_tt = lv_step. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 9.1 TimedTrigger Aktion
Der Funktionsbaustein GENERAL_GET_RANDOM_INT hat einen ImportParameter namens RANGE vom Typ i und einen Exportparameter namens RANDOM vom Typ i. Dieser Funktionsbaustein gibt einen Zufallswert 0 E_VISIBLE-VISIBLE
DATA lr_timed_trigger TYPE REF TO cl_wd_timed_trigger. lr_timed_trigger = cl_wd_timed_trigger=>new_timed_trigger( id = ’TIMED_TRIGGER’ delay = 5 on_action = ’TRIGGER’). Listing 9.2 Dynamische Erzeugung eines TimedTrigger UI-Elements
9.1.2 ButtonChoice – Druckknopfauswahl Wir können dieses UI-Element nutzen, um unter den verschiedenen Optionen zu wählen, welche das Menü bietet. Nachfolgend zeigen wir eine Tabelle mit einigen ButtonChoice Eigenschaften, die gebunden werden können, und den Attribut-Typ, falls die Eigenschaft bindungsfähig ist (Tabelle 9.3). Tabelle 9.3 Einige der ButtonChoice-UI-Elementeigenschaften Name
Typ
Initialwert
Bindungsfähig
repeatSelectedAction selectedActionItem imageSource
WDY_BOOLEAN STRING STRING
true -
yes yes yes
Wir erzeugen eine WD-Applikation, in welcher wir das ButtonChoice-UIElement verwenden um dem Anwender eine Menüauswahl mit zwei Optionen zu bieten: potenzieren (Power) und dividieren (Divide). Um diese Rechnungen auszuführen müssen wir die Methoden der Klasse CL_FOEV_BUILTINS verwenden. Wie in Abb. 9.5 ersichtlich hat diese Klasse viele Rechenmethoden, angefangen mit der PLUS-Methode (welche eine einfache Addition ausführt) bis zu Funktionen zur Ermittlung des ganzzahligen Teils oder des Hyperbelsinus. Die Struktur der POWER-Methode der Klasse CL_FOEV_BUILTINS ist dargestellt in Abb. 9.6.
136
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.5 Klasse CL_FOEV_BUILTINS
Abb. 9.6 Struktur der power-Methode der Klasse CL_FOEV_BUILTINS
Diese Methode hat zwei Import-Parameter mit Namen IM_ARG1 und IM_ARG2 und einen Exportparameter namens EX_RESULT vom Typ floating. Die Methode divide hat die gleichen Parameter. Für unsere Aufgabe erzeugen wir einen Context-Knoten mit Namen CALCULATE mit den Context-Attributen ARG1, ARG2 und RESULT, alle vom Typ f.
9.1
Action
137
Diese werden benötigt um die Rechenoperation auszuführen und das Ergebnis festzuhalten. Die WD-Komponentenstruktur und die View-Contextstruktur sind in Abb. 9.7 dargestellt.
Abb. 9.7 WD-Komponentenstruktur und View-Contextstruktur
Das View-Layout ist in Abb. 9.8 dargestellt.
Abb. 9.8 View-Layout
In dem ButtonChoice-UI-Element fügen wir zwei Optionen ein: menuactionitem1 und menuactionitem2. Für diese beiden erzeugten Optionen setzen wir die Aktionen (Potenzieren und Dividieren) und wir nutzen die Hotkey-Eigenschaft, um dem Anwender die Möglichkeit zu bieten, die entsprechende Tastenkombination zu drücken um die dazugehörende Eventhandler-Methode auszuführen. Wenn der Anwender das erste Mal mit dem UI-Element ButtonChoice interagiert, kann eine Aktion ausgewählt werden und das Framework löst die passende Eventhandler-Methode aus. Die zuletzt gewählte Aktion verbleibt am UI-Element
138
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Die zuletzt gewählte Aktion verbleibt am UIElement ButtonChoice, nachdem die Aktion ausgeführt wurde. Abb. 9.9 Einige der ButtonChoice-UI-Elementeigenschaften
ButtonChoice, nachdem die Aktion ausgeführt wurde. Dieses Verhalten wird durch die Eigenschaft repeatSelectedAction ermöglicht (Abb. 9.9). Das Framework triggert die Eventhandler-Methode onactiondividieren, wenn der Anwender die entsprechende ButtonChoice-Option oder die Tastenkombination CTRL_D drückt. Listing 9.3 zeigt das Coding dieser Methode.
METHOD onactiondividieren . DATA lr_oref TYPE REF TO cx_foev_error_in_function. DATA ls_calculate TYPE wd_this->element_calculate. DATA lv_arg1 LIKE ls_calculate-arg1. DATA lv_arg2 LIKE ls_calculate-arg2. DATA lv_result LIKE ls_calculate-result. wd_this->attribute_get( IMPORTING p_arg1 = lv_arg1 p_arg2 = lv_arg2 ). TRY. cl_foev_builtins=>divide( EXPORTING im_arg1 = lv_arg1 im_arg2 = lv_arg2 IMPORTING ex_result = lv_result ). CATCH cx_foev_error_in_function INTO lr_oref. ENDTRY. wd_this->attribute_set( EXPORTING p_result = lv_result ). ENDMETHOD.
Listing 9.3 Die onactiondividieren-Eventhandler-Methode
Um die Context-Attribute ATR1 und ATR2 zu lesen, verwenden wir die benutzerdefinierte Methode namens ATTRIBUTE_GET, welche zwei Export- Parameter hat (Abb. 9.10). Um das Ergebnis der Divisionsrechnung an das Context-Attribut RESULT zu übergeben, müssen wir die benutzerdefinierte Methode ATTRIBUTE_SET anwenden, die einen Importparameter besitzt (Abb. 9.11). Die Laufzeitstruktur ist in Abb. 9.12 dargestellt.
9.1
Action
139
Abb. 9.10 Die benutzerdefinierte Methode, die erforderlich ist, um die Context-Attribute zu lesen
Abb. 9.11 Die benutzerdefinierte Methode ist erforderlich um das Ergebnis an das ContextAttribut RESULT zu übergeben
Abb. 9.12 Laufzeit für die Dividieren-Operation
140
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Um eine Zahl zu potenzieren triggert das Framework die Eventhandler-Methode onactionpotenzieren (Listing 9.4). METHOD onactionpotenzieren . . . .. . .. . .. . ... TRY. cl_foev_builtins=>power( EXPORTING im_arg1 = lv_arg1 im_arg2 = lv_arg2 IMPORTING ex_result = lv_result ). CATCH cx_foev_error_in_function INTO lr_oref. ENDTRY. . . .. . .. . .. . .. . .. ENDMETHOD.
Listing 9.4 Die onactionpotenzieren Eventhandler-Methode
Wir haben die statische Methode POWER der Kalkulationsklasse CL_FOEV_BUILTINS verwendet, um die Berechnung nummer1 potenziert mit nummer2 auszuführen. Um die Context-Attribute ATR1 und ATR2 zu lesen, rufen wir die gleiche benutzerdefinierte Methode ATRRIBUTE_GET auf. Um das Rechenergebnis zu übergeben, rufen wir die Methode ATTRI BUTE_SET. In diesem Beispiel haben wir Fehler abgefangen, die auftreten können. Aber wir haben diese Meldungen nicht an den Anwender weitergegeben. Die Art und Weise wie wir TRY . . . ENDTRY, RAISE, CATCH verwenden und die Ausnahmen anzeigen können, wird detailliert in Kap. 10 beschrieben. 9.1.2.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_BUTTON_CHOICE Nachstehend zeigen wir eine Tabelle, welche die Beziehungen zwischen den View-Designer-Namen und den Laufzeitnamen mit den passenden Typen im Falle der dynamischen Programmierung eines UI-Elements ButtonChoice darstellt (Tabelle 9.4). Tabelle 9.4 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
repeatSelectedAction imageSource selectedactionItem
REPEAT_SELECTED_ACTION IMAGE_SOURCE SELECTED_ACTION_ITEM
WDY_BOOLEAN STRING STRING
Die Implementierung eines dynamischen UI-Element-ButtonChoice mit einem Menü action item names DIVIDIEREN enthält folgende Statements (Listing 9.5).
9.2
Selection
141
METHOD wddomodifyview . DATA lr_button_choice TYPE REF TO cl_wd_button_choice. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_menu_action TYPE REF TO cl_wd_menu_action_item. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_button_choice = cl_wd_button_choice=>new_button_choice( id = ’BTN_CHOICE’ text = ’Wählen’ repeat_selected_action = abap_false ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_button_choice ). lr_container->add_child( lr_button_choice ). lr_menu_action = cl_wd_menu_action_item=>new_menu_action_item( id = ’MENUACTIONITEM1’ text = ’Dividieren’ on_action = ’DIVIDIEREN’ hotkey = cl_wd_menu_action_item=>e_hotkey-ctrl_d ). lr_button_choice->add_choice( the_choice = lr_menu_action ). ENDIF. ENDMETHOD.
Listing 9.5 Dynamische Erstellung eines ButtonChoice-UI-Elements
9.2 Selection Diese Kategorie enthält UI-Elemente mit Selektionsoptionen. Nachfolgend stellen wir einige UI-Elemente vor, die zu dieser Kategorie gehören.
9.2.1 DropDownByKey Dieses UI-Element versorgt den Anwender mit einer Dropdown-Liste, aus welcher er nur einen Eintrag wählen kann. Wir erstellen eine WD-Komponente namens Y_UI_DROPDOWNBYKEY mit einem View namens V_VIEW und einem Window. Es gibt viele Möglichkeiten die Dropdown-Liste mit Werten zu versorgen. Man könnte zum Beispiel eine Domäne verwenden, die im ABAP Dictionary definiert ist. Oder wir können die wdDoInit-Hook-Methode oder eine Supply-Funktion Methode benutzen. Für unser Beispiel nutzen wir die Domäne Y_LAND_DOMAENE, die die Namen aller EU-Mitgliedstaaten enthält. Das View-Layout ist in Abb. 9.13 dargestellt.
142
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.13 View-Layout
Wie bereits erwähnt, können die meisten der UI-Element-Eigenschaften gebunden werden. Nachstehend zeigen wir eine Tabelle mit einigen der DropDownByKey-Eigenschaften, die gebunden werden können, und den AttributTyp, falls die Eigenschaft bindungsfähig ist (Tabelle 9.5). Tabelle 9.5 Eigenschaften von einigen der DropDownByKey-UI-Elementen Name
Typ
Initialwert
Bindungsfähig
readOnly selectedKey textDirection state
WDY_BOOLEAN STRING WDUI_TEXT_DIRECTION WDUI_STATE
false inherit normal
yes mandatory yes yes
Die Eigenschaft selectedKey ist eine Pflichtbindung, d.h. wir müssen die Datenbindung für dieses Context-Attribut vornehmen. Die Context-Struktur ist in Abb 9.14 dargestellt. Abb. 9.14 Context-Struktur
Wir haben einen Context-Knoten mit der Kardinalität 1. . .1, Singleton mit zwei Attributen. Das KEY-Attribut ist vom Typ Y_DEFUERDOMAENE, definiert im ABAP Dictionary, und das RESULT-Attribut vom Typ string. Wir definieren die Datenbindung zwischen dem KEY-Attribut und der selectedKey-Eigenschaft von DropDownByKey (Abb. 9.15).
Abb. 9.15 Datenbindung
9.2
Selection
143
Wenn die gewählte Eigenschaft des DropDownByKey-UI-Elements an dieses Attribut gebunden ist, wird der Wert, der in dem Context-Attribut KEY gehalten wird, in der Auswahlliste angezeigt. Wir verwenden das Attribut ERGEBNIS um in dem textView-UI-Element die Hauptstadt der ersten beiden EU Staaten aus der Dropdown Liste anzuzeigen. Nachdem der Anwender einen Wert ausgewählt hat, stößt das Framework die Eventhandler-Methode onactioneustaat_waehlen (Listing 9.6) an. METHOD onactioneustaat_waehlen . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dropdownbykey. DATA lv_ergebnis TYPE string. lr_node = wd_context->get_child_node( ’DROPDOWNBYKEY’ ). lr_node->get_attribute( EXPORTING name = ’KEY’ IMPORTING value = lv_ergebnis ). CASE lv_ergebnis. WHEN ’AT’. ls_data-ergebnis = ’Wien’. WHEN ’BE’. ls_data-ergebnis = ’Brüssel’ WHEN OTHERS. ls_data-ergebnis = ’Unbekannt’. ENDCASE. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 9.6 Eventhandler-Methode
Zur Laufzeit haben wir (Abb. 9.16):
Abb. 9.16 Laufzeit
144
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
9.2.1.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_DROPDOWN_BY_KEY Nachstehend zeigen wir eine Tabelle, welche die Beziehung zwischen dem ViewDesigner-Namen und dem Laufzeitnamen mit den dazugehörenden Typen im Falle der dynamischen Programmierung eines DropDownByKey-UI-Elements darstellt (Tabelle 9.6). Tabelle 9.6 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
selectedKey textDirection
SELECTED_KEY TEXT_DIRECTION
String WDUI_TEXT_DIRECTION
Inherit: CL_WD_DROPDOWN_BY_KEY=>E_TEXT_DIRECTION-INHERIT Ltr: CL_WD_DROPDOWN_BY_KEY=>E_TEXT_DIRECTION-LTR Rtl: CL_WD_DROPDOWN_BY_KEY=>E_TEXT_DIRECTION-RTL state STATE WDUI_STATE Normal: CL_WD_DROPDOWN_BY_KEY=>E_STATE-NORMAL Required CL_WD_DROPDOWN_BY_KEY=>E_STATE-REQUIRED
Die Implementierung eines dynamischen DropDownByKey-UI-Elements enthält folgende Statements (Listing 9.7).
DATA lr_dropdown_by_key TYPE REF TO cl_wd_dropdown_by_key. DATA lv_bind_attribute TYPE string. lv_bind_attribute = ’DROPDOWNBYKEY.KEY’. lr_dropdown_by_key = cl_wd_dropdown_by_key=>new_dropdown_by_key ( id = ’DDK’ bind_selected_key = lv_bind_attribute text_direction = cl_wd_dropdown_by_key=>e_text_ direction-ltr on_select = ’EUSTAAT_WAEHLEN’ ).
Listing 9.7 Dynamische Erzeugung eines DropDownByKey-UI-Elements
9.2.2 DropDownByIndex Dieses UI-Element versorgt den Anwender mit einer Dropdown-Liste, aus welcher er nur einen Eintrag auswählen kann. Dieses UI-Element unterscheidet sich nicht von dem DropDownByKey, wenn es auf dem Bildschirm angezeigt wird. Nur die Implementierung ist ein wenig anders. Wir erzeugen die gleiche WD-Komponente. Nur verwenden wir diesmal ein dropDownByIndex anstelle eines dropDownByKey-UI-Elements.
9.2
Selection
145
In Abb. 9.17 zeigen wir die Context-Struktur. In diesem Fall verwenden wir einen Context-Knoten mit der Dictionary-Struktur SHSVALSTR2, Kardinalität 0. . .n, Singleton. Abb. 9.17 Context-Struktur
Das View-Layout ist dargestellt in Abb. 9.18.
Abb. 9.18 View-Layout
Nachstehend zeigen wir eine Tabelle mit einigen der DropDownByIndexEigenschaften, die gebunden werden können, und den Attribut-Typen, falls die Eigenschaft bindungsfähig ist (Tabelle 9.7). Tabelle 9.7 Einige Eigenschaften der DropDownByIndex-UI-Elemente Name
Typ
Initialwert
Bindungsfähig
readOnly texts state textDirection
WDY_BOOLEAN Translatable text WDUI_STATE WDUI_TEXT_DIRECTION
false normal inherit
yes mandatory yes yes
Wie wir sehen, hat die texts-Eigenschaft eine Bindungspflicht. Wenn diese Eigenschaft des dropDownByIndex-UI-Elements an das VALUE Context-Attribut gebunden ist, wird der in diesem Attribut gehaltene Wert in der Auswahlliste angezeigt. Listing 9.8 zeigt, wie wir die Dropdown Liste mit Werten über die SupplyFunktions-Methode versorgen können.
146
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD supply_dropdownbyindex . DATA: ls_country TYPE if_v_view=>element_dropdownbyindex, lt_country LIKE TABLE OF ls_country. ls_country-value = ’ Österreich’. ls_country-key = ’Wien’. APPEND ls_country TO lt_country. ls_country-value = ’Belgien’. ls_country-key = ’Brüssel’. APPEND ls_country TO lt_country. node->bind_table( new_items = lt_country set_initial_elements = abap_true ). ENDMETHOD.
Listing 9.8 Supply-Funktions-Methode
Zur Laufzeit haben wir (Abb. 9.19):
Abb. 9.19 Laufzeit
9.2.2.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_DROPDOWN_BY_IDX Nachstehend zeigen wir eine Tabelle, welche die Beziehung zwischen dem ViewDesigner-Namen und dem Laufzeitnamen mit den dazugehörenden Typen im Falle der dynamischen Programmierung eines DropDownByIndex-UI-Elements darstellt (Tabelle 9.8). Tabelle 9.8 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
texts TEXTS WDY_MD_TRANSLATABLE_TEXT textDirection TEXT_DIRECTION WDUI_TEXT_DIRECTION Inherit: CL_WD_DROPDOWN_BY_IDX=>E_TEXT_DIRECTION-INHERIT Ltr: CL_WD_DROPDOWN_BY_IDX=>E_TEXT_DIRECTION-LTR Rtl: CL_WD_DROPDOWN_BY_IDX=>E_TEXT_DIRECTION-RTL state STATE WDUI_STATE Normal: CL_WD_DROPDOWN_BY_IDX=>E_STATE-NORMAL Required CL_WD_DROPDOWN_BY_IDX=>E_STATE-REQUIRED
9.2
Selection
147
Die Implementierung eines dynamischen DropDownByIndex-UI-Elements enthält folgende Statements (Listing 9.9):
DATA lr_dropdown_by_index TYPE REF TO cl_wd_dropdown_by_idx. DATA lv_bind_attribute TYPE string. lv_bind_attribute = ’DROPDOWNBYINDEX.VALUE’. lr_dropdown_by_index = cl_wd_dropdown_by_idx=>new_dropdown_by_idx( id = ’DDI’ bind_texts = lv_bind_attribute text_direction = cl_wd_dropdown_by_idx=>e_text_ direction-ltr on_select = ’ANZEIGEN’).
Listing 9.9 Dynamisches Erzeugen eines DropDownByIndex-UI-Elements
9.2.3 RadioButtonGroupByIndex Dieses UI-Element schließt einige RadioButtons ein, die es dem Anwender erlauben, einen Wert auszuwählen. Ähnlich wie bei den DropDown-Listen haben wir hier RadioButtons gruppiert nach dem Schlüssel und dem Index. Unabhängig vom Typ unterscheiden sie sich in der Anzeige auf dem Bildschirm nicht, sondern nur im Implementationsteil. Wir erstellen die gleiche WD-Komponente, wie für das DropDownByIndex-UIElement, nur dass wir das DropDownByIndex-UI-Element durch das RadioButtonGroupByIndex ersetzen. Der Context-View hat die gleiche Struktur. Wir erzeugen einen Context-Knoten namens RADIOBUTTONGROUP_I mit der DictionaryStruktur SHSVALSTR2, Kardinalität 0. . .n, Singleton. Nachstehend zeigen wir eine Tabelle mit einigen der RadioButtonGroupByIndex Eigenschaften, die gebunden werden können, und den Attribut-Typ, falls die Eigenschaft bindungsfähig ist (Tabelle 9.9). Tabelle 9.9 Einige Eigenschaften des UI-Element RadioButtonGroupByIndex Name
Typ
Initialwert
Bindungsfähig
readOnly texts colCount state
WDY_BOOLEAN Translatable text I WDUI_STATE
false 1 normal
yes mandatory yes yes
Der View-Layout ist dargestellt in Abb. 9.20. Wir definieren die gleiche Datenbindung zwischen dem VALUE-Attribut und der texts-Eigenschaft des RadiobuttonGroupByIndex. Wenn die Eigenschaft des
148
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.20 View-Layout
RadiobuttonGroupByIndex-UI-Elements an das VALUE-Attribut gebunden ist, werden die dort gehaltenen Werte dieses Attributes in Spalten und Reihen angezeigt. Um die Anzahl der Spalten festzulegen, in welche die RadioButtonGroupElemente gruppiert werden, nutzen wir die Eigenschaft colCount. In unserem Fall haben wir den Wert auf „2“ gesetzt. Diese Eigenschaft kann durch den Administrator personalisiert werden. Listing 9.10 zeigt, wie wir die RadioButtons mittels der Supply-FunktionMethode mit Werten versorgen (die gleiche Methode wie für die DropDownByIndex Listen).
METHOD supply_radiobutton_i . DATA: ls_country TYPE if_v_view=>element_radiobuttongroup_i, lt_country LIKE TABLE OF ls_country. ls_country-value = ’ Österreich’. ls_country-key = ’Wien’. APPEND ls_country TO lt_country. ls_country-value = ’Belgien’. ls_country-key = ’Brüssel’. APPEND ls_country TO lt_country. ls_country-value = ’Bulgarien’. ls_country-key = ’Sofia’. APPEND ls_country TO lt_country. node->bind_table( new_items = lt_country set_initial_elements = abap_true ). ENDMETHOD.
Listing 9.10 Supply-Funktion-Methode
Zur Laufzeit haben wir (Abb. 9.21): Für das RadioButtonGroupByKey-UI-Element haben wir das gleiche Konzept, wie für das DropDownByKey bereits beschrieben wurde.
9.3
Layout
149
Abb. 9.21 Laufzeit
9.2.3.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_RADIOBUTTON_GROUP_BY_IDX Nachstehend zeigen wir eine Tabelle, welche die Beziehung zwischen dem ViewDesigner-Namen und dem Laufzeitnamen mit den dazugehörenden Typen im Falle der dynamischen Programmierung eines RadioButtonGroupByIndex UI-Elements darstellt (Tabelle 9.10). Tabelle 9.10 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
colCount COL_COUNT I TEXTS WDY_MD_TRANSLATABLE_TEXT texts state STATE WDUI_STATE Normal: CL_WD_RADIOBUTTON_GROUP_BY_IDX=>E_STATE-NORMAL Required CL_WD_RADIOBUTTON_GROUP_BY_IDX=>E_STATE-REQUIRED
Die Implementierung eines dynamischen RadioButtonGroupByIndex-UIElements enthält folgende Anweisungen (Listing 9.11): DATA lr_radiobutton_group_by_index TYPE REF TO cl_wd_radiobutton_group_by_idx. DATA lv_bind_attribute TYPE string. lv_bind_attribute = ’RADIOBUTTONGROUP_I.VALUE’. lr_radiobutton_group_by_index= cl_wd_radiobutton_group_by_idx=>new_radiobutton_group_by_idx( id = ’RDB_INDEX’ bind_texts = lv_bind_attribute col_count = 2 on_select = ’ANZEIGEN’ ). Listing 9.11 Dynamische Erzeugung eines RadioButtonGroupByIndex-UI-Elements
9.3 Layout Diese Kategorie enthält UI-Elemente, die wir nutzen, um das Layout zu erstellen. Nachfolgend beschreiben wir einige der UI-Elemente, die in dieser Kategorie enthalten sind.
150
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
9.3.1 ViewContainerUIElement Dieses UI-Element ist ein Areal innerhalb einer View, welches eine andere View enthält. Es hat keine eigenen Eigenschaften, aber es erbt die Eigenschaften der abstrakten Basisklasse UI-Element. Wir erzeugen eine WD-Komponente, ein Registrierungsformular bestehend aus drei Views (Abb. 9.22). In die View V_VIEW fügen wir zwei ViewContainer-UIElemente (VCU_1 und VCU_2) ein, die nötig sind um die Views V_STEP1 und V_STEP2 einzubetten. Der Context-Knoten wird im COMPONENTCONTROLLER erzeugt, weil wir die Daten zwischen den verschiedenen View Controllern V_STEP1, V_STEP2 und V_VIEW austauschen wollen. Abb. 9.22 WD-Komponentenstruktur
Die COMPONENTCONTROLLER-Context-Struktur Abb. 9.23.
ist
dargestellt
in
Abb. 9.23 Context-Struktur
Der Knoten INFO hat die Kardinalität 0. . .1, Singleton. Die Attribute NAME, EMAIL, STADT sind vom Typ string und das Attribut LAND vom Typ Y_ DEFUERDOMAENE, definiert im ABAP Dictionary als Domäne, die alle EU-Mitgliedstaaten enthält. Zur Laufzeit ist V_VIEW die Default View (d.h. der View, der als erstes angezeigt wird, wenn das Window gerufen wird). Das Layout dieser View ist dargestellt in Abb. 9.24.
9.3
Layout
151
Abb. 9.24 View V_VIEW Layout
Weil wir mehrere Views zur gleichen Zeit und im gleichen Fenster (Window) anzeigen wollen, werden wir das ViewContainer-UI-Element verwenden. Zur Laufzeit, wenn der Bildschirm das erste Mal angezeigt wird, möchten wir, dass solange nur die Felder der View V_VIEW für den Anwender sichtbar sind, bis der Anwender das UI-Element LinktoAction drückt. Aus diesem Grund haben wir als Default in VCU_1 und in VCU_2 jeweils einen EMPTYVIEW eingefügt (Abb. 9.25). Eine EMPTYVIEW ist ein spezieller View-Typ, der automatisch generiert wird und der verwendet wird um andere Views zu verstecken.
Abb. 9.25 Window-Struktur
Zur Laufzeit haben wir (Abb. 9.26): Wie wir sehen, werden nur die UI-Elemente der Default View V_VIEW angezeigt, weil VCU_1 und VCU_2 die EMPTYVIEWs als Default haben. Dies ist in Abb. 9.27 schematisch dargestellt. Nachdem der Anwender das UI-Element LinkToAction gedrückt hat (ID = LTA_WEITER), möchten wir in VCU_1 die View V_STEP1 anzeigen. Um das zu erreichen, definieren wir ein Outbount-Plug in die View V_VIEW (Abb. 9.28).
152
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.26 Laufzeit
Component Y_UI_VIEWCONTAINERUIE Window W_DEFAULT View V_VIEW
VCU_1 EMPTYVIEW VCU_2 EMPTYVIEW
Abb. 9.27 Im Fenster (Window) eingebettete Views
Abb. 9.28 Definition eines Outbound-Plug in der View V_VIEW
In Abb. 9.29 zeigen wir das V_STEP1 Layout. Um in der Lage zu sein, den Viewinhalt von V_STEP1 anzuzeigen, wenn der Anwender das UI-Element LinkToAction drückt (ID = LTA_WEITER), müssen wir einen Inbound-Plug in der View V_STEP1 definieren (Abb. 9.30). Jetzt betten wir den View V_STEP1 in das ViewContainerUIElement VCU_1 ein und erstellen den Navigations-Link (Abb. 9.31). Wenn der Anwender das UI-Element LinkToAction drückt, stößt das Framework die Eventhandler-Methode onactionlta1 an. Wenn wir einen Outbound Plug
9.3
Layout
153
Abb. 9.29 V_STEP1 View-Layout
Abb. 9.30 Definition eines Inbound-Plug in der View V_STEP1
Abb. 9.31 Window-Struktur
für die View erstellen, wird eine Fire-Methode zu dem Interface hinzugefügt. Eine Fire-Methode unseres Outbound Plug op_to_v_step1 wird mit folgendem Statement gerufen: wd_this->fire_op_to_v_step1_plg( ).
154
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Wir haben einen Navigations-Link von OP_TO_V_STEP1 nach IP_V_STEP1 erzeugt. Wird diese Methode abgefeuert, wird die View V_STEP1 angezeigt. Um die Fire-Methode zu integrieren, können wir den Web Dynpro Code Wizard nutzen (Abb. 9.32).
Abb. 9.32 Aufruf des Web Dynpro Code Wizard
Zur Laufzeit haben wir (Abb. 9.33):
View V_STEP1
Abb. 9.33 Laufzeit
Nachstehend müssen wir die View V_STEP2 anzeigen, wenn der Anwender das UI-Element LinkToAction (ID = LTA_SPEICHERN) drückt. Um das zu erreichen, müssen wir einen Outbound-Plug namens OP_TO_V_STEP2 in View V_STEP1 definieren und die generierte Methode abfeuern (Abb. 9.34).
Abb. 9.34 Outbound-Plug, Eventhandler-Methode
9.3
Layout
155
In Abb. 9.35 zeigen wir das V_STEP2 Layout.
Abb. 9.35 V_STEP2 View-Layout
Anschliessend müssen wir einen Inbound-Plug namens IP_V_STEP2 definieren. Wir betten die View V_STEP2 in das ViewContainerUIElement VCU_2 ein und erzeugen einen korrespondierenden Navigations-Link (Abb. 9.36).
Abb. 9.36 Window-Struktur
Die Laufzeitstruktur ist in Abb. 9.37 dargestellt. 9.3.1.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_VIEW_CONTAINER_UIELEMENT
156
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
View V_STEP2
Abb. 9.37 Laufzeit
Die Implementierung eines dynamischen ViewContainerUIElement enthält folgende Statements (Listing 9.12):
data lr_vcu type ref to cl_wd_view_container_uielement. lr_vcu = cl_wd_view_container_uielement=>new_view_container_uielement( id = ’VCU’ ).
Listing 9.12 Dynamische Programmierung eines ViewContainerUIElement
In diesem Fall, nach der dynamischen Erzeugung des ViewContainerUIElements, müssen wir dynamisch die einbettende View und die Navigations-Links erzeugen.
9.3.2 TabStrip Dieses UI-Element erlaubt uns einige Tabreiter darzustellen. Der Anwender kann so von einer Registerkarte zur anderen wechseln. Wir erzeugen eine WD-Komponente, ein Registrierungsformular, mit der in Abb. 9.38 dargestellten Struktur. Wir erzeugen ein UI-Element TabStrip und fügen zwei Tabreiter ein. Um die Tabreiter einzufügen, machen wir einen Rechtsklick auf den TabStrip-Namen und wählen aus dem Kontextmenü: Insert Tab. Wenn der Anwender den Button Weiter drückt, navigieren wir zum nächsten Tabreiter und zeigen die Daten, die der Anwender in die Registrierungsform des ersten Tabreiters eingegeben hat.
9.3
Layout
157
Abb. 9.38 WD-Komponentenstruktur
Das View-Layout ist in Abb. 9.39 dargestellt.
Abb. 9.39 View-Layout
Nachstehend zeigen wir eine Tabelle mit einigen der Eigenschaften des UIElements TabStrip, die gebunden werden können, und den Attribut-Typ, falls die Eigenschaft bindungsfähig ist (Tabelle 9.11). Tabelle 9.11 Einige der Eigenschaften des UI-Elements TabStrip Name
Typ
Initialwert
Bindungsfähig
selectedTab tabAlignment width
STRING WDUI_TAB_ALIGNMENT STRING
fast -
yes yes yes
158
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Die Eigenschaft selectedTab vom Typ string kann genutzt werden, um von einem Tabreiter zum anderen zu navigieren. Die Eigenschaft setzt den Namen des selektierten Tabreiters. Wir definieren eine Datenbindung zwischen der selectedTab-Eigenschaft und dem Context-Attribut mit dem gleichen Namen (string), festgelegt im Knoten DYNAMISCH im Context-View. Der Knoten STUDENT hat die Dictionary-Struktur YSTRU_PERSON, Kardinalität 0. . .1, Singleton. Die View Context-Struktur ist dargestellt in Abb. 9.40. Abb. 9.40 Context-Struktur
Durch die Verwendung der wdDoInit-Hook-Methode versehen wir das Attribut SELCTEDTAB des Knotens DYNAMISCH mit der ID des Tabreiters, den wir zur Laufzeit aktiv haben möchten – TAB_1 (Listing 9.13). METHOD wddoinit . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-selectedtab = ’TAB_1’. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 9.13 Die wdDoInit-Hook-Methode
Wenn der Anwender den „Weiter“-Button drückt, stößt das Framework die Eventhandler-Methode onactionweiter (Listing 9.14) an. Wir versehen die Eigenschaft selectedtab mit dem Wert TAB_2, womit wir den nächsten Tabreiter TAB_2 selektieren. Die Laufzeitstruktur ist in Abb. 9.41 dargestellt. 9.3.2.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_TABSTRIP
9.3
Layout
159
METHOD onactionweiter . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-selectedtab = ’TAB_2’. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 9.14 Eventhandler-Methode onactionweiter
Abb. 9.41 Laufzeit
Nachstehend zeigen wir eine Tabelle, welche die Beziehung zwischen dem View-Designer-Namen und dem Laufzeitnamen mit den dazugehörenden Typen im Falle der dynamischen Programmierung eines TabStrip-UI-Elements darstellt (Tabelle 9.12). Tabelle 9.12 Dynamische Programmierung View-Designer-Name
Laufzeitname
selectedTab SELECTED_TAB width WIDTH tabAlignment TAB_ALIGNMENT Exact: CL_WD_TABSTRIP=>E_TAB_ALIGNMENT-EXACT Fast: CL_WD_TABSTRIP=>E_TAB_ALIGNMENT-FAST
Typ String String WDUI_TAB_ALIGNMENT
Für das tabStrip-UI-Element haben wir als Aggregation das Tab-Element. Es ist die Laufzeitklasse CL_WD_TAB. Die Implementierung des dynamischen TabStrip-UI-Elements mit zwei Tabreitern enthält nachfolgende Statements (Listing 9.15):
160
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD wddomodifyview . DATA lr_tabstrip TYPE REF TO cl_wd_tabstrip. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_tab1 TYPE REF TO cl_wd_tab. DATA lr_tab2 TYPE REF TO cl_wd_tab. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_tabstrip = cl_wd_tabstrip=>new_tabstrip( id = ’TABSTRIP’ selected_tab = ’TAB_1’ on_select = ’SELECT’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_tabstrip ). lr_container->add_child( lr_tabstrip ). lr_tab1 = cl_wd_tab=>new_tab( id = ’TAB_1’ ). lr_tab2 = cl_wd_tab=>new_tab( id = ’TAB_2’ ). DATA lr_header1 TYPE REF TO cl_wd_caption. DATA lr_header2 TYPE REF TO cl_wd_caption. lr_header1 ?= cl_wd_caption=>new_caption( text = ’Tab1’). lr_header2 ?= cl_wd_caption=>new_caption( text = ’Tab2’). lr_tab1->set_header( lr_header1 ). lr_tabstrip->add_tab( the_tab = lr_tab1 ). lr_tab2->set_header( lr_header2 ). lr_tabstrip->add_tab( the_tab = lr_tab2 ). ENDIF. ENDMETHOD.
Listing 9.15 Dynamische Programmierung eines TabStrip-UI-Elements
9.3.3 PageHeader Dieses UI-Element bietet die Möglichkeit, eine Überschrift für eine Seite zu erzeugen. In den Titelinhalt und das PageHeader-Areal können wir andere UI-Elemente einfügen. Wir erzeugen eine WD-Komponente mit der in Abb. 9.42 dargestellten Struktur. Wir nehmen die View V_VIEW als Master View. Hier fügen wir ein PageHeaderUI-Element ein, das zwei LinkToAction-UI-Elemente enthält. Und im dem PageHeader-Areal fügen wir ein ViewContainerUIElement ein. Wenn der Anwender mit dem LinkToAction-UI-Element interagiert, zeigen wir im ViewContainerUIElement eine der beiden Slave Views V_ LAND oder V_ BEWERBER. All dies ist in Abb. 9.43 schematisch dargestellt.
9.3
Layout
161
Abb. 9.42 WD-Komponentenstruktur
Y_UI_PAGEHEADER
PageHeader Title Content
PageHeader Area
Abb. 9.43 Applikationsstruktur
Nachdem das UI-Element PageHeader in die View V_VIEW eingefügt ist, können wir einen PageHeader-Titelinhalt einfügen (Abb. 9.44 – rechts) und ein weiteres PageHeader-Areal (Abb. 9.44 – links).
Abb. 9.44 Einfügen des Titelinhalts und PageHeader Areal
In einem PageHeaderArea können wir so viele UI-Elemente einfügen, wie wir möchten. Hier haben wir uns entschieden, nur ein UI-Element (ViewContainerUIElement) einzufügen. Als Darstellungsoptionen hat es Standard, Emphasized undTransparent. In unserem Beispiel haben wir die Default-Darstellung Standard. Um auf dem Bildschirm die anderen PageHeaderArea-Darstellungen zu sehen, können wir Werte aus einer Liste auswählen, einen nach dem anderen, und das
162
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Ergebnis in der View-Darstellung ansehen. Oder wir können die Anwendung laufen lassen und die verschiedenen Änderungen sehen. Im System finden wir zwei WD-Komponenten, in welchen wir die UI-Elemente sehen und die Auswirkungen der Änderungen der Eigenschaften dieser UI-Elemente betrachten können. Diese Komponenten sind WDR_TEST_EVENTS und WDR_TEST_UI_ELEMENTS. Das Layout für V_VIEW ist dargestellt in Abb. 9.45. Abb. 9.45 V_VIEW View-Layout
Jede View (V_ LAND und V_ BEWERBER) hat ein Table-UI-Element, in dem wir die Daten zeigen, die in unseren Datenbanktabellen YPERSONEN und YEU_ LAENDER gespeichert sind. Das Ergebnis zur Laufzeit ist in Abb. 9.46 dargestellt.
PageHeader Title content
PageHeader Area
Abb. 9.46 Laufzeit
9.3.3.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_PAGE_HEADER Nachstehend zeigen wir eine Tabelle, welche die Beziehung zwischen dem View-Designer-Namen und dem Laufzeitnamen mit den dazugehörenden Typen im
9.3
Layout
163
Falle der dynamischen Programmierung eines UI-Elements PageHeader darstellt (Tabelle 9.13). Tabelle 9.13 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
title TITLE WDY_MD_TRANSLATABLE_TEXT TEXT_DIRECTION WDUI_TEXT_DIRECTION textDirection CL_WD_PAGE_HEADER=>E_TEXT_DIRECTION-INHERIT CL_WD_PAGE_HEADER=>E_TEXT_DIRECTION-LTR CL_WD_PAGE_HEADER=>E_TEXT_DIRECTION-RTL
Für das PageHeader-UI-Element haben wir als Aggregation die Elemente: Area und TitleContent. Die Area-Laufzeitklasse ist CL_WD_PAGE_HEADER_AREA. Die Implementierung des dynamischen UI-Elements PageHeader (mit PageHeader-Titel) und das PageHeaderArea (mit einem textView-UI-Element) enthält nachfolgende Statements (Listing 9.16):
METHOD wddomodifyview . DATA lr_pageheader TYPE REF TO cl_wd_page_header. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_area TYPE REF TO cl_wd_page_header_area. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_pageheader = cl_wd_page_header=>new_page_header( id = ’PH_PAGEHEADER’ text_direction = cl_wd_page_header=>e_text_direction-ltr ). lr_pageheader->set_title( ’PAGEHEADER - DYNAMISCH’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_pageheader ). lr_container->add_child( lr_pageheader ). lr_area = cl_wd_page_header_area=>new_page_header_area( id = ’PAGEHEADAREA’ design = cl_wd_page_header_area=>e_design-emphasized ). DATA lr_textview TYPE REF TO cl_wd_text_view. lr_textview = cl_wd_text_view=>new_text_view( id = ’TXT’ text = ’PageHeaderArea’ ). lr_area->set_content( the_content = lr_textview ). lr_pageheader->add_area( the_area = lr_area ). ENDIF. ENDMETHOD.
Listing 9.16 Dynamische Programmierung eines PageHeader-UI-Elements
164
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
9.3.4 ContextualPanel Dieses UI-Element bietet Navigationsfunktionen. Seine Navigationsliste kann viele Ebenen haben. Wir erzeugen das gleiche Beispiel wie für den PageHeader. Aber nun verwenden wir zwei LinktoAction-UI-Elemente, um den Inhalt für ein UI-Element ContextualPanel zu erzeugen. In einem UI-Element ContextualPanel können wir verschiedene Elementarten einfügen: FreeContextualArea, NavigationList und ViewSwitch. Für unser Beispiel nehmen zwei FreeContextualArea Elemente. In einem FreecontextualArea können wir einen Inhalt und einen Header einfügen. Wir können den Header auf erweiterbar oder nicht erweiterbar setzen. Der Inhalt ist ein Bereich, in welchen wir andere UI-Elemente einfügen können, die wir innerhalb des FreeContextualArea anzeigen möchten (Abb 9.47).
Abb. 9.47 FreeContexualArea
Abb. 9.48 V_VIEW View-Layout
9.3
Layout
165
Die V_VIEW View-Layout hat die Struktur wie in Abb. 9.48 dargestellt. Zur Laufzeit haben wir (Abb. 9.49):
Abb. 9.49 Laufzeit
9.3.4.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_CONTEXTUAL_PANEL Für das UI-Element ContextualPanel haben wir als Aggregation die Elemente FreeContextualArea, ViewSwitch und NavigationList. Die FreeContextualAreaLaufzeitklasse ist CL_WD_FREE_CONTEXTUAL_AREA. Die Implementierung eines dynamischen contextualPanel-UI-Element mit einem FreeContextualArea-Element, das den Inhalt (linkToAction-UI-Element) hat und einen Header (expandableTitle-Element), enthält folgende Statements (Listing 9.17).
9.3.5 Tray-UI-Element Wie alle Container, schließt dieses UI-Element eine Reihe anderer UI-Elemente ein, aber es stellt auch weitere Funktionalitäten zu Verfügung. Wir erzeugen eine WD-Komponente mit der Struktur wie in Abb. 9.50 dargestellt. Im View-Layout fügen wir zwei Tray-UI Elemente ein. Das erste Element zeigt die Kandidaten Informationen an, das zweite Tray zeigt einige Details zu dem ausgewählten Kandidaten an. Diese Details sind die Landesflagge und die Hauptstadt. In den MIME-Ordner importieren wir drei Bilder mit Flaggen, die wir anzeigen müssen, wenn der Anwender einen Bewerber aus diesem Land auswählt. Nachdem das Tray-UI-Element in dem View-Layout eingefügt ist, können wir ein Menü einfügen (Abb. 9.51 – rechts) und wir können, in jedem Menü, eine MenüOption einfügen (Abb. 9.51 – links). Die Menüoptionen sind: Menu, MenuActionItem, MenuCheckBox, MenuRadioButton und MenuSeparator. In unserem Fall haben wir die Option MenuActionItem (Abb. 9.52) gewählt.
166
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD wddomodifyview . DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_contextualpanel TYPE REF TO cl_wd_contextual_panel. DATA lr_freecontextualarea TYPE REF TO cl_wd_free_contextual_area. DATA lr_linktoaction TYPE REF TO cl_wd_link_to_action. DATA lr_header TYPE REF TO cl_wd_expandable_title. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_contextualpanel = cl_wd_contextual_panel=>new_contextual_panel( id = ’CP_CONTEXTUALPANEL’ ). lr_freecontextualarea = cl_wd_free_contextual_area=>new_free_ contextual_area( id = ’FREECONTEXTUALAREA_1’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_contextualpanel ). lr_container->add_child( lr_contextualpanel ). lr_linktoaction = cl_wd_link_to_action=>new_link_to_action( id = ’CONTENT_1’ on_action = ‘Mitgliedsstaaten_anzeigen’ text = ’ EU-Mitgliedsstaaten anzeigen’ ). lr_freecontextualarea->set_content( the_content = lr_linktoaction ). lr_header = cl_wd_expandable_title=>new_expandable_title( id = ’EXPANDABLETITLE_1’ expandable = abap_true expanded = abap_true title = ’ EU-Mitgliedsstaaten’ ). lr_freecontextualarea->set_header( the_header = lr_header ). lr_contextualpanel->add_item( the_item = lr_freecontextualarea ). ENDIF. ENDMETHOD.
Listing 9.17 Dynamische Programmierung eines contextualPanel-UI-Elements
Abb. 9.50 WD-Komponentenstruktur
9.3
Layout
167
Abb. 9.51 Tray-Menü
Abb. 9.52 Erzeugen eines Menü-Elements
Die View-Layoutstruktur ist in Abb. 9.53 dargestellt.
Abb. 9.53 View-Layoutstruktur
Der erste Tray hat zwei Menüoptionen. Diese werden benötigt, um das zweite Tray-UI-Element anzuzeigen oder zu verstecken. Wie bereits erwähnt, können die meisten UI-Elemente gebunden werden. Nachstehend zeigen wir eine Auflistung mit einigen der Eigenschaften des Tray-UI-Elements, die gebunden werden können, und den Attribut-Typ, falls die Eigenschaft bindungsfähig ist (Tabelle 9.14). Wir möchten das UI-Element mittels der Daten aus dem Context verändern. Dazu erzeugen wir einen Context-Knoten namens DYNAMISCH mit drei Attributen: zwei Attribute vom Typ WDY_BOOLEAN (ENABLED_
168
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung Tabelle 9.14 Einige der Eigenschaften des UI-Elements Tray
Name
Typ
Initialwert
Bindungsfähig
expanded design hasContentPadding scrollingMode
WDY_BOOLEAN WDUI_TRAY_DESIGN WDY_BOOLEAN WDUI_SCROLLING_MODE
True transparent True none
yes yes yes yes
OPTION1, ENABLED_OPTION2) und ein Attribut namens VISIBLE, vom Typ WDUI_VISIBILITY. Um die übereinstimmenden Informationen und dazugehörenden Details anzuzeigen, müssen wir einen Context-Knoten mit der DictionaryStruktur YVIEW_WETBEWERB (ein Datenbank-Views definiert im ABAP Dictionary) erzeugen. Die Context-Struktur ist dargestellt in Abb. 9.54. Abb. 9.54 Context-Struktur
Der Context-Knoten DETAIL wird über die Methode Supply-Funktion SUPPLY_WETTBEWERB versorgt (Listing 9.18). METHOD supply_wettbewerb. DATA: lt_wettbewerb TYPE TABLE OF yview_wettbewerb. SELECT * FROM yview_wettbewerb INTO TABLE lt_wettbewerb. IF sy-subrc = 0. node->bind_table( new_items = lt_wettbewerb ). ENDIF. ENDMETHOD
Listing 9.18 Methode Supply-Funktion
Um in der Lage zu sein, die aktiven Eigenschaften der Menüoptionen – erstellt in dem ersten Tray-UI-Element - zu verändern, definieren wir die folgende Datenbindung: (Abb. 9.55).
9.3
Layout
169
Abb. 9.55 Datenbindung
Zum Zeitpunkt der Initialisierung möchten wir den zweiten Tray verstecken, die MENU_OPTION1 aktivieren und die MENU_OPTION2 nicht aktivieren. Um das zu realisieren, editieren wir die wdDoInit-Hook Methode (Listing 9.19).
METHOD wddoinit . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-enabled_option1 = abap_true. ls_data-enabled_option2 = abap_false. ls_data-visible = cl_wd_tray=>e_visible-none. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 9.19 Die wdDoIni- Methode
Um in der Lage zu sein die visible-Eigenschaft des zweiten Tray mit der ID „TRAY_DETAIL“ zu verändern, definieren wir eine Datenbindung zwischen diesen Eigenschaften und dem Context-Attribut VISIBLE: Wenn der Anwender die erste Menüoption „MENU_OPTION1“ auswählt, stößt das Framework die Eventhandler-Methode onactionanzeigen an (Listing 9.20).
170
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD onactionanzeigen. DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-enabled_option1 = abap_false. ls_data-enabled_option2 = abap_true. ls_data-visible = cl_wd_tray=>e_visible-visible. lr_node->set_static_attributes( ls_data ). ENDMETHOD
Listing 9.20 Die Eventhandler-Methodeonactionanzeigen
Wenn der Anwender die zweite Menüoption „MENU_OPTION2“ auswählt, stößt das Framework die Eventhandler-Methode onactionunsichtbar an (Listing 9.21). METHOD onactionunsichtbar . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-enabled_option1 = abap_true. ls_data-enabled_option2 = abap_false. ls_data-visible = cl_wd_tray=>e_visible-none. lr_node->set_static_attributes( ls_data ). ENDMETHOD
Listing 9.21 Die Eventhandler-Methode onactionunsichtbar
Zur Laufzeit können wir wählen, ob wir die Details zu dem Bewerber anzeigen oder verstecken (Abb. 9.56).
Abb. 9.56 Laufzeit
9.3
Layout
171
9.3.6 MessageArea Dieses UI-Element stellt einen Platzhalter für Nachrichten dar. Es hilft uns festzulegen, wo sie in der View erscheinen. Wie wir gesehen haben, werden die Nachrichten defaultmäßig im unteren Teil des Bildschirms dargestellt. Der Nachrichtenort kann durch das Hinzufügen eines MessageArea-UI-Elements geändert werden. Wir benötigen nur ein MessageArea-UI-Element je View Layout. Wir erzeugen ein Beispiel um eine Eingabe des Anwenders zu prüfen. Falls der Anwender eine Kombination aus Klein- und Großbuchstaben von A – Z oder Leertaste eingibt, zeigen wir eine Nachricht mit dem Text „Deine Angabe ist string“. Wenn nicht, zeigen wir eine Nachricht “Deine Angabe ist nicht string”. Um diese Nachrichten anzuzeigen, verwenden wir ein MessageArea-UI-Element. Es werden kleine Programme verwendet, die die Möglichkeit bieten die erzeugten regulären Ausdrücke (regex) zu testen, bevor man sie verwendet. Solch ein Programm ist demo_regex_toy. Durch Verwendung der Transaktion SA38 oder SE38 können wir dieses Programm starten (Abb. 9.57).
Abb. 9.57 Regex-Toy-Bildschirm
172
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Durch die Verwendung von regulären Ausdrücken können wir die Werte filtern, welche der Anwender auf dem Web-Dynpro-Bildschirm eingegeben hat. Wir beginnen unser Beispiel mit der Erzeugung einer Komponente namens Y_UI_MESSAGEAREA mit einer View namens V_VIEW. In der Context-View erstellen wir ein Context-Attribut FIRSTNAME vom Type STRING. Das ViewLayout ist in Abb. 9.58 dargestellt.
Abb. 9.58 View-Layout
Wie zu sehen ist, haben wir in diesem Fall ein UI-Element MessageArea in den Group Container eingefügt. Dies ist der Platz, an welchem alle Nachrichten angezeigt werden. Wenn der Anwender den Button mit der ID „BTN“ drückt, stößt das Framework die Eventhandler-Methode onactionueberpruefen an (Listing 9.22). Durch Verwendung der statischen Methode MATCHES der Klasse CL_ABAP_MATCHER prüfen wir den Wert, den der Anwender in das UI-Element inputField eingegeben hat. Falls der Wert den von uns in der lokalen Variablen lv_pattern spezifierten Konditionen entspricht, verwenden wir die Methode REPORT_MESSAGE um eine Nachricht vom Typ information anzuzeigen. Andernfalls geben wir mit der gleichen Methode die Fehlernachricht aus. Weil wir dem Anwender auf dem Bildschirm zeigen wollen, ob der von ihm in das Eingabefeld eingegebene Wert einem String entspricht oder nicht, verwenden wir einen Parameter, der die Eingabe beinhaltet, die er gerade getätigt hat. Aus diesem Grund haben wir für die Methode REPORT_MESSAGE einen Parameter namens „params“ verwendet. Durch Doppelklick auf den Methodennamen navigieren wir vorwärts und wir sehen dann all die Parameter, die zu der Methode gehören, und von welchem Typ sie sind. Für den Parameter „params“ benötigen wir eine Variable vom Typ wdr_name_value_list, welcher tatsächlich ein Tabellentyp mit einer flachen Struktur ist. Aus dieser Struktur haben wir den Namen (den Parameternamen, in unserem Fall „vorname“) und den Wert (mit dem wir zur Laufzeit den Parameternamen „lv_vorname“ ersetzen wollen). In Kap. 10 werden wir mehr über den „Message Manager“ erfahren: Wie wir eine Nachricht in einem Fenster darstellen
9.3
Layout
173
METHOD onactionueberpruefen . DATA: lv_vorname TYPE string, lv_pattern TYPE string. wd_context->get_attribute( EXPORTING name = ’VORNAME’ IMPORTING value = lv_vorname ). lv_pattern = ’[a-zA-Z\s]*’. CHECK lv_vorname IS NOT INITIAL. DATA: lr_api_controller TYPE REF TO if_wd_controller, lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). DATA: lt_message_parameters TYPE wdr_name_value_list, ls_message_parameter LIKE LINE OF lt_message_parameters. ls_message_parameter-name = ’vorname’. ls_message_parameter-value = lv_vorname. APPEND ls_message_parameter TO lt_message_parameters. IF cl_abap_matcher=>matches( pattern = lv_pattern text = lv_vorname ) = abap_true. lr_message_manager->report_message( message_text =’Deine Angabe &vorname ist string’ message_type = 0 params = lt_message_parameters ). ELSE. lr_message_manager->report_message( message_text =’Deine Angabe &vorname ist nicht string!’ message_type = 2 params = lt_message_parameters ). endif. ENDMETHOD.
Listing 9.22 Prüfung der Dateneingabe des Anwenders
können oder wie wir die ABAP-Klassen verwenden können, um Nachrichten und Ausnahmen zu erzeugen. In Abb. 9.59 werden die Nachrichten durch Verwendung des UI-Elements MessageArea angezeigt.
Abb. 9.59 Zur Laufzeit mit MessageArea-UI-Element
9.3.6.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_MESSAGE_AREA
174
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Tipp Weitere Informationen zur Eingabeprüfung und sicheren ABAP-Programmierung im Allgemeinen, finden Sie in dem SAP Press-Buch: „Sichere ABAP Programmierung" Wiegenstein et al.).
Tabelle 9.15 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
firstVisibleMessages historyvisible maxVisibleMessages
FIRST_VISIBLE_MESSAGE HISTORY_VISIBLE MAX_VISIBLE_MESSAGES
I WDY_BOOLEAN I
Nachstehend zeigen wir eine Tabelle, die die Beziehung zwischen dem ViewDesigner-Namen und dem Laufzeitnamen mit den dazugehörenden Typen im Falle der dynamischen Programmierung eines MessageArea-UI-Elements darstellt (Tabelle 9.15). Die Implementierung eines dynamischen MessageArea-UI-Elements enthält die nachfolgenden Statements (Listing 9.23): data lr_messagearea type ref to cl_wd_message_area. lr_messagearea = cl_wd_message_area=>new_message_area( id = ’MESSAGE_AREA’ HISTORY_VISIBLE = abap_true ). Listing 9.23 Die dynamische Programmierung eines MessageArea-UI-Elements
9.4 Complex Diese Kategorie enthält komplexe UI-Elemente, was ihre Struktur und den Inhalt betrifft. Nachstehend präsentieren wir einige UI-Elemente aus dieser Kategorie.
9.4.1 Table Unter Verwendung dieses UI-Elements können wir Daten, in Reihen und Spalten arrangiert, anzeigen. Tabelle 9.16 zeigt einige der Tabelleneigenschaften, die gebunden werden können, und den Attributtyp, falls die Eigenschaft bindungsfähig ist. In dieser Übung möchten wir Daten eines Endbenutzers entgegennehmen und diese jeweils nach dem letzten Datensatz in ein Table-UI-Element einfügen. Um dies zu erreichen, erstellen wir eine WD-Komponente namens Y_UI_TABLE, die eine View V_VIEW und ein Default Window enthält. In der Context-View benötigen wir
9.4
Complex
175 Tabelle 9.16 Einige Eigenschaften des UI-Elements Table
Name
Typ
Initialwert
Bindungsfähig
selectionMode dataSource rowSelectable design gridMode
WDUI_TSMODE Context node WDY_BOOLEAN WDUI_TABLE_DESIGN WDUI_TABLE_GRID_MODE
auto true standard both
yes mandatory yes yes yes
zwei Context-Knoten. Ein Context-Knoten wird dazu benötigt, den neuen Datensatz des Benutzers zu halten, der zweite für alle Datensätze. Die Context-Struktur wird in Abb. 9.60 dargestellt. Abb. 9.60 Context-Struktur
Der Context-Knoten REGISTRIERUNG hat die Kardinalität 1. . .1, Singleton. Seine Context-Attribute sind: NAME vom Typ STRING, GEBURTSTAG vom Typ YGEBURTSTAG, LAND vom Typ Y_DEFUERDOMAENE und NR vom I Typ. Wir verwenden die Attribute dieses Context-Knotens zum Speichern jedes neuen Satzes. Der Context-Knoten TABELLE hat die Kardinalität 0. . .n, Singleton, Selection 0. . .1, Supply-Funktion SUPPLY_PERSON und initialization lead selection ist nicht automatisch gesetzt. In diesem Fall wollen wir die lead selection manuell setzen. Die Context-Attribute haben denselben Namen und Datentyp wie der ContextKnoten REGISTRIERUNG. Wir nutzen die Attribute dieses Context-Knotens zum Speichern aller Registrierungen. Im nächsten Schritt müssen wir das View-Layout erstellen. Um eine Tabelle in unser View-Layout einzufügen, gibt es zwei Möglichkeiten: Wir können die Tabelle manuell einfügen oder den Web Dynpro Wizard zu Hilfe nehmen. Zuerst erklären wir die erste Option. Nach dem Einfügen eines UI-Element Table in unsere View müssen wir eine Datenbindung erstellen. Wenn eine Tabelle per Wizard an einen Context-Knoten gebunden wird, brauchen wir nicht jede einzelne Tabellenspalte zu erstellen. Wir müssen lediglich den Context-Knoten auswählen und schon versorgt uns das Framework mit den verfügbaren Attributen. Auf diese Weise
176
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
wird die Eigenschaft DataSource (obligatorisch) des Table-UI-Elements an den Context-Knoten TABELLE gebunden (Abb. 9.61). 1
Abb. 9.61 UI-Element Table – Erzeugen der Bindung
Die Cell-Editoren der Tabellenspalte beschreiben das UI-Element, das für Anzeigen und Editieren des Spalteninhalts benutzt wird. Wir erkennen, dass unsere Spalten durch die Benutzung von textView-UI-Elementen erstellt werden. Jedes Attribut repräsentiert eine Spalte in unserer Tabelle, und für jede Spalte können wir ein UI-Element wählen. Danach hängt die zu bindende Standardeigenschaft vom gewählten UI-Element ab. Zum Beispiel ist für das TextView-UI-Element die Eigenschaft text, und für den DropDownByKey ist der Name der zu bindenden Eigenschaft selectedKey (Abb. 9.62). Das View-Layout wird dargestellt in Abb. 9.63. Für jedes Attribut, für das die bind option markiert ist, generiert das Framework eine passende Spalte. Zum Beispiel wird für das Attribut NR die Spalte TBL_BEISPIEL_NR, für das Attribut NAME die Spalte TBL_BEISPIEL_NAME vom Framework generiert, etc. Das UI-Element Table bietet die Möglichkeit, über die Eigenschaft visibleRowCount so viele Zeilen anzuzeigen wie wir brauchen (in unserem Fall 5). Im Standardmodus ist die Eigenschaft displayEmptyRows auf ABAP_TRUE gesetzt. Falls wir diese Eigenschaft auf ABAP_FALSE setzen, werden die Zeilen, die in unserer Tabelle leer sind, nicht länger auf dem Bildschirm angezeigt. Die zweite Option, ein Table-UI-Element in unsere View einzufügen, geht über den Web Dynpro Wizard
(Abb. 9.64).
9.4
Complex
Abb. 9.62 Cell-Editor der Tabellenspalte – Name der zu bindenden Eigenschaft
Abb. 9.63 View-Layout
177
178
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.64 Web Dynpro Wizard zum Einfügen eines Table-UI-Elements ins View-Layout
In diesem Fall generiert der Wizard das Table-UI-Element und wir verwenden folgende Prozedur, um die Datenbindung zu erstellen. Nachdem der Benutzer die neuen Werte eingegeben hat (Name, Geburtstag und Land), müssen wir diese Werte im Table-UI-Element hinter die anderen Datensätze speichern. Dafür brauchen wir eine Aktion. Für ein Table-UI-Element können wir eine Toolbar einfügen. Wir brauchen eine Toolbar um einen ToolBarButton in diesen Bereich einfügen zu können (Abb. 9.65).
1
2
3
Abb. 9.65 Einfügen eines ToolBarButton
9.4
Complex
179
Wir füllen den Knoten „TABELLE“ mit zwei Werten, via Supply-Funktion Methode (Listing 9.24). METHOD supply_person . DATA: ls_tabelle TYPE wd_this->element_tabelle, lt_tabelle LIKE TABLE OF ls_tabelle, lv_counter TYPE i VALUE 1. ls_tabelle-nr = lv_counter. ls_tabelle-name = ’Antonia Maria Crist’. ls_tabelle-geburtstag = ’19800305’. ls_tabelle-land = ’DE’. lv_counter = lv_counter + 1. APPEND ls_tabelle TO lt_tabelle. ls_tabelle-nr = lv_counter. ls_tabelle-name = ’Albu Alina’. ls_tabelle-geburtstag = ’19800908’. ls_tabelle-land = ’IT’. APPEND ls_tabelle TO lt_tabelle. node->bind_table( new_items = lt_tabelle set_initial_elements = abap_true ). node->set_lead_selection_index( index = lv_counter ). ENDMETHOD.
Listing 9.24 Supply-Funktion-Methode
Die lokale Variable lv_counter wird zur Erstellung der Datensatz-ID verwendet. Nach der Befüllung des Knotens benutzen wir die Methode SET_LEAD_SELECTION_INDEX, um die Lead Selection via Index zu setzen. Wie wir sehen, ist der Index mit dem Wert des lv_counter gesetzt. Auf diese Art und Weise ist der letzte Wert der Tabelle selektiert. Wie wir schon zuvor erwähnt haben, wird, wenn die „Initialization lead selection“ für einen Knoten auf „YES“ ist, immer das erste Element dieses Knotens selektiert. Daher beeinflussen wir das ausgewählte Element, wenn unser Context-Knoten die selektierte Eigenschaft „NO“ hat, durch Benutzung des set_lead_selection_index. Um die Lead Selection zu beeinflussen, haben wir die folgenden Methoden zur Verfügung: • • • •
Set_lead_selection Move_first Move_previeus Move_to.
180
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Für unseren Context-Knoten TABELLE haben wir die Selection 0. . .1, was bedeutet, dass maximal eine Zeile selektiert werden kann, wenn die Knoten-Elemente als Tabelle angezeigt werden. Wenn der User den „Hinzufügen“-Button anklickt, triggert das Framework die Eventhandler-Methode onactionhinzufuegen (Listing 9.25).
METHOD supply_person . DATA: ls_tabelle TYPE wd_this->element_tabelle, lt_tabelle LIKE TABLE OF ls_tabelle, lv_counter TYPE i VALUE 1. ls_tabelle-nr = lv_counter. ls_tabelle-name = ’Antonia Maria Crist’. ls_tabelle-geburtstag = ’19800305’. ls_tabelle-land = ’DE’. lv_counter = lv_counter + 1. APPEND ls_tabelle TO lt_tabelle. ls_tabelle-nr = lv_counter. ls_tabelle-name = ’Albu Alina’. ls_tabelle-geburtstag = ’19800908’. ls_tabelle-land = ’IT’. APPEND ls_tabelle TO lt_tabelle. node->bind_table( new_items = lt_tabelle set_initial_elements = abap_true ). node->set_lead_selection_index( index = lv_counter ). ENDMETHOD.
Listing 9.25 Eventhandler-Methode
Wir übergeben den Wert des Attributs NR des TABELLE-Context-Knotens an die lokale Variable lv_counter. Wie wir oben erwähnt haben, verwenden wir diese lokale Variable, um die Datensatz-ID zu erzeugen. Nach jedem neuen Datensatz erhöhen wir diesen Wert um 1. Der Benutzer gibt die Werte Name,Geburtstag und Land ein und wir erzeugen die zugehörige ID. Die Laufzeitstruktur ist in Abb. 9.66 abgebildet. Zusätzlich können wir der Tabellen-Toolbar einen Reset-Button hinzufügen. Nachdem der Benutzer die Sätze eingegeben hat, kann er die Felder Name, Geburtstag und Land zurücksetzen, um einen neuen Satz einzugeben. Der Toolbar-Button „Zurücksetzen“, vom selben Typ ToolBarButton, ist mit einer Aktion namens ZURUECKSETZEN verknüpft. Das Listing 9.26 zeigt die Eventhandler-Methodeonactionzuruecksetzen. Die Laufzeitstruktur wird in Abb. 9.67 dargestellt.
9.4
Complex
181
Abb. 9.66 Laufzeit
Abb. 9.67 Laufzeit
METHOD onactionzuruecksetzen. DATA: lr_node TYPE REF TO if_wd_context_node, ls_registrierung TYPE wd_this->element_registrierung. lr_node = wd_context->get_child_node( ’REGISTRIERUNG’ ). lr_node->bind_structure( EXPORTING new_item = ls_registrierung ). ENDMETHOD.
Listing 9.26 Die Eventhandler-Methodeonactionzuruecksetzen
182
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung Tabelle 9.17 Dynamische Programmierung
View-Designer-Name
Laufzeitname
dataSource DATA_SOURCE visibleRowCount VISIBLE_ROW_COUNT design DESIGN Alternating: CL_WD_TABLE=>E_DESIGN-ALTERNATING Standard: CL_WD_TABLE=>E_DESIGN-STANDARD Transparent: CL_WD_TABLE=>E_DESIGN-TRANSPARENT
Typ Object VISIBLE_ROW_COUNT WDUI_TABLE_DESIGN
9.4.1.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_TABLE Nachfolgend zeigen wir eine Tabelle, die die Korrespondenz zwischen dem View-Entwurfszeit- und View-Laufzeitnamen im Falle der dynamischen Programmierung vom Typ Table-UI-Element mit den passenden Typen zeigt (Tabelle 9.17). Für das UI-Element Table haben wir, als Aggregation die Table Column, Group Column, Header, Legend Popin, MasterColumn und Toolbar. Das TableColumnElement repräsentiert eine Spalte der Tabelle und hat die Laufzeitklasse CL_WD_TABLE_COLUMN. Der Tabellentitel wird durch die Verwendung eines Caption-Elements implementiert und hat die Laufzeitklasse CL_WD_CAPTION. Die Implementierung eines dynamischen Table-UI-Elements mit Tabellenheader, alternierendem Entwurf, drei sichtbaren Zeilen und einer Spalte, die ein TextViewUI-Element als Cell-Editor hat, enthält die folgenden Anweisungen (Listing 9.27). METHOD wddomodifyview . DATA lr_table TYPE REF TO cl_wd_table. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_column_name TYPE REF TO cl_wd_table_column. DATA lr_text_view TYPE REF TO cl_wd_text_view. DATA lr_table_header TYPE REF TO cl_wd_caption. DATA lr_column_name_header TYPE REF TO cl_wd_caption. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_table = cl_wd_table=>new_table( id = ’TBL_TABELLE’ bind_data_source = ’TABELLE’ design = cl_wd_table=>e_design-alternating visible_row_count = 3 ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_table ). lr_container->add_child( lr_table ). lr_column_name = cl_wd_table_column=>new_table_column( id = ’TBL_BEISPIEL_NAME’ ).
9.4
Complex
183
lr_table_header ?= cl_wd_caption=>new_caption( text = ’Tabelle - Beispiel’). lr_table->add_column( the_column = lr_column_name ). lr_table->set_header( lr_table_header ). lr_text_view = cl_wd_text_view=>new_text_view( id = ’TXV_NAME’ bind_text = ’TABELLE.NAME’ ). lr_column_name_header ?= cl_wd_caption=>new_caption( text = ’Name’). lr_column_name->set_table_cell_editor( the_table_cell_editor = lr_text_view ). lr_column_name->set_header( lr_column_name_header ). ENDIF. ENDMETHOD.
Listing 9.27 Dynamische Programmierung eines Table-UI-Elements
9.4.2 RoadMap Dieses UI-Element ermöglicht es uns, die Schritte zu zeigen, die wir zum Vervollständigen einer bestimmten Aufgabe benötigen. Nachfolgend sind einige der RoadMap-Eigenschaften aufgelistet, die gebunden werden können, und deren Attributstyp, falls die Eigenschaft bindungsfähig ist (Tabelle 9.18). Für das RoadMap-Beispiel ziehen wir die Übung aus dem ViewContainerUIElement heran, das wir ein wenig umbauen. Die WD-Komponentenstruktur wird in Abb. 9.68 gezeigt. In diesem Fall ersetzen wir die LinkToAction-UI-Elemente durch zwei Buttons: „Zurück“ und „nächster Schritt“. Diese Buttons werden der View V_VIEW hinzugefügt, und der Benutzer kann via RoadMap vom ersten bis zum letzten Schritt durchnavigieren. In diesem Fall wurde nur ein ViewContainerUIElement verwendet, und für jeden Schritt haben wir eine View. In der View V_VIEW fügen wir ein RoadMap-UI-Element mit drei Schritten ein. Um einem RoadMap-UI-Element einen Schritt hinzuzufügen, machen wir einen
Tabelle 9.18 Einige Eigenschaften des UI-Elements RoadMap Name
Typ
Initial- wertBindungsfähig
selectedStep accessibilityDescription startPointDesign endPointDesign
STRING Translatable text WDUI_ROAD_MAP_EDGE_DESIGN WDUI_ROAD_MAP_EDGE_DESIGN
standard standard
yes yes yes yes
184
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.68 WD-Komponentenstruktur
Rechtsklick auf das Element und wählen „Step einfügen“ aus dem Kontextmenü (Abb. 9.69).
Abb. 9.69 RoadMap-Schritte
Das Layout derView V_VIEW ist in Abb. 9.70 dargestellt. Um das UI-Element RoadMap und den Button via Daten aus dem erzeugten Context manipulieren zu können, erstellen wir im V_VIEW einen Context-Knoten namens DYNAMISCH. Dieser Knoten hat drei Attribute: • SELECTEDSTEP, vom Typ STRING, zum dynamischen Setzen der ID des selektierten Schritts; • ENABLED_NAECHST, vom Typ WDY_BOOLEAN, zur Manipulation der enabled-Eigenschaft des Buttons „Nächster Schritt“; • ENABLED_ZURUECK, vom Typ WDY_BOOLEAN, zur Manipulation der enabled-Eigenschaft des „Zurück“-Buttons (Abb. 9.71 – rechts).
9.4
Complex
185
Abb. 9.70 V_VIEW View-Layout
Abb. 9.71 Context-Struktur
Um die Benutzerdaten zu halten und anzuzeigen, haben wir im COMPONENTCONTROLLER einen Knoten namens INFO (Abb. 9.71 – links) erstellt. Dieser Context-Knoten hat dieselbe Struktur, wie sie im ViewContainerUIElement Beispiel gezeigt wurde. Die Attribute sind: NAME, EMAIL & STADT (vom Typ string) und LAND (vom Typ Y_DEFUERDOMAENE). Wir erstellen ein Context-Mapping zwischen diesem Context-Knoten und den Context-Views V_STEP1, V_STEP2 und V_STEP3. Das V_STEP1 View-Layout hat die in Abb. 9.72 abgebildete Struktur.
Abb. 9.72 V_STEP1 View-Layout
186
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Das V_STEP2 View-Layout hat die in Abb. 9.73 abgebildete Struktur.
Abb. 9.73 V_STEP2 View-Layout
Das V_STEP3 View-Layout hat die in Abb. 9.74 abgebildete Struktur.
Abb. 9.74 V_STEP3 View-Layout
Die View „V_VIEW“ ist die Default-View, die zuerst angezeigt wird. Im ViewContainerUIElement betten wir alle drei Views V_STEP1, V_STEP2 und V_STEP3 ein. Die View V_STEP1 ist in diesem Fall die Default-View. Um zwischen den Views navigieren zu können, müssen wir Inbound- und Outbound-Plugs erstellen. Im View V_VIEW, erstellen wir drei Outbound Plugs: • OP_TO_V_STEP1 wird benötigt, um zur View V_STEP1 zu navigieren • OP_TO_V_STEP2 wird benötigt, um zur View V_STEP2 zu navigieren • OP_TO_V_STEP3 wird benötigt, um zur View V_STEP3 zu navigieren Die View V_STEP1 hat einen Inbound-Plug namens IP_V_STEP1, die View V_STEP2 hat einen Inbound-Plug namens IP_V_STEP2 und die View V_STEP3 hat einen Inbound-Plug namens IP_V_STEP3. Die Window-Struktur wird in Abb. 9.75 dargestellt. In der wdDoInit-Hook-Methode (V_VIEW) setzen wir dynamisch die Attributwerte für SELECTEDSTEP, ENABLED_NAECHST und ENABLED_ZURUECK (Listing 9.28). Wenn der Bildschirm das erste Mal aufgebaut wird, möchten wir den „Zurück“Button auf not enabled haben, den „Nächster Schritt“-Button auf enabled, und den STEP1 als aktiven RoadMap Schritt (Abb. 9.76). Wenn der Benutzer den „Nächster Schritt“-Button klickt, triggert das Framework die Eventhandler-Methode onactionnaechster_schritt (Listing 9.29).
9.4
Complex
187
Abb. 9.75 Window-Struktur
METHOD wddoinit . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-enabled_naechst = abap_true. ls_data-enabled_zurueck = abap_false. ls_data-selectedstep = ’STEP1’. lr_node->set_static_attributes( ls_data ). ENDMETHOD
Listing 9.28 Die wdDoInit-Hook-Methode
Wie wir sehen (Abb. 9.77), machen wir den STEP2 aktiv: ls_data-selectedstep = ‘STEP2’, wir feuern die Methode ab, die uns hilft, zur nächsten View V_STEP2 zu navigieren wd_this>fire_op_to_v_step2_plg( ) und machen beide Buttons verfügbar ls_data-enabled_naechst = abap_true. ls_data-enabled_zurueck = abap_true. Wenn der Benutzer den „Nächster Schritt“-Button erneut drückt, deaktivieren wir diesen Button (Abb. 9.78)
188
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.76 Laufzeit
METHOD onactionnaechster_schritt . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. DATA lv_selectedstep TYPE string. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). lr_node->get_attribute( EXPORTING name = ’SELECTEDSTEP’ IMPORTING value = lv_selectedstep CASE lv_selectedstep. WHEN ’STEP1’. ls_data-selectedstep = ’STEP2’. ls_data-enabled_naechst = abap_true. ls_data-enabled_zurueck = abap_true. wd_this->fire_op_to_v_step2_plg( ). WHEN ’STEP2’. ls_data-selectedstep = ’STEP3’. ls_data-enabled_naechst = abap_false. ls_data-enabled_zurueck = abap_true. wd_this->fire_op_to_v_step3_plg( ). WHEN OTHERS. ls_data-enabled_naechst = abap_false. ls_data-enabled_zurueck = abap_true. ENDCASE. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
).
Listing 9.29 Die Eventhandler-Methodeonactionnaechster_schritt
ls_data-enabled_naechst = abap_false. STEP3 wird aktiviert ls_data-selectedstep = ‘STEP3’ und wir feuern die Methode ab, die uns hilft, zu View V_STEP3 zu navigieren wd_this->fire_op_to_v_step3_plg( ), Wenn der Benutzer den „Zurück“-Button drückt, triggert das Framework die Eventhandler-Methode onactionzurueck (Listing 9.30).
9.4
Complex
189
Abb. 9.77 Laufzeit
Abb. 9.78 Laufzeit
Wir wir sehen (Abb. 9.79), navigieren wir zurück zur View V_STEP2, wenn der Benutzer den „Zurück“- Button anklickt wd_this->fire_op_to_v_step2_plg( ). Wir aktivieren beide Buttons ls_data-enabled_naechst = abap_true. ls_data-enabled_zurueck = abap_true. Wir machen Schritt STEP2 zum aktiven Schritt ls_data-selectedstep = ‘STEP2’.
Wenn der Benutzer erneut den „Zurück“-Button drückt, navigieren wir zurück zur View V_STEP1 (Abb. 9.80) wd_this->fire_op_to_v_step1_plg( ).
Wir deaktivieren den „Zurück“ -Button ls_data-enabled_zurueck = abap_false.
und machen den Schritt STEP1 zum aktiven Schritt ls_data-selectedstep = ‘STEP1’.
190
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD onactionzurueck . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_dynamisch. DATA lv_selectedstep TYPE string. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). lr_node->get_attribute( EXPORTING name = ’SELECTEDSTEP’ IMPORTING value = lv_selectedstep CASE lv_selectedstep. WHEN ’STEP3’. ls_data-selectedstep = ’STEP2’. ls_data-enabled_naechst = abap_true. ls_data-enabled_zurueck = abap_true. wd_this->fire_op_to_v_step2_plg( ). WHEN ’STEP2’. ls_data-selectedstep = ’STEP1’. ls_data-enabled_naechst = abap_true. ls_data-enabled_zurueck = abap_false. wd_this->fire_op_to_v_step1_plg( ). WHEN OTHERS. ls_data-enabled_naechst = abap_true. ls_data-enabled_zurueck = abap_false. ENDCASE. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
).
Listing 9.30 Die Eventhandler-Methodeonactionzurueck Abb. 9.79 Laufzeit
9.4.2.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_ROAD_MAP Nachfolgend präsentieren wir eine Tabelle, die im Fall dynamischer Programmierung vom Typ RoadMap-UI-Element die Korrespondenz zwischen dem View-Designer-Namen und dem Laufzeitnamen aufzeigt, mit den passenden Typen (Tabelle 9.19).
9.4
Complex
191
Abb. 9.80 Laufzeit
Tabelle 9.19 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
selectedStep SELECTED_STEP String startPointDesign START_POINT_DESIGN WDUI_ROAD_MAP_EDGE_DESIGN CL_WD_ROAD_MAP=>E_START_POINT_DESIGN-DISABLED CL_WD_ROAD_MAP=>E_START_POINT_DESIGN-MORE CL_WD_ROAD_MAP=>E_START_POINT_DESIGN-MORE_DISABLED CL_WD_ROAD_MAP=>E_START_POINT_DESIGN-SELECTED CL_WD_ROAD_MAP=>E_START_POINT_DESIGN-STANDARD
Für das RoadMap-UI-Element haben wir, als Aggregation den Schritt: RoadMapStep oder MultipleRoadMapStep. Das RoadMapStep-Element repräsentiert einen Schritt in einer RoadMap, und hat die CL_WD_ROAD_MAP_STEP Laufzeitklasse. Die Implementierung eines dynamischen RoadMap-UI-Elements mit zwei Schritten enthält die folgenden Anweisungen (Listing 9.31):
9.4.3 PhaseIndicator Ähnlich dem RoadMap-UI-Element können wir die Schritte auch durch Verwendung des PhaseIndicator per Wizard zeigen. Nachfolgend zeigen wir einige der Eigenschaften des PhaseIndicator, die gebunden werden können, und der Attributtypen, falls die Eigenschaft bindungsfähig ist (Table 9.20). Eine Phase ist ein Schritt im PhaseIndicator, der bindungsfähige Eigenschaften hat, zum Beispiel enable und status. Tabelle 9.21 präsentiert einige dieser Eigenschaften und zeigt, wie wir die status-Eigenschaft zur dynamischen Manipulation verwenden können. Wir erstellen dasselbe Beispiel für die RoadMap, nutzen aber in diesem Beispiel ein PhaseIndicator-UI-Element mit drei Phasen. Die WD-Komponentenstruktur ist in Abb. 9.81 abgebildet.
192
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD wddomodifyview . DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_roadmap TYPE REF TO cl_wd_road_map. DATA lr_step1 TYPE REF TO cl_wd_road_map_step. DATA lr_step2 TYPE REF TO cl_wd_road_map_step. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_roadmap = cl_wd_road_map=>new_road_map( id = ’RM_ROADMAP’ bind_selected_step = ’DYNAMISCH.SELECTEDSTEP’ start_point_design = cl_wd_road_map=>e_start_point_designselected ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_roadmap ). lr_container->add_child( lr_roadmap ). lr_step1 = cl_wd_road_map_step=>new_road_map_step( id = ’STEP1’ description = ’STEP 1’ name = ’1’ ). lr_roadmap->add_step( the_step = lr_step1 ). lr_step2 = cl_wd_road_map_step=>new_road_map_step( id = ’STEP2’ description = ’STEP 2’ name = ’2’ ). lr_roadmap->add_step( the_step = lr_step2 ). ENDIF. ENDMETHOD.
Listing 9.31 Dynamische Programmierung eines RoadMap-UI-Elements Tabelle 9.20 Einige der Eigenschaften des UI-Elements PhaseIndicator Name
Typ
Initial- wert
Bindungsfähig
selectedPhase accessibilityDescription firstVisiblePhase backgroundDesign
STRING Translatable text STRING WDUI_PHASE_IND_BGD_DESIGN
standard
yes yes yes yes
In diesem Fall haben wir die Views V_STEP1, V_STEP2 und V_STEP3 in V_PHASE1, V_PHASE2 und V_PHASE3 umbenannt. Der Inhalt dieser Views ist derselbe. Wir können eine View durch Rechtsklick auf den View-Namen und die Wahl von umbenennen aus dem Kontextmenü umbenennen. Um eine Phase in das PhaseIndicator-UI-Element einzufügen, rechtsklicken wir auf das Element und wählen aus dem Kontextmenü Phase einfügen (Abb. 9.82).
9.4
Complex
193
Tabelle 9.21 Einige der Phaseneigenschaften und die dynamische Manipulation des Status Name
Typ
Initialwert
Status WDUI_PHASE_STATUS normal Status: completed CL_WD_PHASE=>E_STATUS-COMPLETED Status: normal CL_WD_PHASE=>E_STATUS-NORMAL Status: unavailable CL_WD_PHASE=>E_STATUS-UNAVAILABLE Status: warning CL_WD_PHASE=>E_STATUS-WARNING
Abb. 9.81 WD-Komponentenstruktur
Abb. 9.82 Einfügen einer Phase in einen PhaseIndicator
Bindungsfähig yes
194
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Für die erste Phase haben wir die Status-Eigenschaft auf completed gesetzt. Für die zwei anderen Phasen (Phase2 und Phase3) haben wir die Statuseigenschaft dynamisch gesetzt, durch Verwendung der zwei Attribute namens STATUS2 und STATUS3 vom Typ WDUI_PHASE_STATUS. Um die enabledEigenschaft des „Weiter“-Buttons zu ändern, benutzen wir das gleiche Attribut ENABLED_WEITER vom Typ WDY_BOOLEAN, und um die ausgewählte Phase zu manipulieren, benutzen wir das Attribut SELECTEDPHASE vom Typ string (Abb. 9.83 – rechts).
Abb. 9.83 Context-Struktur
Der Knoten INFO ist definiert im COMPONENTCONTROLLER und hat die gleiche Struktur wir im vorherigen Beispiel gezeigt. Wir erzeugen Context-Mapping zwischen diesem Context-Knoten und den Context-Views V_PHASE1, V_PHASE2 und V_PHASE3. Das Layout der View V_VIEW wird in Abb. 9.84 gezeigt.
Abb. 9.84 Das V_VIEW Layout
Diese View hat zwei definierte Outbound-Plugs: OP_TO_V_PHASE2 und OP_TO_V_PHASE3. Die View V_PHASE1 hat keinen Inbound-Plug, die View V_PHASE2 hat einen Inbound-Plug namens IP_V_PHASE2 und die View PHASE_3 hat einen InboundPlug namens IP_V_PHASE3.
9.4
Complex
195
Die Window-Struktur ist in Abb. 9.85 dargestellt. Abb. 9.85 Window-Struktur
Die View V_PHASE1 wird im ViewControllerUIElement angezeigt; wenn der Bildschirm das erste Mal aufgebaut wird, ist diese View als Default-View definiert. Wir müssen die Attributwerte für SELECTEDPHASE, STATUS2, STATUS3 und ENABLED_ WEITER dynamisch setzen. Zu diesem Zweck verwenden wir die wddoinit-Hook-Methode (Listing 9.32).
METHOD wddoinit . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE if_v_view=>element_dynamisch. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). ls_data-enabled_weiter = abap_true. ls_data-status2 = CL_WD_PHASE=>E_STATUS-WARNING. ls_data-status3 = CL_WD_PHASE=>E_STATUS-WARNING. ls_data-selectedphase = ’PHASE1’. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 9.32 Die wdDoInit-Hook-Methode
Wie wir sehen, selektieren wir die erste Phase: ls_data-selectedphase = wir besetzen Phase2 und Phase3 mit dem Warning-Status
PHASE1 ,
196
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
ls_data-status2= cl_wd_phase=>e_status-warning. ls_data-status3 = cl_wd_phase=>e_status-warning.
setzen den Next-Button auf verfügbar (enabled) (Abb. 9.86).
Abb. 9.86 Laufzeit
Wenn der Anwender den Button drückt, triggert das Framework die Eventhandler-Methode onactionweiter (Listing 9.33).
METHOD onactionweiter . DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE if_v_view=>element_dynamisch. DATA lv_phase TYPE string. lr_node = wd_context->get_child_node( ’DYNAMISCH’ ). lr_node->get_attribute( EXPORTING name = ’SELECTEDPHASE’ IMPORTING value = lv_phase ). CASE lv_phase. WHEN ’PHASE1’. ls_data-selectedphase = ’PHASE2’. ls_data-enabled_weiter = abap_true. ls_data-status2 = cl_wd_phase=>e_status-completed. ls_data-status3 = cl_wd_phase=>e_status-warning. wd_this->fire_op_to_v_phase2_plg( ). WHEN ’PHASE2’. ls_data-selectedphase = ’PHASE3’. ls_data-enabled_weiter = abap_false. ls_data-status2 = cl_wd_phase=>e_status-completed. ls_data-status3 = cl_wd_phase=>e_status-completed. wd_this->fire_op_to_v_phase3_plg( ). WHEN OTHERS. ls_data-enabled_weiter = abap_false. ENDCASE. lr_node->set_static_attributes( ls_data ). ENDMETHOD.
Listing 9.33 Die onactionweiter-Eventhandler-Methode
9.4
Complex
197
Wie wir sehen, aktivieren wir die Phase2, ls_data-selectedphase = ’PHASE2’
wir setzen Phase2 auf completed-Status und Phase3 auf Warning-Status ls_data-status2 = cl_wd_phase=>e_status-completed. ls_data-status3 = cl_wd_phase=>e_status-warning.
und den „Weiter“-Button auf enabled (Abb. 9.87).
Abb. 9.87 Laufzeit
Beim nochmaligen Drücken des „Weiter“-Buttons setzen wir Phase2 und Phase3 auf completed-Status ls_data-status2 = cl_wd_phase=>e_status-completed. ls_data-status3 = cl_wd_phase=>e_status-completed,
und deaktivieren den „Weiter“-Button (Abb. 9.88).
Abb. 9.88 Laufzeit
9.4.3.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_PHASE_INDICATOR Nachfolgend präsentieren wir eine Tabelle, die die Korrespondenz zwischen dem View-Designer-Namen und dem Laufzeitnamen mit den passenden Typen zeigt,
198
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung Tabelle 9.22 Dynamische Programmierung
View-Designer-Name
Laufzeitname
Typ
selectedPhase SELECTED_PHASE String firstVisiblephase FIRST_VISIBLE_PHASE String backgroundDesign BACKGROUND_DESIGN WDUI_PHASE_IND_BGD_DESIGN CL_WD_PHASE_INDICATOR=>E_BACKGROUND_DESIGN-EMPHASIZED CL_WD_PHASE_INDICATOR=>E_BACKGROUND_DESIGN-TRANSPARENT
im Falle von dynamischer Programmierung vom Typ PhaseIndicator-UI-Element (Tabelle 9.22). Für das UI-Element PhaseIndicator haben wir als Aggregation das Phasen Element. Es hat die Laufzeitklasse CL_WD_PHASE. Die Implementierung eines dynamischen PhaseIndicator-UI-Elements mit zwei Phasen enthält die folgenden Anweisungen (Listing 9.34):
9.4.4 Tree – Sequentielle Implementierung Mit diesem UI-Element können wir die im Context definierte Hierarchie veranschaulichen. Für dieses UI-Element können wir benutzen: • eine sequentielle Implementierung mit einem nicht-rekursiven Knoten, falls die Anzahl der Ebenen zur Entwurfszeit spezifiziert werden kann • eine rekursive Implementierung mit einem rekursiven Knoten, falls die Anzahl der Ebenen zur Entwurfszeit unbekannt ist. Wir erstellen eine WD-Komponente (Abb. 9.89). In diesem Fall (sequentielle Implementierung) benötigen wir keinen rekursiven Knoten. Ein Context-Knoten TREE wird im Context eines View Controllers erzeugt. Er hat die Kardinalität 1. . .1 und ist Singleton. Unter diesem Context-Knoten erstellen wir einen weiteren Context-Knoten TREE_NODE mit zwei Attributen. Unter diesem Context-Knoten erstellen wir einen weiteren Context-Knoten TREE_LEAF mit einem Attribut (Abb. 9.90). Die Attribute STUDENTNAME, WERT and STUDENTINFO sind vom Typ string. Der Context-Knoten TREE_LEAF ist nicht Singleton, weil wir für jedes Element des TREE_NODE-Context-Knotens eine Instanz dieses Knotens erzeugen müssen. Im Attribut STUDENTNAME halten wir den Namen jedes Studenten, für jeden Studenten haben wir passende Informationen im Attribut STUDENTINFO. In ein Tree-UI-Element können wir Knotentypen vom TreeItemType und TreeNodeType einfügen, um anzugeben, welche Unterknoten (subnodes) und welche Context-Attribute gerade angezeigt werden (Abb. 9.91).
9.4
Complex
199
METHOD wddomodifyview . DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_phaseindicator TYPE REF TO cl_wd_phase_indicator. DATA lr_phase1 TYPE REF TO cl_wd_phase. DATA lr_phase2 TYPE REF TO cl_wd_phase. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_phaseindicator = cl_wd_phase_indicator=>new_phase_indicator( id = ’PI_PHASEINDICATOR’ bind_selected_phase = ’DYNAMISCH.SELECTEDPHASE’ first_visible_phase = ’PHASE1’ background_design = cl_wd_phase_indicator=>e_background_designtransparent ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_phaseindicator ). lr_container->add_child( lr_phaseindicator ). lr_phase1 = cl_wd_phase=>new_phase( id = ’PHASE1’ description = ’PHASE 1’ status = cl_wd_phase=>e_status-completed ). lr_phaseindicator->add_phase( the_phase = lr_phase1 ). lr_phase2 = cl_wd_phase=>new_phase( id = ’PHASE2’ description = ’PHASE 2’ bind_status = ’DYNAMISCH.STATUS2’ ). lr_phaseindicator->add_phase( the_phase = lr_phase2 ). ENDIF. ENDMETHOD.
Listing 9.34 Dynamische Programmierung eines PhaseIndicator-UI-Elements
Abb. 9.89WDKomponentenstruktur
200
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.90 Context-Struktur
Abb. 9.91 Einfügen von Knotentypen
Das View-Layout wird in Abb. 9.92 gezeigt.
Abb. 9.92 View-Layout
Das TreeItemType-Element –in unserem Fall TREE_IT – beschreibt einen Knoten, der keine Kinder haben kann und immer als Blatt-Element angezeigt wird. Das TreeNodeType Element –in unserem Fall TREE_NT – beschreibt einen Knoten, der Kinder haben kann und als Baumknoten angezeigt wird.
9.4
Complex
201
In Abb. 9.93 zeigen wir die Contextbindung zu den Tree-Elementen.
Abb. 9.93 Bindung des Contexts zu den Tree-Elementen
Der Context-Knoten TREE_NODE wird über die Methode Supply-Funktion gefüllt (Listing 9.35).
METHOD supply_tree_node . DATA: ls_student TYPE if_v_view=>element_tree_node, lt_student LIKE TABLE OF ls_student. ls_student-studentname = ’Ionescu Ana Maria’. ls_student-wert = ’A’. APPEND ls_student TO lt_student. ls_student-studentname = ’Marinescu Loredana’. ls_student-wert = ’B’. APPEND ls_student TO lt_student. ls_student-studentname = ’Marton Luminita’. ls_student-wert = ’C’. APPEND ls_student TO lt_student. node->bind_table( lt_student ). ENDMETHOD.
Listing 9.35 Füllen der Context-Attribute des TREE_NODE-Context-Knotens
Die Werte für den Kindknoten (child node) TREE_LEAF werden genauso via Supply-Funktion-Methode gefüllt (Listing 9.36).
202
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD supply_tree_leaf . DATA: ls_student TYPE if_v_view=>element_tree_leaf, lt_student LIKE TABLE OF ls_student. DATA: lv_wert TYPE string. parent_element->get_attribute( EXPORTING name = ’WERT’ IMPORTING value = lv_wert ). CASE lv_wert. WHEN ’A’. ls_student-studentinfo = ’Article - YES’. APPEND ls_student TO lt_student. ls_student-studentinfo = ’Exam - 5’. APPEND ls_student TO lt_student. ls_student-studentinfo = ’Academic year - II’. APPEND ls_student TO lt_student. WHEN ’B’. ls_student-studentinfo = ’Article - NO’. APPEND ls_student TO lt_student. ls_student-studentinfo = ’Academic year - I’. APPEND ls_student TO lt_student. WHEN OTHERS. ls_student-studentinfo = ’Article - YES’. APPEND ls_student TO lt_student. ls_student-studentinfo = ’Exam - 3’. APPEND ls_student TO lt_student. ls_student-studentinfo = ’Academic year - IV’. APPEND ls_student TO lt_student. ENDCASE. node->bind_table( lt_student ). ENDMETHOD.
Listing 9.36 Füllen der Context-Attribute des TREE_LEAF-Context-Knotens
Zur Laufzeit wird diese Methode für jedes Element des Eltern-Context-Knotens aufgerufen (Abb. 9.94). 9.4.4.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_TREE Nachfolgend zeigen wir eine Tabelle, die die Korrespondenz zwischen dem View-Designer-Namen und dem Laufzeitnamen, mit den passenden Typen zeigt, im Falle von dynamischer Programmierung eines Tree UI-Elements (Tabelle 9.23). Für das UI-Element Tree haben wir, als Aggregation die Knotentypen TreeItemType und TreeNodeType. Das TreeItemType-Element hat die Laufzeitklasse CL_WD_TREE_ITEM_TYPE und das TreeNodeType-Element hat die Laufzeitklasse CL_WD_TREE_NODE_TYPE.
9.4
Complex
203 Element 1 Student A Ionescu Anamaria
Element 11 Article -yes
Element 12 Exam - 5
Element 2 Student B
Element 3 Student C
Marinescu Loredana
Marton Luminita
Element 21
Element 31
Article -no
Article -yes
Element 22 Academic year - I
Element 32 Exam - 3
Element 13
Element 33
Academic year - II
Academic year -IV
Abb. 9.94 Laufzeit
Tabelle 9.23 Dynamische Programmierung ViewDesignerName dataSource Title defaultNodeIcon source
Laufzeitname
Typ
DATA_SOURCE Object TITLE WDY_MD_TRANSLATABLE_TEXT DEFAULT_NODE_ICON_SOURCE STRING
Die Implementierung eines dynamischen Tree-UI-Elements mit zwei Knotentypen (TreeNodeType und TreeItemType) enthält die folgenden Anweisungen (Listing 9.37):
9.4.5 DateNavigator Dieses UI-Element bietet die Möglichkeiten, einen Kalender anzuzeigen, darin zu navigieren und Daten einzugeben. Dabei sind Jahr, Monat, Tag oder ein Datumsintervall vom angezeigten Kalender auswählbar. Nachfolgend präsentieren wir eine Tabelle mit einigen der DataNavigatorEigenschaften, die gebunden werden können, sowie deren Attributtyp, sofern die Eigenschaft bindungsfähig ist (Tabelle 9.24). Wir erstellen eine WD-Komponente namens Y_UI_DATENAVIGATOR. Im Context-View erzeugen wir drei Attribute: MONAT, WOCHE und TAG vom Typ string und zwei Context-Knoten:
204
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD wddomodifyview . DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_tree TYPE REF TO cl_wd_tree. DATA lr_treenode TYPE REF TO cl_wd_tree_node_type. DATA lr_treeitem TYPE REF TO cl_wd_tree_item_type. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_tree = cl_wd_tree=>new_tree( id = ’TRE_SEQUENTIAL’ bind_data_source = ’TREE’ title = ’Studenten informationen’ default_node_icon_source = ’~Icon/CheckedOk’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_tree ). lr_container->add_child( lr_tree ). lr_treenode = cl_wd_tree_node_type=>new_tree_node_type( id = ’TREE_NT’ bind_data_source = ’TREE.TREE_NODE’ bind_text = ’TREE.TREE_NODE.STUDENTNAME’ ). lr_treeitem = cl_wd_tree_item_type=>new_tree_item_type( id = ’TREE_IT’ bind_data_source = ’TREE.TREE_NODE.TREE_LEAF’ bind_text = ’TREE.TREE_NODE.TREE_LEAF.STUDENTINFO’ ). lr_tree->add_node_type( index = 1 the_node_type = lr_treenode ). lr_tree->add_node_type( index = 2 the_node_type = lr_treeitem ). ENDIF. ENDMETHOD.
Listing 9.37 Dynamische Programmierung
Tabelle 9.24 Einige Eigenschaften des UI-Elements DataNavigator Name
Typ
Initial Wert
Bindungsfähig
firstDayOfWeek firstSelectedDate lastSelectedDate selectionMode startsWith
WDUI_DAY_OF_WEEK D D WDUI_DATE_SELECTION_MODE D
auto single -
yes yes yes yes yes
• LEGEND, Kardinalität 0. . .n, Supply-Funktion namens SUPPLY_ LEGEND, Context-Attribute: CATEGORY vom Typ WDY_MD_DATE_ MARKING_CATEGORY und TEXT vom Typ string
9.4
Complex
205
• MARKING, Kardinalität 0. . .n, Supply-Funktion namens SUPPLY_ MARKING, Context-Attribute: CATEGORY vom WDY_MD_DATE_ MARKING_CATEGORY Typ und DATUM vom Typ D. Im View-Layout fügen wir ein UI-Element DateNavigator mit DateNavigatorLegend und DateNavigatorMarking ein (siehe Abb. 9.95). Unter Verwendung des DateNavigatorLegend-Elements können wir eine Legende für den DateNavigator hinzufügen. Und mit dem DateNavigatorMarking-Element können wir Einträge einer spezifischen Kategorie innerhalb des DateNavigator-UI-Elements hervorheben.
Abb. 9.95 Context-View und DateNavigatorLegend, DateNavigatorMarking-Eigenschaften
Die wichtigsten Eigenschaften des DateNavigatorLegend-Elements sind: • „category“, das uns erlaubt, die Legendenkategorien zu erstellen (in Format eins, zwei, drei und vier). Es muss an ein Context-Attribut gebunden werden, das diese Kategorien speichert. • „text“, welches Texte speichert, die jede Kategorie beschreiben. • „dataSource“, welches an einen Context-Knoten gebunden werden muss, der die Kategorien und die Texte der Legendeneinträge speichert. Die wichtigsten Eigenschaften des DateNavigatorMarking-Elements sind: • „category“, welches an ein Context-Attribut gebunden werden muss, das die Kategorie der hervorgehobenen Daten speichert.
206
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
• „dataSource“, welches an einen Context-Knoten gebunden werden muss, das die Kategorien, Daten und den Tooltip der hervorgehobenen Daten speichert. • „tooltip“ ist nicht notwendigerweise bindungsfähig. In unserem Fall haben wir kein Attribut für den Tooltip gespeichert, weil wir keinen Quickinfo-Text anzeigen wollen, wenn der Benutzer den Mauszeiger über die hervorgehobenen Daten des DateNavigator-UI-Elements bewegt. • „date“ wird an ein Context-Attribut gebunden, das das Datum der hervorgehobenen Daten speichert.
Das View-Layout ist in Abb. 9.96 abgebildet.
Abb. 9.96 View-Layout
Das DateNavigator-UI-Element hat viele Eigenschaften und Ereignisse. Wir haben in unserem Beispiel die Eigenschaften wie folgt geändert: Hier haben wir Sonntag als ersten Tag der Woche in unserem Kalender festgelegt. Auf diese Art und Weise zeigen wir drei Monate in unserem Kalender.
9.4
Complex
207
Wir haben die Intervall-Option aus der Liste gewählt, weil wir die Möglichkeit bieten möchten, ein Datumsintervall anzuwählen. Wir haben das Anfangsdatum für unseren Kalender festgelegt. Um in den TextView-UI-Elements die Woche, den Tag oder den Monat anzeigen zu können, den der Benutzer in unserem Kalender auswählt, haben wir folgende Events benutzt: onDaySelect, onMonthSelect and onWeekSelect (Abb. 9.97).
Abb. 9.97 Events des DataNavigator-UI-Elements
Zuerst müssen wir unsere Knoten mit Werten füllen. Das Listing 9.38 zeigt die Supply-Funktion-Methodesupply_legend.
METHOD supply_legend . DATA: ls_legend TYPE wd_this->element_legend, lt_legend LIKE TABLE OF ls_legend. ls_legend-category = cl_wd_date_nav_legend=>e_category-one. ls_legend-text = ’Tag der offenen Tür’. APPEND ls_legend TO lt_legend. ls_legend-category = cl_wd_date_nav_legend=>e_category-two. ls_legend-text = ’Betriebsausflug’. APPEND ls_legend TO lt_legend. ls_legend-category = cl_wd_date_nav_legend=>e_category-three. ls_legend-text = ’Happy hour’. INSERT ls_legend INTO TABLE lt_legend. node->bind_table( lt_legend ). ENDMETHOD.
Listing 9.38 Die Supply-Funktion-Methodesupply_legend
Wir erstellen drei Legendenkategorien (one, two und three) mit folgenden Texten: „Tag der offenen Tür“ für die erste Kategorie, „Betriebsausflug“ für die zweite Kategorie und „Happy hour“ für die dritte Kategorie. Das Listing 9.39 zeigt die Supply-Funktion Methodesupply_marking, die zum Füllen des MARKING-Knotens mit Werten gebraucht wird.
208
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD supply_marking . DATA: ls_marking TYPE wd_this->element_marking, lt_marking LIKE TABLE OF ls_marking. ls_marking-category = cl_wd_date_nav_legend=>e_category-one. ls_marking-date = ’20090811’. APPEND ls_marking TO lt_marking. ls_marking-category = cl_wd_date_nav_legend=>e_category-two. ls_marking-date = ’20090821’. APPEND ls_marking TO lt_marking. ls_marking-category = cl_wd_date_nav_legend=>e_category-three. ls_marking-date = ’20090824’. APPEND ls_marking TO lt_marking. node->bind_table( lt_marking ). ENDMETHOD.
Listing 9.39 Die Supply-Funktion-Methodesupply_marking
Auf diese Weise markieren (highlight) wir den Tag 11.08.2009 für die erste Kategorie, den Tag 21.08.2009 für die zweite Kategorie, und für die dritte Kategorie den Tag 24.08.2009. Wenn der Anwender einen Tag in unserem Kalender selektiert, triggert das Framework die Eventhandler-Methode onactionon_day_select (Abb. 9.98).
Abb. 9.98 Die Eventhandler-Methodeonactionon_day_select
Als Importparameter für unsere Eventhandler-Methode haben wir den Parameter namens DAY vom Typ D, der den ausgewählten Tag speichert. Diesen Wert übergeben wir an unser TAG-Attribut, das in der Context-View erstellt wird. Wenn der Anwender eine Woche in unserem Kalender selektiert, triggert das Framework die Eventhandler-Methode onactionon_week_select (Abb. 9.99).
9.4
Complex
209
Abb. 9.99 Die Eventhandler-Methodeonactionon_week_select
Als Importparameter für unsere Eventhandler-Methode haben wir die Parameter WEEK vom Typ I, der die selektierte Woche speichert, und YEAR vom Typ I, der das entsprechende Jahr zur selektierten Woche aufnimmt. Wir übergeben diese Werte in unser WOCHE-Attribut, das wir in der Context-View erstellt haben. Wenn der Anwender einen Monat in unserem Kalender selektiert, triggert das Framework die Eventhandler-Methode onactionon_month_select (Abb. 9.100).
Abb. 9.100 Die Eventhandler-Methodeonactionon_month_select
Als Importparameter für unsere Eventhandler-Methode haben wir: MONTH vom Typ I, das den selektierten Monat speichert, und YEAR vom Typ I, dass das entsprechende Jahr des selektierten Monats aufnimmt. Wir übergeben diese Werte an unser MONAT-Attribut, das in der Context-View erstellt wurde.
210
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Zur Laufzeit haben wir: (Abb. 9.101)
Abb. 9.101 Laufzeit
9.4.5.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_DATE_NAVIGATOR Nachfolgend präsentieren wir eine Tabelle, die die Korrespondenz zwischen dem Viewdesigner-Namen und dem Laufzeitnamen, mit den passenden Typen, im Falle der dynamischen Programmierung eines DateNavigation-UI-Elements (Tabelle 9.25). Die Implementierung eines dynamischen DateNavigator UI-Elements mit den Elementen DateNavigatorLegend und DateNavigatorMarking enthält die folgenden Anweisungen (Listing 9.40): Tabelle 9.25 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
firstDayOfWeek FIRST_DAY_OF_WEEK WDUI_DAY_OF_WEEK CL_WD_DATE_NAVIGATOR=>E_FIRST_DAY_OF_WEEK-SUNDAY CL_WD_DATE_NAVIGATOR=>E_FIRST_DAY_OF_WEEK-AUTO monthsPerColumn MONTHS_PER_COLUMN I MONTHS_PER_ROW I monthsPerRow startsWith STARTS_WITH D selectionMode SELECTION_MODE WDUI_DATE_SELECTION_MODE CL_WD_DATE_NAVIGATOR=>E_SELECTION_MODE-NONE CL_WD_DATE_NAVIGATOR=>E_SELECTION_MODE-RANGE CL_WD_DATE_NAVIGATOR=>E_SELECTION_MODE-SINGLE
9.5
Graphic
211
METHOD wddomodifyview . DATA lr_date_navigator TYPE REF TO cl_wd_date_navigator. DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_datenav_legend TYPE REF TO cl_wd_date_nav_legend. DATA lr_datenav_marking TYPE REF TO cl_wd_date_nav_marking. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_date_navigator = cl_wd_date_navigator=>new_date_navigator( id = ’DATENAVIGATOR’ first_day_of_week = cl_wd_date_navigator=>e_first_day_of_weeksunday months_per_column = 1 months_per_row = 3 selection_mode = cl_wd_date_navigator=>e_selection_mode-range starts_with = ’20090801’ on_day_select = ’ON_DAY_SELECT’ on_month_select = ’ON_MONTH_SELECT’ on_week_select = ’ON_WEEK_SELECT’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_date_navigator ). lr_container->add_child( lr_date_navigator ). lr_datenav_legend = cl_wd_date_nav_legend=>new_date_nav_legend( id = ’DATENAVIGATORLEGEND’ bind_category = ’LEGEND.CATEGORY’ bind_data_source = ’LEGEND’ bind_text = ’LEGEND.TEXT’ ). lr_date_navigator->set_legend( the_legend = lr_datenav_legend ). lr_datenav_marking = cl_wd_date_nav_marking=>new_date_nav_ marking( id = ’DATENAVIGATORMARKING’ bind_category = ’MARKING.CATEGORY’ bind_data_source = ’MARKING’ bind_date = ’MARKING.DATUM’ ). lr_date_navigator->set_marking( the_marking = lr_datenav_marking). ENDIF. ENDMETHOD.
Listing 9.40 Dynamische Programmieung eines DataNavigator UI-Elements
9.5 Graphic Diese Kategorie enthält UI-Elemente, die uns helfen, mit Grafiken, Landkarten etc. zu arbeiten Nachfolgend präsentieren wir einige der UI-Elemente innerhalb dieser Kategorie.
212
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
9.5.1 Image Dieses UI-Element ermöglicht es uns, Grafiken in unsere WD-Applikation zu integrieren. Ebenso wie die anderen UI-Elemente hat es einige Eigenschaften. Nachfolgend zeigen wir eine Tabelle mit einigen bindungsfähigen Eigenschaften des Image-UI-Elements, und dem Attributtyp, falls die Eigenschaft bindungsfähig ist (Tabelle 9.26). Tabelle 9.26 Einige Eigenschaften des UI-Elements Image Name
Typ
Initialwert
Bindungsfähig
border adjustImageSize height width isDecorative source
I WDY_BOOLEAN STRING STRING WDY_BOOLEAN STRING
0 false
yes yes yes yes yes yes
false
Wir erstellen eine WD-Komponente, mit der wir zwischen drei Images wählen und das aktuelle Image über die Daten aus dem Context manipulieren können. Die WD-Komponentenstruktur ist in Abb. 9.102 dargestellt. Abb. 9.102 WD-Komponentenstruktur
Wir importieren drei Images im JPG-Format. Wie schon erwähnt, müssen wir, um ein Image in einen MIME-Ordner zu importieren, Anlegen -> Mime-Objekt -> Importieren aus dem Kontextmenü wählen, welches nach Rechtsklick auf den WD-Komponentennamen gezeigt wird. Der Context-Knoten DYNAMISCH hat Kardinalität 1. . .1, Singleton. Die Attribute WIDTH und HEIGH sind vom Typ STRING und das Context-Attribut BORDER vom Typ I. Wir verwenden diese Context-Attribute zur Manipulation der
9.5
Graphic
213
Eigenschaften des UI-Elements Image. Für die Context-Attribute WIDTH, BORDER und HEIGH wird die Datenbindung zu den Eigenschaften (mit denselben Namen) des UI-Elements Image definiert, Abb. 9.103.
Abb. 9.103 WD-Komponentenstruktur
Der Context-Knoten DROPDOWNBYINDEX hat die Dictionarystruktur SHSVALSTR2, Kardinalität 0. . .n, Singleton. Wir haben eine Datenbindung zwischen dem Attribut KEY und der Eigenschaft texts des UI-Elements dropDownByIndex definiert. Das Context-Attribut VALUE wird benutzt, um die Eigenschaftsquelle des Image-UI-Elements zu manipulieren. Diese Eigenschaft definiert den Namen der Imagedatei, wie er auf dem Bildschirm angezeigt wird. Das Layout ist in Abb. 9.104 dargestellt.
Abb. 9.104 View-Layoutstruktur
Um die Context-Attribute des Context-Knotens DROPDOWNBYINDEX mit Werten zu füllen, verwenden wir die Supply-Funktion-Methode, wie in Listing 9.41 gezeigt.
214
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD supply_dropdownbyindex . DATA: ls_image TYPE wd_this->element_dropdownbyindex, lt_image LIKE TABLE OF ls_image. ls_image-key = ’Deutschland’. ls_image-value = ’deutschland.jpg’. APPEND ls_image TO lt_image. ls_image-key = ’Frankreich’. ls_image-value = ’france.jpg’. APPEND ls_image TO lt_image. ls_image-key = ’Italien’. ls_image-value = ’italia.jpg’. APPEND ls_image TO lt_image. node->bind_table( new_items = lt_image set_initial_elements = abap_true ). ENDMETHOD.
Listing 9.41 Supply-Funktion-Methode
Zur Laufzeit haben wir (Abb. 9.105):
Abb. 9.105 Laufzeit
9.5.1.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_IMAGE
9.5
Graphic
215 Tabelle 9.27 Dynamische Programmierung
View-Designer-Name
Laufzeitname
Typ
border source width height
BORDER SOURCE WIDTH HEIGHT
I STRING STRING STRING
Nachfolgend präsentieren wir eine Tabelle, die die Korrespondenz zwischen dem Viewdesigner-Names und dem Laufzeitname mit den passenden Typen zeigt, im Falle von dynamischer Programmierung eines Image-UI-Elements (Tabelle 9.27). Die Implementierung eines dynamischen UI-Elements Image enthält die folgenden Anweisungen (Listing 9.42):
data lr_image type ref to cl_wd_image. lr_image = cl_wd_image=>new_image( id = ‘IMG_IMAGE’ bind_width = ‘DYNAMISCH.WIDTH’ bind_height = ‘DYNAMISCH.HEIGHT’ bind_border = ‘DYNAMISCH.BORDER’ bind_source = ‘DROPDOWNBYINDEX.VALUE’ ). Listing 9.42 Dynamische Erstellung eines UI-Elements Image
9.5.2 BusinessGraphics Dieses UI-Element befähigt uns zur Benutzung einiger Diagrammtypen in unserer WD-Applikation. Der Internet Graphics Service (IGS) unterstützt uns bei der Arbeit mit diesem UI-Element, indem er Grafiken im Browser anzeigt. Die Chart Engine ist eine C++-Bibliothek, die Diagrammtypen unterstützt, von einfachen Diagrammtypen (z.B. Balken- oder Kreisdiagramme) bis zu komplexen Diagrammen (z.B. gantt). Wir erstellen eine WD-Komponente mit der in Abb. 9.106 dargestellten Struktur. Unter Verwendung des UI-Elements BusinessGraphics zeigen wir die grafische Illustrierung der in der Datenbanktabelle YPERSONEN gespeicherten Daten. Die Context-View hat die in Abb. 9.107 dargestellte Struktur. Der Knoten person hat die Dictionary-Struktur YPERSONEN, Kardinalität 1...n, Singleton. Aus dieser Struktur wählen wir nur NACHNAME und P_ALTER. Wir haben den Typ Säulendiagramm benutzt, um die Daten aus den Spalten unserer Datenbanktabelle grafisch darzustellen.
216
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.106 WD-Komponentenstruktur
Abb. 9.107 Context-Struktur
Das View-Layout ist in Abb. 9.108 abgebildet.
Abb. 9.108 View-Layout
Mit Hilfe der Supply-Funktion füllen wir den Knoten PERSON mit Daten aus der Datenbanktabelle YPERSONEN. Wir selektieren alle Daten aus den zwei Spalten NACHNAME und P_ALTER.
9.5
Graphic
217
Zur Laufzeit haben wir (Abb. 9.109):
Abb. 9.109 Laufzeit
Um Customizing-Einstellungen für Businessgrafiken auszuführen, müssen wir den SAP Chart Designer verwenden. Wir greifen auf dieses Tool per Mausdoppelklick auf das Diagrammbild im View-Layout zu. Nun ist der SAP Chart Designer offen und wir können unser Diagramm customizen (Abb. 9.110).
Abb. 9.110 Chart Designer
218
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Wir speichern die Einstellungen, die wir vorgenommen haben. Das Framework generiert eine MIME-Datei im XML-Format und setzt die Eigenschaft customizing des BusinessGraphics-UI-Elements (Abb. 9.111).
Abb. 9.111 Speichern der Customizing-Einstellungen in einer XML-Datei
Abb. 9.112 zeigt das Laufzeitresultat.
Abb. 9.112 Laufzeitresultat
9.5.2.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_BUSINESS_GRAPHICS Nachfolgend präsentieren wir eine Tabelle, die die Korrespondenz zwischen dem Viewdesigner-Namen und dem Laufzeitnamen, mit den passenden Typen zeigt, im Falle dynamischer Programmierung eines BusinessGraphics-UI-Elements (Tabelle 9.28).
9.5
Graphic
219 Tabelle 9.28 Dynamische Programmierung
View-Designer-Name
Laufzeitname
Typ
Customizing Dimension
CUSTOMIZING DIMENSION
string WDUI_BGDIMENSION
dimension: pseudo_three CL_WD_BUSINESS_GRAPHICS=>E_DIMENSION-PSEUDO_ THREE dimension: three CL_WD_BUSINESS_GRAPHICS=>E_DIMENSION-THREE dimension: two CL_WD_BUSINESS_GRAPHICS=>E_DIMENSION-TWO chartType CHART_TYPE WDUI_BGTYPE chartType: columns CL_WD_BUSINESS_GRAPHICS=>E_CHART_TYPE-COLUMNS chartType: area CL_WD_BUSINESS_GRAPHICS=>E_CHART_TYPE-AREA chartType: bars CL_WD_BUSINESS_GRAPHICS=>E_CHART_TYPE-BARS
Für ein BusinessGraphics-UI-Element, haben wir als Aggregation Category und Series. Das Category-Object hat die CL_WD_CATEGORY Laufzeitklasse. Series kann Series sein, Laufzeitklasse CL_WD_SERIES oder SimpleSeries, Laufzeitklasse CL_WD_SIMPLE_SERIES. Die Implementierung eines dynamischen BusinessGraphics-UI-Elements (mit SimpleSeries und Category) enthält die folgenden Anweisungen (Listing 9.43). METHOD wddomodifyview . DATA lr_flow_data TYPE REF TO cl_wd_flow_data. DATA lr_container TYPE REF TO cl_wd_uielement_container. DATA lr_businessgraphics TYPE REF TO cl_wd_business_graphics. DATA lr_category TYPE REF TO cl_wd_category. DATA lr_simpleseries TYPE REF TO cl_wd_simple_series. IF first_time EQ abap_true. lr_container ?= view->get_element( ’ROOTUIELEMENTCONTAINER’ ). lr_businessgraphics = cl_wd_business_graphics=>new_business_ graphics( id = ’BGR’ chart_type = cl_wd_business_graphics=>e_chart_type-columns dimension = cl_wd_business_graphics=>e_dimension-two height = 300 width = 300 bind_series_source = ’PERSON’ customizing = ’D7VP83HZ7Z922W5F6ZL0UJQKL.xml’ ). lr_flow_data = cl_wd_flow_data=>new_flow_data( element = lr_businessgraphics ). lr_container->add_child( lr_businessgraphics ). lr_category ?= cl_wd_category=>new_category( id = ’CATEGORY’ bind_description = ’PERSON.NACHNAME’ tooltip = ’Nachname des Bewerbes’ ).
220
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
lr_simpleseries ?= cl_wd_simple_series=>new_simple_series( id = ’SIMPLESERIES’ label = ’Alter des Bewerbes’ bind_value = ’PERSON.P_ALTER’ tooltip = ’Alter des Bewerbes’ ). lr_businessgraphics->set_category( the_category = lr_category ). lr_businessgraphics->add_series( the_series = lr_simpleseries ). ENDIF. ENDMETHOD.
Listing 9.43 Dynamische Erstellung eines BusinessGraphics-UI-Elements
9.6 Integration Diese Kategorie enthält UI-Elemente, die uns helfen, verschiedene andere Technologien in unsere Web-Dynpro-Anwendung zu integrieren. Nachfolgend präsentieren wir einige der UI-Elemente, die diese Kategorie beinhaltet.
9.6.1 InteractiveForms Adobe Document Service (ADS) ist die von Adobe entwickelte Software, geschrieben in Java und C++, eingebettet in die SAP-Entwicklungsoberfläche um Formulare zu erstellen. Die Kommunikation zwischen dem ABAP Stack und dem Java Stack ist via Web Service realisiert. Mit der SM59 Transaktion können wir die ADS-HTTP-Verbindung zu einem externen Server sehen – j2ee engine (Bild 9.113). Um sicherzugehen, dass ADS korrekt konfiguriert ist, führen wir das Programm FP_PDF_TEST_00 über die Transaktionen SE38 oder SA38 aus. Falls die Konfiguration korrekt ist, erhalten wir als Output die Versionsnummer des installierten ADS (Abb. 9.114). Um Fomulare erstellen zu können, müssen wir den Adobe LifeCycle Designer lokal installiert haben. Tipp Für weitere Informationen wird auf das SAP-PRESS Buch SAP Interactive Forms by Adobe (Hauser et al.), verwiesen.
Zuerst erstellen wir ein Beispiel, bei dem wir ein nicht-interaktives PDFFormular in einer WD-Komponente verwenden. Die WD-Komponente hat die in Abb. 9.115 abgebildete Struktur. Im View-Layout fügen wir ein InteractiveForm-UI-Element hinzu. Anschließend müssen wir die Eigenschaften pdfSource und dataSource an den Context binden.
9.6
Integration
221
Abb. 9.113 ADS-HTTP-Verbindung zu einem externen Server
Abb. 9.114 Prüfen, ob das ADS korrekt konfiguriert ist
Die pdfSource ist an ein Attribut vom Typ xstring zu binden, damit das generierte PDF-Dokument gespeichert werden kann. Die dataSource-Eigenschaft muss an den Context-Knoten gebunden werden, der die Daten für unser PDF-Formular liefert. Dieser Knoten kann die Kardinalität 0. . .1 oder 1. . .1 haben. Unter diesem Knoten erstellen wir weitere Context-Knoten. In unserem Fall haben wir lediglich einen Knoten namens PERSON, Kardinalität
222
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.115 WD-Komponentenstruktur
1. . .n, der als Dictionary-Struktur unsere Datenbanktabelle YPERSONEN hat, die im ABAP-Dictionary definiert ist (gefüllt via Supply-Funktion). Die Context-Struktur und das View-Layout sind dargestellt in Abb. 9.116.
Abb. 9.116 Datenbindung
Durch die Eigenschaft templateSource spezifizieren wir den eindeutigen Namen des Adobe-Formulars, das wir benutzen. Wir geben den Namen des Formulars ein, und dann, durch DoppelKlicken, erfolgt eine Vorwärtsnavigation, weil dieses Formular noch nicht existiert. Diese Aktion öffnet ein Pop-up-Fenster, in welches wir
9.6
Integration
223
den Interface-Namen eingeben müssen (Abb. 9.117). Das generierte Formular wird eine XML-Schema–basierte Schnittstelle benutzen.
Abb. 9.117 Spezifizieren des Formular-Interface
Mit dem CONTEXT-Button können wir unseren Context-Knoten DATASOURCE zum Erstellen des Interface verwenden. Die Struktur des Context-Knotens wird im Tabreiter Data View des Adobe LifeCycle Designer (Abb. 9.118) angezeigt.
Abb. 9.118 Form Builder
Die Context-Elemente können einfach per drag & drop auf das Formularlayout gezogen werden. Alternativ können wir den Tabellenassistent verwenden, um das Aussehen unserer Tabelle zu entwerfen. (Abb. 9.119).
224
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.119 Erstellen des Formularlayouts
Weil unser Knoten die Kardinalität 1. . .n hat, wird der Tabellen-Header automatisch erzeugt. Wir können manuell das Layout der Tabelle unter Verwendung der Tools entwerfen, die auf der rechten Seite des Form Builder verfügbar sind. Weitere Informationen über die Verwendung des LiveCycle Designer in der SAPUmgebung bekommen wir mit Hilfe der „Adobe LiveCycle Designer Hilfe“ (durch F1) oder im Menü Hilfe-> Adobe LifeCycle Designer Hilfe Wir setzen einen Standardlayout-Typ, aktivieren das Formular, das Interface und unsere WD-Komponente. Danach können wir die Anwendung ausführen (Abb. 9.120).
Abb. 9.120 Laufzeit
9.6
Integration
225
Für die interaktiven Formulare müssen wir die Eigenschaft „enabled“ des InteractiveForm-UI-Elements auf TRUE setzen und die Eigenschaft „read only“ desselben InteractiveForm-UI-Elements auf FALSE. Dann haben wir eine Aktion mit ihrem onSubmit-Ereignis zu verknüpfen, weil das Framework die verknüpfte Eventhandler-Methode triggert, wenn der Benutzer einen speziellen Senden-Button drückt, der Bestandteil des Adobe Designer ist. Wir erzeugen ein sehr einfaches Beispiel, das zeigt, wie wir ein interaktives PDFFormular innerhalb einer View verwenden und wie wir ein PDF-Template in den Adobe Designer importieren können. Wir erstellen eine WD-Komponente, die den in Abb. 9.121 dargestellten ContextView hat.
Kardinalität 1…1; es liefert die Daten für unser interaktives PDF-Formular Kardinalität 1…1 YPERSONEN Dictionary Structure
Attribut vom Typ DATUM zur Anzeige der aktuellen Daten im Formular
Attribut vom Typ xstring, benötigt um das generierte, interaktive PDFDokument zu speichern
Abb. 9.121 Context-Viewstruktur
Die Eigenschaften des UI-Elements InteractiveForm werden in Abb. 9.122 dargestellt. Wie wir sehen, haben wir ein onSubmit Ereignis namens „Senden“, die enabledEigenschaft ist auf TRUE gesetzt und die readOnly-Eigenschaft ist auf FALSE gesetzt. Weil wir kein activeX Control benutzen wollen, lassen wir die displayType Eigenschaft auf native (default). Wenn der Benutzer den Senden-Button klickt, triggert das Framework die Eventhandler-Methode onactionsenden aus unserem View-Methoden-Tabreiter (Listing 9.44). Wenn der Benutzer den Senden-Button drückt, prüfen wir, ob er die benötigten Werte eingegeben hat: Vorname, Nachname und seine Telefonnummer. Falls die notwendigen Werte korrekt eingegeben wurden, zeigen wir eine Informationsmeldung; ansonsten informieren wir den Benutzer darüber, dass alle Felder Pflichtfelder sind. In diesem Fall haben wir unser eigenes Attribut im Attribute-Tabreiter erstellt (Abb. 9.123).
226
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.122 Eigenschaften des UI-Elements InteractiveForm
DATA lr_current_controller TYPE REF TO if_wd_controller. lr_current_controller ?= wd_this->wd_get_api( ). wd_this->atr_mm = lr_current_controller->get_message_manager( ). Listing 9.44 Die Eventhandler-Methodeonactionsenden
Abb. 9.123 Benutzerdefiniertes Attribut
Um auf das von uns erzeugte Attribut Zugriff zu haben, müssen wir die wd_thisSelbstreferenz benutzen. Mit Hilfe der wdDoInit Hook-Methode übergeben wir die Referenz an den Message Manager im ATR_MM Attribut: DATA lr_current_controller TYPE REF TO if_wd_controller. lr_current_controller ?= wd_this->wd_get_api( ). wd_this->atr_mm = lr_current_controller->get_message_manager( ).
9.6
Integration
227
Mit derselben wdDoInit-Hook Methode haben wir den Wert des DATA-Attributs gesetzt: sy-datum. Auf diese Weise zeigen wir das aktuelle Datum innerhalb des Formulars. Anschließend benutzen wir die Vorwärtsnavigation, um unsere Formularobjekte zu erstellen: das Formular ZINTERACTIVE und das Interface ZINTERACTIVE. Danach importieren wir eine PDF-Template-Datei in unser neu generiertes Formular. Die Template-Datei wurde in PowerPoint erzeugt (ein Blatt) und nach Adobe PDF konvertiert (Abb. 9.124).
Abb. 9.124 Struktur der PDFTEMPLATE-Datei
Mit dem Menü Extras->Importieren können wir den Import durchführen (Abb. 9.125).
Abb. 9.125 Importieren einer Adobe PDF-Datei
228
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.126 Formularentwurf
Als Ergebnis ist das PDF-Template in unser Formular eingefügt (Abb. 9.126). Mit einfachem Drag & drop ziehen wir die Context-Elemente auf den Formularentwurf. Anschließend fügen wir einen Zurücksetzen-Button aus der Standardbibliothek ein, und wir nutzen die Web Dynpro Native library zum Einfügen eines Senden-Buttons, der benötigt wird, um die Daten abzusenden. Für die nativeVersion (interaktives Szenario), haben wir einen Zero Client Installation (ZCI) Layout-Typ genutzt, und wir haben ein ZCI Script über das Menü Utilities > Insert Web Dynpro Script eingefügt (alternativ durch den FP_ZCI_UPDATE Report). Falls wir ein ActiveX Control verwenden möchten, müssen wir die displayTypeEigenschaft als ActiveX setzen und die Web Dynpro ActiveX Library und einen passenden Layout-Typ benutzen. Auf diese Weise wird das Formular via Active Components Framework (ACF) angezeigt. Wir aktivieren das Formular, das Interface und unsere WD-Komponente. Danach können wir die Anwendung ausführen.
9.6.1.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_INTERACTIVE_FORM Nachfolgend präsentieren wir eine Tabelle, die die Korrespondenz zwischen dem Viewdesigner-Namen und dem Laufzeitnamen, mit den passenden Typen zeigt, im Falle von dynamischer Programmierung eines InteractiveForm-UI-Elements (Tabelle 9.29). Die Implementierung eines dynamischen InteractiveForm-UI-Elements (noninteractive) enthält die nachfolgenden Anweisungen (Listing 9.45):
9.6
Integration
229 Tabelle 9.29 Dynamische Programmierung
View-Designer-Name
Laufzeitname
Typ
pdfSource PDF_SOURCE XSTRING enabled ENABLED WDY_BOOLEAN dataSource DATA_SOURCE OBJECT width WIDTH STRING height HEIGHT STRING displayType DISPLAY_TYPE activeX: CL_WD_INTERACTIVE_FORM=>E_DISPLAY_TYPE-ACTIVE_X Native: CL_WD_INTERACTIVE_FORM=>E_DISPLAY_TYPE-NATIVE
DATA lr_interactive_form TYPE REF TO cl_wd_interactive_form. lr_interactive_form = cl_wd_interactive_form=>new_interactive_form( id = ’IFO_NON_INTERACTIVE’ view = view bind_data_source = ’DATASOURCE’ bind_pdf_source = ’PDFSOURCE’ template_source = ’ZADOBE’ display_type = cl_wd_interactive_form=>e_display_type-native enabled = abap_false width = ’400px’ height = ’500px’ ).
Listing 9.45 Dynamische Erzeugung eines InteractiveForm-UI-Elements
9.6.2 FileUpload Wir können dieses UI-Element benutzen, um eine Datei vom Client zum Server hochzuladen. Nachfolgend zeigen wir eine Liste mit einigen der FileUpload-Eigenschaften, die gebunden werden können, und deren Attributtypen, falls die Eigenschaft bindungsfähig ist (Tabelle 9.30). Tabelle 9.30 Einige Eigenschaften des UI-Elements FileUpload Name
Typ
data fileName mimeType
XSTRING STRING STRING
Initiawert
Bindungsfähig mandatory yes yes
Wir erstellen ein sehr einfaches Beispiel, in dem wir eine Textdatei, die die Zahlen von 1 bis 10 beinhaltet, zum Server hochladen und den Dateiinhalt dann in einem
230
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
Abb. 9.127 Dateistruktur
Webbrowser-Fenster anzeigen. Abb. 9.127 zeigt die Struktur der test.txt-Datei, welche mit Notepad auf dem Desktop editiert wurde. Wir erstellen eine WD-Komponente mit einer View namens V_VIEW. Im Context-View erzeugen wir vier Attribute: FILECONTENT vom Typ xstring, benötigt zum Speichern des Dateiinhalts, FILENAME vom Typ string (für den Namen der Upload-Datei), MIMETYPE vom Typ string für den mime-Typ der UploadDatei und SIZE vom Typ INTEGER, benötigt um die Dateigröße (in Bytes) zu speichern. Die WD-Komponentenstruktur und die Context-Viewstruktur werden in Abb. 9.128 dargestellt.
Abb. 9.128 WD-Komponentenstruktur und Context-Viewstruktur
Wir fügen der View V_VIEW ein FileUpload-UI-Element hinzu. Dieses UIElement hat keine damit verknüpfte Aktion. Um die Datei hochzuladen, müssen wir ein UI-Element aus der Aktions-Kategorie, in unserem Fall ein Button, hinzufügen. Wie wir gesehen haben, ist die obligatorische Eigenschaft des UI-Elements DATA. Für dieses UI-Element realisieren wir eine Datenbindung ans Context-Attribut vom Typ xstring (FILECONTENT). Das View-Layout wird in Abb. 9.129 veranschaulicht. Das UI-Element FileUpload hat ein Eingabefeld, in das wir den Verzeichnispfad und den Namen der Datei, die wir zum Server hochladen, schreiben, und einen Button, der die Möglichkeit bietet, nach einer Datei zu suchen. Falls wir mit diesem
9.6
Integration
231
Abb. 9.129 View-Layout
Button nach einer Datei suchen, wird der voll qualifizierte Pfad in das Eingabefeld geschrieben. Wenn der Benutzer auf den Laden-Button drückt, wird der Dateiinhalt in das XSTRING-Attribut geladen. Mit Hilfe der Eventhandler-Methodeonactionladen berechnen wir die Dateigröße über die XSTRLEN-Funktion. Listing 9.46 zeigt die Struktur dieser Methode. METHOD onactionladen. DATA lv_content TYPE xstring. DATA lv_size TYPE i. wd_context->get_attribute( EXPORTING name = ’FILECONTENT’ IMPORTING value = lv_content ). lv_size = XSTRLEN( lv_content ). wd_context->set_attribute( name = ’SIZE’ value = lv_size ). ENDMETHOD
Listing 9.46 Die Eventhandler-Methodeonactionladen
Wenn der Benutzer den Anzeigen-Button drückt, triggert das Framework die Eventhandler-Methode onactionanzeigen (Listing 9.47). Wie wir sehen, haben wir die statische Methode ATTACH_FILE_ TO_RESPONSE von CL_WD_RUNTIME_SERVICES benutzt, um einer Rückmeldung eine Datei anzuhängen. Diese Methode hat die folgenden Parameter: I_FILENAME (der Name der Datei), I_CONTENT (beinhaltet die Datei im XSTRING-Format), I_MIME_TYPE (der Mime-Typ der Datei),
232
9 User-Interface-Elemente (UI-Elemente), statische und dynamische Programmierung
METHOD onactionanzeigen . DATA: lv_content TYPE xstring, lv_mimetype TYPE string, lv_size TYPE i, lv_filename TYPE string. wd_context->get_attribute( EXPORTING name = ’FILECONTENT’ IMPORTING value = lv_content ). wd_context->get_attribute( EXPORTING name = ’FILENAME’ IMPORTING value = lv_filename ). wd_context->get_attribute( EXPORTING name = ’MIMETYPE’ IMPORTING value = lv_mimetype ). wd_context->get_attribute( EXPORTING name = ’SIZE’ IMPORTING value = lv_size ). cl_wd_runtime_services=>attach_file_to_response( i_filename = lv_filename i_content = lv_content i_mime_type = lv_mimetype i_in_new_window = abap_true i_inplace = abap_true ). ENDMETHOD.
Listing 9.47 Die Eventhandler-Methodeonactionanzeigen
I_IN_NEW_WINDOW (Parameter vom Typ Boolean, der spezifiziert, ob der Dateiinhalt in einem neuen Fenster angezeigt werden soll) und I_INPLACE (vom selben Typ Boolean). Unter Verwendung des Löschen-Buttons löschen wir die Daten aus dem Context. Falls wir diese Daten nicht löschen, bleibt die Datei im Speicher, bis eine neue Datei hochgeladen wird oder wir die Anwendung abschließen. Die Laufzeitstruktur wird in Abb. 9.130 dargestellt. 9.6.2.1 Dynamische Programmierung RUNTIME CLASS: CL_WD_FILE_UPLOAD Nachfolgend präsentieren wir eine Tabelle, die die Korrespondenz zwischen dem Viewdesigner-Namen und dem Laufzeitname, mit den passenden Typen zeigt, im Falle von dynamischer Programmierung eines FileUpload-UI-Elements (Tabelle 9.31). Die Implementierung eines dynamischen FileUpload-UI-Elements enthält die folgenden Anweisungen (Listing 9.48): Um weitere Informationen bezüglich der Ausführungszeit von ABAPProgrammteilen, Ratschläge und bestimmte Tipps & Tricks für ABAP Objects (z.B. ABAP Objects Performance-Beispiele) zu bekommen, können wir die SE30 Transaktion (Laufzeitanalyse: Einstieg) verwenden.
9.6
Integration
233
1
2 Abb. 9.130 Laufzeit Tabelle 9.31 Dynamische Programmierung View-Designer-Name
Laufzeitname
Typ
data fileName mimeType
DATA FILE_NAME MIME_TYPE
XSTRING STRING STRING
DATA lr_file_upload TYPE REF TO cl_wd_file_upload. lr_file_upload = cl_wd_file_upload=>new_file_upload( id = ’FILEUPLOAD’ bind_data = ’FILECONTENT’ bind_file_name = ’FILENAME’ bind_mime_type = ’MIMETYPE’
).
Listing 9.48 Dynamische Erzeugung eines FileUpload-UI-Element
Tipp Das Erscheinungsbild der UI-Elemente kann durch Themes beeinflusst werden. Diese können entweder für Anwendungen, die im SAP-Netweaver-Portal laufen, oder für Stand-alone-Applikationen verwendet werden.
Kapitel 10
Nachrichten, Ausnahmen und Web Dynpro ABAP
If we can really understand the problem, the answer will come out of it, because the answer is not separate from the problem Jiddu Krishnamurti
Zusammenfassung Dieses Kapitel zeigt, wie man mit Ausnahmen (exceptions) und Nachrichten (messages) innerhalb von Web-Dynpro-ABAP-Applikationen arbeitet. Für jede der beiden Varianten (Nachrichten und Ausnahmen) präsentieren wir zwei mögliche Implementierungsszenarien. Demzufolge starten wir mit der Modalität, Texte von Nachrichten und Ausnahmen zu erstellen, und schließen mit der Art und Weise, sie in den erstellten Applikationen zu verwenden. Ein gutes Benutzer-Interface fängt Ausnahmen ab, beschreibt die auftretenden Fehler und zeigt Nachrichten an, die Informationen für den Anwender beinhalten. Wie wir bereits gesehen haben, bietet Web Dynpro mittels IF_WD_MESSAGE_ MANAGER das Interface als Nachrichtenmanager an. Dieses Interface enthält viele Methoden, die wir zur Nachrichtenerstellung nutzen können. Zum Beispiel: • REPORT_T100_MESSAGE – beschreibt eine Nachricht durch Verwendung der Eingabe T100; • REPORT_ERROR_MESSAGE – beschreibt eine Web-Dynpro-Nachricht mit optionalen Parametern; • REPORT_ATTRIBUTE_T100_MESSAGE – beschreibt eine Web-DynproAusnahme für ein Context-Attribut; • REPORT_ATTRIBUTE_ERROR_MESSAGE – beschreibt eine Web-DynproAusnahme für ein Context-Attribut; • REPORT_SUCCESS – beschreibt eine Erfolgsnachricht; • REPORT_WARNING – beschreibt eine Warnungsnachricht; • REPORT_EXCEPTION – beschreibt eine Web-Dynpro-Ausnahme. Die Methoden mit REPORT_ATTRIBUTE_XXX oder REPORT_ELEMENT_ XXX können verwendet werden, um Nachrichten mit dem UI-Element zu verbinden, das die Nachricht erzeugt hat.
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_10,
235
236
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
Bis jetzt haben wir nur einfache Nachrichten erzeugt, die einen Text beinhalten, der in das Coding eingefügt war. Diese Art der Programmierung wird aus vielen Gründen nicht empfohlen. So kann der in das Coding eingefügte Nachrichtentext nicht ohne Änderung des Codings übersetzt werden. In diesem Kapitel werden wir Nachrichten mittels der Assistance-Klasse, der T100-Tabelle, der Ausnahme-Klasse und der Nachrichten-Klasse erzeugen.
10.1 Nachrichtenbehandlung Die Nachrichten, die wir in den Web-Dynpro-Applikationen anzeigen, können auf vielerlei Art erzeugt werden. Zum Beispiel können wir Nachrichten erzeugen: • als dynamische Texte – gespeichert im Textpool der Assistance-Klasse; • als Texte aus der Datenbanktabelle T100. Es ist nicht empfehlenswert, sprachspezifische Texte in der Kodierung der Geschäftslogik einzufügen.
10.1.1 Dynamische Texte – gespeichert im Textpool der Assistance-Klasse Eine der wichtigsten Funktionen der Assistance-Klasse ist das Management der dynamischen Texte. Im ABAP Web Dynpro stellt die Klasse CL_WD_COMPONENT_ASSISTANCE zentrale Funktionen zur Verfügung, durch welche eine WD-Komponente auf Textsymbole der Assistance-Klasse zugreifen kann. Wir erzeugen eine WD-Komponente, ein Registrierungsformular für den Anwender (Abb. 10.1).
Abb. 10.1 WD-Komponentenstruktur
Der Anwender soll ein Registrierungsformular mit zwei Pflichtfeldern ausfüllen: Name und Geburtstag. Wenn der Anwender das Formular mit den erforderlichen Daten ausgefüllt hat, zeigen wir eine Informationsnachricht, die darüber informiert,
10.1
Nachrichtenbehandlung
237
dass die Daten gespeichert sind. Wenn der Anwender nicht die erforderlichen Felder ausfüllt, zeigen wir eine Fehlernachricht. Das Layout und der Context-Knoten sind in Abb. 10.2 dargestellt.
Abb. 10.2 Das Layout und der Context-Knoten
Um mit dynamischen Texten arbeiten zu können, die im Textpool der AssistanceKlasse gespeichert sind, müssen wir zuerst die Assistance-Klasse erzeugen. Wir können den Class Builder (Transaktion SE24) verwenden, um eine gewöhnliche ABAP-Klasse zu erzeugen. Eine Assistance-Klasse ist eine übliche ABAP-Klasse, die von der Superklasse CL_WD_COMPONENT_ASSISTANCE erbt. Diese Superklasse versorgt unsere Klasse YCL_ASSISTANCE_CLASS mit zwei zusätzlichen Methoden (Abb. 10.3).
Abb. 10.3 Erzeugen der Assistance-Klasse
Um Textsymbole in der Assistance-Klasse zu pflegen, wählen wir aus dem Assistance-Klasse-Pflege-Menü Springen->Textelemente. Jedes neue Text-Symbol hat ein Identifikations-Symbol (eine dreistellige ID) und einen dazugehörenden Text (Abb. 10.4).
238
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
Abb. 10.4 Text-Symbole
Um in der Lage zu sein, mittels des Instanzattributes WD_ASSIST der Assistance-Klasse auf die Text-Symbole zuzugreifen, müssen wir die AssistanceKlasse unserer Komponente zuweisen. Für jede Web-Dynpro-Component können wir nur eine eindeutig zugewiesene Assistance Klasse zuweisen (Abb. 10.5).
Abb. 10.5 Assistance-Klasse, zugewiesen zu einer Web-Dynpro-Component
Wenn der Anwender den Button REGISTIERUNG drückt, stößt das Framework die Eventhandler-Methode onactionregistrierung an (Listing 10.1). Um Zugriff auf die Textsymbole der Assistance-Klasse zu bekommen, brauchen wir eine lokale Variable vom Typ string (text_success TYPE string). Wenn zur Laufzeit die Methode if_wd_component_assistance∼get_text gerufen wird, wird die ID an den KEY-Parameter übergeben und das entsprechende Textsymbol wird in der lokalen Variablen vom Typ string gespeichert. DATA: text_success TYPE string. text_success = wd_assist->if_wd_component_assistance˜get_text ( key = 002 )
Um Zugriff auf die Textform einer Assistance-Klasse zu haben, können wir den Web Dynpro Code Wizard nutzen (Abb. 10.6). Wenn die Attribute NAME oder GEBURTSTAG leer sind, zeigen wir eine Fehlernachricht durch Verwendung der Methode report_error_message an. Andernfalls zeigen wir eine Information mittels der report_success-Methode. In Abb. 10.7 zeigen wir das Ausführungsergebnis.
10.1
Nachrichtenbehandlung
239
METHOD onactionregistrierung. DATA:text_success TYPE string, text_error TYPE string. text_error= wd_assist->if_wd_component_assistance~get_text ( key = ’001’ ). text_success = wd_assist->if_wd_component_assistance~get_text ( key = ’002’ ). DATA: lr_node TYPE REF TO if_wd_context_node, lv_name TYPE string, lv_geburtstag TYPE ygeburtstag. lr_node = wd_context->get_child_node( ’PERSON’ ). lr_node->get_attribute( EXPORTING name = ’NAME’ IMPORTING value = lv_name ). lr_node->get_attribute( EXPORTING name = ’GEBURTSTAG’ IMPORTING value = lv_geburtstag ). DATA lr_api_controller TYPE REF TO if_wd_controller. DATA lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). IF lv_name IS INITIAL OR lv_geburtstag IS INITIAL. lr_message_manager->report_error_message( message_text = text_error ). ELSE. lr_message_manager->report_success( message_text = text_success ). ENDIF. ENDMETHOD.
Listing 10.1 Coding der Eventhandler-Methode
Abb. 10.6 Web Dynpro Code Wizard
10.1.2 Text aus der Datenbanktabelle T100 Wir können Nachrichten durch Verwendung der Nachrichtenpflege erzeugen Transaktion SE91 (Abb. 10.8). Die hier erzeugten Nachrichten werden in der Datenbanktabelle T100 gespeichert. Diese Tabelle hat folgende Spalten: Nachrichtennummer – MSGNR, Nachrichtentext – TEXT, Sprachenschlüssel – SPRSL und Arbeitsgebiet – ARBGB (Abb. 10.9).
240
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
Abb. 10.7 Ergebnis der Applikation
Abb. 10.8 Nachrichtenklasse YCL_T100MESSAGE
Abb. 10.9 Die Struktur der T100-Tabelle
Wir können in dieser Tabelle nach allen Nachrichten mit der Nummer 000, der Sprache Deutsch (DE) und allen Texten, die mit dem Wort „Der“ beginnen, suchen. Als Ergebnis der Suche finden wir unsere Nachricht (Abb. 10.10). Wir erzeugen die gleiche WD-Komponente, verwenden diesmal aber die Nachrichten mit dem Text aus der Datenbanktabelle T100.
10.1
Nachrichtenbehandlung
241
Abb. 10.10 Suche nach einer Nachricht in Tabelle T100
Wenn der Anwender den Button REGISTRIERUNG drückt, stößt das Framework die Eventhandler-Methode onactionregistrierung an (Listing 10.2).
METHOD onactionregistrierung. DATA: lr_node TYPE REF TO if_wd_context_node, lv_name TYPE string, lv_geburtstag TYPE ygeburtstag. lr_node = wd_context->get_child_node( ’PERSON’ ). lr_node->get_attribute( EXPORTING name = ’NAME’ IMPORTING value = lv_name ). lr_node->get_attribute( EXPORTING name = ’GEBURTSTAG’ IMPORTING value = lv_geburtstag ). DATA lr_api_controller TYPE REF TO if_wd_controller. DATA lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). IF lv_name IS INITIAL OR lv_geburtstag IS INITIAL. lr_message_manager->report_t100_message( msgid = ’YCL_T100MESSAGE’ msgno = ’000’ msgty = ’E’). ELSE. lr_message_manager->report_t100_message( msgid = ’YCL_T100MESSAGE’ msgno = ’001’ msgty = ’I’). ENDIF. ENDMETHOD.
Listing 10.2 Coding der Eventhandler-Methode
Wenn die Attribute NAME oder GEBURTSTAG leer sind, zeigen wir eine Fehlernachricht durch Verwendung der Methode report_t100_message an. Msgty stellt den Nachrichtentyp E – Fehler dar, msgid repräsentiert den Namen der Nachrichtenklasse und msgno stellt die Nachrichten-ID (eine dreistellige Zahl) dar. Wenn die Attribute NAME oder GEBURTSTAG nicht leer sind, zeigen wir eine Information-Nachricht vom Typ I an.
242
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
Zur Laufzeit ist das Benutzer-Interface das gleiche wie im letzten Beispiel (Abb. 10.7). Der einzige Unterschied ist die Art und Weise, wie wir die Nachricht erzeugt haben.
10.2 Ausnahmebehandlung Ausnahmen können durch die ABAP-Laufzeitumgebung ausgelöst werden oder explizit durch das Coding. Ausnahmesituationen haben viele Anlässe (z.B. Kardinalitätenmissachtung für einen Context-Knoten). Die Ausnahmen sind entweder behandelt oder unbehandelt. Alle unbehandelten Ausnahmen führen zu einem Laufzeitfehler, einem sogenannten short dump. Wir können alle vom System erzeugten short dumps mit der Transaktion ST22 (ABAP-Laufzeitfehler) ansehen (Abb. 10.11).
Abb. 10.11 ABAP-Laufzeitfehler
Wir können die Laufzeitfehler von heute und gestern durch die Verwendung der beiden Buttons „Heute“ und „Gestern“ finden. Oder wir suchen nach speziellen Laufzeitfehlern durch Verwendung der Suchparameter. ABAP Web Dynpro bietet Unterstützung bei der Arbeit mit den Ausnahmeklassen durch die Methoden des Message Managers an. Jeder Ausnahme ist ein erklärender Text zugeordnet, der die Ausnahme beschreibt. Es kann ein Online Text Repository OTR oder ein Text aus einer Nachrichtenklasse sein. Wir können unsere eigene Nachrichtenklasse als globale Klasse durch die Verwendung des Class Builder erzeugen oder als lokale Klassen in unseren Programmen. Klassenbasierte Ausnahmebehandlung beruht auf den Ausnahmeklassen; es besteht eine Bezeichnungsbestimmung für eine Ausnahmeklasse: der Name muss mit cx, zcx oder ycx beginnen.
10.2
Ausnahmebehandlung
243
Als Basis-Ausnahmeklassen haben wir CX_STATIC_CHECK, CX_DYNAMIC _CHECK und CX_NO_CHECK. Diese Klassen sind abgeleitet von der Superklasse CX_ROOT.
10.2.1 Ausnahmeklasse mit OTR Text Wir erzeugen eine WD-Komponente mit der in Abb. 10.12 dargestellten Struktur. Abb. 10.12 WD-Komponentenstruktur
Durch die Verwendung des View V_VIEW implementieren wir eine Suchmaske. Der Anwender gibt die aktuelle ID ein und erhält Informationen dazu. Alle Daten zu den Bewerbern sind in der Datenbanktabelle YPERSONEN gespeichert, die wir im ABAP Dictionary erstellt haben. Wenn wir in der Datenbank die gesuchte ID nicht finden, lösen wir eine Ausnahme aus und zeigen eine entsprechende Nachricht. Das View-Layout ist dargestellt in Abb. 10.13.
Abb. 10.13 View-Layout
Der Context hat die in Abb. 10.14 dargestellte Struktur. Wir haben den Knoten Search (Singleton, Kardinalität 1. . .1) definiert und das Context-Attribut ID_PERSON vom Typ ypersonen-id_person, Eingabehilfemethode Automatisch. Diesem Tabellenfeld haben wir im ABAP Dictionary die Suchhilfe YSUCHH_ID_PERSON zugewiesen. Wir verwenden dieses Context-Attribut um die gegenwärtige, vom Anwender in der Suchmaske eingegebene ID zu halten. Der Kindknoten PERSON (Singleton, Kardinalität 0. . .1) hat die DictionaryStruktur YPERSONEN und als Attribute haben wir schnell fast die gesamten
244
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
Abb. 10.14 Context-Struktur
Tabellenfelder (ohne id_person, mandt). Wir nutzen diesen Context-Knoten, um alle übereinstimmenden Daten zu der gesuchten ID zu halten. Um die ErgebnisInformationen anzuzeigen, müssen wir die Datenbindung zwischen diesem Knoten und dem UI-Element Table erzeugen. Der Anwender gibt eine ID ein und drückt den Button SUCHEN. Wenn es einen Eintrag mit dieser ID in der Datenbanktabelle YPERSONEN gibt, zeigen wir im UI-Element Table die entsprechenden Informationen. Andernfalls lösen wir eine Ausnahme aus, und die entsprechende Fehlernachricht wird angezeigt. Bevor wir mit der Ausnahmenachricht arbeiten können, müssen wir eine Ausnahmeklasse erzeugen (Abb. 10.15).
Abb. 10.15 Erzeugen einer Ausnahmeklasse
10.2
Ausnahmebehandlung
245
Wie zu sehen ist, erzeugen wir eine Ausnahmeklasse ohne Nachrichtenklasse. In diesem Fall wird die OTR als zentraler Speicherort für die Ausnahmetexte verwendet. Im Tabreiter „Texte“ erzeugen wir einen Ausnahmetext „Der Bewerber mit dieser ID: &id_bewerber& existiert nicht!“, mit der ID: YCX_NO_BEWERBER (Abb. 10.16).
Abb. 10.16 Definieren eines Ausnahmetextes
Jeder Ausnahmetext, den wir unter dem Tabreiter Texte erzeugen, besteht aus einer ID und einem dazugehörenden Text. Der Platzhalter &id_bewerber& wird zur Laufzeit durch den Inhalt der Attribute mit dem gleichen Namen, definiert unter dem Tabreiter Attribute, ersetzt (Abb. 10.17).
Abb. 10.17 Definieren von Attributen
Wenn der Anwender den SUCHEN-Button drückt, stößt das Framework die Eventhandler-Methode onactionsuchen an (Listing 10.3). Nach der Datendefinition übergeben wir den Wert des Attributs id_person an die lokale Variable lv_id_person. Durch Verwendung der Kontrollstruktur TRY – ENDTRY behandeln wir eine Ausnahme, die möglicherweise auftreten könnte. Wir verwenden Open SQL, um alle Daten aus der Datenbanktabelle YPERSONEN in die interne Tabelle lt_bewerber zu selektieren, bei denen das Feld id_person unserer gesuchten ID entspricht.
246
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
METHOD onactionsuchen. DATA obj TYPE REF TO ycx_exception_otrtext. DATA: lt_bewerber TYPE TABLE OF ypersonen, lr_node TYPE REF TO if_wd_context_node, ls_data TYPE if_v_view=>element_search, lv_id_person TYPE ypersonen-id_person. lr_node = wd_context->get_child_node( ’SEARCH’ ). lr_node->get_attribute( EXPORTING name = ’ID_PERSON’ IMPORTING value = lv_id_person ). TRY. SELECT * FROM ypersonen INTO TABLE lt_bewerber WHERE id_person = lv_id_person. IF sy-subrc = 0. DATA lr_subnode TYPE REF TO if_wd_context_node. lr_subnode = lr_node->get_child_node( ’PERSON’ ). lr_subnode->bind_table( new_items = lt_bewerber ). ELSE. RAISE EXCEPTION TYPE ycx_exception_otrtext EXPORTING textid = ycx_exception_otrtext=>ycx_no_bewerber id_bewerber = lv_id_person. ENDIF. CATCH ycx_exception_otrtext INTO obj. DATA lr_api_controller TYPE REF TO if_wd_controller. DATA lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). lr_message_manager->report_exception( message_object = obj ). ENDTRY. ENDMETHOD.
Listing 10.3 Coding der Eventhandler-Methode
Wenn wir den Datensatz in unserer Datenbanktabelle finden, versorgen wir den Kindknoten PERSON. Da in dem TRY-Block keine Ausnahme aufgetreten ist, fährt das System mit den Prozessschritten nach ENDTRY fort. Wenn andernfalls in dem TRY-Block eine Klassenbasierte Ausnahme auftritt, sucht das System nach einem Ausnahmebehandler. Durch RAISE EXCEPTION können wir eine Ausnahme explizit aus unserer WD-Methode auslösen. RAISE EXCEPTION TYPE ycx_exception_otrtext EXPORTING textid = ycx_exception_otrtext=>ycx_no_bewerber id_bewerber = lv_id_person.
Diese Ausnahme wird im CATCH Block der gleichen TRY-Kontrollstruktur abgefangen. CATCH ycx_exception_otrtext INTO obj. Weil das zusätzliche INTO spezifiziert ist, wird eine Referenz auf das Ausnahmeobjekt in obj gespeichert, wenn obj eine Objektreferenzvariable ist. Danach nutzen wir die Methode REPORT_EXCEPTION des IF_WD_ MESSAGE_MANAGER-Interface, um über eine WD-Ausnahme zu berichten. In Abb. 10.18 zeigen wir das Ergebnis. Das erste Bild zeigt die Laufzeit, zu welcher die Ausnahme in der TRY – ENDTRY-Kontrollstruktur auftritt und das
10.2
Ausnahmebehandlung
247
Abb. 10.18 Applikations-Ergebnis
zweite Bild zeigt den Fall, wenn keine Ausnahme auftritt. In dem zweiten Szenario können wir gleichzeitig das Ergebnis der Suchhilfe (erstellt im ABAP Dictionary und dem Feld id_person unserer Datenbanktabelle YPERSONEN zugeordnet) zeigen.
10.2.2 Ausnahmeklasse mit Text aus der Nachrichtenklasse Wir erzeugen die gleiche WD-Komponente, verwenden diesmal aber eine Ausnahmeklasse mit Texten aus der Nachrichtenklasse. Abbildung 10.19 zeigt die Erstellung einer Ausnahmeklasse unter Verwendung der Nachrichtenklasse. In diesem Fall ist das Interface IF_T100_MESSAGE automatisch in der Klassendefinition inkludiert. Zuerst erstellen wir eine Nachrichtenklasse (Abb. 10.20). Unter dem Tabreiter Eigenschaften dieser Ausnahmeklasse müssen wir den Namen der Nachrichtenklasse eingeben, die wir verwenden (Abb. 10.21). Wir erzeugen das gleiche Attribut ID_BEWERBER unter dem Tabreiter Attribute (Abb. 10.22).
248
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
Abb. 10.19 Erzeugung einer Ausnahmeklasse
Abb. 10.20 Nachrichtenklasse
Jede Ausnahme-ID kann zu einer Nachrichtenklasse und Nachrichten-ID gemappt werden. Um das zu erreichen, müssen wir den Button Nachrichtentext verwenden (Abb. 10.23). Wir weisen das Ausnahmeklasse-Attribut ID_BEWERBER der Nachrichtenklasse YCL_T100MSG, Nachrichtennummer 000 zu. Der Platzhalter & wird zur Laufzeit durch den Inhalt des Attributs ID_BEWERBER ersetzt. Nach der Aktivierung können wir diese Ausnahmeklasse in unserer WDKomponente verwenden. Ausnahmetexte, die auf der Nachrichtenklasse basieren, werden normalerweise auf die gleiche Weise verwendet wie die Ausnahmetexte, die OTR-Texte nutzen.
10.2
Ausnahmebehandlung
249
Abb. 10.21 Zuordnung der Nachrichtenklassen
Abb. 10.22 Klassenattribut
Wenn der Anwender den SUCHEN-Button drückt, stößt das Framework die Eventhandler-Methode onactionsuchen an, die die gleiche Struktur wie im Listing 10.3 hat. Die einzige Modifikation, die wir vornehmen müssen, ist die, den Namen der Ausnahmeklasse zu ändern, die gerufen wird, wenn eine Ausnahme auftritt (Listing 10.4).
250
10
Nachrichten, Ausnahmen und Web Dynpro ABAP
Abb. 10.23 Zuordnung von Attributen einer Ausnahmeklasse zu einer Nachricht
DATA obj TYPE REF TO ycx_exception_t100text. . . .. . .. . .. . .. RAISE EXCEPTION TYPE ycx_exception_t100text EXPORTING textid = ycx_exception_t100text=>ycx_no_bewerber id_bewerber = lv_id_person. . . .. . .. . .. CATCH ycx_exception_t100text INTO obj. . . .. . .. . .. Listing 10.4 Ausnahmebehandlung
Kapitel 11
Erstellen mehrsprachiger Applikationen
If you talk to a man in a language he understands, that goes to his head. If you talk to him in his language, that goes to his heart Nelson Mandela
Zusammenfassung Dieses Abschnitt konzentriert sich hauptsächlich auf die Erstellung von mehrsprachigen Applikationen. So können die Anwendungen, die wir realisieren, leicht internationalisiert werden, ohne dass es nötig wäre, sie umzukodieren. Es müssen lediglich einige zentrale Zeichenketten übersetzt werden. Dazu müssen wir wie folgt einige Regeln beachten: die von der ABAP Workbench angebotenen Werkzeuge benutzen, eine Originalsprache für unser Projekt bestimmen, und die Eingabe sprachspezifischer Texte in der Kodierung der Geschäftslogik vermeiden. Internationalisierung (Internationalization - I18N) ist notwendig für eine globale Business-Software. In diesem Kapitel zeigen wir einige Werkzeuge der ABAP Workbench, mit der man mehrsprachige User Interfaces erstellen kann, sowie Werkzeuge, um mehrsprachige Datensätze zu erstellen. Wenn sich ein Benutzer im SAP-System anmeldet, kann er die Anmeldesprache auswählen. Falls er dies nicht macht, wird automatisch die Anmeldesprache des Benutzerkontos verwendet (Abb. 11.1) – Transaktion SU01.
Abb. 11.1 Anmeldesprache
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_11,
251
252
11
Erstellen mehrsprachiger Applikationen
Das ist die Sprache, in der die Web-Dynpro-Anwendung (und alle anderen Entwicklungsobjekte) im Original geschrieben wurde und auch die Sprache, die das System nach dem Anmelden benutzt. Eine Liste mit allen im System installierten Sprachen kann mit der Transaktion SMLT – Sprachenmanagement angezeigt werden (Abb. 11.2).
Abb. 11.2 Transaktion: Sprachenmanagement
In unserem Beispiel können wir Englisch, Deutsch und Russisch als Anmeldesprachen benutzen, und wir können unsere Applikation aus der Originalsprache in eine dieser Sprachen übersetzen.
Tipp Es ist ratsam, alle erstellten Repository-Objekte, die für ein Projekt benötigt werden, in der Sprache zu erstellen, die ursprünglich für das Projekt festgelegt wurde. So können wir vermeiden, dass z.B. die für das Backend benötigten Elemente in Englisch erstellt werden, die Elemente für das Web Interface in Deutsch und so weiter. Weitere Informationen zu diesem Thema, Vor- und Nachteile sowie Tricks für eine gute ABAP- Programmierung finden Sie im SAP-Buch „Official ABAP- Programming Guidelines (Keller et al.)“.
ABAP Workbench bietet viele Werkzeuge, die den Erstellungsprozess für internationalisierte Applikationen vereinfachen. So erstellen wir ohne Neugestaltung oder Abwandlung WD-Applikationen, die multiple Sprachen unterstützen. Wie bereits erwähnt, enthält eine internationalisierte Applikation im Quelltext keine sprachspezifischen Textelemente. Als sprachspezifisch lassen sich z.B. folgende Texte nennen: • Texte, die z.B. für die Kennzeichnung von UI-Elementen oder für die dynamische Programmierung usw. benötigt werden; • Texte, die bei der Erstellung von Entwicklungsobjekten im ABAP Dictionary definiert wurden; • Meldungen.
11.1
Erstellung von mehrsprachigen User Interfaces
253
11.1 Erstellung von mehrsprachigen User Interfaces Wir erstellen eine einfache WD-Komponente unter Nutzung einiger der zuvor erwähnten Werkzeuge, um ohne Code-Änderungen Unterstützung für Englisch und Deutsch zu bieten. Hierzu müssen wir nur gewisse zentralisierte Strings übersetzen. Nach Änderung der Anmeldesprache (in unserem Beispiel von „de“ zu „en“) werden die Daten automatisch in der entsprechenden Sprache angezeigt. Die WD-Komponentenstruktur ist in Abb. 11.3.dargestellt. Abb. 11.3 WD-Komponentenstruktur
Im Context-View erstellen wir einen Context-Knoten namens PERSON, Kardinalität 1. . .1, Singleton, Dictionary-Struktur YPERSONEN und ein ContextAttribut namens TEXT_I18N vom Typ STRING. Context-View und View-Layout sind in Abb. 11.4 dargestellt.
Abb. 11.4 Context-Knoten und View-Layout
Wir haben keine statischen Strings für die „Text“-Eigenschaften der UI- Elemente Label und Button oder für das Caption-View-Element eingefügt. Die als Labels für das InputField-UI-Element gezeigten Strings stellen den Text des Label- Felds der in ABAP Dictionary erstellten elementaren Datenelemente dar. So repräsentiert z.B. das Label mit der ID „VORNAME_LBL“ das Label für das InputField, welches an das Attribut „VORNAME“ gebunden ist. Das Datenelement für dieses Attribut ist YPERSONEN-VORNAME. Wenn wir unsere Tabellendefinitionen ansehen,
254
11
Erstellen mehrsprachiger Applikationen
können wir erkennen, dass der grundlegende Datentyp YVORNAME ist. Aus Abb. 11.5 wird ersichtlich, dass die „Text“ Eigenschaften des Labels VORNAME_LBL keine statischen Werte enthalten. Um diesen String anzulegen, verwenden wir den in dem Datenelement YVORNAME definiertenText mit der Länge MEDIUM, z.B: „Vorname“.
Abb. 11.5 Texteigenschaften und elementare Datenelemente
11.1.1 Internationalisierung der in ABAP Dictionary definierten Datenelemente Um in ABAP Dictionary definierte Datenelemente zu internationalisieren, müssen wir die dazugehörigen Texte übersetzen. Abbildung 11.6 zeigt, auf welchem Weg wir die Übersetzung vornehmen können.
Abb. 11.6 Datenelement-Texte übersetzen
Anschließend öffnet sich ein Pop-up-Fenster mit der Frage, in welche Sprache der Text übersetzt werden soll. Wir wählen Englisch und tragen den für die Strings zu übersetzenden Text ein (Abb. 11.7).
11.1
Erstellung von mehrsprachigen User Interfaces
255
Abb. 11.7 Übersetzung der Strings
Wir wiederholen die gleichen Schritte so lange, bis alle Strings der entsprechenden elementaren Datenelemente übersetzt sind.
11.1.2 Internationalisierung von in ABAP Dictionary definierten Domänen Auf ähnliche Weise übersetzen wir die in unserer Domäne Y_LAND_DOMAENE gespeicherten Texte (Abb. 11.8). Abbildung 11.9 zeigt die Übersetzung von Festwerten für eine Domäne.
11.1.3 Internationalisierung von Text aus OTR In unserem Beispiel müssen wir einen Wert in die Text-Eigenschaft des UI-Elementes Button eingeben. Hierfür wählen wir den OTR-Text, der im SOTR_VOCABULARY_BASIC-Paket existiert (Abb. 11.10). Um unseren eigenen OTR-Text zu erstellen, können wir das Menü Springen-> Online Text Repository Browser oder die Transaktion SOTR_EDIT (Editor für OTR-Texte) verwenden.
256
11
Erstellen mehrsprachiger Applikationen
Abb. 11.8 Übersetzung Deutsch - Englisch für eine Domäne
Abb. 11.9 Übersetzung der Festwerte einer Domäne
Abbildung 11.11 zeigt, wie wir einen OTR-Text unter Verwendung des Online Text Repository Browsers erstellen können. Das im SOTR_VOCABULARY_BASIC-Paket gespeicherte Basis-Vokabular kann für alle Pakete verwendet werden, aber die erstellten OTR-Texte sind nur einmal pro Paket gespeichert. (Abb. 11.12). Um einen OTR-Text zu übersetzen, können wir Transaktion SE63 „Einstieg: Standard – Übersetzungsumfeld“ verwenden.
11.1
Erstellung von mehrsprachigen User Interfaces
Abb. 11.10 Der OTR-Text des SOTR_VOCABULARY_BASIC-Pakets
Abb. 11.11 OTR-Texte erstellen
Abb. 11.12 Unser eigendefinierter OTR-Text
257
258
11
Erstellen mehrsprachiger Applikationen
Nach der Übersetzung des Textes können wir unsere eigendefinierten OTR-Texte in der gleichen Weise verwenden wie OTR-Texte, die im SOTR_VOCABULARY_BASIC-Paket von SAP definiert wurden.
11.1.4 Internationalisierung von Texten einer Assistance-Klasse Im vorausgegangen Kapitel haben wir gesehen, wie wir Assistance-Klassen für die Arbeit mit Meldungen anwenden können. In unserem Beispiel verwenden wir die im Textpool der Assistance-Klasse gespeicherten Texte, um unseren für das Caption View Element benötigten Text mehrsprachig anzubieten. Wir erstellen eine Assistance-Klasse namens YCL_I18N_BEISPIEL. Dort definieren wir den mehrsprachig zu ändernden Text (Abb. 11.13).
Abb. 11.13 Texte einer Assistance-Klasse
Im Feld mLen müssen wir die Maximallänge des Strings eines Textsymbols spezifizieren. Wie wir bereits gesehen haben, sollte dieser Wert größer oder gleich der definierten Länge (dLen) sein. Es empfiehlt sich, einen größeren Wert zu verwenden, da wir zu dem Zeitpunkt der Design-Erstellung nicht wissen, für wie viele Sprachen wir Unterstützung bieten werden. In deutscher Sprache ist die Länge beispielweise 37. Wenn wir jedoch diesen String in eine andere Sprache übersetzen, kann der Wert größer sein. In diesem Fall wären wir nicht in der Lage, den gesamten übersetzten Text einzugeben. Die Länge ist im Textpool gespeichert. Um diesen Text aus dem Deutschen ins Englische zu übersetzen, wählen wir aus dem Menü Springen-> Übersetzung (Abb. 11.14).
Abb. 11.14 Übersetzung von Texten aus der Assistance-Klasse
11.1
Erstellung von mehrsprachigen User Interfaces
259
Anschließend realisieren wir eine Daten-Anbindung zwischen den Attributen TEXT_I18N und dem Eigenschaftstext des Caption-Elements. Wir greifen dynamisch auf den String zu, den wir gerade definiert und übersetzt haben (Listing 11.1).
METHOD wddoinit. DATA: lv_text TYPE string. lv_text = wd_assist->if_wd_component_assistance~get_text( ’001’). wd_context->set_attribute( name = ’TEXT_I18N’ value = lv_text). ENDMETHOD.
Listing 11.1 wdDoInit-Hook-Methode
Wie oben bereits erwähnt, müssen wir die Assistance-Klasse unserer Komponente zuweisen, damit wir in der Lage sind, auf die Textsymbole der Assistance-Klasse unter Verwendung des Instanz-Attributes WD_ASSIST zuzugreifen. Danach lassen wir unsere Anwendung laufen (Abb. 11.15).
Abb. 11.15 Laufzeit. Default-Sprache: Deutsch
260
11
Erstellen mehrsprachiger Applikationen
Wir ändern die Spracheinstellung auf Englisch (en) (Abb. 11.16).
Abb. 11.16 Laufzeit – Englisch (en)
11.1.5 Internationalisierung von Meldungen Wir erstellen eine Nachrichtenklasse namens YCL_I18NMSG, in der wir eine Meldung mit dem ID „000“ und dem Kurztext „Vorname wird verlangt!“ definieren. Wir möchten, dass diese Meldung angezeigt wird, wenn der Anwender den Suchen-Button anklickt. Um diese Meldung zu übersetzen, wählen wir aus dem Menü Springen>Übersetzung (Abb. 11.17).
Abb. 11.17 Übersetzung eines Kurztextes in der Nachrichtenklasse
Wenn der Anwender den Button „Suchen“ klickt, wird durch das Framework die Eventhandler-Methode onactionsuchen ausgelöst (Listing 11.2).
11.1
Erstellung von mehrsprachigen User Interfaces
261
METHOD onactionsuchen. DATA: lr_node TYPE REF TO if_wd_context_node, lv_vorname TYPE ypersonen-vorname. lr_node = wd_context->get_child_node(’PERSON’). lr_node->get_attribute( EXPORTING name = ’VORNAME’ IMPORTING value = lv_vorname ). IF lv_vorname IS INITIAL. DATA: lr_api_controller TYPE REF TO if_wd_controller, lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller-> get_message_manager( ). lr_message_manager->report_t100_message( msgid = ’YCL_I18NMSG’ msgno = ’000’ msgty = ’E’). ENDIF. ENDMETHOD.
Listing 11.2 Die Eventhandler-Methode onactionsuchen
Wir verwenden unsere Anwendung in der Originalsprache Deutsch und in Englisch (Abb. 11.18).
Abb. 11.18 Multilanguage-Meldungen
262
11
Erstellen mehrsprachiger Applikationen
Tipp Wie in den Beispielen bereits erläutert, verwenden wir für die Übersetzung von Texten Springen->Übersetzung Auf die gleiche Weise können wir Lang- oder Kurztexte aus Adobe Forms übersetzen.
11.2 Mehrsprachige Datensätze in der Datenbank In diesem Beispiel ändern wir die in den Datenbanktabellen gespeicherten Datensätze in mehrsprachige. Mit einem sehr einfachen Beispiel zeigen wir, wie wir nicht nur in der Anmeldesprache Daten in Datenbanktabellen speichern. Anschließend kreieren wir das User Interface in Web Dynpro, um zu sehen, wie wir diese Daten verarbeiten können. Wir kopieren Tabelle YEU_LAENDER und ändern die Bezeichnung in YEUL_I18N. Unser Ziel ist es, die Staatsform (political system) jedes EU-Landes nicht nur in Deutsch, sondern auch in Englisch zu speichern.
11.2.1 Unser Beispiel Bevor wir unser eigenes Beispiel erstellen, werden wir kurz die Tabellenstruktur erklären, die wir bauen werden. Wir beginnen mit der Suche nach einer Texttabelle. Eine Texttabelle endet gewöhnlich auf T und enthält für jeden Schlüssel einen erklärenden Text in mehreren Sprachen. Mit Transaktion SE11 können wir uns alle Tabellen, die auf „_T“ enden, anzeigen lassen (Abb. 11.19).
Abb. 11.19 Texttabelle suchen
Aus der angezeigten Liste wählen wir die Tabellenstruktur der Texttabelle für „Texttabelle zu Behandlung von F/S-Objekt“ aus. (Abb. 11.20).
11.2
Mehrsprachige Datensätze in der Datenbank
263
Abb. 11.20 Texttabellen-Struktur
Wie wir sehen, haben wir für jeden FSOBJANL-Key ein Feld namens SPRAS des SPRAS-Typs, zu dem der Sprachenschlüssel und die beiden Felder BEZ (Bezeichnung) und KURZBEZ (Kurztext) gehören, welche einen erklärenden Text in mehreren Sprachen enthalten. In diesem Beispiel haben wir Unterstützung für Deutsch und Englisch und somit eine Übersetzung in zwei Sprachen (E – English, D – Deutsch) für jeden Key (Abb. 11.21).
Abb. 11.21 Inhalt einer Texttabelle
Schauen wir uns die Fremdschlüssel-Beziehung an (Abb. 11.22): Wie man sieht, ist die Tabelle eine Texttabelle für Tabelle /BEV3/CHCTFSOS. Die Tabellenstruktur ist in Abb. 11.23 dargestellt. Die Tabelle /BEV3/CHCFSOS_T ist eine Texttabelle für /BEV3/CHCTFSOS. Wenn wir uns beide Tabellen näher ansehen, können wir sehen, dass die Texttabelle zusätzlich ein Sprachenschlüssel-Feld enthält sowie für jeden Schlüssel-Eintrag von
264
11
Erstellen mehrsprachiger Applikationen
Abb. 11.22 Fremdschlüssel-Beziehung
Abb. 11.23 Die Tabelle /BEV3/CHCFSOS
/BEV3/CHCTFSOS zwei zusätzliche Felder, die einen erklärenden Text in Englisch und Deutsch enthalten. Schauen wir uns nun die Struktur von Tabelle /BEV3/CHCFSOBJS an (Abb. 11.24): Für unsere Zwecke ist an diesem Beispiel das Feld FSOBJANL interessant. Wie wir sehen, ist für dieses Feld ein Fremdschlüssel für /BEV3/CHCTFSOS definiert.
11.2.2 Erstellung von Tabellen-Strukturen und Internationalisierung von Datensätzen Für unser Beispiel stellen wir die gleiche Struktur her wie vorstehend abgebildet, jedoch nur mit einem erklärenden Text zu staatsform für jedes EU-Land. Tabelle YEUL_I18N hat die gleiche Struktur wie in Abb. 11.25 dargestellt. Das Feld STAATSFORM hat einen Fremdschlüssel für Tabelle YSF_KEY definiert, welcher die ID für staatsform beinhaltet. (Abb. 11.26).
11.2
Mehrsprachige Datensätze in der Datenbank
Abb. 11.24 Struktur der Tabelle /BEV3/CHCFSOBJS
Abb. 11.25 Tabelle YEUL_I18N
Abb. 11.26 Key Table
265
266
11
Erstellen mehrsprachiger Applikationen
Die Texttabelle hat die in Abb. 11.27 gezeigte Struktur.
Abb. 11.27 Die Texttabelle
Um den staatsform-Schlüssel mit den in der Texttabelle enthaltenen Beschreibungen zu verknüpfen, müssen wir unter Verwendung eines Fremdschlüssels die Tabelle YSF_KEY_T mit der Tabelle YSF_KEY verbinden. (Abb. 11.28).
Abb. 11.28 Fremdschlüssel
Als nächstes müssen wir die Daten einpflegen, die sich auf ein Objekt beziehen und automatisch zwischen den Tabellen YSF_KEY und YSF_KEY_T verteilt werden (Abb. 11.29). Um dies zu erreichen, erstellen wir eine Pflege-View (Abb. 11.30). Rufen Sie Transaktion SE11 auf, geben Sie die Bezeichnung der neuen Pflegeview ins Feld VIEW ein und klicken Sie den CREATE-Button. Im nächsten Popup-Fenster wählen Sie, welche Ansicht erstellt werden soll. In unserem Beispiel ist dies „Pflege-View“. Tragen Sie, wie nachstehend abgebildet, die Tabellen-Namen ein
11.2
Mehrsprachige Datensätze in der Datenbank
267
Entry
Pflege-View
Abb. 11.29 Datenpflege in Tabelle YSF_KEY und YSF_KEY_T
Abb. 11.30 Pflege-View
und klicken Sie den Button „Beziehungen“. In unserem Beispiel können wir den Vorschlag akzeptieren. Abbildung 11.31 zeigt die Viewfelder.
Abb. 11.31 Viewfelder
Zur Generierung der Tabellenpflege treffen wir anschließend folgende Menüauswahl: Hilfsmittel->Tabellenpflegegenerator (Abb. 11.32). Wir gehen nun zur Pflege-View zurück und wählen aus dem Menü Hilfsmittel-> Inhalt (Abb. 11.33).
268
11
Erstellen mehrsprachiger Applikationen
Abb. 11.32 Pflege-View-Erstellung
Abb. 11.33 Inhalte eingeben
Mit dem „Neue Einträge“-Button können wir neue Datensätze (Abb. 11.34). Wir geben drei neue Staatsformen ein, die wir anschließend in die Sprache übersetzen. Hierfür wählen wir zunächst den Eintrag aus, den setzen möchten. Danach gehen wir zum Menü und treffen folgende Springen -> Übersetzung (Abb. 11.35). Auf diese Weise übersetzen wir alle Datensätze.
eingeben englische wir überAuswahl:
11.2
Mehrsprachige Datensätze in der Datenbank
269
Abb. 11.34 Neue Einträge
Abb. 11.35 Datensätze übersetzen
11.2.3 Verwendung von internationalisierten Datensätzen in Web Dynpro Durch eine Web-Dynpro-Anwendung erstellen wir ein Mini-Administrations-UserInterface für unsere Tabelle YEUL_I18N. Abbildung 11.36 zeigt View-Layout und Context-Knoten. Der Context-Knoten hat die Dictionary-Struktur YEUL_I18N. Das Resultat zur Laufzeit sehen Sie in Abb. 11.37. Um entsprechend der Anmeldesprache Werte aus der Datenbank zu wählen, erstellen wir eine Datenbank-View in ABAP Dictionary und führen eine Selektion durch, bei der spras = sy-langu ist.
270
11
Erstellen mehrsprachiger Applikationen
Abb. 11.36 View-Layout und Context-Knoten
Abb. 11.37 Internationalisierung – Datenbankeinträge
SELECT * FROM yi18n_view INTO TABLE lt_i18nv WHERE spras = sy-langu.
Wir erstellen einen Context-Knoten namens I18NSELECT, welcher als Dictionary-Struktur die View „YI18N_VIEW“ hat, welche wir in ABAP Dictionary kreiert haben (Abb. 11.38). Das Ergebnis zur Laufzeit ist in Abb. 11.39 zu sehen.
11.2
Mehrsprachige Datensätze in der Datenbank
Abb. 11.38 Datenbank-View und Context-Knoten
Abb. 11.39 Laufzeit
271
Kapitel 12
Web-Dynpro-Modell
Always do your best. What you plant now, you will harvest later Og Mandino
Zusammenfassung Dieses Kapitel präsentiert die Rolle eines Modells in einer Multikomponenten-Web-Dynpro-Anwendung, wobei nicht nur gezeigt wird, wie solch ein Modell verwendet wird, sondern auch, wie man es erstellt. Wir konzentrieren uns auf drei Arten von Modellen: Assistance-Klasse, BAPI und Web Service. Bis jetzt haben wir nur kleine Anwendungen entwickelt, um mit SQL- Anweisungen in den Methoden einer View auf die Daten einer Tabelle zuzugreifen. Diese Programmierweise ist nicht in Einklang mit dem MVC-Entwurfsmuster. Gemäß dem Model-View-Controller (MVC)-Paradigma haben Anwendungsdaten und deren Benutzerschnittstelle getrennt zu sein. Das Modell (Model)wird hierbei durch die Geschäftslogik (business logic) repräsentiert, Die Präsentation (View) enthält die Benutzerschnittstelle und die Steuerung (Controller) hat verschiedene Verantwortlichkeiten, wie die Kommunikation zwischen dem Model und View, oder Datenverarbeitung zur Laufzeit. Auf diese Weise ist es möglich, die Benutzerschnittstelle zu ändern, ohne die Geschäftslogik zu verändern, oder entsprechend die Geschäftslogik zu ändern, ohne die Benutzerschnittstelle zu ändern. Gleichzeitig können wir dieselbe Geschäftslogik für weitere Benutzerschnittstellen verwenden. Im Web Dynpro ABAP, kann das Model implementiert werden durch: • • • •
Assistance-Klasse; BAPI; WebService; Gesichtslose Komponente, etc.
Ein Web Service kann mit einer „black box“ verglichen werden, die bestimmte Funktionalitäten bietet. Diese Funktionalitäten können in einer Client-Applikation integriert sein (in unserem Fall, Web Dynpro ABAP), die den entsprechenden Web Service konsumiert. Insofern mag ein Web Service bestimmte Eingaben von der U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_12,
273
274
12
Web-Dynpro-Modell
Client-Applikation benötigen und die entsprechende Antwort liefern. Für gewöhnlich werden Web Services benutzt, um zwischen verschiedenen Plattformen zu kommunizieren. Wie zuvor erwähnt, ist eine Assistance-Klasse eine normale ABAP-Klasse, die von CL_WD_COMPONENT_ASSISTANCE erbt. Jede Web-Dynpro-Component kann eine eindeutig zugewiesene Assistance-Klasse sein, die bestimmte Vorzüge bietet, wie folgend: • Sie arbeitet mit Textsymbolen; • es ist vorteilhafter, ihre Methoden aufzurufen als jene, die in einem Web Dynpro Controller definiert sind. The Business Application Program Interfaces (BAPI) sind spezifische Methoden für Business-Objekt-Typen, die die Möglichkeit bieten, auf externe Daten und Prozesse zuzugreifen. Die gesichtslose Komponente (Faceless Component) ist eine Web-DynproKomponente, die weder View noch Window hat, das heißt, sie besitzt keinerlei Benutzerschnittstelle, aber sie kapselt Funktionalität und kann benutzt werden, um ein Modell zu bauen.
12.1 Assistance-Klasse als Modell für eine Multikomponenten-Applikation Im Grunde kann jede ABAP-Klasse als Modell benutzt werden. Die Besonderheit einer Assistance-Klasse ist, dass wir sie einer Web-Dynpro-Component zuordnen können und sie automatisch instanziiert wird, wenn die richtige Komponente aufgerufen wird. Wir erzeugen eine Assistance-Klasse namens YCL_MODEL (Abb. 12.1).
Abb. 12.1 Assistance-Klasse
In dieser Assistance-Klasse erstellen wir drei Methoden namens BEWERBER_SUCHEN, BEWERBER_AUSWAEHLEN und BEWERBER_EINTRAGEN (Abb. 12.2). Hier speichern wir den Code, den wir innerhalb der WD-Komponenten brauchen, um nach einem Bewerber zu schauen, alle Bewerber auszuwählen und Informationen über einen Bewerber in die Datenbanktabelle YPERSONEN einzufügen oder Daten aus der Tabelle zu lesen.
12.1
Assistance-Klasse als Modell für eine Multikomponenten-Applikation
275
Abb. 12.2 Methoden für die Assistance-Klasse
Vor der Implementierung unserer Methoden erzeugten wir den geringsten Level an Coding zur Abstraktion des Datenzugriffs. In diesem Fall wählen wir die Implementierung der einfachsten Datenzugriffsmethode, indem wir die klassischen ABAP-Werkzeuge einsetzen, also Funktionsbausteine, aber wir können auch andere Tools verwenden, z.B. die persistenten Objektklassen, um von der objektorientierten Programmierung (OOP) zu profitieren. Falls wir persistente Objekte nutzen möchten, um auf die Daten von der Datenbanktabelle im objektorientierten Modus zuzugreifen, können wir für unser Web-Dynpro-Projekt auf dieselbe Struktur zurückgreifen (indem wir die Assistance-Klasse als Modell nehmen). Wir müssen jedoch in diesem Fall die Funktionsbausteine durch persistente Klassen ersetzen.
Tipp Weitere Details zu persistenten Objekten findet man im SAP Press-Buch: Object Services in ABAP (Christian Assig et al.).
Einer der Funktionsbausteine wird später benutzt werden, als Endpunkt für einen BAPI. Er wird ebenfalls zur Erstellung eines Web Service dienen. Ein Funktionsbaustein (FuBa) ist eine Prozedur mit öffentlicher Schnittstelle, die innerhalb einer Funktionsgruppe erstellt wird. Um eine Funktionsgruppe zu erstellen, wählen wir Anlegen->Funktionsgruppe aus dem Kontextmenü unseres Paketnamens. Wir erzeugen eine Funktionsgruppe namens YFG_ACCESSDB. Hier implementieren wir drei FuBa namens YFM_BEWERBER_SUCHEN, YFM_BEWERBER_AUSWAEHLEN und YFM_BEWERBER_EINTRAGEN. Listing 12.1 zeigt die Implementierung von YFM_BEWERBER_SUCHEN. Die Ausnahmeklasse YCX_EXCEPTION_T100TEXTwar oben bereits definiert, als wir gesehen haben, wie wir mit den Ausnahmeklassen in WD arbeiten können. Listing 12.2 zeigt die Implementierung von YFM_BEWERBER_ AUSWAEHLEN.
276
12
Web-Dynpro-Modell
FUNCTION yfm_bewerber_suchen. *"------------------------------------------*"*"Lokale Schnittstelle: *" IMPORTING VALUE(ID_BEWERBER) TYPE YPERSONEN-ID_PERSON *" *" EXPORTING VALUE(ITAB) TYPE YTABELLENTYP *" *" RAISING YCX_EXCEPTION_T100TEXT *" *"------------------------------------------TRY. SELECT * FROM ypersonen INTO TABLE itab WHERE id_person = id_bewerber. IF sy-subrc 0. RAISE EXCEPTION TYPE ycx_exception_t100text EXPORTING textid = ycx_exception_t100text=>ycx_no_bewerber id_bewerber = id_bewerber. ENDIF. ENDTRY. ENDFUNCTION.
Listing 12.1 Implementierung von YFM_BEWERBER_SUCHEN
FUNCTION yfm_bewerber_auswaehlen. *"-------------------*"*"Lokale Schnittstelle: *" EXPORTING REFERENCE(ITAB) TYPE YTABELLENTYP *" *" RAISING YCX_EXCEPTION_T100TEXT *" *"-------------------TRY. SELECT * FROM ypersonen INTO TABLE itab. IF sy-subrc 0. RAISE EXCEPTION TYPE ycx_exception_t100text EXPORTING textid = ycx_exception_t100text=>ycx_auswaehlen_nicht _moeglich. ENDIF. ENDTRY. ENDFUNCTION.
Listing 12.2 Implementierung von YFM_BEWERBER_AUSWAEHLEN
12.1
Assistance-Klasse als Modell für eine Multikomponenten-Applikation
277
Dieser FuBa ermittelt die Daten von allen Bewerbern. Dafür erzeugen wir eine neue Message ID – 001 „Auswählen nicht möglich!“ und eine neue Exception-ID YCX_AUSWAEHLEN_NICHT_MOEGLICH mit dem Text aus der Nachrichtenklasse – message ID 001. Listing 12.3 zeigt die Implementierung von YFM_BEWERBER_EINTRAGEN. FUNCTION yfm_bewerber_eintragen. *"------------------------------------------*"*"Lokale Schnittstelle: *" IMPORTING REFERENCE(ID_BEWERBER) TYPE YPERSONEN-ID_PERSON *" " REFERENCE(VORNAME) TYPE YPERSONEN-VORNAME * REFERENCE(NACHNAME) TYPE YPERSONEN-NACHNAME *" REFERENCE(P_ALTER) TYPE YPERSONEN-P_ALTER *" REFERENCE(TELEFON) TYPE YPERSONEN-TELEFON *" " REFERENCE(ID_LAND) TYPE YPERSONEN-ID_LAND * *" RAISING YCX_EXCEPTION_T100TEXT *" *"------------------------------------------DATA wa_person TYPE ypersonen. wa_person-mandt = sy-mandt. wa_person-id_person = id_bewerber. wa_person-vorname = vorname. wa_person-nachname = nachname. wa_person-p_alter = p_alter. wa_person-telefon = telefon. wa_person-id_land = id_land. TRY. INSERT into ypersonen values wa_person. IF sy-subrc 0. RAISE EXCEPTION TYPE ycx_exception_t100text EXPORTING textid = ycx_exception_t100text=>ycx_eintragen_ nicht_moeglich. ENDIF. ENDTRY. ENDFUNCTION.
Listing 12.3 Implementierung von YFM_BEWERBER_EINTRAGEN
Dieser FuBa fügt Informationen über einen Bewerber in die Datenbanktabelle YPERSONEN ein. Hierfür erzeugen wir eine neue Message ID – 002 „Die Bewerberdaten können nicht eingegeben werden!“ und eine neue Exception ID YCX_EINTRAGEN_NICHT_MOEGLICH mit dem Text aus der Nachrichtenklasse – Message ID 002. Ein FuBa kann über Testen/Ausführengetestet werden. So können wir prüfen, ob unser FuBa korrekt läuft. Anschließend implementieren wir unsere erste Methode aus der Assistance-Klasse.
278
12
Web-Dynpro-Modell
Abbildung 12.3 zeigt die Implementierung der Methode BEWERBER_SUCHEN.
Abb. 12.3 Implementierung der Methode BEWERBER_SUCHEN
Um einen FuBa aufzurufen, können wir den Muster-Button verwenden (Abb. 12.4).
Abb. 12.4 Muster
Abbildung 12.5 zeigt die Implementierung der zweiten Methode aus unserer Assistance-Klasse. Abbildung 12.6 zeigt die Implementierung der letzten Methode unserer Assistance-Klasse. Der Class Builder liefert eine Testumgebung für Klassen. Wir testen unsere Klasse über denselben Testen/Ausführen-Button (Abb. 12.7). So erhalten wir autonome Einheiten, die unabhängig voneinander getestet werden können, bevor wir sie in größere Anwendungen integrieren. Wenn wir auf das Beispiel zurückblicken, das sich auf die Ausnahmeklasse mit OTR-Text bezieht, erkennen wir, dass das gesamte Coding in einer Methode des View Controllers integriert war. Deswegen hatten wir die Anwendungsschicht
12.1
Assistance-Klasse als Modell für eine Multikomponenten-Applikation
Abb. 12.5 Implementierung der Methode BEWERBER_AUSWAEHLEN
Abb. 12.6 Implementierung der Methode BEWERBER_EINTRAGEN
Abb. 12.7 Testen der Assistance-Klasse
279
280
12
Web-Dynpro-Modell
(application layer) nicht von der Geschäftsschicht (business layer) und von der Präsentationsschicht (presentation layer) getrennt. Wir erzeugen die Präsentationsschicht durch eine Web-Dynpro-Component. Dazu erstellen wir eine Hauptkomponente namens YM_MAIN, in welcher wir drei sekundäre Elemente benutzen: Y_AUSWAEHLEN, Y_SUCHEN und Y_EINTRAGEN (Abb. 12.8).
Abb. 12.8 WD-Komponentenstruktur
Alle Komponenten definieren dieselbe Assistance-Klasse, YCL_MODEL. Alle eventuellen Änderungen, die an der Modellklasse im Framework gemacht werden, sind für alle anderen Komponenten verfügbar, wenn sie diese Modellklasse als Assistance-Klasse definiert haben. Auf diese Weise können wir Daten zwischen Komponenten gemeinsam nutzen. Wie wir oben erwähnten, kann jede ABAP-Klasse als Modellklasse benutzt werden, aber die vom Web Dynpro Framework angebotenen Services sind nur einer Assistance-Klasse zugänglich, die von der abstrakten Klasse CL_WD_ COMPONENT_ASSISTANCE erbt. Die YM_MAIN-Komponente repräsentiert den Startpunkt dieser Anwendung; es ist die einzige Komponente, die eine Web-Dynpro-Anwendung definiert hat. Wir ordnen unsere Assistance-Klasse YCL_MODEL unseren Komponenten zu (Abb. 12.9). Das View-Layout für die Main-Komponente YM_MAIN ist in Abb. 12.10 dargestellt. Unter Verwendung des ViewContainerUIElement zeigen wir eine der Views V_AUSWAEHLEN, V_SUCHEN or V_EINTRAGEN.
12.1
Assistance-Klasse als Modell für eine Multikomponenten-Applikation
281
Abb. 12.9 Assistance-Klasse den Komponenten zugeordnet
Abb. 12.10 Das V_MAIN-Layout
Um zwischen den drei benutzten Views zu navigieren, müssen wir drei Outbound-Plugs definieren. Abbildung 12.11 zeigt die definierten Outbound-Plugs und die Struktur des Window. Bevor wir die Instanz der benutzten Komponenten erstellen können, müssen wir sie auf dem V_MAIN View Level anwenden. Wenn der Benutzer das linkToAction-UI-Element – Eintragen – drückt, triggert das Framework die Eventhandler-Methode onactioneintragen (Listing 12.4). Wie wir sehen, ist die zur Main-Komponente gehörige Instanz für die Assistance-Klasse durch die Anweisung lr_cmp_usage->create_component( assistance_class = me->wd_assist )mit der benutzten Komponenteninstanz verknüpft. Auf diese Weise gewährleisten wir, dass beide Komponenten auf dieselbe Instanz der Assistance-Klasse zugreifen. Die Eventhandler-Methoden onactionauswaehlen und onactionsuchen haben die gleiche Struktur, außer dem Namen des Outbound-Plug,der abgefeuert wird, wenn der Benutzer die entsprechenden linkToAction-UI-Elements drückt (Listing 12.5).
282
12
Web-Dynpro-Modell
Abb. 12.11 Outbound-Plugs, Window-Struktur
METHOD onactioneintragen. DATA: lr_cmp_usage TYPE REF TO if_wd_component_usage. lr_cmp_usage = wd_this->wd_cpuse_eintragen( ). IF lr_cmp_usage->has_active_component( ) IS INITIAL. lr_cmp_usage->create_component( assistance_class = me-> wd_assist ). ENDIF. wd_this->fire_op_to_v_eintragen_plg( ). ENDMETHOD.
Listing 12.4 Eventhandler-Methode
METHOD onactionsuchen . . .. . .. . .. . .. . . wd_this->fire_op_to_v_suchen_plg( ). ENDMETHOD. METHOD onactionauswaehlen. . . .. . .. . .. . .. . . wd_this->fire_op_to_v_auswaehlen_plg( ENDMETHOD.
).
Listing 12.5 Eventhandler-Methoden
Auf diese Weise erzeugen wir die Instanz der benutzten Komponente und spezifizieren die Referenz auf die aktive Instanz der Assistance-Klasse. Das V_AUSWAEHLEN-View-Layout und die Context-Struktur sind in Abb. 12.12 dargestellt.
12.1
Assistance-Klasse als Modell für eine Multikomponenten-Applikation
283
Abb. 12.12 View-Layout und Context-Struktur
Hier zeigen wir alle Daten aus unserer YPERSONEN-Datenbanktabelle. Der Knoten BEWERBER hat die Dictionary-Struktur YPERSONEN, Kardinalität 1...n, Singleton, Supply-Funktion SUPPLY_BEWERBER (Listing 12.6). METHOD supply_bewerber. wd_this->populate_node( ). ENDMETHOD.
Listing 12.6 Supply-Funktion-Methode
Wie wir sehen, rufen wir die benutzerdefinierte Methode POPULATE_NODE zum Füllen des Context-Knotens mit Werten auf. Diese Methode haben wir zu diesem Zweck erstellt. Zusätzlich bewirkt die Methode jedes Mal, wenn der Benutzer den Refresh-Button drückt, einen Update auf die im Context-Knoten befindlichen Daten. Listing 12.7 zeigt die benutzerdefinierte Methode POPULATE_NODE. Beim Aufruf der Komponente Y_AUSWAEHLEN wird die Assistance-Klasse automatisch instanziiert. Danach ist diese Instanz dann durch das Attribut WD_ASSIST verfügbar: lt_person = wd_assist->bewerber_auswaehlen( ). Auf diese Weise rufen wir die Methode bewerber_auswaehlen der AssistanceKlasse und übergeben das Resultat an die interne Tabelle lt_person. Drückt der Benutzer den Refresh-Button, triggert das Framework die Eventhandler-Methode onactionrefresh (Listing 12.8). Das View-Layout V_EINTRAGEN und die Context-Struktur werden in Abb. 12.13 dargestellt. Der Knoten BEWERBER hat die Dictionary-Struktur YPERSONEN, Kardinalität 1...1, Singleton. Mit Hilfe dieser Komponente fügen wir Daten in unsere Datenbanktabelle YPERSONENein. Wenn der Benutzer den Speichern-Button drückt, triggert das Framework die Eventhandler-Methode onactionspeichern (Listing 12.9).
284
12
Web-Dynpro-Modell
METHOD populate_node. DATA lr_node TYPE REF TO if_wd_context_node. DATA ls_data TYPE wd_this->element_bewerber. DATA lr_oref TYPE REF TO ycx_exception_t100text. DATA lt_person TYPE STANDARD TABLE OF ypersonen. lr_node = wd_context->get_child_node( ’BEWERBER’ ). TRY. lt_person = wd_assist->bewerber_auswaehlen( ). lr_node->bind_table( new_items = lt_person ). CATCH ycx_exception_t100text INTO lr_oref. DATA lr_api_controller TYPE REF TO if_wd_controller. DATA lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). lr_message_manager->report_exception( message_object = lr_oref ). ENDTRY. ENDMETHOD.
Listing 12.7 Die POPULATE_NODE-Methode
METHOD onactionrefresh. wd_this->populate_node( ). ENDMETHOD.
Listing 12.8 Die Eventhandler-Methode ONACTIONREFRESH
Abb. 12.13 View-Layout und Context-View
Wir müssen zuallererst prüfen, ob der Benutzer Werte in alle Pflichtfelder eingetragen hat. Für diesen Check benutzen wir die wdDoBeforeAction-Hook- Methode, die Kap. 7 beschriebene Struktur hat. Falls der Benutzer Werte in alle Felder eingegeben hat, rufen wir die Methode bewerber_eintragen von der Modellklasse und wir übergeben die eingefügten Werte an die Methodenparameter.
12.1
Assistance-Klasse als Modell für eine Multikomponenten-Applikation
285
wd_assist->bewerber_eintragen( vorname = lv_vorname nachname = lv_nachname p_alter = lv_alter telefon = lv_telefon id_land = lv_id_land ).
Wenn die Daten erfolgreich gespeichert wurden, informieren wir den Anwender darüber mit einer Nachricht, die in unserer Assistance-Klasse mit dem Identifikations-Symbol M01 definiert ist. Sollte sich eine Ausnahme ereignen, zeigen wir dies dem Benutzer mit einer Nachricht durch die report_exception-Methode an. „Atr_mm“ repräsentiert ein Attribut, das im Tabreiter „Attribute“ des aktuellen Views erstellt wird. Dieses ist als Bezugstyp von if_wd_message_manager deklariert. Unter Verwendung der wdDoInit-Hook-Methode übergeben wir im atr_mm-Attribut die Referenz an den Message Manager:
METHOD onactionspeichern. DATA lr_oref TYPE REF TO ycx_exception_t100text. DATA lr_node TYPE REF TO if_wd_context_node. DATA lr_element TYPE REF TO if_wd_context_element. DATA ls_data TYPE wd_this->element_bewerber. DATA: lv_vorname LIKE ls_data-vorname, lv_nachname LIKE ls_data-nachname, lv_alter LIKE ls_data-p_alter, lv_telefon LIKE ls_data-telefon, lv_id_land LIKE ls_data-id_land. lr_node = wd_context->get_child_node(’BEWERBER’). lr_element = lr_node->get_element( ). lr_element->get_static_attributes( IMPORTING static_attributes = ls_data). lv_vorname = ls_data-vorname. lv_nachname = ls_data-nachname. lv_alter = ls_data-p_alter. lv_telefon = ls_data-telefon. lv_id_land = ls_data-id_land. TRY. wd_assist->bewerber_eintragen(vorname = lv_vorname nachname = lv_nachname p_alter = lv_alter telefon = lv_telefon id_land = lv_id_land). DATA: lv_erfolg_text TYPE string. lv_erfolg_text = wd_assist->if_wd_component_assistance~get_text(’M01’). wd_this->atr_mm->report_success(message_text = lv_erfolg_text). CATCH ycx_exception_t100text INTO lr_oref. wd_this->atr_mm->report_exception(message_object = lr_oref). ENDTRY. ENDMETHOD.
Listing 12.9 Die Eventhandler-Methode onactionspeichern
286
12
Web-Dynpro-Modell
DATA lr_api_controller TYPE REF TO if_wd_controller. lr_api_controller ?= wd_this->wd_get_api( ). wd_this->atr_mm=lr_api_controller->get_message_manager( ).
Das V_SEARCH-View-Layout und die Context-Struktur werden in Abb. 12.14 dargestellt.
Abb. 12.14 View-Layout und Context-Struktur
Die Context-Struktur ist die gleiche wie für den Context, den wir zur Veranschaulichung der Ausnahmeklasse mit OTR Text realisiert haben. Drückt der Benutzer den Suchen Button, triggert das Framework die Eventhandler-Methode onactionsuchen (Listing 12.10). METHOD onactionsuchen. DATA lr_oref TYPE REF TO ycx_exception_t100text. DATA: lt_bewerber TYPE STANDARD TABLE OF ypersonen, lr_node TYPE REF TO if_wd_context_node, lv_id_bewerber TYPE ypersonen-id_person. lr_node = wd_context->get_child_node(’SUCHEN’). lr_node->get_attribute(EXPORTING name = ’ID_PERSON’ IMPORTING value = lv_id_bewerber). TRY. lt_bewerber = wd_assist->bewerber_suchen( id_bewerber = lv_id_bewerber). DATA lr_subnode TYPE REF TO if_wd_context_node. lr_subnode = lr_node->get_child_node(’PERSON’). lr_subnode->bind_table( new_items = lt_bewerber ). CATCH ycx_exception_t100text INTO lr_oref. wd_this->atr_mm->report_exception(message_object = lr_oref). ENDTRY. ENDMETHOD.
Listing 12.10 Eventhandler-Methode
12.1
Assistance-Klasse als Modell für eine Multikomponenten-Applikation
287
Wenn die Komponente Y_SUCHEN aufgerufen wird, wird die AssistanceKlasse automatisch instanziiert. Danach ist diese Instanz durch das Attribut WD_ASSIST verfügbar: lt_bewerber = wd_assist->bewerber_suchen(id_bewerber = lv_id_ bewerber).
Auf diese Weise rufen wir die Methode bewerber_suchen aus der AssistanceKlasse auf und übergeben das Resultat in die interne Tabelle lt_bewerber. Wenn sich eine Ausnahme ereignet, zeigen wir dies dem Anwender durch eine Nachricht über die report_exception-Methode. Abbildung 12.15 zeigt das Ergebnis zur Laufzeit.
Abb. 12.15 Laufzeit
288
12
Web-Dynpro-Modell
Wir können unsere Anwendung durch die Möglichkeit, einen BewerberDatensatz zu ändern, erweitern. Für die Datenbanktabelle YPERSONEN haben wir im ABAP Dictionary ein Sperrobjekt definiert. Mit diesem können wir den Zugriff auf dieselben Daten unserer Datenbanktabelle YPERSONEN mit mehr als einer WD-Applikation synchronisieren (Abb. 12.16).
WD Applikation Browser 1 Sätze ändern
WD Applikation Browser 2 Sätze ändern
YPERSONEN
Schreibzugriff gesperrt Anforderung kollidiert
Abb. 12.16 Objekte sperren
Um eine Sperre zu setzen und zu lösen, definieren wir in unserer AssistanceKlasse zwei zusätzliche Methoden, die die generierten Funktionsbausteine ENQUEUE_YPERSONEN und DEQUEUE_YPERSONENbenutzen. Hinterher rufen wir unsere definierten Methoden von unseren WD-Methoden aus jedes Mal auf, wenn wir einen oder mehrere Datensätze sperren möchten, oder gesperrte Datensätze wieder lösen möchten. Für die Durchführung einer Suche in einer Datenbanktabelle nach allen Datensätzen, die einem bestimmten Suchmuster entsprechen, benutzen wir die ABAPKlassen CL_ABAP_REGEX und CL_ABAP_MATCHER. In unserem Fall durchsuchen wir die Spalte vorname unserer Datenbanktabelle YPERSONEN, um alle Sätze zu finden, die eine gewünschte Zeichenkette enthalten. Dieser Suchwert steht in der lokalen Variablen lv_vorname (Listing 12.11). Wie zu sehen, benutzten wir die statische Methode CONTAINS der Klasse CL_ABAP_MATCHER, wobei „pattern“ das Suchmuster repräsentiert und „text“ den zu durchsuchenden Text. Das Resultat will „abap_true“ sein, wenn die Suche erfolgreich abgeschlossen wurde. cl_abap_matcher=>contains( pattern = lv_vorname text = -vorname) = abap_true.
Nach jeder erfolgreichen Suche fügen wir die entsprechenden Sätze in die interne Tabelle itabein. Danach füllen wir diese Werte in den an die Tabelle, in der die Ergebnisse angezeigt werden, gebundenen Knoten.
12.2
BAPI als Modell
289
TYPES: BEGIN OF st_person, mandt TYPE ypersonen-mandt, id_person TYPE ypersonen-id_person, vorname TYPE ypersonen-vorname, nachname TYPE ypersonen-nachname, telefon TYPE ypersonen-telefon, alter TYPE ypersonen-p_alter, id_land TYPE ypersonen-id_land, END OF st_person. DATA: it_person TYPE TABLE OF st_person, lv_vorname TYPE ypersonen-vorname. FIELD-SYMBOLS LIKE LINE OF it_person. SELECT * FROM ypersonen INTO TABLE it_person. LOOP AT it_person ASSIGNING . IF cl_abap_matcher=>contains( pattern = lv_vorname text = -vorname) = abap_true. INSERT INTO TABLE itab. ENDIF. ENDLOOP.
Listing 12.11 Suche mit CL_ABAP_MATCHER
12.2 BAPI als Modell BAPI sind Standard-SAP-Schnittstellen, als Methoden für die Business- Objekttypen definiert, die für den Geschäftsdatenaustausch zwischen SAP-Komponenten, aber auch zwischen SAP- und Non-SAP-Komponenten verwendet werden. In unserem Beispiel benutzen wir den Funktionsbaustein YFM_BEWERBER_ SUCHEN zur Erstellung eines einfachen BAPI-Beispiels, das wir als Modell in einer Web-Dynpro-Component einsetzen. Um das zu tun, sollten wir zuerst einige Änderungen auf Ebene des Funktionsbausteins vornehmen.
12.2.1 Erzeugen eines BAPI Wir erzeugen eine neue Funktionsgruppe, in der wir YFM_BEWERBER_SUCHEN kopieren und in YBAPI_YBEWERBER_SUCHENumbenennen. Für ein BAPI haben wir die Namenskonvention BAPI__<method_name>. Im Falle von suchen( ) BAPI, das die Details für den Objekttyp YBEWERBERliest, ist der Name des verknüpften Funktionsbausteins YBAPI_YBEWERBER_SUCHEN. Im Eigenschaften-Tabreiter des Funktionsbausteins aktivieren wir die Option „Remote-fähiger Baustein“ (Abb. 12.17). Anschließend erzeugen wir eine Struktur im ABAP Dictionary mit denselben Komponenten wie bei unserer Tabelle YPERSONEN (Abb. 12.18).
290
12
Web-Dynpro-Modell
Abb. 12.17 Die Option Remote-fähiger Baustein
Abb. 12.18 Struktur YBAPI_YPERSONEN
Wir benutzen diese Struktur, um unsere Parameter id_bewerber vom Typ YBAPI_YPERSONEN-ID_PERSON und itab LIKE YBAPI_YPERSONEN zu definieren. Nun müssen wir noch eine weitere Änderung durchführen, weil wir Ausnahmen nicht länger nutzen können. RAISE EXCEPTION TYPE ycx_exception_t100text EXPORTING textid = ycx_exception_t100text=>ycx_no_bewerber id_bewerber = id_bewerber.
Zwecks Rückgabe einer Nachricht, falls keine Sätze mit der angegebenen ID in der Datenbanktabelle YPERSONEN existieren, nehmen wir einen ReturnParameter, um die Ausnahmenachrichten an die rufende Anwendung rückzumelden. Mit diesem Return Parameter, basierend auf der Referenzstruktur BAPIRET2, sind wir in der Lage, alle möglichen Fehler, die auftreten können, aufzuzeichnen und zu klassifizieren.
12.2
BAPI als Modell
291
Die Struktur BAPIRET2 hat den in Abb. 12.19 dargestellten Aufbau.
Abb. 12.19 Die BAPIRET2-Struktur
Wir können diese Struktur mit Hilfe des Funktionsbausteins BALW_ BAPIRETURN_GET2 füllen (Listing 12.12). CALL FUNCTION ’BALW_BAPIRETURN_GET2’ EXPORTING type = cl = number = PAR1 = ’ ’ * PAR2 = ’ ’ * PAR3 = ’ ’ * PAR4 = ’ ’ * LOG_NO = ’ ’ * LOG_MSG_NO = ’ ’ * PARAMETER = ’ ’ * ROW = 0 * FIELD = ’ ’ * IMPORTING * RETURN = . * Listing 12.12 Muster für BALV_BAPIRETURN_GET2
Das Listing 12.13 zeigt die Struktur des Funktionsbausteins. FUNCTION ybapi_ybewerber_suchen .
292
12
Web-Dynpro-Modell
*"----------------------------------------*"*"Lokale Schnittstelle: *" IMPORTING VALUE(ID_BEWERBER) TYPE YBAPI_YPERSONEN-ID_PERSON *" *" TABLES ITAB STRUCTURE YBAPI_YPERSONEN OPTIONAL *" RETURN STRUCTURE BAPIRET2 OPTIONAL *" *"----------------------------------------DATA msg_id_bewerber LIKE sy-msgv1. CLEAR msg_id_bewerber. REFRESH: return, itab. SELECT * FROM ypersonen INTO TABLE itab WHERE id_person = id_bewerber. IF sy-subrc 0. msg_id_bewerber = id_bewerber. CALL FUNCTION ’BALW_BAPIRETURN_GET2’ EXPORTING type = ’E’ cl = ’YCL_T100MSG’ number = ’000’ par1 = msg_id_bewerber IMPORTING return = return. APPEND return. ELSE. APPEND return. ENDIF. ENDFUNCTION.
Listing 12.13 Funktionsbaustein
Anstatt eine Ausnahme auszulösen, falls wir keine Sätze mit der spezifizierten ID finden, benutzen wir den Funktionsbaustein BALW_BAPIRETURN_GET2 zum Füllen der Struktur BAPIRET2. Wir verwendeten die definierte Nachrichtenklasse YCL_T00_MSG Nummer 000, und wir haben den Parameter Platzhalter durch den vom Benutzer eingegebenen Wert für die Bewerber ID ersetzt. Nach Speichern und Aktivieren können wir unseren Funktionsbaustein freigeben. Funktionsbaustein-> Freigabe-> Freigabe. Als Resultat unserer FREIGABEAktion erhalten wir eine Meldung vom Typ YBAPI_YBEWERBER_SUCHEN. Mittels der Transaktion SWO1 (Business Object Builder: Einstieg) erstellen wir ein Objekt namens YBEWERBER (Abb. 12.20). Wir fügen eine Methode namens SUCHEN hinzu: Hilfsmittel-> APIMethoden-> Methode einfügen (Abb. 12.21).
12.2
BAPI als Modell
293
Abb. 12.20 Erstellen des Objekts YBEWERBER
Abb. 12.21 Erstellen der API-Methode
Wir müssen unser Objekt freigeben. Dazu wählen wir aus dem Menü Bearbeiten -> Freigabestatus ändern-> Objekttyp-> In modelliert. Dieselben Schritte wiederholen wir für In implementiert und In freigegeben, und ebenso für Objekttypkomponente. Nach der Freigabe des Objektes können wir es testen (Abb. 12.22).
294
12
Web-Dynpro-Modell
Abb. 12.22 Testen des BAPI
12.2.2 Verwenden des erzeugten BAPI als Modell Wir erstellen eine Web-Dynpro-Komponente namens Y_BAPI, wobei wir das erzeugte BAPI als Modell benutzen, um die erforderlichen Daten aus der Datenbanktabelle YPERSONEN zu erlangen (Abb. 12.23).
Abb. 12.23 WD-Komponentenstruktur
Nach Rechtsklick auf den Namen der WD-Komponente wählen wir aus dem Kontextmenü Anlegen-> Service-Anrufe. Der Web Dynpro Wizard öffnet sich und unterstützt beim Erstellen der Context-Struktur und Generieren einer Methode, die den erforderlichen Code für den Service Anrufe enthält. Die Schritte des Wizards sind: • Start; • Controller auswählen – wir nehmen den existierenden Controller (Abb. 12.24);
12.2
BAPI als Modell
295
Abb. 12.24 Selektion des Controllers
• Service–Typ auswählen – wir selektieren den Funktionsbaustein (Abb. 12.25);
Abb. 12.25 Selektion des Service-Typs
• Service auswählen– wir spezifizieren nur den Namen des Funktionsbausteins YBAPI_YBEWERBER_SUCHEN; die Destination box bleibt ungefüllt (leer) (Abb. 12.26). So wird der Funktionsbaustein lokal aufgerufen;
Abb. 12.26 Selektion des Service
• Kontext anpassen – hier können wir wählen, welcher Objekttyp die ServiceFunktionsparameter im WD-Controller repräsentieren soll – als Parameter, als ein Controllerattribut oder als ein Context-Knoten oder Context-Attribut (Abb. 12.27); • Methodennamen angeben – wir müssen den Namen der generierten Methode spezifizieren, die den Service ausführen soll (Abb. 12.28); • Controller generieren Nach dem letzten Schritt drücken wir den FERTIGSTELLEN-Button, und der Wizard wird beendet. Er generiert den COMPONENTCONTROLLER Context
296
12
Web-Dynpro-Modell
Abb. 12.27 Anpassen des Kontexts
Abb. 12.28 Spezifizieren des Methodennamens
und die passende Methode EXECUTE_YBAPI_YBEWERBER_SUCHEN, die den Service ausführen soll (Abb. 12.29).
Abb. 12.29 Der generierte Context und Methode
Der Context-Knoten IMPORTING enthält das ID_BEWERBER-Attribut, in welchem der Wert der gesuchten ID gespeichert ist.
12.3
Web Service
297
Der Context-Knoten CHANGING enthält die zwei Context-Knoten ITAB und RETURN. Der Context-Knoten ITAB halt die Informationen über den Bewerber mit der gesuchten ID. Der Context-Knoten RETURN hat die Struktur BAPIRET2; wir müssen sein Meldungsattribut dafür nutzen, die Rückgabemeldungen für den Anwender auf dem Bildschirm anzuzeigen. Das View-Layout hat den in Abb. 12.30 dargestellten Aufbau.
Abb. 12.30 View-Layout und Context-View
Wenn der Benutzer den Button drückt, um einen Bewerber zu suchen, triggert das Framework die Eventhandler-Methode onactionsuchen (Listing 12.14). Der Modus des BAPI-Aufrufs ist in der vom Wizard generierten Methode in COMPONENTCONTROLLERgekapselt. Wir müssen also lediglich diese Methode aufrufen. Wenn die gesuchte ID in der Datenbanktabelle YPERSONEN nicht existiert, zeigen wir die passende Fehlermeldung, die in der Attributmeldung des RETURNKnotens gespeichert ist. Abbildung 12.31 zeigt das Ergebnis zur Laufzeit.
12.3 Web Service Der Anwendungsserver (Application Server) ABAP kann ein Web Service Provider und ein benötigter Web Service sein. Abbildung 12.32 zeigt die Basisarchitektur des Web Service Framework von AS ABAP.
298
12
Web-Dynpro-Modell
METHOD onactionsuchen . wd_comp_controller->execute_ybapi_ybewerber_suchen( ). DATA: lr_bapi_node TYPE REF TO if_wd_context_node, lr_changing TYPE REF TO if_wd_context_node, lr_return TYPE REF TO if_wd_context_node. DATA lv_bapi_message TYPE bapi_msg. lr_bapi_node = wd_context->get_child_node(‘YBAPI_ YBEWERBER_SUCH‘). lr_changing = lr_bapi_node->get_child_node(‘CHANGING‘). lr_return = lr_changing->get_child_node(‘RETURN‘). lr_return->get_attribute(EXPORTING name = ’MESSAGE’ IMPORTING value = lv_bapi_message). IF lv_bapi_message IS NOT INITIAL. DATA: lr_api_controller TYPE REF TO if_wd_controller, lr_message_manager TYPE REF TO if_wd_message _manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message _manager( ). lr_message_manager->report_error_message( message_text = lv_bapi_message). ENDIF. ENDMETHOD.
Listing 12.14 Eventhandler-Methode
Abb. 12.31 Laufzeit
12.3
Web Service
299
WSDL
Discover
2
UDDI Service Directory
1
Publish
WS PROVIDER
WS CLIENT 3
Bind
Abb. 12.32 Basis der Web-Service-Framework-Architektur
Der Web Service Provider erstellt den WS und seine Definition. Danach veröffentlicht er das WSDL-Dokument in einem Universal Description Discovery and Integration (UDDI) Service Directory, oder er erstellt einen direkten Austausch des WSDL-Dokuments mit dem WS Client. Die Web Service Description Language (WSDL) ist eine spezielle Form von XML, die die von einem Client benötigten Informationen enthält, um sich mit einem Web Service Provider zu verbinden und alle benötigten Informationen zum programmtechnischen Arbeiten mit dem entsprechenden Service (z.B. Anzahl der Parameter, die dem Service übergeben werden, Struktur des zurückgegebenen Ergebnisses, Typ der benutzten Parameter). Wir können die freigegebenen Web Services in einem UDDI-Register speichern. Es gibt viele Organisationen, die Web Services kostenlos anbieten. Solche freien Web Services finden wir unter der URL http://www.xmethods.net/ve2/index.po. Die Web-Adresse des öffentlichen UDDI Service Directory für SAP können wir unter der URL http://uddi.sap.com finden. Mit der ABAP Workbench haben wir viele Optionen zum Erstellen eines Web Service (Inside-out-Typ). Wir können beispielsweise ein BAPI benutzen, einen Funktionsbaustein, eine Funktionsgruppe oder eine Schnittstellenmeldung. In unserem Fall möchten wir die gleiche Suchoption für unsere Datenbanktabelle YPERSONEN liefern. Die Implementierung eines Funktionsbausteins wird als Endpunkt eines Web Service genutzt. Nach der Implementierung des Funktionsbausteins erstellen wir die Definition des Web Service mit nur wenigen Mausklicks, testen und gebrauchen es in Web Dynpro ABAP als Modell für unsere WDKomponente. Auf WS-Sicherheit legen wir nicht das Hauptaugenmerk, denn wir erstellen nur ein kleines Beispiel, das wir zur Veranschaulichung brauchen, wie man einen Web Service im Web Dynpro ABAP gebraucht.
300
12
Web-Dynpro-Modell
12.3.1 Erstellen des Web Service Zunächst kopieren wir den für die Suche nach einem Bewerber erforderlichen Funktionsbaustein und modifzieren ihn leicht (Listing 12.15). Wir aktivieren die Option „Remote-fähiger Baustein“in den Eigenschaften des Funktionsbausteins.
FUNCTION yfm_bewerber_suchen. *"-------------------------------------------*"*"Lokale Schnittstelle: *" IMPORTING VALUE(ID_BEWERBER) TYPE YPERSONEN-ID_PERSON *" *" EXPORTING VALUE(VORNAME) TYPE YPERSONEN-VORNAME *" VALUE(NACHNAME) TYPE YPERSONEN-NACHNAME *" " VALUE(TELEFON) TYPE YPERSONEN-TELEFON * VALUE(P_ALTER) TYPE YPERSONEN-P_ALTER *" VALUE(ID_LAND) TYPE YPERSONEN-ID_LAND *" *" EXCEPTIONS NO_ID *" *"-------------------------------------------DATA wa_personen TYPE ypersonen. SELECT SINGLE vorname nachname telefon p_alter id_land INTO CORRESPONDING FIELDS OF wa_personen FROM ypersonen WHERE id_person EQ id_bewerber. IF sy-subrc 0. RAISE no_id. ENDIF. vorname = wa_personen-vorname. nachname = wa_personen-nachname. telefon = wa_personen-telefon. p_alter = wa_personen-p_alter. id_land = wa_personen-id_land. ENDFUNCTION.
Listing 12.15 Implementierung von YFM_BEWERBER_SUCHEN
Wie wir vorab erwähnt haben, können in RFC-enabled-Funktionsbausteinen keine Ausnahmeklassen verwendet werden. Aus diesem Grund nehmen wir in unserem Beispiel eine nicht-klassenbasierte Ausnahme: NO_ID. Um die Ausnahmen, die sich ereignen können, zu verwalten, könnten wir auch die BAPIRET2-Struktur ähnlich dem letzten Beispiel benutzen. Dann wandeln wir unser RFC in einen Web Service. Dafür haben wir einige Möglichkeiten, wie folgt:
12.3
Web Service
301
• Rechtsklick auf den FuBa-Namen und aus dem Kontextmenü Anlegen -> Web Servicewählen • Im Function Builder (Transaktion SE37) wählen wir aus dem Menü Hilfsmittel -> Weitere Hilfsmittel -> Web Services erzeugen Die Schritte des Wizards sind: Objekttyp – wir können den Objekttyp wählen; in unserem Fall ist der Web Service ein Service Provider (Abb. 12.33).
Abb. 12.33 Wizard-Schritt: Objekttyp
Service Provider – wir erstellen einen Service Provider für ein existentes ABAPObjekt (Inside-out) (Abb. 12.34).
Abb. 12.34 Wizard-Schritt: Service Provider
Objekttyp – hier geben wir einen Namen und eine kurze Beschreibung für unseren Web Service ein, und wir wählen den Typ des Endpunkts (Abb. 12.35).
Abb. 12.35 Wizard-Schritt: Objekttyp
Endpunkt wählen – hier können wir den Namen des FuBa eingeben, den wir als Endpunkt für unseren Web Service bestimmen. (Abb. 12.36)
302
12
Web-Dynpro-Modell
Abb. 12.36 Wizard Schritt: Endpunkt wählen
Service konfigurieren – hier wählen wir das Autorisierungsprofil. Wie zuvor erwähnt, wählen wir zum Zweck dieses Beispiels das Profil PRF_DT_IF_SEC_NO (Abb. 12.37).
Abb. 12.37 Wizard-Schritt: Service konfigurieren
Paket/Auftrag eingeben – hier müssen wir den Namen des Pakets Y_WEBDYNPRO eingeben sowie die Transportanforderung. Fertigstellen – dies ist der letzte Schritt des Wizards, wo wir darüber informiert werden, dass der Web Service mit dem gewünschten Namen nach Drücken des „Fertigstellen“ Buttons generiert wird. Als Ergebnis sehen wir die Service-Definition (Abb. 12.38).
Abb. 12.38 Die generierte Service-Definition
12.3.2 Web-Service-Konfiguration Um die notwendigen Konfigurationsaufgaben durchzuführen, benutzen wir den SOA-Manager, auf den über die Transaktion SOAMANAGER zugegriffen werden
12.3
Web Service
303
kann. Bei Verwendung von „Einzelne Web Services oder Proxys verwalten“ können wir nach unserem angelegten WS suchen und ihn konfigurieren (Abb. 12.39). Die entsprechende Option finden wir im Tabreiter „Business-Administration“.
Abb. 12.39 Nach unserem Web Service suchen
Durch Drücken des „Apply Selection“-Buttons betrachten wir die Details zu unserer Service-Definition. Über den „Konfigurationen“-Tabreiter können wir einen Service und einen Service-Endpunkt für unsere Service-Definition YWS_BEWERBER anlegen (Abb. 12.40).
Abb. 12.40 Details der Service-Definition – Konfigurationen
Jede Service-Definition hat mehr als einen Service und für jeden Service können wir mehr als einen Endpunkt anlegen. Jeder Service-Endpunkt kann einen Service in anderer Weise konfigurieren.
304
12
Web-Dynpro-Modell
12.3.3 Testen des Web Service Nach der Konfiguration unseres Endpunkts speichern wir und gehen in den Tabreiter „Übersicht“ (Abb. 12.41).
Abb. 12.41 Details zur Service-Definition – Übersicht
Von hier wählen wir den Link „WSDL-Dokument für gewähltes Binding öffnen“ und kopieren die URL-Adresse aus dem erscheinenden Fenster. Mit Selektieren des Links „Web-Service-Navigator für gewähltes Binding öffnen“ öffnet sich die Web Service Testseite und wir können unseren neu erzeugten Web Service nach Drücken des „Test“ Button ausprobieren (Abb. 12.42).
Abb. 12.42 Web Services Navigator
Falls ein Fehler passiert, müssen wir die J2EE-Serverzugriffsinformation (Hostname und eine Portnummer) konfigurieren, weil die Web-Service-Testseite (Web Services Navigator) auf dem Java-Stack läuft. Dafür können wir die Transaktion SOAMANAGER aufrufen -> Tabreiter Technische Konfiguration -> Option Systemgrundeinstellungen.
12.3
Web Service
305
Nun lässt sich der Web Service testen (Abb. 12.43).
Abb. 12.43 Testen unseres Web Service – Anforderung/Antwort
12.3.4 Inanspruchnahme des Web Service in Web Dynpro Um den angelegten Web Service in der Web-Dynpro-Applikation in Anspruch zu nehmen, müssen wir zuerst einen Proxy anlegen. Um den zu erstellen, bedienen wir uns desselben Wizards wie für das Anlegen des Web Service. Diesmal sind die Wizard-Schritte: Objekttyp – Service-Consumer (Abb. 12.44).
Abb. 12.44 Wizardschritt-Objekttyp
Quelle wählen – erlaubt die Auswahl der Quelle des WSDL-Dokuments (Abb. 12.45). Quelle wählen – hier tragen wir die URL des Web Service ein (Abb. 12.46). Die URL holen wir per copy & paste aus der SOAMANAGER-Transaction. Paket/Auftrag eingeben – wir müssen den Paketnamen eintragen, das Präfix und die Workbench-Anforderung (Abb. 12.47). Weil gleichzeitig mit der Generierung der proxyclass auch andere Entwicklungsobjekte (z.B. Dictionary-Objekte,
306
12
Web-Dynpro-Modell
Abb. 12.45 Wizardschritt – Ausgewählte Quelle
Abb. 12.46 Wizardschritt – Ausgewählte Quelle
Abb. 12.47 Wizardschritt – Paket/Auftrag eingeben
Klassen und Schnittstellen) generiert werden, wird empfohlen, diese Objekte in einem separaten Paket zu generieren (in unserem Fall: im Y_PROXY Paket). Fertigstellen– nach dem letzten Schritt generiert der Wizard den ServiceConsumer (Abb. 12.48). Die generierten Entwicklungsobjekte werden in Abb. 12.49 dargestellt. Vor dem Drücken auf den Testen-Button zum Testen des Consumer-Proxy müssen wir einen logischen Port über die Transaktion SOAMANAGERoder die alte Transaktion LPCONFIG anlegen. In der SOAMANAGER-Transaktion, im selben Fenster in dem wir nach dem Web Service gesucht haben, können wir nun nach einem Consumer-Proxy mit dem externen Namen „yws_bewerber“ suchen (Abb. 12.50).
12.3
Web Service
307
Abb. 12.48 Der Consumer-Proxy
Abb. 12.49 Generierte Entwicklungsobjekte
Mit dem Drücken des „Apply Selection“-Buttons öffnen wir das Feld, wo wir die Proxy-Definition anlegen können. Im Tabreiter „Konfigurationen“ können wir den Logischen Port anlegen. Im nächsten Schritt müssen wir die Web-Dynpro-Component erstellen, um den angelegten Client Proxy zu benutzen. Wir erzeugen eine Web-Dynpro-Component namens Y_WS_CONSUMER mit einer View namens V_VIEW und einem Default Window. Ähnlich unserem BAPI-Beispiel können wir mit Hilfe des Service Call (Anlegen-> Service-Anrufe) unseren Client Proxy in unsere WD-Applikation integrieren. Hierzu verwenden wir die Option „Proxy eines Web Service“ als
308
12
Web-Dynpro-Modell
Abb. 12.50 Suchen nach einem Consumer-Proxy
Servicetyp. Dann geben wir den Namen der Proxyklasse, die öffentliche Methode und den logischen Port ein. Während wir im letzten Beispiel zeigten, wie der Wizard zu benutzen ist, wollen wir nun zeigen, wie man den Proxy ohne Hilfe des Wizards nutzt. Falls wir komplexere Strukturen haben, kann es vorkommen, dass der Wizard nur ein Attribut generiert anstelle eines Contents mit Context-Attributen. In solch einem Fall müssen wir manuell die adäquaten Modifikationen vornehmen. Der V_VIEW-Context-View und das Layout sind in Abb. 12.51 dargestellt. Das ID_BEWERBER-Attribut ist vom Typ YPERSONEN-ID_PERSONund soll zur Pflege der ID des gesuchten Wettbewerbers dienen. Der Person-Kindknoten hat die Dictionary-Struktur YPERSONEN, sodas wir hier die Daten über den gesuchten Wettbewerber finden: seinen Vornamen, seinen Nachnamen, seine Telefonnummer, Alter und Länder-ID. Im View-Layout haben wir die UI-Elemente eingefügt: Group, InputField, Label und Table.
Abb. 12.51 Context-View und View-Layout
Wenn der Benutzer den Suchen-Button drückt, triggert das Framework die Eventhandler-Methode onactionsuchen (Listing 12.16).
12.3
Web Service
309
METHOD onactionsuchen. DATA: lr_node TYPE REF TO if_wd_context_node, lr_subnode TYPE REF TO if_wd_context_node, ls_subnode TYPE wd_this->element_person, lv_id_bewerber TYPE ypersonen-id_person. DATA: obj1 TYPE REF TO ysco_yws_bewerber, obj2 TYPE REF TO cx_ai_system_fault, ls_input TYPE ysyfm_bewerber_suchen, ls_output TYPE ysyfm_bewerber_suchenresponse. lr_node = wd_context->get_child_node(’PERSON_SUCHEN’). lr_subnode = lr_node->get_child_node(’PERSON’). lr_node->get_attribute(EXPORTING name = ’ID_BEWERBER’ IMPORTING value = lv_id_bewerber). TRY. CREATE OBJECT obj1. CATCH cx_ai_system_fault INTO obj2. ENDTRY. ls_input-id_bewerber = lv_id_bewerber. TRY. CALL METHOD obj1->yfm_bewerber_suchen EXPORTING input = ls_input IMPORTING output = ls_output. CATCH cx_ai_system_fault INTO obj2. CATCH cx_ai_application_fault . ENDTRY. IF ls_output IS INITIAL. DATA lr_api_controller TYPE REF TO if_wd_controller. DATA lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_ manager( ). lr_message_manager->report_exception(message_object = obj2). ELSE. ls_subnode-vorname = ls_output-vorname. ls_subnode-nachname = ls_output-nachname. ls_subnode-telefon = ls_output-telefon. ls_subnode-p_alter = ls_output-p_alter. ls_subnode-id_land = ls_output-id_land. lr_subnode->set_static_attributes(ls_subnode). ENDIF. ENDMETHOD.
Listing 12.16 Die Eventhandler-Methode onactionsuchen
Wenn wir Proxyobjekte in Methoden oder Programmen verwenden, können wir uns die Erzeugung des Codes mit drag & drop erleichtern (Abb. 12.52). Für den Proxy (obj1 TYPE REF TO ysco_yws_bewerber) haben wir eine Referenzvariable deklariert und zusätzlich zwei lokale Strukturen, um den Eingabeparameter (ls_input TYPE ysyfm_bewerber_suchen) zu setzen und die Rückgabe (ls_output TYPE ysyfm_bewerber_suchenresponse) zu bekommen.
310
12
Web-Dynpro-Modell
Drag & Drop
Abb. 12.52 Drag and drop zur Codegenerierung
Nach der Anlage des Proxy rufen wir ihn und übergeben die Rückgabewerte an den korrespondierenden Kindknoten „PERSON“. Zur Laufzeit haben wir (Abb. 12.53):
Abb. 12.53 Runtime
Kapitel 13
ALV und Select Options
I never know what I m going to put on the canvas. The canvas paints itself. I m just the middleman Peter Max
Zusammenfassung Die folgende Lektion beschreibt detailliert, wie die Standardkomponenten ALV und SO bei der Erstellung unserer eigenen Web-DynproAnwendungen helfen. Wir beginnen mit einem einfachen Beispiel, bei dem ALV zum Anzeigen von Daten in einer Tabelle verwendet wird, und wir schließen damit, dass wir beide Komponenten für fortgeschrittenes Suchen und Anzeigen der Suchdaten benutzen. Dabei berücksichtigen wir auch die zusätzlichen Funktionalitäten, die ALV bietet (z.B. Datenexport nach Excel). SAP List Viewer (ALV) ist ein Tool, das wir zur Anzeige von Daten in einer zweidimensionalen Tabelle, in einer hierarchisch-sequenziellen Liste oder einer Baumstruktur benutzen können. Es kann für eine große Auswahl von Applikationen verwendet werden; von klassischem Dynpro bis Web Dynpro. In userem Beispiel verwenden wir in Web Dynpro die AVL-Komponente SALV_WD_TABLE um Daten in einer zweidimensionalen Tabelle anzuzeigen. „Select Options“ bietet uns den Nutzen komplexer Suchfunktionen. Zum Beispiel verwenden wir die Komponente WDR_SELECT_OPTIONS um einen Selectionoption-Screen zu erstellen, der uns gleichzeitig vier Standard Buttons bietet: Abbrechen, Prüfen, Zurücksetzen und Übernehmen.
13.1 SAP List Viewer In diesem Unterkapitel lernen wir die Standard-Komponente SALV_WD_TABLE und ihre Vorteile kennen.
13.1.1 Einfaches ALV Beispiel Wir erstellen eine WD-Komponente, die bei Verwendung der ALV-Komponente SALV_WD_TABLE, alle Informationen über Kandidaten anzeigt. Um diese U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_13,
311
312
13
ALV und Select Options
Komponente verwenden zu können, müssen wir zunächst eine ComponentVerwendung anlegen. Abbildung 13.1 zeigt die Struktur der WD-Komponente und die Component-Verwendung.
Abb. 13.1 WD-Komponentenstruktur, Component-Verwendung
Im COMPONENTCONTROLLER erstellen wir einen Knoten PERSON mit der Dictionary-Struktur YPERSONEN, Singleton, Kardinalität 0. . .n und SupplyFunktion SUPPLY_PERSONEN (Abb. 13.2).
Abb. 13.2 Context-Knoten und Supply-Funktion
Die Struktur des View-Layout ist in Abb. 13.3 dargestellt.
Abb. 13.3 View-Layout
In unserem Beispiel haben wir uns für die Nutzung eines ViewContainerUIElements entschieden, um „Table“-Interface-View der SALV_WD_TABLE Komponente einzubauen. Wir können eine View oder eine Interface-View auch direkt in ein Window einbauen, wenn wir keine zusätzlichen UI-Elemente benötigen. Die TableInterface-View ist die zentrale View einer ALV-Komponente und repräsentiert
13.1
SAP List Viewer
313
den Container, in dem das ALV-Output angezeigt wird. Abbildung 13.4 zeigt die Window-Struktur und die gewählte Interface-View.
Abb. 13.4 Window-Struktur und Interface-Views der ALV-Komponente
Um ein Reverse-Mapping (Umgedrehtes Mapping) durchzuführen, erstellen wir zunächst eine InterfaceController-Usage (Abb. 13.5).
Abb. 13.5 InterfaceController-Usage
Als Nächstes muss der DATA-Context-Knoten mit den Values aus dem PERSON-Context-Knoten (Abb. 13.6) versorgt werden. Der Context-Knoten DATA muss die Struktur und die Daten aus ALV Output beinhalten. Die Laufzeitstruktur ist in Abb. 13.7 dargestellt. Wie wir zuvor erwähnt haben, bietet die ALV-Komponente die folgenden neuen Einsatzmöglichkeiten: • Exportieren der angezeigten Daten in Microsoft Excel durch den Export Button; • Drucken einer Version im PDF-Format durch den Druckversion Button;
314
13
ALV und Select Options
Abb. 13.6 Context-Mapping
Abb. 13.7 Laufzeitstruktur
• Einfacher Data Filter durch die Filter-Option; • Komplexe Einstellungen durch Verwendung der Settings-Option. Die Settings-Option bietet die Möglichkeit einige Spalten zu verdecken, komplexes Suchen und Filter anzulegen, den Anzeigemodus zu ändern und eine Druckversion zu erstellen. Wir können die vorgenommenen Änderungen speichern und sie dem derzeitigen Anwender als initiale View zuordnen (Abb. 13.8). Nach dem Speichern der Änderungen sehen wir das Ergebnis (Abb. 13.9).
13.1.2 ALV-Konfigurationsmodell Um ein ALV-Output zu konfigurieren, können wir folgende Einstellungen nutzen: table settings, column settings, field settings, standard function settings oder application-specific function settings.
13.1
SAP List Viewer
315
Abb. 13.8 Option Einstellungen
Abb. 13.9 ALV-Einstellungen
Durch Ausführung der Transaktion SE24 können wir die Struktur des CL_SALV_WD_CONFIG_TABLE sehen (Abb. 13.10). Hier befinden sich die Interfaces und ihre Methoden, die für die Manipulation des ALV Output verwendet werden. 13.1.2.1 Manipulieren des ALV Output: Zeilen löschen, Spalten verdecken, sortieren Wir wollen den ALV Output so manipulieren, dass nur fünf Zeilen angezeigt werden, die Table-Eigenschaft Design Alternating setzen, die Tabelle aufsteigend nach dem id_land-Feld sortieren und die ersten beiden Spalten (Mandant und ID) verdecken.
316
13
ALV und Select Options
Abb. 13.10 CL_SALV_WD_CONFIG_TABLE
Das nachstehende Beispiel zeigt, wo wir einige Änderungen vornehmen. Wir definieren eine Component-Verwendung auf V_VIEW-Level (Abb. 13.11).
Abb. 13.11 Definieren der Component-Verwendung auf View Ebene
Wir implementieren die wdDoInit-Hook-Methode (Listing 13.1). Wir haben die Methode GET_MODEL des Interface IWCI_SALV_WD_TABLE angewandt. Diese Methode hat keine Import Parameter und liefert ein komplettes Konfigurationsmodell (CL_SALV_WD_CONFIG_TABLE). Die ALV-Komponente basiert zum Teil auf der UI-Element Table. Um Table Design und die Anzahl der sichtbaren Zeilen einzustellen, verwenden
13.1
SAP List Viewer
317
METHOD wddoinit . DATA: lr_cmp_usage TYPE REF TO if_wd_component_usage, lr_salv_wd_table TYPE REF TO iwci_salv_wd_table, lr_table TYPE REF TO cl_salv_wd_config_table, lr_field TYPE REF TO cl_salv_wd_field. lr_cmp_usage = wd_this->wd_cpuse_alv_usage( ). IF lr_cmp_usage->has_active_component( ) IS INITIAL. lr_cmp_usage->create_component( ). ENDIF. lr_salv_wd_table = wd_this->wd_cpifc_alv_usage( ). lr_table = lr_salv_wd_table->get_model( ). lr_table->if_salv_wd_column_settings~delete_column( ’MANDT’ ). lr_table->if_salv_wd_column_settings~delete_column( ’ID_PERSON’). lr_table->if_salv_wd_table_settings~set_design( cl_wd_table=> e_design-alternating ). lr_table->if_salv_wd_table_settings~set_visible_row_count( 5 ). lr_field = lr_table->if_salv_wd_field_settings~get_field( ’ID_LAND’ ). lr_field->if_salv_wd_sort~create_sort_rule( ). ENDMETHOD.
Listing 13.1 Die wdDoInit-Hook-Methode
wir die Methoden set_design bzw. set_visible_row_count aus dem Interface IF_SALV_WD_TABLE_SETTINGS. Wenn wir uns die dynamische Programmierung eines Table UI-Elementes ansehen, erkennen wir, dass die Eigenschaft für das wechselweise Table Design cl_wd_table=>e_design-alternating ist und die Eigenschaft VISIBLE_ ROW_COUNT ganzzahlig ist (in unserem Fall 5). Um die zwei Spalten zu löschen, wenden wir die Methode delete_column aus dem IF_SALV_WD_COLUMN_SETTINGS-interface an. Für das Erstellen einer Sortierregel verwenden wir die Methode create_sort_rule aus dem Interface IF_SALV_WD_SORT. Die Standardregel für Sortierungen ist: sort_order =
if_salv_wd_c_sort=>sort_order_asscending
Zur Laufzeit haben wir (Abb. 13.12):
Abb. 13.12 Laufzeit
318
13
ALV und Select Options
13.1.2.2 Ändern des Zellen-Editors Wie wir wissen, bestimmt der Table-Cell-Editor einer Spalte, welcher Zelleninhalt angezeigt wird. Im Standard-Modus werden die Tabellen-Zellen durch Anwendung des UI-Elementes TextView erstellt. Für die Spalte „Europäische Länder“ ändern wir den Cell Editor. Für unser Beispiel verwenden wir ein linkToURL-UI-Element, das die Webseite öffnet, in der alle Informationen über die EU-Länder zu finden sind. Hierfür müssen wir dem untenstehenden Beispiel Coding hinzufügen. Ein linkToURL-UI-Element muss dynamisch erstellt werden. Listing 13.2 zeigt das zusätzliche Coding in der wdDoInit-Hook-Methode.
DATA: lr_column TYPE REF TO cl_salv_wd_column, lr_link_to_url TYPE REF TO cl_salv_wd_uie_link_to_url. lr_column = lr_table->if_salv_wd_column_settings~get_column( ’ID_LAND’ ). CREATE OBJECT lr_link_to_url. lr_link_to_url->set_text_fieldname( ’ID_LAND’ ). lr_link_to_url->set_reference( ’http://europa.eu/abc/ european_countries/eu_members/index_de.htm’ ). lr_column->set_cell_editor( lr_link_to_url ).
Listing 13.2 Änderung des Cell Editor
Zur Laufzeit haben wir (Abb. 13.13): 13.1.2.3 Hinzufügen eines Headers zu ALV-Tabelle Einer ALV-Tabelle kann auch ein Header hinzugefügt werden. Hierfür müssen wir die Methode CREATE_HEADER des Interfaces IF_SALV_ WD_TABLE_SETTINGS anwenden (Listing 13.3). Zur Laufzeit haben wir (Abb. 13.14): 13.1.2.4 Listenanfang und Listenende für ALV-Output festlegen Für ein ALV-Output kann man einen Listenanfang (Header Text) und ein Listenende (Footer Text) erstellen. Wie wir sehen konnten, bietet die von uns genutzte ALV-Komponente zwei Context-Knoten namens TOP_OF_LIST und END_OF_LIST. Diese Context-Knoten speichern die Daten für Header und Footer. Jeder Context-Knoten enthält ein Context-Attribut namens CONTENT des CL_SALV_FORM_ELEMENT Typs. Um auf diese Context-Knoten aus unserer View V_VIEW zugreifen zu können, müssen wir ein Context-Mapping erstellen (Abb. 13.15). Danach müssen wir das Grund-Layout definieren und die Elemente kreieren. Für unser Beispiel haben wir uns für die Verwendung des Layouts Zeilen-Typ, Klasse
13.1
SAP List Viewer
319
Abb. 13.13 Laufzeit
DATA: lr_settings_alv_table TYPE REF TO if_salv_wd_table_settings. DATA: lr_alv_header TYPE REF TO cl_salv_wd_header. lr_settings_alv_table ?= lr_table. lr_alv_header = lr_settings_alv_table->get_header( ). lr_alv_header->set_text( ’ALV Header’ ).
Listing 13.3 Header der ALV-Tabelle
Abb. 13.14 Header für ALV-Tabelle
320
13
ALV und Select Options
Abb. 13.15 Context-Mapping
CL_SALV_FORM_LAYOUT_FLOW entschieden. Wir erstellen ein Text-Element für den Header und ein Text-Element für den Footer (Listing 13.4). Abbildung 13.16 zeigt das Laufzeitresultat.
DATA lr_node_top_of_list TYPE REF TO if_wd_context_node. DATA lr_node_end_of_list TYPE REF TO if_wd_context_node. DATA lr_flow_top TYPE REF TO cl_salv_form_layout_flow. DATA lr_flow_end TYPE REF TO cl_salv_form_layout_flow. DATA lr_text_top TYPE REF TO cl_salv_form_text. DATA lr_text_end TYPE REF TO cl_salv_form_text. CREATE OBJECT lr_flow_top. lr_text_top = lr_flow_top->create_text( position = 1 text = ’Header Text’ tooltip = ’Top of list’ ). CREATE OBJECT lr_flow_end. lr_text_end = lr_flow_end->create_text( position = 1 text = ’Footer Text’ tooltip = ’End of list’ ). lr_node_top_of_list = wd_context->get_child_node( ’TOP_OF_LIST ’). lr_node_top_of_list->set_attribute( value = lr_flow_top name = ’CONTENT’ ). lr_node_end_of_list = wd_context->get_child_node( ’END_OF_LIST ’). lr_node_end_of_list->set_attribute( value = lr_flow_end name = ’CONTENT’ ). lr_table->if_salv_wd_table_settings~set_top_of_list_visible ( value = abap_true ). lr_table->if_salv_wd_table_settings~set_end_of_list_visible ( value = abap_true ).
Listing 13.4 Header und Footer für eine ALV-Tabelle
13.1
SAP List Viewer
321
Abb. 13.16 Laufzeitresultat
13.1.2.5 Hinzufügen eines selbstdefinierten UI-Elements an die ALV-Toolbar Der ALV-Toolbar, können wir unsere eigenen UI-Elemente hinzufügen. Hierfür hängen wir ein linkToAction-UI-Element an (Listing 13.5). DATA lr_linktoaction TYPE REF TO cl_salv_wd_fe_link_to_action. CREATE OBJECT lr_linktoaction. lr_linktoaction->set_text(’ Unser selbstdefinierte linkToAction ’). DATA linktoaction TYPE REF TO cl_salv_wd_function. linktoaction = lr_table>if_salv_wd_function_settings~ create_function( id = ’LTA’ ). linktoaction->set_editor( lr_linktoaction ).
Listing 13.5 Hinzufügen eines linkToAction-UI-Elements an die ALV-Toolbar
Abbildung 13.17 zeigt das Laufzeitresultat.
Abb. 13.17 Laufzeitresultat
322
13
ALV und Select Options
Um unser linkToAction Element in ein anderes UI-Element zu ändern, müssen wir den Editor-Typ des linkToAction (CL_SALV_WD_FE_LINK_TO_ACTION) in einen anderen zugelassenen Typ ändern. Zum Beispiel müssen wir für einen Editor Button nur den Class-Names ändern: CL_SALV_FE_BUTTON. Wenn dieser Link von einem Anwender angeklickt wird, müssen wir eine Eventhandler Methode anstoßen. Wie wir sehen können, haben wir keine Aktion für diesen Link definiert. Um herauszufinden welches UI-Element angeklickt wurde, nutzen wir das ON_FUNCTION Event (Ereignis). Wir erstellen eine Eventhandler-Methode namens LINKTOACTION_ACTION und wählen das Event ON_FUNCTION (Abb. 13.18). Wenn unser Link mit dem ID = ‘LTA’ angeklickt wird, wird ein Statement-Block ausgeführt (Abb. 13.19).
Abb. 13.18 Eventhandler-Methode für unsere selbstdefinierte linkToAction
Abb. 13.19 Eventhandler-Methode
13.2
Select Options
323
13.2 Select Options Wir erstellen eine WD-Komponente, die komplexe Möglichkeiten bietet, nach einem Bewerber zu suchen. Um die komplexen Suchmöglichkeiten nutzen zu können, haben wir die WDR_SELECT_OPTIONS-Komponente verwendet. Abbildung 13.20 zeigt die WD-Komponentenstruktur und die Component-Verwendung (Usage-Definition).
Abb. 13.20 Die WD Komponentenstruktur, Component-Verwendung
Wir erstellen in der Context-View den Context-Knoten PERSON mit der gleichen Struktur (Kardinalität 0. . .n, Dictionary-Struktur YPERSONEN, Singleton, ohne Supply-Funktion). Im View-Layout müssen wir ein ViewContainer-UI-Element eingeben, das für die Integration des Interface-View WND_SELECTION_SCREEN der Select Options Komponente benötigt wird. Neben diesem UI-Element brauchen wir einen Button und ein Table-UI-Element. Abbildung 13.21 zeigt Context-View und View-Layout.
Abb. 13.21 Context-View und View-Layout
324
13
ALV und Select Options
Wir definieren eine Component-Verwendung auf View-Ebene (Abb. 13.22).
Abb. 13.22 Component-Verwendung
Wir erstellen zwei View-Attribute (Abb. 13.23):
Abb. 13.23 View-Attribute
• M_HANDLER type ref to IF_WD_SELECT_OPTIONS • M_WD_SELECT_OPTIONS type ref to IWCI_WDR_SELECT_OPTIONS Wir verwenden die wdDoInit-Hook-Methode, um die benutzte Komponente WDR_SELECT_OPTIONS zu instanziieren, damit eine Range-Tabelle dynamisch erstellt und ein Selection-Screen-Feld hinzugefügt werden kann (Listing 13.6). Unter Verwendung der Methode INIT_SELECTION_SCREEN des Interface IWCI_WDR_SELECT_OPTIONS, initialisieren wir den Selection Screen. Anschließend verwenden wir die Methode CREATE_RANGE_TABLE des IF_WD_SELECT_OPTIONS-Interface für die dynamische Erstellung einer RangeTabelle. Diese Methode hat drei wichtige Parameter: I_TYPENAME Typ STRING, I_LENGTH Typ I, I_DECIMALS Typ I und einen wiederkehrenden Parameter RT_RANGE_TABLE Typ ref to DATA. Der I_TYPENAME ist nicht optional; wir nutzen ihn um das Daten-Element für die Komponenten LOW und HIGH zu spezifizieren. Die ID_PERSON hat den Datentyp YID (Abb. 13.24).
13.2
Select Options
325
METHOD wddoinit . DATA: rt_range_table TYPE REF TO data, lv_tooltip TYPE string VALUE ’Suchen nach id’, lv_abap_bool TYPE boolean VALUE abap_true, lr_componentcontroller TYPE REF TO ig_componentcontroller, lr_cmp_usage TYPE REF TO if_wd_component_usage. lr_cmp_usage = wd_this->wd_cpuse_select_options( ). IF lr_cmp_usage->has_active_component( ) IS INITIAL. lr_cmp_usage->create_component( ). ENDIF. wd_this->m_wd_select_options = wd_this->wd_cpifc_select_options( ). wd_this->m_handler = wd_this->m_wd_select_options->init_selection_screen( ). rt_range_table = wd_this->m_handler->create_range_table( i_typename =’YID’ ). wd_this->m_handler->add_selection_field( i_id =’ID_PERSON’ i_obligatory = lv_abap_bool it_result = rt_range_table i_tooltip = lv_tooltip i_value_help_type = if_wd_value_help_handler=> co_prefix_searchhelp i_value_help_id = ’YSUCHH_ID_PERSON’ ). ENDMETHOD Listing 13.6 Die wdDoInit-Hook-Methode
Eine Range-Tabelle hat vier Komponenten: SIGN, OPTION, LOW und SCREEN. Es kann als spezieller Typ der Tabelle auch im ABAP Dictionary kreiert werden.
Abb. 13.24 Datenbanktabelle YPERSONEN
326
13
ALV und Select Options
Die Methode ADD_SELECTION_FIELD des IF_WD_SELECT_OPTIONSInterface fügt ein weiteres Feld an den Selection Screen. Diese Methode hat viele Parameter, aber nur einer ist obligatorisch – I_ID. Wir haben die folgenden verwendet: • i_id Parameter vom Datentyp STRING, um die ID des Selection-Feldes zu definieren; • i_obligatory Parameter vom Datentyp ABAP_BOOL, um das Mussfeld zu setzen; • it_result vom Datentyp ref to DATA, um eine Reference zur Range-Tabelle zu erstellen; • i_tooltip vom Datentyp STRING, um eine kurze Info in Tooltip-Form zu erstellen; • i_value_help_type vom Typ IF_WD_VALUE_HELP_HANDLER=>CO_ PREFIX_NONE, um den Typ der Suchhilfe, die wir benutzen wollen zu definieren; • i_value_help_id vom Typ WDY_VALUE_HELP_ID, um den Namen der Suchhilfe zu spezifizieren oder den Namen der OVS (Object Vaue Selector), Komponente. In unserem Fall ist das Feld ID_PERSON mit dem Suchfeld namens YSUCHH_ID_PERSON verbunden. Wenn der Anwender den Suchen-Button anklickt, stößt das Framework die Eventhandler-Methode onactionsuchen an (Listing 13.7). METHOD onactionsuchen . DATA: l_node TYPE REF TO if_wd_context_node. DATA: rt_range_table TYPE REF TO data. DATA: it_ypersonen TYPE TABLE OF ypersonen. FIELD-SYMBOLS: TYPE ANY TABLE. rt_range_table = wd_this->m_handler->get_range_table_of_sel_field( i_id = ’ID_PERSON’ ). ASSIGN rt_range_table->* TO . CLEAR it_ypersonen. REFRESH it_ypersonen. SELECT * INTO CORRESPONDING FIELDS OF TABLE it_ypersonen FROM ypersonen WHERE id_person IN . l_node = wd_context->get_child_node( name = ‘PERSON‘ ). l_node->bind_elements( it_ypersonen ). ENDMETHOD
Listing 13.7 Die Eventhandler-Methode onactionsuchen
Die Methode GET_RANGE_TABLE_OF_SEL_FIELD des Interface IF_WD_ SELECT_OPTIONS hat einen Import-Parameter I_ID, vom Datentyp STRING, und sendet die Range-Tabelle für das Selektionfeld zurück – rt_range_table generic type DATA.
13.2
Select Options
327
Wir definieren ein Field-Symbol typisiert als ANY TABLE, und mit dem Dereferencing Operator de-referenzieren wir die generisch, mit Daten in unser FieldSymbol eingegebene, Data-Reference Variable „->∗“. Anschließend wählen wir alle zu unserer Suche gehörenden Datensätze und leiten diese Werte in die passenden Attribute des Context-Knotens PERSON weiter. Wir müssen die Interface-View WND_SELECTION_SCREEN in das ViewContainer-UI-Elementeinfügen. Jetzt sind wir bereit, die Anwendung laufen zu lassen (Abb. 13.25).
Abb. 13.25 Einschluss des View Interface WND_SELECTION_SCREEN
Abbildung 13.26 zeigt das Laufzeitresultat.
Abb. 13.26 Laufzeitresultat
Im Standardmodus ist die Selektionsoption das Intervall zwischen zwei Werten, aber wir können auch eine andere Selektionoption anwenden (Abb. 13.27). Wir haben gesehen, dass die Komponente WND_SELECTION_SCREEN vier weitere Buttons für vier angebotene Funktionen anbietet: • • • •
Abbrechen (Cancel); Prüfen (Check); Zurücksetzen (Reset); Übernehmen (Execute).
328
13
ALV und Select Options
Abb. 13.27 Optionen wählen
Einen dieser Buttons können wir mit der Methode SET_GLOBAL_OPTIONS des IF_WD_SELECT_OPTIONS-Interface verdecken. Diese Methode hat vier obligatorische Parameter vom Typ ABAP_BOOL (Abb. 13.28).
Abb. 13.28 Die Parameter SET_GLOBAL_OPTIONS
Wir wollen unser Beispiel ausweiten, in dem wir die Buttons ABBRECHEN, ZURÜCKSETZEN, ÜBERNEHMEN verdecken und mit dem PRÜFEN-Button die Eventhandler-Methode on_pruefenanstoßen. In diesem Fall benutzen wir nicht unseren Suchen-Button. Wir implementieren den Code in der Eventhandler-Methode on_pruefen. Zuerst müssen wir in der wdDoInit Hook-Methode SET_GLOBAL_OPTIONS ausführen (Listing 13.8). Danach erstellen wir die Eventhandler-Methode on_pruefenund wir registrieren sie zum ON_CHECK-Ereignis in der WDR_SELECT_OPTIONS Komponente (Abb. 13.29). Dieser Event wird angestoßen, wenn wir den PRÜFEN-Button betätigen. Wir kopieren das komplette Coding der onactionsuchen-Eventhandler-Methode in die on_pruefen-Eventhandler-Methode und können danach die Anwendung ausführen (Abb. 13.30).
13.2
Select Options
329
wd_this->m_handler = wd_this->m_wd_select_options->init_selection_screen( ). wd_this->m_handler->set_global_options( i_display_btn_cancel = abap_false i_display_btn_check = abap_true i_display_btn_reset = abap_false i_display_btn_execute = abap_false ). . . .. . .. . .. . .. . .. . .. . .. . . ENDMETHOD.
Listing 13.8 wdDoInit-Hook-Methode
Abb. 13.29 Registrierung des ON_CHECK-Ereignisses
Abb. 13.30 Laufzeitresultat
330
13
ALV und Select Options
Um mehr als ein Auswahlschirm (Selection Screen)-Feld zu erzeugen, müssen wir mit der wdDolnit-Hook-Methode so viele Range-Tabellen anlegen wie wir Selection Auswahlschirm-Felder benötigen. Dann müssen wir die EventhandlerMethode erweitern damit sie die gewünschten Daten selektieren kann.
13.3 ALV und Select Options In diesem Fall, benutzen wir beide Komponenten: WDR_SELECT_OPTIONS für Select Options (SO) und SALV_WD_TABLE für ALV (Abb. 13.31).
Abb. 13.31 Component-Verwendung
Wir kopieren die vorstehende WD-Komponente und benenen sie in Y_ALV_UND_SOum. Hier führen wir einige Änderungen durch: • Wir erstellen den Context-Knoten im COMPONENTCONTROLLER; • löschen das UI-Element Table und fügen ein neues ViewContainer-UI-Element ein. Dies ist nötig um die „Table“ Interface-View einzubinden; • definieren die benötigten Component-Verwendungen; • definieren die benötigten Context-Mappings; • prüfen, ob die Instanz der benutzen Komponente ALV_USAGE erstellt ist. Falls nicht, müssen wir sie erstellen. • Das View-Layout hat die in Abb. 13.32 gezeigte Struktur.
Abb. 13.32 View-Layout
13.3
ALV und Select Options
Abbildung 13.33 zeigt die Window-Struktur. Abb. 13.33 Window-Struktur
Abbildung 13.34 zeigt das Laufzeitresultat.
Abb. 13.34 Laufzeitresultat: SO und ALV
331
Kapitel 14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Learn from yesterday, live for today, hope for tomorrow. The important thing is not to stop questioning Albert Einstein
Zusammenfassung Das aktuelle Kapitel beschäftigt sich vorwiegend damit, wie Web-Dynpro-Anwendungen unter Verwendung des SAP-NetWeaver-Portals ins Portal integriert werden. Gleichzeitig zeigen wir, wie wir zwischen zwei Anwendungen über das Portal-Eventing (Event-Sender und Event-Receiver) kommunizieren können. Das SAP-NetWeaver-Portal bietet viele Möglichkeiten, um seine Inhalte zu erstellen – von Wizards und Templates bis hin zu Anwendungen, die in oder entwickelt werden. Unser Ziel ist es, eine erstellte Anwendung namens y_ui_contextualpanel ins Portal zu integrieren. Danach entwickeln wir eine Web-Dynpro-Component, die ein Portalereignis senden kann, eine Web-Dynpro-Component, die auf ein Portalereignis reagieren kann und zu guter Letzt integrieren wir die erstellten Anwendungen ins Portal. Um auf das Portal zuzugreifen, müssen wir zur Portal-Homepage navigieren (zum Beispiel URL http://hostname:50000/irj) und den Begrüßungsbildschirm zum Login benutzen. Nach einem erfolgreichen Login (mit einem Portaluser, der die passenden Berechtigungen hat) müssen wir uns mit dem Backend-ABAP-System verbinden, weil wir unsere Web-Dynpro-Anwendungen im ABAP-System entwickelt werden. Für das erste Beispiel erzeugen wir eine iView, die zur Integration unserer Anwendung benötigt wird, außerdem legen wir eine Portalrolle an und weisen sie dem Benutzer zu, der sie zum Zugriff auf die Web-Dynpro-Anwendung braucht. Um nach der Entwicklung der Web-Dynpro-Komponenten und der Integration der Anwendungen in die zwei IViews die Portal-Ereignisse ausführen zu können, erstellen wir eine Portal-Seite, weisen die iViews dieser Seite zu, die Seite wiederum der Rolle und die Rolle dem Benutzer. Um zwischen zwei Anwendungen sogar dann kommunizieren zu können, wenn diese Anwendungen nicht dieselbe Technologie nutzen oder auf verschiedenen System laufen, können wir das Portal-Eventing nutzen (Ereignis-Sender und U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_14,
333
334
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Ereignis-Empfänger), unter der Bedingung, dass die Applikationen in zwei Portal iViews integriert werden. Zur Realisierung der Anwendungen benutzen wir einen Portal-User, der alle notwendigen Autorisierungen besitzt, inklusive der Berechtigungen zum Anlegen von Verknüpfen von Rollen. In der Praxis sind solche Berechtigungen für einen einzigen User nur in Testsystemen vertretbar; in Produktivsystemen sind die Zuordnungen der Administratoren (z.B. User Administrator, Content Administrator, System Administrator) sehr genau definiert und getrennt. Gleichzeitig kann ein Benutzer ohne administrative Rollen nur solche Funktionalitäten nutzen, die ihm vom Administrator zugeordnet wurden. Tipp Für weitere Informationen zum Portal verweisen wir auf das SAP PRESS-Buch NetWeaver Portal (Niculescu et al.)
14.1 Anlegen eines Ordners Wir beginnen unsere Übung mit dem Anlegen eines Ordners, der alle nachfolgend erstellten Portal-Objekte aufnimmt. Im Portal-Katalog erstellen wir einen Ordner namens book. Um diese Operation durchzuführen, müssen wir das Kontextmenü öffnen (per Rechtsklick auf dem Ordner, unter dem wir unseren Ordner erzeugen wollen) und New -> Folder wählen. Ein Wizard öffnet sich (Abb. 14.1) und wir können das Verzeichnis anlegen.
Abb. 14.1 Anlegen eines neuen Ordners
14.2
Verbindung zum Backend-ABAP-System
335
Einige Informationen sind wie folgt einzugeben: • Folder Name – Name des angelegten Ordners. • Folder ID – eindeutige ID für den neu angelegten Ordner; • Master Language – die Originalsprache für alle nachfolgend in diesem Ordner angelegten Portalobjekte; • Description – kurze Beschreibung des neu angelegten Ordners. Nach dem Speichern der Information generiert das Framework den erzeugten book-Ordner im Portal-Katalog. Um andere Eigenschaften zu setzen, können wir den verfügbaren Wizard benutzen. Wir müssen erwähnen, dass der book-Ordner die Rechte vom übergeordneten Ordner erbt.
14.2 Verbindung zum Backend-ABAP-System Im nächsten Schritt verbinden wir uns mit dem Backend-ABAP-System. Zu diesem Zweck erstellen wir ein neues System: System Administration -> System Configuration -> System Landscape, das den System Landscape Editor öffnet. Hier navigieren wir zu unserem book-Order und öffnen das Kontextmenü durch Rechtsklick. Mittels New -> System (from template) öffnet sich ein Wizard, der die Möglichkeit bietet, ein neues System mit wenigen einfachen Schritten zu definieren (Abb. 14.2).
Abb. 14.2 Erstellung eines neuen Systems
Im ersten Wizard-Schritt müssen wir ein Template auswählen (Abb. 14.3). Im nächsten Schritt müssen wir allgemeine Eigenschaften eingeben, wie System Name, System ID, Master Language, Description (Abb. 14.4).
336
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Abb. 14.3 Auswahl des Templates
Abb. 14.4 Allgemeine Eigenschaften
Danach öffnen wir den Object Editor und konfigurieren unser System. Wir starten mit der Property Category namens Web Application Server (Web AS) (Abb. 14.5). Für die nächste Konfiguration navigieren wir zur Property Category Connector,die zur Realisierung unserer Konfiguration benötigt wird:
14.2
Verbindung zum Backend-ABAP-System
337
Abb. 14.5 Property Category – Web Application Server
, , , , ,
der SAP-Client des Backend; spezifiziert die Systemnummer, mit der wir uns verbinden wollen; spezifiziert die System-ID, mit der wir uns verbinden wollen; der Serverport; der Systemtyp.
In der nächsten Konfiguration gehen wir zu Property Category User Management (Abb. 14.6), was nötig ist, um den Log-on-Modus zu bestimmen, mit dem der Benutzer sich an unserem ABAP-Backend-System anmeldet. Als Logon-Methoden haben wir SAPLOGONTICKET verwendet.
Abb. 14.6 Property Category – User Management
338
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Jedes System muss zumindest ein System-Alias aufweisen, einen Namen, der vom Systemadministrator definiert wird und der für den Bezug zum spezifizierten System benötigt wird. Unter Verwendung des System Aliases Tool können wir einen Alias-Namen für unser ABAP-Backend-System einsetzen (Abb. 14.7).
Abb. 14.7 Anlegen eines Aliasnamens für unser ABAP-System
Nun sind wir in der Lage, unsere Systemkonfiguration mittels des Tools Connection Tests zu testen (Abb. 14.8).
Abb. 14.8 Testen der Verbindung zum ABAP System
Falls bereits eine Systemkonfiguration für unser ABAP Backend existiert, brauchen wir kein weiteres anzulegen.
14.3 Anlegen einer iView Eine iView (integrierte View) repräsentiert das kleinste Element, das wir im SAPNetWeaver-Portal anlegen können. In unserem Fall benutzen wir ein iView für
14.3
Anlegen einer iView
339
die Integration unserer Web-Dynpro-Anwendung. Um eine neue iView in unserem book-Ordner anzulegen, müssen wir zu Content Administration -> Portal Content navigieren und per Rechtsklick auf den Ordnernamen das Kontextmenü öffnen (Abb. 14.9). Das Portal Content Studio repräsentiert die zentrale Umgebung zum Erstellen des Portal-Inhalts.
Abb. 14.9 Erstellen einer iView im Book-Ordner
Mit Hilfe des Wizards können wir eine neue iView anlegen, unter Benutzung von: • • • •
iView Template; Portal Component; Web Dynpro Java Application. Wir wählen die erste Option – iView Template, weil unser Ziel die Integration der Web Dynpro ABAP Application ins Portal ist.
Im nächsten Wizard-Schritt können wir ein Template aus der vorhandenen Template-Liste wählen. Hier finden wir viele Templates, z.B. URL iView (für die Integration einer Website ins Portal), SAP Transaction (iView, mit der eine SAP-Transaktion im Portal angezeigt wird), SAP Web Dynpro iView (benötigt zur Integration einer Web Dynpro ABAP oder Java Applikation) (Abb. 14.10). Im nächsten Schritt haben wir die Möglichkeit, die iView General Properties wie folgt zu erstellen: • iView Name – der iView-Name , der im Portalkatalog angezeigt wird, etc.; • iView ID – eindeutige ID für die angelegte iView; • Master Language – die Originalsprache, in der die Eigenschaften generiert wurden; • Description – optionale Beschreibung (Abb. 14.11). Im nächsten Wizard-Schritt können wir zwischen der Integration einer WebDynpro-ABAP-Applikation und einer Web-Dynpro-Java-Applikation (Abb. 14.12) wählen. Im letzten Schritt geben wir die Parameter unserer Web-Dynpro-ABAPApplikation ein (Abb. 14.13).
340
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Abb. 14.10 Auswählen eines Templates aus der vorhandenen Template-Liste
Wenn wir den Finish-Button drücken, startet das Framework damit, die gelieferte Information zu verarbeiten und die passende iView zu generieren. Wir können unsere Web-Dynpro-Applikation durch die Wahl von Preview aus unserem Kontextmenü testen (Abb. 14.14).
14.4 Anlegen einer Rolle und Rollenzuordnung Mit einer Rolle können wir angeben, auf welche Dienste ein Benutzer oder eine Benutzergruppe zugreifen darf, und wir können definieren, welchen Inhalt im Portal der Benutzer oder die Benutzergruppe sehen darf. In diesem Beispiel legen wir eine Portalrolle an. Im nächsten Kapitel lernen wir dann, wie wir eine Rolle im ABAP-Backend-System anlegen können, um Lösch-Erlaubnis für die Datenbanktabelle YPERSONEN durch eine Web-Dynpro-Applikation zuzuteilen. Im book-Ordner legen wir eine Rolle über das Kontextmenü an, New -> Role (Abb. 14.15). Als Ergebnis generiert der Wizard eine neue Rolle: Mittels des Delta-Link-Konzepts können wir die iView unserer neuen Rolle zuweisen (Abb. 14.16).
14.4
Anlegen einer Rolle und Rollenzuordnung
341
Abb. 14.11 iView allgemeine Eigenschaften
Abb. 14.12 Web Dynpro for ABAP iView
Als Ergebnis sehen wir die erstellte Zuordnung: Danach weisen wir die erzeugte Portalrolle unserem Testbenutzer Gellert zu. Um diese Zuweisung umzusetzen, greifen wir auf User Administration -> Identity Management zu und suchen unseren Testbenutzer (Abb. 14.17). Wir selektieren den Benutzer und können als Resultat im unteren Bereich des Bildschirms die Details zum ausgewählten Benutzer sehen. Dann können wir mit dem Modify-Button, die neugeschaffene Rolle dem betreffenden Benutzer zuweisen (Abb. 14.18). Der Add-Button erlaubt uns nun, die Rolle nach der Selektion der Liste der Rollen, die dem Benutzer zugeordnet sind, anzufügen.
342
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Der Systemname
Der Name der WD Applikation (erstellt im ABAP back-end) die wir in die iView integrieren wollen
Abb. 14.13 Web-Dynpro-Parameter
Generated iView
Abb. 14.14 Testen der iView
14.5 Ausführen der Applikation innerhalb des Portals Um die Top-Level-Navigation und die Seite, die in der zugewiesenen Rolle definiert ist, zu sehen, speichern wir unsere Änderungen, melden uns ab und dann wieder an. Nach dem Login sehen wir im oberen Bereich des Bildschirms, auf der Hauptnavigationsleiste, das neue Item namens CONTEXTUALMENU-UIElement, korrespondierend zu unserer neu zugewiesenen Rolle. Abbildung 14.19 zeigt die innerhalb des Portals ausgeführte Anwendung.
14.6
Triggern eines Portalereignisses
343
Abb. 14.15 Anlegen einer Rolle
Abb. 14.16 Zuordnen der iView zur Rolle, mittels Delta-Link-Konzept
14.6 Triggern eines Portalereignisses Web Dynpro bietet durch den Portal-Manager einige Methoden, die zum Triggern von Ereignissen und zur Reaktion auf Portalereignisse verwendet werden können. Dafür können wir die Methoden der Schnittstellen IF_WD_PORTAL_INTEGRATION wie folgt verwenden: • FIRE – Trigger Portalereignis; • SUBSCRIBE_EVENT – Portalereignis-Registrierung; • UNSUBSCRIBE_EVENT – Löschen einer Portalereignis-Registrierung.
344
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Abb. 14.17 Nach einem Benutzer suchen
Abb. 14.18 Zuweisung einer Portalrolle zum Benutzer Gellert
Abb. 14.19 Im Portal ausgeführte Web-Dynpro-Anwendung
14.6
Triggern eines Portalereignisses
345
Für den Umfang dieses Beispiels wollen wir unsere zuerst angelegte Komponente wiederverwenden. In diesem Fall geben wir aber den Namen in der Web-Dynpro-Komponente ein, die das Portalereignis triggert und wir zeigen die Begrüßung in der zweiten Web-Dynpro-Komponente, die auf das Portalereignis reagiert (Abb. 14.20).
SAP NetWeaver Portal Page
Portal Events
Web-Dynpro-ABAPAnwendung– event trigger Web-Dynpro-ABAPAnwendung reacting to portal event
Abb. 14.20 Verarbeiten von Portalereignissen
Das Portal-Eventing-Konzept gilt entsprechend für die Kommunikation zwischen Anwendungen, die aus verschiedenen Technologien stammen. Mit diesem Beispiel erstellen wir die Anwendung, die das Portal-Eventing triggert und die Anwendung, die auf das Portalereignis reagiert, mit derselben Technologie, Web Dynpro ABAP. Unsere Absicht ist es, die beiden Fälle zu zeigen und, abhängig von den Erfordernissen, eine der Varianten (Trigger oder Empfänger) zu wählen – in Kombination mit einer Anwendung, die in einer anderen Technologie (Web Dynpro Java, Visual Composer, etc) entwickelt wurde. Wir beginnen mit dem Anlegen der Web-Dynpro-Component, die fähig ist, ein Portalereignis mit der FIRE-Methode auszulösen. Die Struktur dieser Komponente und das View-Layout sind in Abb. 14.21 dargestellt.
Abb. 14.21 Web-Dynpro-Komponentenstruktur und View-Layout
346
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
In der Context-View haben wir ein Context-Attribut namens „NAME“, vom Typ STRING. Wenn der Anwender den „Event trigger“ Button drückt, benutzen wir die FIRE-Methode, um ein Portalereignis zu triggern, das vom Portal danach der zweiten IView übergeben wird, welche sich für dieses Ereignis registriert hat, entsprechend die zweite Web-Dynpro-ABAP-Applikation. Auf diese Weise können die Ereignisse zwischen den iViews transportiert werden (Web Dynpro Applikationen oder Applikationen, die andere Technologien nutzen). Listing 14.1 zeigt das Coding der Eventhandler-Methode onactionevent_trigger. METHOD onactionevent_trigger . DATA lv_name TYPE string. wd_context->get_attribute( EXPORTING name = ‘NAME‘ IMPORTING value = lv_name ). DATA:lr_api_component TYPE REF TO if_wd_component, lr_portal_manager TYPE REF TO if_wd_portal_integration. lr_api_component = wd_comp_controller->wd_get_api( ). lr_portal_manager = lr_api_component->get_portal_manager( ). lr_portal_manager->fire( portal_event_namespace = ’sap.example’ portal_event_name = ’person_name’ portal_event_parameter = lv_name ). ENDMETHOD.
Listing 14.1 Eventhandler-Methode onactionevent_trigger
Wie wir sehen, benutzen wir nach der Übergabe des Wertes des Context-Attributs in die lokale Variable LV_NAME die FIRE-Methode der IF_WD_PORTAL_INTEGRATION Schnittstelle, um das Portalereignis mit dem Namen „person_name“ auszulösen. Diese Methode hat drei Importparameter vom Typ STRING: • PORTAL_EVENT_NAMESPACE – Namensraum, in dem das Ereignis gespeichert ist; • PORTAL_EVENT_NAME – Name des Ereignisses; • PORTAL_EVENT_PARAMETER – Parameter. • Diese Werte müssen mit der Ereignis-Empfänger-Anwendung übereinstimmen. Web Dynpro Wizard bietet den notwendigen Support für die Arbeit mit Portalereignissen (Abb. 14.22).
Abb. 14.22 Web Dynpro Wizard und Portal Manager
14.7
Reaktion auf ein Portalereignis
347
14.7 Reaktion auf ein Portalereignis Nun erzeugen wir gerade die Web-Dynpro-Anwendung, die fähig ist, auf das von der ersten IView im Portal getriggerte Ereignis zu reagieren. Die Struktur dieser Komponente, das View-Layout und die Context-View sind dargestellt in Abb. 14.23.
Abb. 14.23 Web-Dynpro-Komponentenstruktur, View-Layout und Context-View
In der Context-View brauchen wir nur das Context-Attribut „NAME“, von dem wir den Wert in Verbindung mit einer WILLKOMMEN-Zeichenkette übergeben. Um unsere Web Dynpro Applikation für ein Portalereignis zu registrieren, müssen wir die SUBSCRIBE_EVENT-Methode derselben Schnittstelle IF_WD_PORTAL_INTEGRATION benutzen. Diese Methode soll innerhalb der wdDoInit-Hook-Methode verwendet werden (Listing 14.2). METHOD wddoinit . DATA lr_api_component TYPE REF TO if_wd_component. DATA lr_portal_manager TYPE REF TO if_wd_portal_integration. lr_api_component = wd_comp_controller->wd_get_api( ). lr_portal_manager = lr_api_component->get_portal_manager( ). DATA lr_api_controller TYPE REF TO if_wd_view_controller. lr_api_controller ?= wd_this->wd_get_api( ). lr_portal_manager->subscribe_event( portal_event_namespace = ’sap.example’ portal_event_name = ’person_name’ view = lr_api_controller action = ’EVENT_RECEIVER’ ). ENDMETHOD.
Listing 14.2 Die wdDoInit-Hook-Methode
Die SUBSCRIBE_EVENT Methode hat drei Parameter vom Typ STRING und einen Parameter vom Bezugstyp IF_WD_VIEW_CONTROLLER. Wie wir sehen, benötigt diese Methode nicht nur die Spezifikation des Namensraums (namespace), den Namen des Ereignisses und die View, sondern auch den Namen der Aktion, die nach dem Auftreten des Ereignisses aufgerufen wird. Wir haben eine Aktion namens „EVENT_RECEIVER“ erstellt. Die Eventhandler-Methode ist in Listing 14.3 dargestellt.
348
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
METHOD onactionevent_receiver . DATA lv_event_name TYPE string. DATA lv_event_parameter TYPE string. lv_event_name = wdevent->get_string( name = ’PORTAL_EVENT_NAME’ ). IF lv_event_name = ’person_name’. lv_event_parameter = wdevent->get_string( name = ’PORTAL_EVENT _PARAMETER’). CONCATENATE ’WILLKOMMEN’ lv_event_parameter INTO lv_event_parameter SEPARATED BY space. wd_context->set_attribute( name = ’NAME’ value = lv_event_parameter ). ENDIF. ENDMETHOD.
Listing 14.3 Die Eventhandler-Methode onactionevent_receiver
Mit Verwendung der Methode GET_STRING (Parameter: PORTAL_ EVENT_NAME) übergeben wir den Wert des Portalereignisnamens in die lokale Variable lv_event_name. Danach müssen wir den Parameterwert erhalten, sofern die lokale Variable den Wert „person_name“ hat (unser definierter Ereignisname). Per Methode GET_STRING (Parameter: PORTAL_EVENT_PARAMETER) können wir den Parameter des Portalereignisses dem Aktions-Parameter WDEVENT und an unsere lokale Variable lv_event_parameter übergeben. Im letzten Schritt erstellen wir die Begrüßung und übergeben diesen Wert im Context-Attribut.
14.8 Anlegen einer Seite (Page) In diesem Fall müssen die zwei iViews auf demselben Bildschirm erscheinen. Dies ist der Grund, warum wir eine Seite (Page) benutzen. In einer Portalseite können wir iViews oder andere Portalseiten einfügen und wir können ein passendes Layout setzen. Um eine Seite in unserem book-Ordner unterzubringen, klicken wir rechts auf den Ordnernamen und wählen aus dem Kontextmenü New -> Page. Ein Wizard führt uns durch die notwendigen Schritte zur Erstellung unserer ersten Portalseite. Im ersten Schritt müssen wir die Seiteneigenschaften eingeben (Abb. 14.24). Im nächsten Schritt müssen wir das Seitentemplate wählen, auf dessen Basis die neue Portalseite gründet (hier haben wir „Default Page Template“ gewählt) und im letzten Schritt, vor OVERVIEWund SAVE, wählen wir das der Seite zugeordnete Layout. Dieses Layout bestimmt, wie der Inhalt angeordnet wird (Abb. 14.25). In unserem book-Ordner legen wir zwei iViews an, die wir zur Integration unserer zwei erstellten Web-Dynpro-Applikationen brauchen. Abbildung 14.26 zeigt die Struktur des book-Ordners.
14.8
Anlegen einer Seite (Page)
Abb. 14.24 Wizard-Schritt: Seiteneigenschaften
Abb. 14.25 Wizard-Schritt: Seitenlayout
Portal Role
iViews
Portal Page
Abb. 14.26 Struktur des book-Ordners
349
350
14
Integration einer Web-Dynpro-Applikation ins SAP-NetWeaver-Portal
Nach der Anlage der iView-Seite müssen wir lediglich noch die beiden iViews zuweisen: Event sender und Event receiver an unsere Portalseite namens „Portal event“. Zur Ausführung dieser Operation benutzen wir das delta-link-Konzept, welches wir erstmals angewendet haben, als wir die iView der Rolle zugewiesen haben. Nun sind wir in der Lage, den Page Content zu sehen (Abb. 14.27).
Abb. 14.27 Page Content
14.9 Ausführen der Anwendung, die die Portalereignisse verarbeitet Alles was wir noch tun müssen ist, die Portalseite unserer Rolle zuzuweisen (durch das delta-link-Konzept) und einen logoff und ein neues Login innerhalb des Portals durchzuführen. Abbildung 14.28 zeigt das Ergebnis zur Laufzeit.
Abb. 14.28 Laufzeit
14.9
Ausführen der Anwendung, die die Portalereignisse verarbeitet
351
Drag & Drop der iView von einer Spalte zu einer anderen
Abb. 14.29 Page Layout
Falls wir die Anzeige der zwei iViews innerhalb der Seite anders anordnen möchten, können wir das Page Layout verwenden. Wir können auch die Entwürfe mit Drag & Drop ändern und die iViews, die den Inhalt definieren, neu anordnen (Abb. 14.29).
Kapitel 15
Web Dynpro und Berechtigung
Only when you will realize that you have wings and understand what they are for you will be able to learn how to fly Marie-Suzanne Labelle
Zusammenfassung Basierend auf dem RBAC-Verfahren (Role Based Access Control, deutsch: rollenbasierte Zugriffskontrolle) stellen wir den SAP R/3rollenbasierten Berechtigungsmodus vor. Demnach kann ein Benutzer über eine Anzahl von Rollen verfügen, die ihm die Berechtigung erteilen, auf bestimmte Ressourcen des Systems zuzugreifen. Unter diesem Gesichtspunkt werden wir Entwicklungsobjekte erstellen, mit denen man dem Benutzer die Möglichkeit gewähren kann, auf Datensätze einer Datenbank zuzugreifen, und wir werden in Web Dynpro ABAP die Deklaration AUTHORITY-CHECK verwenden, um die Berechtigung des aktuellen Benutzers zu prüfen. Für alleinstehende, nicht in einem Portal integrierte Web Dynpro Applikationen soll das Sicherheitskonzept in der Applikation programmiert werden. Für Applikationen die innerhalb des Portals laufen, können wir das Portalsicherheitskonzept zur Authentifizierung und Zugangsautorisierung zur Applikation nutzen. Die Art und Weise, wie wir das tun können hängt von der speziellen Situation ab. Zum Beispiel können wir in dem Portal die Autorisierung für den dem Anwender anzubietenden Inhalt definieren. Aber wir können nicht die Autorisierung für die Backend Applikation selbst definieren. Diese Art der Autorisierung soll im Backend vorgenommen werden, mittels Entwicklungsobjekten wie Autorisierungsfelder, Autorisierungsobjekte usw. Um zu überprüfen, welche Funktionen von dem Anwender ausgeführt werden können oder auf welche Objekte er zugreifen darf, können wir im Backend, mittels einer Web Dynpro Applikation, Statements wie AUTHORITY-CHECK verwenden. Diese Statements sind auf der Programmebene in unserer Applikation implementiert oder in dem Model, das wir für unsere Applikation verwenden. Nun erstellen wir ein ganz einfaches Beispiel, um zu zeigen, wie wir ein Autorisierungsobjekt in einer Web-Dynpro-Component verwenden können, um die Autorisation des gegenwärtigen Anwenders zu prüfen und den Zugriff zu der Open SQL Aktion delete für unsere Datenbanktabelle YPERSONEN zu gewähren. Wir
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_15,
353
354
15
Web Dynpro und Berechtigung
nehmen einen User Administrator und einen Profile Administrator um die Objektklasse, das Autorisierungsobjekt und die Rolle zu erzeugen und die weisen diese erstellte Rolle unserem Testanwender Gellert zu. Wir erzeugen die Web- DynproComponent und überprüfen mittels dieses Testanwenders seine Rechte die erwähnte Aktion delete auszuführen (Abb. 15.1). Berechtigung zum Löschen der Sätze 004– Löschen der Sätze 004– 100 aus der YPERSONEN Datenbanktabelle
Benutzer Bi
Bx
Test-benutzer „Gellert“
Rollen ytest_role Rx Ry
Permissions -> Berechtigung: Klasse, Objekt, Felder BO − ytest _ auth
B – Benutzer R – Rolle (Einzel und sammeln) BO – Berechtigungsobjekte BF – Berechtigungsfeld BOK – Berechtigung Objektklasse
BF: ACTVT YAF_PERSON BOn
BFt
BOK
Abb. 15.1 Der Zusammenhang Benutzer – Rolle – Berechtigung, für unser Beispiel
Ein Autorisierungsobjekt wird verwendet, um die Berechtigung des Anwenders für spezielle Aktivitäten zu prüfen. Normalerweise sind diese Autorisierungen mit Autorisierungsprofilen kombiniert und diese Profile werden Rollen zugewiesen. Dann kann eine Rolle (Einzelrolle oder Sammelrolle) einem Anwender/Benutzer zugewiesen werden und alle Autorisationsänderungen betreffen dann alle Anwender, welche die betreffende Rolle zugewiesen haben. Der Sinn dieses Kapitel ist dem Leser eine allgemeine Vorstellung über das Autorisierungskonzept im SAP R/3 zu geben und über die Art und Weise der Anwendung dieses Konzepts, um sichere Web Dynpro Applikationen zu erstellen. Aus diesem Grund wählten wir ein Beispiel, in welchem wir alle erforderlichen Entwicklungselemente erzeugen können, auch wenn in der Praxis diese Anforderungen nur gelegentlich vorkommen. SAP bietet eine große Anzahl von Autorisierungsobjekten und Vordrucken, welche wir anwenden und entsprechend unseren Anforderungen einstellen können. In den meisten Fällen verwenden wir Autorisierungsgruppen (erweiterte Autorisierung für bestimmte Objekte) und Autorisierungsobjekte wie S_TABU_DIS, S_TABU_LINE, um Zugriff auf Tabellen zu gewähren. Wir haben bereits eine Autorisierungsgruppe in Kap. 11 verwendet, als wir eine Tabellenpflege
15.1
Rollenbasierte Zugriffskontrollmodell – RBAC
355
erstellt haben. In diesem Beispiel wählten wir aus der Autorisierungsgruppenliste ,&NC&‘ (keine Sicherheit) und wir sahen, dass dieses Autorisierungsobjekt als S_TABU_DIS vordefiniert wurde. Wir können ein Autorisierungsobjekt über das Menü Hilfsmittel -> Berechtigungsgruppe zuordnen einem View und einer transparenten Tabelle – erstellt im ABAP Dictionary – zuweisen. Weil wir in unserem Fall nur einem Anwender die Möglichkeit anbieten bestimmte Sätze aus der Tabelle YPERSONEN zu löschen, hat die Verwendung der Autorisierungsgruppe keine Bedeutung. Ein anderer Grund für die Verwendung der Autorisierungsgruppe in dem Beispiel war es, die Basiselemente voranzubringen, ohne Eingaben in die privaten Objektfelder und gleichzeitig das Berechtigungsfeld ACTVT zu präsentieren, dem wir beim Arbeiten mit Web Dynpro Anwendungen oft begegnen, wenn wir die Berechtigung für verschiedene Aktivitäten mit Tabellen prüfen.
Tipp Für weitere Details zum SAP Autorisierungskonzept verweisen wir auf das Buch SAP Authorization System von IBM Business Consulting Services.
15.1 Rollenbasierte Zugriffskontrollmodell – RBAC Das an der Basis des dargestellten Konzepts stehende Modell ist das Rollenbasierende Zugriffs Modell – Role Based Access Control, ein Zugriffskontrollmodell, das gegenwärtig benutzt wird, um sichere Systeme zu entwickeln. Dieses Modell wurde erstmals publik gemacht durch Ferraiolo und Kuhn, im Jahre 1992 (the 15th National Computer Security Conference, 1992, Baltimore MD, pages 554 – 563), in einer Form die dem Anwender den Zugriff auf Ressourcen durch die Verwendung von Rollen und Genehmigungen erlaubt und in welcher die Rollen Genehmigungen von anderen Rollen erben können. Verschiedene Formen des rollenbasierende Zugriffs Modell – Role Based Access Control – wurden in einer Vielzahl gewerblicher Systeme erzeugt und implementiert. Nachstehend stellen wir eine erweiterte Form des RBAC Modells vor. Modell Name: Rollenbasierende Zugriffs Modell – Role Based Access Control Kontext: Jede Umgebung, in welcher wir den Zugriff auf Ressourcen basierend auf den Anwenderrollen kontrollieren müssen. Problem: Wie können wir den Anwendern in Übereinstimmung mit Ihren Rollen Rechte zuweisen, so dass jeder Anwender nur die notwendige Autorisation hat, um seine Pflichten zu erfüllen? Lösung: In Abb. 15.2 wird ein Modell für den Rollenbasierende Zugriffs Modell – Role Based Access Control – dargestellt. Wir werden dieses Konzept in Bezug auf den Application Server ABAP erklären. Die Klasse „User“ stellt den Benutzer dar, der versucht den Zugriff auf geschützte Objekte (Transaktionen, Programme, Services) zu erhalten und die Klasse „Role“
356
15
Web Dynpro und Berechtigung
Abb. 15.2 Das Rollenbasierende Zugriffs Modell – Role Based Access Control – Schumacher et al. [10]
stellt die Benutzer Rollen dar. Eine Rolle kann eine einzelne oder eine zusammengesetzte Rolle sein. Die zusammengesetzte Rolle kann nur einzelne Rollen beinhalten und die einzelne Rolle kann zum Beispiel das Logon Menü für den Benutzer und die Autorisationsobjekte enthalten. SAP bietet eine große Anzahl einzelner Rollen zur Verwendung an, aber wir können auch unsere eigenen erstellen. Klasse „Rights“ beschreibt die Zugriffsart (löschen, schreiben usw.). Jeder Anwender kann zu einer oder mehreren Gruppen gehören. Durch die Klasse „Session“ wird das Prinzip des „niedrigsten Privilegs“ implementiert in Übereinstimmung mit den – für jede Session – notwendigen Privilegien, die der Anwender braucht, um seinen Pflichten nachzukommen. In unserem in Abb. 15.1 dargestelltem Beispiel erzeugt das Profil Administrator eine einzelne Rolle YTEST_ROLE, weist diesem das Autorisationsobjekt YTEST_AUTH zu, pflegt die Felder und generiert das Autorisationsprofil. Unser Testanwender Gellert versucht in der Datenbank YPERSONEN eine Löschoperation durchzuführen, aber ihm wurde die YTEST_ROLE noch nicht zugewiesen. Deshalb hat er nicht die Autorisation diese Operation durchzuführen. Erst nachdem der User Administrator ihm diese Rolle zugewiesen hat, kann er die Löschoperation für die Datenbanksätze innerhalb des Bereichs 004 – 100 durchführen. Wir haben eine Trennung zwischen der Rolle Administrator und den Rechten des Administrators. Neben dieser grundsätzlichen Teilung gibt es weitere Szenarios die verwendet werden können. Applikationen: J2EE, SAP NetWeaver, Oracle, etc.
15.2 Berechtigung Objektklasse Ein oder mehrere Berechtigungsobjekte sollen einer Klasse zugewiesen werden. Um eine neue Klasse zu erzeugen, können wir von dem Bildschirm „Pflege der Berechtigungsobjekte“ (Transaktion SU21), den ANLEGEN Button nutzen (Abb. 15.3).
15.4
Berechtigungsfeld
357
Abb. 15.3 Berechtigung Objektklasse
15.3 Berechtigungsobjekt Nach der Erzeugung der Klasse können wir ein Berechtigungsobjekt direkt in der erstellten Klasse (Abb. 15.4) erzeugen oder wir können zuerst eine Berechtigung Objektklasse kreieren und dann das Objekt der erstellten Klasse zuweisen (Abb. 15.5).
15.4 Berechtigungsfeld Ein Berechtigungsobjekt kann maximal 10 Berechtigungsfelder enthalten. Diese Felder können aus einer Liste existierender Berechtigungsfelder (Aktivitäten, Aktionen etc.) ausgewählt werden oder wir können unser eigenes Berechtigungsfeld erzeugen. Abb. 15.6 zeigt die Struktur des Berechtigungobjekts namens YTEST_AUTH. Wir haben uns entschieden ein Feld namens ACTVT hinzuzufügen, weil wir eine Aktivität überprüfen müssen. Die möglichen Aktivitäten die geschützt werden können sind in der Tabelle TACT gespeichert, welche eine 1. . .CN Schlüssel Relation zur Tabelle TACTZ hat und eine txt Beziehung mit dem Tabelle TACTT. In der Tabelle TACTT werden die Aktivitäten Beschreibungen gespeichert und in
358
15
Web Dynpro und Berechtigung
Abb. 15.4 Ein Berechtigungsobjekt anlegen
Abb. 15.5 Zuweisung eines Berechtigungsobjekts zu einer Klasse
15.4
Berechtigungsfeld
359
Abb. 15.6 Definierung des Berechtigungsfelds
der Tabelle TACTZ sind die gültigen Aktivitäten für jedes Berechtigungsobjekt gespeichert (Abb. 15.7).
Abb. 15.7 Tabelle TACT und einige seiner zugehörigen Tabellen
Die Struktur der Tabelle TACT ist dargestellt in Abb. 15.8. Wie wir sehen enthält diese Tabelle alle Aktivitäten, die wir nutzen können (Abb. 15.9). Aus dem „Liste der Berechtigungsfelder“ Bildschirm können wir den Button „Neues Berechtigungsfeld“ verwenden oder wir können die Transaktion SU20nutzen, um zu der Liste der Autorisationsfelder zu navigieren (Abb. 15.10). Hier haben wir ein neues Feld namens YAF_PERSON erzeugt (Abb. 15.11). Dann speichern wir das neu erzeugte Feld und gehen zurück zu unserem Berechtigungsobjekt. Hier fügen wir YAF_PERSON durch die Verwendung der „Zulässige
360
Abb. 15.8 Tabelle TACT
Abb. 15.9 Aktionen aus der Tabelle TACT
Abb. 15.10 Liste der Berechtigungsfelder
15
Web Dynpro und Berechtigung
15.4
Berechtigungsfeld
361
Abb. 15.11 Berechtigungsfeld
Aktivitäten“ am Ende des Bildschirms ein. Wir wählen die Löschen Aktivität aus der Aktivitätsliste (Abb. 15.12). Falls wir dieses Autorisationsobjekt künftig wieder verwenden möchten, können wir weitere Aktivitäten ankreuzen. Für unsere Anforderung nutzen wir nur die Löschen Aktivität.
Abb. 15.12 Definieren der Aktivitäten
362
15
Web Dynpro und Berechtigung
15.5 Erzeugen einer Einzelrolle und ändern seiner Berechtigungdaten Nach der Erstellung des Berechtigungsobjekts, erzeugen wir eine Einzelrolle durch Verwendung der Transaktion PFCG (Abb. 15.13).
Abb. 15.13 Erzeugen einer neuen Einzelrolle
Danach ändern wir die Autorisationsdaten für die neu erstellte Rolle. Um das zu realisieren, verwenden wir den Tabreiter „Berechtigungen“. Das Areal „Berechtigungsdaten pflegen und Profile generieren“ und den „Berechtigungsdaten ändern“ Button (Abb. 15.14).
Abb. 15.14 Berechtigungsdaten Ändern für eine Rolle
Durch die Verwendung des Tabreiters „Menü“ können wir Teile aus dem Anwender Menü definieren, die in SAP Easy Access gesehen werden können. Weil unsere
15.6
Anlegen der Web-Dynpro-Component
363
Autorisation keine neue Transaktion oder andere Objekte benötigt, verwenden wir diesen Tabreiter nicht. Durch die Verwendung des Tabs „Benutzer“ können wir dem Anwender eine neue Rolle zuweisen. Wir werden diese Option nicht verwenden, aber wir werden später die neu erstellte Rolle zu unserem Testbenutzer hinzufügen. In diesem Fall, möchten wir kein Template zum generieren eines Autorisierungsprofils benutzen. Aus diesem Grund wählen wir aus dem Pop-up Fenster den Button „Keine Vorlage auswählen“ (Abb. 15.15).
Abb. 15.15 Auswahl des Template-Fensters
Im Rahmen unseres Beispiels wählen wir unser Berechtigungsobjekt manuell. Wir drücken den „Manuell“-Button und geben den Namen des gerade angelegten Berechtigungsobjekts an (Abb. 15.16). Danach wählen wir die in der Liste gefundene Aktivität – „LÖSCHEN“ (Abb. 15.17). Danach wählen wir das Intervall der IDs, in der die spezifizierte LÖSCHEN Aktion zur Durchführung freigegeben ist (Abb. 15.18). Wir generieren das Autorisierungsprofil durch Drücken des Generieren Buttons. Als Ergebnis können wir unser Profil sehen, das die Berechtigung zum Löschen von Daten aus der Datenbanktabelle YPERSONEN ermöglicht – Sätze von 004 bis zu 100 (Abb. 15.19).
15.6 Anlegen der Web-Dynpro-Component Dann erstellen wir eine Web-Dynpro-Component namens Y_BERECHTIGUNG. Die Komponentenstruktur ist dargestellt in Abb. 15.20.
364
15
Web Dynpro und Berechtigung
Abb. 15.16 Manuelle Selektion der Berechtigung
Abb. 15.17 Auswahl der LÖSCHEN Aktivität
Abb. 15.18 Volle Autorisierung für IDs
Mit dieser WD-Komponente suchen wir nach einem Satz in der Datenbanktabelle YPERSONEN. Wir können einen Datensatz auch löschen, falls uns die Berechtigung zum Durchführen der gewünschten Aktivität vorliegt.
15.6
Anlegen der Web-Dynpro-Component
365
Abb. 15.19 Generierung des Profils
Abb. 15.20 WD Komponentenstruktur
Das View-Layout und die Context-Viewstruktur sind aufgeführt in Abb. 15.21.
Abb. 15.21 Context-Struktur und View-Layout
366
15
Web Dynpro und Berechtigung
15.6.1 Prüfen der Autorisierung des aktuellen Benutzers Wenn der Anwender den Löschen Button klickt, triggert das Framework die Eventhandler-Methode onactionloeschen (Listing 15.1). METHOD onactionloeschen. DATA: lt_candidate TYPE TABLE OF ypersonen, lr_node TYPE REF TO if_wd_context_node, lv_id_person TYPE yid. DATA lr_api_controller TYPE REF TO if_wd_controller. DATA lr_message_manager TYPE REF TO if_wd_message_manager. lr_api_controller ?= wd_this->wd_get_api( ). lr_message_manager = lr_api_controller->get_message_manager( ). lr_node = wd_context->get_child_node( ’LOESCHEN’ ). lr_node->get_attribute( EXPORTING name = ’ID_PERSON’ IMPORTING value = lv_id_person ). AUTHORITY-CHECK OBJECT ’YTEST_AUTH’ ID ’ACTVT’ FIELD ’06’ ID ’YAF_PERSON’ FIELD lv_id_person. IF sy-subrc EQ 0. DELETE FROM ypersonen WHERE id_person = lv_id_person. IF sy-subrc EQ 0. lr_message_manager->report_t100_message( msgid = ’YCL_T100MSG’ msgno = ’004’ msgty = ’S’ ). ENDIF. ELSE. lr_message_manager->report_t100_message( msgid = ’YCL_T100MSG’ msgno = ’003’ msgty = ’E’ ). ENDIF. ENDMETHOD. Listing 15.1 Die onactionloeschen Eventhandler-Methode
Wie wir sehen, haben wir eine Berchtigungsprüfung vor der Durchführung der Löschen Aktion vorgenommen. AUTHORITY-CHECK OBJECT ’YTEST_AUTH’ ID ’ACTVT’ FIELD ’06’ ID ’YAF_PERSON’ FIELD lv_id_person.
In diesem Fall prüfen wir die Berechtigung des aktuellen Benutzers. Wir können Minimum 1 und Maximum 10 Berchtigungsfelder mit festgelegten IDs haben. In diesem Fall haben wir das ACTVT und unser selbsterstelltes Berchtigungsfeld YAF_PERSON. Für jedes Berechtigungsfeld können wir einen zu prüfenden Wert eingeben, oder wir verwenden das zusätzliche DUMMY um die
15.6
Anlegen der Web-Dynpro-Component
367
Prüfung des entsprechenden Feldes zu vermeiden. Die Prüfung ist nur dann erfolgreich, wenn alle Bedingungen erfüllt sind: das Feld ACTVT (Aktivitäten) mit dem erlaubten Wert 06 (Löschen) UND das Feld YAF_PERSON dessen erlaubter Wert einer der IDs von 004 bis 100 ist. Wenn die Prüfung erfolgreich ist, ist sy-subrc = 0; ansonsten ist es auf einen Wert ungleich 0 gesetzt. 4 – Autorisierungs Check nicht erfolgreichl; 12 – Keine Autorisierung wurde im Autorisierungs Objekt gefunden; 24 – Falsche Autorisierungsfelder oder eine falsche Anzahl von Autorisierungs Feldern. In der Nachrichtenklasse YCL_T100MSG, haben wir zwei Meldungen mit den IDs 003 und 004 angelegt, die zur Anzeige der Erfolgsmeldung notwendig sind, oder der Fehlermeldungen, wenn die Aktion nicht erlaubt wird. Wir haben eine Rolle YTEST_ROLE angelgt, aber wir haben diese nicht mit unserem Benutzer verknüpft. Aus diesem Grund sind wir zur Laufzeit nicht berechtigt, den Satz mit der ID “004” zu löschen. Abbildung 15.22 zeigt die Benutzerschnittstelle zur Laufzeit.
Abb. 15.22 Laufzeit
Falls wir als Entwickler keine bestimmte Berechtigung haben, um die verlangten Aufgaben zu erfüllen, behelfen wir uns mit der Transaktion SU53, um herauszufinden, welche Berechtigung fehlt und den Administrator darüber zu informieren. Nach Erhalt der Ausnahmemeldung, die durch eine fehlende Berechtigung ausgelöst wird, ermitteln wir mit SU53 die entsprechenden Informationen und machen einen Screenshot für den Administrator. Wenn wir beispielsweise die Transaktion SE11 benutzen wollen, uns dafür aber die passende Berechtigung fehlt, erfahren wir in der Transaktion SU53 die Objektklasse, das Berechtigungsobjekt und das Berechtigungsfeld, welche wir brauchen (Abb. 15.23). Die Transaktion ST01 bietet die Möglichkeit, einen Systemtrace zu erzeugen, um die fehlenden Berechtigungsobjekte zu ermitteln.
Abb. 15.23 Fehlgeschlagene Berechtigungsprüfung
368
15
Web Dynpro und Berechtigung
15.6.2 Anbinden der Benutzer-Rolle und Ausführen der Applikation Zur Durchführung der Löschen Aktion müssen wir die angelegte Rolle dem User zuordnen, der sie für diese Aktion braucht (in unserem Fall der Testbenutzer Gellert). Mit der Transaktion SU01können wir Benutzer Master Records verändern, (z.B. ändern, sperren oder entsperren, Passwort ändern), Benutzer Master Records löschen oder einen neuen Benutzer anlegen (direkt oder über das Kopieren eines vorhandenen) (Abb. 15.24).
Abb. 15.24 Benutzerpflege
Im Tabreiter „Rollen“ können wir unsere angelegte Rolle YTEST_ROLE dem Testbenutzer zuordnen (Abb. 15.25).
Abb. 15.25 Zuordnen der Rolle „YTEST_ROLE“ zum Testuser
Wir führen unsere Web-Dynpro-Anwendung erneut aus. Die Berechtigungen werden aktiv und unser Testbenutzer kann die Lösch-Aktion für die Datensätze 004-010 in der Datenbanktabelle YPERSONEN durchführen (Abb. 15.26). Falls wir versuchen, einen Datensatz außerhalb des Intervalls 004 – 100 zu löschen, bekommen wir diesselbe „Keine Berechtigung“ Nachricht. In diesem Fall wird die Berechtigungsprüfung vorgenommen und das System vergleicht die vom Administrator eingegebenen Werte im Autorisierungsprofil mit denjenigen, die das
15.6
Anlegen der Web-Dynpro-Component
369
Abb. 15.26 Dem Benutzer ist das Löschen von Daten erlaubt
Programm erfordert. Als Resultat ist die Prüfung nicht erfolgreich und er ist nicht berechtigt, diese Aufgabe durchzuführen (Abb. 15.27). Record out of range 004-100
Abb. 15.27 Löschen eines Datensatzes außerhalb des Intervalls 004–100
Andere Berechtigungsobjekte, die wir oft prüfen, sind: S_TCODE – um die Berechtigung zu prüfen, eine Transaktion auszuführen S_PROGRAM – um die Berechtigung zu prüfen, ein Programm auszuführen S_RFC – um die Berechtigung zu prüfen, ein RFC auszuführen S_TABU_DIS – für Tabellenpflege
Kapitel 16
Web Dynpro ABAP Mind Map
Teachers open the door. You enter by yourself. Chinese proverb
Zusammenfassung Der Schwerpunkt dieses Kapitels ist die Vorstellung von Mind Map, basierend auf den in diesem Buch beschriebenen Elementen. Es kann eine effektive Hilfe beim Zusammenfassen der Kenntnisse sein und das Lernen von Web Dynpro erleichtern. Tony Buzan wird als Vater der Mind Map angesehen. Mind Maps sind Diagramme zur Strukturierung von Ideen, die den Menschen in vielen Aufgabenbereichen unterstützen. Mind Maps werden meistens für Notizen in Besprechungen oder in der Schule verwendet; als eine gute Methode, Wissen zusammenzufassen oder als Vorbereitung für eine Präsentation. Mehr Details über die Vorteile der Mind-Map-Anwendung für das Erlernen von Web Dynpro finden Sie in dem Artikel „The Advantages of using Mind Map for learning Web Dynpro” (Cristea et al., Web Dynpro, Computer Applications in Engineering Education. Online veröffentlicht: 19.2.2009).
16.1 Erstellung einer Mind Map Um eine Mind Map zu erstellen, beginnen wir an einem zentralen Punkt; in unserem Fall dem Web Dynpro ABAP. Dieser ist der Hauptinhalt der Mind Map, und alle durch Linien damit verbunden Unterbegriffe repräsentieren die Keywords bzw. die hauptsächlichen Ideen. In unserem Beispiel haben wir eine Mind Map erstellt, welche die Themen dieses Buches repräsentiert. Vom UI-Element bis zu Hook-Methoden und KomponentenWiederverwendung hilft uns diese gut strukturierte Mind Map, Web Dynpro ABAP schneller zu lernen und gleichzeitig die für das Erlernen dieser Technologie benötigten Hauptelemente im Gedächtnis zu verankern. Für jedes Thema oder Unterthema können wir eine oder mehrere Dateien mit Details zum entsprechenden Thema, Beispielen, Abbildungen, Links etc. anhängen. Wenn wir uns zum Beispiel ein UI-Element ansehen, können wir unschwer erkennen, dass die UI-Elemente, die mit Web Dynpro verwendet werden, in gewisse Unterkatagorien eingeteilt sind. In diesem Buch präsentieren wir die folgenden U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1_16,
371
372
16
Web Dynpro ABAP Mind Map
Kategorien: Layout, Action, Selection, Complex, Graphic und Integration. Jede dieser Kategorien hat dazugehörige UI-Elemente. In unserem Beispiel haben wir nur die UI-Elemente vorgestellt, die in diesem Buch verwendet wurden, aber wie bereits erwähnt können sie sehr leicht erweitert werden. Auf dem Markt können wir eine breitgefächerte Auswahl an Software finden. iMindMap wird weltweit als die offizielle Mind-Mapping-Software angesehen, unterstützt von Tony Buzan. Für die Erstellung unserer Mind Map haben wir den Mindjet MindManager verwendet, der unter der folgenden URL heruntergeladen (und als Trial-Version-Gratifikation getestet) werden kann: http://www.mindjet.com.
16.2 Web Dynpro ABAP Mind Map Abbildung 16.1 stellt die Mind Map dar, die erstellt wurde, um das Erlernen von Web Dynpro ABAP zu erleichtern.
Abb. 16.1 Web Dynpro ABAP Mind Map
Abkürzungsverzeichnis
ABAP ACTVT ADS ALV AS ABAP AS Java BAPI FuBA I18N iView J2EE LUW MANDT MVC OTR PDF RBAC RFC SDN SO SPRAS SQL UDDI URL WSDL WYSIWYG XML
Advanced Business Application Programming Berechtigungsfeld – Activity Adobe Document Service SAP List Viewer Application Server ABAP Application Server Java Business Application Program Interfaces Funktionsbaustein Internationalization (Internationalisierung) integrierte View Java platform Logical Unit of Work Data element, SAP client field Model View Controller Online Text Repository Portable Document Format Role Based Access Control (Rollenbasierendes Zugriffsmodell) Remote Function Call SAP Developer Network Select Options Datenelement, Sprachenschlüssel Structured Query Language Universal Description Discovery and Integration Uniform Resource Locator Web service Description Language What You See Is What You Get Extensible Markup Language
U. Gellert, A.D. Cristea, Praxishandbuch Web Dynpro ABAP, Xpert.press, C Springer-Verlag Berlin Heidelberg 2011 DOI 10.1007/978-3-642-11387-1,
373
Die Autoren
Ulrich Gellert lebt in der Nähe von Heidelberg. Nach seiner Ausbildung zum ITKaufmann in den Jahren 1983–1985 war er Mitgründer der S+P LION GmbH im Jahr 1985. Er hat eine über 25 jahe Erfahrung als Entwickler, Berater und Projektleiter in zahlreichen Projekten. Seit 2003 ist er Vorstandsvorsitzender der S+P LION AG. Die S+P LION AG ist eine international tätige IT-Beratung mit über 500 festen und freien Mitarbeitern von denen ca. 430 im SAP Beratungsumfeld tätig sind. Viele dieser Mitarbeiter sind direkt bei SAP (primär in Walldorf und St. Leon) eingesetzt. Zusätzlich ist er Mitglied in einem Aufsichtsrat und Business-Engel bei einigen Start-Up-Firmen. Ana Daniela Cristea studierte Informatik an der Universität von Petrosani (Rumänien) und schloss das Studium als Jahrgangsbeste ab. Sie arbeitete vier Jahre als Universitätsassistentin an der Polytechnischen Universität von Timisoara (Rumänien). Zur Zeit lebt sie in Pforzheim und arbeitet an ihrer Dissertation zum Thema „Contribution to the creation and development of a new SAP authorization concept based on Qualifications and physical connection through RFID” sie arbeitet als freiberufliche SAP-Beraterin. Sie ist Autorin und Co-Autorin zahlreicher Artikel und hat bisher drei Fachbücher veröffentlicht.
375
Bibliografie
Whealy C (2007) Inside Web Dynpro for Java. SAP Press, ISBN 978-3-89842-092-5 Hauser J, Deutesfeld A, Rehmann S, Szücs T, Thun P (2009) SAP Interactive Forms by Adobe. SAP Press, ISBN 978-1-59229-245-7 Keller H, Thümmel WH(2009) Official ABAP Programming Guidelines. SAP Press, ISBN 978-159229-290-5 Assig C, Fobbe AH, Niemietz A (2009) Object Services in ABAP. SAP Press, ISBN 978-3-83621404-9 Keller H, Krüger S (2005) ABAP Objects. SAP Press, ISBN 978-1-59229-079-6 Wiegenstein A, Schumager M, Schinzel S, Weidemann F (2009) Sichere ABAP Programmierung. SAP Press, ISBN 978-3-8362-1357-8 Raepple M (2008 ) The Developer’s Guide to SAP NetWeaver Security. SAP Press, ISBN 978-159229-180-9 Niculescu V, Klappert K, Krcmar H (2008) SAP NetWeaver Portal. SAP Press, ISBN 978-1-59229145-8 IBM Business Consulting Services (2003) SAP Authorization System. SAP Press, ISBN 978-159229-016-1 Schumacher M, Fernandez–Buglioni E, Hybertson D, Buschmann F, Sommerland P (2006) Security Patterns, Integrating Security and Systems Engineering. Wiley. ISBN 0-470-85884-2 http://www.mindjet.com. Cristea Cristea AD, Berdie A, Osaci M, Chirtoc D (2009) The Advantages of using Mind Map for learning Web Dynpro Wiley InterScience Journal - Computer Applications in Engineering Education, Publiziert online: 19. Feb. 2009. http://www.sdn.sap.com/irj/sdn Lorez A, Schöppe G, Consbruch F, Knapp D, Sonnerberg F (2006) SAP-Anwendungen mit Adobe Flex. SAP Press, ISBN 978-3-89842-794-4 Banner M, Latka B, Spee M, Schroth R (2008) Developer’s Guide to SAP NetWeaver Portal Applications. SAP Press, ISBN 978-1-59229-225-7
377
Sachverzeichnis
A ABAP Debugger, 11, 28–31 ABAP Dictionary, 35–55, 58–61, 64, 66–67, 97, 141–142, 150, 168, 222, 243, 247, 252–255, 269–270, 288–289, 325, 355 ABAP Editor, 20 ABAP Workbench, 1, 3, 11, 251–252, 299 Abhängiger Knoten, 57 Access control, 353, 355–356 Adobe Document Service (ADS), 220 Adobe Flex, 16 Adobe LifeCycle Designer, 220, 223–224 Aktion, 18–19, 93, 102, 104, 108, 115–117, 132–134, 137–138, 178, 180, 222, 225, 230, 322, 347, 353–354, 363, 366–368 ALV Konfigurationsmodell, 314–322 ALV Standard-Komponente, 311–313, 316, 318 Anmeldeseite, 31–34 Application Server (AS) ABAP, 1, 3, 11, 28, 297, 336–337, 355 Application Server (AS) Java, 1 Assistance-Klasse, 236–239, 258–260, 273–289 Ausnahmeklasse, 242–250, 275, 278, 286, 300 AUTHORITY-CHECK, 353, 366 B Back-end, 342 Benutzerdefinierte Instanzmethode, 93, 110–113 Berechtigung, 7, 353–369 Berechtigungsfeld, 354–355, 357–361, 366–367 Berechtigungsfeld ACTVT, 355 Berechtigungsobjekt, 357–359, 363, 367
Berechtigungsobjekt S_PROGRAM, 369 Berechtigungsobjekt S_RFC, 369 Berechtigungsobjekt S_TABU_DIS, 369 Berechtigungsobjekt S_TCODE, 369 Breakpoint, 28–29 Business Application Program Interfaces (BAPI), 273–275, 289–299, 307 Business-Ebene (Layer), 3 BusinessGraphics-UI-Element, 218–220 ButtonChoice-UI-Element, 135, 137–138, 141 Button-UI-Element, 16 C Cell-Editoren (Cell-Editor), 176–177, 182, 318 CL_ABAP_MATCHER, 172–173, 288–289 CL_ABAP_REGEX, 288 Class Builder, 237, 242, 278 Component-Verwendung (Usage), 82, 312, 316, 323–324, 330 Container-Formular, 72–73, 79 Content administrator, 334 Context-Attribute, 11, 17–18, 49, 57–69, 71, 74–76, 88, 94, 99, 103, 106–107, 110–111, 136, 138–140, 175, 198, 201–202, 204–205, 212–213, 308 Context-Knoten, 17–18, 23, 53, 57–69, 71–73, 77, 80–85, 89, 93–99, 101, 103–104, 106–107, 110, 113, 122, 124, 132, 136, 142, 145, 147, 150, 167–168, 175–176, 179–180, 184–185, 194, 198, 201–203, 205–206, 212–213, 221, 223, 237, 242, 244, 253, 269–271, 283, 295–297, 312–313, 318, 323, 327, 330 Context-Mapping, 71–91, 114, 185, 194, 314, 318, 320, 330 Context Menüs, 15, 17, 27, 105 ContextualPanel-UI-Element, 165–166 Controller-Interface, 23
379
380 D DataNavigator-UI-Element, 207 Datenbanktabelle, 11, 39–40, 47, 54, 58, 97, 162, 215–216, 222, 236, 239–241, 243–247, 262, 274–275, 277, 283, 288, 290, 294, 297, 299, 325, 340, 353–354, 363–364, 368 Datenbank-View, 50–53, 168, 269, 271 Datenbindung, 18–19, 29, 71–91, 95, 101–102, 106, 142, 147, 158, 168–169, 175, 178, 213, 222, 230, 244 Datenelement, 11, 36–40, 42–43, 59–60, 67, 108, 253–255 Default-View, 186, 195 Delta Link, 340, 343, 350 Dereferencing Operator, 327 Diagram View, 4 Direktes Mapping, 80–84 Domäne, 37–40, 108, 141, 150, 255–256 DropDownByIndex-UI-Element, 145–147 DropDownByKey-UI-Element, 142–144 E Eclipse, 1 Eingebaute Datentypen, 36 Einzelrolle, 354, 362 Elementare Datentypen, 35 Empty View, 24 End of list, 318, 320 Entwicklerschlüssel, 11 Erweiterungskategorie, 41, 43–44 Event (Ereignis), 322 Eventhandler-Methoden, 20, 116–120, 281–282 Externes Context-Mapping, 80–84 F Favoriten, 6–9 Field Symbol, 289, 326–327 FileUpload-UI-Element, 230, 232–233 Fire-Methoden, 113–116, 118 FlowLayout, 101, 121–124 FQDN (Fully qualified domain name), 15 Framework, 17, 19–22, 25–26, 49, 60, 63, 66, 68, 73, 86, 93, 102, 105, 108, 110, 113, 115, 117–118, 137, 138, 140, 143, 152, 158, 169–170, 172, 175–176, 180, 186, 188, 196, 208–209, 218, 225, 228, 231, 238, 241, 245, 249, 260, 280–281, 283, 286, 297, 299, 308, 326, 335, 340, 366 Fremdschlüssel, 44–46, 263–264, 266 Funktionsbaustein, 11, 54–55, 97, 133–134, 275, 288–289, 291–292, 295, 299–300 Funktionsgruppe, 275, 289, 299
Sachverzeichnis G Gesichtslose Komponente (Faceless Component), 80–81, 273–274 GridLayout, 121, 124–127 Group-UI-Element, 72 H Hook-Methoden, 20, 93–109, 371 Hotkey, 137, 141 I Image-UI-Element, 212–213, 215 Inbound-Plug, 14, 24–25, 93, 113–120, 152–153, 155, 186, 194 InputField-UI-Element, 16–18, 21, 73–74, 103–104, 106, 253 InteractiveForm-UI-Element, 220, 225, 228–229 Interface Controller, 22, 66, 68 Interface Methoden, 71–91 Internationalization (I18N), 251 Internes Context-Mapping, 77–80 Interne Tabelle, 64, 66, 245, 283, 287–288 InvisibleElement-UI-Element, 125, 127 iView, 333–334, 338–343, 346–351 K Kardinalität, 61–62, 65, 67, 95, 97, 99, 104, 113, 133, 142, 145, 147, 150, 158, 175, 198, 204, 212–213, 215, 221, 224–225, 243, 253, 283, 312, 323 Kind-Knoten, 53 Klasse, 97, 104, 106–107, 124, 131, 135–136, 172, 236–238, 242, 258–260, 273–275, 277–283, 285, 287–288, 318, 354–358 L Label-UI-Element, 16, 75, 101 LayoutData, 122 Lead-Selection, 61, 63, 65 LinkToAction-UI-Element, 98–99, 102, 160, 164–165, 183, 281, 321 LinkToURL-UI-Element, 318 M MatrixLayout, 121, 126–128 Mehrsprachig, 251–271 MessageArea-UI-Element, 171, 173–174 Message Manager, 89, 111, 118–119, 172–173, 226, 239, 241–242, 246, 261, 284–286, 298, 309, 366 Microsoft Excel, 313 Mind Map, 371–372 Model View Controller (MVC), 1, 273 Multikomponenten-Applikation, 81, 274–289
Sachverzeichnis Multipurpose Internet Mail Extensions (MIMEs), 99, 165, 212, 218, 229–233 N Nachrichtenklasse, 240–242, 245, 247–250, 260, 277, 292, 367 Navigation Manager, 4 O Object Navigator, 11–12, 35, 48 OTR (Online Text Repository), 242–243, 245, 248, 255–258, 278, 286 Outbound-Plug, 14, 24, 113–116, 118, 120, 152, 154, 186, 194, 281 P PageHeader-UI-Element, 160 Page Layout, 351 Paket, 11–13, 48, 85, 255–258, 302, 305–306 Pattern, 172–173, 288–289 PERSISTENCE-Ebene (layer), 3 Persistente Klasse, 275 PhaseIndicator-UI-Element, 191 Portal Content Studio, 339 Portal Eventing (Portalereignis), 333, 345 Portal-Homepage, 333 Portal-Katalog, 334–335 Portal Page, 349 Portal-User, 334 Präsentations-Ebene (Layer), 3 R RadioButtonGroupByIndex, 147–149 Range table, 324–326 Regex Toy, 171 Repository Object, 37, 61–66, 242, 252, 255–256 Reverse Mapping (Umgedrehtes Mapping), 85–88, 313 RoadMap UI Element, 183, 190–192 Role Based Access Control (RBAC), 353, 355–356 Rootuielementcontainer, 14, 16, 121–122, 141, 160, 163, 166, 182, 192, 199, 204, 211, 219 RowLayout, 121, 128–130 S SALV_WD_TABLE, 311–312, 316–320, 330 Sammelrolle, 354 SAP Easy Access, 5–9, 362 SAP GUI, 9 SAP List Viewer (ALV), 311 SAP-Mandantenfeld MANDT, 42, 244, 277, 289, 317
381 SAP NetWeaver Developer Studio, 1–3 SAP NetWeaver Platform, 1–2, 233, 333–351, 356 SAP NetWeaver-Portal, 233, 333–351 SAP R/3-Berechtigung, 353–354 SAP Verknüpfung (Shortcut), 5, 9 Selbstreferenz wd_this, 23 Select Options SO (Standard-Komponente), 311 Service Call (Service-Anrufe), 307 Singleton, 61, 63, 65, 67, 95–97, 99, 104, 113, 133, 142, 145, 147, 150, 158, 175, 198, 212–213, 215, 243, 253, 283, 312, 323 Sperrobjekt, 256 Sperrtabelle, 55 Sprachenschlüssel, 239, 263 Start-Transaktion, 8–9 Struktur, 3–4, 29–30, 40–41, 43, 47, 53, 55, 57, 61–64, 66–68, 72, 79–81, 85, 95, 97, 104, 106, 114, 122, 133, 135–136, 142, 145, 147, 150–151, 153, 155–156, 158, 160, 165, 168, 172, 174–175, 185–187, 194–195, 200, 215–216, 220, 222–223, 227, 230–231, 240, 243–244, 249, 253, 263–266, 269–270, 275, 281–284, 286, 289–292, 294, 297, 299–300, 308, 312–313, 315, 323, 330–331, 345, 347–349, 357, 359, 365 Suchhilfe, 47–50, 59, 243, 247, 326 Supply-Funktion Methoden, 110 System-Administrator, 334, 338 T Tabellenpflege, 42, 267, 354, 369 Tabellentyp, 40, 53, 66, 172 Tabelle T100, 236, 239–242 Tabelle TACT, 357, 359–360 Tabelle TCURC, 46 Tabelle TSTC, 7 TabStrip-UI-Element, 159–160 Testbenutzer, 341, 363, 368 Textsymbol, 236–238, 258–259, 274 Texttabelle, 262–263, 266 TextView-UI-Element, 16, 20, 72, 74, 76, 102, 143, 163, 176, 182, 207 TimedTrigger-UI-Element, 133–134 Top of list, 318, 320 Transaktion PFCG, 362 Transaktion SA38, 171, 220 Transaktion SE11, 35, 262, 266, 367 Transaktion SE14, 47 Transaktion SE24, 131, 237, 315 Transaktion SE37, 55, 301
382 Transaktion SE38, 171, 220 Transaktion SE63, 256 Transaktion SE80, 8–9, 11 Transaktion SE91, 239 Transaktion SE93, 7 Transaktion SICF, 32 Transaktion SM59, 220 Transaktion SMLT, 252 Transaktion SOAMANAGER, 302, 304–306 Transaktion ST01, 367 Transaktion ST22, 242 Transaktion SU01, 251, 368 Transaktion SU20, 359 Transaktion SU21, 356 Transaktion SU53, 367 Transparent-Tabelle, 42–47, 168, 182, 355 Tray-UI-Element, 165–170 Tree-UI-Element, 198, 203 Table-UI-Element, 63, 162, 174, 176, 178, 182–183, 323 U UI (User Interface)-Element, 131–233 Unabhängiger Knoten, 57 User Administrator, 334, 354, 356 V View, 1, 3–4, 12, 14–25, 29, 50–53, 57, 61, 63–65, 71–73, 76–80, 82, 84–88, 90, 93–122, 126, 128, 130–131, 133–135, 137, 140–142, 144–163, 165–168, 171–172, 174–178, 182–192, 194–206, 208–211, 213, 215–217, 219–220, 222–223, 225, 229–231, 243, 246, 253, 258, 266–271, 273–274, 278, 280–286, 297, 307–308, 311–324, 327, 330, 338, 345–347, 355, 365 ViewContainer-UI-Element, 4, 151, 323, 327, 330 View-Controller, 14, 18–19, 21–22, 64, 73, 77, 80, 84, 93–120, 273 View Designer, 14–15, 134–135, 140, 144, 146, 149, 159, 162–163, 174, 182, 190–191, 197–198, 202–203, 210, 215, 219, 229, 233
Sachverzeichnis View-Layout, 14–17, 29, 73, 77, 79–80, 84, 95, 99, 104, 122, 131, 133, 137, 141–142, 145, 147–148, 153, 155, 157, 162, 164–165, 167, 172, 175–178, 185–186, 200, 205–206, 213, 216–217, 220, 222, 230–231, 243, 253, 269–270, 280, 282, 283–284, 286, 297, 308, 312, 323, 330, 345, 347, 365 ViewSet, 4 W Währungsschlüssel, 44–45 WdDoBeforeAction, 94, 104–105, 284 WdDoExit, 94, 97–98 WdDoInit, 63, 83–84, 94–97, 106, 110, 141, 158, 169, 186–187, 195, 226–227, 259, 285, 316–318, 324–325, 328–329, 347 WdDoModifyView, 94, 98–103, 111, 124, 126, 128, 130, 134, 141, 160, 163, 166, 182, 192, 199, 204, 211, 219 WdDoOnContextMenu, 94, 105–109 WDR_SELECT_OPTIONS, 311, 323–324, 328, 330 WDR_TEST_EVENTS, 162 WDR_TEST_UI_ELEMENTS, 162 Web Dynpro ABAP, 3–4, 11, 15, 131, 235–250, 273, 299, 339, 345–346, 353, 371–372 Web-Dynpro-Anwendung, 11, 25–28, 30, 32–33, 35, 37, 220, 252, 269, 273, 280, 311, 333, 339, 344, 347, 368 Web Dynpro Code Wizard, 65, 89–91, 115, 154, 238–239 Web-Dynpro-Component, 11–13, 16, 24–26, 38, 41, 47, 49, 53, 238, 274, 280, 289, 307, 333, 345, 353–354, 363–367 Web Dynpro Explorer, 3 Web Dynpro Java, 1, 3–4, 339, 345 Web Dynpro Perspective, 1–2 Web Service, 220, 273–275, 297–310 Wertetabelle, 37, 39–40, 44 What You See Is What You Get (WYSIWYG), 3 Window, 4, 12, 24–25, 72, 79–80, 86, 88, 94, 104, 114–116, 141, 150–153, 155, 174, 186–187, 195, 232, 274, 281–282, 307, 312–313, 331