From 47e67b0aa12758fcbe6eb68f95a35ceb66c268e7 Mon Sep 17 00:00:00 2001 From: ulrich Date: Sun, 01 Dec 2024 16:25:09 +0000 Subject: [PATCH] Code aufgeraeumt --- src/de/uhilger/neon/JarScanner.java | 122 +++++++++++------ src/de/uhilger/neon/Factory.java | 261 ++++++++++++++++++------------------- 2 files changed, 207 insertions(+), 176 deletions(-) diff --git a/src/de/uhilger/neon/Factory.java b/src/de/uhilger/neon/Factory.java index 578ad4f..48ceb6d 100644 --- a/src/de/uhilger/neon/Factory.java +++ b/src/de/uhilger/neon/Factory.java @@ -94,22 +94,23 @@ Gson gson = new Gson(); return gson.fromJson(sb.toString(), NeonDescriptor.class); } - - public void runInstance(Class c, NeonDescriptor d) - throws ClassNotFoundException, NoSuchMethodException, InstantiationException, + + public void runInstance(Class c, NeonDescriptor d) + throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { this.runInstance(c, d, null, new ArrayList<>()); } - public void runInstance(Class c, NeonDescriptor d, List<String> packageNames) - throws ClassNotFoundException, NoSuchMethodException, InstantiationException, + public void runInstance(Class c, NeonDescriptor d, List<String> packageNames) + throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { this.runInstance(c, d, packageNames, new ArrayList<>()); } + /** * Einen Neon-Server gemaess einem Serverbeschreibungsobjekt herstellen und starten * - * @param starter die Klasse, mit der Neon durch Aufruf dieser Methode gestartet wird + * @param starter die Klasse, mit der Neon durch Aufruf dieser Methode gestartet wird * @param d das Object mit der Serverbeschreibung * @param packageNames Namen der Packages, aus der rekursiv vorgefundene Actors eingebaut werden * sollen @@ -122,12 +123,12 @@ * @throws InvocationTargetException * @throws IOException */ - public void runInstance(Class starter, NeonDescriptor d, List<String> packageNames, List<DataProvider> sdp) - throws ClassNotFoundException, NoSuchMethodException, InstantiationException, + public void runInstance(Class starter, NeonDescriptor d, List<String> packageNames, List<DataProvider> sdp) + throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { Logger.getLogger(Factory.class.getName()).log(Level.FINER, System.getProperty("java.class.path")); - + List serverList = d.server; Iterator<ServerDescriptor> serverIterator = serverList.iterator(); while (serverIterator.hasNext()) { @@ -135,7 +136,7 @@ HttpServer server = HttpServer.create(new InetSocketAddress(sd.port), 0); fireServerCreated(server); - if(packageNames == null) { + if (packageNames == null) { packageNames = d.actorPackages; } addContexts(starter, d, server, sd.contexts, packageNames, sdp); @@ -145,30 +146,30 @@ } fireInstanceStarted(); } - + private Authenticator createAuthenticator(NeonDescriptor d) { Authenticator auth = null; - if(d.authenticator != null) { + if (d.authenticator != null) { try { Object authObj = Class.forName(d.authenticator.className) .getDeclaredConstructor().newInstance(); - if(authObj instanceof Authenticator) { + if (authObj instanceof Authenticator) { 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; - } - } + } + } return auth; } - private void addContexts(Class c, NeonDescriptor d, HttpServer server, List contextList, List<String> packageNames, - List<DataProvider> sdp) - throws ClassNotFoundException, NoSuchMethodException, InstantiationException, + private void addContexts(Class c, NeonDescriptor d, HttpServer server, List contextList, List<String> packageNames, + List<DataProvider> sdp) + throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { Map<String, HttpHandler> sharedHandlers = new HashMap(); Iterator<ContextDescriptor> contextIterator = contextList.iterator(); @@ -177,45 +178,45 @@ ContextDescriptor cd = contextIterator.next(); HttpHandler h = buildHandler(cd, sharedHandlers); if (h != null) { - HttpContext ctx = server.createContext(cd.contextPath, h); + HttpContext ctx = server.createContext(cd.contextPath, h); Map<String, Object> ctxAttrs = ctx.getAttributes(); /* Achtung: Wenn verschiedene Elemente dasselbe Attribut deklarieren, ueberschreiben sie sich die Attribute gegenseitig. */ - ctxAttrs.putAll(cd.attributes); - if (h instanceof Handler) { + ctxAttrs.putAll(cd.attributes); + if (h instanceof Handler) { for (String packageName : packageNames) { - wireActors(c, - packageName, Actor.class, (Handler) h, + wireActors(c, + packageName, Actor.class, (Handler) h, cd.attributes.get("contextName")); - ctx.getAttributes().put("serverDataProviderList", sdp); + ctx.getAttributes().put("serverDataProviderList", sdp); } - } - if(cd.authenticator instanceof String) { - if(!(auth instanceof Authenticator)) { + } + if (cd.authenticator instanceof String) { + if (!(auth instanceof Authenticator)) { auth = createAuthenticator(d); } - if(auth instanceof Authenticator) { - ctx.setAuthenticator(auth); + if (auth instanceof Authenticator) { + ctx.setAuthenticator(auth); ctx.getAttributes().putAll(d.authenticator.attributes); fireAuthenticatorCreated(ctx, auth); // event umbenennen in etwas wie authAdded oder so } - + } - + //Authenticator auth = createAuthenticator(d); //if (auth instanceof Authenticator && cd.authenticator instanceof String) { // ctx.setAuthenticator(auth); // ctx.getAttributes().putAll(d.authenticator.attributes); // fireAuthenticatorCreated(ctx, auth); //} - if(cd.filter != null) { - for(String filterClassName : cd.filter) { + if (cd.filter != null) { + for (String filterClassName : cd.filter) { // Object filterObj = Class.forName(filterClassName) - .getDeclaredConstructor().newInstance(); - if(filterObj instanceof Filter) { + .getDeclaredConstructor().newInstance(); + if (filterObj instanceof Filter) { Filter filter = (Filter) filterObj; ctx.getFilters().add(filter); } @@ -228,10 +229,10 @@ } } } - - private HttpHandler buildHandler(ContextDescriptor cd, Map<String, HttpHandler> sharedHandlers) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, + + private HttpHandler buildHandler(ContextDescriptor cd, Map<String, HttpHandler> sharedHandlers) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { - HttpHandler h; + HttpHandler h; if (!cd.sharedHandler) { h = getHandlerInstance(cd); } else { @@ -245,7 +246,7 @@ } return h; } - + private HttpHandler getHandlerInstance(ContextDescriptor cd) { try { Object handlerObj = Class.forName(cd.className) @@ -256,112 +257,102 @@ // 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")) { - ClassLoader cl = c.getClassLoader(); - InputStream stream = cl - .getResourceAsStream(packageName.replaceAll("[.]", "/")); - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); - Iterator i = reader.lines().iterator(); - while (i.hasNext()) { - String line = i.next().toString(); - if (line.endsWith(".class")) { - try { - Class actorClass = cl.loadClass(packageName + "." - + line.substring(0, line.lastIndexOf('.'))); - if (actorClass != null && actorClass.isAnnotationPresent(annotation)) { - wire(h, actorClass, contextName); - } - } catch (ClassNotFoundException ex) { - // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden? + JarScanner js = new JarScanner(c, annotation); + if (!js.isJar()) { + ClassLoader cl = c.getClassLoader(); + InputStream stream = cl + .getResourceAsStream(packageName.replaceAll("[.]", "/")); + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + Iterator i = reader.lines().iterator(); + while (i.hasNext()) { + String line = i.next().toString(); + if (line.endsWith(".class")) { + try { + Class actorClass = cl.loadClass(packageName + "." + + line.substring(0, line.lastIndexOf('.'))); + if (actorClass != null && actorClass.isAnnotationPresent(annotation)) { + wire(h, actorClass, contextName); } - } else { - wireActors(c, packageName + "." + line, annotation, h, contextName); + } catch (ClassNotFoundException ex) { + // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden? } + } else { + wireActors(c, packageName + "." + line, annotation, h, contextName); } - } 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); + } else { + js.processZipContent(packageName, this, h, contextName); } } - + /** - * 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. - * - * 2. Sie liefert - faelschlicherweise - null bzw. einen leeren Stream, wenn die Packagestruktur + * 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. + * + * 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 + * + * 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 * 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 + * @param packageName */ private void listClasses(Class c, String packageName) { - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "packageName: " + packageName); - //ClassLoader cl = c.getClassLoader(); - String newPackageName = packageName.replaceAll("[.]", "/"); - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "newPackageName: " + newPackageName); - InputStream stream = c - .getResourceAsStream(newPackageName); - if(stream != null) { - BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); - Iterator i = reader.lines().iterator(); - Logger.getLogger(Factory.class.getName()).log(Level.FINER, Long.toString(reader.lines().count())); - while (i.hasNext()) { - String line = i.next().toString(); - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "class to inspect: " + line); - if (line.endsWith(".class")) { - try { - Class actorClass = c.getClassLoader().loadClass(packageName + "." - + line.substring(0, line.lastIndexOf('.'))); - if (actorClass != null && actorClass.isAnnotationPresent(Actor.class)) { - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "ACTOR"); - } else { - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "no actor"); - } - } catch (ClassNotFoundException ex) { - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "Klasse nicht gefunden"); + Logger.getLogger(Factory.class.getName()).log(Level.FINER, "packageName: " + packageName); + //ClassLoader cl = c.getClassLoader(); + String newPackageName = packageName.replaceAll("[.]", "/"); + Logger.getLogger(Factory.class.getName()).log(Level.FINER, "newPackageName: " + newPackageName); + InputStream stream = c + .getResourceAsStream(newPackageName); + if (stream != null) { + BufferedReader reader = new BufferedReader(new InputStreamReader(stream)); + Iterator i = reader.lines().iterator(); + Logger.getLogger(Factory.class.getName()).log(Level.FINER, Long.toString(reader.lines().count())); + while (i.hasNext()) { + String line = i.next().toString(); + Logger.getLogger(Factory.class.getName()).log(Level.FINER, "class to inspect: " + line); + if (line.endsWith(".class")) { + try { + Class actorClass = c.getClassLoader().loadClass(packageName + "." + + line.substring(0, line.lastIndexOf('.'))); + if (actorClass != null && actorClass.isAnnotationPresent(Actor.class)) { + Logger.getLogger(Factory.class.getName()).log(Level.FINER, "ACTOR"); + } else { + Logger.getLogger(Factory.class.getName()).log(Level.FINER, "no actor"); } - } else { - listClasses(c, packageName + "." + line); + } catch (ClassNotFoundException ex) { + Logger.getLogger(Factory.class.getName()).log(Level.FINER, "Klasse nicht gefunden"); } - } } else { - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "stream ist null"); + listClasses(c, packageName + "." + line); } + } + } else { + Logger.getLogger(Factory.class.getName()).log(Level.FINER, "stream ist null"); + } } - - + /* Eine Action-Annotation enthaelt gewoehnlich die Route, die 'unterhalb' des Kontextpfades als 'Ausloeser' zur @@ -370,7 +361,13 @@ 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(); for (Method method : methods) { @@ -385,7 +382,6 @@ } /* -------------- FactoryListener Implementierung --------------- */ - private List<FactoryListener> listeners; public void addListener(FactoryListener l) { @@ -406,7 +402,7 @@ l.serverCreated(server); } } - + private void fireHandlerCreated(HttpContext ctx, HttpHandler h) { for (FactoryListener l : listeners) { l.handlerCreated(ctx, h); @@ -418,7 +414,7 @@ l.contextCreated(context); } } - + private void fireAuthenticatorCreated(HttpContext context, Authenticator auth) { for (FactoryListener l : listeners) { l.authenticatorCreated(context, auth); @@ -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); } -} +} \ No newline at end of file diff --git a/src/de/uhilger/neon/JarScanner.java b/src/de/uhilger/neon/JarScanner.java index f0cd8ab..23f8bd0 100644 --- a/src/de/uhilger/neon/JarScanner.java +++ b/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 void processZipContent(ClassLoader urlCL, File archive, String packageName, JarScannerListener l, Handler h, String contextName) { +public final class JarScanner { + + private final URI path; + private final Class annotation; + private final Class cls; + private final ClassLoader urlCL; + + /** + * 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); } @@ -89,7 +117,7 @@ } } } - + private String getPackageName(String fullClassName) { String packageName; int pos = fullClassName.lastIndexOf("."); @@ -100,61 +128,69 @@ } return packageName; } - + 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) { + if (pos > -1) { jarPath = /*"jar:" + */ classPath.substring(0, pos); } else { jarPath = classPath; } finest("path: " + jarPath); - return new URI(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) { log(Level.FINEST, msg); } - + private void finer(String msg) { log(Level.FINER, msg); } - + private void log(Level l, String msg) { 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); } - + } -- Gitblit v1.9.3