aschuch
I'm new here

Objekte aus dem Ausgabekanal heraus an Methode übergeben

Jump to solution

Hallo zusammen,

angenommen ich habe die folgende statische Methode in einer Library eines FS-Modul in der Klasse SomeClass implementiert:

public static String doSomething(Section section) {
     return section.getDisplayName();
}

Wie kann ich diese Methode aus dem Ausgabekanal heraus aufrufen, um z.B.  den Rückgabewert der Methode über $CMS_SET(...)$ in einer Variablen zu  speichern?
Und ist es überhaupt möglich das Section-Objekt als solches aus dem  Ausgabekanal heraus zu übergeben? (Aus einem Renderskript heraus geht  es, das weiss ich, aber direkt aus dem Ausgabekanal?)

Ich habe das mal mit einer Service-Methode ausprobiert, die ich über

$CMS_SET(result, #global.getConnection().getService("de.adesso.firstspirit.SomeService").doSomething(#global.section))$

aufgerufen habe und dabei die Erfahrung gemacht, dass innerhalb des  Ausgabekanals der Zugriff auf Objekte wie z.B. #global, #global.section,  #global.page usw. nur zur textuellen Ausgabe der Inhalte dieser  Elemente möglch ist. Es wird immer alles auf eine Zeichenkette  heruntergebrochen.
D.h. durch den obigen Aufruf wurde der textuelle Inhalt des Absatzes an  die Methode übergeben, was dann natürlich zu einem Fehler geführt hat.

Viele Grüße,
Alexander

0 Kudos
1 Solution

Accepted Solutions
gockel
Crownpeak employee

Welche alternative Möglichkeit gibt es denn, eine Modul-Klasse bzw. konkret eine Modul-Methode aus dem Ausgabekanal heraus aufzurufen? (außer über ein Renderskript)

Keine. Das Renderskript mit Executable ist der alternative Weg.

View solution in original post

0 Kudos
8 Replies
gockel
Crownpeak employee

Hallo Alexander,

dabei die Erfahrung gemacht, dass innerhalb des  Ausgabekanals der  Zugriff auf Objekte wie z.B. #global, #global.section,  #global.page  usw. nur zur textuellen Ausgabe der Inhalte dieser  Elemente möglch ist.  Es wird immer alles auf eine Zeichenkette  heruntergebrochen.
D.h.  durch den obigen Aufruf wurde der textuelle Inhalt des Absatzes an  die  Methode übergeben, was dann natürlich zu einem Fehler geführt hat.

das ist so nicht richtig. Der Aufruf, den du gemacht hast, sollte genau so funktionieren, wie von dir erwartet. Ich habe es gerade mit einem Aufruf an einen unserer Services nachgetestet. In meinem Fall war der Methodenparameter #global.project und auch das zurückgegebene Objekt war ein komplexer Typ, auf den ich nach dem $CMS_SET$ mit einem $CMS_VALUE()$ Aufruf zugegriffen habe.

Was mich an deinem Aufruf gegen den Service ein wenig wundert ist die Angabe des Namens

getService("de.adesso.firstspirit.SomeService")

Ist dieser Service wirklich mit diesem Namen, also dem vollständigen package als Namen als Service registriert? Ansonsten müsstest du nämlich die Klasse an die Methode #getService übergeben, um diesen zu erhalten.

getService(class("de.adesso.firstspirit.SomeService"))

Allgemeine Anmerkungen:

  • Man sollte sich rein aus Performancegründen gut überlegen, ob man aus einem Template (Ausgabekanal) heraus, also während der Generierung und auch während der Vorschau einen Service ansprechen will / muss.
  • Wenn es eher darum geht statt einem Skript eine Java Klasse zu verwenden sollte man eher ein Executable verwenden (siehe nachfolgend)

Skript als Executable einbinden

1. Executable als Library einbinden

Zunächst implementiert man eine Klasse, die das Interface Executable implementiert.

2. Skript als Executable einbinden

executable.jpg

3. Aufruf und Übergabe von Objekten an das Executable

Ein solches Skript wird wie gewohnt aufgerufen. Bsp:

$CMS_RENDER(script:"executable", "var1":#global.node)$

Innerhalb der Executable Implementierung stehen die übergebenen Parameter (in diesem Fall "var1") dann innerhalb der context Map, die als Parameter an die Methode #execute übergeben wird, zur Verfügung.

Hallo Sebastian,

erstmal vielen Dank für die ausführliche Antwort!

Was mich an deinem Aufruf gegen den Service ein wenig wundert ist die Angabe des Namens

getService("de.adesso.firstspirit.SomeService")


Ist dieser Service wirklich mit diesem Namen, also dem vollständigen package als Namen als Service registriert? Ansonsten müsstest du nämlich die Klasse an die Methode #getService übergeben, um diesen zu erhalten.


getService(class("de.adesso.firstspirit.SomeService"))

Ja, bei dieser Klasse handelt es sich um einen Service, der in Form einer Service-Komponente dem FirstSpirit-Modul hinzugefügt ist.

Ich habe gerade auch noch einmal versucht einem Service ein komplexes Objekt (#global.section) zu übergeben und weiterzuverarbeiten und bin verwundert, dass es funktioniert hat. Wer weiß was ich vorher falsch gemacht habe. Nun gut ... Smiley Happy

Jetzt stelle ich mir die Frage in welchen Fällen man denn gezwungenermaßen einen Aufruf über

getService(class("..."))

durchführen muss?

Und bei der zuerst von mir beschriebenen Methode handelt es sich um keine solche Service-Methode:

angenommen ich habe die folgende statische Methode in einer Library eines FS-Modul in der Klasse SomeClass implementiert:

public static String doSomething(Section section) {
     return section.getDisplayName();
}

Wie rufe ich eine solche aus dem Ausgabekanal auf?

Hätte gedacht, dass das dann über

$CMS_SET(test, class("de.adesso.firstspirit.SomeClass").doSomething(#global.section))$

funktionieren sollte. Tut es bei mir jedoch nicht.

Viele Grüße,

Alexander

0 Kudos
gockel
Crownpeak employee

Ja, bei dieser Klasse handelt es sich um einen Service, der in Form  einer Service-Komponente dem FirstSpirit-Modul hinzugefügt ist.

Entscheidend ist an dieser Stelle, wie der der Servicedescriptor innerhalb der module.xml definiert ist.

<service>
     <name>BeispielService</name>
     <description>Ein Beispiel Service</description>
     <class>de.espirit.firstspirit.service.exampl.ExampleService</class>
</service>

In diesem Beispiel ist der Service über folgende Wege erreichbar:

1. getService("BeispielService")

2. getService(class("de.espirit.firstspirit.service.exampl.ExampleService"))

Wenn also in deinem Fall  de.adesso.firstspirit.SomeService innerhalb des <name> Tags steht, dann sollte es auch so funktionieren, wie du es initial verwendet hast.

Jetzt stelle ich mir die Frage in welchen Fällen man denn gezwungenermaßen einen Aufruf über
"getService(class("..."))"
durchführen muss?

Gar nicht. In der Verwendung des Aufrufs innerhalb einer Javaklasse sollte man den Aufruf mit der Klasse nehmen, da dieser typsicher ist. Aus dem Template heraus ist es im Grunde egal.

Hätte gedacht, dass das dann über


$CMS_SET(test, class("de.adesso.firstspirit.SomeClass").doSomething(#global.section))$


funktionieren sollte. Tut es bei mir jedoch nicht.

Ich auch. Kannst du mal die Fehlermeldung posten, die bei der Generierung bzw. Previewerzeugung geloggt wird. Ggfls. musst du das Template-Debugging einschalten. ($CMS_SET(#global.debugMode, true)$)

Sebastian Gockel schrieb:

Entscheidend ist an dieser Stelle, wie der der Servicedescriptor innerhalb der module.xml definiert ist.

<service>
     <name>BeispielService</name>
     <description>Ein Beispiel Service</description>
     <class>de.espirit.firstspirit.service.exampl.ExampleService</class>
</service>


In diesem Beispiel ist der Service über folgende Wege erreichbar:



1. getService("BeispielService")
2. getService(class("de.espirit.firstspirit.service.exampl.ExampleService"))


Wenn also in deinem Fall  de.adesso.firstspirit.SomeService innerhalb des <name> Tags steht, dann sollte es auch so funktionieren, wie du es initial verwendet hast.


Der Package-Pfad steht nicht im <name>-Tag. Darin steht einfach nur ein Name, den ich für den Service vergeben habe:

<service>
    <name>BeispielService</name>
    <description>Mein BeispielService</description>
    <class>de.adesso.firstspirit.BeispielServiceImpl</class>

</service>

Und trotzdem funktioniert der Aufruf über

getService("de.espirit.firstspirit.service.exampl.BeispielService")


ohne das class(...). Evtl. ein Feature? Smiley Happy

Sebastian Gockel schrieb:

Hätte gedacht, dass das dann über


$CMS_SET(test, class("de.adesso.firstspirit.SomeClass").doSomething(#global.section))$


funktionieren sollte. Tut es bei mir jedoch nicht.

Ich auch. Kannst du mal die Fehlermeldung posten, die bei der Generierung bzw. Previewerzeugung geloggt wird. Ggfls. musst du das Template-Debugging einschalten. ($CMS_SET(#global.debugMode, true)$)

Bei der Generierung kommt es zu einer ClassNotFoundException. Hier der StackTrace:

ERROR 13.10.2010 13:36:02.314 {seID=6091} (de.espirit.firstspirit.generate.SiteProduction): java.lang.ClassNotFoundException: de.adesso.firstspirit.teaser.template.TeaserTemplateUtil

    inside of: Template 'Teaserseite' (id=6063)

    inside of: $CMS_RENDER(template:"WEBeditInplaceBody", name:"teaser_top")$ - at 320, 15

    inside of: Format Template 'WEBeditInplaceBody' (id=6150)

    inside of: $CMS_TRIM(level:4)$ - at 1, 34

    inside of: $CMS_TRIM(level:0)$ - at 15, 5

    inside of: $CMS_VALUE(#global.page.body(name))$ - at 15, 24

    inside of: Template 'teaserFunctionTeaser' (id=6087)

    inside of: $CMS_SET(bla, class("de.adesso.firstspirit.teaser.template.TeaserTemplateUtil").test(#global.section))$ - at 31, 1

java.lang.ClassNotFoundException: de.adesso.firstspirit.teaser.template.TeaserTemplateUtil

    at java.net.URLClassLoader$1.run(URLClassLoader.java:200)

    at java.security.AccessController.doPrivileged(Native Method)

    at java.net.URLClassLoader.findClass(URLClassLoader.java:188)

    at java.lang.ClassLoader.loadClass(ClassLoader.java:307)

    at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)

    at java.lang.ClassLoader.loadClass(ClassLoader.java:252)

    at java.lang.ClassLoader.loadClassInternal(ClassLoader.java:320)

    at java.lang.Class.forName0(Native Method)

    at java.lang.Class.forName(Class.java:169)

    at de.espirit.firstspirit.parser.impl.MethodClassForName.eval(MethodClassForName.java:33)

    at de.espirit.firstspirit.parser.impl.DottedExpression.eval(DottedExpression.java:69)

    at de.espirit.firstspirit.parser.impl.CmsSetImpl.print(CmsSetImpl.java:116)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.parser.impl.AbstractPrintable.print(AbstractPrintable.java:79)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.generate.AbstractGenerationContext.print(AbstractGenerationContext.java:1034)

    at de.espirit.firstspirit.generate.Global.print(Global.java:388)

    at Global_print_Body_872.invoke(Unknown Source)

    at de.espirit.firstspirit.parser.eval.Invoker$MethodWrapperImpl.invoke(Invoker.java:944)

    at de.espirit.firstspirit.parser.eval.Invoker.invokeMethod(Invoker.java:465)

    at de.espirit.firstspirit.parser.eval.Invoker.invokeMethod(Invoker.java:397)

    at de.espirit.firstspirit.parser.eval.Invoker.evalMethod(Invoker.java:208)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:199)

    at de.espirit.firstspirit.parser.impl.CmsValueImpl.print(CmsValueImpl.java:69)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.parser.impl.AbstractPrintable.print(AbstractPrintable.java:79)

    at de.espirit.firstspirit.parser.impl.CmsTrimImpl.print(CmsTrimImpl.java:167)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.parser.impl.AbstractPrintable.print(AbstractPrintable.java:79)

    at de.espirit.firstspirit.parser.impl.CmsTrimImpl.print(CmsTrimImpl.java:167)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.parser.impl.AbstractPrintable.print(AbstractPrintable.java:79)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.parser.impl.CmsRenderImpl.print(CmsRenderImpl.java:68)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.parser.impl.AbstractPrintable.print(AbstractPrintable.java:79)

    at de.espirit.firstspirit.parser.EvaluatorImpl.print(EvaluatorImpl.java:445)

    at de.espirit.firstspirit.store.access.sitestore.PageRefImpl.render(PageRefImpl.java:851)

    at de.espirit.firstspirit.store.access.sitestore.PageRefImpl.createContent(PageRefImpl.java:809)

    at de.espirit.firstspirit.generate.SiteProduction.render(SiteProduction.java:179)

    at de.espirit.firstspirit.generate.SiteProduction.render(SiteProduction.java:135)

    at de.espirit.firstspirit.generate.SiteProduction.render(SiteProduction.java:138)

    at de.espirit.firstspirit.generate.SiteProduction.render(SiteProduction.java:138)

    at de.espirit.firstspirit.generate.SiteProduction.start(SiteProduction.java:105)

    at de.espirit.firstspirit.generate.SiteProduction.start(SiteProduction.java:98)

    at de.espirit.firstspirit.server.scheduler.GenerateTaskExecutor.run(GenerateTaskExecutor.java:201)

    at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.executeLocal(ScheduleManagerImpl.java:1971)

    at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.executeLocal(ScheduleManagerImpl.java:1951)

    at de.espirit.firstspirit.server.scheduler.ScheduleManagerImpl$TaskCallable.call(ScheduleManagerImpl.java:1879)

    at de.espirit.firstspirit.server.ExecutionManagerImpl$ExtendedCallable.call(ExecutionManagerImpl.java:505)

    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

    at java.util.concurrent.FutureTask.run(FutureTask.java:138)

    at de.espirit.common.util.BoundedExecutorService$RunnableWrapper.run(BoundedExecutorService.java:414)

    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:441)

    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)

    at java.util.concurrent.FutureTask.run(FutureTask.java:138)

    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886)

    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908)

    at java.lang.Thread.run(Thread.java:619)

    at de.espirit.common.util.SuspendableThread.run(SuspendableThread.java:36)

Diese Klasse TeaserTemplateUtil ist Teil einer Library-Komponente, die dadurch ja per Definition auf dem FirstSpirit-Server und im Java-Client bekannt sein sollte, oder?

<library>
    <name>Teaser Libraries</name>
    <description>Libraries for the teaser module</description>
    <resources>
        <resource name="TeaserModule">lib/teaser-module.jar</resource>
    </resources>

</library>

Jedenfalls kann ich die Methoden dieser Klasse innerhalb eines RenderSkripts prolemlos verwenden. Und diese Renderskripte kommen ja auch bei der Generierung auf dem Server zur Ausführung.

0 Kudos

Über die Methode "class" können keine Modulklassen angesprochen werden. Es existiert dafür ein interner "enhancement request" mit der ID #88553.

Peter

Ahso, ok. Danke für den Hinweis. Das ist gut zu wissen.

Welche alternative Möglichkeit gibt es denn, eine Modul-Klasse bzw. konkret eine Modul-Methode aus dem Ausgabekanal heraus aufzurufen? (außer über ein Renderskript)

0 Kudos
gockel
Crownpeak employee

Welche alternative Möglichkeit gibt es denn, eine Modul-Klasse bzw. konkret eine Modul-Methode aus dem Ausgabekanal heraus aufzurufen? (außer über ein Renderskript)

Keine. Das Renderskript mit Executable ist der alternative Weg.

0 Kudos

Alles klar, dann weiß ich bescheid.

Vielen Dank für die ausführliche Hilfe!

0 Kudos