WebAppServer_1B.pdf - DHBW Mosbach
WebAppServer_1B.pdf - DHBW Mosbach
WebAppServer_1B.pdf - DHBW Mosbach
Sie wollen auch ein ePaper? Erhöhen Sie die Reichweite Ihrer Titel.
YUMPU macht aus Druck-PDFs automatisch weboptimierte ePaper, die Google liebt.
Stateful und Stateless BSP-Anwendungen: HTTP ist stateless !<br />
Stateful BSP-Programmierung :<br />
Anwendungskontext über Response hinaus<br />
gehalten ⇒ Bei Weiterführung zur Vfg.<br />
NWAS "merkt" sich Daten, die zu Anwendung<br />
gehören (Rollbereich), greift bei Fortsetzung<br />
wieder darauf zu:<br />
Klassisches R/3: Bei jedem SAPGUI-Bildwechsel<br />
NWAS: Daten auch nach Senden der Response-<br />
Seite an Browser für weitere Requests derselben<br />
BSP-Anwendung zur Vfg ⇒ Session Stickness !<br />
Nachteil :<br />
- Hohe Last auf dem Server - Kontextdaten vieler User im Speicher halten<br />
- Ressourcen unnötig lange gehalten, wenn User BSP-Anwendung abbricht (Timeout)<br />
Vorteil :<br />
User 1<br />
Session 1<br />
User 2<br />
Session 2<br />
User 3<br />
Session 3<br />
NWAS: stateful<br />
session<br />
session<br />
- Einfachere Programmierung - Daten bleiben zur Vfg (keine Cookies etc nötig!)<br />
- Keine erneute Datenbeschaffung + wiederholte DB-Zugriffe ! (Performanz !!)<br />
session<br />
Ressource Laufzeit vs. Ressource Speicher<br />
HTTP ist ein zustandsloses Protokoll: Nach Antwort eines Servers auf die Anfrage eines Clients hält<br />
der Server keine Zustandsinformationen über den Client - jede neue Anfrage des Clients erfordert<br />
einen neuen Verbindungsaufbau und erneute Datenbeschaffung.<br />
Jedoch wird in einer stateful BSP-Anwendung der Anwendungskontext über die Response<br />
(Serverroundtrip) und alle Benutzerinteraktionen hinweg gehalten, bis die BSP-Anwendung beendet<br />
ist. Der Anwendungs- / Benutzerkontext wird wie bei einer klassischen R/3-Transaktion im<br />
Rollbereich zwischengespeichert und wieder in den zuständigen WAS-Workprozess hineingerollt,<br />
wenn die Bearbeitung fortgesetzt wird. Der Anwendungskontext wird über alle Request-Response-<br />
Zyklen einer BSP-Anwendung gehalten - die Daten stehen auf jeder Seite über die gesamte Session<br />
zur Vfg.<br />
Konsequenzen:<br />
Auf dem Server wird eine große Last erzeugt: Web-Anwendungen werden meist von vielen<br />
Benutzern eingesetzt. Für jeden Benutzer wird Kontext auf dem Netweaver Application Server<br />
gehalten und belastet somit dessen Speicherkapazität.<br />
Ressourcen werden unnötig lange auf dem Server gehalten: Webbrowser melden sich nicht beim<br />
Server ab, wenn ein "flüchtiger" Benutzer zu einer anderen Seite navigiert. Eine offene Sitzung<br />
kann somit nicht beendet werden - und verbleibt im Speicher des WAS bis der Timeout-<br />
Mechanismus den Kontext freigibt. Da dies einige Zeit dauern kann, werden begrenzte Server-<br />
Speicherressourcen unnötig lange blockiert. Ist der Server nicht mehr in der Lage, weitere Daten zu<br />
speichern, verweigert er die Erstellung zusätzlicher Sessions, so dass kein weiterer Anwender die<br />
Applikation nutzen kann.<br />
Die Programmierung ist jedoch leichter zu realisieren: Die Daten stehen beim erneuten Zugriff<br />
ohne erneute DB-Abfragen für die komplette BSP-Session zur Vfg. Die Zahl der Datenbankzugriffe<br />
ist minimal. Es kann auf Cookies oder Hidden Fields verzichtet werden. Man sollte sich jedoch stets<br />
fragen, ob es wirklich nötig ist, die komplette Benutzersitzung permanent aufzubewahren.<br />
(1)<br />
Zeit
Session- Handling: SAP-Session- ID<br />
HTTP arbeitet stateless ⇒ Kennt nur unabhängige Requests<br />
BSP-LZ generiert Session-ID<br />
in Session-Cookie: sap-contextid<br />
-Imstateful-Fall verschickt<br />
Nach Response wird Verbindung geschlossen<br />
⇒ Kein Mechanismus zur Sessionkennzeichnung :<br />
Zuordnung mehrerer Request zu einer gemeinsamen Sitzung<br />
- Identifikation mehrerer Requests als Teil einer logischen Session (Anwendung)<br />
- Gültig bis zum Sitzungs-Ende<br />
- Abfrage über autom. instantiiertes Objekt runtime<br />
In allen Eventhandlern + Layout<br />
Attribut session_id abgreifbar<br />
Explizites Beenden einer Session :<br />
Data: s_id TYPE string .<br />
s_id = runtime→session_id .<br />
navigation→exit( 'http://www.sap.com' ) .<br />
Bewirkt im stateful-Fall den Abbau des Session-Kontextes + Freigabe aller Ressourcen<br />
(2)<br />
Funktioniert nicht, wenn in Browser-<br />
Einstellungen Sitzungs-Cookies nicht<br />
zugelassen sind !!<br />
Zum Session-Handling dient das globale, automatisch instantiierte Objekt runtime vom Typ<br />
IF_BSP_RUNTIME. Über runtime hat man Zugriff auf das Attribut session_id. Dieses enthält einen<br />
eindeutigen Sitzungsschlüssel zur Sitzungsidentifikation. (Eine weitere nützliche Methode des<br />
runtime-Objekts ist get_url(). Diese liefert die URL der aktuellen BSP-Seite zurück.)<br />
Allerdings wird nur im stateful-Fall dieser Sitzungsschlüssel in Form eines Sitzungs-Cookies an den<br />
Client-Browser geschickt (und von diesem mit dem nächsten Request der gleichen Session wieder an<br />
den Server).<br />
Eine BSP-Session ist der Zeitraum zwischen Start der Applikation durch Aufruf der entsprechenden<br />
URL, und Beenden der Applikation. Die Zuordnung von Requests zu einer stateful-BSP-Session<br />
erfolgt mit Hilfe von Session-Cookies, die von der BSP-Laufzeit erzeugt werden. Sie werden<br />
clientseitig als "sap-contextid" im Speicher abgelegt und bestehen auf dem Client nur für den<br />
Zeitraum der BSP-Session. Damit ist es der BSP-Laufzeit möglich, den Client-Requests eine<br />
eindeutige Session-Nummer anzufügen, um den Request im stateful-Fall einer bestimmten Session<br />
und dem Applikationskontext zuzuordnen. Bei jedem erstmaligem Aufruf einer neuen BSP-Anwendung<br />
wird eine neue session_id vergeben.<br />
Eine stateful-BSP-Anwendung hält Daten, die der Anwender eingegeben oder angefragt hat<br />
(Applikations- / Benutzerkontext), über die komplette BSP-Session hinweg. Der benutzer-spezifische<br />
Applikationskontext steht über die einzelnen Request-Response-Zyklen hinaus zur Vfg und wird von<br />
Seitenaufruf zu Seitenaufruf aktualisiert.<br />
Leider wird die Synchronität zwischen Client und Server durch das Stateful-Zustandsmodell<br />
gefährdet und muss vom Entwickler sichergestellt werden: Der Zustand der Anwendung kann sich<br />
von der Anzeige im Browser unterscheiden, zB durch Navigieren in der Browser-Historie oder mittels<br />
Browser-Back-Button. Ein User kann zu einer Webseite zurück navigieren und diese erneut senden,<br />
obwohl die Anwendung mit anderen Anfragen rechnet:
Stateless BSP-Anwendungen<br />
Nach Absenden jeder Response wird aktueller<br />
Benutzerkontext abgebaut und alle Ressourcen<br />
freigegeben ⇒<br />
- Alle Instanzen gelöscht<br />
- Alle Seitenattribut-Werte gelöscht<br />
- Alle Anwendungsklassen-Attributwerte<br />
gelöscht.<br />
Werte bei nächstem Request nicht mehr zur Vfg.<br />
Server ohne "Gedächtnis" - bedient isolierte<br />
Requests.<br />
Kompletter Kontextneuaufbau bei jedem<br />
Seitenwechsel erforderlich.<br />
1. Seitenattribute<br />
User 1<br />
User 2<br />
User 1<br />
In OnInitialization oder Layout wird Wert zugewiesen.<br />
In OnInputProcessing verwendbar, Wert dort aber wieder initial<br />
2. Attribute des Applikationsklassen-Objekts<br />
WAS : stateless<br />
response<br />
request<br />
response<br />
request<br />
request<br />
response<br />
Attribute (Einzelwerte und ganze interne Tabellen) nach Response in OnInputProcessing wieder initial<br />
Das Stateless-Zustandsmodell hält den benutzerspezifischen Applikationskontext nur für die Dauer<br />
eines Request-Response-Zyklus. Eine BSP-Anwendung stateless auszuführen bedeutet, daß für<br />
jeden Request ein neuer Applikationskontext erzeugt wird und einschließlich sämtlicher Instanzen<br />
nach jeder Response wieder verworfen wird (zustandslos = "gedächtnis-frei"). Ist der Request<br />
bearbeitet und die Response an der Browser gesendet, werden alle Ressourcen freigegeben. Der<br />
WAS verhält sich somit so, als würde sich jeder Benutzer einer BSP-Anwendung bei jedem<br />
Seitenwechsel abmelden und anschließend erneut anmelden.<br />
Der Kontext (Inhalt Seitenattributen und die Instanz der Anwendungsklasse mit ihren Attribut-Werten)<br />
bleibt nicht über einen Request- / Response-Zyklus hinaus auf dem WAS erhalten - und muss somit<br />
bei jedem folgenden Request komplett neu aufgebaut werden.<br />
Beispiel: Man weist in einer stateless-BSP einem Seitenattribut im Layout einen Wert zu. Dann kann<br />
zwar das Seitenattribut im Eventhandler OnInputProcessing verwendet werden, sein Wert ist dort<br />
aber wieder initial! Das gleiche gilt für die Attribute der Applikationsklasse.<br />
Anmerkung: Mit Ablauf des Benutzerkontextes wird auch das ABAP-Memory abgebaut, so dass die<br />
entsprechenden ABAP-Anweisungen:<br />
IMPORT ... FROM MEMORY ID ... und EXPORT ... TO MEMORY ID ...<br />
nicht sinnvoll einsetzbar sind.<br />
Das Verwerfen des Kontextes lässt sich auch in der SAP-Benutzerliste SM04 erkennen: Während<br />
des Aufrufs einer BSP-Anwendung erscheint kein Eintrag in der Benutzerliste. Erst wenn man zB in<br />
einem Eventhandler einen Beakpoint setzt, erscheint die Sitzung in der Benutzliste! Wird die gleiche<br />
Anwendung stateful geschaltet, so wird der Benutzkontext gehalten und führt zu einen Eintrag in der<br />
Benutzerliste.<br />
(3)<br />
Zeit
Stateless BSP-Anwendungen<br />
Nachteil :<br />
- Daten neu beschaffen, wenn in mehreren BSPs einer Anwendung benötigt<br />
- Erneute Datenbeschaffung und DB-Anfragen - oder: Cookies .....<br />
Vorteil :<br />
- Server Ressourcen nur während Request-Bearbeitung beansprucht.<br />
⇒ Kein Blockieren unnötiger Ressourcen<br />
- Bessere Skalierung des Servers - gut für viele Anwender<br />
- Browser-Back/Forward-Navigation unproblematisch<br />
- Direkter Sprung in beliebige Anwendungsseite unproblematisch<br />
Einstellen des Zustandsverhaltens :<br />
In Eigenschaften der BSP-Anwendnung kann stateful oder stateless selektiert werden!<br />
Selektives Umschalten zur LZ möglich - gemischte BSP-Anwendung :<br />
Setzen des Attributs keep_context des Objekts runtime :<br />
Umschalten auf stateful : runtime→keep_context = 1 .<br />
Umschalten auf stateless : runtime→keep_context = 0 .<br />
..... im Eventhandlercode ...<br />
Requests<br />
(4)<br />
Keine "Session Stickness" bei<br />
verteiltem SAP-System aus<br />
mehreren NWAS ⇒<br />
Jeder einzelnen Request kann von<br />
vorgelagerten WebDispatcher<br />
einem anderen NWAS des<br />
Systems zugeteilt werden !<br />
Web<br />
Disp.<br />
NWAS 1<br />
NWAS 2<br />
NWAS 3<br />
Vorteil ist die Ressourcennutzung: Auf dem NWAS werden nur während der Bearbeitung eines<br />
Requests Ressourcen beansprucht. Sofortiges Verwerfen des Applikationskontext nach Absenden der<br />
Response vermeidet unnötige Speicherbelegung durch zahlreiche "flüchtige" Internetuser. Stateless<br />
Programmierung führt somit zu einer guten Skalierung des Servers und ist für Web-Anwendungen<br />
(viele "flüchtige" Anwender) gut geeignet.<br />
Nachteilig ist die hohe Zahl von Datenbankzugriffen. Daten müssen ständig neu beschafft werden:<br />
Daten, die mehrere BSPs innerhalb einer BSP-Anwendung benötigen, müssen mehrfach von der DB<br />
gelesen werden. Dies führt zu einer höheren Last auf der DB und zu Laufzeitverlängerungen<br />
gegenüber dem Stateful-Zustandsmodell. Es gibtLösungen diesen Nachteil zu umgehen (s.u.)<br />
Für Applikationen, die keine Statusdaten brauchen, ist stateless (Default) sinnvoller, da nicht unnötig<br />
Ressourcen im SAP-System belegt werden.<br />
In den Eigenschaften einer BSP-Anwendung läßt sich festlegen, ob die gesamte Anwendung stateful<br />
oder stateless gehandhabt wird. Aber es ist auch möglich, zwischen stateful und stateless zur<br />
Laufzeit umzuschalten (gemischte BSP-Applikation). Dies wird zur LZ erreicht durch das Setzen<br />
des Attributs keep_context des Objekts runtime (Typ if_bsp_runtime). Das Umschalten ist in den<br />
Eventhandlern möglich. Typischerweise würde die Anwendung stateful geschaltet, wenn der<br />
Anwender Daten eingibt, die im weiteren Verlauf der Anwendung weiterhin benötigt werden.<br />
Da stateless BSP-Anwedungen keinen Kontext auf dem NWAS für den User speichern, kann jeder<br />
Teilschritt einer Webanwendung von einem anderen NWAS eines verteilten SAP-Systems bearbeitet<br />
werden – im Gegensatz zu einer klassischen SAP-Anwendung, bei der der User nach seiner<br />
Anmeldung (via Message Server) einem bestimmten NWAS fest zugeteilt wird und im Rollbereich<br />
dieses NWAS ein entsprechender Userkontext gehalten wird. In einer stateless BSP-Anwendung wird<br />
somit Session-Stickness vermieden und die Skalierbarkeit des Systems deutlich verbessert !<br />
Dagegen erzwingen statefull BSP-Anwendungen Session-Stickness durch das Halten von User-<br />
Kontext auf einem der NWAS. Aufeinander folgende Request der gleichen Session können somit nicht<br />
auf verschiedene NWAS verteilt werden, da der Userkontext nur auf einem der NWAS gehalten wird.<br />
Verteiltes System
Weitergabe von Seitenattribut-Werten innerhalb BSP<br />
1<br />
2<br />
Browser<br />
Wertübergabe bei impliziter + expliziter Navigation :<br />
OnInputProcessing<br />
Navigation<br />
OnInitialization<br />
On<br />
Initialization<br />
req.<br />
Seitenattribut :<br />
test type string<br />
Layout<br />
Request-Response-Zyklus<br />
= Kontextlebensdauer<br />
res.<br />
BSP 1<br />
Browser<br />
req.<br />
Formular<br />
On<br />
InputProcessing<br />
.....<br />
.....<br />
Bereits behandelt ....<br />
(5)<br />
Identisch für stateless und stateful<br />
Unterschiedlich für AUTO und<br />
Nicht-AUTO-Seitenattribute<br />
Seitenattribut test füllbar in :<br />
1. OnInitialization<br />
2. Layout<br />
3. Form<br />
Wert in OnInputProcessing<br />
noch gefüllt und abgreifbar?<br />
Identisch für AUTO und Nicht-<br />
AUTO-Seitenattribute<br />
Unterschiedlich für stateless<br />
und stateful Anwendungen<br />
................................<br />
Bereits behandelt wurde die Übergabe von Seitenattribut-Werten aus dem Zeitpunkt<br />
OnInputProcessing an OnInitialization. Hier wurden verschiedene Arten der Navigation auf die gleiche<br />
oder eine andere BSP unterschieden. Es ging um die Wertübergabe:<br />
OnInputProcessing → ( Navigation ) → OnInitialization<br />
Das Verhalten hing nicht davon ab, ob die BSP-Anwendung stateful oder stateless lief. Dagegen<br />
war entscheidend, ob es sich um ein Auto-Seitenattribut oder Nicht-Auto-Seitenattribut handelte.<br />
Nun betrachten wir die Übergabe von Seitenattribut-Werten aus den Zeitpunkt OnInitialization,<br />
Layout und Formbearbeitung an OnInputProcessing. Es geht um die Wertübergabe:<br />
OnInitialization / Layout / Formular → OnInputProcessing<br />
Das Verhalten hängt nicht davon ab, ob es sich um ein Auto-Seitenattribut oder Nicht-Auto-<br />
Seitenattribut handelt. Dagegen ist es entscheidend, ob die BSP-Anwendung stateful oder stateless<br />
läuft.
Weitergabe von Seitenattribut-Werten innerhalb BSP<br />
Seitenattribut test gefüllt in: Zugriff in:<br />
1. OnInitialization<br />
2. Layout<br />
OnInputProcessing<br />
3. Form<br />
Noch gefüllt + abgreifbar in OnInputProcessing :<br />
Seitenattribut stateless stateful<br />
gefüllt in :<br />
OnInitialization nein ja<br />
Layout nein ja<br />
Form (Benutzereingabe) ja request→get_form_field( ) ja<br />
(6)<br />
Identisch für AUTO und Nicht-<br />
AUTO-Seitenattribute<br />
Unterschiedlich für stateless<br />
und stateful Anwendungen<br />
Man bewegt sich in ein und derselben BSP-Seite<br />
Dennoch Seitenattribut-Werte nicht ständig verfügbar !<br />
BSP-Seitengrenzen nicht identisch mit Umfang eines Request-Response-Zyklus !<br />
In der Tabelle ist das Verhalten einer stateful- und stateless-BSP-Anwendung gegenübergestellt.<br />
Wenngleich man sich ständig innerhalb einer BSP-Seite bewegt, stehen die einmal gefüllten<br />
Seitenattribut-Werte nicht ständig zur Verfügung - was eventuell der Intuition widerspricht.
Halten von Kontextdaten in stateless BSP- Anwendungen :<br />
Hidden Fields + Clientseitige Cookies + Serverseitige Cookies<br />
HTTP ist stateless, aber :<br />
Betriebswirtschaftliche Transaktionen benötigen internen Zustand = Userkontext<br />
Dieser ist der Inhalt der laufenden Session und einem Client zugeordnet<br />
Abhilfe :<br />
Zustand als Parameter versteckt / gespeichert, den Serverprogramm auswertet :<br />
→ Korrekte Fortsetzung der Transaktion<br />
→ Generieren der korrekten Response<br />
1. Unsichtbare Eingabeelemente <br />
2. Clientseitige Cookies<br />
3. Serverseitige SAP-"Cookies" auf DB<br />
Anwendungsfall :<br />
Weitergabe von User- bzw. Rollen-<br />
Informationen für angemeldete User<br />
Ein gutes Beispiel für die Notwendigkeit, den Benutzerkontext (Zustand) aufzubewahren ist der<br />
Warenkorb eines OnlineShops:<br />
Die Auswahl des Besuchers muss im Warenkorb gespeichert bleiben, selbst wenn zwischendurch<br />
die Verbindung unterbrochen wird. Wenn der Kunde, nachdem er einige Waren aufgenommen hat,<br />
eine andere Webseite aufsucht und dann zum Onlineshop zurückkehrt, sollen alle Inhalte und<br />
Details des Warenkorbes noch vorhanden sein. Dazu müssen diese Informationen als Kontext<br />
gespeichert werden.<br />
Die Gedächtnisfreiheit von HTTP (und somit das wiederholte Einlesen von Daten) läßt sich auch in<br />
einer stateless BSP-Anwendung durch verschiedene Techniken umgehen:<br />
a) Unsichtbares Eingabeelement: Ablegen von Daten in einem HTML-Formular durch hidden<br />
fields. Diese werden über mehrere Seiten hinweg innerhalb von Forms übertragen.<br />
b) Cookies (client- und serverseitig): Das ICF bietet Methoden zum Senden und Empfangen von<br />
Cookies. Die Lebensdauer von Cookies kann bestimmt werden.<br />
(7)
Hidden Fields<br />
Für Benutzer unsichtbares Weiterreichen von<br />
Formulardaten = Name-Wert-Paare über mehrere Seiten<br />
Behandlung analog zu sichtbaren Formularfeldern<br />
In BSP mit navigation→set_parameter() an Folgeseite<br />
CASE event_id. OnInputProcessing<br />
WHEN 'Opt'.<br />
navigation→set_parameter( 'user' ).<br />
navigation→goto_page( 'next.htm' ).<br />
ENDCASE.<br />
first.htm<br />
<br />
Layout<br />
<br />
<br />
<br />
<br />
Form<br />
13<br />
Form<br />
13<br />
Form<br />
Hidden field<br />
13<br />
13<br />
(8)<br />
Web<br />
Server<br />
next.htm<br />
Seitenattribut Auto<br />
user X<br />
..............................<br />
In einem HTML-Formular sind für den Anwender nicht sichtbare, versteckte HTML-Input-Felder vom<br />
Typ hidden mit zugewiesenen Werten abgelegt. Nach Versand des Formulars mittels Submit kann<br />
das versteckte Textfeld auf dem Server ausgelesen und die Information weiterverarbeitet werden.<br />
Der Inhalt versteckter Textfelder (hidden fields) wird innerhalb eines HTML-Formulars versteckt<br />
mitgesendet. Diese Informationen sind - analog zu sichtbaren INPUT-Feldern - in Name-Wert-Paaren<br />
zusammengefasst. Man nutzt dieses Verfahren, um Variablen, die auf mehreren oder allen Seiten der<br />
Anwendung benötigt werden, „durchzuschleifen“, dh von Seite zu Seite zu übergeben.<br />
Für eine BSP ist es irrelevant, ob Werte aus einer Form als Typ = "hidden" oder Typ = "text" beim<br />
Request mitgesendet werden. Damit die eingegebenen Daten auch in der Folgeseite verarbeitet<br />
werden können, muss in allen Fällen mit navigation→set_parameter() der Wert weitergeleitet werden.<br />
Die Folgeseite muss ein gleichnamiges Auto-Seitenattribut besitzen, um den Wert<br />
entgegennehmen zu können.<br />
Mit der Technik der versteckten Felder lassen sich somit Informationen über mehrere Seiten in<br />
HTML-Formularen übertragen. Dazu muss das Name-Wert-Paar auch in den Folgeseiten wiederum<br />
als hidden field an deren Folgeseiten übertragen werden. Eine typische Anwendung ist die<br />
Weitergabe von User- bzw. Rolleninformationen innerhalb einer stateless BSP-Anwendung. Dies<br />
kann alternativ natürlich auch mit Cookies geschehen.<br />
Es ist nicht möglich, die Werte interner Tabellen auf diese Weise zu übertragen!<br />
Zum Weiterreichen derselben hidden fields über mehrere Seiten einer BSP-Anwendung sind<br />
Seitenfragmente gut geeignet.<br />
Nachteile: Es ist umständlich, die hidden fields in allen relevanten Seiten zu deklarieren. Ferner gibt<br />
es browserabhängige Größenbegrenzungen für Formularfelder. Somit eignen sich hidden fields nur für<br />
kleine Steuerungs-Kontexte.
Client- Cookies<br />
HTTP-Client (Browser)<br />
Request<br />
Response<br />
Request<br />
HTTP-Server<br />
(9)<br />
HTTP- Cookie :<br />
Bis zu 4 KB pro Cookie, nur Strings<br />
Maximal 300 pro Client<br />
Maximal 20 pro Server oder Domäne<br />
Von Server mit HTTP-Response gesendet<br />
Vom Client mit nächsten Request automatisch<br />
zur selben Server-URL zurückgeschickt.<br />
Lebendauer :<br />
- temporär - persisitent (mit Verfallsdatum)<br />
Data: booklist type string.<br />
OnInputProcessing BSP-Objekte und<br />
request→get_cookie(<br />
Methoden zum Aus-<br />
exporting name = 'basket'<br />
lesen und Übergeben<br />
importing value = booklist ).<br />
von Cookies an HTTP-<br />
* Cookie-Datenstring booklist in interne Tabelle überführen<br />
Strom ......<br />
* Interne Tabelle = Einkaufskorb verwalten<br />
Keine internen Tabellen -<br />
* Interne Tabelle wieder in Cookie-Datenstring booklist überführen<br />
müssten erst serialisiert<br />
* .......................................................<br />
werden ............<br />
response→set_cookie(<br />
SS0-Tickets + SessionIDs<br />
exporting name = 'basket'<br />
werden als nichtpersistente<br />
Cookies geführt ⇒<br />
value = booklist<br />
Lebensdauer + Gültigkeit für<br />
expires = 'TUE, 30-MARCH-13 23:59:59 GMT ' ).<br />
eine Session<br />
SSO-Cookie = MYSAPSSO2<br />
Eigenschaften eines HTTP-Client-Cookies: Bis zu 4 KByte Textdaten werden vom Server in der<br />
angeforderten HTTP-Response eingebettet und mitgesendet. Den Inhalt des Cookies legt der Server<br />
fest. Cookies können serverseitig gesetzt und bereits im HTTP-Protokollkopf mitgeschickt werden -<br />
oder mittels des JS-Objekts document.cookie clientseitig erst beim Aufbau der HTML-Seite im<br />
Browser gesetzt werden. Die Wirkung ist dieselbe: Bei jedem folgenden Request werden die Cookie-<br />
Daten im HTTP-Protokollkopf zurück an den Server gesendet. Das Cookie enthält :<br />
1. Die zu sichernde Information - benutzerbezogene Zustandsinformationen, z.B. fortlaufende<br />
Nummern für den Zustand einer Transaktion, oder der aktuelle Inhalt eines Warenkorbs. (Name-<br />
Wert-Paare). 2. Die Gültigkeitsdauer. 3. Die URL des Ursprungsservers (Domain).<br />
Nachteil von Client-Cookies: Da sie Teil des HTTP-Protokolls sind, können sie nur Felder vom Typ<br />
String enthalten – keine internen Tabellen. Da sie bei jedem Request mitgesendet werden erzeugen<br />
Cookies auch Netzlast.<br />
Ein Cookie kann von einem Server nicht aktiv angefordert werden. Der Server sendet Cookies zum<br />
Browser. Der Client-Browser schickt den Inhalt des Cookies beim nächsten HTTP-Request zum<br />
gleichen Server automatisch wieder mit.<br />
Die Lebensdauer ist entweder a) temporär - der Browser hält den Cookie nur im Speicher, mit Ende<br />
der Browser-Session geht der Cookie verloren. Oder b) persistent - der Browser speichert das Cookie<br />
lokal in einem festgelegten Verzeichnis, so dass es in der nächsten Browser-Session wieder<br />
ausgelesen werden kann. Der Server gibt dazu dem Cookie ein Verfallsdatum (expiration date) mit,<br />
nach dessen Ablauf der Browser den Cookie nicht mehr sendet. Browsereinstellungen legen fest,<br />
ob Cookies überhaupt oder erst nach Nachfrage angenommen werden sollen. Sie lassen sich durch<br />
den Browseruser abschalten. Somit sind clientseitige Cookies kein sicheres Mittel. Clienseitige<br />
Cookies sollten also nicht als "Basisfunktionalität" einer Anwendung eingesetzt werden, sondern<br />
allenfalls als Ergänzung. Sicherlich ist es nicht sinnvoll, sensible Daten als Browser-Cookie abzulegen.
Client- Cookies<br />
Zahlreiche(!) weitere Methoden zur Cookie-Manipulation<br />
im Interface IF_HTTP_ENTITY<br />
Importparameter von set_cookie()<br />
Name Typ Bedeutung<br />
name String Name des Cookies<br />
value String Wert des Cookies<br />
domain String Domäne der aufgerufenen Seite.<br />
Wenn nicht gesetzt, dann Hostname des sendenden Servers<br />
path String Gültiges Verzeichnis auf Server; Default = Pfad der aktuellen Seite<br />
expires String Zeitstempel, legt Ende der Lebensdauer fest.<br />
Format: Wdy, DD-Mon-YY HH:MM:SS GMT<br />
zB Tue, 30-March-12 23:59:59 GMT<br />
secure i Wert : 1 Cookie nur über HTTPS-Verbindung sendbar<br />
Wert : 0 Cookie auch über ungesicherte Verbindung sendbar<br />
Mögliche Aufrufzeitpunkte von :<br />
get_cookie: OnRequest, OnInitialization, OnInputProcessing, OnManipulation<br />
set_cookie: OnInitialization, OnManipulation<br />
Das ICF bietet in IF_HTTP_ENTITY Methoden zum Versenden und Empfangen clientseitiger<br />
Cookies. Diese Methoden stehen über die automatisch instantiierten Objekte request und response<br />
zur Vfg. Man kann einen beliebigen String im Cookie ablegen. Die Lebensdauer des Cookies ist<br />
durch einen Zeitstempel steuerbar:<br />
Wenn man kein Verfallsdatum angibt, wird das Cookie beim Schließen des Browsers<br />
(Sessionende) gelöscht. Soll das Cookie auf dem Client abgelegt werden, dann muss dem Cookie<br />
in der Methode set_cookie() ein Verfallsdatum mitgegeben werden.<br />
Cookies mit abgelaufenem Verfallsdatum werden nicht mehr an den Server gesendet. Vom WAS<br />
aus können clientseitige Cookies gelöscht werden. Dazu sendet man das Cookie erneut an den<br />
Client, datiert das Verfallsdatum jedoch in die Vergangenheit.<br />
Das Pfad-Attribut beschränkt das Cookie auf bestimmte Server-URLs. Der Wert '/' drückt aus, das<br />
das Cookie für alle URLs auf dem Server gültig ist. Weitere mögliche Werte sind z.B. runtime-<br />
>runtime_url oder runtime->page_url.<br />
Die Klasse CL_BSP_UTILITY verfügt über die statsiche Methode data_to_string_http, mit der sich ein<br />
Zeitstempel im gewünschten Format erzeugen lässt:<br />
Data: ts TYPE bsptimestamp, tss(14) TYPE c.<br />
ts-date = sy-datum . ts-time = sy-uzeit . tss = ts .<br />
Cl_BSP_UTILITY⇒ date_to_string_http( timestamp = tss ) .<br />
Die Objekte request und response stehen mit ihren Methoden nur zu den angegebenen Zeitpunkten<br />
zur Vfg. Zu anderen Zeitpunkten kann man sich die aktuellen Instanz-Referenzen über die Referenz<br />
page der aktuellen BSP-Seitenklasse beschaffen:<br />
Data: response TYPE REF TO if_http_resonse , request TYPE REF TO if_http_request .<br />
response = page→get_response( ) . request = page→get_request( ) .<br />
(10)
Cookies auf Server : Serverseitige SAP-Cookies<br />
HTTP-Client (Browser)<br />
Request<br />
Response<br />
Request<br />
WAS<br />
Server-Cookie :<br />
- Speichern von Zustandsdaten, Kontext in DB-Tabelle sscookie<br />
- Beliebige Typen und Mengen → Einzelwerte, Strukturen, ganze Tabellen<br />
- Lebensdauerkonzept<br />
- Zugriff durch statische Methoden der Klasse CL_BSP_SERVER_SIDE_COOKIE<br />
Vorteil : Ergebnisse komplexer Selects für direkten Wiederzugriff abgelegt<br />
Standardprogramme :<br />
BSP_SHOW_SERVER_COOKIES : zeigt alle Server-Cookies an<br />
BSP_CLEAN_UP_SERVER_COOKIES : löscht alle abgelaufenen Server-Cookies<br />
DB<br />
Serverseitiges<br />
Cookie :<br />
Speichern von<br />
Kontext in<br />
stateless-<br />
Anwendungen<br />
Serverseitigen SAP-Cookies: Serverseitige Cookies sind persistente Daten (Felder, Strukturen,<br />
ganze Tabellen) und werden in der DB des Systems abgelegt. Somit ist das Setzen und Lesen eines<br />
Server-Cookies ein DB-Zugriff. Sie werden nicht zwischen Client und Server hin und her transferiert.<br />
Es existiert ein Verfallszeitmechanismus.<br />
Ihr Vorteil:<br />
Man kann beliebig viele anlegen und sie haben unbegrenzte Größe.<br />
Anwendungsdaten werden in oft komplexen select-Anweisungen aus mehreren DB-Tabellen<br />
zusammengestellt. Indem man die einmal in einer internen Tabelle gesammelten Daten in Form<br />
eines serverseitigen Cookies auf der DB ablegt .....<br />
vermeidet man wiederholte komplexe Select-Anweisungen, und greift stattdessen die<br />
gewünschten Daten in einem einfacheren Zugriff ab.<br />
beschränkt man den DB-Zugriff auf die gewünschte Menge.<br />
Somit kann der Einsatz von Server-Cookies die Performanz steigern.<br />
Die Klasse CL_BSP_SERVER_SIDE_COOKIE stellt Methoden zum Arbeiten mit serverseitigen<br />
Cookies zur Vfg. Folgende Standardprogramme sind hilfreich:<br />
BSP_SHOW_SERVER_COOKIES : zeigt alle Server-Cookies an<br />
BSP_CLEAN_UP_SERVER_COOKIES : löscht alle abgelaufenen Server-Cookies<br />
Sollte als periodischer Batch-Job vom WAS-Admin eingeplant werden, da Server-Cookies, deren<br />
Verfallszeit abgelaufen ist, nicht automatisch gelöscht werden. Das Programm besteht nur aus<br />
einer Zeile: delete from sscookie where expiryd lt sy-datum.<br />
Jedoch wird beim Auslesen ein serverseitiges Cookie automatisch aus DB gelöscht. Soll es erhalten<br />
bleiben, muss es sofort im Anschluss an den Lesevorgang wieder auf die DB geschrieben werden. Die<br />
Verfallszeit kann in Sekunden oder Tagen angegeben werden.<br />
(11)
SAP-Server-Cookies : CL_BSP_SERVER_SIDE_COOKIE<br />
* Server-Cookie Schreiben :<br />
Cl_BSP_SERVER_SIDE_COOKIE ⇒set_server_cookie (<br />
exporting<br />
name = 'booklist'<br />
application_namespace = runtime→application_namespace<br />
application_name = runtime →application_name<br />
username = sy-uname<br />
session_id = runtime→session_id<br />
data_name = 'it_book_data'<br />
data_value = it_book_data<br />
expiry_time_rel = 3600 ).<br />
Server-Cookie auch unabhängig von bestimmter Anwendung,<br />
Session, User speicherbar<br />
In diesem Fall: application_namespace = 'NONE'<br />
application_name = 'NONE'<br />
username = 'NONE'<br />
session_id = 'NONE'<br />
(12)<br />
Server-Cookie hier<br />
angelegt für :<br />
- aktuellen User,<br />
- aktuelle Anwendung<br />
- aktuelle Session<br />
Nur für diese später<br />
auch zugreifbar ....<br />
Anwendungsname und<br />
Session-ID als Attribute des<br />
globalem Objekt runtime in<br />
allen Eventhandlern und<br />
Layout zur Vfg.<br />
Die Methodenparameter von set_server_cookie() und ihre Bedeutung:<br />
name Beliebiger Name des Cookies als String<br />
username Beleibiger Benutzername als String, muss nicht mit sy-uname<br />
übereinstimmen<br />
data_name Datenname als String – muss identisch mit 'data_value' sein<br />
data_value Dateninhalte beliebigen Typs, auch interne Tabellen<br />
expiry_time_rel Relative Lebensdauer in Sekunden als Integer<br />
expiry_date_rel Relative Lebensdauer in Tagen als Integer<br />
expiry_time_abs Absolute Lebensdauer als Zeitfeld vom Typ T<br />
expiry_date_abs Absolute Lebensdauer als Datumsfeld vom Typ D<br />
Mit den Parametern data_value und data_name werden zu sichernder Datenobjektinhalt und<br />
Datenobjektname festgelegt. Dies ist notwending, wel die Cookie-Daten in einer generischen<br />
Clustertabelle auf der DB gespeichert werden.<br />
Zur endeutigen Identifizierung eines Server-Cookies sind die Session-ID sowie Benutzer- und<br />
Anwendungsname geeignet. Diese Werte stehen als Attribute des automatisch instantiierten Objekts<br />
runtime zur Vfg.<br />
Man kann ein Server-Cookie auch Anwendungs-, Session- und Benutzer-unabhängig ablegen! In<br />
diesem Fall würde man den Parametern:<br />
application_namespace application_name username session_id<br />
einfach zB als Default den String-Wert 'NONE' zuweisen.<br />
Auf Server-Cookies deren Vefallszeit abgelaufen ist, kann nicht mehr zugegriffen werden. Sie werden<br />
jedoch nicht automatisch aus der DB gelöscht.
SAP-Server-Cookies : CL_BSP_SERVER_SIDE_COOKIE<br />
* Server-Cookie Lesen<br />
Data: ex_d type SYDATE .<br />
Data: ex_t type SYTIME .<br />
Cl_BSP_SERVER_SIDE_COOKIE ⇒get_server_cookie (<br />
exporting<br />
name = 'booklist'<br />
application_namespace = runtime→application_namespace<br />
application_name = runtime →application_name<br />
username = sy-uname<br />
session_id = runtime→session_id<br />
data_name<br />
importing<br />
= 'bookshop_data'<br />
expiry_date = ex_d<br />
expiry_time<br />
changing<br />
= ex_t<br />
data_value = it_book_data ) .<br />
* Server-Cookie Löschen - unahängig von Lebensdauer<br />
Cl_BSP_SERVER_SIDE_COOKIE ⇒ delete_server_cookie ( .... ) .<br />
(13)<br />
Alle Parameter außer<br />
Lebensdauer sind auch<br />
beim Auslesen<br />
mitzugeben ...<br />
Alle Parameter (außer der Lebensdauer) müssen auch beim Lesen wieder mitgegeben werden, damit<br />
das richtige Cookie gefunden wird.<br />
Die Methode get_server_cookie() liefert auserdem die Lebensdauer des Server-Cookies zurück,<br />
und zwar als Datums- oder Zeitfeld in Form der SAP-Dictionary-Datentypen SYDATE und SYTIME.<br />
Es existiert eine eigene Methode delete_server_cookie(), um das Cookie manuell (unabhängig von<br />
seiner Lebensdauer) aus der DB zu löschen:<br />
Cl_BSP_SERVER_SIDE_COOKIE ⇒ delete_server_cookie (<br />
exporting<br />
name = 'booklist"<br />
application_namespace = runtime→application_namespace<br />
application_name = runtime →application_name<br />
username = sy-uname<br />
session_id = runtime→session_id ).<br />
Anmerkung: Der Hauptspeicher des NWAS scheidet zum Zwischenspeichern von Sitzungs-daten<br />
aus, da die Session bei jedem Request auf einer anderen Maschine bearbeitet werden kann, falls es<br />
sich um ein SAP-System aus mehreren WAS handelt. Die Verteilung des Speicherinhalts auf alle<br />
Applikationsserver wäre zu aufwendig.
Datenhaltung bei Stateless-Anwendungen<br />
via Netzwerk<br />
Hidden Field, set_parameter()<br />
- Begrenzte Datenmenge<br />
- Benötigt keine DB-Zugriffe<br />
- Belastet das Netzwerk<br />
Client-Cookie<br />
- Begrenzte Zahl und Datenmenge<br />
- Vom Browser-User abschaltbar<br />
- Benötigt keine DB-Zugriffe<br />
- Belastet das Netzwerk<br />
via Datenbank<br />
Quelle: [WOLF03]<br />
Server-Cookie + DB-Ablage<br />
- Unbegrenzte Datenmenge<br />
- Schont das Netzwerk<br />
- Belastet die DB-Performanz<br />
- Belegt DB-Speicher<br />
- Regelmäßiges "Säubern" nötig<br />
Stateful oder Stateless :<br />
Sehr grosse Zahl gleichzeitiger User ⇒ stateless<br />
Komplexere Anwendung, wenige User, aufwendige DB-Zugriffe ⇒ stateful<br />
Auch - oder gerade - in stateless Applikationen stellt sich die Frage, wie trotz Verlustes des<br />
Anwendungskontextes nach jedem Request, z.B. Benutzereingaben über mehrere Requests hinweg<br />
gerettet werden können. Hierzu ist entsprechende Funktionalität zu programmieren. Es gibt zwei<br />
Verfahrensgruppen - Verwendung des Netzwerks bzw der Datenbank.<br />
Je kleiner die zu haltende Datenmenge (bis zu wenigen kB), desto effizienter ist die Netzwerk-<br />
Lösung. Wird die bei jeder Benutzeraktion über das Netz zu übertragende Datenmenge größer,<br />
resultieren jedoch schnell nicht mehr akzeptable Antwortzeiten.<br />
Die Datenbank hat den Vorteil, dass in ihr auch grosse Datenmengen verarbeitet werden können.<br />
Allerdings ist die Datenbank der "bottleneck" des SAP-Systems.<br />
Daumenregel: stateful oder stateless?<br />
Als Daumenregel gilt, daß Internetszenarien, die von einer potenziell sehr großen Anzahl Benutzer<br />
gleichzeitig genutzt werden, eher stateless arbeiten sollten. Komplexere Anwendungen, die von<br />
einer begrenzten Anzahl Benutzer parallel eingesetzt werden und die über einem teurer zu<br />
ermittelnden Datenbestand operieren, bieten sich eher für das stateful Programmieren an.<br />
Stateless BSP-Applikation blockieren nur dann Server-Ressourcen, solange ein einzelner Request<br />
bearbeitet wird. Nach Abarbeitung des Requests werden alle Ressourcen an das System<br />
zurückgegeben und für andere Requests eingesetzt.<br />
Stateless Applikation erlauben somit – aus Sicht der Ressource "Speicher" – eine optimale<br />
Skalierung. Andererseits kann das Freigeben des Anwendungskontext nach jedem Request<br />
erfordern, dieselben Daten mehrfach aus der Datenbank zu lesen und aufzubereiten. Somit wird die<br />
Einsparung an Speicher durch Laufzeit-Einbußen möglicherweise kompensiert. Dies ist von Fall zu<br />
Fall genau zu analysieren und zu beurteilen.<br />
(14)
Zustände BSP-Anwendung<br />
Webbrowser 1<br />
Webbrowser 2<br />
Internet<br />
WAS<br />
1<br />
1<br />
1<br />
1<br />
2<br />
2<br />
2<br />
2<br />
Zeit<br />
(15)<br />
stateful stateless<br />
Quelle:<br />
Heinemann, Rau 2005<br />
Stateful :<br />
Seiten-Objekt bleibt<br />
erhalten ⇒<br />
OnCreate nur einmal<br />
durchlaufen !<br />
OnDestroy gar nicht !<br />
Die Aufrufabfolge der Event-Handler ist abhängig vom Zustandmodell der BSP-Applikation bzw. -<br />
Seite , da sich der Aufruf der Events nach der Lebenszeit des BSP-Seitenobjekts richtet.<br />
Stateless-Modell: Bei der Bearbeitung eines Request überprüft die BSP-Laufzeit, ob für die<br />
angeforderte Seite bereits ein Seitenobjekt existiert. Falls kein Seitenobjekt existiert, wird der<br />
OnCreate-Handler aufgerufen und durchlaufen und für die Seite ein Seitenobjekt erzeugt. Auto-<br />
Seitenattribute werden übernommen, so dass sie der Seite zur Vfg stehen. Es folgt OnRequest.<br />
Falls eine Benutzeraktion voranging, wird OnInputProcessing angestoßen. Dessen Programmcode<br />
kann auf eine andere Seite navigieren oder auf der Seite verbleiben.<br />
Im ersten Fall wird der OnDestroy-Handler aufgerufen und das Seitenobjekt zerstört. Daraufhin<br />
beginnt der Zyklus für die annavigierte Seite von Neuem.<br />
Im zweiten Fall würde OnInitialization derselben Seite aufgerufen. Im Anschluss erfolgt das<br />
Zusammenführen statischen Layout-HTMLs und dynamischen ABAP-Layout-Codes und die<br />
Einbettung in einen HTTP-Datenstrom im OnLayout-Handler. Danach wird OnManipulation<br />
aufgerufen; hierin kann der Datenstrom noch verändert werden. Daraufhin wird OnDestroy<br />
angestoßen und das Seitenobjekt gelöscht. In OnDestroy bietet es sich im stateless-Fall an,<br />
Zustandsdaten zu sichern. Abschließend wird der HTTP-Datenstrom an den Client geschickt.<br />
Das Statefull-Modell unterscheidet sich im Ablauf der Handler vom Stateless-Modell nur bezüglich<br />
des OnCreate- und OnDestroy-Events. Im Statefull-Modell bleiben die Seitenobjekte einer BSP-<br />
Applikation für die gesamte Dauer der BSP-Session erhalten.<br />
Daher wird OnCreate für jede BSP-Seite nur einmal ausgeführt.<br />
Das Event OnDestroy wird im Stateful-Fall überhaupt nicht prozessiert, da während einer Stateful-<br />
Session keine Seitenobjekte zerstört werden.<br />
1<br />
2<br />
2<br />
1<br />
2
Online Text Repository OTR : Internationalisierung<br />
Ziel: Anwendung in mehreren Sprachen (sprachunabhängig)<br />
OTR: Zentrale paketspezifische Textablage + Dienste zur Texterfassung und Übersetzung<br />
OTR-Tags im BSP-Layout verwendbar – Textarten :<br />
1. Kurztexte (Aliastexte): Unter Aliasnamen paketweit ansprechbar<br />
2. Langtexte: Direkt in OTR-Tags eingeschlossen<br />
<br />
<br />
<br />
OTR-Texte <br />
<br />
<br />
<br />
Dieser Text ist lang und kommt nur einmal vor.<br />
Deshalb im OTR als Langtext abgelegt<br />
<br />
<br />
<br />
<br />
<br />
<br />
Paketname immer Teil des<br />
Aliasnamens !<br />
(16)<br />
<br />
..... <br />
Alle BSP-Seiten und Seitenfragmente können auf<br />
alle OTR-Texte des Pakets zugreifen ......<br />
Pflege der OTR-Texte :<br />
a) Kurztexte aus Layout durch Doppelklick auf<br />
OTR-Referenz (Vorwärtsnavigation ins Pflegebild<br />
für OTR-Texte)<br />
b) durch Menü Springen → OTR Browser<br />
c) durch Direkteinstieg in TA SOTR_EDIT<br />
Übersetzung der OTR-Texte :<br />
Springen → Übersetzung →<br />
OTR Kurztexte / Langtexte<br />
Weitere Infos in [WOLF03]<br />
Das OTR ist die zentrale Textablage. Im BSP-Layout können OTR-Direktiven eingesetzt werden.<br />
OTR-Objekte sind einem Paket zugeordnet und werden in Transportaufträge aufgenommen. Damit<br />
eine BSP-Anwendung in mehreren Sprachen zur Vfg steht, sollte man im Layout alle<br />
übersetzungsrelevanten Teile als OTR-Texte angeben. (Übersetzung in TA SE63).<br />
Es werden Langtexte und Kurztexte unterschieden, wobei die absolute Länge des abgelegten Textes<br />
nicht wesentliches Untescheidungsmerkmal ist. Wichtiger ist die Häufigkeit des Vorkommens:<br />
Kommt ein Text nur einmal in einer BSP-Anwendung vor, dann wird der Text als Langtext im OTR<br />
abgelegt. Man legt einen Langtext an, indem man im Layout der BSP den Text selbst zwischen die<br />
Tags ..... schreibt und die Seite aktiviert. Dadurch wird der Text automatisch ins<br />
OTR eingetragen. Langtexte stehen für sich selbst, dh sind nicht über einen Aliasnamen oder<br />
Schlüssel erreichbar.<br />
Wird dagegen ein Text häufig gebraucht, wird der Text unter einem Aliasnamen als Kurztext im<br />
OTR abgelegt. Über diesen Aliasnamen ist dieser Text paketweit ansprechbar und somit<br />
wiederverwendbar. Die Übersetzung muss nur einmal erfolgen. Das Anlegen von Kurztexten erfolgt<br />
durch Schreiben des Tags und Doppelklick auf den Aliasnamen. Auf<br />
einem Bildschirmbild kann man den Aliasnamen, die maximale Textlänge und den Text pflegen. Der<br />
Aliasname beginnt immer mit dem Namen des zugeordneten Pakets.<br />
Um Texte zu übersetzen, muss durch das Menü Springen → Übersetzung → OTR Langtext in die<br />
Übersetzung verzweigt werden.<br />
Man erhält einen Überblick über alle dem Paket zugeordneten OTR-Texte im OTR-Browser,<br />
erreichbar durch das BSP-Layout-Menü Springen → OTR Browser. Im OTR wird auch ein Kontext zu<br />
jedem OTR-Objekt (Ersteller, Datum, ....) gespeichert.
OTR<br />
Notation nur im Layout-Bereich anwendbar.<br />
Jedoch auch in Eventhandlern und Anwendungsklasse Zugriff auf Kurztexte<br />
mittels runtime-Objekt oder Klasse CL_BSP_GET_TEXT_BY_ALIAS :<br />
DATA: alias TYPE STRING, text TYPE STRING.<br />
alias = ' zbsptest/gruss '.<br />
text = runtime→get_otr_text( alias ).<br />
CL_BSP_GET_TEXT_BY_ALIAS ⇒ get_text (<br />
exporting language = 'EN'<br />
alias = alias<br />
importing alias_text = text ) .<br />
OTR-Texte können in Übersetzungsvarianten<br />
unterschiedliche Länge aufweisen ⇒<br />
Abschneiden überschüssiger Leerzeichen im<br />
Layout durch BSP-Seitendirektive :<br />
<br />
Die OTR-Referenz wird intern in einen Methoden-aufruf der runtime-Instanz<br />
aufgelöst. Der Methodenaufruf cl_bsp-runtime=>get_otr_text() kann auch in den Eventhandlern und<br />
der Anwendungsklasse erfolgen - aber auch in Reports und konventionellen ABAP-Programmen<br />
außerhalb der BSP-Programmierung. Vertiefung siehe [WOLF03].<br />
Eine Anwendungsmöglichkeit ist die sprachunabhängige Hinterlegung von Fehlermeldungen, die<br />
beim Prozessieren der Eventhandler erzeugt werden - oder die Wiederverwendung von Texten auch<br />
innerhalb derselben Sprache. OTR-Texte werden auf dem WAS gepuffert - dies macht den Zugriff<br />
schnell. Durch das Systemkommando /$otr kann der OTR-Puffer manuelle zurückgesetzt<br />
werden, wenn Textänderungen vorgenommen worden sind.<br />
Auch mittels der Klasse CL_BSP_GET_TEXT_BY_ALIAS kann auf OTR-Texte zugegriffen werden.<br />
Die Klasse hat nur eine statische Methode get_text(). Hier kann auch die gewünschte Sprache als<br />
Parameter übergeben werden. Somit können auch Texte in Sprachen verwendet werden, die nicht der<br />
Anmeldesprache des Benutzers entsprechen.<br />
Damit eine BSP in der gewünschten Sprache angezeigt wird, muss diese Sprache im benutzten<br />
Service hinterlegt sein. Dazu werden in der TA SICF Alias-Services eingerichtet.<br />
OTR-Texte können Parameter beinhalten. Hierzu wird der Platzhalter für den Parameter durch das &<br />
eingeschlossen. Nur Buchstaben, Ziffern und Unterstrich sind erlaubt. Zur Laufzeit wird dann der<br />
benannte Platzhalter durch einen Wert (zB Seitenattribut) ersetzt.<br />
Wenn man einen OTR-String anlegt und in verschiedene Sprachen übersetzt, so wird die Länge der<br />
übersetzten Strings in der Regel in den verschiedenen Sprachen unterschiedlich sein. Ein langer<br />
OTR-String könnte sehr kurze Übersetzungen besitzen. Allerdings wird mit dem String in allen seinen<br />
Übersetzungen durch das OTR-System stets nur die Länge des Orginal-Strings gespeichert - und<br />
liefert somit eventuell OTR-Strings mit überschüssigen Spaces zurück, so dass HTML-Darstellungen<br />
unschön verbreitert sind. Die o.a. BSP-Seitendirektive sorgt dafür, dass aus jedem in die Seite<br />
eingefügten OTR-Strings überflüssige Spaces entfernt werden.<br />
(17)
Timeout-Situationen : Session-Timeout und Processing-Timeout<br />
1. Session-Timeout<br />
HTTP → Server kann nur passiv auf eingehende Client-Requests reagieren.<br />
⇒ Server merkt nicht, wenn Client abspringt (Browser schliesst, wegnavigiert, untätig ist)<br />
⇒ Bindet kritische Ressourcen (Status) auf dem Server<br />
⇒ Inaktive Sessions nach vorkonfigurierter idle time vom ICM abgeräumt !<br />
Rollback, Sperren(!) + Ressourcen freigeben, Session gelöscht<br />
Maximum idle time :<br />
Konfiguriert in Systemprofil-Parameter rdisp/plugin_auto_logout<br />
Default : 30 Minuten<br />
Client-Browser bekommt timeout allerdings nicht mit, nicht vom Server darüber informierbar.<br />
Erst bei nächsten Roundtrip tritt Fehler wegen inaktiver Session auf.<br />
Benutzer-Info mittels Workaround : Nach idle time → Browser-Fenster via Skript löschen:<br />
<br />
var T = 31 /*min*/ * 60 * 1000; /*ms*/<br />
window.setTimeout( "document.URL = 'about:blank' ;" , T ) ;<br />
<br />
Gilt stets für gesamten WAS<br />
und alle BSP-Anwendungen,<br />
nicht für einzelne BSP-<br />
Anwendungen verlängerbar,<br />
jedoch in SICF verkürzbar<br />
Der Session-Timeout bezieht sich auf das Browser-Verhalten: Wenn sich Browser nach Ablauf dieser<br />
Zeit nicht mehr meldet wird der Kontext verworfen<br />
HTTP ist ein striktes Request/Response-Protokoll; der Server kann nur auf einen Browser-Request hin<br />
tätig werden. Der Server kann nicht beim Browser "nachfragen": "Bist du noch da". Er kann höchstens<br />
für sich einen internen Timeout setzen und nach dessen Ablauf die Verbindung schliessen. Der Server<br />
kann dem Browser zu keinen Zeiten "zwischendurch" Informationen zukommen lassen. Somit kann<br />
der Browser auch nicht über eingetretene Session-Timeouts informiert werden. Die Session wird<br />
einfach beendet, ohne dass im Browser-Fenster etwas darauf hindeutet. Wenn der User später an<br />
seinen Arbeitsplatz zurückkehrt, so sieht er im Browser weiterhin die offene scheinbar noch laufende<br />
BSP-Anwendung. Erst bei der nächsten Interaktion tritt ein Fehler auf und der User bemerkt die<br />
verlorene Session.<br />
Als Hilfe für den User dient das clientseitige JavaScript, das in jede Seite der BSP-Anwendung<br />
einzubauen wäre. Solange der User mit der BSP-Anwendung interagiert setzt sich jede neu geladene<br />
Seite einen neu initialisiereten Timer. Im Skript gehen wir von einer Server-idle time von 30 Minuten<br />
aus. Sollte der User den Browser länger als 31 Minuten nicht bedienen (keine neuen Seiten anfordern)<br />
so wird der Brower-Screen gelöscht - und der User bemerkt auf diese Weise, dass die Session<br />
serverseitig beendet wurde.<br />
Es ist möglich, den Server darüber zu informieren, dass der Browser die BSP-Anwendung verlässt<br />
(wegnavigiert oder geschlossen wird), indem das onUnLoad-JavaScript-Event der Seiten verwendet<br />
wird und eine JavaScript-Funktion appUnload() implementiert wird. Diese wird beim Eintreten von<br />
onUnLoad augerufen. Für Details der Lösung (Verwendung von Framesets) verweisen wir auf<br />
[MCKE06], S.125ff.<br />
(18)
Timeout-Situationen : Session-Timeout und Processing-Timeout<br />
2. Processing-Timeout<br />
Maximale Prozessdauer für Bearbeitung HTTP-Request durch ABAP-Stack auf Server<br />
Bei Überschreiten wird ABAP-Session + BSP-Anwendung abgebrochen<br />
⇒ Fehlermeldung 500 Connection timed out an Browser<br />
In ICM-Verwaltung SMICM eingesehbar :<br />
Wird pro offenem HTTP-Port eingestellt<br />
Konfigurierbar in Systemprofil-Parameter: icm/server_port<br />
(19)<br />
Ermöglichen längerer Prozessdauern :<br />
Neuen HTTP- Port in SMICM<br />
definieren mit längerer maximaler<br />
Prozessdauer :<br />
Springen → Services und dort<br />
Service→ Anlegen<br />
Verfügbar nach Neustart NWAS<br />
Der "Connection Timeout" ist die Folge eines Überschreitens der maximalen Prozessdauer. Er<br />
drückt aus, dass die Verbindung zwischen ICM und ABAP-Stack eine Zeitüberschreitung erfahren hat.<br />
Die Fehlermeldung hat nichts zu tun mit einem Session-Timeout (idle timeout).<br />
Länger als dieses Zeitintervall darf die Request-Bearbeitung durch die WAS-Workprozesse nicht<br />
dauern, sonst wird die Bearbeitung abgebrochen und der User erhält eine Fehlerseite. Wenn dieses<br />
Zeit zu knapp eingestellt ist, dann kann nicht mehr richtig debuggt werden, da die Dauer des Debugs<br />
einfliesst.<br />
In Produktivsystemen ist die maximale Prozessdauer meist auf relativ kleine Werte gesetzt, so dass<br />
Workprozesse nicht lange blockiert werden können. Nachteilig kann sein, dass Debuggen von BSP-<br />
Anwendungen nicht mehr funktioniert, da der Debug-Vorgang in die Prozessdauer eingeht. Abhilfe<br />
schafft das Anlegen eines weiteren HTTP-Ports mit längerer maximaler Prozessdauer. Die URL<br />
(Port-Nummer) der BSP-Anwendung muss im Browser entsprechend geändert werden, damit sie beim<br />
Aufruf über den neuen Port läuft.<br />
Anmerkung: Die keep-alive Zeit (sichtbar in TA SMICM) legt gemäß HTTP1.1 die Zeit in Sekunden<br />
fest, die der ICM eine untätige TCP-Verbindung offen hält (und auf einen Browser-Request) wartet,<br />
ehe er sie schliesst. Die Wiederverwendung von TCP-Verbindungen verbessert das Antwortverhalten<br />
bei HTTP-Requests, da keine erneuten Roundtrips zwischen Browser und Server nötig sind, um eine<br />
neue TCP-Verbindung aufzusetzen. Allerdings ist die maximale Zahl gleichzeitig offener TCP-<br />
Verbindungen des Servers begrenzt. Deshalb werden nicht verwendete TCP-Verbindungen nach<br />
einigen Sekunden idle time geschlossen.<br />
Die Profil-Parameter des ICM können in der TA SICM eingesehen werden durch Aufruf des<br />
Memüpunkts Springen→Parameter→Anzeigen. Hier finden sich auch die Einstellungen für maximale<br />
Zeitdauern
LZ- Fehler-Behandlung<br />
Historische BSP Error Pages → seit 6.40 inaktiv !<br />
Neues Konzept ab 6.40 :<br />
(20)<br />
BSP Runtime setzt TRY / CATCH<br />
um jeden Seitenaufruf. Wenn beim<br />
Prozessieren der BSP LZ-Exception<br />
auftritt wird Kontrolle an Fehlerseite<br />
übergeben<br />
Problem :<br />
Auch die Fehlerseite ist eine BSP !<br />
⇓<br />
Nicht sinnvoll bei Schiefstand im<br />
BSP-Framework !<br />
Wenn Exception auftritt, wird BSP-Framework sofort verlassen + ICF übernimmt Kontrolle<br />
ICF-Klasse CL_HTTP_EXT_BSP fängt Fehler aus BSP-Anwendungen + erzeugt generische<br />
HTML-Fehlerseite mittels Methode REPORT_ERROR_HTML.<br />
Ausprobieren in BSP z.B. mit : <br />
Durch das Konzept der BSP Fehlerseiten konnten in jeder BSP-Anwendung eine oder mehrere<br />
BSP-Seiten als Fehlerseiten ausgewiesen werden. Dies geschah einfach durch Setzen eines Eintrags<br />
auf der Eigenschaftenseite. Problematisch daran ist, dass es sich bei der Fehlerseite selbst auch um<br />
eine BSP handelt. Tritt ein Fehler auf, so startet die Fehlerseite in der fehlerbehafteten Umgebung der<br />
Orginal-BSP. Die Fehlerseite hat keine Information darüber, was von der Orginal-BSP bereits in das<br />
HTTP response-Objekt geschrieben wurde – und somit Teil der erzeugten Antwort ist, die an den<br />
Client geht. Zudem könnte auch der gesamte BSP-Stack selbst in einem fragwürdigen Zustand sein.<br />
Schlimmstenfalls könnte die Fehlerseite selbst einen Fehler auslösen, während sie auf den Fehler der<br />
Original-BSP eingeht.<br />
Aufgrund dieser Problematik hat SAP ab NWAS 6.40 den Support für das Fehlerseiten-Konzept<br />
eingestellt: Alle Fehlerseiten-Einträge auf BSP-Eigenschaftsseiten werden seitdem einfach von der<br />
BSP-Laufzeit ignoriert. Allerdings wurde sofort ein neues Konzept ausgeliefert, das BSP-Anwender<br />
auch customizen können: Wenn eine LZ-Exception auftritt, so wird das BSP-Framework komplett<br />
verlassen und das ICF übernimmt die Kontrolle mit eingestellten Fehlerklassen. Die automatisch<br />
erzeugten generischen Fehlerseiten decken die meisten LZ-Fehler-Situationen ab und liefern viele<br />
Diagnose-Informationen.<br />
Konfigurations-Möglichkeiten: In DB-Tabelle BSPERRHANDLER kann eine andere Fehler-Klasse<br />
und ihre Methode hinterlegt werden, die im LZ-Fehlerfall gerufen wird. Mittels Wildcards (*) in der<br />
angegebenen URL kann eine Fehlerklasse für eine Gesamtheit von BSP-Anwendungen vorgesehen<br />
werden. Die Klasse CL_BSP_ERRHANDLER_SAMPLE enthält ein SAP-Beispiel für eine selbstgeschriebene<br />
Fehlerklasse und ihre Methode REPORT_ERROR_HTML. Die Klassen<br />
CL_BSP_ERRHANDLER und CL_HTTP_EXT_BSP können als Kopiervorlagen für eigene<br />
Fehlerklassen dienen.<br />
Man befindet sich dabei jedoch nicht mehr innerhalb des BSP-Frameworks. Somit können BSP<br />
Extensions und HTMLB nicht eingesetzt werden! Es ist ein HTML-String zusammenzustellen und dem<br />
ICF-response-Objekt zu übergeben: response→append_cdata( html ).
Fehler-Behandlung – Fehlermeldungen erzeugen + verwalten<br />
ICF-Klasse CL_BSP_MESSAGES erlaubt Speichern + Abfragen von Meldungen<br />
Referenz darauf durch message-Attribut des page-Objekts: page→messages<br />
Methoden zum Verwalten selbstverfasster Meldungen aufgrund eigener Prüfungen :<br />
page→messages→add_message( condition = ' feldname'<br />
message = ' Hier der erläuternde Text '<br />
severity = 1 ).<br />
if page→messages→num_messages( ) is not initial.<br />
data: feldname type string.<br />
data: text type string.<br />
data: sev type i.<br />
page→messages→get_message (<br />
exporting index = 1<br />
importing condition = feldname<br />
mesagge = text<br />
severity = sev ) .<br />
endif.<br />
page→messages→delete_message( condition = 'feldname' ).<br />
page→messages→reset( ).<br />
(21)<br />
Bedeutung der Parameter<br />
condition :<br />
Feldname, dem der Fehler<br />
zuzuordnen ist<br />
message :<br />
Beschreibender Meldungstext<br />
severity (optional) :<br />
Fehlerschwere (default = Error)<br />
Durch eigene Prüfungen innerhalb der Anwendung können Fehlersituationen unterschied-licher<br />
Schwere bemerkt werden. Die zugehörige Information kann mit einem Fehlertext, einer Fehlerstufe<br />
und der Nennung eines zugehörigen Feldnamens (dessen Werte für den Fehler verantwortlich sind)<br />
übersichtlich verwaltet werden. Dazu werden einem message-Objekt Informationen übergeben. Ein<br />
message-Objekt der Klasse CL_BSP_MESSAGES steht als Attribut messages des automatisch<br />
erzeugten page-Objekts zur Verfügung.<br />
Es ist möglich, dass mehrere Formularfelder auf einer BSP fehlerhaft sind. In diesem Fall sollte<br />
(ähnlich wie bei der Dynpro-Verarbeitung) immer nur die erste Fehlermeldung ausgegeben werden.<br />
Durch den Aufruf der Methode num_messages() kann überprüft werden, ob überhaupt ein Fehler<br />
aufgetreten ist.<br />
Eventuell ist es sinnvoll, entsprechende Methoden in der Applikationsklasse zu kapseln.<br />
Die Klasse CL_BSP_MESSAGES enthält konstante Attribute, durch die die Fehlerschwere<br />
(Fehlersufen / severity) als Integer codiert werden kann. Die Fehlerschwere ist ein Kennzeichen, durch<br />
das entschieden werden kann, ob nur eine Warnung ausgegeben werden oder aber die vielleicht die<br />
gesamte BSP-Anwendung abgebrochen werden soll:<br />
CO_SEVERITY_ERROR Fehlerstufe: Fehler<br />
CO_SEVERITY_FATAL_ERROR Fehlerstufe: Fataler Fehler<br />
CO_SEVERITY_INFO Fehlerstufe: Nur eine Information<br />
CO_SEVERITY_SUCCESS Fehlerstufe: Erfolgsmeldung<br />
CO_SEVERITY_WARNING Fehlerstufe: Nur eine Warnung
Einstellung Anmeldedialog<br />
(22)<br />
In SICF ist für einen Service das<br />
Anmeldeverhalten der Anwendung<br />
einstellbar über:<br />
Fehlerseiten • Anmeldefehler<br />
Systemanmeldung • Konfiguration<br />
Definition service-spezifischer<br />
Einstellungen möglich, die von globalen<br />
Einstellungen abweichen<br />
Mittels Aliases kann sogar für eine Anwendung eine Vielzahl unterschiedlicher Anmeldes-creens<br />
hinterlegt werden – dies ist insbesondere dann nützlich, wenn man verschiedene interne und externe<br />
Zugänge zu einer Anwendung unterstützen möchte. Insbesondere können Mandant und<br />
Anmeldesprache bereits hinterlegt werden.<br />
Das Look & Feel der Anmeldeseite kann eingestellt werden, indem man auf SAP-Vorlagen<br />
zurückgreift. Es ist jedoch sogar möglich, ein benutzerspezifisches Layout und Ablauf der Anmeldung<br />
zu hinterlegen, indem man eine ABAP-OO-Klasse hinterlegt, die von der Klasse<br />
CL_ICF_SYSTEM_LOGIN erbt. Als Kopiervorlage oder anpassbares Beispiel liefert SAP dazu die<br />
Klasse CL_ICF_EXAMPLE01_LOGIN aus.
Performance-Analyse<br />
Anteile im Zeitverbrauch für BSP-Anwendungen :<br />
1. Reine Netzwerk-Übertragungszeit: Tool ping mit Option -l für variable Datenpaketgröße<br />
C:\> ping -l 32950 m65z05.hcc.uni-magdeburg.de<br />
2. BSP-Laufzeit auf NWAS + im Netz für Request-Response-Zyklus<br />
SAP-BSP-Testprogramm IT03 → Testseiten zwischen 1 und 64 KB<br />
3. Reine Server-Prozessdauer mittels ABAP-Stopuhr-Funktion GET RUN TIME FIELD<br />
4. Browser Rendering : Seitenaubau-Zeit mittels JavaScript-Stoppuhr Date()<br />
<br />
var renderStart = new Date() ; <br />
ABAP- und Browser-Stoppuhr-<br />
....................... <br />
Funktionen klammern das<br />
Seitencoding<br />
<br />
var renderEnd = new Date() ;<br />
var renderTime = renderEnd.getTime() - renderStart.getTime();<br />
window.status = "Server=" + "" + " Render-Time=" + renderTime ;<br />
<br />
Verschiedene Anteile der Ausführungsdauer einer BSP-Anwendung sowie Analyse-Tools:<br />
Durch das ping-Tool wird die reine Netzwerk-Übertragungszeit gemessen. Das Tool sendet einen<br />
kleinen Test-Request an den Server (Datengröße einstellbar, default 32 Bytes) und der Server liefert<br />
einfach die gleichen Daten zurück. Alles passiert auf OS-Ebene und enthält kaum Server-Overhead.<br />
Die ermitelte Zeit ist die Summe aus Request + Response Zeit.<br />
Die SAP Demoanwendung IT03 liefert einfach nur Testseiten unterschiedlicher Grösse und<br />
Zusammensetzung (Text oder Bilder). Dabei sind alle Schichten des WAS beteiligt. Die benötigte Zeit<br />
ist die Zeit zum Füllen des ABAP-Buffers, übertragen zum ICM Erzeugen von HTTP, Übergabe ans<br />
Netzwerk und Übermittlung zum Browser.<br />
Die reine Server-Prozessdauer kann mittels ABAP-Stoppuhr-Funktion gemessen werden, deren<br />
paarweise Aufrufe die gesamte BSP-Seite einklammern. Das o.a. JavaScript gibt die Zeitdauer in der<br />
Statusleiste des Browsers aus. Gemessen wird die Zeit, die im Applikationscoding verbraucht wird; sie<br />
enthält keinen BSP-LZ-Overhead.<br />
Die Browser-Rendering-Zeit (Aufbau + Darstellung der HTML-Seite) muss im Browser mit JavaScript<br />
ermittelt werden. Die Differenz zwischen Start- und Endzeit der Seitenbearbeitung wird gemessen. Die<br />
JavaScript-Aufrufe stehen außerhalb des gesamten HTML-Codes der Seite.<br />
(23)
Performance-Analyse<br />
Workbench-Performance-Tools<br />
Statistical Records : ABAP-Laufzeit ohne ICM-Zeiten<br />
1. Aktivieren mit ABAP-Programm RSSTATISTIC<br />
2. BSP-Anwendungen ausführen<br />
3. TA STAD aufrufen, um die Statistik-Files auszulesen<br />
Filtern nach Ausführungszeit, User und Programm SAPMHTTP<br />
(24)<br />
Doppelklick auf Eintrag<br />
liefert detaillierte Daten<br />
zu Zeiten und<br />
Speicherverbrauch<br />
Um die aktuelle Server-Prozesszeit zu messen können Statistical-Records verwendet werden. Diese<br />
schreiben durch das ICF sehr kleine Zeitstempel in die BSP-Anwendung. Die gemessenen Zeiten<br />
geben die komplette ABAP-Laufzeit wieder. Die Statistik-Optionen sind per Default nicht für HTTP<br />
aktiviert und müssen gesondert aktiviert werden.<br />
Zum Auswerten dient die TA STAD. Der Zeitfilter ist entsprechend der Zeit des Tests zu stetzen und<br />
die Ausgabe auf das Programm SAPMHTTP zu begrenzen. (Dieses Programm ist der allererste<br />
Aktivierungsschritt, wenn HTTP-Calls auf den ABAP-Stack plaziert werden.)<br />
Typischerweise dauert der erste Seitenzugriff deutlich länger als nachfolgende Zugriffe auf die<br />
gleiche Seite. Beim ersten Zugriff muss die ABAP-Load der BSP-Seite aus der Datenbank beschafft<br />
und in den Programmpuffer geladen werden, so dass ein großer DB-Overhead resultiert, der bei<br />
folgenden Zugriffen nicht mehr auftritt.<br />
Laufzeitanalyse: Sehr detaillierte Informationen liefert die Laufzeit-Analyse, deren Daten für eine<br />
Anwendung in der TA SE30 angezeigt werden.<br />
1. Die Laufzeitanalyse für BSP-Anwendungen wird aktiviert in der Serviceverwaltung TA SICF. Dort<br />
den Menüpfad Bearbeiten→Laufzeitanalyse →Aktivieren wählen.<br />
2. Die zu analysierende BSP-Anwendung ist auszuführen.<br />
3. In der TA SE30 können die gesammelten Daten analysiert werden.<br />
Die erfassten Informationen betreffen DB-Zugriffe, Funktions- und Methoden-Aufrufe, Aufruf-<br />
Hierachien - und ermöglichen auch Sprünge an Sourcecode-Stellen, deren Laufzeitverhalten<br />
ermittelt wurde ..... und vieles mehr ....<br />
Die Besprechung dieses reichhaltigen Tools übersteigt jedoch deutlich den Fokus unserer<br />
Vorlesung. Weitere Informationen finden sich in: Thomas Schneider "SAP-Performanceoptimierung.<br />
Analyse und Tuning von SAP-Systemen."
BSP-Caching : ICM Server Cache<br />
Erhöhung Performanz + Skalierbarkeit von BSP-Anwendungen (bis zu Faktor 20)<br />
→ Für BSP-Erstellung notwendige Server-Ressourcen werden reduziert.<br />
→ Wiederholte Ausführung häufig angeforderter BSPs entfällt.<br />
Steuerung des BSP-Caching-Verhaltens<br />
1. SE80 → BSP-Eigenschaften → Caching<br />
- Verfallsdauer für Caching im Internet Server-Cache<br />
- Verfallsdauer für Caching im Browser-Client<br />
- Browserabhängiges Seiten-Caching<br />
2. Im Coding der BSP-Applikation durch Methoden von ICF-Klassen<br />
Kein Eintrag ⇒ Caching<br />
kommt für Seite nicht zum<br />
Einsatz ......<br />
... aber natürlich doch für Inhalte des<br />
MIME-Repositories der Anwendung !<br />
Seite nur aus Server-Cache<br />
liefern wenn Request vom<br />
gleichen Browsertyp kommt<br />
Mit Objekt response der Klasse CL_HTTP_RSPONSE Verfallszeit des ICM Server-Caches steuern :<br />
- Relative Verfallszeit festlegen: response→server_cache_expire_rel( )<br />
- Absolute Verfallszeit festlegen: response→server_cache_expire_abs( )<br />
Durch statische Methoden von CL_HTTP_SERVER Invalidieren + Auffrischen des ICM Server-Cache:<br />
- Cache-Einträge für Seite : CL_HTTP_SERVER ⇒ server_cache_invalidate( )<br />
- Alle Objekte im Server Cache : CL_HTTP_SERVER ⇒ server_cache_invalidate_all( )<br />
Quelle: SAP-Bibliothek (Online-Docu) Benchmark Tests für Cache-Treffer im Hauptspeicher haben<br />
Antwortzeiten von unter einer Millisekunde pro Request und einen Gesamtdurchlauf von über 3000<br />
Requests pro Sekunde auf einer 4-CPU Hardware ergeben. MIME-Objekte werden nach dem ersten<br />
Laden automatisch im Server-Cache eingetragen. Bei Änderungen wird der Puffer invalidiert, was<br />
auch programmgesteuert erfolgen kann.<br />
Man kann sowohl für den Browser Cache als auch für den ICM Server-Cache bestimmen, wie lange<br />
die Seite im Cache gehalten werden soll. Wenn nichts angegeben wird, wird der entsprechende<br />
Cache für die Seite nicht verwendet. Das Kennzeichen Browser abhängig bedeutet, dass der Server<br />
die Seite nur aus dem Cache holt, wenn der Request vom gleichen Browser-Typ kommt. Wenn das<br />
Kennzeichen nicht gesetzt ist müssen alle von der Seite verwendeten Elemente browserunabhängig<br />
sein. Browser-Cache: Der Client kann nicht merken, wenn sich eine Seite geändert hat; er liefert bei<br />
der gleichern URL immer dieselbe Seite aus dem Cache, bis die Verfallsdauer abgelaufen ist - somit<br />
ist der Browser-Cache weniger gut kontrollierbar wie der Server-Cache.<br />
Steuerung des ICM-Server_Caches: Halten von BSPs im Server-Cache<br />
Man kann die relative Verfallszeit oder eine absolute Verfallszeit angeben sowie auch spezielle<br />
Cache-Einträge (nicht nur ganze BSP-Seiten) invalidieren - auch in Abhängigkeit von<br />
Benutzereingaben.<br />
Durch die Invalidierungs-Methoden kann man stets die Aktualität der gecachten Seite gewährleisten.<br />
Die Angaben werden vom System automatisch an andere Applikationsserver weitergeleitet, damit<br />
die Cache-Integrität gewährleistet ist. Man vermeide allzu häufige Invalidierungen, um systemweite<br />
Übertragungen an andere App-Server zu minimieren.<br />
Beispiel: response->server_cache_expire_abs( expires_abs_time = '180000 ) .<br />
Jeden Abend um 18 Uhr wird der Cache-Eintrag invalidiert. Dies kann für Dinge, die einmal täglich<br />
neu berechnet werden (z.B. aktuelle Preise), sinnvoll sein.<br />
(26)
NWAS als HTTP-Client<br />
REPORT ZCLIENTDEMO.<br />
DATA: myurl TYPE STRING,<br />
myclient TYPE REF TO IF_HTTP_CLIENT,<br />
rc TYPE I,<br />
content TYPE STRING.<br />
Auf Fehlerhandling<br />
myurl = 'http://www.sap.de'.<br />
wurde verzichet ......<br />
* Erstellen HTTP-Client :<br />
cl_http_client=>create_by_URL(<br />
exporting url = myurl<br />
importing client = myclient ).<br />
* Senden Request und Empfangen der Response :<br />
myclient→send( ).<br />
myclient→receive( ).<br />
myclient→response->get_status( importing code = rc ).<br />
* Abholen Response-Daten im Character-Format: get_cdata()<br />
* Abholen Response-Daten im Binär-Format: get_data()<br />
content = myclient→response→get_cdata( ).<br />
* Schliessen Request und Freigeben der Ressourcen :<br />
myclient→close( ).<br />
NWAS kann als Web-Client<br />
Requests an andere WebServer<br />
(auch: NWAS) absetzen und<br />
Response entgegennehmen.<br />
Zentral ist die Klasse :<br />
CL_HTTP_CLIENT<br />
Der NWAS kann auch als Client fungieren: Es kann ein Request an einen HTTP-Server gesendet<br />
und die Response empfangen werden. Der Request wird mit Methoden des Interfaces<br />
IF_HTTP_CLIENT aufgebaut, gesendet und die Response empfangen. Als HTTP-Server kann ein<br />
weiterer SAP NWAS oder auch ein beliebiger anderer Server fungieren.<br />
Um einen HTTP-Client aufzubauen muss eine gültige URL angegeben werden. Durch Methoden der<br />
Klasse CL_HTTP_CLIENT kann der Request abgesetzt und und die Response entgegengenommen<br />
werden. Es ist wichtig, mit der Methode close() die HTTP-Verbindung zu schliesen, damit die<br />
gehaltenen Systemressourcen wieder freigegeben werden.<br />
Der Returncode rc enthält den HTTP-Statuscode des Requests und müsste ausgewertet werden.<br />
"Typische" Werte sind zB :<br />
rc = 200 (OK) rc = 302 (Redirect) rc = 401 (Authentication Required)<br />
rc = 500 (Server Error)<br />
Da der NWAS auch als Web-Client fungieren kann, läßt sich durch BSP-Anwendungen auch eine<br />
Verknüpfung zwischen verschiedenen Websites herstellen. Auf dieser Basis lassen sich mit dem<br />
NWAS auch Internetportale zur kollaborativen, unternehmensübergreifenden Geschäftsprozessierung<br />
realisieren – Stichwort SOA !!<br />
(28)
Profilpflege NWAS<br />
Relevante Einstellungen des<br />
NWAS in Profildateien.pfl im<br />
NWAS-Filessystem<br />
Zur Profilpflege RZ10 :<br />
Werkzeuge → CCMS →<br />
Konfiguration → Systemprofile<br />
Infos durch Anzeige von :<br />
→ Verwaltungsdaten<br />
→ Grundpflege<br />
→ Erweiterte Pflege<br />
Hier auch festgelegt, ob ICM beim<br />
Starten der Instanz aktiviert wird +<br />
ob HTTP- und SMTP-PlugIn<br />
eingebunden und Port zugeordnet<br />
ist<br />
(30)<br />
Auf Fehlerhandling<br />
wurde verzichet ......<br />
Der NWAS wird mit einem Standard-Systemprofil ausgeliefert, dessen einzelne Parameter die<br />
Performanz des NWAS stark beeinflussen. Dort ist u.a. gepflegt, welche PlugIns des ICMs aktiviert<br />
und welche Ports ihnen zugeordnet sind. Zu erkennen in der Erweiterten Pflege ist zB der HTTP-<br />
Server-Port mit dem Wert 8065.<br />
Alle Profildateien befinden sich im Filesystem des NWAS und werden beim Starten des Systems<br />
(bzw der Instanz) ausgelesen.
Übersicht BSP-Seiten-Direktiven<br />
BSP-Direktive Beispiel Bedeutung<br />
Festlegen Server-Skriptsprache<br />
Einbinden von Seitenfragmenten<br />
Skript-Tag<br />
BSP-Kommentar<br />
Ausgabe-Tag<br />
OTR-Kurztext<br />
Text OTR-Langtext<br />
<br />
Wir listen die verschiedenen BSP-Seiten-Direktiven auf, die bei der Entwicklung von BSP-Seiten<br />
eingesetzt werden können.<br />
Bis auf das Einbinden von BSP-Extensions haben wir alle Direktiven kennengelernt<br />
(31)
Bewertung + Einordnung BSP-Technologie<br />
Nutzung bestehender<br />
SAP-Anwendungen<br />
ohne Anpassung<br />
Neue Anwendungen<br />
mittleren Umfangs<br />
Komplette<br />
Beeinflussung +<br />
Ausprogrammierung<br />
von Look & Feel<br />
Zustandslose Appl.<br />
Neue Anwendungen<br />
großen Umfangs<br />
Übernahme von SAP-<br />
Oberflächenelementen<br />
Konventioneller Browser Interner ITS<br />
Konventioneller Browser<br />
Mobile Devices mit<br />
individueller CSS-<br />
Anpassung<br />
Ausnutzen HTML5 + JS + CSS<br />
Alle Plattformen<br />
Browser<br />
BSP<br />
Konventionelle<br />
Einbettung in ABAP-<br />
Workbench und<br />
vertraute ABAP-Welt<br />
Relativ offenes<br />
Framework<br />
(32)<br />
Web Dynpro<br />
Durchgängig MVC<br />
Eigene Begrifflichkeit<br />
Vorgegebene<br />
Oberflächenelemente<br />
Geschlossenes<br />
Framework<br />
BSP ist sicherlich nicht die aktuelleste und mächtigste SAP-Web-Technologie. BSP bietet sich jedoch<br />
an, wenn kleinere und mittlere Web-Projekte mit geringem Aufwand schnell zu erstellen sind. Vorteile<br />
sind :<br />
1. Einfache Umsetzung des konventionellen ServerPage-Paradigmas<br />
2. Aufbau der Oberflächen liegt komplett in der Hand des Entwicklers<br />
3. Firmenspezifisches Look &Feel und Corporate Identity-Vorgaben lassen sich umsetzen<br />
4. Wie stark die Komplexität des zugrundeliegenden ICF-Frameworks genutzt wird, liegt in der<br />
Hand des Entwicklers
Anhang : Fortgeschrittene Techniken<br />
1. Mails aus BSP<br />
2. Programmieren eigener ICF-Services + HTTP-Handler<br />
3. Programmierung eigener BSP-Extensions (Tag Libraries)<br />
4. MVC mit BSP<br />
Im Folgenden werden fortgeschrittene Möglichkeiten im BSP-Umfeld besprochen. Zur weiteren<br />
Vertiefung verweisen wir jedoch auch auf die zur Vorlesung angegebene Literatur !<br />
(33)
Mails aus BSPs mittels BCS<br />
Verwendung Business Communication<br />
Service<br />
Voraussetzungen :<br />
1. SMTP-Plugin im ICM-Profil konfiguriert, zB :<br />
icm/server_port_1 = PROT=SMTP, PORT=25<br />
2. In TA SCOT Mailing via SMTP eingeschaltet::<br />
Grün hinterlegter Eintrag SMTP<br />
3. Zuweisung Mail-Domäne an SAP-System<br />
Beispielcoding im Report ZMAILDEMO<br />
in Paket ZBSPTEST .......<br />
(34)<br />
Erzeugte Mail und deren Zustand in<br />
SAPconnect-Administration TA SCOT<br />
überprüfbar durch Auswahl der<br />
Sendeübersicht :<br />
Hilfsmittel → Übersicht Sendeaufträge<br />
Mit Klick auf Brille email prüfen<br />
In Empfängerliste stehen Adressaten.<br />
Der NWAS verfügt über ein SMTP-Plugin, das emails direkt aus BSP-Anwendungen versenden kann,<br />
sofern der WAS an einen Mailserver gekoppelt ist. Um Mails zu senden müssen einige Objekte<br />
verschiedener Klassen durch statische Methodenaufrufe erzeugt werden:<br />
1.Mail-Auftrag erzeugen mittels Klasse CL_BCS und statischer Methode create_persistent().<br />
2.Mail-Dokument erzeugen mittels Klasse CL_DOCUMENT_BCS und statischer Methode<br />
create_document(). Mail-Text wird in interner Tabelle vom Typ character(255) verwaltet. Zu<br />
sendender Text muss in dieser Tabelle stehen.<br />
3.Erzeugtes Dokument dem Mail-Auftrag zuordnen durch Instanz-Methode set_document() der<br />
Klasse CL_BCS.<br />
4. Festlegen des Senders durch Klasse CL_SAPUSER_BCS und statischer Methode create().<br />
5.Erzeugten Sender dem Mail-Auftrag zuordnen durch Instanz-Methode set_sender() der Klasse<br />
CL_BCS.<br />
6. Festlegen des Empfängers mittels Klasse CL_CAM_ADRESS_BCS und statischer Methode<br />
create_internet_adress(), sowie Interface IF_RECIPIENT_BCS.<br />
7. Empfänger an Mailaufrag übergeben durch Instanz-Methode add_recipient() der Klasse<br />
CL_BCS.<br />
8. Mail-Auftrag freigeben durch Instanz-Methode send() der Klasse CL_BCS. Das Senden der Mail<br />
erfolgt asynchron.<br />
9. COMMIT WORK.<br />
In der SAPconnect-Administration (TA SCOT) kann der Erfolg des Mailversands überprüft werden.
Eigene HTTP- Handler<br />
Vordefinierter BSP- Handler = Klasse CL_HTTP_EXT_BSP<br />
Eigener HTTP- Handler = Jede ABAP-Klasse die if_http_extension implementiert<br />
Einziger Methode : handle_request() Zur Requestbearbeitung<br />
Eingabeparameter : Objekt server Zugriff HTTP-request/ -response<br />
Methodenaufruf : response→set_cdata() HTTP-Antwort<br />
METHOD if_http_extension~handle_request.<br />
data: text type string, info type string.<br />
info = server→request→get_header_field( '~path' ).<br />
text = ' Service erreicht! '<br />
server→response→set_status( code = 200 reason = 'OK' ).<br />
server→response→set_cdata( text ).<br />
if_http_extension~flow_rc = if_http_extension~co_flow_ok.<br />
ENDMETHOD.<br />
Attribut if_http_extension~flow_rc steuert Aufruf weiterer Behandler<br />
Request vollständig behandelt, keine weiteren Handler :<br />
if_http_extension~flow_rc = if_http_extension~co_flow_ok.<br />
Nach Ausführung Behandler weitere Behandler :<br />
if_http_extension~flow_rc = if_http_extension~co_flow_ok_others_opt.<br />
(35)<br />
Vorteil<br />
Totale Kontrolle<br />
der Request-<br />
Bearbeitung ohne<br />
BSP-LZ-Zugriffe<br />
⇓<br />
Leichtgewichtige<br />
schlanke Services<br />
Servlet-artige<br />
Programmierung<br />
BSPs sind aus Sicht des ICM ledglich eine besondere Art von HTTP-Services, die alle durch den<br />
speziellen, von SAP ausgelieferten Requestbehandler CL_HTTP_EXT_BSP bedient werden. Dieser<br />
ist dem SICF-Knoten /sap/bc/bsp zugeordnet. Wird eine BSP-Anwendung über die Workbench<br />
angelegt, so wird automatisch ein Unterknoten dazu angelegt. Dadurch ist auch automatisch<br />
sichergestellt, dass die Anwendung vom SAP-BSP-Framework, also dem Behandler<br />
CL_HTTP_EXT_BSP aufgerufen wird.<br />
Ein eigener HTTP-Handler ist einfach eine normale ABAP-Klasse die das Interface<br />
if_http_extension mit seiner einzigen Methode handle_request() implementiert. Deren<br />
Eingabeparameter ist ein server-Objekt, das HTTP-request und -response-Objekte enthält. Durch<br />
handle_request() wird ein Request bearbeitet und darin durch Aufruf der Methode<br />
response→set_cdata() eine HTTP-Antwort erzeugt. Wenn der ICM einen zugehörigen Knoten in der<br />
Service-Verwaltung gefunden hat, dann wird ein Objekt der Behandler-Klasse instantiiert und deren<br />
Methode handle_request() aufgerufen.<br />
Durch wenige Codezeilen kann ein neuer HTTP-Behandler in das ICF eingefügt werden. Vorteil<br />
selbstgeschriebener Handler ist, dass man totale Kontrolle über die HTTP-request-Auswertung und<br />
HTTP-response-Erstellung hat. Wenn die Leistungen der BSP-LZ gar nicht benötigt werden, so lassen<br />
sich auf diese Weise sehr schlanke und performante Lösungen realisieren.
Eigener HTTP- Handler in SICF<br />
ZCL_HTTP_HANDLER<br />
Beispiel für resultierende URL :<br />
Service HandlerTest angelegt in SICF direkt unter default_host :<br />
http://m65z.hcc.uni-magdeburg.de:8065/handlertest<br />
(36)<br />
In SICF muss neuer Service<br />
angelegt werden<br />
Pfad im SICF-Baum bestimmt<br />
URL des Service<br />
Eigene HTTP-Behandlerklasse<br />
ist in Handlerliste einzutragen<br />
Sollen weitere Handler im<br />
Anschluss aufgerufen werden,<br />
sind auch sie in gewünschter<br />
Reihenfolge in Handlerliste<br />
aufzunehmen<br />
Das Interface if_http_extension hat ein Attribut namens flow_rc. Dessen Wert steuert, ob nach<br />
Ausführung des Requests noch weitere Behandler aufgerufen werden sollen oder die Behandlung<br />
beendet ist. Es stehen in dem Interface dazu vordefinierte Konstanten zur Verfügung:<br />
Request ist vollständig behandelt, die response wurde komplett erstellt, es sind keine weiteren<br />
Handler (also auch nicht das BSP-Framework) aufzurufen: if_http_extension~flow_rc =<br />
if_http_extension~co_flow_ok<br />
Nach Ausführung des Behandlers sind weitere Behandler aufzurufen. Diese sind in ihrer Aufruf-<br />
Reihenfolge in der Handler-Liste des Services innerhalb der Service-Verwaltung aufgeführt:<br />
if_http_extension~flow_rc = if_http_extension~co_flow_ok_others_opt<br />
Eigene Handler sind als eigener Service in den SICF-Baum aufzunehmen und in die Handlerliste<br />
aufzunehmen. Da eigene Handler nicht zum BSP-Framework gehören, sollten sie im SICF-Baum nicht<br />
unterhalb von /sap/bc/bsp eingetragen werden, sondern unter einem separaten Pfad.<br />
Der Aufruf selbstgeschriebener Handler erfolgt mit einer URL, die neben dem Namen des Servers<br />
auch den SICF-Pfad enthält.<br />
Trägt man in der Handler-Liste auch die Klasse CL_HTTP_EXT_BSP ein, so würde im Anschluss<br />
auch das BSP-Framework aufgerufen werden.
Eigene Tag-Library = BSP-Extension<br />
* Redefinition Methode in generierter Behandler-Klasse :<br />
METHOD IF_BSP_ELEMENT~DO_AT_END.<br />
data: grussformel type string value ' Hallo, & ! ',<br />
out type ref to if_bsp_writer.<br />
out = get_previous_out( ).<br />
replace '&' in grussformel with name.<br />
out→print_string( grussformel ).<br />
ENDMETHOD.<br />
<br />
<br />
<br />
Test eigene Extension <br />
<br />
<br />
<br />
<br />
<br />
<br />
Tag-Libraries :<br />
Einheitliche Darstellung von Oberflächenelementen<br />
+ Präsentationslogik<br />
Zusammenfassung + Auslagerung<br />
aufwendiger statischer + dynamischer<br />
Elemente in Tag-Bibliothek<br />
⇒ Wiederverwendung + Lesbarkeit !<br />
⇒ Einheitliches Layout !<br />
⇒ Einbinden als selbstdefinierte<br />
parametrisierte Tags<br />
Beispiele:<br />
Tabellen + Suchen/Sortieren, Trees, Kalender, ….<br />
Workbench :<br />
(37)<br />
1. Anlegen → BSP-Extension<br />
2. Anlegen → BSP-Element<br />
3. Attribute für BSP-Element anlegen<br />
⇒ Behandlerklassen automatisch generiert<br />
4. Methode(n) der generierten Klasse durch<br />
eigenes Behandlercoding redefinieren<br />
⇒ Funktionalität + Attributbelegung<br />
5. Neue Tag-Library in BSP-Seiten<br />
anmelden + Tags aufrufen<br />
Tag Libraries sind ein wichtiges Hilfsmittel bei der Gestaltung der Benutzerschnittstelle. Sie bieten die<br />
Möglichkeit, wiederkehrende grafische Elemente einheitlich darzustellen. Auch immer gleiche Logik<br />
zur Präsentation von Daten kann in Tags ausgelagert werden. Der Name Extension bedeutet: Man<br />
kann den Grundwortschatz der Präsentierungssprache HTML um eigene Tags erweitern. BSP-<br />
Extensions kommen somit als Erweiterung der HTML-Tags daher und fügen sich besser in das<br />
Design einer HTML-Seite ein als zahlreiche Scripting-Anweisungen.<br />
Der Hauptgrund für den Einsatz von Tag Libraries ist die Wiederverwendbarkeit. Immer gleicher<br />
HTML-Code wird nicht in die Webseiten eingestreut, da man diesen auch als parametrisiertes Tag<br />
aufrufen kann. Das Layout bleibt lesbar, einheitlich und übersichtlich. Man erreicht mit Tag Libraries,<br />
gleichbleibenden Code nur einmal implementieren zu müssen.<br />
Das BSP-Element ähnelt technisch einem Funktionsbausteinaufruf. Die Schnittstelle sind die<br />
Element-Attribute. So lassen sich variable Teile des zu generierenden Codes durch entsprechende<br />
Attributwerte steuern. Auf Serverebene stellt sich eine Seite als eine Mischung von HTML- und BSP-<br />
Elementen dar. Der Server transformiert die BSPElemente in die Zielsprache HTML, die an den Client<br />
gesendet wird. Die Regeln der Transformation sind in der Implementierung der BSP-Elemente<br />
verborgen. Der für die Präsentationslogik notwendige Code wird verborgen. In der Seite wird nur das<br />
gewünschte Layoutelement, geeignet parametrisiert, angesprochen. Die Erzeugung des Codes wird<br />
an die Elementbehandlerklasse delegiert und gehört somit nicht mehr zur Präsentationsinformation<br />
der jeweiligen Seite.<br />
Dadurch, dass die Elementbehandlerklasse von einer automatisch generierten Basisklasse erbt,<br />
enthält sie automatisch Implementierungen des Interfaces IF_BSP_ELEMENT. Diese sind jedoch alle<br />
leer. Damit ein BSP-Element etwas Sinnvolles tut, muss man mindestens eine Methode dieses<br />
Interface redefinieren und mit eigenem Code versehen - wie es oben mit der Methode do_at_end( )<br />
geschieht.
Model View Controller Paradigma MVC-Design Pattern<br />
Konsequente Entkopplung von<br />
Ablaufsteuerung, Präsentation<br />
(Layout) und Geschäftslogik in<br />
separaten Objekten<br />
Request<br />
Response<br />
Methodenaufrufe<br />
Datenfluss<br />
Ereignisse<br />
Kontrollfluss<br />
Daten-<br />
Weitergabe<br />
View-Auswahl<br />
View-Aufruf<br />
Controller<br />
View<br />
Zustandsabfragen<br />
<br />
<br />
Steuerung<br />
Steuerung<br />
Kontrollfluss<br />
Kontrollfluss<br />
der<br />
der<br />
Anwendung<br />
Anwendung<br />
<br />
<br />
Events<br />
Events<br />
behandeln<br />
behandeln<br />
<br />
<br />
Daten<br />
Daten<br />
an<br />
an<br />
View<br />
View<br />
geben<br />
geben<br />
/<br />
/<br />
von<br />
von<br />
View<br />
View<br />
holen<br />
holen<br />
<br />
<br />
Übersetzen<br />
Übersetzen<br />
Benutzereingaben<br />
Benutzereingaben<br />
für<br />
für<br />
Model<br />
Model<br />
<br />
<br />
Auswahl<br />
Auswahl<br />
passende<br />
passende<br />
View<br />
View<br />
für<br />
für<br />
Response<br />
Response<br />
Aufruf<br />
Model<br />
Zustandsänderungen<br />
Quelle: OIO, Kursmaterial<br />
<br />
<br />
Visualisieren<br />
Visualisieren<br />
der<br />
der<br />
Anwendungsdaten<br />
Anwendungsdaten<br />
<br />
<br />
Darstellung<br />
Darstellung<br />
+<br />
+<br />
Benutzerinteraktion<br />
Benutzerinteraktion<br />
<br />
<br />
Senden<br />
Senden<br />
von<br />
von<br />
Benutzereingaben<br />
Benutzereingaben<br />
an<br />
an<br />
Controller<br />
Controller<br />
(38)<br />
<br />
<br />
Container<br />
Container<br />
für<br />
für<br />
Geschäftsdaten<br />
Geschäftsdaten<br />
und<br />
und<br />
Geschäftslogik<br />
Geschäftslogik<br />
<br />
<br />
Kapselung<br />
Kapselung<br />
Anwendungszustand<br />
Anwendungszustand<br />
<br />
<br />
Eigentliche<br />
Eigentliche<br />
Datenverarbeitung<br />
Datenverarbeitung<br />
durch<br />
durch<br />
Geschäftslogik<br />
Geschäftslogik<br />
<br />
<br />
Information<br />
Information<br />
View<br />
View<br />
bei<br />
bei<br />
Änderung<br />
Änderung<br />
Server<br />
Architektur entsteht immer durch Zerlegung eines Ganzen in einzelne Komponenten und Definition<br />
von deren strukturierten Zusammenwirken. Dabei orientiert man sich an typischen Mustern,<br />
sogenannten Design Patterns.<br />
MVC führt zu einer besseren organisatorischen und logischen Strukturierung der Anwendung. Es wird<br />
das Prinzip "Separation of Concerns" umgesetzt, wodurch auch die Wartbarkeit deutlich zunimmt.<br />
Ohne andere Komponenten zu beeinflussen, können zB die Views oder Teile des Models<br />
ausgetauscht werden.
MVC mit BSP<br />
Einbettung in Workbench +<br />
Forward-Navigation<br />
Controller<br />
View<br />
Model<br />
BSP-Anwendung zugeordnet Anlegen→ Controller<br />
BSP-Anwendung zugeordnet Anlegen→ Controller<br />
<br />
<br />
Ablaufsteuerung<br />
Ablaufsteuerung<br />
(Flow<br />
(Flow<br />
Logic)<br />
Logic)<br />
der<br />
der<br />
Anwendung<br />
Anwendung<br />
durch<br />
durch<br />
entsprechende<br />
entsprechende<br />
Methoden<br />
Methoden<br />
–<br />
–<br />
analog<br />
analog<br />
BSP-Eventhandlern<br />
BSP-Eventhandlern<br />
<br />
<br />
Klassen<br />
Klassen<br />
erben<br />
erben<br />
von<br />
von<br />
ICF-Basisklasse<br />
ICF-Basisklasse<br />
CL_BSP_CONTROLLER2<br />
CL_BSP_CONTROLLER2<br />
<br />
<br />
Können<br />
Können<br />
Views<br />
Views<br />
aufrufen<br />
aufrufen<br />
sowie<br />
sowie<br />
Model-Objekt<br />
Model-Objekt<br />
erzeugen<br />
erzeugen<br />
+<br />
+<br />
ansprechen<br />
ansprechen<br />
<br />
<br />
Aufrufbar<br />
Aufrufbar<br />
mit<br />
mit<br />
eigener<br />
eigener<br />
URL<br />
URL<br />
Endung<br />
Endung<br />
.do<br />
.do<br />
<br />
<br />
Coding<br />
Coding<br />
hinterlegen<br />
hinterlegen<br />
durch<br />
durch<br />
Überschreiben<br />
Überschreiben<br />
geerbter<br />
geerbter<br />
Methoden<br />
Methoden<br />
<br />
<br />
Normale<br />
Normale<br />
ABAP-OO-Klassen<br />
ABAP-OO-Klassen<br />
<br />
<br />
Erben<br />
Erben<br />
von<br />
von<br />
CL_BSP_MODEL<br />
CL_BSP_MODEL<br />
<br />
<br />
Zahlreiche<br />
Zahlreiche<br />
geerbte<br />
geerbte<br />
Methoden<br />
Methoden<br />
<br />
<br />
Frei<br />
Frei<br />
definierbare<br />
definierbare<br />
eigene<br />
eigene<br />
Methoden<br />
Methoden<br />
+<br />
+<br />
Attribute<br />
Attribute<br />
zur<br />
zur<br />
Darstellung<br />
Darstellung<br />
der<br />
der<br />
Logik<br />
Logik<br />
<br />
<br />
Direkt<br />
Direkt<br />
via<br />
via<br />
ClassBuilder<br />
ClassBuilder<br />
angelegt<br />
angelegt<br />
<br />
<br />
Aufrufe<br />
Aufrufe<br />
erfolgen<br />
erfolgen<br />
aus<br />
aus<br />
Methoden<br />
Methoden<br />
der<br />
der<br />
Controller-Klasse<br />
Controller-Klasse<br />
<br />
<br />
BSP-Anwendung<br />
BSP-Anwendung<br />
zugeordnet Anlegen → Seite → View<br />
zugeordnet Anlegen → Seite → View<br />
<br />
<br />
Haben<br />
Haben<br />
keine<br />
keine<br />
eigene<br />
eigene<br />
URL<br />
URL<br />
–<br />
–<br />
nicht<br />
nicht<br />
direkt<br />
direkt<br />
aufrufbar<br />
aufrufbar<br />
<br />
<br />
Vom<br />
Vom<br />
Controller<br />
Controller<br />
aufgerufen<br />
aufgerufen<br />
+<br />
+<br />
mit<br />
mit<br />
Daten<br />
Daten<br />
versorgt<br />
versorgt<br />
<br />
<br />
Haben<br />
Haben<br />
Eigenschaften,<br />
Eigenschaften,<br />
Layout,<br />
Layout,<br />
Seitenattribute<br />
Seitenattribute<br />
<br />
<br />
Keine<br />
Keine<br />
Eventhandler,<br />
Eventhandler,<br />
keine<br />
keine<br />
Auto-Seitenattribute<br />
Auto-Seitenattribute<br />
Der Controller beinhaltet die Steuerungslogik der Anwendung. Er reagiert auf User-Input und<br />
Ereignisse und verteilt Aufgaben an die View und das Model. Innerhalb BSP besteht der Controller<br />
aus zwei separaten Teilen: 1. Das Controller-Eigenschaften-Objekt mit den Attributen des<br />
Controllers (Verwaltungsinformationen, URL, Zustandsverhalten) 2.Eine zugeordnete ABAP-OO-<br />
Klasse, die von der BSP-Systemklasse CL_BSP_CONTROLLER2 erbt. Diese Klasse enthält die<br />
eigentliche Controller-Logik; in ihr wird der ABAP-Code hinterlegt, der die Aufgaben des Controllers<br />
umsetzt.<br />
Im Gegensatz zu BSP-Seiten können Views nicht direkt von Außen aufgerufen werden.<br />
In einer BSP-Anwendung können sowohl Seiten mit Ablauf-Logik als auch Controller und Views sowie<br />
Model-Klassen vorhanden sein. Je komplexer eine BSP-Anwendung ist, desto eher lohnt sich der<br />
zusätzliche Aufwand des MVC-Patterns.<br />
Zur Umsetzung von MVC in einer BSP-Anwendung sind ABAP-OO-Kenntnisse erforderlich,<br />
insbesondere auch Vererbung, Überschreiben von Methoden und das Prinzip der Polymorphie. Da<br />
separate ABAP-OO-Klassen angelegt werden, bekommt man in der Workbench alle Elemente der<br />
entsprechenden BSP-Anwendung (inklusive der Klassen) nur in der Paket-Sicht zu Gesicht.<br />
Auf die sehr mächtigen Möglichkeiten des DataBindings zwischen Views und Models können wir hier<br />
nicht eingehen. Wir verweisen dafür auf die Literatur, insbesondere auf :<br />
B. McKellar T.Jung : Advanced BSP Programming, Kapitel 13<br />
(39)
MVC mit BSP<br />
Controller-Eigenschaften<br />
View-Seiten haben keine eigene URL, keine<br />
Eventhandler, keine Auto-Seitenattribute ….<br />
Controller-Bestandteile = (40)<br />
1. Controller-Eigenschaften +<br />
2. Controller-Klasse / -Objekt<br />
Bei Anlegen von Controllern in<br />
Workbench wird Name der<br />
Controller-Klasse genannt<br />
Durch Vorwärtsnavigation kann<br />
man im ClassBuilder Methoden<br />
überschreiben<br />
CL_BSP_CONTROLLER2 dabei<br />
automatisch als Superklasse<br />
gesetzt<br />
View-Eigenschaften<br />
Im Gegensatz zu BSP-Seiten können Views nicht direkt von Außen aufgerufen werden. Sie verfügen<br />
auch nicht über Eventhandler – denn die Geschäftslogik liegt im Model und die Kontrollflusssteuerung<br />
im Controller.
Verarbeitungs-Ablauf im Controller<br />
Controller repräsentiert Ablaufsteuerung einer BSP-Seite (Flow Logic)<br />
Durch Methoden und deren definierten Aufruf realisiert - BSP-Runtime besorgt Aufrufe<br />
Analog : Eventhandler einer konventionellen BSP-Seite mit Ablauflogik<br />
Konventionelle BSP-Seite<br />
OnCreate<br />
OnInitialization<br />
OnRequest<br />
Layout<br />
OnInputProcessing<br />
OnManipulation<br />
Hier nur Grundlagen. Mächtige Möglichkeiten für Data-<br />
Bindung und automatischer Datenübertragung :<br />
B. McKellar T.Jung : Advanced BSP Programming<br />
Kapitel 13<br />
Controller-Methoden und ihre Bedeutung :<br />
MVC-Controller-Klasse<br />
DO_INIT<br />
DO_INITATTRIBUTES<br />
DO_REQUEST<br />
DO_HANDLE_DATA<br />
DO_HANDLE_EVENT<br />
DO_FINISH_OUTPUT<br />
CALL_VIEW , Dispatch_Input<br />
Festlegen der Ablauflogik durch Überschreiben<br />
(Redfinieren) dieser von CL_BSP_CONTROLLER2<br />
geerbten Methoden in der eigenen Controller-Klasse<br />
ClassBuilder : Redine-Button im Methoden-Tab für selektierte Methode<br />
DO_INIT : Diese Methode wird bei der Erzeugung der Controller-Instanz aufgerufen. Hier kann z. B. ein Objekt<br />
einer Model-Klasse erzeugt werden. Wird bei stateful-Anwendungen nur einmal gerufen.<br />
DO_INITATTRIBUTES : Ist mit dem BSP-Eventhandler Onlnititialization vergleichbar.<br />
DO_REQUEST : Zentrale Methode für Eingabe-/Ausgabe-Steuerung. Steuert die folgenden spezialisierten<br />
Methoden für Input-Verarbeitung:<br />
DO_HANDLE_DATA sorgt dafür, dass die Model-Klasse mit Daten gefüllt wird. Daten der Formfelder und<br />
Nachrichten werden übergeben. DO_HANDLE_EVENT gibt den Parameter GLOBAL_EVENT aus und füllt im<br />
Fall von Events, die von BSP-Elementen ausgelöst werden, das HTMLB-Event-Objekt. DO_FINISH_INPUT<br />
reagiert mithilfe des GLOBAL _EVENT-Parameters auf Ereignisse. Es ist die letzte Methode der<br />
Eingabeverarbeitung.<br />
Eintreffende Client-Requests werden direkt an den Hauptcontroller geleitet mittels des URL-Aufrufs. Nach<br />
DO_INIT und DO_INITATTRIBUT wird die zentrale Methode DO_ REQUEST aufgerufen. Von dieser Methode<br />
können eingehende Daten an eventuelle Subcontroller weitergeleitet werden. Dies übernimmt die Methode<br />
DISPATCH_INPUT. Sie liest die Daten aus den Formfeldern des Request-Objekts aus und leitet sie an die<br />
jeweils adressierten Subcontroller weiter. Ferner sogt diese Methode dafür, dass die Methoden<br />
DO_HANDLE_DATA, DO_HANDLE_EVENT und DO_FINISH_INPUT aufgerufen werden<br />
Daten, die für den Hauptcontroller bestimmt sind, werden innerhalb von DO_REQUEST durch die Methoden<br />
DO_HANDLE_DATA, DO_HANDLE_EVENT und DO_FINISH_INPUT verarbeitet. Subcontroller verarbeiten<br />
ihnen zugeordnete Daten ebenfalls über ihre Implementation dieser Methoden.<br />
Zur Ausgabeverarbeitung werden ein oder mehrere Views erzeugt und aufgerufen. Dies wird mittels der Methode<br />
CALL_VIEW ausgeführt. Controller können auf den Status inaktiv gesetzt oder neue Controller erzeugt werden.<br />
(41)
MVC mit BSP – typische Strukturen<br />
Model<br />
Controller<br />
Aufrufe<br />
Ein Controller kann mehrere Views<br />
nacheinander ansteuern ……<br />
BSP-Anwendung<br />
Controller 1<br />
Model 1<br />
Aufruf<br />
View 1<br />
View 1<br />
View 1<br />
View 1<br />
Controller 2<br />
Model 2<br />
Aufruf<br />
View 2<br />
BSP-Seite<br />
Model<br />
Controller<br />
Ein übergeordneter Haupt-Controller<br />
steuert die Verteilung der Anwendungslogik<br />
durch Aufruf von Sub-Controllern ….<br />
Controller 3<br />
Model 3<br />
Aufruf<br />
View 3<br />
Aufrufe<br />
Model 1<br />
Model 2<br />
Model 3<br />
Jede einzelne "BSP-Seite" implementiert alle<br />
drei MVC-Komponenten. Views durch<br />
zugeordnete Controller gerufen …..<br />
(42)<br />
Controller 1<br />
Controller 2<br />
Aufruf<br />
View 2<br />
Aufruf<br />
View 1<br />
Controller 3<br />
Aufruf<br />
View 3<br />
In einer BSP-Anwendung können sowohl Seiten mit Ablauf-Logik als auch Controller, Models und<br />
Views vorhanden sein. Aus einem Controller können auch Controller anderer BSP-Anwendungen<br />
aufgerufen werden.<br />
Je komplexer eine BSP-Anwendung ist, desto eher lohnt sich der zusätzliche Aufwand des MVC-<br />
Patterns. Es gibt eine Vielzahl von Kombinationsmöglichkeiten. Insgesamt nimmt die Wartbarkeit der<br />
Anwendung zu, da eine saubere Trennung und Strukturierung nach MVC-Anteilen besteht.<br />
Einzelnen Komponenten können relativ leicht ausgetauscht werden.<br />
Da der Umgang mit dem MVC-Pattern relativ komplex ist und Einarbeitungszeit erfordert, hat SAP<br />
im WebDynpro-Programmiermodell die Anwendungsentwicklung durch grafische Entwicklungsanteile<br />
vereinfacht, durch die das MVC-Grundgerüst automatisch generiert wird.<br />
Durch den Controller können Views aufgerufen und an deren Seitenattribute Daten übergeben<br />
werden. Dazu könnte auch die Referenz auf ein Model-Objekt gehören! (Es ist aber auch möglich, den<br />
HTML-Datenstrom direkt in der Methode do_request() mit der Methode write() zu erzeugen.)<br />
Aus einem Controller kann ein SubController-Objekt erzeugt und diesem auch gleich ein Model-<br />
Objekt übergeben werden. Dazu dienen die geerbten Methoden create_controller( ) und<br />
set_model().<br />
SubController können auch dynamisch aktiviert und deaktiviert werden, so dass sie nicht<br />
überflüssigerweise abgearbeitet werden. Dazu dient ebenfalls eine geerbte Methode:<br />
controller_set_active( controller_id = 'sub1' active = 0 ).
Controller-Methoden überschreiben<br />
METHOD do_init. " Einbinden Model-Objekt, DB-Zugriffe, …..<br />
model ?= create_model( model_id = 'm1' class_name = 'Z_M_DEMO' ).<br />
model→carrid = 'LH'.<br />
model→read_flight_data( ). " Datenbeschaffung + Geschäftslogik ……<br />
ENDMETHOD.<br />
Zentrale Methoden der Controller-Klasse<br />
METHOD do_request. " Redefintion / Überschreiben<br />
data: view type ref to if_bsp_page. " View-Objekt<br />
data: input type string.<br />
input = request→get_form_field( name = 'input' ).<br />
dispatch_input( ). " Trigger Eingabe-Verarbeitung + Events<br />
if input = 'Einstieg'.<br />
view = create_view( view_name = 'main.htm' ). call_view( view ).<br />
else. " View mit Werten versehen<br />
view = create_view( view_name = 'next.htm' ).<br />
view→set_attribute( name = 'text' value = sy-uname ).<br />
call_view( view ).<br />
endif.<br />
ENDMETHOD.<br />
(43)<br />
Ziel :<br />
Erzeugen Modell- und View-Objekte.<br />
Model-Objekte als Controller-Attribute<br />
verwaltet<br />
Möglichkeiten :<br />
1. Request-Datenzugriff, View<br />
erzeugen, View-Seitenattribute<br />
übergegen, View rufen.<br />
2. Aus Controller verschiedene Views<br />
aufrufbar.<br />
3. Controller kann andere Controller<br />
aufrufen. Hierarchie von Controllern !<br />
4. Aus View sind Controller aufrufbar<br />
oder Redirects möglich ……..<br />
View next.htm<br />
<br />
<br />
<br />
Aufruf View <br />
<br />
<br />
Benutzer <br />
<br />
<br />
Eine Controllerklasse verfügt typischerweise über Attribute vom Typ der verwendeten Models und instanziiert<br />
entsprechende Objekte in seiner Methode do_init(). Jeder erzeugten Model-Instanz wird eine ID gegeben. Auf diese Weise<br />
sind sie auch in dem geerbten Attribut M_MODELS des Controller-Objekts unterscheidbar. Es existieren geerbte Methoden<br />
SET_MODEL, GET_MODEL, CREATE_MODEL, DELETE_MODEL im Controller, durch die gespeicherte Liste der Model-<br />
Objekte verwaltet werden kann. Der Controller kontrolliert somit auch die Erzeugung von Model-Objekten und deren<br />
Lebensdauer.<br />
MVC wird typischerweise in stateful BSP-Anwendungen verwendet. Grund ist, dass es aufwendig ist, in stateless-<br />
Anwendungen die erforderlichen Controller- und Model-Objekte immer wieder neu zu erzeugen und insbesondere deren<br />
korrekten internen Zustand konsistent zu rekonstruieren. Das Controller-Objekt enthält als Attribut eine Tabelle mit<br />
Referenzen auf erzeugte Model-Objekte. In stateless-Anwendungen müsste diese Tabelle erst immer wieder hergestellt und<br />
die darin enthaltenen Model-Objekte zustandsmäßig korrekt rekonstruiert werden. Allerdings existieren Techniken mit denen<br />
man Model-Instanzen zwischenspeichern und wiederherstellen kann. Dazu gehören die Serialisierung und Deserialisierung<br />
von Model-Objekten als XML-Strings und deren Zwischenspeicherung als Server-Cookie.<br />
Der Aufruf der Methode dispatch_input() sogt dafür, dass alle für die Eingabe-Verarbeitung erforderlichen Events ausgelöst<br />
werden und alle dafür vorgesehenen Controller-Methoden aufgerufen werden. Diese Methode muss nur einmal aus dem<br />
Haupt-Controller aufgerufen werden.<br />
Aus einem Controller können andere Controller gerufen werden, so dass neben Haupt-Controllern auch Sub-Controller<br />
definiert werden können:<br />
data: ctl type ref to zcl_bsp_subcontroller .<br />
ctl ?= create_controller( controller_name = 'sub1.do' controller_id = 'sub' ) .<br />
ctl→testdata = 'Irgendwas'.<br />
call_controller( controller_instance = ctl ). " Aufruf aus Hauptcontroller. Dieser behält Kontrolle<br />
* navigation->goto_page( 'sub1.do' ). " Navigation zu Subcontroller: Hauptcontroller wird abgebaut:<br />
Auch aus einer View lässt sich mittels BSP-Extensions eine anderer Controller aufrufen :<br />
<br />
Auch Redirects sind möglich: