# Tomcat: Packete dynamisch auslesen und Klassen erzeugen



## ThLu (23. Nov 2011)

Hallo liebes Java-Forum,

ich habe einen Tomcat 7 als Applikationsserver laufen auf dem ich mein .war-Verzeichnis deployed habe. Mein Programm hat fünf Schichten:
1. Schicht und 2. Schicht sind nur Datenbank + Zugriff, deswegen habe ich die hier weggelassen.
3. Schicht: Logik
4. Schicht: Logikzugriffsschicht für die Servlets
5. Schicht: Servlets

Ich biete verschiedene Services an, die alle XML oder KML Daten zurückliefern. Die Architektur ist so gedacht auch jeder anders später neue Services implementieren kann, dazu muss er einfach ein eigenes Servlet schreiben, das von meinem TestServlet erbt. Die Klasse TestServlet ergänzt eigentlich die Basis-Servlet Klasse nur um eine Funktion 
	
	
	
	





```
public void getCapability()
```
, die von allen Servlets implementiert sein muss, da ich hierüber Informationen über den Service sammele. 
Ich habe mir das so gedacht, dass wenn der Service AllCapabilititiesGetServlet aufgerufen wird, alle Pakete der 5. Schicht durchlaufen werden und für jedes Servlet die Funktion getCapability() aufgerufen wird. Die Funktion schreibt nämlich jedes mal einen Eintrag in ein Array und dieses Arry liefert mein AllCapabilititesGetServlet als XML-File zurück. 
Durch die Struktur will ich sicher stellen, dass sobald ein neues Servlet von wem auch immer geschrieben wurde und dann die Capabilitites ausgelesen werden sollen, auch die neu angelegten Servlets berücksichtigt werden und direkt in das Array geschrieben werden.

Dazu habe ich folgende relevante Klassen:

5. Schicht: AllCapabiltiitesGetServlet:

```
package de.test.servlets.get;

import java.io.IOException;
import java.io.PrintWriter;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import de.test.get.AllCapabilitiesGet;
import de.test.servlets.help.TestServlet;

/**
 * Servlet implementation class AllCapabilitites
 */
public class AllCapabilititiesGetServlet extends TestServlet {
	private static final long serialVersionUID = 1L;
       
	private AllCapabilitiesGet ref;
	private String answer;
	
    /**
     * @see HttpServlet#HttpServlet()
     */
    public AllCapabilititiesGetServlet() {
        super();
    }
    
    public void init() throws ServletException {
		ref = new de.test.get.AllCapabilitiesGet();
	}

	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.setContentType("application/xml");
		response.setHeader("Content-Disposition", "attachment; filename=AllCapabilities.xml");
		
		answer = ref.getAllCapabilities();
		PrintWriter out = response.getWriter();
		out.println(answer);	
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse response)
	 */
	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

	}

	@Override
	public void getCapability() {
		//Hier steht nichts drin weil dieser Service alle Capabilities liefert
	}

}
```

4. Schicht: AllCapabilititesGet

```
package de.test.get;

import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;

import de.testrest.datalogic.Manager;

@Path("/GET/AllCapabilities")
public class AllCapabilitiesGet {

	@GET
	@Produces(MediaType.TEXT_XML)
	public String getAllCapabilities(){
		String testString = Manager.getInstance().getAllCapabilities();
		return testString;
	}
	
}
```


3. Schicht: Manager:

