Gumdrop

Gumdrop Servlet Container

Gumdrop provides a complete, conformant Java Servlet 4.0 container as part of its multiserver framework. This document describes the architecture, configuration, and features of the servlet container.

Contents

Related Resources

Architecture

The servlet container was the original motivation for the Gumdrop project, first released in early 2005 as a complete implementation of the Servlet 2.4 API. At that time, mainstream enterprise servlet containers used blocking java.net.Socket implementations which directly linked the number of incoming TCP connections to threads in the JVM. This created a significant scalability bottleneck: a server with 1,000 concurrent connections required 1,000 threads, consuming memory and CPU resources for context switching. Practically, simultaneous client connections above this number were impossible.

Gumdrop was designed from the ground up to use non-blocking I/O via the then-new Java NIO Selector API. This architecture completely decouples the number of client connections from the number of servlet worker threads, which are drawn from a separate thread pool (ThreadPoolExecutorService) of configurable size.

Loose Coupling via Pipes

The servlet specification requires that servlets read request body data from an InputStream, a blocking API that doesn't naturally fit an event-driven architecture. Gumdrop solves this with a pipe-based multiplexing approach:

  1. I/O Worker Loops - A small pool of SelectorLoop threads handle all network I/O for all connections. When request body data arrives, it is written to a pipe associated with that request.
  2. Servlet Worker Pool - A separate thread pool services servlet requests. Each servlet thread reads request body data from the pipe's input stream, which blocks only until data is available.
  3. Asynchronous Support - For Servlet 3.1+ asynchronous processing, servlets can register a ReadListener to be notified when data becomes available, avoiding blocking entirely.

This design means that even with tens of thousands of concurrent connections, the server requires only a small number of threads: the I/O worker pool (defaulting to twice the number of processors) plus the servlet worker pool (configured separately). Both pools are independent of connection count.

Request Flow

Servlet Container Request Flow Diagram

Asynchronous Processing

Gumdrop provides complete Servlet 3.0+ asynchronous processing support, allowing servlets to perform long-running operations without blocking worker threads. This is particularly valuable for applications that need to wait for external resources (databases, remote APIs, message queues) while maintaining high throughput.

How Async Processing Works

When a servlet calls request.startAsync(), Gumdrop:

  1. Releases the worker thread - The servlet worker thread returns to the pool immediately after the service() method completes, freeing it to handle other requests.
  2. Schedules a timeout - A configurable timeout (default 30 seconds) is set. If the async context is not completed before timeout, listeners are notified and an error response is sent.
  3. Maintains the connection - The underlying I/O connection remains open and managed by the SelectorLoop, ready to send the response when the application completes processing.

Async Context API

The AsyncContext provides methods for completing or re-dispatching the request:

Non-Blocking I/O

Servlet 3.1 introduced non-blocking I/O through the ReadListener and WriteListener interfaces. Gumdrop implements these by integrating with the underlying SelectorLoop event system:

// Example: Non-blocking read
input.setReadListener(new ReadListener() {
    public void onDataAvailable() throws IOException {
        while (input.isReady()) {
            int b = input.read();
            // process byte
        }
    }
    
    public void onAllDataRead() throws IOException {
        asyncContext.complete();
    }
    
    public void onError(Throwable t) {
        // handle error
    }
});

Error Handling and Telemetry

Async processing integrates with Gumdrop's telemetry system. Errors during async processing are recorded in OpenTelemetry spans with appropriate ErrorCategory classification:

Async Processing Flow

Async Servlet Processing Flow Diagram

Async Configuration

To enable async support for a servlet, set async-supported in the deployment descriptor or use the @WebServlet annotation:

<servlet>
  <servlet-name>AsyncServlet</servlet-name>
  <servlet-class>com.example.AsyncServlet</servlet-class>
  <async-supported>true</async-supported>
</servlet>

Or using annotations:

@WebServlet(urlPatterns = "/async", asyncSupported = true)
public class AsyncServlet extends HttpServlet {
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        AsyncContext ctx = req.startAsync();
        ctx.start(new Runnable() {
            public void run() {
                // Perform async work
                resp.getWriter().println("Async response");
                ctx.complete();
            }
        });
    }
}

Note that all filters in the filter chain must also have async-supported=true for the servlet to use async processing.

Servlet 4.0 Features

