Skip to content

Commit 2eb5a3f

Browse files
committed
fix dynamic application loading
1 parent b99d3ec commit 2eb5a3f

File tree

19 files changed

+291
-93
lines changed

19 files changed

+291
-93
lines changed

net.lecousin.core/src/main/java/net/lecousin/framework/application/Application.java

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131
import net.lecousin.framework.exception.NoException;
3232
import net.lecousin.framework.io.IO;
3333
import net.lecousin.framework.io.provider.IOProvider;
34-
import net.lecousin.framework.io.provider.IOProviderFromPathUsingClassloader;
3534
import net.lecousin.framework.locale.LocalizedProperties;
3635
import net.lecousin.framework.log.Logger;
3736
import net.lecousin.framework.log.LoggerFactory;
@@ -67,6 +66,9 @@ private Application(
6766
this.properties = new Hashtable<>(properties);
6867
else
6968
this.properties = new Hashtable<>();
69+
this.properties.put("groupId", artifact.groupId);
70+
this.properties.put("artifactId", artifact.artifactId);
71+
this.properties.put("version", artifact.version.toString());
7072
this.debugMode = debugMode;
7173
this.threadFactory = threadFactory;
7274
this.librariesManager = librariesManager;
@@ -81,8 +83,7 @@ private Application(
8183
private boolean debugMode;
8284
private ThreadFactory threadFactory;
8385
private LibrariesManager librariesManager;
84-
private ApplicationClassLoader rootClassLoader;
85-
private IOProviderFromPathUsingClassloader rootClassLoaderIOProvider;
86+
private ApplicationClassLoader appClassLoader;
8687
private Console console;
8788
private Properties preferences = null;
8889
private Locale locale;
@@ -183,14 +184,13 @@ public LibrariesManager getLibrariesManager() {
183184
}
184185

185186
/** Return the application class loader. */
186-
@SuppressWarnings("unchecked")
187-
public <T extends ClassLoader & ApplicationClassLoader> T getClassLoader() {
188-
return (T)rootClassLoader;
187+
public ApplicationClassLoader getClassLoader() {
188+
return appClassLoader;
189189
}
190190

191191
/** Get a resource from the class loader as an IO.Readable. */
192192
public IO.Readable getResource(String filename, byte priority) {
193-
IOProvider.Readable provider = rootClassLoaderIOProvider.get(filename);
193+
IOProvider.Readable provider = appClassLoader.getIOProvider(filename);
194194
if (provider == null)
195195
return null;
196196
try {
@@ -341,8 +341,7 @@ public Void run() {
341341
loading.start();
342342
SynchronizationPoint<Exception> sp = new SynchronizationPoint<>();
343343
loading.listenInline(() -> {
344-
app.rootClassLoader = librariesManager.start(app);
345-
app.rootClassLoaderIOProvider = new IOProviderFromPathUsingClassloader((ClassLoader)app.rootClassLoader);
344+
app.appClassLoader = librariesManager.start(app);
346345
librariesManager.onLibrariesLoaded().listenInline(sp);
347346
});
348347

net.lecousin.core/src/main/java/net/lecousin/framework/application/ApplicationClassLoader.java

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package net.lecousin.framework.application;
22

3+
import java.net.URL;
4+
5+
import net.lecousin.framework.io.provider.IOProvider;
6+
37
/**
48
* ClassLoader dedicated to an application.
59
*/
@@ -8,4 +12,13 @@ public interface ApplicationClassLoader {
812
/** Return the application. */
913
Application getApplication();
1014

15+
/** Return an IOProvider for the given application's resource. */
16+
IOProvider.Readable getIOProvider(String filename);
17+
18+
/** Load a class. */
19+
Class<?> loadClass(String className) throws ClassNotFoundException;
20+
21+
/** Search a resource. */
22+
URL getResource(String filename);
23+
1124
}

net.lecousin.core/src/main/java/net/lecousin/framework/application/development/package-info.java

Lines changed: 0 additions & 6 deletions
This file was deleted.

net.lecousin.core/src/main/java/net/lecousin/framework/application/launcher/DevLauncher.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,7 @@ else if (args[i].startsWith("-maven-repository=")) {
215215
startApp.getError().printStackTrace(System.err);
216216
}
217217
LCCore.stop(true);
218+
return;
218219
}
219220
ISynchronizationPoint<Exception> appClosed = startApp.getResult();
220221
if (appClosed != null) {

net.lecousin.core/src/main/java/net/lecousin/framework/application/launcher/DynamicLibrariesManager.java

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515

1616
import net.lecousin.framework.application.Application;
1717
import net.lecousin.framework.application.ApplicationBootstrap;
18+
import net.lecousin.framework.application.ApplicationClassLoader;
1819
import net.lecousin.framework.application.ApplicationConfiguration;
1920
import net.lecousin.framework.application.Artifact;
2021
import net.lecousin.framework.application.SplashScreen;
@@ -29,7 +30,6 @@
2930
import net.lecousin.framework.application.libraries.artifacts.LoadedLibrary;
3031
import net.lecousin.framework.application.libraries.classloader.AbstractClassLoader;
3132
import net.lecousin.framework.application.libraries.classloader.AppClassLoader;
32-
import net.lecousin.framework.application.libraries.classpath.DefaultApplicationClassLoader;
3333
import net.lecousin.framework.application.libraries.classpath.LoadLibraryExtensionPointsFile;
3434
import net.lecousin.framework.application.libraries.classpath.LoadLibraryPluginsFile;
3535
import net.lecousin.framework.collections.TreeWithParent;
@@ -75,7 +75,6 @@ public DynamicLibrariesManager(
7575
private Application app;
7676
private File appDir;
7777
private AppClassLoader appClassLoader;
78-
private DefaultApplicationClassLoader defaultClassLoader;
7978
private ArrayList<File> devPaths;
8079
private SplashScreen splash;
8180
private List<LibraryDescriptorLoader> loaders;
@@ -92,12 +91,10 @@ private static class Lib {
9291

9392
private Map<String, Lib> libraries = new HashMap<>();
9493

95-
@SuppressWarnings("unchecked")
9694
@Override
97-
public DefaultApplicationClassLoader start(Application app) {
95+
public ApplicationClassLoader start(Application app) {
9896
this.app = app;
9997
this.appClassLoader = new AppClassLoader(app);
100-
this.defaultClassLoader = new DefaultApplicationClassLoader(app, null);
10198

10299
app.getDefaultLogger().debug("Start loading application in development mode");
103100

@@ -139,7 +136,7 @@ public Void run() {
139136
developmentMode(stepDevProjects, stepDependencies, stepVersionConflicts);
140137
else
141138
productionMode(stepDependencies, stepVersionConflicts);
142-
return defaultClassLoader;
139+
return this.appClassLoader;
143140
}
144141

145142
private void developmentMode(long stepDevProjects, long stepDependencies, long stepVersionConflicts) {
@@ -608,8 +605,7 @@ public Void run() {
608605
AsyncWork<Void, Exception> ep = null;
609606
try {
610607
IO.Readable io = ((AbstractClassLoader)lib.library.getClassLoader())
611-
.get("META-INF/net.lecousin/extensionpoints")
612-
.provideIOReadable(Task.PRIORITY_IMPORTANT);
608+
.open("META-INF/net.lecousin/extensionpoints", Task.PRIORITY_IMPORTANT);
613609
PreBufferedReadable bio = new PreBufferedReadable(io, 512, Task.PRIORITY_IMPORTANT, 1024,
614610
Task.PRIORITY_RATHER_IMPORTANT, 8);
615611
BufferedReadableCharacterStream stream = new BufferedReadableCharacterStream(bio, StandardCharsets.UTF_8, 256, 32);
@@ -629,7 +625,7 @@ public Void run() {
629625
if (path == null) continue;
630626
try {
631627
IO.Readable io = ((AbstractClassLoader)lib.library.getClassLoader())
632-
.get(path).provideIOReadable(Task.PRIORITY_IMPORTANT);
628+
.open(path, Task.PRIORITY_IMPORTANT);
633629
previous = custom.loadPluginConfiguration(io, lib.library.getClassLoader(), previous);
634630
jp.addToJoin(previous);
635631
} catch (FileNotFoundException e) {
@@ -643,7 +639,7 @@ public Void run() {
643639
// plugins
644640
try {
645641
IO.Readable io = ((AbstractClassLoader)lib.library.getClassLoader())
646-
.get("META-INF/net.lecousin/plugins").provideIOReadable(Task.PRIORITY_IMPORTANT);
642+
.open("META-INF/net.lecousin/plugins", Task.PRIORITY_IMPORTANT);
647643
PreBufferedReadable bio = new PreBufferedReadable(io, 512, Task.PRIORITY_IMPORTANT, 1024,
648644
Task.PRIORITY_RATHER_IMPORTANT, 8);
649645
BufferedReadableCharacterStream stream = new BufferedReadableCharacterStream(bio, StandardCharsets.UTF_8, 256, 32);
Lines changed: 29 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,29 @@
1-
package net.lecousin.framework.application.libraries;
2-
3-
import java.io.File;
4-
import java.util.List;
5-
6-
import net.lecousin.framework.application.Application;
7-
import net.lecousin.framework.application.ApplicationClassLoader;
8-
import net.lecousin.framework.concurrent.synch.ISynchronizationPoint;
9-
import net.lecousin.framework.io.IO;
10-
11-
/** Allows to load libraries and get information about loaded ones. */
12-
public interface LibrariesManager {
13-
14-
/** This method is automatically called on application startup so this libraries manager
15-
* can initialize and load libraries as needed for the given application.
16-
*/
17-
<T extends ClassLoader & ApplicationClassLoader> T start(Application app);
18-
19-
/** Return a synchronization point which is blocked until this libraries manager has been initialized
20-
* and has loaded all required libraries. */
21-
ISynchronizationPoint<Exception> onLibrariesLoaded();
22-
23-
/** Open a resource or return null if it does not exist. */
24-
IO.Readable getResource(String path, byte priority);
25-
26-
/** Return the list of libraries loaded. Each File may be a file in case of a JAR, or a directory. */
27-
List<File> getLibrariesLocations();
28-
29-
}
1+
package net.lecousin.framework.application.libraries;
2+
3+
import java.io.File;
4+
import java.util.List;
5+
6+
import net.lecousin.framework.application.Application;
7+
import net.lecousin.framework.application.ApplicationClassLoader;
8+
import net.lecousin.framework.concurrent.synch.ISynchronizationPoint;
9+
import net.lecousin.framework.io.IO;
10+
11+
/** Allows to load libraries and get information about loaded ones. */
12+
public interface LibrariesManager {
13+
14+
/** This method is automatically called on application startup so this libraries manager
15+
* can initialize and load libraries as needed for the given application.
16+
*/
17+
ApplicationClassLoader start(Application app);
18+
19+
/** Return a synchronization point which is blocked until this libraries manager has been initialized
20+
* and has loaded all required libraries. */
21+
ISynchronizationPoint<Exception> onLibrariesLoaded();
22+
23+
/** Open a resource or return null if it does not exist. */
24+
IO.Readable getResource(String path, byte priority);
25+
26+
/** Return the list of libraries loaded. Each File may be a file in case of a JAR, or a directory. */
27+
List<File> getLibrariesLocations();
28+
29+
}

net.lecousin.core/src/main/java/net/lecousin/framework/application/libraries/classloader/AbstractClassLoader.java

Lines changed: 46 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,11 @@ public Application getApplication() {
5353

5454
/** Search a resource. */
5555
protected abstract URL loadResourceURL(String name);
56-
56+
57+
protected abstract Object getResourcePointer(String path);
58+
59+
protected abstract IO.Readable openResourcePointer(Object pointer, byte priority) throws IOException;
60+
5761
private List<AbstractClassLoader> subLoaders = null;
5862

5963
/** Add a class loader from a resource contained by this class loader, for example an inner jar file. */
@@ -157,21 +161,26 @@ final Class<?> loadClassInLibrary(String name) throws IOException {
157161

158162
@Override
159163
public final IOProvider.Readable get(String path) {
164+
Object pointer = getResourcePointer(path);
165+
AbstractClassLoader cl = this;
166+
if (pointer == null) {
167+
if (subLoaders != null)
168+
for (AbstractClassLoader sub : subLoaders) {
169+
pointer = sub.getResourcePointer(path);
170+
if (pointer != null) {
171+
cl = sub;
172+
break;
173+
}
174+
}
175+
if (pointer == null)
176+
return null;
177+
}
178+
Object ptr = pointer;
179+
AbstractClassLoader owner = cl;
160180
return new IOProvider.Readable() {
161181
@Override
162182
public IO.Readable provideIOReadable(byte priority) throws IOException {
163-
try { return loadResourceAsIO(path, priority); }
164-
catch (FileNotFoundException e) {
165-
if (subLoaders == null) throw e;
166-
for (AbstractClassLoader sub : subLoaders) {
167-
try {
168-
return sub.get(path).provideIOReadable(priority);
169-
} catch (FileNotFoundException e2) {
170-
// not found
171-
}
172-
}
173-
throw e;
174-
}
183+
return owner.openResourcePointer(ptr, priority);
175184
}
176185

177186
@Override
@@ -180,6 +189,25 @@ public String getDescription() {
180189
}
181190
};
182191
}
192+
193+
/** Open a resource. */
194+
public final IO.Readable open(String path, byte priority) throws IOException {
195+
Object pointer = getResourcePointer(path);
196+
AbstractClassLoader cl = this;
197+
if (pointer == null) {
198+
if (subLoaders != null)
199+
for (AbstractClassLoader sub : subLoaders) {
200+
pointer = sub.getResourcePointer(path);
201+
if (pointer != null) {
202+
cl = sub;
203+
break;
204+
}
205+
}
206+
if (pointer == null)
207+
throw new FileNotFoundException(path);
208+
}
209+
return cl.openResourcePointer(pointer, priority);
210+
}
183211

184212
/** Search for a resource. */
185213
public final URL getResourceURL(String name) {
@@ -221,4 +249,9 @@ public InputStream getResourceAsStream(String name) {
221249
return appClassLoader.getResourceAsStreamFrom(name, this);
222250
}
223251

252+
@Override
253+
public IOProvider.Readable getIOProvider(String filename) {
254+
return appClassLoader.getIOProviderFrom(filename, this);
255+
}
256+
224257
}

0 commit comments

Comments
 (0)