```
package de.testrest.datalogic;

import java.io.File;

import java.io.StringWriter;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.sql.*;
import java.util.ArrayList;
import java.util.Set;

import javax.servlet.ServletContext;

import org.jdom.*;
import org.jdom.output.*;

import sun.misc.Launcher;

import de.micromata.opengis.kml.v_2_2_0.*;

/**
 * Diese Klasse ist die Basislogik und stellt somit die Basisfunktionalitäten der Services zur Verfügung
 *
 */
public class Manager {

...
	
	//verwaltet alle Capabilities (Capabilitites ist eine eigene Klasse)
	ArrayList<Capability> allCapabilities = new ArrayList<Capability>();
	
	/**
	 * Liefert alle Capabilitites zurück (nutzt Java Reflection)
	 * @return String im XML-Format mit allen Capabilitites
	 */	
	public String getAllCapabilities(){
		
		//ArrayList für alle vorhandenen Klassen
		ArrayList<String> allClasses = new ArrayList<String>();
		
		//Hilfs-ArrayListen die jeweils alle Klassen der vier aufgezeigten Pakete enthalten
		ArrayList<String> getAL = findClassNames("de.test.servlets.get");
		ArrayList<String> delAL = findClassNames("de.test.servlets.delete");
		ArrayList<String> putAL = findClassNames("de.test.servlets.put");
		ArrayList<String> postAL = findClassNames("de.test.servlets.post");

		//Jede ArrayList wird mit ihrer Länge durchlaufen und allClasses hinzugefügt
		//Danach hat man nur noch die Main-ArrayList die alle vorhanden Klassennamen enthält
		//Den Umweg musste man gehen, da die Pakete unterschiedliche Länge haben können
		
		for (int i = 0; i<getAL.size();i++){
			allClasses.add("de.test.servlets.get."+getAL.get(i));
		}
		for (int i = 0; i<delAL.size();i++){
			allClasses.add("de.test.servlets.delete."+delAL.get(i));
		}
		for (int i = 0; i<putAL.size();i++){
			allClasses.add("de.test.servlets.put."+putAL.get(i));
		}
		for (int i = 0; i<postAL.size();i++){
			allClasses.add("de.test.servlets.post."+postAL.get(i));
		}
		
		//Für jeden Eintrag in allClasses...
		for(int i = 0;i<allClasses.size();i++){
			
			//...wird sich der Name geholt...
			String className = (String) allClasses.get(i);
			
			//..dann wird eine Class deklariert...
			@SuppressWarnings("rawtypes")
			Class cls;
			
			try {
				//...und diese Klasse wird initialisiert und instanziiert mit dem entsprechenden Name...
				cls = Class.forName(className);
				Object obj = cls.newInstance();
				
				//...dann werden alle Methoden dieser Klasse durchlaufen...
				for(java.lang.reflect.Method method : obj.getClass().getMethods()) {
					//...und sobald diese Methode getCapabilitiy heißt
					if(method.getName().equals("getCapability")){
						//wird diese angestoßen (jedes Servlet muss diese abstrakte Funktion getCapabilitis implementieren
						method.invoke(obj,null);
					}
				}
				
			} catch (ClassNotFoundException e) {
				e.printStackTrace();
			} catch (InstantiationException e) {
				e.printStackTrace();
			} catch (IllegalAccessException e) {
				e.printStackTrace();
			} catch (IllegalArgumentException e) {
				e.printStackTrace();
			} catch (InvocationTargetException e) {
				e.printStackTrace();
			}
		}
		return generateCapabilitiesXML();
	}
	
	/**
	 * Hilfsfunktion für getAllCapabilitis
	 * Findet zu einem gegebenen Paketname die einzelnen Klassennamen
	 * @return ArrayList<String> alle Klassennamen des jeweiligen Pakets
	 */	
	 public static ArrayList<String> findClassNames(String pckgname) {
	     
		 //ArrayList für alle Klassennamen wird erzeugt
		 ArrayList<String> classnames = new ArrayList<String>();
		 
		 	//Falls der package-Name nicht mit einem "/" beginnt wird eins davor gesetzt
	        String name = new String(pckgname);
	        if (!name.startsWith("/")) {
	            name = "/" + name;
	        }        
	       
	        //danach erden alle "." durch "/" ersetzt
	        name = name.replace('.','/');
	        
	        // Es wird sich ein File-Objekt erzeugt
	       URL url = Launcher.class.getResource(name);
	        
	        //TODO: Die Ressource ist auf dem Server leer!!! lokal nicht!
	        File directory = new File(url.getFile());
	        
	        //Falls es ein directory gibt...
	        if (directory.exists()) {
	            //...hole den Inhalt...
	            String [] files = directory.list();
	            for (int i=0;i<files.length;i++) {
	                //...nimm nur die Inhalt mit .class am Ende...
	                if (files[i].endsWith(".class")) {
	                    //...und ziehe die letzten sechs Zeichen ab (wegen .class)
	                    String classname = files[i].substring(0,files[i].length()-6);
	                    //Falls der Klassenname ungleich AllCapabilititesGetServlet ist, füge den Name der ArrayList classnames hinzu
	                    if(!(classname.equals("AllCapabilititiesGetServlet")))
	                    	classnames.add(classname);
	                }
	            }
	        }
	        //gibt die ArrayList mit allen Klassennamen zurück
	        return classnames;
	    }
	
}
```

Das Problem ist jetzt, dass lokal alles wunderbar funktioniert und ich die Packete auslesen, die Klassen erzeugen und die Funktionen aufrufen kann. Auf dem Server allerdings die URL in meiner Manager - findClassNames immer leer ist (Zeile 126). Das liegt daran das der Pfad irgendwie nicht stimmt. Der Pfad ist WEB-INF/classes/de/test/XXX (das XXX steht für die jeweiligen Klassen). Ich habe schon versucht über ServletContext getResource und getRealPath zu arbeiten, jedoch ohne Erfolg. Ich sitze schon mehrere Tage an diesem einen Problem. 

Hat von euch jemand eine Idee wie ich an den Pfad komme und die dynamisch Klassen auslesen kann?
Ich wäre über jede Art von Tipp dankbar.

Viele Grüße,
Thomas.


----------



## Chris_K (25. Nov 2011)

Wenn ich das richtig sehe, verwendest Du Java Reflection. Das scheint auch das Problem zu sein, weil das auf dem Tomcat nicht funktioniert.


----------



## ThLu (27. Nov 2011)

Hey Chris K,

Danke schön für die Antwort.
Mist, dann kann ich also mein gesamtes Programm umschreiben? Ich dachte es wäre irgendwie möglich dynamisch Pakete von einem Applikationsserver auszulesen. So habe ich aber immerhin wieder was dazu gelernt.

Viele Grüße,
Thomas.


----------



## ThLu (27. Nov 2011)

Hallo zusammen,

es geht doch!

Habe im Internet folgendes gefunden was wunderbar funktioniert:
URL url = Thread.currentThread().getContextClassLoader().getResource(name);

Viele Grüße,
Thomas.


----------

