# Jars nachträglich laden (aus den WEB-INF/lib Ordner)



## SebiB90 (21. Okt 2009)

Hi,

ich habe folgendes Szenario. Ich habe eine Webanwendung bei der ich eine Libary benutze, die sich beim Starten der Anwendung selbst entpackt und auch weitere Jar Dateien in den WEB-INF/lib Ordner extrahiert, die es brauch. Das Problem ist, dass Tomcat nur beim Starten der Anwendung die Libs aus den WEB-INF/lib Ordner lädt. Die nachträglich extrahierten Libs werden nicht benutzt und daher kommt es zu Exceptions.

Daher frage ich mich jetzt, wie kann ich diese Jars nachträglich laden? Einen neuen URLClassloader erstellen hilft nicht so richtig. Weil ich nicht selbst die Classdateien dann per Reflexion laden will, die Klassen sollen einfach verfügbar seien. So als ob sie bereits beim Start drin gewesen wären. Habt ihr eine Idee, wie man sowas realisieren kann?

Schöne Grüße
Sebi

Nachtrag: Falls es wichtig ist: Die Libary, die sich selbst entpackt, erstelle ich selbst, somit kann ich den Entpackungsprozess beeinflussen und dort die Jars nachladen (Wenn ich wüsste wie).


----------



## Noctarius (21. Okt 2009)

Neuen URL-Classloader mit Webapp-Classloader als Parent erzeugen und dem Thread als Standardclassloader unterschieben.


----------



## SebiB90 (21. Okt 2009)

Also wenn du folgendes meintest:

```
ClassLoader parent = Thread.currentThread().getContextClassLoader();
URLClassLoader classLoader = new URLClassLoader(jarUrls, parent);
Thread.currentThread().setContextClassLoader(classLoader);
```
Dann funktioniert es leider nicht =/


----------



## Noctarius (21. Okt 2009)

Joar genau das meinte ich


----------



## SebiB90 (21. Okt 2009)

Funktioniert leider so nicht. Komme zu folgender Exception:


```
21.10.2009 22:36:09 org.apache.catalina.core.ApplicationContext log
SCHWERWIEGEND: StandardWrapper.Throwable
java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory
	at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:725)
	at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:239)
	at javax.faces.webapp.FacesServlet.init(FacesServlet.java:164)
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4149)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4458)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardHost.start(StandardHost.java:722)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
	at org.apache.catalina.core.StandardService.start(StandardService.java:516)
	at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:583)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
21.10.2009 22:36:09 org.apache.catalina.core.StandardContext loadOnStartup
SCHWERWIEGEND: Servlet /abcde-standalone threw load() exception
java.lang.IllegalStateException: Application was not properly initialized at startup, could not find Factory: javax.faces.context.FacesContextFactory
	at javax.faces.FactoryFinder$FactoryManager.getFactory(FactoryFinder.java:725)
	at javax.faces.FactoryFinder.getFactory(FactoryFinder.java:239)
	at javax.faces.webapp.FacesServlet.init(FacesServlet.java:164)
	at org.apache.catalina.core.StandardWrapper.loadServlet(StandardWrapper.java:1173)
	at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:993)
	at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4149)
	at org.apache.catalina.core.StandardContext.start(StandardContext.java:4458)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardHost.start(StandardHost.java:722)
	at org.apache.catalina.core.ContainerBase.start(ContainerBase.java:1045)
	at org.apache.catalina.core.StandardEngine.start(StandardEngine.java:443)
	at org.apache.catalina.core.StandardService.start(StandardService.java:516)
	at org.apache.catalina.core.StandardServer.start(StandardServer.java:710)
	at org.apache.catalina.startup.Catalina.start(Catalina.java:583)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
	at java.lang.reflect.Method.invoke(Unknown Source)
	at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:288)
	at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:413)
```

Diese dürfte aber eigentlich nicht kommen, wenn alle jars im ClassLoader drin sind. Bei einem zweiten Start der WebApplikation läuft alles Problemlos, weil dann die ganzen Jars schon entpackt sind und sofort im Classpath drin sind... =/ Aber es muss doch irgendwie beim ersten mal klappen.


----------



## Noctarius (21. Okt 2009)

Wieso musst du die überhaupt beim Starten entpacken?


