# Erreichbarkeit des ServletContextes



## oetzi (2. Aug 2012)

Hallo zusammen,

komme ich aus einer Nicht-Servlet also z. B. irgendeiner Worker Klasse an den ServletContext ran?
Oder bin ich gezwungen diesen immer aus dem aufrufendem Servlet zu übergeben?

Gruß
oetzi


----------



## SlaterB (2. Aug 2012)

eine fertige Unterstützung gibt es nicht,
aber jeder Programmablauf ist an einen Thread gebunden,
du könntest also Objekte irgendwo in einer statischen Map zum Thread als Key ablegen und wieder abfragen


----------



## mvitz (2. Aug 2012)

Dafür gäbe es dann (wenn ich die Antwort von SlaterB richtig verstanden habe), als "fertige" Lösung ThreadLocal


----------



## maki (2. Aug 2012)

Solche Servletspezifischen Dinge am besten komplett von nicht-Servlet Klassen fernhalten, koppelt sehr stark und macht testen unmöglich.


----------



## nillehammer (2. Aug 2012)

maki hat gesagt.:
			
		

> Solche Servletspezifischen Dinge am besten komplett von nicht-Servlet Klassen fernhalten, koppelt sehr stark und macht testen unmöglich.


Absolut richtig! Überlege, was genau Du aus dem ServletContext in Deinem Nicht-Servlet brauchst und übergib genau das bei Aufruf der entspr. Methode.


----------



## oetzi (2. Aug 2012)

mhh, es geht um Informationen, die anwendungsübergreifend für alle Aufrufe (und alle User) gleich sind. Es handelt sich um ein Spiel, wo (vielleicht eher untypisch) Daten von anderen Nutzern mit berücksichtigt werden müssen.
Da habe ich schon verschiedene Ansätze ausprobiert, aber mit allen hatte ich früher oder später meine Probleme. 

für simple read-only Informationen könnte man ja statische Klassen bzw. Methoden verwenden. 
Vorteil: Ich komme von überall (auch nicht Servlets) dran.
Nutze ich allerdings statische Methoden in Kombination mit übergebenen Objekten, mit denen irgendwie weitergearbeitet werden sollte, kam ich irgendwann immer zu dem Problem, dass keine statische Methode auf nicht-statische Methoden nicht zugreifen können (oder ähnliches). 
Darum habe ich irgendwann versucht den ServletKontext zu nutzen, um statische Methoden gar nicht mehr zu nutzen. Da habe ich jetzt aber das oben beschriebene Problem, dass ich nicht von überall dran komme...

Vielleicht stelle ich die Frage mal allgemeiner:
Wie geht man besten vor um Informationen, die immer und von überall abrufbar sein sollen, vorzuhalten?
Dabei wäre es wichtig, dass ich auch aus Nicht-Servlet Klassen dran komme. 
Schließlich möchte ich ja meine Anwendung so strukturieren, dass nicht alles in einem Servlet bearbeitet werden muss. Ich habe aktuell halt "Service"/"Worker" Klassen, die von mehreren und unterschiedlichen Servlets genutzt werden.

Das sind übrigens größtenteils Daten, die bei jedem Request benötigt werden, so dass ich nicht einfach alles in die Datenbank schreiben möchte.


----------



## nillehammer (2. Aug 2012)

Schreibe Dir eigene Daten-Klasse (oder besser ein Interface plus Implementierung), die alle zum Processing benötigten Daten inkl. Zugriffsmethoden enthält. Reiche eine Instanz dieser Klasse an die processing-Methode (oder wie sie auch immer heißt) des Workers weiter. Durch diese Klasse als Informationsspeicher kapselst Du den Worker von der Web-Schicht weg. Du könntest ihn so auch ohne Webanwendung mit Testdaten aufrufen.

Instanzen der Daten-Klasse kannst Du durchaus im Request-, Session- oder Application-Scope ablegen und von dort holen. Du kannst sie aber auch aus einer Datenbank oder einem File laden oder statisch im Code erzeugen. Das Wichtige ist, dass Dein Worker von dem ganzen Hintergrundkrams und woher die Daten kommen, nichts mitbekommt. Er bekommt einfach die benötigten Daten in der benötigten Form und verarbeitet diese.