Gumdrop implements the Servlet 4.0 specification, providing modern HTTP features that leverage HTTP/3 and HTTP/2 capabilities. These features work transparently with Gumdrop’s HTTP Server Handler API.

HTTP/2 Server Push (PushBuilder)

Server push allows the server to proactively send resources to the client before they are explicitly requested. This is particularly effective for pushing CSS, JavaScript, or images that the server knows the client will need.

@WebServlet("/page")
public class PageServlet extends HttpServlet {
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        
        // Push the stylesheet before sending the HTML
        PushBuilder pushBuilder = req.newPushBuilder();
        if (pushBuilder != null) {
            pushBuilder.path("/css/styles.css").push();
            pushBuilder.path("/js/app.js").push();
        }
        
        // Now send the HTML page
        resp.setContentType("text/html");
        resp.getWriter().println("<html>...");
    }
}

The newPushBuilder() method returns null if:

When a push promise is sent, the pushed resource is processed through the same servlet container pipeline as a normal request, allowing the pushed response to benefit from filters, security constraints, and caching.

HTTP Trailer Headers

HTTP trailers are headers sent after the message body. They are useful for sending metadata that is computed during body transmission, such as checksums or signatures. Gumdrop supports trailers for both HTTP/1.1 (chunked encoding) and HTTP/2.

@WebServlet("/upload")
public class UploadServlet extends HttpServlet {
    
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        
        MessageDigest digest = MessageDigest.getInstance("SHA-256");
        
        // Declare which trailers will be sent
        resp.setTrailerFields(() -> {
            Map<String, String> trailers = new HashMap<>();
            trailers.put("X-Content-SHA256", Base64.getEncoder()
                .encodeToString(digest.digest()));
            return trailers;
        });
        
        // Stream response while computing checksum
        OutputStream out = resp.getOutputStream();
        // ... write body, updating digest ...
        
        // Trailers are sent automatically when response completes
    }
}

Request trailers can be accessed after the request body has been fully read:

if (req.isTrailerFieldsReady()) {
    Map<String, String> trailers = req.getTrailerFields();
    String checksum = trailers.get("x-content-checksum");
}

WebSocket Upgrade

Servlets can upgrade HTTP connections to WebSocket using the standard HttpUpgradeHandler API. Gumdrop bridges the Servlet API's blocking I/O model to its event-driven WebSocket implementation.

@WebServlet("/websocket")
public class WebSocketServlet extends HttpServlet {
    
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) 
            throws ServletException, IOException {
        
        // Check for WebSocket upgrade request
        if ("websocket".equalsIgnoreCase(req.getHeader("Upgrade"))) {
            req.upgrade(MyWebSocketHandler.class);
        } else {
            resp.sendError(HttpServletResponse.SC_BAD_REQUEST);
        }
    }
}

public class MyWebSocketHandler implements HttpUpgradeHandler {
    
    private WebConnection connection;
    
    @Override
    public void init(WebConnection wc) {
        this.connection = wc;
        // Connection is now upgraded - start handling WebSocket frames
        // via the WebConnection's input/output streams
    }
    
    @Override
    public void destroy() {
        // Clean up resources
    }
}

For most WebSocket applications, consider using Gumdrop’s native WebSocket API directly, which provides a simpler event-driven model. The Servlet upgrade API is primarily useful for applications that need to maintain Servlet API compatibility.

Servlet Mapping API

The HttpServletMapping interface provides information about how the current request was mapped to a servlet:

HttpServletMapping mapping = req.getHttpServletMapping();
String matchValue = mapping.getMatchValue();      // matched part of URL
String pattern = mapping.getPattern();            // URL pattern used
String servletName = mapping.getServletName();    // servlet name
MappingMatch matchType = mapping.getMappingMatch(); // EXACT, PATH, EXTENSION, DEFAULT

This is particularly useful for servlets mapped with wildcards that need to determine which specific resource was requested.

Container and Context Configuration

Service Properties

org.bluezoo.gumdrop.servlet.ServletService is the HTTP application service for the servlet container. Container properties, contexts, and listeners are all configured directly on the <service> element:

The servlet worker pool is distinct from the I/O worker loops, allowing independent tuning based on workload characteristics.

Because the servlet container is an HTTP service, it inherits Gumdrop’s full transport and protocol independence layer. This means the servlet container can serve applications over HTTP/3 (QUIC), HTTP/2, and HTTP/1.1 simply by configuring the appropriate listeners. Adding an HTTP3Listener alongside an HTTPListener is all that is required to enable HTTP/3 for servlet applications:

