StefanS
Returning Observer

Isolated Module: Server-Mode vs Module-Mode

Moin,

eigentlich hätte ich ja gedacht, dass ich im Isolated Mode eines Moduls die Nutzung von Bibliotheken verstecken kann. Dies funktioniert aber nicht, wenn diese Bibliotheken im Modul selbst genutzt werden, dessen Klassen auf server-Ebene liegen.

Hintergrund: Ich möchte Utility-Klassen bereitstellen, die ich bspw. in Auftrags-Aktionen nutzen kann. Dafür muss die Modul-Bibliothek im server-Mode bereitgestellt werden, weil die Klassen sonst nicht sichtbar sind. Nun benutze ich auch eine commons-Bibliothek in den Utilities. Die (externe) Bibliothek möchte ich natürlich nicht auf server-Mode stellen. Das geht aber nicht (und der FSM-Checker meckert auch entsprechend).

Wie sieht eine gute Alternative aus? Gibt es einen praktischen oder pragmatischen Ansatz, um solche Klassen bereitzustellen oder müssen dann alle genutzten Libraries auch auf server-Mode stehen? Würde ja ein wenig dem Isolated Gedanken widersprechen. Warum findet der Classloader der Modulbibliothek die (Modul-internen) module-Mode-Libraries nicht? Oder übersehe ich die einfache Lösung?

Danke für eure Gedanken
Stefan

0 Kudos
6 Replies
Windmüller
Crownpeak employee


eigentlich hätte ich ja gedacht, dass ich im Isolated Mode eines Moduls die Nutzung von Bibliotheken verstecken kann.

Die eigentliche Intention des Isolated Mode ist, die vom FirstSpirit-Server mitgelieferten Jars von den Klassen der Module zu isolieren. Ansonsten wären Änderungen an den internen Bibliotheken nur mit hohem Risiko möglich, da sich die Module womöglich auf bestimmte Versionen verlassen. Durch die Isolierung kann jedes Modul die Librarys in den Versionen mitbringen, die es selbst benötigt.

 

Hintergrund: Ich möchte Utility-Klassen bereitstellen, die ich bspw. in Auftrags-Aktionen nutzen kann. Dafür muss die Modul-Bibliothek im server-Mode bereitgestellt werden, weil die Klassen sonst nicht sichtbar sind. Nun benutze ich auch eine commons-Bibliothek in den Utilities. Die (externe) Bibliothek möchte ich natürlich nicht auf server-Mode stellen. Das geht aber nicht (und der FSM-Checker meckert auch entsprechend).

Das ist soweit auch erst einmal richtig. Allerdings ist die Sichtbarkeit der Classloader eine andere: Modul-lokale Classloader haben Zugriff auf alle globalen Ressourcen von allen Modulen, die wiederum den Runtime-Classloader von FirstSpirit "sehen" können. Die Richtung von Server-Scope nach Module-Scope ist nicht möglich. Hier das Zitat aus der Dokumentation:

"Es gilt: Klassen aus global-definierten Jars können keine Klassen aus modul-lokal definierten Jars benutzen. Der umgekehrte Weg ist jedoch möglich."

Ganz generell ist die Empfehlung, auf globale Ressourcen soweit wie möglich zu verzichten, vor allem wenn es sich um häufig genutzte Komponenten (wie in diesem Fall Apache Commons) handelt.

StefanS
Returning Observer

Hi Stephan,

grundsätzlich ist mir das alles schon klar. Eigentlich ist meine Frage eher, wie eine Lösung der Problematik aussehen könnte. Und wieso der Classloader bei Server-Level Klassen eines Moduls nicht auch den eigenen Modul-Classloader erreichen können sollte. Thommy hat mir das damals bestimmt alles schon einmal erklärt 😊

Man möchte für seine (Utility-)Klassen doch auch keinen Client-Service-Mechanismus aufsetzen müssen, um eine ordentliche Trennung hinzubekommen. 🤔

