Untergeordnete Seiten
  • 3 - Szenario: Bildabschnitte laden

Versionen im Vergleich

Schlüssel

  • Diese Zeile wurde hinzugefügt.
  • Diese Zeile wurde entfernt.
  • Formatierung wurde geändert.

Nächstes Tutorial ⯈

In 2 - Szenario: Dokument laden haben wir das reine Laden eines Dokuments simuliert. In diesem Tutorial schauen wir uns die tatsächliche Anzeige des Dokuments, bzw. - um korrekt zu sein - von Ausschnitten des Dokuments an.

Tiles und Tileservlet

Um das Szenario "Bildabschnitt laden" zu verstehen, beschäftigen wir uns kurz mit den JWT-Mechanismen zur Anzeige von Dokumenten. Will der JWT-Client ein Dokument anzeigen, fordert er vom JWT-Server entsprechend gerenderte Bilddaten an. Dabei liefert der Server nicht das komplett gerenderte Dokument, sondern teilt das Dokument in sogenannte Tiles bzw. Kacheln auf. Der Ausschnitt der Tiles hängt von verschiedenen Faktoren ab:

  • Ausgewählte Seite
  • Zoomlevel
  • Scrollposition
  • Rendereinstellungen (z.B. Gradation)

Die Tiles sind PNGs und werden vom Server über ein Servlet, dem Tileservlet, zur Verfügung gestellt. Der Pfad des Tileservlets zeigt standardmäßig auf /jwt/tile.

Scrollen

Wenn wir bzw. unsere Anwender nun innerhalb eines Dokuments scrollen, blättern oder zoomen, schickt der JWT-Client jeweils einen neuen Request an das TileServlet. Der JWT-Server rendert dann den passenden Ausschnitt und stellt diesen dem Client zur Verfügung.

Wir beschränken uns hier auf das Vorgehen beim Scrollen. Bei den anderen Szenarien würden wir aber analog vorgehen.

Für unser Szenario legen wir eine neue Scala-Klasse an und nennen diese SimulationTiles.scala.

Beim Scrollen werden nacheinander Tiles zum gerade angezeigten Ausschnitt angefordert. Wie schon in den letzten Tutorials nutzen wir die Entwicklerwerkzeuge unseres Browsers, um die Anfragen an das TileServlet zu identifizieren. Sobald wir durch das Dokument nach unten scrollen, sollten mehrere solche Request gelistet sein (/jwt/tile?v=...). Wir kopieren die komplette Request-URL und erstellen für jede Anfrage einen neuen Aufruf innerhalb des Szenarios.

Erweitern
titleZur Anzeige unserer Beispielvideos hier erweitern...

Image RemovedImage Added

 

Die Anfragen an das TileServlet sind wieder einfache GET-Requests:

Codeblock
titleSimulationTiles.scala
themeRDark
languagescala
    val scn = scenario("Tile retrieval Scenario")
    .exec(_.set("uuid", java.util.UUID.randomUUID))
    .exec(http("Load tile")
        .get("/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*23be8204-e817-44c3-9609-eb68b68c5756*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*0*10*11*0*842*595*0*0*12*1*")
        .headers(defaultHeader)
        .check(status.is(200))
     )

 

Unser komplettes Szenario mit mehreren Requests sollte nun ungefähr so aussehen:

Codeblock
titleSzenario - Tiles
themeRDark
languagescala
collapsetrue
import io.gatling.core.Predef._
import io.gatling.http.Predef._
class SimulationSimple extends Simulation {
  val httpProtocol = http
    .baseURL("http://localhost:8080/jwt-tutorial-003-5.7.0.2")
      
  val defaultHeader= Map(
    "Accept" -> "*/*",
    "Accept-Encoding" -> "gzip, deflate, br",
    "Accept-Language" -> "de-DE,de;q=0.9,en-US;q=0.8,en;q=0.7",
    "Cache-Control" -> "no-cache",
    "Connection" -> "keep-alive",
    "Content-Type" -> "text/plain;charset=UTF-8",
    "DNT" -> "1",
    "Origin" -> "http://localhost:8080",
    "Pragma" -> "no-cache",
    "User-Agent" -> "Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.139 Safari/537.36",
    "X-GWT-Module-Base" -> "http://localhost:8080/jwt-tutorial-003-5.7.0.2/imageviewer/",
    "X-GWT-Permutation" -> "79A1155DD3CB7EBBA33EE56F4B55FD77",
    "X-JWT-Client-ID" ->"${uuid}")
    