----------



## freez (2. Aug 2012)

oetzi hat gesagt.:


> Schließlich möchte ich ja meine Anwendung so strukturieren, dass nicht alles in einem Servlet bearbeitet werden muss. Ich habe aktuell halt "Service"/"Worker" Klassen, die von mehreren und unterschiedlichen Servlets genutzt werden.
> 
> Das sind übrigens größtenteils Daten, die bei jedem Request benötigt werden, so dass ich nicht einfach alles in die Datenbank schreiben möchte.



Wenn diese Daten in den Servlets vorhanden sind und deine Service / Worker Klassen von den Servlets aufgerufen werden, dann kannst du doch die Daten deinen Worker Instanzen übergeben ... oder?

Edit 16:21Uhr: Ich schließe mich nachträglich meinem Vorredner an


----------



## oetzi (2. Aug 2012)

nillehammer hat gesagt.:


> Instanzen der Daten-Klasse kannst Du durchaus im Request-, Session- oder Application-Scope ablegen und von dort holen.


Genau um so was in der Art ging es mir ursprünglich. 
Komme ich denn irgendwie an solch eine Datenklasse, die im Application-Scope (ServletContext) liegt außerhalb eines Servlets ran?
Das wäre dann wohl der einfachste und sauberste Weg.



> Das Wichtige ist, dass Dein Worker von dem ganzen Hintergrundkrams und woher die Daten kommen, nichts mitbekommt. Er bekommt einfach die benötigten Daten in der benötigten Form und verarbeitet diese.


Jep, ich probiere die Schnittstellen zum Worker/Service so schlank und übersichtlich wie möglich zu halten. Darum wäre es mir am liebsten, wenn ich die übergreifenden Daten aus dem ApplicationScope ziehen könnte und nicht bei jedem Aufruf übergeben müsste



> Wenn diese Daten in den Servlets vorhanden sind und deine Service / Worker Klassen von den Servlets aufgerufen werden, dann kannst du doch die Daten deinen Worker Instanzen übergeben ... oder?


Klar, das geht theoretisch, das würde aber bedeuten, dass ich bei jedem der vielen Methodenaufrufe  
1. im Servlet alle benötigten Daten zusammen sammeln muss und
2. diese alle an Worker/Service Klasse übergeben muss

Wie grad schon oben beschrieben, wäre es deutlich übersichtlicher und einfacher, wenn das "Daten zusammen sammeln" komplett im Worker/Service passieren könnte (aus dem ServletContext) und ich wirklich nur die individuellen Daten übergeben müsste.


----------



## nillehammer (2. Aug 2012)

> Klar, das geht theoretisch, das würde aber bedeuten, dass ich bei jedem der vielen Methodenaufrufe
> 1. im Servlet alle benötigten Daten zusammen sammeln muss und
> 2. diese alle an Worker/Service Klasse übergeben muss


Und? Ich finde es keinen schlechten Stil, die Daten genau dort und in dem Moment zu sammeln, in dem man sie wirklich braucht. Und wirklich Arbeit ist das auch nicht, es reduziert sich doch auf einen getAttribute-Aufruf auf dem ServletContext.


----------



## maki (2. Aug 2012)

Schliesse mich meinen Vorrednern an.

Man braucht absolut kein static in so einem Falle, das zeigt eigentlich dass du Lücken hast was die Grundlagen betreffen.

Irgendwo musst du ja sowas wie ein Domänenmodell oder zumindest ein Datenmodell haben, nur mit Servlets und Strings wird das nix.


----------



## nillehammer (2. Aug 2012)

Oder ist das mit dem Domänenmodell (also bspw. Klasse Player für alle eingeloggten Spieler) klar? Und dass man in Request-, Session- und ApplicationScope auch solche Objekte oder sogar Listen, Sets, Maps solcher Objekte ablegen kann auch?