<service id="web" class="org.bluezoo.gumdrop.servlet.ServletService">
  <context path="" root="web"/>
  <listener class="org.bluezoo.gumdrop.http.HTTPListener">
    <property name="port">443</property>
    <property name="secure">true</property>
    <property name="keystore-file">keystore.p12</property>
    <property name="keystore-pass">changeit</property>
  </listener>
  <listener class="org.bluezoo.gumdrop.http.h3.HTTP3Listener">
    <property name="port">443</property>
    <property name="cert-file">cert.pem</property>
    <property name="key-file">key.pem</property>
  </listener>
</service>

Mainstream servlet containers such as Apache Tomcat, GlassFish, and Undertow do not support HTTP/3 natively, typically requiring a reverse proxy to terminate QUIC connections. Gumdrop’s architecture makes this unnecessary: servlets, filters, and JSP pages operate identically regardless of the underlying HTTP version, benefiting from HTTP/3’s reduced latency and elimination of head-of-line blocking without any code changes.

The servlet container also benefits from HTTP/2 features including HPACK header compression, stream multiplexing, flow control, and server push, as well as chunked encoding, HTTPS, and OpenTelemetry integration. See the HTTP documentation for details on the underlying HTTP implementation.

Context Configuration

Define web applications as <context> elements directly inside the <service>:

<service id="web" class="org.bluezoo.gumdrop.servlet.ServletService">
  <context path="" root="web"/>
  <context path="/app" root="myapp.war" distributable="true"/>
  <listener class="org.bluezoo.gumdrop.http.HTTPListener">
    <property name="port">8080</property>
  </listener>
</service>

Configuring Realms

Realms provide authentication and authorisation for protected resources. Configure realms on the service and reference them in web application login-config elements:

<realm id="myRealm" class="org.bluezoo.gumdrop.auth.BasicRealm">
  <property name="href">myRealm.xml</property>
</realm>

<service id="web" class="org.bluezoo.gumdrop.servlet.ServletService">
  <property name="realms">
    <map>
      <entry key="myRealm" ref="#myRealm"/>
    </map>
  </property>
  <context path="" root="web"/>
  ...
</service>

The BasicRealm reads users, passwords, and roles from an XML file. Custom realm implementations can integrate with LDAP, databases, or other authentication backends.

Cluster Session Replication

Web applications marked as distributable participate in session replication across cluster nodes. When a session attribute is modified, the change is broadcast to other nodes via UDP multicast, allowing any node to service requests for that session.

How It Works

Gumdrop uses a UDP multicast protocol to replicate session data:

  1. When setAttribute is called on a distributed session, the container serializes the session attribute and broadcasts it to the cluster multicast group.
  2. Other nodes receive the message, authenticate and decrypt it, then update their local copy of the session.
  3. Session invalidation and timeout events are also replicated.

Security Features

Session replication uses AES-256-GCM encryption with a shared secret key. All cluster traffic is authenticated and encrypted. The protocol includes:

Network Considerations

Multicast traffic respects network boundaries but relies on proper network segmentation. Cluster nodes should be deployed on an isolated network segment or VLAN. The shared secret key must be distributed securely to all nodes via the cluster-key service property.

Telemetry

The cluster node will publish telemetry metrics if telemetry is enabled.

Hot Deployment

Unless disabled, the servlet container monitors web applications for changes and automatically redeploys them when modifications are detected. This enables rapid development cycles without manual server restarts.

File Monitoring

Gumdrop uses the Java NIO WatchService API (introduced in Java 7) to monitor the filesystem for changes. This provides efficient, event-based notification rather than polling:

Redeployment Process

When a change is detected:

  1. Active requests are allowed to complete
  2. The context's classloader is closed, releasing loaded classes
  3. The deployment descriptor is re-parsed
  4. A new classloader is created for the context
  5. Servlets, filters, and listeners are re-initialised

Session data is preserved across redeployments when possible.

Deployment Descriptors

Gumdrop supports the standard web.xml deployment descriptor format through Servlet 4.0, including:

Core Elements

Gumdrop-Specific Context Parameters

The following context parameters control Gumdrop container behaviour:

<context-param>
  <param-name>org.bluezoo.gumdrop.show-stack-traces</param-name>
  <param-value>false</param-value>
</context-param>

Security Elements

Advanced Features

Annotations

