GSB 7.0 Standardlösung

ViewDispatcher

Der ViewDispatcher ist ein spezieller Template Finder, der die Vererbungshierachie von Dokumenttypen besonders berücksichtigt.

Das GSB Content Modell ist eine objektorientierte Datenstruktur, die unter anderem stark vom Vererbungskonzept Gebrauch macht. Ebenso wie Datentypen können auch die Darstellungstemplates, die einem Dokumenttyp zugeordnet sind, entlang der Vererbungshierarchie der Dokumenttyp vererbt werden. In einen abgeleiteten Dokumenttyp können vererbte Darstellungstemplates überschrieben werden. Wenn ein Dokument mithilfe eines Darstellungstemplates beispielsweise als HTML-Seite dargestellt werden soll, so muss zunächst die Implemation des Darstellungstemplates (d.h. die JSP) bestimmt werden, die aus dem Dokument den gewünschten HTML-Code erzeugt. Diese Aufgabe wird durch einen sogenannten Template Finder übernommen.

Es ist erforderlich, gemeinsame Templates für alle Mandanten zu haben, die aber nach bestimmten Regeln überschrieben bzw. ergänzt werden können.

Aus diesem Grund wurde für den GSB ein eigener TemplateFinder entwickelt, der als Dispatcher für weitere "Unter"-ViewDispatcher dient (für jeden Mandanten einen). Dadurch können verschiedene Templates-Sets getrennt konfiguriert und verwaltet werden.

Technische Umsetzung

Der Einstiegspunkt für die technische Umsetzungsbetrachtung ist die Klasse

  • de.bundonline.basis.web.viewdispatcher.
  • MultiCustomerViewDispatcher.

