Hello! After almost 2 years of refactoring and development, I think Pax Web 8 is ready for release. Manual updates are still on my list and some exhaustive documentation (and maybe a blog post) is being prepared...
TL;DR: - `mvn clean install -DskipTests` in `main` branch of > https://github.com/ops4j/org.ops4j.pax.web > - start with clean Karaf 4.3.3 > > karaf@root()> repo-remove org.ops4j.pax.web-7.3.19 > karaf@root()> repo-add > mvn:org.ops4j.pax.web/pax-web-features/8.0.0-SNAPSHOT/xml/features > karaf@root()> feature:install pax-web-http-tomcat > karaf@root()> feature:install pax-web-war > karaf@root()> bundle:install -s > 'webbundle:mvn:io.hawt/hawtio-war/2.13.6/war?Web-ContextPath=/hawtio' > > - browse to http://localhost:8181/hawtio > However I think it'd be good to describe the rationale behind the rewrite and some key points of the new release. *Background information:* My single, initial reason to start the refactoring was https://github.com/ops4j/org.ops4j.pax.web/issues/1413 issue (migrated from https://ops4j1.jira.com/browse/PAXWEB-1123): "HTTP Whiteboard and selection of the ServletContextHelper". Whiteboard specification says, that every web element may reference a target ServletContextHelper using "osgi.http.whiteboard.context.select" service registration property and its value is an LDAP filter, which may also be: osgi.http.whiteboard.context.select=(osgi.http.whiteboard.context.name=*) which means "register the servlet into ALL available ServletContextHelpers". Pax Web 7 was taking the osgi.http.whiteboard.context.select property value and was doing split("=") on it to get the name/id of the target context... Effectively 1:1 relation was assumed, while Whiteboard specification assumes 1:N relationship. So I started to rewrite the internal Pax Web model... And somehow much much more was refactored. *Pax Web 8 goals:* - I've carefully read chapters 102 (Http Service specification), 128 (Web Applications specification) and 140 (Whiteboard specification) of OSGi CMPN R7 and tried to implement everything in best possible way - I always appreciated how well and cleverly Pax Web was written by others from this list: 11:41 $ git shortlog -snc origin/pax-web-7.2.x > 894 adreghi...@gmail.com > 747 anierbeck > 284 Achim Nierbeck > 182 ANierbeck > 123 Guillaume Nodet > 114 Jean-Baptiste Onofré > 103 Marc Schlegel > 77 jbonofre > 53 lostiniceland > 44 Stephan Siano > 37 Harald Wellmann > 21 Marc Klinger > 20 Freeman Fang > ... > - I wanted to keep the "spirit" of Pax Web - emphasizing target runtime (Jetty, Tomcat, Undertow) over "specification first" approach - I wanted to ensure that everything in Pax Web works as similar as possible in all 3 supported runtimes - I wanted to keep the possibility to use native container configuration (jetty.xml, tomcat-server.xml, undertow.xml) in addition to what we can pass through org.ops4j.pax.web PID - I wanted to make Pax Web 8 more reliable (no more flaky tests, no more random Thread.sleep() in tests, ...) *Pax Web 8 highlights:* - Latest versions of Jetty 9.4.x, Tomcat 9.0.x (without TIPI!) and Undertow 2.2.x are used - Web "elements" mentioned in Http Service and Whiteboard specifications are handled: servlets, filters, listeners, error pages - additionally, Pax Web 8 supports everything that can be configured in web.xml besides: <env-entry>, <post-construct>, <pre-destroy>, <resource-env-ref>, <resource-ref>, <administered-object>, <connection-factory>, <data-source>, <default-context-path>, <description>, <ejb-local-ref>, <ejb-ref>, <icon>, <jms-connection-factory>, <jms-destination>, <mail-session>, <message-destination>, <message-destination-ref>, <module-name>, <persistence-context-ref>, <persistence-unit-ref>, <service-ref> - "above" what we can find in web.xml, Pax Web 8 supports: - ServletContainerInitializers (SCI) - proved by working JSF/Primefaces/Vaadin examples - web-fragment.xmls - annotated web elements (@WebServlet, @WebFilter, @WebListener) - META-INF/resources locations - websockets via HttpService and Whiteboard - web fragment scanning using tomcat-util-scanner - without any mention in any CMPN specification, JSPs, welcome-pages, security configurations are supported - no more xbean used to scan the "class space" - no more dependency to ASM - single configuration thread that operates on global model and synchronizes the model changes with the state of target runtime (Jetty, Tomcat, Undertow) - consistent structure of pax-web-jetty, pax-web-tomcat and pax-web-undertow: - there's single org.ops4j.pax.web.service.<runtime>.internal.<Runtime>ServerController class (per runtime) implementing org.ops4j.pax.web.service.spi.ServerController#sendBatch() method - org.ops4j.pax.web.service.spi.task.Batch is a sequence of "operations" that change the model or affect the runtime - there's single org.ops4j.pax.web.service.<runtime>.internal.<Runtime>ServerWrapper class (per runtime) that: - keeps an instance of the "server" (org.eclipse.jetty.server.Server, org.apache.catalina.core.StandardServer or io.undertow.server.HttpHandler + collection of org.xnio.channels.AcceptingChannels) - Pax Web 8 DOESN'T use easy-to-use io.undertow.Undertow class! - implements org.ops4j.pax.web.service.spi.task.BatchVisitor interface that's used to react to state-changing operations (like registration of a servlet) - mind that a "batch" may be "transactional" - each runtime bundle contains some overriden runtime classes (like org.ops4j.pax.web.service.jetty.internal.PaxWebFilterHolder that extends org.eclipse.jetty.servlet.FilterHolder) - Knowing that we have 3 "ways into" the Pax Web (HttpService, Whiteboard, WABs), Pax Web 8 introduces the concept of "the view of the WebContainer" - each "way" uses specific "view" to interact with Pax Web runtime - The model is greatly simplified comparing to Pax Web 7: - there exist "model" classes (like org.ops4j.pax.web.service.spi.model.elements.ServletModel) which are held internall and passed around between whiteboard, war, runtime and target container bundles - from Whiteboard perspective, the "incoming" services, like "javax.servlet.Servlet" or "org.osgi.service.http.context.ServletContextHelper" are "tracked into" the model classes, so whether the servlet is registered by HttpService, Whiteboard or through a WAB, its processing is consistent and there's no problem mixing WABs, Whiteboard and HttpService approaches - the "model" classes are divided into "web elements" and "web contexts" and each "web element" may reference one or many "web contexts" and the relation is dynamic - ... *Pax Web 8 example:* The most important use-case is: - user/bundle registers (Whiteboard approach) a servlet without specifying a "context" and the servlet has mapping "/my-servlet" - this servlet should be available at URL http://localhost:8181/my-servlet - another user/bundle registers a org.osgi.service.http.context.ServletContextHelper service with "osgi.http.whiteboard.context.path=/my-context" and " osgi.http.whiteboard.context.name=default" properties - *immediately* (asap) the first servlet should be available at http://localhost:8181/my-context/my-servlet and *no longer* it should be available at the first URL Yes, it works. Also shadowing may happen, because when two servlets are registered with the same name and target context, only the one with higher ranking/lower service.id should be available. There are many integration tests that show what happens when conflicting services are registered across different contexts. *Summary*: If you have some time, please checkout https://github.com/ops4j/org.ops4j.pax.web/tree/main, `mvn clean -DskipTests` it and give it a try. For example in Karaf 4.3.3 (after uncommenting "karaf" user in `etc/users.properties`) we can do: karaf@root()> repo-remove org.ops4j.pax.web-7.3.19 > Removing features repository: > mvn:org.ops4j.pax.web/pax-web-features/7.3.19/xml/features > karaf@root()> repo-add > mvn:org.ops4j.pax.web/pax-web-features/8.0.0-SNAPSHOT/xml/features > Adding feature url > mvn:org.ops4j.pax.web/pax-web-features/8.0.0-SNAPSHOT/xml/features > karaf@root()> feature:install pax-web-http-tomcat > karaf@root()> feature:install pax-web-war > karaf@root()> bundle:install > 'webbundle:mvn:io.hawt/hawtio-war/2.13.6/war?Web-ContextPath=/hawtio' > Bundle ID: 68 > karaf@root()> start 68 > Then you can log in to http://localhost:8181/hawtio using karaf/karaf credentials (JAAS based authentication) and then navigate to http://localhost:8181/hawtio/jmx/attributes?nid=root-Catalina-WebResourceRoot-localhost-%2FServletContextModel-3-Cache which shows cache configuration for the default (resource) servlet used by /hawtio WAB. kind regards and thanks for the patience ;) Grzegorz Grzybek