SebastianStieme
Returning Observer

Data Access Plugin Zugriff auf externe System z. B. via REST

Jump to solution

Hallo,

ich/wir sind gerade dabei ein Data Access Plugin zu entwickeln. Dieses soll Daten via REST von einem Server X abfragen und dann eben in FirstSpirit für den Redakteur, aber dann natürlich auch die Generierung spülen.

Das Problem was ich nun aber habe, ist dass das DAP die Daten vom Client aus abrufen will. Der Plan wäre ja aber das der REST Call vom FirstSpirit-Server aus geht.

Der Server X, also das externe System ist nämlich nur vom FirstSpirit-Server aus erreichbar.

Wie stelle ich das am besten an?

Das ist DAP ist und bleibt vermutlich immer ein Client-Modul? Das geht vermutlich auch nicht anders?

Muss ich jetzt irgendwie noch einen zusätzlichen Server-Service schreiben? Sprich dann wäre die Kommunikation vom Server X an den Server-Service an das DAP?

Und wenn ja, wie mache ich das grob?

Baue ich ein komplett separates FirstSpirit Modul für den Server-Service? Oder packe ich alles zusammen und muss dann "nur" die module.xml erweitern?

Uns fehlt es hier leider so ein wenig an der Grundidee, wie das eigentlich funktionieren soll.

Hier ggf. noch ein paar Infos zum aktuellen Stand:

in der DataStream Klasse frage ich dann via

HttpRequest request = HttpRequest.newBuilder()

.uri(URI.create("http://localhost:8081/api/agendas"))

.GET()

.build();

die externe Schnittstelle ab.

vielen Dank und Gruß

Sebastian

1 Solution

Accepted Solutions
bIT_sosswald
Returning Responder

Hallo Sebastian,

nach einem kurzen Blick in die Module-XML sieht es so aus, als ob du nur eine Library bzw. eine Pulic-Komponente hast. Diese werden um es plakativ auszudrücken "da ausgeführt wo sie aufgerufen werden". - Das geht aus der Doku IMHO nicht wirklich bzw. zumindest nicht klar hervor. Ich musste das auch auf die harte Tour lernen und habe die gleiche Erfahrung gemacht wie du.

Die einfachste Lösung ist vermutlich, dass du die Logik der externen Anbindung in eine Service-Komponente auslagerst. Das DAP würde dann den FS-Service über einen entsprechenden Broker holen und von diesem Daten abfragen. Der Service wiederum läuft eben als "zentraler Service" auf dem FS-Server, führt von dort den Zugriff auf das externe System durch und liefert die Daten an das DAP, welches im z.B. im Client läuft, zurück.

So löse ich zumindest immer meine Anforderungen, wenn ich möchte, dass eine Operation zwingend vom FS-Server und nicht aus dem Client ausgeführt wird.

Um auf deine Fragen einzugehen:

  • Ja, der Client hat ja die Hoheit über die Aktionen des Users z.B. was der User wann in das Suchfeld des DAP eingibt etc. und muss somit steuern wann das DAP ANfragen startet und wie die Ergebnisse im CLient dargestellt werden. - Von daher macht es durchaus Sinn, dass das DAP im Client läuft.
  • Ja, ich würde einen separaten Service schreiben, der die Kommunikation mit dem Drittsystem übernimmt.
  • Ich würde dazu KEIN eigenes Modul schreiben, sondern den Service mit in dein DAP-Modul packen. (Gehört fachlich ja zusammen.)
  • Ja, wenn du den Service in deinem Modul hast und die module.xml entsprechend erweiterst wird der Service direkt beim Installieren des Moduls gestartet und du kannst ihn in deinem DAP verwenden.

Beste Grüße

Sandro

View solution in original post

0 Kudos
6 Replies
bIT_sosswald
Returning Responder

Hallo Sebastian,

nach einem kurzen Blick in die Module-XML sieht es so aus, als ob du nur eine Library bzw. eine Pulic-Komponente hast. Diese werden um es plakativ auszudrücken "da ausgeführt wo sie aufgerufen werden". - Das geht aus der Doku IMHO nicht wirklich bzw. zumindest nicht klar hervor. Ich musste das auch auf die harte Tour lernen und habe die gleiche Erfahrung gemacht wie du.

Die einfachste Lösung ist vermutlich, dass du die Logik der externen Anbindung in eine Service-Komponente auslagerst. Das DAP würde dann den FS-Service über einen entsprechenden Broker holen und von diesem Daten abfragen. Der Service wiederum läuft eben als "zentraler Service" auf dem FS-Server, führt von dort den Zugriff auf das externe System durch und liefert die Daten an das DAP, welches im z.B. im Client läuft, zurück.

