Cette page documente l’implémentation : ce qui se passe entre le moment où la connexion HTTP arrive sur Chappe et celui où la Servlet écrit sa réponse. Elle complète Concepts (vocabulaire) et Référence (API).

Vue d’ensemble : trois couches, deux modules JPMS

Diagram

Séquence d’une requête HTTP

Diagram

Aucune copie de body : ServletOutputStreamImpl écrit directement dans le Body Chappe. Le ServletInputStream lit directement depuis le frame parser Chappe.

Modèle de threading

  • Un virtual thread par requête. Chappe accept() produit déjà un VT par connexion. Foy reste sur ce thread jusqu’à la fin de service().

  • Pas de pool plateforme. Aucun ExecutorService à dimensionner.

  • Async : aucun coût supplémentaire. request.startAsync() capture le VT courant ; le programme peut détacher la réponse, mais le container ne réserve aucun thread plateforme.

  • ThreadLocal : utilisé prudemment via ScopedValue (JEP 506) côté Chappe. Foy hérite de ce contexte sans le bloquer.

Le bridge ne pin jamais un VT sur un moniteur Java — toutes les sections critiques utilisent ReentrantLock ou des structures lock-free. Voir lien:https://codeberg.org/Vidocq/foy/src/branch/main/BENCH.md[BENCH.md] pour les chiffres.

Lifecycle du container

Diagram

fireContextInitialized() et fireContextDestroyed() sont exposés par FoyChappeBoot.Mounted — l’appelant choisit le moment exact (typiquement après / avant ChappeMountPoint.mount / unmount).

Intégration CDI via Vauban

foy-cdi-vauban agit en deux temps :

  1. build-time (Vauban) — le processeur d’annotations Vauban génère les bean producers pour ServletContext, HttpServletRequest et HttpSession. Aucune réflexion, tout est en Class-File API (JEP 484).

  2. runtime (Foy)FoyVaubanBootstrap.beanManager() retourne le BeanManager injecté à FoyChappeBoot. À chaque requête, ServletDispatcher pousse l’instance courante de HttpServletRequest dans le RequestScoped context.

Bénéfice : @Inject HttpServletRequest req fonctionne dans n’importe quelle Servlet ou Filter, sans proxy dynamique runtime.

Choix d’implémentation

Choix Justification

Pas de scan classpath runtime

Tous les @WebServlet / @WebFilter / @WebListener sont connus à la compilation via Vauban. Démarrage en O(1) du nombre de beans, pas O(N) du classpath.

Pas de réflexion runtime

Conformité aux principes de l’écosystème Vidocq. Compatibilité AOT (GraalVM, Leyden CDS).

Pas de copie de body

ServletOutputStreamImpl et ServletInputStreamImpl se branchent sur les Body Chappe directement.

requires io.vidocq.chappe.api dans foy-core

Couplage M1 temporaire — sera remplacé en M2 par une SPI FoyHttpExchange dans foy-api pour pouvoir brancher d’autres transports.

Pas de META-INF/services runtime

Les SPI Servlet (ex. ServletContainerInitializer) ne sont pas chargées par scan ; elles passent par le BeanManager Vauban.

Limites connues

  • Cross-context dispatch (ServletContext.getContext) : pas implémenté — voir TCK : Jakarta Servlet 6.1.

  • WebSocket Servlet 6.1 : // TODO@user: planifié, pas de date.

  • JSP : non supporté, non planifié.

  • Form-based authentication : // TODO@user: en cours.

Pour des chiffres comparatifs (Tomcat, Jetty), voir lien:https://codeberg.org/Vidocq/foy/src/branch/main/BENCH.md[BENCH.md].