# [GWT] Relative Pfade auf dem Server



## kirdie (26. Dez 2010)

Ich bin wieder mal am verzweifeln mit GWT, mein derzeitiges Problem ist der Dateizugriff vom Server aus.
Ich habe meine Anwendung unter /home/someuser/projekte/java/meinprojekt/war/meinprojekt-version/WEB-INF/classes.
Jetzt habe ich eine Ressource, sagen wir mal /home/someuser/projekte/java/meinprojekt/war/meinprojekt-version/WEB-INF/classes/myresource.txt" auf die ich gerne zugreifen würde. Jetzt benutze ich "mvn gwt:run" um meine GWT Anwendung im hosted mode zu starten.  Aber da ich das letztendlich auf einem webserver habe, kann ich natürlich nicht den absoluten Pfad benutzen, sondern nur den Relativen. Ich gehe also davon aus, dass ich mit "new File("myresource.txt")" auf die Datei zugreifen kann - geht aber nicht (FileNotFoundException). Wenn ich allerdings auf dem Server "String x = new File(".").getAbsolutePath()" mache, dann bekomme ich zurück " /home/someuser/projekte/java/meinprojekt/" was mich sehr verwundert. Da sich ja die Versionsnummer ändern kann, möchte ich nicht jedesmal einen anderen Pfad einstellen, nur wenn ich eine Datei einlesen möchte und wenn ich am Ende die Applikation auf einem richtigen Server habe, dürfte ich ja sowieso nur alles unterhalb des WEB-INF/classes oder wenigstens des meinprojekt-version-Ordners haben.

Die Frage ist jetzt also, wie ich den Pfad zu meinen ganzen Dateien bekomme, kann mir da jemand helfen? Ich bin ziemlich neu mit GWT aber ich finde zu dieser absoluten Grundlagenfrage irgendwie überhaupt nichts. Ich habe beim googlen etwas von "getServletContext().getContextPath()" gelesen, aber da kommt nur ein Leerstring raus.


----------



## Bierhumpen (26. Dez 2010)

Was willst du überhaupt machen? Mit GWT kannst du eh keine Dateien auf dem Server lesen.


----------



## Tomate_Salat (26. Dez 2010)

@Bierhumpen: hat er doch geschrieben

@kirdie: Eine Lösung (weis nicht wie gut im Web-bereich) wäre:

```
return getClass().getResource("../../../../user.txt").getPath();
```
Die ganzen [c]../[/c] sollten selbsterklärend sein: da liegen ein paar packages dazwischen. Aber ich kann so meine user.txt abrufen.

MFG

Tomate_Salat


----------



## kirdie (27. Dez 2010)

@Tomate_Salat: Also wenn du eine Klasse myClass im Package net.mypackage hast, würdest du in der Klasse myClass getClass().getResource("../../user.txt") machen? Das probier ich mal. Aber gibt es auch eine elegantere Lösung?
@Bierhumpen: Wieso nicht? Auf dem Server läuft doch ganz normales Java, warum soll das keine Dateien lesen können?


----------



## Manuel (27. Dez 2010)

Versuch mal mit getRealPath("/meinPfad...")


----------



## kirdie (27. Dez 2010)

Also getRealPath(".") wenn ich was direkt aus WEB-INF/classes haben will?


----------



## Tomate_Salat (27. Dez 2010)

> getClass().getResource("../../user.txt") machen


ja, mit [c]..[/c] springst du immer eine Ebene zurück. Wie elegant diese Methode ist, keine Ahnung, beschäftige mich gerade selbst neu im Webbereich.



> Also getRealPath(".") wenn ich was direkt aus WEB-INF/classes haben will?


Nein, bei mir geht das auf das war-verzeichnis, aber nicht auf die WEB-INF/classes/... Hier musst du den Pfad halt erweitern. 

```
getServletContext().getRealPath("/WEB-INF/classes/haumich.tod");
```


----------



## Bierhumpen (27. Dez 2010)

kirdie hat gesagt.:


> @Bierhumpen: Wieso nicht? Auf dem Server läuft doch ganz normales Java, warum soll das keine Dateien lesen können?



GWT läuft auf dem Client und zwar als JavaScript...


----------



## maki (27. Dez 2010)

> Jetzt habe ich eine Ressource, sagen wir mal /home/someuser/projekte/java/meinprojekt/war/meinprojekt-version/WEB-INF/classes/myresource.txt" auf die ich gerne zugreifen würde.


Die Ressource als Stream laden wenn sie schon im CP ist, [c]java.io.File[/c] ist im Normalfall zu vermeiden in ServletContainern und vor allem in AppServern.


Smartly load your properties - JavaWorld


----------



## kirdie (27. Dez 2010)

