Ultrakompakter HTTP Server
ulrich
2024-12-01 692dc7be9791f131bfb253c13363b75bc41b8467
JarScanner umbenannt, das Laden von Klassen ohne Jar ebenfalls auf Scanner umgestellt
1 files renamed
1 files modified
105 ■■■■■ changed files
src/de/uhilger/neon/Factory.java 45 ●●●● patch | view | raw | blame | history
src/de/uhilger/neon/Scanner.java 60 ●●●● patch | view | raw | blame | history
src/de/uhilger/neon/Factory.java
@@ -23,7 +23,6 @@
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;
@@ -48,6 +47,7 @@
import java.util.concurrent.Executors;
import java.util.logging.Level;
import java.util.logging.Logger;
import de.uhilger.neon.Scanner.ScannerListener;
/**
 * Einen Neon-Server aus einer Beschreibungsdatei herstellen
@@ -65,7 +65,7 @@
 * @author Ulrich Hilger
 * @version 1, 6.2.2024
 */
public class Factory implements JarScannerListener {
public class Factory implements ScannerListener {
  public Factory() {
    listeners = new ArrayList<>();
@@ -138,8 +138,8 @@
      if (packageNames == null) {
        packageNames = d.actorPackages;
      }
      addContexts(starter, d, server, sd.contexts, packageNames, sdp);
      }
      addContexts(new Scanner(starter, Actor.class), d, server, sd.contexts, packageNames, sdp);
      server.setExecutor(Executors.newFixedThreadPool(10));
      server.start();
@@ -167,7 +167,7 @@
    return auth;
  }
  private void addContexts(Class c, NeonDescriptor d, HttpServer server, List contextList, List<String> packageNames,
  private void addContexts(Scanner scn, NeonDescriptor d, HttpServer server, List contextList, List<String> packageNames,
          List<DataProvider> sdp)
          throws ClassNotFoundException, NoSuchMethodException, InstantiationException,
          IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
@@ -187,8 +187,8 @@
        ctxAttrs.putAll(cd.attributes);
        if (h instanceof Handler) {
          for (String packageName : packageNames) {
            wireActors(c,
                    packageName, Actor.class, (Handler) h,
            wireActors(scn,
                    packageName, (Handler) h,
                    cd.attributes.get("contextName"));
            ctx.getAttributes().put("serverDataProviderList", sdp);
          }
@@ -266,32 +266,11 @@
  }
  @SuppressWarnings("unchecked")
  private void wireActors(Class c, String packageName, Class annotation, Handler h, String contextName) {
    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);
            }
          } catch (ClassNotFoundException ex) {
            // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden?
          }
        } else {
          wireActors(c, packageName + "." + line, annotation, h, contextName);
        }
      }
  private void wireActors(Scanner scn, String packageName, /*Class annotation, */Handler h, String contextName) {
    if (!scn.isJar()) {
      scn.processClasses(this, packageName, h, contextName);
    } else {
      js.processZipContent(packageName, this, h, contextName);
      scn.processZipContent(packageName, this, h, contextName);
    }
  }
@@ -427,7 +406,7 @@
    }
  }
  /* -------------- JarScannerListener Implementierung --------------- */
  /* -------------- ScannerListener Implementierung --------------- */
  @Override
  public void annotationFound(Class foundClass, Handler h, String contextName) {
    wire(h, foundClass, contextName);
src/de/uhilger/neon/Scanner.java
File was renamed from src/de/uhilger/neon/JarScanner.java
@@ -17,46 +17,55 @@
 */
package de.uhilger.neon;
import java.io.BufferedReader;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
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.Iterator;
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
 * Die Klasse Scanner 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 final class JarScanner {
public final class Scanner {
  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
   * Einen Scanner 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) {
  public Scanner(Class c, Class annotation) {
    this.annotation = annotation;
    this.cls = c;
    this.urlCL = getUrlClassLoader(cls);
    this.path = getPath(c);
 }
  }
  public Class getAnnotation() {
    return annotation;
  }
  /**
   * Den Inhalt einer Jar-Datei nach Klassen durchsuchen, die die dem Konstruktor gegebene
@@ -64,11 +73,11 @@
   *
   * @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 l ein Objekt, das 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) {
  public void processZipContent(String packageName, ScannerListener l, Handler h, String contextName) {
    try {
      ZipFile zipfile = new ZipFile(new File(path));
      Enumeration en = zipfile.entries();
@@ -87,7 +96,7 @@
  }
  @SuppressWarnings("unchecked")
  private void processZipEntry(ZipEntry zipentry, String packageName, JarScannerListener l, Handler h, String contextName) {
  private void processZipEntry(ZipEntry zipentry, String packageName, ScannerListener l, Handler h, String contextName) {
    finest(zipentry.getName());
    String zName = zipentry.getName();
    if (zName.toLowerCase().endsWith(".class")) {
@@ -118,6 +127,31 @@
    }
  }
  public void processClasses(ScannerListener l, String packageName, Handler h, String contextName) {
      ClassLoader cl = getCl();
      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(getAnnotation())) {
              //wire(h, actorClass, contextName);
              l.annotationFound(actorClass, h, contextName);
            }
          } catch (ClassNotFoundException ex) {
            // Klasse nicht gefunden. Muss das geloggt oder sonstwie behandel werden?
          }
        } else {
          //wireActors(js, packageName + "." + line, h, contextName);
          processClasses(l, packageName + "." + line, h, contextName);
        }
      }
  }
  private String getPackageName(String fullClassName) {
    String packageName;
    int pos = fullClassName.lastIndexOf(".");
@@ -127,6 +161,10 @@
      packageName = fullClassName;
    }
    return packageName;
  }
  public ClassLoader getCl() {
    return cls.getClassLoader();
  }
  public ClassLoader getUrlClassLoader(Class c) {
@@ -171,7 +209,7 @@
    try {
      return new URI(jarPath);
    } catch (URISyntaxException ex) {
      Logger.getLogger(JarScanner.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
      Logger.getLogger(Scanner.class.getName()).log(Level.SEVERE, ex.getMessage(), ex);
      return null;
    }
  }
@@ -185,10 +223,10 @@
  }
  private void log(Level l, String msg) {
    Logger.getLogger(JarScanner.class.getName()).log(l, msg);
    Logger.getLogger(Scanner.class.getName()).log(l, msg);
  }
  public interface JarScannerListener {
  public interface ScannerListener {
    public void annotationFound(Class foundClass, Handler h, String contextName);
  }