Gumdrop supports annotation-driven configuration as specified in Servlet 3.0+:

Annotations are processed during context initialisation by scanning classes in WEB-INF/classes and JAR files in WEB-INF/lib.

Web Fragments

Library JAR files may include META-INF/web-fragment.xml to contribute servlets, filters, and listeners. Fragments are merged with the main deployment descriptor according to ordering rules.

JNDI Resources

Gumdrop supports Java Naming and Directory Interface (JNDI) resources that can be configured externally and looked up by web applications at runtime. This allows configuration data, database connections, mail sessions, and messaging resources to be managed by the container rather than hardcoded in application code.

Resources are defined in gumdroprc and bound to the container's JNDI naming tree. Web applications reference these resources in their deployment descriptors using resource-ref, resource-env-ref, or through annotation-based injection.

DataSource (JDBC Connection Pooling)

The data-source element defines a JDBC DataSource with built-in connection pooling. Gumdrop manages a pool of database connections that are reused across requests, reducing connection overhead.

<data-source name="jdbc/myDB"
             class-name="org.postgresql.Driver"
             server-name="localhost"
             port-number="5432"
             database-name="myapp"
             user="dbuser"
             password="dbpass"
             initial-pool-size="5"
             min-pool-size="5"
             max-pool-size="20"
             max-idle-time="300"/>

DataSource properties:

Gumdrop recognises common JDBC driver classes and automatically constructs the connection URL from the server, port, and database properties. Supported drivers include PostgreSQL, MySQL/MariaDB, Oracle, SQL Server, DB2, Derby, SQLite, and H2.

Reference in deployment descriptor:

<resource-ref>
  <res-ref-name>jdbc/myDB</res-ref-name>
  <res-type>javax.sql.DataSource</res-type>
  <res-auth>Container</res-auth>
</resource-ref>

Usage in servlet code:

Context ctx = new InitialContext();
DataSource ds = (DataSource) ctx.lookup("java:comp/env/jdbc/myDB");
Connection conn = ds.getConnection();
try {
    // Use connection
} finally {
    conn.close(); // Returns to pool
}

Mail Session (JavaMail)

The mail-session element defines a JavaMail Session for sending and receiving email. The session is pre-configured with server details and authentication credentials.

<mail-session name="mail/smtp"
              host="smtp.example.com"
              user="mailuser"
              password="mailpass"
              from="noreply@example.com"
              transport-protocol="smtp"
              store-protocol="imap">
  <property name="mail.smtp.port" value="587"/>
  <property name="mail.smtp.starttls.enable" value="true"/>
</mail-session>

Mail session properties:

Additional JavaMail properties can be specified using nested property elements. Common properties include STARTTLS enablement, port numbers, and SSL configuration.

Usage in servlet code:

Context ctx = new InitialContext();
Session session = (Session) ctx.lookup("java:comp/env/mail/smtp");
MimeMessage msg = new MimeMessage(session);
msg.setRecipients(Message.RecipientType.TO, "user@example.com");
msg.setSubject("Hello");
msg.setText("Message body");
Transport.send(msg);

JMS Connection Factory

The jms-connection-factory element defines a JMS ConnectionFactory for messaging. This requires a JMS provider implementation in the classpath.

<jms-connection-factory name="jms/ConnectionFactory"
                        class-name="org.apache.activemq.ActiveMQConnectionFactory"
                        user="jmsuser"
                        password="jmspass"
                        client-id="gumdrop-client">
  <property name="broker-url" value="tcp://localhost:61616"/>
</jms-connection-factory>

JMS connection factory properties:

JMS Destination

The jms-destination element defines a JMS queue or topic.

<jms-destination name="jms/queue/OrderQueue"
                 class-name="org.apache.activemq.command.ActiveMQQueue">
  <property name="physical-name" value="OrderQueue"/>
</jms-destination>

<jms-destination name="jms/topic/Notifications"
                 class-name="org.apache.activemq.command.ActiveMQTopic">
  <property name="physical-name" value="Notifications"/>
</jms-destination>

The interface type (javax.jms.Queue or javax.jms.Topic) is inferred from the JNDI name prefix (queue/ or topic/) if not explicitly specified.

Environment Entries

Environment entries (env-entry) provide simple configuration values to web applications. These are defined in the deployment descriptor rather than gumdroprc.