Könnte man alternativ nicht in FirstSpirit die in einem Modul als "Public" deklarierten Klassen automatisch global als eine Art Proxy bereitstellen und so komplett auf Server-Scope verzichten?

Besten Dank für deine Geduld und Hilfe,
Stefan

0 Kudos

Das Problem ist hier die Transitivität der Classloader. Wenn globale Classloader Zugriff auf ihre "eigenen" Modul-Classloader haben, die aber wiederum Zugriff auf alle globalen Ressourcen, wäre die Isolierung der Module untereinander nicht mehr gegeben.

Utility-Klassen in den globalen Scope zu schieben mag eine naheliegende Idee sein, ist mit der Classloader-Hierarchie aber problematisch. Besser wäre es z.B., die Klassen in einzelne Jar-Artefakte zu verpacken, die dann von den jeweiligen Modulen im lokalen Classloader mitgebracht werden.

StefanS
Returning Observer

Hm. Entweder habe ich den letzten Absatz nicht verstanden oder wir reden von unterschiedlichen Dingen. 😄

Mit Utility-Klassen meine ich Funktionscontainer, die ich in Auftragsaktionen oder Vorlagen nutze, um komplexe Skripte zu vermeiden bzw. um der "Executable-Schwemme" zu entgehen.

Und anscheinend stimmt dann die Dokumentation für Public Klassen auch nicht (mehr?), denn dort steht ja: "Public-Komponenten sind immer server-weit sichtbar, d.h. sie stehen nach der Installation auf dem Server, im Client, in Scripten und anderen Modulen ohne weitere Aktivierung zur Verfügung". Für Executables scheint dies ja zu funktionieren. Zumindest laut Doku: "Eine ausführbare Implementierung kann auch referenziert werden, wenn die Klasse in einem modul-lokalen Jar-Archiv liegt". Kann aber auch sein, dass ich das falsch lese.

0 Kudos

Hi Stefan,

die von dir verlinkte Doku spricht von Komponenten. Das ist nicht gleichbedeutend mit Klassen. Am Beispiel von Executables: Die sind über #!executable-class als Komponente zwar nutzbar, auch wenn (was ja auch in der Doku unter „Gültigkeitsbereich“ erklärt bzw. empfohlen wird) ihre Klassen im module-Scope liegen.

Mit „ausführbare Implementierung“ sind hier schlicht Executables gemeint. 

Viele Grüße 

Michael

0 Kudos
Windmüller
Crownpeak employee

Sorry, da gab es wirklich ein Missverständnis. Für mich sind "Utility-Klassen" solche, die aus Bequemlichkeit einmal geschrieben werden, um sie dann an verschiedenen Orten (oder in verschiedenen Projekten) zu nutzen, wie etwa ein StringUtil.

Die Verwirrung mit den Executables kommt wohl daher, dass mit "server-weit sichtbar" nicht gemeint ist, dass die gewünschten Klassen im Server-Scope liegen müssen. Executables laufen (wie auch Upload-Hooks) vollständig auf dem FirstSpirit-Server in einer Umgebung wie dem FS-Server oder dem SiteArchitect, die den passenden lokalen Modul-Classloader für die Ausführung selbst auswählen kann.

Ein Gegenbeispiel wäre ein Service: Dieser kann auch von einem (Web-)Client aus aufgerufen werden. Da es im Application-Server (z.B. Tomcat) aber nur einen Classloader gibt, der nicht unter unserer Kontrolle steht, kann hier jede Klasse nur in einer einzigen Version geladen werden: Die Version, welche durch den globalen FirstSpirit-Classloader vorgegeben ist. Daher sollte ein Service nur das eigene Interface auf den Server-Scope legen, die gesamte Implementierung kann im Modul-Scope geschehen. Vorsicht ist hier nur geboten bei der Definition von Methodenparametern und Rückgabewerten, diese sollten idealerweise aus dem JDK kommen.