Und worum es eigentlich geht, ist eine Art Zugriffs-Schicht auf die Daten? Das wäre gut, es zu machen. Definiere Dir Interfaces für Deine Services. Schreibe Dir Implementierungen dieser. Wenn ein Service die Dienste eines anderen braucht, schreibe einen Konstruktor, der das entspr. Service-Interface als Parameter entgegennimmt und in einer privaten finalen Instanzvariablen speichert.

Wie kriegst Du jetzt Instanzen dieser Services zu fassen? Ein Standardweg, dies zu tun ist Dependency Injection. Da Du eh schon auf Servlets unterwegs bist, würde ich zu JSF 2.0. raten. Da kann man mit Annotationen viele Services zusammenstöpseln und in diverse Stellen injizieren. Ein anderer Weg, wäre, einen ServletContext-Listener zu schreiben und in dessen contextInitialized-Methode das alles selbst aufzubauen.


----------



## oetzi (3. Aug 2012)

nillehammer hat gesagt.:


> Und? Ich finde es keinen schlechten Stil, die Daten genau dort und in dem Moment zu sammeln, in dem man sie wirklich braucht. Und wirklich Arbeit ist das auch nicht, es reduziert sich doch auf einen getAttribute-Aufruf auf dem ServletContext.



Naja, das mag jetzt kein total schlechter Stil sein, aber Vorteile sehe ich keine. 
Im Gegensatz dazu würde der gleiche get Aufruf im worker zu einer schlankeren Schnittstelle führen, was immerhin der Übersichtlichkeit und Vereinfachung dienen würde.

Zu Anfang habt ihr ja allerdings schon gesagt, dass ich vom worker aus nicht an den ServletContext dran komme. Somit scheint das ja leider gar keine Option zu sein.




> Man braucht absolut kein static in so einem Falle



Da ich mit static bisher wenig rumgespielt habe, mag ich da noch nicht ganz sattelfest sein.
Ich habe beispielsweise einige Tabellen, die konstante Werte für verschiedene Dinge enthalten (Item-Informationen, Skill-Informationen, etc.). Diese lese ich aktuell beim Start des Server einmalig aus der Datenbank aus und speichere sie in einer statischen Liste, die ich über statische Methoden abfrage. 
Das fand ich ganz praktisch und das meinte ich auch mit der "read-only Informationen".
Spricht hier was gegen die static Nutzung?



> Oder ist das mit dem Domänenmodell (also bspw. Klasse Player für alle eingeloggten Spieler) klar? Und dass man in Request-, Session- und ApplicationScope auch solche Objekte oder sogar Listen, Sets, Maps solcher Objekte ablegen kann auch?



Den Begriff Domänenmodell habe ich zwar noch nicht gehört, aber vom Beispiel her würde ich sagen: ja 
Auch das man in den verschiedenen Scopes Daten speichern kann ist bekannt (Mit ApplicationScope meinst du den ServletContext, oder?). 



> Und worum es eigentlich geht, ist eine Art Zugriffs-Schicht auf die Daten? Das wäre gut, es zu machen. Definiere Dir Interfaces für Deine Services. Schreibe Dir Implementierungen dieser. Wenn ein Service die Dienste eines anderen braucht, schreibe einen Konstruktor, der das entspr. Service-Interface als Parameter entgegennimmt und in einer privaten finalen Instanzvariablen speichert.
> 
> Wie kriegst Du jetzt Instanzen dieser Services zu fassen? Ein Standardweg, dies zu tun ist Dependency Injection. Da Du eh schon auf Servlets unterwegs bist, würde ich zu JSF 2.0. raten. Da kann man mit Annotationen viele Services zusammenstöpseln und in diverse Stellen injizieren. Ein anderer Weg, wäre, einen ServletContext-Listener zu schreiben und in dessen contextInitialized-Methode das alles selbst aufzubauen.



Dieser Weg hört sich sehr interessant an!
Über Dependency Injection die jeweiligen Services zu holen wäre ja noch einfacher, als sich die Sachen immer aus dem ServletContext zu holen. 
Habe bis jetzt nur in einer Spring Schulung vor einigen Jahren mal Berührungspunkte mit DI gehabt, aber selber noch nie genutzt. 

