Cómo empezar con Servlet 4.0 – IBM Developer

Cómo empezar con Servlet 4.0

La API del Servlet de Java™ es un bloque de construcción fundamental del Java predominante por el lado del servidor, y forma parte de tecnologías Java EE, como JAX-RS para servicios web, JSF (JavaServer Faces) y JSP (JavaServer Pages). Los Servelts de Java también funcionan por sí mismos, brindando una gama de funciones que soportan el contenido web dinámico. Entre ellas, están filtros, seguridad web y funciones para manejar solicitudes y respuestas HTTP.

Servlet 4.0 es la versión más reciente de la API, y es una de las principales actualizaciones de la especificación de Java EE 8. Como aprenderá en este tutorial, el Servlet 4.0 está listo para HTTP/2 y adopta completamente el push del servidor, además lo amplía al tecnologías basadas en el servlet, como JSF 2.3. Este tutorial también le ayuda a empezar a utilizar la nueva interfaz HttpServletMapping, que permite realizar el descubrimiento en tiempo de ejecución de un URL de correlacionamiento del servlet.

Resumen de servlets

Un servlet de Java es una tecnología por el lado del servidor que se ejecuta sobre el protocol HTTP. Los servlets esperan a que el cliente envíe un mensaje de solicitud al servidor y después envían un mensaje de respuesta al cliente. Los mensajes de solicitud y de respuesta están formados por dos partes:

  • La cabecera contiene información acerca del mensaje.
  • El cuerpo contiene la carga útil del mensaje, es decir, el contenido.

En un intercambio típico, el cliente invoca un servlet solicitando un URL específico del navegador o de otro cliente HTTP, como curl.

En el Listado 1, el servlet se activa cuando se solicita su ruta. La solicitud se delega al método adecuado, que se determina mediante el método HTTP. En este caso, debido a que la solicitud era una solicitud del método GET, es manejada por el método doGet() del servlet de Java.

La ruta del servlet para el siguiente intercambio es: http://hostname/applicationroot/showlogoservlet.

Listing 1. Implementación de un servlet sencillo

@WebServlet("/showlogoservlet")
public class SimpleServlet extends HttpServlet {

   @Override
   protected void doGet(HttpServletRequest request,
                        HttpServletResponse response) 
                        throws ServletException, IOException {

       getServletContext()
         .getRequestDispatcher("/showlogo.jsp")
         .forward(request, response);

   }
}

Principales funciones nuevas de Servlet 4.0

Las principales funciones nuevas de Servlet 4.0 son el push del servidor y una nueva API que descubre las correlaciones de un URL del servlet durante el tiempo de ejecución.

El push del servidor es la mejora más visible de HTTP/2, y se expone al servlet a través de la interfaz PushBuilder . El push del servidor también está implementado en la API de JavaServer Faces y se invoca durante la fase del ciclo de vida de RenderResponsePhase para que las páginas JSF puedan aprovechar sus mejoras de rendimiento.

La nueva interfaz de descubrimiento de correlaciones del servlet, HttpServletMapping, permite que una infraestructura obtenga información acerca de un URL que activó determinada solicitud de un servlet. Es probable que esto tenga un uso específico para infraestructuras que necesiten esta información para sus trabajos internos.

En las siguientes secciones, brindaré una visión general del push del servidor y cómo funciona en los servlets de Java, incluyendo el push de servidor en JSF 2.3. También mostraré un intercambio de ejemplo que destaca la nueva función de descubrimiento de correlaciones del servlet.

El push de servidor en Servlet 4.0

El push de servidor permite que el servidor anticipe los requisitos de recursos de una solicitud del cliente. Después puede enviar esos recursos al cliente antes de que se finalice el proceso de la solicitud.

Para imaginar los beneficios del push del servidor, considere una página web que está formada por imágenes y otras dependencias como los archivos CSS y JavaScript. El cliente sólo hace una solicitud para la página web. Después, el servidor analiza la página solicitada, determina los recursos necesarios para representarla y los envía de forma proactiva a la caché del cliente.

Hace todo mientras está procesando la solicitud de la página web original. Para cuando el cliente recibe la respuesta, los recursos que necesita ya están en la caché.

PushBuilder

El servlet 4.0 expone el push de servidor a través de la interfaz PushBuilder. Para acceder, hay que obtener una instancia de PushBuilder desde HttpServletRequest, llamando al método newPushBuilder(). El listado 2 muestra cómo obtener una instancia de PushBuilder.

Listing 2. Cómo obtener un nuevo PushBuilder

@Override
protected void doGet(HttpServletRequest request, 
                     HttpServletResponse response) 
                     throws ServletException, IOException {

   PushBuilder pushBuilder = request.newPushBuilder();

}