<env-entry>
  <env-entry-name>maxItemsPerPage</env-entry-name>
  <env-entry-type>java.lang.Integer</env-entry-type>
  <env-entry-value>25</env-entry-value>
</env-entry>

<env-entry>
  <env-entry-name>adminEmail</env-entry-name>
  <env-entry-type>java.lang.String</env-entry-type>
  <env-entry-value>admin@example.com</env-entry-value>
</env-entry>

Supported types include java.lang.String, java.lang.Integer, java.lang.Long, java.lang.Double, java.lang.Float, java.lang.Boolean, and java.lang.Character.

JCA Administered Objects

The administered-object element defines arbitrary managed objects for Java Connector Architecture (JCA) integration. These are instantiated by Gumdrop and bound to JNDI with properties set via JavaBean conventions.

<administered-object jndi-name="custom/MyConfig"
                     administered-object-class="com.example.ConfigBean"
                     administered-object-interface="com.example.Config">
  <property name="server-url" value="https://api.example.com"/>
  <property name="timeout" value="30000"/>
  <property name="enable-cache" value="true"/>
</administered-object>

Resource Injection

Servlet 3.0+ supports annotation-based resource injection. Annotate fields or setter methods with @Resource and Gumdrop will inject the resource automatically:

@WebServlet("/orders")
public class OrderServlet extends HttpServlet {

    @Resource(name = "jdbc/myDB")
    private DataSource dataSource;

    @Resource(name = "mail/smtp")
    private Session mailSession;

    @Resource(name = "maxItemsPerPage")
    private int pageSize;

    protected void doGet(HttpServletRequest req, HttpServletResponse resp) {
        Connection conn = dataSource.getConnection();
        // ...
    }
}

For injection to work, the resource must either be defined in gumdroprc (for DataSources, mail sessions, etc.) or in the deployment descriptor (for environment entries).

JAX-WS and JAX-RS

Gumdrop’s servlet container can host JAX-WS SOAP and JAX-RS REST web services without any container modifications or additional J2EE dependencies. Both are deployed as standard servlets: add an implementation to your web application’s WEB-INF/lib, configure the servlet in web.xml, and Gumdrop dispatches requests to it like any other servlet.

Gumdrop does not bundle JAX-WS or JAX-RS implementations. Applications that need web services include Metro, CXF, Jersey, or RESTEasy in their WAR; this keeps the container lean and lets you choose the implementation and version.

JAX-WS (SOAP)

Metro (JAX-WS Reference Implementation)

Add Metro JARs to WEB-INF/lib (e.g. jaxws-rt and its transitive dependencies from Maven Central). Configure the servlet and context listener in web.xml:

