Ultrakompakter HTTP Server
ulrich
2024-12-01 40f0b0d27ec38c97fadb4c64dba6855c6ee2e904
src/de/uhilger/neon/Handler.java
@@ -22,6 +22,7 @@
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;
@@ -30,6 +31,8 @@
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.
@@ -91,7 +94,17 @@
    //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");
    }
  }
  /**
@@ -128,9 +141,16 @@
   */
  @Override
  public void handle(HttpExchange exchange) throws IOException {
    HttpHelper hh = new HttpHelper();
    String route = hh.getRouteString(exchange);
    Type requestMethod = Type.valueOf(exchange.getRequestMethod());
    String route = exchange
            .getRequestURI()
            .getPath()
            .substring(exchange
                    .getHttpContext()
                    .getPath()
                    .length());
    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 
@@ -141,32 +161,42 @@
    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, routeRest, route.substring(routeRest.length()));
            handleRequest(exchange, o, routeRest, route.substring(routeRest.length()), requestMethod);
          }
          pos = routeRest.lastIndexOf("/");
        }
      } else {
        found = true;
        handleRequest(exchange, o, route, route);
        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);
          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) throws IOException {
  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 {
@@ -175,13 +205,22 @@
      for (Method method : methods) {
        Action action = method.getAnnotation(Action.class);
        if (action != null) {
          if (action.route().equals("/") || action.route().startsWith(route)) {
          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");
            }
          }
        }
@@ -190,6 +229,7 @@
            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");
    }
    //}
  }
@@ -199,11 +239,25 @@
    Parameter[] methodParams = method.getParameters();
    Object[] actionArgs = new Object[count];
    String[] routeParams = subroute.split("/");
    /*
      Fall 1: Es sind mehr als ein Parameter zu uebergeben und die Route enthaelt
      weniger Parameter als die Methode erfordert.
      Fall 2: Die Methode erwartet Parameter und der erste Parameter ist nicht
      vom Typ HttpExchange.
      Wenn einer dieser beiden Faelle eintritt, wird alles als Parameter an die Methode
      uebergeben, was eventuell als Teil einer Query im URL oder im Body enthalten ist.
      Fuer Mthoden, die nicht vom Typ HTTP GET sind, kann ein Actor kann dann den Body
      nicht mehr lesen, weil das bereits an dieser Stelle gemacht wurde.
    */
    Map queryParams = new HashMap();
    if ((count > 1 && count > routeParams.length)
            || (methodParams.length > 0 && !methodParams[0].getType().equals(HttpExchange.class))) {
      queryParams = new HttpHelper().getQueryMap(exchange);
    }
    int k = 0;
    for (Parameter methodParam : methodParams) {
      if (methodParam.getType().equals(HttpExchange.class)) {