Se devolverá una nueva instancia de PushBuilder por cada invocación del método newPushBuilder(). Si el push de servidor no está disponible, newPushBuilder() devolverá null. En algunos casos, el cliente puede rechazar un push de servidor para una transacción seleccionada. El push de servidor tampoco funcionará si el cliente no está utilizando una conexión segura. Por lo tanto, es importante asegurar que se realiza una prueba para el valor devuelto null antes de llamar a los métodos de la estancia PushBuilder .

Como su nombre indica, PushBuilder implementa el patrón del constructor. En esta implementación, la solicitud de push se construye encadenando juntos los métodos mutator. Estos métodos mutator configuran la instancia de PushBuilder estableciendo sus cabeceras HTTP, el tipo de método (GET es el único valor aceptable), la cadena de caracteres de la consulta, el ID de la sesión y la ruta de recursos (es decir, la ruta para el recurso que se enviará).

La mayoría de las cabeceras de la solicitud de la instancia de HttpServletRequest original simplemente se añaden a la instancia de PushBuilder. Ya que no son necesarias para el funcionamiento adecuado del push de servidor, no se incluyen las siguientes:

  • Cabeceras condicionales
  • Cabeceras de rango
  • Cabeceras esperadas
  • Cabeceras de autorización
  • Cabeceras de recomendante

Ahora, veamos cómo se construye y provoca una acción del push de servidor.

1. Configurar el recurso para el envío

La ruta es la única configuración que se deben establecer antes de enviar un recurso al cliente. Para establecer la ruta hay que llamar al método path(). Solo se debe llamar a este método una vez, ya que muta el valor de la ruta del objeto PushBuilder. La ruta puede empezar con una barra oblicua (“/”) para indicar que la ruta del recurso es una ruta absoluta; en caso contrario, se considera que la ruta del recurso es relativa a la ruta del contexto de la solicitud asociada. La ruta puede contener la cadena de caracteres de una consulta, que se fusionará con cualquier cadena de caracteres que el método queryString() establezca.

2. Enviar el recurso

Después, se llamará al método push(), que empuja el recurso al cliente. El método push() inicia la “conversación” push con el cliente. En segundo plano, el cliente recibe una estructura de PUSH_PROMISE , que actúa como una notificación de la intención de enviar el recurso. El cliente puede rechazar el recurso enviando de vuelta un RST_STREAM. Este mecanismo permite que el cliente conserve el control de cuáles son los recursos que recibe. Por lo tanto, el cliente está protegido, contra la sobrecarga con recursos que no quiere o que ya tiene en su caché.

Una vez que se ha obtenido una instancia de PushBuilder , se puede utilizar varias veces, tal como se muestra en el Listado 3. La ruta y las cabeceras condicionales se ponen como nulas, pero el resto de los campos se dejan como están. Éstos se pueden reutilizar en otro push de servidor.

Listing 3. Reutilizar una instancia de PushBuilder

PushBuilder pushBuilder = request.newPushBuilder();

if (pushBuilder != null) {
   pushBuilder.path("images/hero‑banner.jpg").push();
   pushBuilder.path("css/menu.css").push();
   pushBuilder.path("js/marquee.js").push();
}

En el Listado 3 la ruta para hero-banner.jpg se establece en la estancia de PushBuilder a través del método path() , y se envía al cliente llamando a push(). El método push() es no bloqueante, y devuelve la llamada inmediatamente para que más recursos—en este caso menu.css y marquee.js—se puedan enviar posteriormente.

Utilizar el push de servidor con JSF

JavaServer Faces ya identifica los requisitos de cada página como parte del ciclo de vida de su representación de la página, así que es perfecto para el server push. Mejor aún, desde la perspectiva de un desarrollador, no hay que hacer nada diferente para activar esta función. Se obtiene gratis con la actualización a JSF 2.3.

El listado 4 demuestra la integración de JSF y del push de servidor.

Listing 4. Utilizar el push de servidor en una página de JSF

<h:head>
   <h:outputStylesheet library="css" name="logo.css"/>
   <h:outputScript library="js" name="logo.js"/>
   <title>JSF 2.3 ServerPush Example</title>
</h:head>
<h:body>
   <h:form>
       <h:graphicImage library="images" name="logo.jpg"/>
   </h:form>
</h:body>
</html>

La página de JSF del Listado 4 requiere de tres recursos:

  • Un archivo CSS llamado logo.css.
  • Un archivo JavaScript llamadologo.js.
  • Una imagen llamada logo.jpg.