<servlet>
  <servlet-name>MyService</servlet-name>
  <servlet-class>com.sun.xml.ws.transport.http.servlet.WSServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>MyService</servlet-name>
  <url-pattern>/services/*</url-pattern>
</servlet-mapping>
<listener>
  <listener-class>com.sun.xml.ws.transport.http.servlet.WSServletContextListener</listener-class>
</listener>

Define endpoints in WEB-INF/sun-jaxws.xml. Metro generates WSDL dynamically at runtime.

Apache CXF (JAX-WS)

Add CXF JARs to WEB-INF/lib. Configure the CXF servlet:

<servlet>
  <servlet-name>CXFServlet</servlet-name>
  <servlet-class>org.apache.cxf.transport.servlet.CXFServlet</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>CXFServlet</servlet-name>
  <url-pattern>/services/*</url-pattern>
</servlet-mapping>

Configure endpoints via CXF’s cxf.xml or Spring configuration in WEB-INF/cxf-beans.xml, or use CXF’s programmatic API.

JAX-RS (REST)

Jersey (JAX-RS Reference Implementation)

Add Jersey JARs to WEB-INF/lib (e.g. jersey-container-servlet and its dependencies from Maven Central). Configure the servlet:

<servlet>
  <servlet-name>JerseyServlet</servlet-name>
  <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class>
  <init-param>
    <param-name>javax.ws.rs.Application</param-name>
    <param-value>com.example.MyApplication</param-value>
  </init-param>
</servlet>
<servlet-mapping>
  <servlet-name>JerseyServlet</servlet-name>
  <url-pattern>/api/*</url-pattern>
</servlet-mapping>

Alternatively, use jersey.config.server.provider.packages to scan a package for @Path resource classes.

RESTEasy

Add RESTEasy JARs to WEB-INF/lib. Configure the servlet:

<servlet>
  <servlet-name>ResteasyServlet</servlet-name>
  <servlet-class>org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher</servlet-class>
</servlet>
<servlet-mapping>
  <servlet-name>ResteasyServlet</servlet-name>
  <url-pattern>/api/*</url-pattern>
</servlet-mapping>

RESTEasy discovers resources via @ApplicationPath or resteasy.servlet.mapping.prefix, or configure an Application subclass.

Apache CXF (JAX-RS)

CXF also implements JAX-RS. Use the same CXFServlet as for JAX-WS; configure JAX-RS endpoints in cxf.xml or cxf-beans.xml. CXF can serve both SOAP and REST from the same application.

Notes

JavaServer Pages

Gumdrop includes a comprehensive JSP 2.0+ implementation providing server-side template rendering for web applications. The implementation supports the complete JSP specification including scripting elements, directives, standard actions, expression language, and custom tag libraries.

Compilation Architecture

JSP pages are compiled to Java servlets on first access and cached for subsequent requests. Gumdrop uses an in-memory compilation architecture that eliminates temporary file I/O:

  1. Parsing - The JSP source is parsed by either the traditional JSP parser (for .jsp files with <% %> syntax) or the XML parser (for .jspx files with pure XML syntax). The result is an abstract syntax tree of JSP elements.
  2. Code Generation - A code generator traverses the AST and produces Java servlet source code. Line number mappings are maintained for accurate error reporting.
  3. In-Memory Compilation - The generated Java source is compiled directly in memory using the javax.tools.JavaCompiler API. No temporary .java files are written to disk.
  4. Class Loading - The compiled bytecode is loaded by a custom classloader that serves the class directly from memory.

This approach improves performance and security by avoiding filesystem writes, and simplifies deployment since no writable temporary directory is required.

Dependency Tracking and Hot Reload

In development mode, Gumdrop monitors JSP files for changes and automatically recompiles them when modifications are detected. The dependency tracker maintains relationships between JSP files and their includes:

The hot reload feature uses Java NIO's WatchService for efficient filesystem monitoring without polling.

Expression Language (EL)

Gumdrop implements EL 3.0 for accessing application data within JSP pages. The expression evaluator supports:

Tag Libraries

Custom tag libraries extend JSP functionality through reusable components. Gumdrop supports:

Tag libraries are discovered from TLD files in WEB-INF, WEB-INF/lib/*.jar!/META-INF, and via <taglib> declarations in the deployment descriptor.

JSP Configuration

The jsp-config element in web.xml controls JSP processing for groups of pages:

<jsp-config>
  <taglib>
    <taglib-uri>http://example.com/tags</taglib-uri>
    <taglib-location>/WEB-INF/tlds/example.tld</taglib-location>
  </taglib>
  
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
    <page-encoding>UTF-8</page-encoding>
    <scripting-invalid>false</scripting-invalid>
    <el-ignored>false</el-ignored>
    <is-xml>false</is-xml>
    <include-prelude>/WEB-INF/jspf/header.jspf</include-prelude>
    <include-coda>/WEB-INF/jspf/footer.jspf</include-coda>
    <trim-directive-whitespaces>true</trim-directive-whitespaces>
    <default-content-type>text/html; charset=UTF-8</default-content-type>
    <buffer>16kb</buffer>
  </jsp-property-group>
</jsp-config>

Property group options:

Precompilation

For production deployments, JSP pages can be precompiled at build time using the JSPPrecompiler utility:

java org.bluezoo.gumdrop.servlet.jsp.JSPPrecompiler \
    -webapp /path/to/webapp \
    -output /path/to/classes \
    -package org.example.jsp \
    -threads 4 \
    -verbose

Precompilation benefits include faster startup time (no compilation on first request), early detection of JSP syntax errors, and reduced runtime memory usage (no compiler in memory). The precompiler supports parallel compilation for large applications.

Error Reporting

When JSP compilation fails, Gumdrop maps Java compilation errors back to the original JSP source locations. Error messages include the JSP filename, line number, and column position, making it easy to locate and fix problems.

Examples

For practical examples demonstrating JSP features including scriptlets, expressions, directives, JSTL usage, custom tags, and EL expressions, see the JSP Examples page.


← Back to Main Page | HTTP Server & Client | WebSocket Service & Client | SMTP Server & Client | IMAP Server | POP3 Server | Telemetry

Gumdrop Servlet Container