Zum Hauptinhalt gehen

Workflow mit Service im ContentCreator nutzen

Kommentare

10 Kommentare

  • Zendesk API User
    Author: king - 11/20/2014 14:02

    Hallo Andreas,

    wir haben eine Passage in der FirstSpirit Module-Developer Dokumentation in Kapitel 2.10.2 gefunden, die das Problem beseitigen helfen können sollte. Allerdings ist hier explizit die Rede von IBM WebSphere. Wir verwenden jedoch Apache Tomcat, hier in Version 7.0.54.

    Dabei wird vorgeschlagen, die "fs-webrt.jar" nicht zentral über den Tomcat Standard-Classloader  sondern je FirstSpirit Web-Applikation vorzuhalten und dabei über den sog. WebApp-Classloader laden zu lassen. Ziel ist: Klassen nicht über unterschiedliche Classloader zu verwenden und dadurch deren Verwaltung zu trennen. Diesen Schritt haben wir manuell versucht, in dem wir sowohl die gesamte JAR aus dem Modul mit den Services als auch die JAR "fs-webrt.jar" in sämtlichen FirstSpirit-spezifischen Web-Applikationen "/fs5webedit", "/fs5preview", "/fs5staging", "/fs5root" bereitgestellt haben. Das Ergebnis überraschte: der Aufruf der "getService()"-Methode war weiterhin NICHT möglich.

    Die Variante eine dedizierte WebApp über ein Modul bereitzustellen und dann auf dem Applikationsserver zu deployen macht jedoch genau das auch: beim Download der "WAR"-Datei aus FirstSpirit heraus wird die "fs-webrt.jar" implizit in das WAR-Archiv zu den dort bestehenden Bibliotheken gelegt, die Teil der Web-Komponente sind. Zusammen werden sie dann über für den Classloader verfügbar gemacht. Wir haben diesen Schritt auch deshalb nicht explizit hier versucht, weil schon dere obere fehlschlug.

    Allerdings - und das interssant - klappt dann der Aufruf der "getService()"-Methode wenn die Service-Klassen explizit im Standard-Classloader neben der "fs-webrt.jar" liegen, also unter ~tomcat/lib. Jedoch mussten wir die JAR mit den FirstSpirit Service-Methoden um gewisse Pakete reduzieren, etwas solche, deren Klassen in FirstSpirit-Templates statisch aufgerufen werden. Als Beispiel sei die "PermaLink"-Klasse genannt:

    permaLink = PermaLink.getPermaLink(gc, e, languageId, contentId, e.getProject().getName() + "_", "html");

    Bei beiden eingangs beschriebenen Wegen:

    1. manuelle Kopie,
    2. WebApp-Anwendung

    würde allerdings dann die Empfehlung aus Kapitel 4.5.3 der "FirstSpirit Dokumentation für Administratoren" beim Setup über einen externen Applikationscontainer nicht befolgt werden können. Hier wird vorgeschlagen, die "fs-webrt.jar" zentral abzulegen und über die zentrale Tomcat Konfigurationsdatei "catalina.properties" zu integrieren.

    Deshalb folgende Fragen:

    - warum klappt der Aufruf von Services über "getService()" dann nicht wenn deren Klassen neben der "fs-webrt.jar" in den FirstSpirit Web-Applikationen liegen?

    - warum ist der Aufruf Möglich wenn beide Teile über den Standard-VM-Klassenlader von Tomcat geladen werden, sie also etwa in ~tomcat/lib liegen?

    - warum braucht es eine Reduzierung diverser Klassen, weil bei der sonst für eine fehlerfreie Nutzung im ContentCreator schädlich sind?

    - wie können diese Klassen identiziert werden?

    - warum gibt es keine Möglichkeit eine zentrale FirstSpirit ContentCreator Web-Anwendung über FirstSpirit zu bauen, die NICHT project-spezifisch ist?

    0
  • Zendesk API User
    Author: AuM - 11/20/2014 17:09

    Ich habe drei Fälle ausprobiert und die Resultate (Classloader und Möglichkeit der Service-Aufrufe) beschrieben. Für jeden Fall habe ich erwähnt wo die fs-webrt.jar, sowie unsere service.jar deployed sind und über welche Classloader der Service sowie die FirstSpirit Connection (context.getConnection()) geladen wurden.

    Der u.g. statische Methodenaufruf bezieht sich auf ein Beanshell-Script, welches in der Seitengenerierung verwendet wird und eine statische Methode aus einer Klasse des Service-JARs aufruft. Diese statische Methode hat folgende Signatur:

    public static String getPermaLink(final GenerationScriptContext context, final IDProvider element,final String languageId, final String contentId, final String uidPrefix, final String templateSet) {

    In den Fällen in denen die Methode in der Seiten-Preview nicht aufrufbar war vermuten wir stark, dass die Signatur nicht gematched hat, da das Objekt vom Typ GenerationScriptContext aus einem anderen Classloader stammt, als die Klasse der o.g. statischen Methode.

    Fs-WebRT in tomcat/lib

    Service-JAR in tomcat/lib:

    Service: org.apache.catalina.loader.StandardClassLoader@5b8b3f9a,

    Connection: WebappClassLoader context: /fs5webedit delegate: false repositories: ----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@5b8b3f9a

    Service Aufruf OK, Statischer Methoden Aufruf nicht OK

    Fs-WebRT in tomcat/lib

    Service-JAR in fs5webedit/lib:

    Service: de.espirit.firstspirit.server.module.ModuleClassesLoader@13b56e1d-81,

    Connection: WebappClassLoader context: /fs5webedit delegate: false repositories: ----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@114662e3

    Service Aufruf nicht OK, Statischer Methoden Aufruf OK

    Fs-WebRT in tomcat/lib

    Service-JAR not deployed:

    Service: de.espirit.firstspirit.server.module.ModuleClassesLoader@49a2e909-101,

    Connection: WebappClassLoader context: /fs5webedit delegate: false repositories: ----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@12fcc66a

    Service Aufruf nicht OK, Statischer Methoden Aufruf OK

    Wir haben, erfolglos, ebenfalls versucht die fs-webrt.jar mit in die WEB-INF/lib zu deployen, konnten jedoch keine Verbesserung feststellen.

    Warum unterscheiden sich Fall 2 und Fall 3 nicht? Ich hätte für Fall 2 erwartet, dass der Service über den WebAppClassLoader geladen wird, da die JAR in der WEB-IN/lib deployed ist.

    Der Vollständigkeit halber anbei noch das Script zum Testen der Service-Aufrufe:

    //!Beanshell

    import com.bosch.fsm.dialogue.DialogueHelper;

    import de.espirit.firstspirit.store.access.pagestore.PageImpl;

    import de.espirit.firstspirit.store.access.pagestore.SectionImpl;

    import de.espirit.firstspirit.store.access.contentstore.Content2Impl;

    import de.espirit.or.schema.Entity;

    import com.bosch.fsm.ams.ActivityManagerServiceImpl;

    service = new ActivityManagerServiceImpl();

    DialogueHelper.showInfoDialogue(context, "Classloaders",  "Service: " + service.getClass().getClassLoader().toString() + ", Connection: " + context.getConnection().getClass().getClassLoader().toString());

    try {

        someService = context.getConnection().getService("ActivityManagerService");

        DialogueHelper.showInfoDialogue(context, "Service found",  "Everything fine.");

    } catch(Exception e) {

        DialogueHelper.showErrorDialogue(context, "Service not found",  "Nothing fine.", e);

    }

    0
  • Zendesk API User
    Author: Peter_Jodeleit - 11/21/2014 9:24

    Fs-WebRT in tomcat/lib

    Service-JAR in tomcat/lib:

    Service: org.apache.catalina.loader.StandardClassLoader@5b8b3f9a,

    Connection: WebappClassLoader context: /fs5webedit delegate: false repositories: ----------> Parent Classloader: org.apache.catalina.loader.StandardClassLoader@5b8b3f9a

    Service Aufruf OK, Statischer Methoden Aufruf nicht OK

    Das "Connection: WebappClassLoader context: /fs5webedit" deutet darauf hin, das in "fs5webedit/lib" noch FirstSpirit-Klassen liegen. Dies führt dazu, das der Tomcat diese "bevorzugt". Damit kommt es dann zu der von dir auch schon vermuteten Inkompatibilität.

    Wichtig ist, dass die Klassen, die interagieren müssen, über den gleichen ClassLoader kommen.

    Entfernt ihr also aus dem "fs5webedit/lib" Verzeichnis die Libs, die Klassen enthalten, die auch unter "tomcat/lib" liegen, sollten beide Fälle funktionieren.

    0
  • Zendesk API User
    Author: AuM - 11/21/2014 9:59

    Hallo Hr. Jodeleit,

    vielen Dank erstmal für die Antwort.

    Die Vermutung, dass FirstSpirit Klassen in der WebApp liegen ist insofern richtig, dass es die Standard-FS-Webedit WebApp ist und diese natürlich FirstSpirit Jars mitbringt (fs-webedit.jar, etc.). Daran möchten wir jedoch auch nichts ändern und diese nicht in das tomcat/lib Verzeichnis verschieben.

    Viel wichtiger für mich ist der zweite genannte Fall (custom-services.jar + fs-webrt.jar in WEB-INF/lib). Hierbei verstehe ich nicht, wieso die Services dort von ModulesClassloader gezogen werden und nicht aus der WebApp. M. M. n. erzeugt dieser Fall eine äquivalente Web-Applikation wie ein Inkludieren einer FS-Modul WebApp Komponente in die ContentCreator Applikation und sollte daher ohne Abstriche sowohl für Service-Aufrufe, als auch statische Methodenaufrufe aus der Preview funktionieren, oder?

    In diesem Fall wären dann sowohl Services, FS-Jars und statische Klassen in dem gleichen Classloader (WebappClassloader) und die Probleme sollten vermutlich verschwunden sein.

    Habe ich hier einen Gedankenfehler oder gibt es einen besseren Weg?

    Vielen Dank und Gruß

    Martin

    P. S.

    Der Grund warum wir keine WebApp-Komponente im FirstSpirit Modul nutzen liegt darin begründet, dass wir pro Stage rd. 20 Projekte haben und in diesem Fall ca. 60 Custom ContentCreator + Preview WebApps deployen und betreiben müssten. Die Möglichkeit eigene Web-Komponenten zentral, also ein mal pro Stage in die ContentCreator / Preview WebApps hinzuzufügen gibt es ja (noch) nicht für eigene Erweiterungen (https://community.e-spirit.com/message/21592#21592).

    Wir wollen den betrieblichen Overhead / zusätzlichen Ressourcenverbrauch der vielen WebApps vermeiden und versuchen daher die relevanten Jar-Files per Dateisystem in die FirstSpirit WebApps zu integrieren.

    0
  • Zendesk API User
    Author: Peter_Jodeleit - 11/21/2014 10:14

    Viel wichtiger für mich ist der zweite genannte Fall (custom-services.jar + fs-webrt.jar in WEB-INF/lib). Hierbei verstehe ich nicht, wieso die Services dort von ModulesClassloader gezogen werden und nicht aus der WebApp.

    Das ist (in eurem Fall "leider") ein Implementierungs-Detail. Solange man nach der Empfehlung vorgeht, stört dieses Detail auch nicht.

    Ich verstehe das Problem und den Anwendungsfall aber durchaus. Eine Änderung der Verfahren in dem Umfeld birgt allerdings ein hohes Risiko und muss bezüglich Kompatibilität genau evaluiert werden.

    0
  • Zendesk API User
    Author: king - 11/21/2014 10:34

    Hallo Herr Jodeleit,

    könnten Sie bezüglich der Empfehlungen (P. Jodeleit, H. Isenberg) von e-Spirit konkret werden?  Wie verhält es sich mit dem "Entwicklerhandbuch für Komponenten" in Kapitel 2.10.2 und der Aussage in Kapitel 4.5.3 der "Dokumentation für Administratoren".

    Nach unserem Verständnis sind wir mit Ansatz (2) durch Ablage der beiden Bibliotheken "fs-webrt.jar" und der individuellen "services.jar" innerhalb von "/fs5webedit" Ihren Wünschen gefolgt. Jedoch zeigte sich hier, wie im Fall (2) von Martin Aulich beschrieben, dass dieser nicht trägt. Da selbst der Service nicht gerufen werden konnte.

    Da sich in der Dokumentation unterschiedliche Aussagen und Empfehlungen finden würden wir gerne verstehen:

    • welche Teile in welche JARs gepackt werden müssen
    • wo diese liegen sollen

    Augenscheinlich werden identische Klassen über unterschiedliche Classloader angezogen. Dies führt zu den hier beschriebenen Problemen.

    0
  • Zendesk API User
    Author: AuM - 11/21/2014 10:37

    Eine kleine Ergänzung von mir:

    Wenn ich mich nicht irre ist die Empfehlung (siehe: https://community.e-spirit.com/community/developer/blog/2014/03/27/how-to-fix-failing-service-calls-in-web-environment) die eigene Jar mit den Services sowie deren Abhängigkeiten als Web-Komponente dem ContentCreator hinzuzufügen, korrekt?

    Wie unterscheidet sich unser Szenario Nr. 2 (manuelles Kopieren der Jars in die Standard FS-WebApps) von der Empfehlung? Wenn ich exemplarisch eine WebApp Komponente mit einer eigenen Jar an den ContentCreator hänge und mir das WAR File downloade wirken beide WebApps äquivalent. Ich verstehe aktuell nicht, warum der Weg über FirstSpirit WebApp Komponenten funktionieren soll und der Weg über manuelles Integrieren der Jars nicht. Vergessen wir da etwas?

    0
  • Zendesk API User
    Author: Peter_Jodeleit - 11/21/2014 12:18

    Mit Fall 2) ist "Fs-WebRT in tomcat/lib und Service-JAR in fs5webedit/lib" gemeint?

    0
  • Zendesk API User
    Author: AuM - 11/21/2014 12:22

    Ja, mit Fall 2) meinte ich folgendes Szenario:

    Fs-WebRT in tomcat/lib

    Service-JAR in fs5webedit/lib:

    Wobei wir als Abwandlung (siehe mein erster Post) ebenfalls die fs-webrt.jar von tomcat/lib in fs5webedit/lib verschoben haben - leider ohne positiven Effekt.

    0
  • Zendesk API User
    Author: AuM - 11/24/2014 13:44

    So, nun ist das Rätsel gelöst!

    Der Grund warum sich in Post https://community.e-spirit.com/message/22690#22690 der Fall 2 und 3 nicht unterschieden haben lag in unserem JAR-File begründet. Über eine transitive Abhängigkeit hat sich die Servlet API in unser JAR-File geschlichen, so dass der Tomcat es für das Classloading ignoriert hat (http://tomcat.apache.org/tomcat-7.0-doc/class-loader-howto.html: "...any JAR file that contains Servlet API classes will be explicitly ignored by the classloader — Do not include such JARs in your web application...").

    Da die Klassen dann gemäß der Classloading Hierarchie vom FS-Modul Classloader gezogen wurden kam es zum beschriebenen Fehlerbild.

    Die Korrekte Lösung (ohne Nutzung von custom Web-Applikationen) ist also das Verschieben der fs-webrt.jar sowie der custom JARs in das WEB-INF/lib Verzeichnis der entsprechenden ContentCreator / Preview Applikationen.

    Vielen Dank für die Unterstützung bei der Fehlersuche!

    Martin

    0

Bitte melden Sie sich an, um einen Kommentar zu hinterlassen.