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