From cc007e5339f7ffc35cdd9b94ce3b712596a1494e Mon Sep 17 00:00:00 2001 From: ulrich Date: Tue, 03 Dec 2024 16:20:46 +0000 Subject: [PATCH] Scan nach Actor-Klassen aus der Initialisierung der Kontexte herausgeloest und zu 'runInstance' verlagert. Hilfstabelle fuer Actors waehrend der Initialisierung eingefuehrt. --- src/de/uhilger/neon/Handler.java | 8 +- src/de/uhilger/neon/Factory.java | 112 +++++++++++++++++++++---------------- src/de/uhilger/neon/TempActor.java | 51 +++++++++++++++++ 3 files changed, 119 insertions(+), 52 deletions(-) diff --git a/src/de/uhilger/neon/Factory.java b/src/de/uhilger/neon/Factory.java index 3748d5b..9f9ef19 100644 --- a/src/de/uhilger/neon/Factory.java +++ b/src/de/uhilger/neon/Factory.java @@ -66,9 +66,12 @@ * @version 1, 6.2.2024 */ public class Factory implements ScannerListener { + + private Map<String, List<TempActor>> actorMap; public Factory() { listeners = new ArrayList<>(); + actorMap = new HashMap<>(); } /** @@ -129,17 +132,22 @@ 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()) { - ServerDescriptor sd = serverIterator.next(); + List<ServerDescriptor> serverList = d.server; + for (ServerDescriptor sd : serverList) { HttpServer server = HttpServer.create(new InetSocketAddress(sd.port), 0); fireServerCreated(server); if (packageNames == null) { packageNames = d.actorPackages; } - addContexts(new Scanner(starter, Actor.class), d, server, sd.contexts, packageNames, sdp); + + Scanner scn = new Scanner(starter, Actor.class); + for (String packageName : packageNames) { + scn.process(this, packageName, new Object[]{}); + // ctx.getAttributes().put("serverDataProviderList", sdp); + } + + addContexts(d, server, sd.contexts, sdp); server.setExecutor(Executors.newFixedThreadPool(10)); server.start(); @@ -167,11 +175,11 @@ return auth; } - private void addContexts(Scanner scn, NeonDescriptor d, HttpServer server, List contextList, List<String> packageNames, + private void addContexts(NeonDescriptor d, HttpServer server, List<ContextDescriptor> contextList, List<DataProvider> sdp) throws ClassNotFoundException, NoSuchMethodException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException { - Map<String, HttpHandler> sharedHandlers = new HashMap(); + Map<String, HttpHandler> sharedHandlers = new HashMap<>(); Iterator<ContextDescriptor> contextIterator = contextList.iterator(); Authenticator auth = null; while (contextIterator.hasNext()) { @@ -182,14 +190,12 @@ Map<String, Object> ctxAttrs = ctx.getAttributes(); /* Achtung: Wenn verschiedene Elemente dasselbe Attribut - deklarieren, ueberschreiben sie sich die Attribute gegenseitig. + deklarieren, ueberschreiben sich die Attribute gegenseitig. */ ctxAttrs.putAll(cd.attributes); - if (h instanceof Handler) { - for (String packageName : packageNames) { - scn.process(this, packageName, (Handler) h, cd.attributes.get("contextName")); - ctx.getAttributes().put("serverDataProviderList", sdp); - } + ctxAttrs.put("serverDataProviderList", sdp); + if (h instanceof Handler handler) { + wire(handler, cd.attributes.get("contextName")); } if (cd.authenticator instanceof String) { if (!(auth instanceof Authenticator)) { @@ -200,22 +206,13 @@ 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) { // Object filterObj = Class.forName(filterClassName) .getDeclaredConstructor().newInstance(); - if (filterObj instanceof Filter) { - Filter filter = (Filter) filterObj; + if (filterObj instanceof Filter filter) { ctx.getFilters().add(filter); } } @@ -330,22 +327,32 @@ Kontextpfades ausgefuehrt werden soll, muss die Action als Route '/' angeben. */ + + /* + Tradeoff: + Es muss bei Initialisierung die Actor-Klasse ganz durchlaufen werden, um alle Methoden + zu finden, die eine Action-Annotation haben. Der Handler 'merkt' sich lediglich den Namen der + Actor-Klassen. Daher muessen bei jedem Aufruf eines Actors ueber den Handler abermals + alle Methoden dieses Actors durchsucht werden, um diejenige Methode zu finden, die mit + der zur Route des Requests passenden Action annotiert ist. + + Dieser Tradeoff bewirkt, dass nicht grosse Geflechte aus Klassen- und Methodenobjekten + fuer die gesamten Actors einer Anwendung im Speicher gehalten werden muessen + sondern dynamisch zur Laufzeit instanziiert werden. + */ + /** - * + * Actor-Klassen dem Handler hinzufuegen + * * @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 + * @param contextName Name des Kontext, dem der Handler zugeordnet ist */ - private void wire(Handler h, Class c, String contextName) { - Method[] methods = c.getMethods(); - for (Method method : methods) { - Action action = method.getAnnotation(Action.class); - if (action != null) { - List actionHandlers = Arrays.asList(action.handler()); - if (actionHandlers.contains(contextName)) { - h.setActor(action.type(), action.route(), c.getName()); - } - } + private void wire(Handler h, String contextName) { + List<TempActor> actorList = actorMap.get(contextName); + Iterator<TempActor> i = actorList.iterator(); + while(i.hasNext()) { + TempActor actor = i.next(); + h.setActor(actor.getHttpMethod(), actor.getRoute(), actor.getActorClassName()); } } @@ -363,6 +370,8 @@ public void destroy() { this.listeners.clear(); this.listeners = null; + this.actorMap.clear(); + this.actorMap = null; } private void fireServerCreated(HttpServer server) { @@ -398,19 +407,26 @@ /* -------------- ScannerListener Implementierung --------------- */ @Override public void annotationFound(Class foundClass, Object[] params) { - Handler h = null; - String contextName = null; - for(Object param : params) { - if(param instanceof Handler) { - h = (Handler) param; - } else if(param instanceof String) { - contextName = (String) param; + Method[] methods = foundClass.getMethods(); + for (Method method : methods) { + Action action = method.getAnnotation(Action.class); + if (action != null) { + List<String> actionHandlers = Arrays.asList(action.handler()); + for (String contextName : actionHandlers) { + TempActor tempActor = new TempActor(); + tempActor.setContextName(contextName); + tempActor.setHttpMethod(action.type()); + tempActor.setRoute(action.route()); + tempActor.setActorClassName(foundClass.getName()); + + List<TempActor> actorList = actorMap.get(contextName); + if(actorList == null) { + actorList = new ArrayList<>(); + } + actorList.add(tempActor); + actorMap.put(contextName, actorList); + } } - } - if(h == null || contextName == null) { - Logger.getLogger(Factory.class.getName()).log(Level.FINER, "Handler oder contextName ist null"); - } else { - wire(h, foundClass, contextName); } } } \ No newline at end of file diff --git a/src/de/uhilger/neon/Handler.java b/src/de/uhilger/neon/Handler.java index db7d025..bbd5e78 100644 --- a/src/de/uhilger/neon/Handler.java +++ b/src/de/uhilger/neon/Handler.java @@ -35,11 +35,11 @@ import java.util.logging.Logger; /** - * Objekte der Klasse Handler nehmen Objekte entgegen die die Annotationen NeonActor enthalten. - * Deren mit NeonMethod annotierten Methoden stellt der Handler via HTTP bereit. + * Objekte der Klasse Handler nehmen Objekte entgegen die die Annotationen Actor enthalten. + * Deren mit Action annotierten Methoden stellt der Handler via HTTP bereit. * - * Wird ein Neon-Server mit der Klasse NeonFactory erzeugt, kann mit der Verwendung dieses Handlers - * die NeonFactory den Server selbsttaetig erstellen, ohne zusaetzlichen Boilerplate Code, den eine + * Wird ein Neon-Server mit der Klasse Factory erzeugt, kann mit der Verwendung dieses Handlers + * die Factory den Server selbsttaetig erstellen, ohne zusaetzlichen Boilerplate Code, den eine * eigene Anwendung mitbringen muesste. * * @author Ulrich Hilger diff --git a/src/de/uhilger/neon/TempActor.java b/src/de/uhilger/neon/TempActor.java new file mode 100644 index 0000000..6f78624 --- /dev/null +++ b/src/de/uhilger/neon/TempActor.java @@ -0,0 +1,51 @@ +package de.uhilger.neon; + +import de.uhilger.neon.Action.Type; + +/** + * + * @author Ulrich Hilger + * @version 0.1, 03.12.2024 + */ +public class TempActor { + + private String contextName; + private Type httpMethod; + private String route; + private String actorClassName; + + public String getContextName() { + return contextName; + } + + public void setContextName(String contextName) { + this.contextName = contextName; + } + + public Type getHttpMethod() { + return httpMethod; + } + + public void setHttpMethod(Type httpMethod) { + this.httpMethod = httpMethod; + } + + public String getRoute() { + return route; + } + + public void setRoute(String route) { + this.route = route; + } + + public String getActorClassName() { + return actorClassName; + } + + public void setActorClassName(String actorClassName) { + this.actorClassName = actorClassName; + } + + + +} -- Gitblit v1.9.3