Sie dient als „der“ am Generator angemeldete TemplateFinder und bekommt die initialen Anfragen für das Auffinden eines Templates zu einer ResourceUri (siehe JavaDoc zu hox.corem.servlets.TemplateFinder#findTemplate (Generator generator, ResourceUri uri).

An einer (bzw. „der“) Instanz dieser Klasse können weitere Mandanten angemeldet werden, die intern über das Instanzieren eines jeweils eigenen von de.bundonline.basis.web.viewdispatcher.CustomerViewDispatcher abgeleiteten TemplateFinders abgebildet werden.

Derzeit gibt es 2 Implementierungen von CustomerViewDispatcher:

  • de.bundonline.basis.web.viewdispatcher.
  • DefaultCustomerViewDispatcher
  • de.bundonline.basis.web.viewdispatcher.
  • IndependentCustomerViewDispatcher

Wird vom Generator eine Anfrage zum Auffinden eines Templates an den MultiCustomerViewDispatcher weitergeleitet, so benutzt dieser die konfigurierte CustomerDeterminationRule. Implementierungen dieses Interfaces dienen dazu, zu einer gegebenen URI einen Identifier (=String) zurückzuliefern, der den Mandanten identifiziert.

Eine Implementierung ist zum Beispiel

  • de.bundonline.basis.web.viewdispatcher.
  • PathViewCustomerDeterminationRule.

Diese Klasse gibt den Namen des 2. Ordners zurück, in dem die Resource aus der gegebenen URI liegt.

Beispiel:

Bei der URI = "/mandant/Content/meinArtikel.html" liefert PathViewCustomerDeterminationRule.getCustomerName() -> "mandant" als Ergebnis

DefaultCustomerViewDispatcher

Der erste von beiden (DefaultCustomerViewDispatcher) bildet das sogenannte "Z" Vererbungsmuster ab. Die Implementierung sieht die Templates aus dem Mandanten-Template-Ordner dabei als Sichten/Views von virtuellen Dokumenttypen, die quasi in die reale Dokumenttypen-Vererbung eingeklinkt werden. Jeder reale Dokumenttyp erbt nun nicht mehr von seinem realen Parent-Dokumenttyp, sondern ist ein Kind von dem mandantenspezifischen (=virtuellen) Parent-Dokumenttyp.

Ein mandantenspezifischer Dokumenttyp wiederum erbt von dem realen Dokumenttyp gleichen Namens.

Beispiel:

ViewDispatcher ViewDispatcher

Beim Einlesen der JSPs (Views) werden nun die Views auf reale und virtuelle Dokumenttypen abgebildet. Der ViewDispatcher benutzt dazu die Methode getDocTypeFromFilenname(String name), um den Namen des Dokumenttyps aus dem Pfad einer JSP zu ermitteln. Der DefaultCustomerViewDispatcher überschreibt diese Methode, benutzt die Super-Methode und ergänzt den dort gefundenen Dokumenttypnamen ggf. um ein Trennzeichen ("$") und den Namen des Mandanten, wenn die JSP unterhalb des mandantenspezifischen Template Verzeichnis liegt

  • (templates/customers/{MANDANTENNAME}).

Beispiel:

getDocTypeFromFile-name("templates/customers/test/Article/render.jsp")

-> Article$test

getDocTypeFromFile-

  • name ("templates/Article/render.jsp")

-> Article

Der ViewDispatcher merkt sich diese gefunden View/Dokumenttyp-Paare in einer Map zum späteren Lookup beim Auffinden von Templates.

Wird nun ein Anfrage für eine bestimmte Resource an diesen ViewDispatcher weitergeleitet (vom MultiCustomerViewDispatcher, siehe oben), so versucht dieser zunächst den Dokumenttyp aus der URI zu ermitteln. Diese Methode des ViewDispatchers ist im DefaultCustomerViewDispatcher überschrieben und ergänzt den von der Superklasse gefundenen Dokumenttypennamen einfach um den Zusatz des Mandanten und erzeugt somit die Zuordnung zu dem mandantenspezifischen Dokumenttyp.

Beispiel:

Für den Mandanten "test" liefert getDocTypeFromUri(uri) für eine URI auf den Dokumenttyp "Article" das Ergebnis "Article$test".

Der jetzige Suchmechanismus nach dem passenden Template ist wiederum Teil des CoreMedia Standard ViewDispatcher, von dem wir ja erben. Er benutzt die zuvor eingelesene Map mit den realen und virtuellen Dokumenttyp-/View-Kombinationen, die auf JSPs verweisen. Wird kein Template für genau diesen Dokumenttyp gefunden, so ruft der ViewDispatcher die Methode superType(String type) auf, um den Parent-Dokumenttyp zu ermitteln. Auch diese Methode ist im DefaultCustomerViewDispatcher überschrieben und liefert, je nachdem ob der angefragte Typ bereits ein mandantenabhängiger Typ ist oder nicht, entweder einen realen oder einen virtuellen Dokumenttypnamen zurück.

Beispiel:

superType("Article") -> "Document$test"

superType("Article$test") -> "Article"

Hinweis:

Diese virtuellen Dokumenttypen existieren *nur* in dem DefaultCustomerViewDispatcher, keiner anderen Klasse ist dies bekannt (ansonsten würde es Fehler geben, wenn auf einen solchen Dokumenttyp referenziert würde)

IndependentCustomerViewDispatcher

Neben dem zuvor beschriebenen "Z"-Vererbungsmuster gibt es auch eine Konfiguration, bei der ein Mandant gar keine oder nur im Ausnahmefall Defaulttemplates benutzt. Bei einer Anfrage an den IndependentCustomerViewDispatcher, wird zunächst nur der Template-Zweig in dem mandantenabhängigen Teil berücksichtigt. Wird dort kein entsprechendes Template gefunden und ist der IndependentCustomerViewDispatcher so konfiguriert, dass er auch die Default-Templates nutzen darf (Konstruktor-Parameter useDefaultTemplates = true), so sucht der MultiCustomerViewDispatcher anschliessend in den default Templates. Anderenfalls bricht der Suchvorgang ab, bzw. es wird die doesNotUnderstand.jsp zurückgeliefert.

Beispiel Suchreihenfolge (mit Defaulttemplates):

Article$mandant ->

Document$mandant ->

Resource$mandant ->

Article ->

Document ->

Resource

Property-Templates

Property-Templates funktionieren natürlich analog. Diese werden intern vom ViewDispatcher ähnlich unseren oben beschriebenen virtuellen Dokumenttypen abgebildet, werden also aus Dokumenttypnamen, Trennzeichen, Propertytyp und ggf. weiterer Einschränkungen (MIME Type) gebildet. Wir ergänzen dann evtl. noch den Mandanten-Postfix und der restliche Lookup ist genau gleich, wie bei den Resource-Templates.

ViewVarianten

View Varianten sind ebenfalls möglich, jedoch ist die Suchreihenfolge beim DefaultCustomerViewDispatcher zu beachten. Wird ein Template plus ViewVariante gesucht, so wird zunächst versucht ein Template mit der ViewVariante im Mandanten-Template-Zweig zu finden. Gelingt dies nicht, so wird versucht das Template ohne Variante im Mandanten-Template-Zweig zu finden. Erst wenn dies auch nicht möglich ist, so wird auf den Default-Zweig übergegangen und dort zunächst wieder die Variante gesucht.

Beispiel Suchreihenfolge

Article$mandant.render[variante] ->

Article$mandant.render ->

Article.render[variante] ->

Article.render ->

Document$mandant.render[variante] ->

Document$mandant.render ->

Document.render[variante] ->

Document.render ->

Resource$mandant.render[variante] ->

Resource$mandant.render ->

Resource.render[variante] ->

Resource.render

Bei mehreren gleichzeitigen Varianten geht der ViewDispatcher so vor, dass er zunächst nach einer JSP mit allen Varianten sucht und danach immer die letzte Variante streicht.

render[varianteA, varianteB, varianteC] ->

render[varianteA, varianteB]

-> render[varianteA] -> render

UML Diagramme & UpdateViews

Die Anzeigen in den Generator Developseiten wurden entsprechend angepasst, so dass diese auch gezielt auf einen Mandanten angewendet werden können. Das gilt für die UpdateViews Aufrufe und die Darstellung des Dokumenttypmodells inklusive der gefundenen Views.