Fix: wireActors, wenn App als JAR laeuft
1 files added
3 files modified
| | |
| | | import com.sun.net.httpserver.HttpContext; |
| | | import com.sun.net.httpserver.HttpHandler; |
| | | import com.sun.net.httpserver.HttpServer; |
| | | import de.uhilger.neon.JarScanner.JarScannerListener; |
| | | import de.uhilger.neon.entity.ContextDescriptor; |
| | | import de.uhilger.neon.entity.NeonDescriptor; |
| | | import de.uhilger.neon.entity.ServerDescriptor; |
| | |
| | | import java.lang.reflect.InvocationTargetException; |
| | | import java.lang.reflect.Method; |
| | | import java.net.InetSocketAddress; |
| | | import java.net.MalformedURLException; |
| | | import java.net.URI; |
| | | import java.net.URISyntaxException; |
| | | import java.util.ArrayList; |
| | | import java.util.Arrays; |
| | | import java.util.HashMap; |
| | |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.concurrent.Executors; |
| | | import java.util.logging.Level; |
| | | import java.util.logging.Logger; |
| | | |
| | | /** |
| | | * Einen Neon-Server aus einer Beschreibungsdatei herstellen |
| | |
| | | * @author Ulrich Hilger |
| | | * @version 1, 6.2.2024 |
| | | */ |
| | | public class Factory { |
| | | public class Factory implements JarScannerListener { |
| | | |
| | | public Factory() { |
| | | listeners = new ArrayList<>(); |
| | |
| | | return gson.fromJson(sb.toString(), NeonDescriptor.class); |
| | | } |
| | | |
| | | public void runInstance(NeonDescriptor d) |
| | | public void runInstance(Class c, NeonDescriptor d) |
| | | throws ClassNotFoundException, NoSuchMethodException, InstantiationException, |
| | | IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { |
| | | this.runInstance(d, null, new ArrayList<>()); |
| | | this.runInstance(c, d, null, new ArrayList<>()); |
| | | } |
| | | |
| | | public void runInstance(NeonDescriptor d, List<String> packageNames) |
| | | public void runInstance(Class c, NeonDescriptor d, List<String> packageNames) |
| | | throws ClassNotFoundException, NoSuchMethodException, InstantiationException, |
| | | IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { |
| | | this.runInstance(d, packageNames, new ArrayList<>()); |
| | | this.runInstance(c, d, packageNames, new ArrayList<>()); |
| | | } |
| | | /** |
| | | * Einen Neon-Server gemaess einem Serverbeschreibungsobjekt herstellen und starten |
| | |
| | | * @throws InvocationTargetException |
| | | * @throws IOException |
| | | */ |
| | | public void runInstance(NeonDescriptor d, List<String> packageNames, List<DataProvider> sdp) |
| | | public void runInstance(Class c, NeonDescriptor d, List<String> packageNames, List<DataProvider> sdp) |
| | | throws ClassNotFoundException, NoSuchMethodException, InstantiationException, |
| | | IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { |
| | | List serverList = d.server; |
| | |
| | | if(packageNames == null) { |
| | | packageNames = d.actorPackages; |
| | | } |
| | | addContexts(d, server, sd.contexts, packageNames, sdp); |
| | | addContexts(c, d, server, sd.contexts, packageNames, sdp); |
| | | |
| | | server.setExecutor(Executors.newFixedThreadPool(10)); |
| | | server.start(); |
| | |
| | | return auth; |
| | | } |
| | | |
| | | private void addContexts(NeonDescriptor d, HttpServer server, List contextList, List<String> packageNames, |
| | | 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 { |
| | |
| | | ctxAttrs.putAll(cd.attributes); |
| | | if (h instanceof Handler) { |
| | | for (String packageName : packageNames) { |
| | | wireActors( |
| | | wireActors(c, |
| | | packageName, Actor.class, (Handler) h, |
| | | cd.attributes.get("contextName")); |
| | | ctx.getAttributes().put("serverDataProviderList", sdp); |
| | |
| | | } |
| | | } |
| | | |
| | | private void wireActors(String packageName, Class annotation, Handler h, String contextName) { |
| | | ClassLoader cl = ClassLoader.getSystemClassLoader(); |
| | | 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 = Class.forName(packageName + "." |
| | | + line.substring(0, line.lastIndexOf('.'))); |
| | | if (actorClass != null && actorClass.isAnnotationPresent(annotation)) { |
| | | wire(h, actorClass, contextName); |
| | | 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? |
| | | } |
| | | } else { |
| | | wireActors(c, packageName + "." + line, annotation, h, contextName); |
| | | } |
| | | } catch (ClassNotFoundException ex) { |
| | | // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden? |
| | | } |
| | | } else { |
| | | wireActors(packageName + "." + line, annotation, h, contextName); |
| | | ClassLoader cl = js.getUrlClassLoader(c); |
| | | js.processZipContent(cl, new File(path), packageName, this, h, contextName); |
| | | } |
| | | } catch (URISyntaxException ex) { |
| | | Logger.getLogger(Factory.class.getName()).log(Level.SEVERE, ex.getMessage(), ex); |
| | | } |
| | | } |
| | | |
| | |
| | | l.instanceStarted(); |
| | | } |
| | | } |
| | | |
| | | /* -------------- JarScannerListener Implementierung --------------- */ |
| | | |
| | | @Override |
| | | public void actorFound(Class actorClass, Handler h, String contextName) { |
| | | wire(h, actorClass, contextName); |
| | | } |
| | | } |
| | |
| | | import de.uhilger.neon.Action.Type; |
| | | import de.uhilger.neon.entity.ActionDescriptor; |
| | | import java.io.IOException; |
| | | import java.lang.reflect.Constructor; |
| | | import java.lang.reflect.InvocationTargetException; |
| | | import java.lang.reflect.Method; |
| | | import java.lang.reflect.Parameter; |
| | |
| | | import java.util.Iterator; |
| | | import java.util.List; |
| | | import java.util.Map; |
| | | import java.util.logging.Level; |
| | | import java.util.logging.Logger; |
| | | |
| | | /** |
| | | * Objekte der Klasse Handler nehmen Objekte entgegen die die Annotationen NeonActor enthalten. |
| | |
| | | |
| | | //Logger.getLogger(Handler.class.getName()) |
| | | // .log(Level.INFO, "{0} {1} {2}", new Object[]{methodType, route, className}); |
| | | dispatcher.get(methodType).put(ad.route, ad); |
| | | //dispatcher.get(methodType).put(ad.route, ad); |
| | | Object adMapObj = dispatcher.get(methodType); |
| | | if(adMapObj instanceof HashMap hashMap) { |
| | | @SuppressWarnings("unchecked") |
| | | HashMap<String, ActionDescriptor> map = hashMap; |
| | | map.put(ad.route, ad); |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "ActionDescriptor route {0} className {1}", new Object[]{route, className}); |
| | | } else { |
| | | Logger.getLogger(Handler.class.getName()).finer("ActionDescriptorMap nicht gefunden"); |
| | | } |
| | | |
| | | } |
| | | |
| | | /** |
| | |
| | | .getHttpContext() |
| | | .getPath() |
| | | .length()); |
| | | |
| | | Type requestMethod = Type.valueOf(exchange.getRequestMethod()); |
| | | String requestMethodStr = exchange.getRequestMethod(); |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "method {0} route {1}", new Object[]{requestMethodStr, route}); |
| | | Type requestMethod = Type.valueOf(requestMethodStr); |
| | | /* |
| | | Es wird erst geprueft, ob zu einer bestimmten Route |
| | | ein Actor registriert wurde. Wenn kein Actor mit dieser |
| | |
| | | Object md = dispatcher.get(requestMethod); |
| | | if (md instanceof Map) { |
| | | int pos = route.lastIndexOf("/"); |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "pos {0}", pos); |
| | | Object o = ((Map) md).get(route); |
| | | if (!(o instanceof ActionDescriptor)) { |
| | | while (!found && (pos > -1)) { |
| | | String routeRest = route.substring(0, pos); |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "pos {0} routeRest {1}", new Object[]{pos, routeRest}); |
| | | o = ((Map) md).get(routeRest); |
| | | if (o instanceof ActionDescriptor) { |
| | | found = true; |
| | |
| | | handleRequest(exchange, o, route, route, requestMethod); |
| | | } |
| | | if (!found) { |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "{0} not found ", route); |
| | | o = dispatcher.get(requestMethod).get("/"); |
| | | if (o instanceof ActionDescriptor) { |
| | | handleRequest(exchange, o, route, route, requestMethod); |
| | | } else { |
| | | // kein ActionDescriptor für '/' |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "Kein Actiondescriptor fuer '/'"); |
| | | } |
| | | } |
| | | } else { |
| | | // keine Actions fuer HTTP Methode |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "Kein Actions fuer HTTP-Methode {0}", requestMethodStr); |
| | | } |
| | | |
| | | } |
| | | |
| | | private void handleRequest(HttpExchange exchange, Object o, String route, String subroute, Type requestMethod) throws IOException { |
| | | Logger.getLogger(Handler.class.getName()).log(Level.FINER, "Handle Request route {0} subroute {1}", new Object[]{route, subroute}); |
| | | ActionDescriptor ad = (ActionDescriptor) o; |
| | | String actorClassName = ad.className; |
| | | try { |
| | |
| | | if (action != null) { |
| | | if ((action.route().equals("/") || action.route().startsWith(route)) && action.type().equals(requestMethod)) { |
| | | Object[] actionArgs = getActionArgs(exchange, method, ad, subroute); |
| | | Object actorObj = actorClass.getDeclaredConstructor().newInstance(); |
| | | addDataProvider(exchange, actorObj); |
| | | Object antwort = method.invoke(actorObj, actionArgs); |
| | | if (!action.handlesResponse()) { |
| | | respond(exchange, antwort); |
| | | @SuppressWarnings("unchecked") |
| | | Object conObj = actorClass.getDeclaredConstructor(); |
| | | if(conObj instanceof Constructor) { |
| | | Constructor con = (Constructor) conObj; |
| | | Object actorObj; |
| | | actorObj = con.newInstance(); |
| | | addDataProvider(exchange, actorObj); |
| | | Object antwort = method.invoke(actorObj, actionArgs); |
| | | if (!action.handlesResponse()) { |
| | | respond(exchange, antwort); |
| | | } |
| | | } else { |
| | | // kein Konstruktor |
| | | Logger.getLogger(Handler.class.getName()).info("Kein Konstruktor gefunden"); |
| | | } |
| | | } |
| | | } |
| | |
| | | InstantiationException | IllegalAccessException | IllegalArgumentException | |
| | | InvocationTargetException ex) { |
| | | // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden? |
| | | Logger.getLogger(Handler.class.getName()).finer("Kein passende Actor-Klasse gefunden"); |
| | | } |
| | | //} |
| | | } |
New file |
| | |
| | | /* |
| | | * Click nbfs://nbhost/SystemFileSystem/Templates/Licenses/license-default.txt to change this license |
| | | * Click nbfs://nbhost/SystemFileSystem/Templates/Classes/Class.java to edit this template |
| | | */ |
| | | |
| | | package de.uhilger.neon; |
| | | |
| | | import java.io.File; |
| | | import java.io.IOException; |
| | | import java.net.MalformedURLException; |
| | | import java.net.URI; |
| | | import java.net.URISyntaxException; |
| | | import java.net.URL; |
| | | import java.net.URLClassLoader; |
| | | import java.util.Enumeration; |
| | | import java.util.logging.Level; |
| | | import java.util.logging.Logger; |
| | | import java.util.zip.ZipEntry; |
| | | 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. |
| | | * |
| | | * @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) { |
| | | try { |
| | | ZipFile zipfile = new ZipFile(archive); |
| | | Enumeration en = zipfile.entries(); |
| | | while (en.hasMoreElements()) { |
| | | ZipEntry zipentry = (ZipEntry) en.nextElement(); |
| | | if (!zipentry.isDirectory()) { |
| | | processZipEntry(urlCL, 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) { |
| | | log(Level.FINEST, zipentry.getName()); |
| | | String zName = zipentry.getName(); |
| | | if (zName.toLowerCase().endsWith(".class")) { |
| | | int pos = zName.indexOf(".class"); |
| | | String fullClassName = zName.substring(0, pos); |
| | | log(Level.FINEST, "full class name: " + zName); |
| | | String fullClassNameDots = fullClassName.replace('/', '.'); |
| | | log(Level.FINEST, "full class name dots: " + fullClassNameDots); |
| | | String pkgName = getPackageName(fullClassNameDots); |
| | | log(Level.FINEST, " -- package name: " + pkgName); |
| | | if (null != urlCL && pkgName.toLowerCase().startsWith(packageName)) { |
| | | Class c = null; |
| | | try { |
| | | c = urlCL.loadClass(fullClassNameDots); |
| | | if (c != null) { |
| | | if (c.isAnnotationPresent(Actor.class)) { |
| | | log(Level.FINER, " ---- ACTOR ---- " + fullClassNameDots); |
| | | l.actorFound(c, h, contextName); |
| | | } else { |
| | | log(Level.FINER, "kein Actor " + fullClassNameDots); |
| | | } |
| | | } else { |
| | | log(Level.FINER, "class NOT loaded: " + zName); |
| | | } |
| | | } catch (ClassNotFoundException ex) { |
| | | log(Level.FINER, " +++++ Class not found: " + ex.getMessage()); |
| | | } |
| | | } |
| | | } |
| | | } |
| | | |
| | | private String getPackageName(String fullClassName) { |
| | | String packageName; |
| | | int pos = fullClassName.lastIndexOf("."); |
| | | if (pos > 0) { |
| | | packageName = fullClassName.substring(0, pos); |
| | | } else { |
| | | packageName = fullClassName; |
| | | } |
| | | return packageName; |
| | | } |
| | | |
| | | public ClassLoader getUrlClassLoader(Class c) { |
| | | URL url; |
| | | ClassLoader urlCL = null; |
| | | try { |
| | | url = getPath(c).toURL(); |
| | | log(Level.FINER, "url: " + url.getPath()); |
| | | urlCL = new URLClassLoader(new URL[]{url}); |
| | | } catch (URISyntaxException ex) { |
| | | log(Level.SEVERE, ex.getMessage()); |
| | | } catch (MalformedURLException ex) { |
| | | log(Level.SEVERE, ex.getMessage()); |
| | | } finally { |
| | | return urlCL; |
| | | } |
| | | } |
| | | |
| | | public URI getPath(Class c) throws URISyntaxException { |
| | | //Class c = this.getClass(); |
| | | String className = c.getName(); |
| | | finer("this name: " + className); |
| | | |
| | | int pos = className.indexOf(".class"); |
| | | if(pos > -1) { |
| | | String classNameWoExt = className.substring(0, pos); |
| | | } |
| | | String classNameWoPkg = className.substring(className.lastIndexOf(".") + 1); |
| | | finer("Class name: " + classNameWoPkg); |
| | | String classPath = c.getResource(classNameWoPkg + ".class").getPath(); |
| | | pos = classPath.indexOf("!"); |
| | | String jarPath; |
| | | if(pos > -1) { |
| | | jarPath = /*"jar:" + */ classPath.substring(0, pos); |
| | | } else { |
| | | jarPath = classPath; |
| | | } |
| | | finer("path: " + jarPath); |
| | | return new URI(jarPath); |
| | | } |
| | | |
| | | 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); |
| | | } |
| | | |
| | | } |
| | |
| | | * Ein neues Objekt der Klasse RangeGroup erzeugen |
| | | */ |
| | | public RangeGroup() { |
| | | ranges = new ArrayList(); |
| | | ranges = new ArrayList<>(); |
| | | } |
| | | |
| | | /** |