Wie wäre dann der grobe Ablauf?
Die Service Klasse würde einmalig initialisiert und dem DI Framework zur Verfügung gestellt. Dieses injiziert die dann jeweils über z. B. Annotationen wie du beschrieben hast. 
Hört sich noch übersichtlicher an  und wäre ein guter Grund sich in die Thematik einzuarbeiten!
Ich nutzte das ganze Projekt sowieso größtenteils als "selbstständige Fortbildungsmaßnahme". 

Stolper grad nur über den Vorschlag JSF zu nutzen. 
wiki sagt dazu "JavaServer Faces (kurz: JSF) ist ein Framework-Standard zur Entwicklung von grafischen Benutzeroberflächen für Webapplikationen." 
Mir sagte JSF auch mehr aus dem Frontend Bereich etwas. Wie passt das die DI rein?


----------



## freez (3. Aug 2012)

oetzi hat gesagt.:


> Stolper grad nur über den Vorschlag JSF zu nutzen.
> wiki sagt dazu "JavaServer Faces (kurz: JSF) ist ein Framework-Standard zur Entwicklung von grafischen Benutzeroberflächen für Webapplikationen."
> Mir sagte JSF auch mehr aus dem Frontend Bereich etwas. Wie passt das die DI rein?



Oh, hätte ich das gewusst, hätte ich dir gleich den Vorschlag gemacht. Managed Beans aus Spring (mit DI) und als Frontend JSF. Aber von "nur Servlets" direkt auf "JSF und Spring" zu springen ist schon etwas Lernarbeit.

Das wunderbare ist daran, dass du in JSF lediglich das Aussehen definierst und "Verknüpfungen" zu den Managed Beans aus Spring hast. Hier kannst du mit einem Singleton Bean aus Spring dein Problem mit "Daten für alle User" lösen. Spring unterstützt dich schon von Haus aus mit den Service Klassen über Annotationen und du kannst eigentlich in jede von Spring verwaltete Klasse beliebige Beans (singleton, session, request) und Services injizieren.


----------



## nillehammer (3. Aug 2012)

oetzi hat gesagt.:
			
		

> Habe bis jetzt nur in einer Spring Schulung vor einigen Jahren mal Berührungspunkte mit DI gehabt, aber selber noch nie genutzt.


Spring ist auch gut. Oder Google Guice oder Tapestry IOC. Letztlich ist es egal. Wenn Du schon was kennst, mach damit weiter. Spring ist ja auch recht verbreitet. Da eignet man sich kein unnötiges Wissen an. Mit JSF war nur ein Vorschlag. Muss auch gleich voraus schicken, dass ich selbst JSF nur am Rande kenne.


> Stolper grad nur über den Vorschlag JSF zu nutzen.
> wiki sagt dazu "JavaServer Faces (kurz: JSF) ist ein Framework-Standard zur Entwicklung von grafischen Benutzeroberflächen für Webapplikationen."
> Mir sagte JSF auch mehr aus dem Frontend Bereich etwas. Wie passt das die DI rein?


Im Hintergrund der JSF-Views arbeiten normale Java-Klassen, Managed-Beans etc. Ich meine, gerade bei den Managed-Beans gäbe es die Möglichkeit von DI mit Annotationen.


----------



## oetzi (3. Aug 2012)

okay, dank euch vielmals für die vielen und schnellen Antworten und Tipps!!

Das wird dann ein ganz schön großes Re-engineering, aber okay. So ist das halt beim lernen 

Der Vollständigkeit halber: "Nur Servlets" setze ich gar nicht ein, sondern nutze schon struts2 als Framework. Wollte die Erklärungen aber nicht unnötig länger und komplexer machen und habe mich auf das Kernproblem fokussiert.

okay, ab Montag habe ich Urlaub, dann habe ich genug Zeit mich in die Sachen einzulesen 

Schönen Gruß
oetzi


----------