So löse ich zumindest immer meine Anforderungen, wenn ich möchte, dass eine Operation zwingend vom FS-Server und nicht aus dem Client ausgeführt wird.

Um auf deine Fragen einzugehen:

  • Ja, der Client hat ja die Hoheit über die Aktionen des Users z.B. was der User wann in das Suchfeld des DAP eingibt etc. und muss somit steuern wann das DAP ANfragen startet und wie die Ergebnisse im CLient dargestellt werden. - Von daher macht es durchaus Sinn, dass das DAP im Client läuft.
  • Ja, ich würde einen separaten Service schreiben, der die Kommunikation mit dem Drittsystem übernimmt.
  • Ich würde dazu KEIN eigenes Modul schreiben, sondern den Service mit in dein DAP-Modul packen. (Gehört fachlich ja zusammen.)
  • Ja, wenn du den Service in deinem Modul hast und die module.xml entsprechend erweiterst wird der Service direkt beim Installieren des Moduls gestartet und du kannst ihn in deinem DAP verwenden.

Beste Grüße

Sandro

0 Kudos

Danke für die Antwort.

Ja, so ähnlich versuche ich es aktuell auch schon zu lösen. Habe nun aber das nächste Problem, dass ich eine ClassCastException erhalte, wenn ich aus dem Client versuche, den ServerService aufzurufen.

Ich versuche mal so viele Infos wie möglich hier darzustellen. Bzw. zu schildern wie ich aktuell vorgehe.

Ich habe zum einen den ExternalAgendaService. Das soll dann der Service sein, der auf dem FS Server als Dienst läuft und dann die Kommunikation zum externen REST-Server übernimmt. Aktuell wäre ich mit einem "Hello World" aber schon mal zufrieden ; ) Sie Screenshot im Anhang scheint der auch als Dienst auf dem Server zu laufen.

Das Problem, welches ich nun aber habe ist, wie ich den Service aus meinem DAP ansprechen kann.

Das ExternalAgendaDataAccessPlugin ist aktuell ein separates Modul. Ich habe die JAR vom ExternalAgendaService hier in den lib Ordner kopiert, so dass ich das dann via mvn dependency im Modul nutzen und bauen kann. Das kopieren dieser JAR in die FSM funktioniert noch nicht, das mach ich aktuell händisch. Heißt also ich kopiere aktuell die ExternalAgendaService.jar händisch in die FSM vom ExternalAgendaDataAccessPlugin.

Dann versuche ich im ExternalAgendaDataAccessPlugin den Service wie folgt anzusprechen:

ExternalAgendaServiceProxy proxy = (ExternalAgendaServiceProxy) context.requireSpecialist(ServicesBroker.TYPE).getService(ExternalAgendaService.class);

erhalte dann aber leider die folgende Fehlermeldung im FS SiteArchitect 😕

WARN  29.11.2021 09:59:02.428 (de.espirit.firstspirit.server.io.AbstractServiceLocator): incompatible class loaders? CachingRemoteModuleClassLoader-120{mode=ISOLATED, module=LMWL FS Solr External Agenda Data Access Plugin, parent=ClientCombinedClassLoader-105{Global Isolated, 20 classloaders, parent=jdk.internal.loader.ClassLoaders$AppClassLoader@2145433b}} / CachingRemoteModuleClassLoader-146{mode=LEGACY, module=LMWL FS Solr External Agenda Service, parent=ClientCombinedClassLoader-107{Global Legacy, 20 classloaders, parent=UnifyingClassLoader-106{3 classLoaders, parent=jdk.internal.loader.ClassLoaders$AppClassLoader@2145433b}}}

ERROR 29.11.2021 09:59:02.432 (de.espirit.common.base.control.AbstractActionProcessor): [JC_Main]Handle failed [ActionEvent[AE@pluginsAccessible,null]@792732213]!

FSVersion=5.2.210809.79900#5284;JDK=11.0.11 64bit AdoptOpenJDK;OS=Windows 10 10.0 amd64;Date=29.11.2021 09:59:02 (I)

java.lang.ClassCastException: Cannot cast de.lmwl.ExternalAgendaServiceProxy to de.lmwl.ExternalAgendaService

at java.base/java.lang.Class.cast(Unknown Source)

at de.espirit.firstspirit.server.io.AbstractServiceLocator.getService(AbstractServiceLocator.java:106)

at de.espirit.firstspirit.server.io.AbstractServerConnection.getService(AbstractServerConnection.java:623)