@Maki: Vielen Dank für den Artikel, der hat mir sehr geholfen. Allerdings ist der von 2003, hat sich seitdem etwas geändert?


----------



## Noctarius (27. Dez 2010)

Wie wär es mit ausprobieren? Wenn es nicht geht wäre ein entsprechender Hinweis mit Fehlermeldung reizvoll.


----------



## kirdie (27. Dez 2010)

Also erstmal danke an alle, das Laden der Propertyfiles funktioniert mit getResources.

Jetzt weiß ich aber nicht, wie ich folgenden Code übersetzen soll:


```
public String[] getListOfDataFiles()
{
		File folder = new File("datafiles/");
		if(!folder.exists()) folder.mkdir();
		SortedSet<String> files = new TreeSet<String>(Arrays.<String>asList(folder.list()));
		return files.toArray(new String[0]);
}
```
und 

```
public void safeDataFile(String filename, String data) throws Exception
{
	 try
	 {
		File f = new File("datafiles/"+filename);
		PrintWriter out;
		out = new PrintWriter(f);
		Properties p = new Properties();		
		p.put("data", data);
		p.store(out,"my data file");
		out.close();
	}
	catch (IOException e)
	{
		throw new Exception(e);
	}
}
```
Mit den Streams kann ich ja keine Dateilisten anzeigen oder Dateien erzeugen...
@Noctarius: Mit Ausprobieren merke ich ja nur, ob es überhaupt funktioniert aber nicht, ob das auch immer noch die optimale oder eleganteste Lösung ist.


----------



## kirdie (27. Dez 2010)

Ok, 
	
	
	
	





```
return getServletContext().getRealPath(".")
```
 liefert mir den Pfad "/home/someuser/projekte/java/meinprojekt/war/meinprojekt-version/", was schon mal super ist, 
	
	
	
	





```
getServletContext().getContextPath()
```
 allerdings immer noch nur einen Leerstring. Müsste getContextPath nicht das gleiche zurückgeben wie getRealPath(".")?

P.S.: Was ist denn die richtige Position für meine Ressourcen, unter .../war/meinprojekt-version/WEB-INF/classes oder direkt unter .../war/meinprojekt-version/? Es sind ja Dateien und keine Klassen.


----------



## Noctarius (27. Dez 2010)

Nein der ContextPath ist Web-Relativ, der Real-Path ist im Dateisystem.


----------



## kirdie (27. Dez 2010)

Hm, jetzt geht es auf einmal nicht mehr. Ich hatte den Aufruf von "getServletContext().getRealPath(".")" in einer Methode, die erst später per RPC aufgerufen wurde, wenn ich den Aufruf jedoch im Konstruktor habe, bekomme ich eine Nullpointerexception.
Wird der Context erst später, nach dem Konstruktor, initialisiert? Was kann ich da machen?


```
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService
{
[...]
	final String resourcePath;

	public GreetingServiceImpl()
	{
		resourcePath = getServletContext().getRealPath(".")+"WEB-INF/classes/";
	}
[...]
```
führt zu

```
java.lang.NullPointerException
	at javax.servlet.GenericServlet.getServletContext(GenericServlet.java:160)
	at net.saim.gwt.server.GreetingServiceImpl.(GreetingServiceImpl.java:64)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
[...]
```


----------



## Noctarius (27. Dez 2010)

Theoretisch kann es da noch nicht initialisiert sein, weil es ja irgendwo herkommen muss. Da du es nicht im Constructor als Parameter hast, kann die Superclass es da auch nicht aus dem Constructor holen.

Liegt die Vermutung nahe (und ich meine es auch schon mal gelesen zu haben), dass der ServletContext erst in der init-Methode gesetzt wird. (Glaub das war sogar bei allen Servlets so).


----------



## kirdie (27. Dez 2010)

Vielen Dank! Es ist mir zwar ein Rätsel, warum im Superkonstruktor nicht die Initmethode aufgerufen wird sondern erst später aber so funktioniert es:


```
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService
{
[...]
    String resourcePath = null;

	@Override
	public void init() throws ServletException
	{
		super.init();
		resourcePath = getServletContext().getRealPath(".")+"WEB-INF/classes/";
	}
[...]
```

Blöd ist nur, dass ich jetzt resourcePath nicht mehr als final deklarieren kann aber damit muss ich halt leben.


----------



## Noctarius (27. Dez 2010)

Weil der Lifecycle so aufgebaut ist.

Instanzierung -> Initialisierung -> Ausführung -> Stop


----------



## maki (28. Dez 2010)

Wie gesagt, kein java.io.File verwenden, sondern als Stream laden: : Interface ServletContext)

Der Artikel ist von 2003 und nciht WebApp spezifisch, aber immer noch sehr richtig


----------

