Jetty not routing to servlet when web application in sub directory of webapps

10,246

Solution 1

In order to correctly deploy Java Web application to some Application Server or just simple Web Container (like in your case), the web app (also called web module) MUST have a specific structure. The top-level directory of a web module is the document root of the application.

Here is a Web Module Structure:

enter image description here

Now, what you define in <url-pattern> in web.xml file it is just a logical / virtual path for some servlet. Again, it is NOT a real path to the physical location of the servlet class, but a logical path - you make it up as you wish.

OK, now you must put your webapp with the right structure right in the webapps directory. For example, in the above picture Assembly Root symbolizes your webapp folder. So you take that folder either directly or you can make a WAR (Web application ARchive) and put it right under webapps directory. It's not that in webapps you have some directory and in that direcory there are several webapps. All web apps must be right under webapps directory.

So in your case, if your webapp folder has a name shlaa, you must put that folder right under webapp. Period.

Now quote from the official Java EE docs:

Mapping URLs to Web Components

When it receives a request, the web container must determine which web component should handle the request. The web container does so by mapping the URL path contained in the request to a web application and a web component. A URL path contains the context root and, optionally, alias:

http://host:port/context-root/alias

Setting the Component Alias

The alias identifies the web component that should handle a request. The alias path must start with a forward slash (/) and end with a string or a wildcard expression with an extension (for example, *.jsp). Since web containers automatically map an alias that ends with *.jsp, you do not have to specify an alias for a JSP page unless you wish to refer to the page by a name other than its file name.

In your case, the URL to your webapp will be http://localhost:8080/shlaa

Now qoute from the Jetty wiki docs (Jetty/Howto/SetContextPathto):

Using the WebAppProvider

The WebAppProvider's role is to look in the ${jetty.home}/webapps/ directory for any deployable applications (such as *.war), and deploy them onto a context of the same name as the filename. For example, the WebAppProvider deploys ${jetty.home}/webapps/MyApp-2.4.war into the context /MyApp-2.4. There is also the special root.war reserved word that deploys into the context / . While this is the easiest deployment mechanism, it sacrifices control over deployment specifics.

To make the long story short just place your web app right under webapps directory to make everything work. As for the <url-pattern> - feel free to define whatever patter you like.

NOTE: actually the are several ways to configure Jetty, i.e. XML configuration is not the only one. See Configuring Jetty for the details.

Quote from The Java™ Servlet SpecificationVersion 3.0:

Chapter 12

Mapping Requests to Servlets

12.1 Use of URL Paths

Upon receipt of a client request, the Web container determines the Web application to which to forward it. The Web application selected must have the longest context path that matches the start of the request URL. The matched part of the URL is the context path when mapping to servlets. The Web container next must locate the servlet to process the request using the path mapping procedure described below. The path used for mapping to a servlet is the request URL from the request object minus the context path and the path parameters. The URL path mapping rules below are used in order. The first successful match is used with no further matches attempted:
  1. The container will try to find an exact match of the path of the request to the path of the servlet. A successful match selects the servlet.

  2. The container will recursively try to match the longest path-prefix. This is done by stepping down the path tree a directory at a time, using the ’/’ character as a path separator. The longest match determines the servlet selected.

  3. If the last segment in the URL path contains an extension (e.g. .jsp), the servlet container will try to match a servlet that handles requests for the extension. An extension is defined as the part of the last segment after the last ’.’ character.

  4. If neither of the previous three rules result in a servlet match, the container will attempt to serve content appropriate for the resource requested. If a "default" servlet is defined for the application, it will be used. Many containers provide an implicit default servlet for serving content. The container must use case-sensitive string comparisons for matching.

12.2 Specification of Mappings

In the Web application deployment descriptor, the following syntax is used to define mappings:

  • A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.

  • A string beginning with a ‘*.’ prefix is used as an extension mapping.

  • The empty string ("") is a special URL pattern that exactly maps to the application's context root, i.e., requests of the form http://host:port/<contextroot>/. In this case the path info is ’/’ and the servlet path and context path is empty string (““).

  • A string containing only the ’/’ character indicates the "default" servlet of the application. In this case the servlet path is the request URI minus the context path and the path info is null.

  • All other strings are used for exact matches only.

Example with your names.

