src/de/uhilger/neon/Factory.java | ●●●●● patch | view | raw | blame | history | |
src/de/uhilger/neon/JarScanner.java | ●●●●● patch | view | raw | blame | history |
src/de/uhilger/neon/Factory.java
@@ -106,6 +106,7 @@ IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { this.runInstance(c, d, packageNames, new ArrayList<>()); } /** * Einen Neon-Server gemaess einem Serverbeschreibungsobjekt herstellen und starten * @@ -156,9 +157,9 @@ auth = (Authenticator) authObj; return auth; } } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden? return null; } @@ -256,20 +257,18 @@ // kein HttpHandler aus newInstance return null; } } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { } catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException ex) { // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden? return null; } } @SuppressWarnings("unchecked") private void wireActors(Class c, String packageName, Class annotation, Handler h, String contextName) { JarScanner js = new JarScanner(); URI path; try { path = js.getPath(c); if(path.toString().endsWith(".class")) { JarScanner js = new JarScanner(c, annotation); if (!js.isJar()) { ClassLoader cl = c.getClassLoader(); InputStream stream = cl .getResourceAsStream(packageName.replaceAll("[.]", "/")); @@ -292,12 +291,7 @@ } } } else { ClassLoader cl = js.getUrlClassLoader(c); js.processZipContent(cl, new File(path), packageName, this, h, contextName); } //listClasses(c, packageName); } catch (URISyntaxException ex) { Logger.getLogger(Factory.class.getName()).log(Level.SEVERE, ex.getMessage(), ex); js.processZipContent(packageName, this, h, contextName); } } @@ -305,23 +299,21 @@ * Diese Testmethode zeigt, dass die Methode getResourceAsStream nicht funktioniert wie * dokumentiert. * * 1. Sie liefert den Inhalt einer gegebenen Package mitsamt Unterpackages als * Stream, wenn sie auf eine Packagestruktur angewendet wird, die unverpackt in einem * Verzeichnis des Dateisystems liegt. * 1. Sie liefert den Inhalt einer gegebenen Package mitsamt Unterpackages als Stream, wenn sie * auf eine Packagestruktur angewendet wird, die unverpackt in einem Verzeichnis des Dateisystems * liegt. * * 2. Sie liefert - faelschlicherweise - null bzw. einen leeren Stream, wenn die Packagestruktur * in einem Jar verpackt ist. * * Saemtliche Versuche, ueber den ClassPath oder die Pfadangabe der Package das Verhalten zu * aendern, gehen bislang fehl (z.B. / oder . als Separator, * / oder . zu Beginn enthalten oder nicht, realative oder absolute packagepfadangabe). * Es ist auch unerheblich, ob * aendern, gehen bislang fehl (z.B. / oder . als Separator, / oder . zu Beginn enthalten oder * nicht, realative oder absolute packagepfadangabe). Es ist auch unerheblich, ob * Class.getResourceAsStream oder Class.getClassLoader().getResourceAsStream verwendet wird. * * Unabhaengig davon, ob und wie letztlich im Fall 2. oben die Methode getResourceAsStream * dazu zu bringen waere, eine Inhaltsliste fuer eine Package zu liefern ist allein die * Tatsache, dass sich die Methode unterschiedlich verhaelt bereits ein * schwerer Bug. * Unabhaengig davon, ob und wie letztlich im Fall 2. oben die Methode getResourceAsStream dazu zu * bringen waere, eine Inhaltsliste fuer eine Package zu liefern ist allein die Tatsache, dass * sich die Methode unterschiedlich verhaelt bereits ein schwerer Bug. * * @param c * @param packageName @@ -361,7 +353,6 @@ } } /* Eine Action-Annotation enthaelt gewoehnlich die Route, die 'unterhalb' des Kontextpfades als 'Ausloeser' zur @@ -370,6 +361,12 @@ Wenn die Action fuer alle Routen 'unterhalb' des Kontextpfades ausgefuehrt werden soll, muss die Action als Route '/' angeben. */ /** * * @param h Handler, dem der Actor hinzugefuegt wird, falls der Kontext uebereinstimmt * @param c hinzuzufuegende Actor-Klasse * @param contextName Name des Kontext, dem der Actor hinzugefuegt wird */ private void wire(Handler h, Class c, String contextName) { Method[] methods = c.getMethods(); @@ -385,7 +382,6 @@ } /* -------------- FactoryListener Implementierung --------------- */ private List<FactoryListener> listeners; public void addListener(FactoryListener l) { @@ -432,9 +428,8 @@ } /* -------------- JarScannerListener Implementierung --------------- */ @Override public void actorFound(Class actorClass, Handler h, String contextName) { wire(h, actorClass, contextName); public void annotationFound(Class foundClass, Handler h, String contextName) { wire(h, foundClass, contextName); } } src/de/uhilger/neon/JarScanner.java
@@ -31,34 +31,63 @@ import java.util.zip.ZipFile; /** * Die Klasse JarScanner enthaelt Methoden, um fuer eine Klasse zu bestimmen, in * welcher JAR-Datei sie liegt und diese JAR-Datei nach Klassen zu durchsuchen. * Die Klasse JarScanner enthaelt Methoden, um fuer eine Klasse zu bestimmen, in welcher JAR-Datei * sie liegt und diese JAR-Datei nach Klassen zu durchsuchen. * * @author Ulrich Hilger * @version 0.1, 30.11.2024 */ public class JarScanner { public final class JarScanner { private final URI path; private final Class annotation; private final Class cls; private final ClassLoader urlCL; public void processZipContent(ClassLoader urlCL, File archive, String packageName, JarScannerListener l, Handler h, String contextName) { /** * Einen JarScanner erzeugen, der das Archiv, in dem sich eine gegebene Klasse befindet, nach * Klassen durchsucht, die eine bestimmte Annotation besitzen * * @param c eine Klasse die sich im Archiv befindet, das durchsucht werden soll * @param annotation die Annotation, nach der gesucht wird */ public JarScanner(Class c, Class annotation) { this.annotation = annotation; this.cls = c; this.urlCL = getUrlClassLoader(cls); this.path = getPath(c); } /** * Den Inhalt einer Jar-Datei nach Klassen durchsuchen, die die dem Konstruktor gegebene * Annotation besitzen. * * @param packageName Name der Package, die einschl. Unterpackages durchsucht wird, nur Klassen * dieser Package und ihrer Unterpackages werden geladen und auf die Anotation ueberprueft * @param l eine Klasse, die verstaendigt wird, wenn eine annotierte Klasse gefunden wurde * @param h der Handler, dem die gefundene Klasse hinzugefuegt werden soll * @param contextName Name des Kontext, dem gefundene Klassen hinzugefuegt werden sollen */ public void processZipContent(String packageName, JarScannerListener l, Handler h, String contextName) { try { ZipFile zipfile = new ZipFile(archive); ZipFile zipfile = new ZipFile(new File(path)); Enumeration en = zipfile.entries(); //ClassLoader cl = getUrlClassLoader(cls); while (en.hasMoreElements()) { ZipEntry zipentry = (ZipEntry) en.nextElement(); if (!zipentry.isDirectory()) { processZipEntry(urlCL, zipentry, packageName, l, h, contextName); processZipEntry(zipentry, packageName, l, h, contextName); } else { // ZIP-Dir muss nicht bearbeitet werden } } zipfile.close(); } catch (IOException ex) { log(Level.SEVERE, ex.getLocalizedMessage()); } } private void processZipEntry(ClassLoader urlCL, ZipEntry zipentry, String packageName, JarScannerListener l, Handler h, String contextName) { @SuppressWarnings("unchecked") private void processZipEntry(ZipEntry zipentry, String packageName, JarScannerListener l, Handler h, String contextName) { finest(zipentry.getName()); String zName = zipentry.getName(); if (zName.toLowerCase().endsWith(".class")) { @@ -70,13 +99,12 @@ String pkgName = getPackageName(fullClassNameDots); finest(" -- package name: " + pkgName); if (null != urlCL && pkgName.toLowerCase().startsWith(packageName)) { Class c = null; try { c = urlCL.loadClass(fullClassNameDots); Class c = urlCL.loadClass(fullClassNameDots); if (c != null) { if (c.isAnnotationPresent(Actor.class)) { if (c.isAnnotationPresent(annotation)) { finest(" ---- ACTOR ---- " + fullClassNameDots); l.actorFound(c, h, contextName); l.annotationFound(c, h, contextName); } else { finest("kein Actor " + fullClassNameDots); } @@ -102,34 +130,37 @@ } public ClassLoader getUrlClassLoader(Class c) { URL url; ClassLoader urlCL = null; ClassLoader cl = null; try { url = getPath(c).toURL(); URL url = getPath(c).toURL(); finer("url: " + url.getPath()); urlCL = new URLClassLoader(new URL[]{url}); } catch (URISyntaxException ex) { log(Level.SEVERE, ex.getMessage()); cl = new URLClassLoader(new URL[]{url}); } catch (MalformedURLException ex) { log(Level.SEVERE, ex.getMessage()); } finally { return urlCL; return cl; } } public URI getPath(Class c) throws URISyntaxException { //Class c = this.getClass(); public String getPathStr() { if (path != null) { return path.toString(); } else { return ""; } } public boolean isJar() { return !getPathStr().toLowerCase().endsWith(".class"); } private URI getPath(Class c) { String className = c.getName(); finest("this name: " + className); int pos = className.indexOf(".class"); if(pos > -1) { String classNameWoExt = className.substring(0, pos); } String classNameWoPkg = className.substring(className.lastIndexOf(".") + 1); String classNameWoPkg = c.getSimpleName();//className.substring(className.lastIndexOf(".") + 1); finest("Class name: " + classNameWoPkg); String classPath = c.getResource(classNameWoPkg + ".class").getPath(); pos = classPath.indexOf("!"); int pos = classPath.indexOf("!"); String jarPath; if(pos > -1) { jarPath = /*"jar:" + */ classPath.substring(0, pos); @@ -137,7 +168,12 @@ jarPath = classPath; } finest("path: " + jarPath); try { return new URI(jarPath); } catch (URISyntaxException ex) { Logger.getLogger(JarScanner.class.getName()).log(Level.SEVERE, ex.getMessage(), ex); return null; } } private void finest(String msg) { @@ -152,9 +188,9 @@ Logger.getLogger(JarScanner.class.getName()).log(l, msg); } public interface JarScannerListener { public void actorFound(Class actorClass, Handler h, String contextName); public void annotationFound(Class foundClass, Handler h, String contextName); } }