in Apache Tomcat, Java, Java EE

Modularity and plug-ability features in Servlet 3.0 specification with Tomcat 9

Modularity and plug-ability features in Servlet 3.0 specification is also called web fragments. The JSR 315 (Java Servlet 3.0 specification) is already 9 years old. The final release dates back to december 10, 2009.
https://jcp.org/en/jsr/detail?id=315
Web fragments are one of the main features of this JSR.
A web fragment is an XML file named web-fragment.xml and located inside the META-INF folder of a jar library.
The root element of this file must be :

<web-fragment>

Web fragments are XML files that will have part of the configurations of a web.xml file.

Here is a short and quick demonstration of it. First, create a web app project with the help of the maven-archetype-webapp archetype.

Here is the content of the web.xml of this first project :

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>
</web-app>

Now create a second project with the help of the maven-archetype-quickstart archetype. Add a resources folder under src/main and then create a META-INF folder under that resources folder. Finally add a new file called web-fragment.xml to that META-INF folder with the following content :

<?xml version="1.0" encoding="UTF-8"?>
<web-fragment xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns="http://java.sun.com/xml/ns/javaee"
              xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
              xsi:schemaLocation="http://java.sun.com/xml/ns/javaee/web-fragment_3_0.xsd"
              id="WebAppFragment_ID" version="3.0">
    <name>authentication-fragment</name>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Client</web-resource-name>
            <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>client</role-name>
        </auth-constraint>
    </security-constraint>

    <security-role>
        <role-name>client</role-name>
    </security-role>

    <login-config>
        <auth-method>FORM</auth-method>
        <realm-name>Client</realm-name>
        <form-login-config>
            <form-login-page>/login.jsp</form-login-page>
            <form-error-page>/login-error.jsp</form-error-page>
        </form-login-config>
    </login-config>

    <error-page>
        <error-code>404</error-code>
        <location>/home.jsp</location>
    </error-page>

</web-fragment>

Add this second project as a dependency in the first project :

...
	<dependency>
			<groupId>com.celinio</groupId>
			<artifactId>secondproject</artifactId>
			<version>0.0.1-SNAPSHOT</version>
		</dependency>
...

Now if we deploy the artefact mainproject.war to a web server such as Tomcat for instance, the following web.xml will be produced :

15-Dec-2018 18:42:12.960 INFO [main] org.apache.catalina.startup.HostConfig.deployWAR Deploying web application archive [E:\devJava\apache-tomcat-9.0.13\webapps\mainproject.war]
15-Dec-2018 18:42:13.194 INFO [main] org.apache.catalina.startup.ContextConfig.webConfig web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE web-app PUBLIC
  "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
  "http://java.sun.com/dtd/web-app_2_3.dtd">
<web-app>  <display-name>Archetype Created Web Application</display-name>




  <servlet>
    <servlet-name>default</servlet-name>
    <servlet-class>org.apache.catalina.servlets.DefaultServlet</servlet-class>
    <init-param>
      <param-name>listings</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>debug</param-name>
      <param-value>0</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet>
    <servlet-name>jsp</servlet-name>
    <servlet-class>org.apache.jasper.servlet.JspServlet</servlet-class>
    <init-param>
      <param-name>fork</param-name>
      <param-value>false</param-value>
    </init-param>
    <init-param>
      <param-name>xpoweredBy</param-name>
      <param-value>false</param-value>
    </init-param>
    <load-on-startup>3</load-on-startup>
  </servlet>

...
<security-constraint>
    <web-resource-collection>
      <web-resource-name>Client</web-resource-name>
      <url-pattern>%2F*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
      <role-name>client</role-name>
    </auth-constraint>
    <user-data-constraint>
      <transport-guarantee>NONE</transport-guarantee>
    </user-data-constraint>
  </security-constraint>

  <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>Client</realm-name>
    <form-login-config>
      <form-login-page>/login.jsp</form-login-page>
      <form-error-page>/login-error.jsp</form-error-page>
    </form-login-config>
  </login-config>

  <security-role>
    <role-name>client</role-name>
  </security-role>



</web-app>
With Tomcat 9, to view the content of the generated web.xml, it is necessary to add the logEffectiveWebXml attribute to the context tag in the context.xml file located under the conf folder and set it to true :
<?xml version="1.0" encoding="UTF-8"?>
<!-- The contents of this file will be loaded for each web application -->
<Context  logEffectiveWebXml="true">

    <!-- Default set of monitored resources. If one of these changes, the    -->
    <!-- web application will be reloaded.                                   -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    <WatchedResource>WEB-INF/tomcat-web.xml</WatchedResource>
    <WatchedResource>${catalina.base}/conf/web.xml</WatchedResource>

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!--
    <Manager pathname="" />
    -->
</Context>
During the deployment, the web server scans and treats the various web fragments that it might find. It will concatenate all the fragments to the main web.xml file. This is a simple demonstration. You might be wondering what might happen if there is more than one web fragment file and more precisely in which order will they be added to the generated web.xml. Well, to deal with that, the absolute-ordering tag was added :
<web-app>
...
<absolute-ordering>
   <name>MyFirstFragment</name>
   <name>MySecondFragment</name>
</absolute-ordering>
...
</web-app>

Finally, the web fragments can also contain ordering themselves with the use of the ordering tag :
<web-fragment>
<name>MyFirstFragment</name>
...
<ordering>
   <before>
   		<name>MySecondFragment</name>
   </before>
</ordering>
...
</web-app>

The code of this small demonstration is on my github account :
https://github.com/longbeach/webfragments.git