    val scn = scenario("Tile retrieval Scenario")
    .exec(_.set("uuid", java.util.UUID.randomUUID))
    .exec(http("Load tile")
        .get("/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*23be8204-e817-44c3-9609-eb68b68c5756*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*0*10*11*0*842*595*0*0*12*1*")
        .headers(defaultHeader)
        .check(status.is(200))
     )
     .exec(http("Load tile")
        .get("/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*8e7d1964-d4ee-41f6-a980-eb73e8fbc477*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*1*10*11*0*842*595*0*0*12*1*")
        .headers(defaultHeader)
        .check(status.is(200))
     )
     .exec(http("Load tile")
        .get("/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*e34eb16e-a812-46c2-8367-47e37a9edb97*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*2*10*11*0*842*595*0*0*12*1*")
        .headers(defaultHeader)
        .check(status.is(200))
     )
     .exec(http("Load tile")
        .get("/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*07d7f425-6f06-477c-aba1-6dc0d13f6123*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*3*10*11*0*842*595*0*0*12*1*")
        .headers(defaultHeader)
        .check(status.is(200))
     )
     .exec(http("Load tile")
        .get("/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*3cd7ffc0-be55-44f0-942d-cf3d9b18be31*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*4*10*11*0*842*595*0*0*12*1*")
        .headers(defaultHeader)
        .check(status.is(200))
     )
     .exec(http("Load tile")
        .get("/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*eb5ccca6-2da7-476f-8326-05b6531b8144*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*5*10*11*0*842*595*0*0*12*1*")
        .headers(defaultHeader)
        .check(status.is(200))
     )
    
    setUp(scn.inject(atOnceUsers(5)))
    .protocols(httpProtocol)
    .assertions(
      global.responseTime.max.lte(2000)
    )
}

Tile-Request

Abschließend schauen wir uns die aufgezeichneten Requests noch einmal genauer an:

Codeblock
titleTile-Request
themeRDark
/jwt/tile?v=1539858587974v7*0*12**3CB61F98B7DF8C3FF5247FFCF595044E*com.levigo.jadice.web.shared.model.internal.FlattenedRenderSpecificationData%2F4206259206*com.levigo.jadice.web.shared.model.settings.AnnotationRenderSettings%2F3358781670*%5BI%2F2970817851*%5BLcom.levigo.jadice.web.shared.model.PageSegmentHandle%3B%2F270004123*org.jwt.shared.model.UrlHandle%2F3547804392*https%3A%2F%2Fwww.levigo.de%2Ffileadmin%2Fdownload%2Fjadicewebtoolkit.pdf*document*eb5ccca6-2da7-476f-8326-05b6531b8144*%5BLjava.lang.String%3B%2F2600011424*ROT_000*1*2*3*4*0*0*72*5*4*0*0*255*255*6*1*7*8*9*5*10*11*0*842*595*0*0*12*1*

In den Request-Parametern sind unterschiedliche Informationen enthalten:

  • Infos zum Rendering in FlattenedRenderSpecificationData und AnnotationRenderSettings.
  • Unser PageSegmentHandle, das UrlHandle (vgl. 2 - Laden eines Dokuments). Es enthält alle Felder des Handles in serialisierter Form, in unserem Fall also die URL des geladenen Dokuments.
  • Zum Schluss noch weitere Informationen, wie z.B. die Rotation: ROT_000.

Weil es sich um einen einfachen GET-Request handelt, können wir die vollständige URL auch direkt in den Browser eingeben und das gerenderte Tile wird im Browser dargestellt.  Eine Änderung des Rotationswerts auf z.B. ROT_180 zeigt das Dokument auf dem Kopf an.

Info

Aufgrund der Struktur des TileRequest müssen wir folgendes beachten:

  • Die URLs verlieren ihre Gültigkeit, sobald wir das PageSegmentHandle anpassen.
  • Neue Versionen von GWT oder JWT können in Ausnahmesituationen dazu führen, dass die URLs ungültig werden.

Recover-Mechanismus

Was wir mit unserem oben erstellten Code zufälligerweise mitgetestet haben, ist der Recover-Mechanismus von JWT (vgl. http://webtoolkit.levigo.de/doc/sect.chapter-reference.general.html#sect.reference.recovery). Was heißt das?

Unser erster Request Richtung JWT ist ein Tile-Request. Bisher hat der Server aber noch gar kein Dokument geladen, zumindest wenn er neu gestartet wurde. Was passiert nun?

Der Server erkennt, dass er das Dokument zu unserem UrlHandle nicht kennt und versucht das Dokument wiederherzustellen. Das passiert über die recover()-Methode des DocumentDataProvider. Alle dazu benötigten Infos stecken, wie wir oben gesehen haben, im Tile-Request. Ab dem zweiten Request kennt der Server das Dokument und muss dieses nicht erneut laden. Was bedeut das für unseren Test und unsere Auswertung?

Wenn wir nicht sicherstellen, dass vor dem ersten Tile-Request das zugehörige Dokument geladen wurde, müssen neben dem eigentlichen Rendering immer zusätzlich folgende Schritte durchlaufen werden:

  • Laden des Dokumenten-Stream
  • Lesen des Streams über den Reader

Dies sollten wir beim Schreiben unserer Test und bei der Auswertung der Ergebnisse immer beachten. Um den Recover-Mechanismus hier auszuklammern müssen wir daher sicherstellen, dass das Dokument bereits zuvor geladen wurde.