at de.espirit.firstspirit.client.io.ProjectConnection.getService(ProjectConnection.java:101)

at de.espirit.firstspirit.agency.ServicesBrokerImpl.getService(ServicesBrokerImpl.java:26)

at de.lmwl.ExternalAgendaDataAccessPlugin.setUp(ExternalAgendaDataAccessPlugin.java:67)

at de.espirit.firstspirit.client.plugin.ReportPluginAgentImpl.setUpAndAppendIfTrusted(ReportPluginAgentImpl.java:64)

at de.espirit.firstspirit.client.plugin.ReportPluginAgentImpl.getReportPlugins(ReportPluginAgentImpl.java:53)

at de.espirit.firstspirit.client.ClientFrame.restoreOrganizeNavigationContext(ClientFrame.java:1126)

at de.espirit.firstspirit.client.ClientFrame.getHandle(ClientFrame.java:965)

at jdk.internal.reflect.GeneratedMethodAccessor26.invoke(Unknown Source)

at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)

at java.base/java.lang.reflect.Method.invoke(Unknown Source)

at de.espirit.common.gui.RunsInEDTProxyFactory$RunsInEDTInvocationHandler.invoke(RunsInEDTProxyFactory.java:143)

at com.sun.proxy.$Proxy4.getHandle(Unknown Source)

at de.espirit.common.base.control.AbstractActionProcessor$ActionProcessDelegate.handle(AbstractActionProcessor.java:1100)

at de.espirit.common.base.control.AbstractActionProcessor$AbstractActionProcess.handle(AbstractActionProcessor.java:1284)

at de.espirit.common.base.control.AbstractActionProcessor$InnerActionProcess.handle(AbstractActionProcessor.java:1576)

at de.espirit.common.base.control.AbstractActionProcessor$InnerActionProcess$1.onGrant(AbstractActionProcessor.java:1559)

at de.espirit.common.base.control.AbstractActionProcessor$ActionProcessDelegate.grant(AbstractActionProcessor.java:957)

at de.espirit.common.base.control.AbstractActionProcessor$AbstractActionProcess.grant(AbstractActionProcessor.java:1279)

at de.espirit.common.base.control.AbstractActionProcessor$InnerActionProcess.grant(AbstractActionProcessor.java:1556)

at de.espirit.common.base.control.AbstractActionProcessor$InnerActionProcess.start(AbstractActionProcessor.java:1551)

at de.espirit.common.base.control.AbstractActionProcessor.doProcess(AbstractActionProcessor.java:436)

at de.espirit.common.base.control.AbstractActionProcessor$2.execute(AbstractActionProcessor.java:589)

at de.espirit.common.util.ExecutorScheduler$ExecuteCommand.run(ExecutorScheduler.java:123)

at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)

at java.base/java.util.concurrent.FutureTask.run(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)

at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)

at java.base/java.lang.Thread.run(Unknown Source)

Hat jemand eine Idee was ich da wohl falsch mache?

Danke und Gruß

Sebastian

-- Update --

ich hab ja jetzt nochmal gelesen "

  • Ich würde dazu KEIN eigenes Modul schreiben, sondern den Service mit in dein DAP-Modul packen. (Gehört fachlich ja zusammen.)

"

Das werde ich dann jetzt mal ausprobieren : ) - wäre ja eh viel besser

0 Kudos

Hi Sebastian,

ganz dumme Frage: Nach der Modulinstallation den FS-Server neu gestartet?

Solche ClassCast-Exceptions kommen / kamen zumindest früher öfters nach einer Modulinstallation. Aber da dann eher mit "java.lang.ClassCastException: Cannot cast com.sun.proxy.$Proxy55 to com..." also ohne konkreten Klassennamen beim Proxy.

In die Anhänge habe ich jetzt mal noch nicht geschaut. 😉

Beste Grüße

Sandro

0 Kudos

ja hab ich. Das hatte ich auch schon mehrfach hier im Forum gelesen.

0 Kudos

Nun hab ich es.

Vielen Dank für die Hilfe. Der Trick war also beides in ein Maven-Projekt zu bauen. Was am Ende sowieso viel besser für uns ist.

Hi Sebastian,

freut mich, dass ich helfen konnte.

Klingt danach, dass da evtl. der Isolated-Mode reingegrätscht hat und der Service daher nicht im anderen Modul erreichbar war oder etwas ähnliches.

Super, dass es jetzt klapp! Viel Spaß beim Daten von extern laden.  

Grüße
Sandro

0 Kudos