Esos recursos se enviarán uno por uno al cliente mientras el motor de JSF esté procesando y representando la página. Esto ocurre durante la fase de representación de la respuesta de JSF. El método ExternalContextImpl.encodeResourceURL() después se llama para cada recurso y se pasa al nuevo URL del recurso. Se obtiene un nuevo objeto PushBuilder de la instancia de HttpServletRequest que está asociada con el ExternalContext. Si es compatible con el push de servidor, el recurso se empuja al cliente antes de enviarle la página.

La interfaz de HttpServletMapping

La nueva API de descubrimiento de correlaciones del servlet del Servlet 4.0 permite que el servidor haga una verificación en tiempo de ejecución del URL que causó la invocación del servlet. Por ejemplo, una solicitud de file.ext, /path y /path/file.ext activará servlet con los patrones de URL /path/* y *.ext.

La interfaz de HttpServletMapping soporta el descubrimiento en tiempo de ejecución del URL de correlaciones de un servlet. Se puede obtener una instancia de la interfaz llamando a getHttpServletMapping() en una instancia de HttpServletRequest. Para obtener información acerca del URL de correlaciones de un servlet se pueden utilizar los siguientes métodos:

  • getMatchValue() devuelve la parte de la ruta del URI que causó el emparejamiento de la solicitud.
  • getPattern() devuelve la representación de String para el patrón del URL.
  • getServletName() devuelve la representación de String para el nombre del servlet.
  • getMappingMatch() devuelve el tipo de coincidencia representado como un valor enum de MappingMatch , que será uno de los siguientes: CONTEXT_ROOT, DEFAULT, EXACT, EXTENSIONo PATH.

El Listado 5 muestra los cuatro métodos de la API en acción.

Listing 5. Descubrimiento de correlaciones del servlet en tiempo de ejecución en el Servlet 4.0

@WebServlet({"/path/∗", "∗.ext"})
public class ServletMapping extends HttpServlet {

    protected void doGet(HttpServletRequest request,
                         HttpServletResponse response) 
                         throws IOException {

        HttpServletMapping mapping = request.getHttpServletMapping();
        String mapping = mapping.getMappingMatch().name();
        String value = mapping.getMatchValue();
        String pattern = mapping.getPattern();
        String servletName = mapping.getServletName();
   }

}

Cambios menores en el Servlet 4.0

Además del push de servidor y de la nueva interfaz HttpServletMapping , Servlet 4.0 incluye un puñado de cambios y de nuevas incorporaciones más pequeñas que merece la pena mencionar.

  1. La cabecera de respuesta Trailer permite que el remitente incluya campos adicionales al final de mensajes troceados. Esto se utiliza para suministrar metadatos que se pueden generar dinámicamente mientras se envía el cuerpo del mensaje, como una verificación de la integridad del mensaje, la firma digital o el estado después del proceso.
  2. Servlet 4.0 añade las clases abstractas GenericFilter y HttpFilter , que simplifican la escritura de filtros al brindar implementaciones mínimas a los métodos del ciclo de vida init() y destroy().
  3. Servlet 4.0 también integra el nuevo HTTP Trailer, que permite que el remitente incluya campos adicionales al final de un mensaje troceado.
  4. La interfaz ServletContext tiene nuevos métodos: addJspFile() añade el servlet con un determinado archivo JSP al contexto del servlet. getSessionTimeout() y setSessionTimeout() brindan acceso al límite temporal de la sesión. getRequestCharacterEncoding() y setRequestCharacterEncoding() brindan acceso y mutan la codificación predeterminada de los caracteres de la solicitud por la del contexto del servlet actual.
  5. El método isRequestedSessionIdFromUrl() de la interfaz HttpServletRequest se ha quedado obsoleto.
  6. Gracias a la mejora a Java SE 8, se añadieron métodos predeterminados a las interfaces del agente de escucha.

Conclusión

El Servlet 4.0 se lanzó principalmente para que integre el nuevo protocolo HTTP/2 y sus muchas funciones de mejora del rendimiento. La interfaz PushBuilder ofrece un control detallado sobre los recursos que se envían a un cliente, lo que derivó a interesantes implementaciones transversales. Como ejemplo, Jetty 9 implementó el push de servidor con la API de PushBuilder en su filtro web PushCacheFilter . Este filtro guarda recurso en la caché en su primera solicitud. Por lo tanto, es capaz de enviar más solicitudes al cliente, incluso mientras la primera solicitud se está procesando en el lado del servidor.

Aunque JSF 2.3 tiene incorporado el push de servidor, JavaServer Pages no lo tiene. La integración del push de servidor en JSF es de gran ayuda, lo que permite a los desarrolladores enfocarse menos en los trucos para mejorar el rendimiento y más en el diseño de páginas web dinámicas. Para los desarrolladores que quieran tener una funcionalidad similar en JSP, necesitan una solución a medida, como el filtro web PushCacheFilter de Jetty 9.