Your webapp name is mapapp (it's the application root). You want your CommentController.do to be accessed via

http://localhost:8080/mapapp/shlaa/CommentController.do

Then (if all other requiremants like directory structure etc are met) in your web.xml you put the following:

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
                        http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <servlet>
        <servlet-name>Comment Controller</servlet-name>
        <servlet-class>com.example.CommentController</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>Comment Controller</servlet-name>
        <url-pattern>/shlaa/CommentController.do</url-pattern>
    </servlet-mapping>

</web-app>

The first forward slash (/) in the above url-pattern symbolizes context root / context path (mapapp in this case).
This way it will work.


Here are some usefull links.

The Java EE 5 Tutorial:

The Java EE 6 Tutorial:

Jetty

Hope this will help you.


UPDATE

For the Jetty specific configuration see this link:
How to have a web app respond only on a specific port

Solution 2

Here's what I think is happening.

Just cloning your application shlaa in both the webapps root and the webapps/mapapp will not clone your servlets to a new location.

The static content works because those files are actually present at that location and Jetty will serve them given the right location

For servlets, the server will recognize only one location, the one inside shlaa/web/WEB-INF/classes (since you cloned your app, I assume your clone will be something like shla/mapapp/web/WEB-INF/classes)

What you have to do is just modify your web.xml so that shlaa/mapapp is also recognized

e.g : (try some combination of below)

<servlet-mapping>
    <servlet-name>CommentController</servlet-name>
    <url-pattern>/mapapp/CommentController.do</url-pattern>
</servlet-mapping>
Share:
10,246
Peter Campbell
Author by

Peter Campbell

An application Developer with a background in .Net and SQL Server Database development

Updated on June 12, 2022

Comments

  • Peter Campbell
    Peter Campbell about 2 years

    I have a web application that is functioning properly (servlets called) when I place the application folder in the {JETTY_HOME}/webapps directory.

    If I place a copy of the web application in a sub folder of webapps, then all the static files are called when I browse to the site, but the servlets that I call via ajax are returning 404.

    http://localhost/shlaa
    
    • calls /shlaa/CommentController.do correctly with no error.
    http://localhost/mapapp/shlaa
    • returns 404 for the ajax call /mapapp/shlaa/CommentController.do

      web.xml in both paths /WEB_INF folders contains the following

      <servlet>
          <servlet-name>CommentController</servlet-name>
          <servlet-class>web.CommentController</servlet-class>
      </servlet>
      <servlet-mapping>
          <servlet-name>CommentController</servlet-name>
          <url-pattern>/CommentController.do</url-pattern>
      </servlet-mapping>
      

      The jetty.xml folder in {JETTY_HOME}/etc contains the following:

       <Call class="org.mortbay.jetty.webapp.WebAppContext" name="addWebApplications">
            <Arg><Ref id="contexts"/></Arg>
              <Arg><SystemProperty name="jetty.home" default="."/>/webapps</Arg>
            <Arg><SystemProperty name="jetty.home" default="."/>/etc/webdefault.xml</Arg>
            <Arg type="boolean">True</Arg>  <!-- extract -->
            <Arg type="boolean">True</Arg> <!-- parent priority class loading -->
        </Call> 
      
    • Zenil
      Zenil over 11 years
      I noticed the .do extension in your servlet pattern. Are you using struts by any chance ?
    • Zenil
      Zenil over 11 years
      Also you said localhost/shlaa calls /mapapp/shlaa/CommentController.do correctly with no error. Can you share the configuration for that ? I am curious how that's working
    • Peter Campbell
      Peter Campbell over 11 years
      @Zenil no not using struts - just got into the habit of ending servlets references with this.
    • Peter Campbell
      Peter Campbell over 11 years
      @Zenil I have placed a cloned application of shlaa in both the webapps root and the webapps/mapapp directory,I have corrected the reference above
    • Zenil
      Zenil over 11 years
      In the first case you said it works correctly : localhost/shlaa calls /mapapp/shlaa/CommentController.do . I was wondering how that's working. Whats your web.xml configuration for that ?
    • Peter Campbell
      Peter Campbell over 11 years
      Sorry for the confusion - localhost/shlaa correctly calls /shlaa/CommentController.do, if I browse to localhost/shlaa/CommentController.do. In the application there is an ajax call that does an http get for CommentController.do on page load.
    • Zenil
      Zenil over 11 years
      That makes sense . Thanks for the clarification.
  • Peter Campbell
    Peter Campbell over 11 years
    cloned application is in path webapps/mapapp/shlaa, I have amended the url-pattern for CommentController in webapps\mapapp\shlaa\WEB-INF\web.xml to /mapapp/shlaa/CommentController.do and I am still getting a 404 when browsing to localhost/mapapp/shlaa/CommentController.do
  • Zenil
    Zenil over 11 years
    @peter shouldn't you try localhost/shlaa/mapapp/CommentController.do ?
  • Peter Campbell
    Peter Campbell over 11 years
    No because the folder structure is webapp - mapapp - shlaa
  • Zenil
    Zenil over 11 years
    @peter I thought slaa was your main web application folder. Since mapapp is your main folder, you should put /shlaa/CommentController.do as the url pattern in your web.xml
  • Peter Campbell
    Peter Campbell over 11 years
    /shlaa/CommentController.do as the url pattern, also returns a 404 when browsing to localhost/mapapp/shlaa/CommentController.do
  • Zenil
    Zenil over 11 years
    @peter A simple debugging step, please try this and let me know. Set the url pattern as /testing (no other change). Restart the server. Now try localhost:8080/mapapp/testing .It should hit your servlet.
  • Zenil
    Zenil over 11 years