----------



## SebiB90 (21. Okt 2009)

Weil wir gerne unser ganzes Programm in einer einzigen Jar Datei weitergeben wollen ohne an die 100 externe Jar Libs mitzugeben. Alle Jars entpacken und zu einer einzigen Datei packen, klappt leider nicht. Da es in den verschiedenen Jars in den META-INF Ordnern Dateien mit gleichen Dateinamen gibt und diese sich gegenseitig überschreiben würden. Ein Beispiel sind die faces-config.xml Dateien. Aber gibt noch weitere.


----------



## Noctarius (21. Okt 2009)

Ihr habt doch eh ein WAR-File, darin kann man doch alles packen?


----------



## maki (21. Okt 2009)

> Weil wir gerne unser ganzes Programm in einer einzigen Jar Datei weitergeben wollen


Das ist doch die war 



> ohne an die 100 externe Jar Libs mitzugeben.


was soll denn das bringen? Wie du siehst, versuchst du sie nun doch wieder zu entpacken...



> Da es in den verschiedenen Jars in den META-INF Ordnern Dateien mit gleichen Dateinamen gibt und diese sich gegenseitig überschreiben würden. Ein Beispiel sind die faces-config.xml Dateien. Aber gibt noch weitere.


Wieso gibt es denn "überlappende" Dateien?
Schon mal an ein Buildsystem gedacht?
zB. Maven2


----------



## SebiB90 (21. Okt 2009)

Das ist alles bischen komplizierter. Die jar ist nur ein framework für ein Portal, das dann noch erweitert wird, durch die Sachen in dem Webprojekt, in dem dieses framework verwendet wird.
Dieses framework verwendet an die 100 externe jars. Damit wir das framework aber in einer jar weitergeben können, müssen wir diese jars mit packen und später entpacken.

Die einfachere Lösung wäre: alle jars entpacken, neue jar mit dem entpackten zeug und unserem zeug zusammen packen. Aber das geht NICHT, aus folgenden grund: Wir haben unter anderem org.springframework.faces-2.0.8.RELEASE.jar und com.springsource.com.sun.facelets-1.1.14.jar als Libs eingebunden. Beide haben im META-INF Ordner eine faces-config.xml. Diese würden sich überschreiben, wenn wir alles in einer jar packen wollten. Versteht ihr das Problem? (ja ich weiß, man kann mehrere faces config in der web.xml angeben, aber das ist nur ein Beispiel von mehreren Dateien, die 'doppelt' vorkommen)


----------



## maki (22. Okt 2009)

> Aber das geht NICHT, aus folgenden grund: Wir haben unter anderem org.springframework.faces-2.0.8.RELEASE.jar und com.springsource.com.sun.facelets-1.1.14.jar als Libs eingebunden.


Ihr wollt da OSGi Bundles als normale Jars verwenden, sonst wären die faces-config.xml Dateien gar nicht sichbar.

Könnt ihr denn nicht die orig. Referenzimplmentierung von Sun verwenden?

So groß wie sich das anhört wäre ein autom. Build nicht verkehrt.


----------



## heizer_28 (16. Jan 2012)

vielleicht es ist noch für jemanden interesant  ich habe es  wie folgt gelöst 
interface  erstellt  dann gelladen und über Interface darauf zugegrifen 

Laden : 

```
ClassLoader parent = Thread.currentThread().getContextClassLoader();
			URLClassLoader urlcl = new URLClassLoader(
					new URL[] { strPathTGoJarFile },parent);

			String strPackage = "packagename.Test ";// Package/Class-Name
			Object instance = null;
			try {
				instance = Class.forName(strPackage, true, urlcl).newInstance(); // call																	// constructor
			} catch (NoClassDefFoundError e) {
				e.printStackTrace();
			}
```

Interface 

```
public interface Itest {
	public String getName();
}
```

classe selbts 

```
public class Test implements Itest{
	
	
	

	public String getFormatName() {
		return "test";
	}
}
```


benutzung :

```
Itest formO = (Itest) instance ;
```


Bemerkung : Itest(Interface) befindet sich im externen Jar der sich in WEB-INF\lib befindet, damit es bei der Applikation und dynamisch geladenen Jar bekannt ist


----------

