UrlRewriteFilter with Glassfish - url-rewriting

How can I integrate URL rewriting in my Glassfish v3 server?
The reason why I want to know this is that I am deploying a PHP application into my Glassfish server using Quercus.
But Quercus relies on mod_rewrite in the Apache Server to provide URL rewriting and this is not available in Glassfish.

Well, you have two options:
either front your GlassFish instance with Apache and use mod_rewrite
or use Tuckey's Url Rewrite Filter
I guess the former is not an option (or you wouldn't post this question). Regarding the later, you could adapt the solution given in Drupal on Glassfish with clean urls using Url Rewrite Filter. Basically, you'll have to:
Get Quercus's war and unpack it
Download the filter and unpack it inside Quercus (this will put the filter jar inside WEB-INF/lib and the urlrewrite.xml under WEB-INF)
Declare the filter in the web.xml (see the instruction)
"Port" your rewrite rules to the urlrewrite.xml file
repackage and deploy the war (or deploy it as an exploded archive)

I've been looking for the answer to this for a couple weeks.
Follow these instructions for JBoss:
http://tapomay.blogspot.com/2011/11/clean-urls-with-drupal-urlrewritefilter.html
He links to an article where one had done this for Tomcat: http://www.brianshowalter.com/blog/running_drupal_on_quercus
In a nutshell, you want to rewrite the URL only IF the requested file or directory do not exist on the system. This is why just UrlRewriteFilter is not enough. You have to add a class-filter to UrlRewriteFilter to check for this.
The instructions I linked to uses an older version of UrlRewriteFilter (3.2.0), it probably works just as well with the newer version (I did it with 3.2.0).
You will use that in conjunction with a class filter (there is a google project repository for this, thanks to the author of the linked article, at https://code.google.com/p/drupalrewritefilter/ )
The instructions say to add the files to Eclipse, but I used Netbeans (just start a new project with existing sources).
You'll need to add the servlet.api.jar (some where on your system, if you have J2EE installed) and the UrleRewriteFilter.jar file you are using to the classpath for the build.
Place the resulting drupalrewritefilter.jar file and the UrlRewriteFilter.jar file you are using in WEB-INF/lib
Your WEB-INF/web.xml should have this filter directive:
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
<init-param>
<param-name>logLevel</param-name>
<param-value>TRACE</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
Use this instead of the one the website for UrlRewriteFilter says to use.
NOTE: The Quercus install contains a DOCTYPE tag in the beginning for the Servlet API 2.2 or 2.3. But the <filter> tag is in the Servlet API 2.4 or higher. Your app will error-out unless you either link to a new Server API DTD or (and this is what I did) just delete the DOCTYPE tag all together.
Then you should have a WEB-INF/urlwrite.xml with:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 4.0//EN"
"http://www.tuckey.org/res/dtds/urlrewrite4.0.dtd">
<urlrewrite>
<class-rule class="com.brianshowalter.drupalrewrite.DrupalRule" />
</urlrewrite>
Reload your drupal app, and then go enable clean URLS's

Related

Getting error while running application deployed as war on Tomcat [duplicate]

I have an HTML form in a JSP file in my WebContent/jsps folder. I have a servlet class servlet.java in my default package in src folder. In my web.xml it is mapped as /servlet.
I have tried several URLs in action attribute of the HTML form:
<form action="/servlet">
<form action="/servlet.java">
<form action="/src/servlet.java">
<form action="../servlet.java">
But none of those work. They all keep returning a HTTP 404 error like below in Tomcat 6/7/8:
HTTP Status 404 — /servlet
Description: The requested resource (/servlet) is not available.
Or as below in Tomcat 8.5/9:
HTTP Status 404 — Not Found
Message: /servlet
Description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists
Or as below in Tomcat 10:
HTTP Status 404 — Not Found
Type: Status Report
Message: The requested resource (/servlet) is not available
Description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists
Why is it not working?
Introduction
This can have a lot of causes which are broken down in following sections:
Put servlet class in a package
Set servlet URL in url-pattern
#WebServlet works only on Servlet 3.0 or newer
javax.servlet.* doesn't work anymore in Servlet 5.0 or newer
Make sure compiled *.class file is present in built WAR
Test the servlet individually without any JSP/HTML page
Use domain-relative URL to reference servlet from HTML
Use straight quotes in HTML attributes
Put servlet class in a package
First of all, put the servlet class in a Java package. You should always put publicly reuseable Java classes in a package, otherwise they are invisible to classes which are in a package, such as the server itself. This way you eliminate potential environment-specific problems. Packageless servlets work only in specific Tomcat+JDK combinations and this should never be relied upon.
In case of a "plain" IDE project, the class needs to be placed in its package structure inside the "Java Sources" folder, not inside "Web Content" folder, which is for web files such as JSP. Below is an example of the folder structure of a default Eclipse Dynamic Web Project as seen in Navigator view (the "Java Sources" folder is in such project by default represented by src folder):
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
In case of a Maven project, the class needs to be placed in its package structure inside main/java and thus not main/resources, this is for non-class files and absolutely also not main/webapp, this is for web files. Below is an example of the folder structure of a default Maven webapp project as seen in Eclipse's Navigator view:
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Note that the /jsps subfolder is not strictly necessary. You can even do without it and put the JSP file directly in webcontent/webapp root, but I'm just taking over this from your question.
Set servlet URL in url-pattern
The servlet URL is specified as the "URL pattern" of the servlet mapping. It's absolutely not per definition the classname/filename of the servlet class. The URL pattern is to be specified as value of #WebServlet annotation.
package com.example; // Use a package!
import jakarta.servlet.annotation.WebServlet; // or javax.*
import jakarta.servlet.http.HttpServlet; // or javax.*
#WebServlet("/servlet") // This is the URL of the servlet.
public class YourServlet extends HttpServlet { // Must be public and extend HttpServlet.
// ...
}
In case you want to support path parameters like /servlet/foo/bar, then use an URL pattern of /servlet/* instead. See also Servlet and path parameters like /xyz/{value}/test, how to map in web.xml?
Do note that it's considered a bad practice to use a Servlet URL pattern of /* or / in an attempt to have a "front controller". So do not abuse these URL patterns in an attempt to try to catch all URLs. For an in depth explanation see also Difference between / and /* in servlet mapping url pattern.
#WebServlet works only on Servlet 3.0 or newer
In order to use #WebServlet, you only need to make sure that your web.xml file, if any (it's optional since Servlet 3.0), is declared conform Servlet 3.0+ version and thus not conform e.g. 2.5 version or lower. It should absolutely also not have any <!DOCTYPE> line. Below is a Servlet 6.0 compatible one (which matches Tomcat 10.1+, WildFly 27+ (Preview), GlassFish/Payara 7+, etc) in its entirety:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0"
>
<!-- Config here. -->
</web-app>
And below is a Servlet 5.0 compatible one (which matches Tomcat 10.0.x, WildFly 22+ (Preview), GlassFish/Payara 6+, etc).
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
>
<!-- Config here. -->
</web-app>
And below is a Servlet 4.0 compatible one (which matches Tomcat 9+, WildFly 11+, GlassFish/Payara 5+, etc).
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
>
<!-- Config here. -->
</web-app>
Or, in case you're not on Servlet 3.0+ yet (e.g. Tomcat 6 or older), then remove the #WebServlet annotation.
package com.example;
import javax.servlet.http.HttpServlet;
public class YourServlet extends HttpServlet {
// ...
}
And register the servlet instead in web.xml like this:
<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>com.example.YourServlet</servlet-class> <!-- Including the package thus -->
</servlet>
<servlet-mapping>
<servlet-name>yourServlet</servlet-name>
<url-pattern>/servlet</url-pattern> <!-- This is the URL of the servlet. -->
</servlet-mapping>
Note thus that you should not use both ways. Use either annotation based configuarion or XML based configuration. When you have both, then XML based configuration will override annotation based configuration.
javax.servlet.* doesn't work anymore in Servlet 5.0 or newer
Since Jakarta EE 9 / Servlet 5.0 (Tomcat 10, TomEE 9, WildFly 22 Preview, GlassFish 6, Payara 6, Liberty 22, etc), the javax.* package has been renamed to jakarta.* package.
In other words, please make absolutely sure that you don't randomly put JAR files of a different server in your WAR project such as tomcat-servlet-api-9.x.x.jar merely in order to get the javax.* package to compile. This will only cause trouble. Remove it altogether and edit the imports of your servlet class from
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
to
import jakarta.servlet.*;
import jakarta.servlet.annotation.*;
import jakarta.servlet.http.*;
In case you're using Maven, you can find examples of proper pom.xml declarations for Tomcat 10+, Tomcat 9-, JEE 9+ and JEE 8- in this answer: How to properly configure Jakarta EE libraries in Maven pom.xml for Tomcat? The alternative is to downgrade the server to an older version, e.g. from Tomcat 10 back to Tomcat 9 or older, but this is clearly not the recommended way to go.
Make sure compiled *.class file is present in built WAR
In case you're using a build tool such as Eclipse and/or Maven, then you need to make absolutely sure that the compiled servlet class file resides in its package structure in /WEB-INF/classes folder of the produced WAR file. In case of package com.example; public class YourServlet, it must be located in /WEB-INF/classes/com/example/YourServlet.class. Otherwise you will face in case of #WebServlet also a 404 error, or in case of <servlet> a HTTP 500 error like below:
HTTP Status 500
Error instantiating servlet class com.example.YourServlet
And find in the server log a java.lang.ClassNotFoundException: com.example.YourServlet, followed by a java.lang.NoClassDefFoundError: com.example.YourServlet, in turn followed by jakarta.servlet.ServletException: Error instantiating servlet class com.example.YourServlet.
An easy way to verify if the servlet is correctly compiled and placed in classpath is to let the build tool produce a WAR file (e.g. rightclick project, Export > WAR file in Eclipse) and then inspect its contents with a ZIP tool. If the servlet class is missing in /WEB-INF/classes, or if the export causes an error, then the project is badly configured or some IDE/project configuration defaults have been mistakenly reverted (e.g. Project > Build Automatically has been disabled in Eclipse).
You also need to make sure that the project icon has no red cross indicating a build error. You can find the exact error in Problems view (Window > Show View > Other...). Usually the error message is fine Googlable. In case you have no clue, best is to restart from scratch and do not touch any IDE/project configuration defaults. In case you're using Eclipse, you can find instructions in How do I import the javax.servlet / jakarta.servlet API in my Eclipse project?
Test the servlet individually without any JSP/HTML page
Provided that the server runs on localhost:8080, and that the WAR is successfully deployed on a context path of /contextname (which defaults to the IDE project name, case sensitive!), and the servlet hasn't failed its initialization (read server logs for any deploy/servlet success/fail messages and the actual context path and servlet mapping), then a servlet with URL pattern of /servlet is available at http://localhost:8080/contextname/servlet.
You can just enter it straight in browser's address bar to test it invidivually. If its doGet() is properly overriden and implemented, then you will see its output in browser. Or if you don't have any doGet() or if it incorrectly calls super.doGet(), then a "HTTP 405: HTTP method GET is not supported by this URL" error will be shown (which is still better than a 404 as a 405 is evidence that the servlet itself is actually found).
Overriding service() is a bad practice, unless you're reinventing a MVC framework — which is very unlikely if you're just starting out with servlets and are clueless as to the problem described in the current question ;) See also Design Patterns web based applications.
Regardless, if the servlet already returns 404 when tested invidivually, then it's entirely pointless to try with a HTML form instead. Logically, it's therefore also entirely pointless to include any HTML form in questions about 404 errors from a servlet.
Use domain-relative URL to reference servlet from HTML
Once you've verified that the servlet works fine when invoked individually, then you can advance to HTML. As to your concrete problem with the HTML form, the <form action> value needs to be a valid URL. The same applies to <a href>, <img src>, <script src>, etc. You need to understand how absolute/relative URLs work. You know, an URL is a web address as you can enter/see in the webbrowser's address bar. If you're specifying a relative URL as form action, i.e. without the http:// scheme, then it becomes relative to the current URL as you see in your webbrowser's address bar. It's thus absolutely not relative to the JSP/HTML file location in server's WAR folder structure as many starters seem to think.
So, assuming that the JSP page with the HTML form is opened by http://localhost:8080/contextname/jsps/page.jsp (and thus not by file://...), and you need to submit to a servlet located in http://localhost:8080/contextname/servlet, here are several cases (note that you can here safely substitute <form action> with <a href>, <img src>, <script src>, etc):
Form action submits to an URL with a leading slash.
<form action="/servlet">
The leading slash / makes the URL relative to the domain, thus the form will submit to
http://localhost:8080/servlet
But this will likely result in a 404 as it's in the wrong context.
Form action submits to an URL without a leading slash.
<form action="servlet">
This makes the URL relative to the current folder of the current URL, thus the form will submit to
http://localhost:8080/contextname/jsps/servlet
But this will likely result in a 404 as it's in the wrong folder.
Form action submits to an URL which goes one folder up.
<form action="../servlet">
This will go one folder up (exactly like as in local disk file system paths!), thus the form will submit to
http://localhost:8080/contextname/servlet
This one must work!
The canonical approach, however, is to make the URL domain-relative so that you don't need to fix the URLs once again when you happen to move the JSP files around into another folder.
<form action="${pageContext.request.contextPath}/servlet">
This will generate
<form action="/contextname/servlet">
Which will thus always submit to the right URL.
Use straight quotes in HTML attributes
You need to make absolutely sure you're using straight quotes in HTML attributes like action="..." or action='...' and thus not curly quotes like action=”...” or action=’...’. Curly quotes are not supported in HTML and they will simply become part of the value. Watch out when copy-pasting code snippets from blogs! Some blog engines, notably Wordpress, are known to by default use so-called "smart quotes" which thus also corrupts the quotes in code snippets this way. On the other hand, instead of copy-pasting code, try simply typing over the code yourself. Additional advantage of actually getting the code through your brain and fingers is that it will make you to remember and understand the code much better in long term and also make you a better developer.
See also:
Our servlets wiki page - Contains some hello world examples
How to call servlet class from HTML form
doGet and doPost in Servlets
How do I pass current item to Java method by clicking a hyperlink or button in JSP page?
Other cases of HTTP Status 404 error:
HTTP Status 404 - Servlet [ServletName] is not available
HTTP Status 404 - The requested resource (/ProjectName/) is not available
HTTP Status 404 - The requested resource (/) is not available
JSP in /WEB-INF returns "HTTP Status 404 The requested resource is not available"
Referencing a resource placed in WEB-INF folder in JSP file returns HTTP 404 on resource
Browser can't access/find relative resources like CSS, images and links when calling a Servlet which forwards to a JSP
Scenario #1: You accidentially re-deployed from the command line while tomcat was already running.
Short Answer: Stop Tomcat, delete target folder, mvn package, then re-deploy
Scenario #2: request.getRequestDispatcher("MIS_SPELLED_FILE_NAME.jsp")
Short Answer: Check file name spelling, make sure case is correct.
Scenario #3: Class Not Found Exceptions
(Answer put here because: Question# 17982240 )
(java.lang.ClassNotFoundException for servlet in tomcat with eclipse )
(was marked as duplicate and directed me here )
Short Answer #3.1: web.xml has wrong package path in servlet-class tag.
Short Answer #3.2: java file has wrong import statement.
Below is further details for Scenario #1:
1: Stop Tomcat
Option 1: Via CTRL+C in terminal.
Option 2: (terminal closed while tomcat still running)
------------ 2.1: press:Windows+R --> type:"services.msc"
------------ 2.2: Find "Apache Tomcat #.# Tomcat#" in Name column of list.
------------ 2.3: Right Click --> "stop"
2: Delete the "target" folder.
(mvn clean will not help you here)
3: mvn package
4: YOUR_DEPLOYMENT_COMMAND_HERE
(Mine: java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war )
Full Back Story:
Accidentially opened a new git-bash window and
tried to deploy a .war file for my heroku project via:
java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war
After a failure to deploy, I realized I had two git-bash windows open,
and had not used CTLR+C to stop the previous deployment.
I was met with:
HTTP Status 404 – Not Found Type Status Report
Message /if-student-test.jsp
Description The origin server did not find a current representation
for the target resource or is not willing to disclose that one
exists.
Apache Tomcat/8.5.31
Below is further details for Scenario #3:
SCENARIO 3.1:
The servlet-class package path is wrong
in your web.xml file.
It should MATCH the package statement at top
of your java servlet class.
File: my_stuff/MyClass.java:
package my_stuff;
File: PRJ_ROOT/src/main/webapp/WEB-INF/web.xml
<servlet-class>
my_stuff.MyClass
</servlet-class>
SCENARIO 3.2:
You put the wrong "package" statement
at top of your myClass.java file.
For example:
File is in: "/my_stuff" folder
You mistakenly write:
package com.my_stuff
This is tricky because:
1: The maven build (mvn package) will not report any errors here.
2: servlet-class line in web.xml can have CORRECT package path. E.g:
<servlet-class>
my_stuff.MyClass
</servlet-class>
Stack Used:
Notepad++ + GitBash + Maven + Heroku Web App Runner + Tomcat9 + Windows10:
Check if you have entered the correct URL Mapping as specified in the Web.xml
For example:
In the web.xml, your servlet declaration maybe:
<servlet>
<servlet-name>ControllerA</servlet-name>
<servlet-class>PackageName.ControllerA</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ControllerA</servlet-name>
<url-pattern>/theController</url-pattern>
</servlet-mapping>
What this snippet does is <url-pattern>/theController</url-pattern>will set the name that will be used to call the servlet from the front end (eg: form) through the URL. Therefore when you reference the servlet in the front end, in order to ensure that the request goes to the servlet "ControllerA", it should refer the specified URL Pattern "theController" from the form.
eg:
<form action="theController" method="POST">
</form>
If you're using IntelliJ, this is what fixed it for me:
Go to the Tomcat configuration:
Configuration > Deployment Tab
Scroll down and add / to the Application Context dropdown
Solution for HTTP Status 404 in NetBeans IDE:
Right click on your project and go to your project properties, then click on run, then input your project relative URL like index.jsp.
Project->Properties
Click on Run
Relative URL:/index.jsp (Select your project root URL)
My issue was that my method was missing the #RequestBody annotation. After adding the annotation I no longer received the 404 exception.
Do the following two steps. I hope, it will solve the "404 not found" issue in tomcat server during the development of java servlet application.
Step 1: Right click on the server(in the server explorer tab)->Properties->Switch Location from workspace metadata to tomcat server
Step 2: Double Click on the server(in the server explorer tab)->Select Use tomcat installation option inside server location menu
I removed the old web library such that are spring framework libraries. And build a new path of the libraries. Then it works.
An old thread, but since I didn't find it elsewhere, here is one more possibility:
If you're using servlet-api 3.0+, then your web.xml must NOT include metadata-complete="true" attribute
This tells tomcat to map the servlets using data given in web.xml instead of using the #WebServlet annotation.
First of all, run your IDE as Admin. After that, right click the project folder -> Project Facets and make sure that the Java Version is set correct. On my PC. (For Example 1.8) Now it should work.
Don't just start your server, for example Wildfly, using the cmd. It has to be launched within the IDE and now visit your localhost URL. Example: http://localhost:8080/HelloWorldServlet/HelloWorld
The fix that worked for me is(if you are using Maven): Rightclick your project, Maven -> Update project. This might give you some other error with the JDK and other Libraries(in my case, MySQL connector), but once you fix them, your original problem should be fixed!
If you would like to open a servlet with javascript without using 'form' and 'submit' button, here is the following code:
var button = document.getElementById("<<button-id>>");
button.addEventListener("click", function() {
window.location.href= "<<full-servlet-path>>" (eg. http://localhost:8086/xyz/servlet)
});
Key:
1) button-id : The 'id' tag you give to your button in your html/jsp file.
2) full-servlet-path: The path that shows in the browser when you run the servlet alone
Mapping in web.xml is what i have done :-
If there's another package made for new program then we must mention :-
packagename.filename between opening and closing of servlet-class tag in xml file.
If you are mapping your files in xml and they are not working or showing errors , then comment on the annotation line of code in the respective files.
Both methods dont work with one another , so either i use annotation method of files mentioned when we create servlet or the way of mapping , then i delete or comment the annotation line. Eg:
<servlet>
<servlet-name>s1</servlet-name>
<servlet-class>performance.FirstServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s1</servlet-name>
<url-pattern>/FirstServ</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>s2</servlet-name>
<servlet-class>performance.SecondServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s2</servlet-name>
<url-pattern>/SecondServ</url-pattern>
</servlet-mapping>
Commenting the annotation line of code in the respective file,if mapping in xml is done.
//#WebServlet("/FirstServ")
//#WebServlet("/SecondServ")
If someone is here who is using MySQL and felt that the code was working the previous day and now it doesn't, then I guess you must open MySQL CLI or MySQL Workbench and just make the connection to the database once. Once it gets connected, then the database also gets connected to the Java Application. I used to get the Hibernate Dialect error stating something wrong with com.mysql.jdbc.Driver. I think MySQL in some computers has a startup problem. This solved for me.
If you are a student and new to Java there might be some issue going on with your web.xml file.
Try removing the web.xml file.
Secondly check that your path variables are properly set or not.
Restart tomcat server Or your PC.
Your problem will be surely solved.
I was facing this issue too, I was receiving a 404 when accessing a URL pattern that I knew was linked to a Servlet. The reason is because I had 2 Servlets with their #WebServlet name parameter set as the same string.
#WebServlet(name = "ServletName", urlPatterns = {"/path"})
public class ServletName extends HttpServlet {}
#WebServlet(name = "ServletName", urlPatterns = {"/other-path"})
public class OtherServletName extends HttpServlet {}
Both of the name parameters are the same. If you're using the name parameter, make sure they are unique compared to all other Servlets on your application.
I had the same issue. Tried all of this but didn't help. I managed to solve this issue by adding element tags to beginning and end of the xml file. ill leave my xml file below for reference.
<?xml version="1.0" encoding="UTF-8"?>
<element>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>InsertServlet</servlet-name>
<servlet-class>com.worklog.InsertServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InsertServlet</servlet-name>
<url-pattern>/insert</url-pattern>
</servlet-mapping>
</web-app>
</element>
I was having the same issue. I was developing a mvc based REST API where there was no explicit html configuration or files. The API was using Swagger to generate a user interface. The problem started when I introduced Swagger version "3.0.0". I reverted back to Swagger "2.9.2" This solved my problem.
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
Please check context root cannot be empty.
If you're using eclipse:
right click, select properties, then web project settings. Check the context root cannot be empty

404 - My jsp cannot find servlet [duplicate]

I have an HTML form in a JSP file in my WebContent/jsps folder. I have a servlet class servlet.java in my default package in src folder. In my web.xml it is mapped as /servlet.
I have tried several URLs in action attribute of the HTML form:
<form action="/servlet">
<form action="/servlet.java">
<form action="/src/servlet.java">
<form action="../servlet.java">
But none of those work. They all keep returning a HTTP 404 error like below in Tomcat 6/7/8:
HTTP Status 404 — /servlet
Description: The requested resource (/servlet) is not available.
Or as below in Tomcat 8.5/9:
HTTP Status 404 — Not Found
Message: /servlet
Description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists
Or as below in Tomcat 10:
HTTP Status 404 — Not Found
Type: Status Report
Message: The requested resource (/servlet) is not available
Description: The origin server did not find a current representation for the target resource or is not willing to disclose that one exists
Why is it not working?
Introduction
This can have a lot of causes which are broken down in following sections:
Put servlet class in a package
Set servlet URL in url-pattern
#WebServlet works only on Servlet 3.0 or newer
javax.servlet.* doesn't work anymore in Servlet 5.0 or newer
Make sure compiled *.class file is present in built WAR
Test the servlet individually without any JSP/HTML page
Use domain-relative URL to reference servlet from HTML
Use straight quotes in HTML attributes
Put servlet class in a package
First of all, put the servlet class in a Java package. You should always put publicly reuseable Java classes in a package, otherwise they are invisible to classes which are in a package, such as the server itself. This way you eliminate potential environment-specific problems. Packageless servlets work only in specific Tomcat+JDK combinations and this should never be relied upon.
In case of a "plain" IDE project, the class needs to be placed in its package structure inside the "Java Sources" folder, not inside "Web Content" folder, which is for web files such as JSP. Below is an example of the folder structure of a default Eclipse Dynamic Web Project as seen in Navigator view (the "Java Sources" folder is in such project by default represented by src folder):
EclipseProjectName
|-- src
| `-- com
| `-- example
| `-- YourServlet.java
|-- WebContent
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
In case of a Maven project, the class needs to be placed in its package structure inside main/java and thus not main/resources, this is for non-class files and absolutely also not main/webapp, this is for web files. Below is an example of the folder structure of a default Maven webapp project as seen in Eclipse's Navigator view:
MavenProjectName
|-- src
| `-- main
| |-- java
| | `-- com
| | `-- example
| | `-- YourServlet.java
| |-- resources
| `-- webapp
| |-- WEB-INF
| | `-- web.xml
| `-- jsps
| `-- page.jsp
:
Note that the /jsps subfolder is not strictly necessary. You can even do without it and put the JSP file directly in webcontent/webapp root, but I'm just taking over this from your question.
Set servlet URL in url-pattern
The servlet URL is specified as the "URL pattern" of the servlet mapping. It's absolutely not per definition the classname/filename of the servlet class. The URL pattern is to be specified as value of #WebServlet annotation.
package com.example; // Use a package!
import jakarta.servlet.annotation.WebServlet; // or javax.*
import jakarta.servlet.http.HttpServlet; // or javax.*
#WebServlet("/servlet") // This is the URL of the servlet.
public class YourServlet extends HttpServlet { // Must be public and extend HttpServlet.
// ...
}
In case you want to support path parameters like /servlet/foo/bar, then use an URL pattern of /servlet/* instead. See also Servlet and path parameters like /xyz/{value}/test, how to map in web.xml?
Do note that it's considered a bad practice to use a Servlet URL pattern of /* or / in an attempt to have a "front controller". So do not abuse these URL patterns in an attempt to try to catch all URLs. For an in depth explanation see also Difference between / and /* in servlet mapping url pattern.
#WebServlet works only on Servlet 3.0 or newer
In order to use #WebServlet, you only need to make sure that your web.xml file, if any (it's optional since Servlet 3.0), is declared conform Servlet 3.0+ version and thus not conform e.g. 2.5 version or lower. It should absolutely also not have any <!DOCTYPE> line. Below is a Servlet 6.0 compatible one (which matches Tomcat 10.1+, WildFly 27+ (Preview), GlassFish/Payara 7+, etc) in its entirety:
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_0.xsd"
version="6.0"
>
<!-- Config here. -->
</web-app>
And below is a Servlet 5.0 compatible one (which matches Tomcat 10.0.x, WildFly 22+ (Preview), GlassFish/Payara 6+, etc).
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
version="5.0"
>
<!-- Config here. -->
</web-app>
And below is a Servlet 4.0 compatible one (which matches Tomcat 9+, WildFly 11+, GlassFish/Payara 5+, etc).
<?xml version="1.0" encoding="UTF-8"?>
<web-app
xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd"
version="4.0"
>
<!-- Config here. -->
</web-app>
Or, in case you're not on Servlet 3.0+ yet (e.g. Tomcat 6 or older), then remove the #WebServlet annotation.
package com.example;
import javax.servlet.http.HttpServlet;
public class YourServlet extends HttpServlet {
// ...
}
And register the servlet instead in web.xml like this:
<servlet>
<servlet-name>yourServlet</servlet-name>
<servlet-class>com.example.YourServlet</servlet-class> <!-- Including the package thus -->
</servlet>
<servlet-mapping>
<servlet-name>yourServlet</servlet-name>
<url-pattern>/servlet</url-pattern> <!-- This is the URL of the servlet. -->
</servlet-mapping>
Note thus that you should not use both ways. Use either annotation based configuarion or XML based configuration. When you have both, then XML based configuration will override annotation based configuration.
javax.servlet.* doesn't work anymore in Servlet 5.0 or newer
Since Jakarta EE 9 / Servlet 5.0 (Tomcat 10, TomEE 9, WildFly 22 Preview, GlassFish 6, Payara 6, Liberty 22, etc), the javax.* package has been renamed to jakarta.* package.
In other words, please make absolutely sure that you don't randomly put JAR files of a different server in your WAR project such as tomcat-servlet-api-9.x.x.jar merely in order to get the javax.* package to compile. This will only cause trouble. Remove it altogether and edit the imports of your servlet class from
import javax.servlet.*;
import javax.servlet.annotation.*;
import javax.servlet.http.*;
to
import jakarta.servlet.*;
import jakarta.servlet.annotation.*;
import jakarta.servlet.http.*;
In case you're using Maven, you can find examples of proper pom.xml declarations for Tomcat 10+, Tomcat 9-, JEE 9+ and JEE 8- in this answer: How to properly configure Jakarta EE libraries in Maven pom.xml for Tomcat? The alternative is to downgrade the server to an older version, e.g. from Tomcat 10 back to Tomcat 9 or older, but this is clearly not the recommended way to go.
Make sure compiled *.class file is present in built WAR
In case you're using a build tool such as Eclipse and/or Maven, then you need to make absolutely sure that the compiled servlet class file resides in its package structure in /WEB-INF/classes folder of the produced WAR file. In case of package com.example; public class YourServlet, it must be located in /WEB-INF/classes/com/example/YourServlet.class. Otherwise you will face in case of #WebServlet also a 404 error, or in case of <servlet> a HTTP 500 error like below:
HTTP Status 500
Error instantiating servlet class com.example.YourServlet
And find in the server log a java.lang.ClassNotFoundException: com.example.YourServlet, followed by a java.lang.NoClassDefFoundError: com.example.YourServlet, in turn followed by jakarta.servlet.ServletException: Error instantiating servlet class com.example.YourServlet.
An easy way to verify if the servlet is correctly compiled and placed in classpath is to let the build tool produce a WAR file (e.g. rightclick project, Export > WAR file in Eclipse) and then inspect its contents with a ZIP tool. If the servlet class is missing in /WEB-INF/classes, or if the export causes an error, then the project is badly configured or some IDE/project configuration defaults have been mistakenly reverted (e.g. Project > Build Automatically has been disabled in Eclipse).
You also need to make sure that the project icon has no red cross indicating a build error. You can find the exact error in Problems view (Window > Show View > Other...). Usually the error message is fine Googlable. In case you have no clue, best is to restart from scratch and do not touch any IDE/project configuration defaults. In case you're using Eclipse, you can find instructions in How do I import the javax.servlet / jakarta.servlet API in my Eclipse project?
Test the servlet individually without any JSP/HTML page
Provided that the server runs on localhost:8080, and that the WAR is successfully deployed on a context path of /contextname (which defaults to the IDE project name, case sensitive!), and the servlet hasn't failed its initialization (read server logs for any deploy/servlet success/fail messages and the actual context path and servlet mapping), then a servlet with URL pattern of /servlet is available at http://localhost:8080/contextname/servlet.
You can just enter it straight in browser's address bar to test it invidivually. If its doGet() is properly overriden and implemented, then you will see its output in browser. Or if you don't have any doGet() or if it incorrectly calls super.doGet(), then a "HTTP 405: HTTP method GET is not supported by this URL" error will be shown (which is still better than a 404 as a 405 is evidence that the servlet itself is actually found).
Overriding service() is a bad practice, unless you're reinventing a MVC framework — which is very unlikely if you're just starting out with servlets and are clueless as to the problem described in the current question ;) See also Design Patterns web based applications.
Regardless, if the servlet already returns 404 when tested invidivually, then it's entirely pointless to try with a HTML form instead. Logically, it's therefore also entirely pointless to include any HTML form in questions about 404 errors from a servlet.
Use domain-relative URL to reference servlet from HTML
Once you've verified that the servlet works fine when invoked individually, then you can advance to HTML. As to your concrete problem with the HTML form, the <form action> value needs to be a valid URL. The same applies to <a href>, <img src>, <script src>, etc. You need to understand how absolute/relative URLs work. You know, an URL is a web address as you can enter/see in the webbrowser's address bar. If you're specifying a relative URL as form action, i.e. without the http:// scheme, then it becomes relative to the current URL as you see in your webbrowser's address bar. It's thus absolutely not relative to the JSP/HTML file location in server's WAR folder structure as many starters seem to think.
So, assuming that the JSP page with the HTML form is opened by http://localhost:8080/contextname/jsps/page.jsp (and thus not by file://...), and you need to submit to a servlet located in http://localhost:8080/contextname/servlet, here are several cases (note that you can here safely substitute <form action> with <a href>, <img src>, <script src>, etc):
Form action submits to an URL with a leading slash.
<form action="/servlet">
The leading slash / makes the URL relative to the domain, thus the form will submit to
http://localhost:8080/servlet
But this will likely result in a 404 as it's in the wrong context.
Form action submits to an URL without a leading slash.
<form action="servlet">
This makes the URL relative to the current folder of the current URL, thus the form will submit to
http://localhost:8080/contextname/jsps/servlet
But this will likely result in a 404 as it's in the wrong folder.
Form action submits to an URL which goes one folder up.
<form action="../servlet">
This will go one folder up (exactly like as in local disk file system paths!), thus the form will submit to
http://localhost:8080/contextname/servlet
This one must work!
The canonical approach, however, is to make the URL domain-relative so that you don't need to fix the URLs once again when you happen to move the JSP files around into another folder.
<form action="${pageContext.request.contextPath}/servlet">
This will generate
<form action="/contextname/servlet">
Which will thus always submit to the right URL.
Use straight quotes in HTML attributes
You need to make absolutely sure you're using straight quotes in HTML attributes like action="..." or action='...' and thus not curly quotes like action=”...” or action=’...’. Curly quotes are not supported in HTML and they will simply become part of the value. Watch out when copy-pasting code snippets from blogs! Some blog engines, notably Wordpress, are known to by default use so-called "smart quotes" which thus also corrupts the quotes in code snippets this way. On the other hand, instead of copy-pasting code, try simply typing over the code yourself. Additional advantage of actually getting the code through your brain and fingers is that it will make you to remember and understand the code much better in long term and also make you a better developer.
See also:
Our servlets wiki page - Contains some hello world examples
How to call servlet class from HTML form
doGet and doPost in Servlets
How do I pass current item to Java method by clicking a hyperlink or button in JSP page?
Other cases of HTTP Status 404 error:
HTTP Status 404 - Servlet [ServletName] is not available
HTTP Status 404 - The requested resource (/ProjectName/) is not available
HTTP Status 404 - The requested resource (/) is not available
JSP in /WEB-INF returns "HTTP Status 404 The requested resource is not available"
Referencing a resource placed in WEB-INF folder in JSP file returns HTTP 404 on resource
Browser can't access/find relative resources like CSS, images and links when calling a Servlet which forwards to a JSP
Scenario #1: You accidentially re-deployed from the command line while tomcat was already running.
Short Answer: Stop Tomcat, delete target folder, mvn package, then re-deploy
Scenario #2: request.getRequestDispatcher("MIS_SPELLED_FILE_NAME.jsp")
Short Answer: Check file name spelling, make sure case is correct.
Scenario #3: Class Not Found Exceptions
(Answer put here because: Question# 17982240 )
(java.lang.ClassNotFoundException for servlet in tomcat with eclipse )
(was marked as duplicate and directed me here )
Short Answer #3.1: web.xml has wrong package path in servlet-class tag.
Short Answer #3.2: java file has wrong import statement.
Below is further details for Scenario #1:
1: Stop Tomcat
Option 1: Via CTRL+C in terminal.
Option 2: (terminal closed while tomcat still running)
------------ 2.1: press:Windows+R --> type:"services.msc"
------------ 2.2: Find "Apache Tomcat #.# Tomcat#" in Name column of list.
------------ 2.3: Right Click --> "stop"
2: Delete the "target" folder.
(mvn clean will not help you here)
3: mvn package
4: YOUR_DEPLOYMENT_COMMAND_HERE
(Mine: java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war )
Full Back Story:
Accidentially opened a new git-bash window and
tried to deploy a .war file for my heroku project via:
java -jar target/dependency/webapp-runner.jar --port 5190 target/*.war
After a failure to deploy, I realized I had two git-bash windows open,
and had not used CTLR+C to stop the previous deployment.
I was met with:
HTTP Status 404 – Not Found Type Status Report
Message /if-student-test.jsp
Description The origin server did not find a current representation
for the target resource or is not willing to disclose that one
exists.
Apache Tomcat/8.5.31
Below is further details for Scenario #3:
SCENARIO 3.1:
The servlet-class package path is wrong
in your web.xml file.
It should MATCH the package statement at top
of your java servlet class.
File: my_stuff/MyClass.java:
package my_stuff;
File: PRJ_ROOT/src/main/webapp/WEB-INF/web.xml
<servlet-class>
my_stuff.MyClass
</servlet-class>
SCENARIO 3.2:
You put the wrong "package" statement
at top of your myClass.java file.
For example:
File is in: "/my_stuff" folder
You mistakenly write:
package com.my_stuff
This is tricky because:
1: The maven build (mvn package) will not report any errors here.
2: servlet-class line in web.xml can have CORRECT package path. E.g:
<servlet-class>
my_stuff.MyClass
</servlet-class>
Stack Used:
Notepad++ + GitBash + Maven + Heroku Web App Runner + Tomcat9 + Windows10:
Check if you have entered the correct URL Mapping as specified in the Web.xml
For example:
In the web.xml, your servlet declaration maybe:
<servlet>
<servlet-name>ControllerA</servlet-name>
<servlet-class>PackageName.ControllerA</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ControllerA</servlet-name>
<url-pattern>/theController</url-pattern>
</servlet-mapping>
What this snippet does is <url-pattern>/theController</url-pattern>will set the name that will be used to call the servlet from the front end (eg: form) through the URL. Therefore when you reference the servlet in the front end, in order to ensure that the request goes to the servlet "ControllerA", it should refer the specified URL Pattern "theController" from the form.
eg:
<form action="theController" method="POST">
</form>
If you're using IntelliJ, this is what fixed it for me:
Go to the Tomcat configuration:
Configuration > Deployment Tab
Scroll down and add / to the Application Context dropdown
Solution for HTTP Status 404 in NetBeans IDE:
Right click on your project and go to your project properties, then click on run, then input your project relative URL like index.jsp.
Project->Properties
Click on Run
Relative URL:/index.jsp (Select your project root URL)
My issue was that my method was missing the #RequestBody annotation. After adding the annotation I no longer received the 404 exception.
Do the following two steps. I hope, it will solve the "404 not found" issue in tomcat server during the development of java servlet application.
Step 1: Right click on the server(in the server explorer tab)->Properties->Switch Location from workspace metadata to tomcat server
Step 2: Double Click on the server(in the server explorer tab)->Select Use tomcat installation option inside server location menu
I removed the old web library such that are spring framework libraries. And build a new path of the libraries. Then it works.
An old thread, but since I didn't find it elsewhere, here is one more possibility:
If you're using servlet-api 3.0+, then your web.xml must NOT include metadata-complete="true" attribute
This tells tomcat to map the servlets using data given in web.xml instead of using the #WebServlet annotation.
First of all, run your IDE as Admin. After that, right click the project folder -> Project Facets and make sure that the Java Version is set correct. On my PC. (For Example 1.8) Now it should work.
Don't just start your server, for example Wildfly, using the cmd. It has to be launched within the IDE and now visit your localhost URL. Example: http://localhost:8080/HelloWorldServlet/HelloWorld
The fix that worked for me is(if you are using Maven): Rightclick your project, Maven -> Update project. This might give you some other error with the JDK and other Libraries(in my case, MySQL connector), but once you fix them, your original problem should be fixed!
If you would like to open a servlet with javascript without using 'form' and 'submit' button, here is the following code:
var button = document.getElementById("<<button-id>>");
button.addEventListener("click", function() {
window.location.href= "<<full-servlet-path>>" (eg. http://localhost:8086/xyz/servlet)
});
Key:
1) button-id : The 'id' tag you give to your button in your html/jsp file.
2) full-servlet-path: The path that shows in the browser when you run the servlet alone
Mapping in web.xml is what i have done :-
If there's another package made for new program then we must mention :-
packagename.filename between opening and closing of servlet-class tag in xml file.
If you are mapping your files in xml and they are not working or showing errors , then comment on the annotation line of code in the respective files.
Both methods dont work with one another , so either i use annotation method of files mentioned when we create servlet or the way of mapping , then i delete or comment the annotation line. Eg:
<servlet>
<servlet-name>s1</servlet-name>
<servlet-class>performance.FirstServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s1</servlet-name>
<url-pattern>/FirstServ</url-pattern>
</servlet-mapping>
<servlet>
<servlet-name>s2</servlet-name>
<servlet-class>performance.SecondServ</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>s2</servlet-name>
<url-pattern>/SecondServ</url-pattern>
</servlet-mapping>
Commenting the annotation line of code in the respective file,if mapping in xml is done.
//#WebServlet("/FirstServ")
//#WebServlet("/SecondServ")
If someone is here who is using MySQL and felt that the code was working the previous day and now it doesn't, then I guess you must open MySQL CLI or MySQL Workbench and just make the connection to the database once. Once it gets connected, then the database also gets connected to the Java Application. I used to get the Hibernate Dialect error stating something wrong with com.mysql.jdbc.Driver. I think MySQL in some computers has a startup problem. This solved for me.
If you are a student and new to Java there might be some issue going on with your web.xml file.
Try removing the web.xml file.
Secondly check that your path variables are properly set or not.
Restart tomcat server Or your PC.
Your problem will be surely solved.
I was facing this issue too, I was receiving a 404 when accessing a URL pattern that I knew was linked to a Servlet. The reason is because I had 2 Servlets with their #WebServlet name parameter set as the same string.
#WebServlet(name = "ServletName", urlPatterns = {"/path"})
public class ServletName extends HttpServlet {}
#WebServlet(name = "ServletName", urlPatterns = {"/other-path"})
public class OtherServletName extends HttpServlet {}
Both of the name parameters are the same. If you're using the name parameter, make sure they are unique compared to all other Servlets on your application.
I had the same issue. Tried all of this but didn't help. I managed to solve this issue by adding element tags to beginning and end of the xml file. ill leave my xml file below for reference.
<?xml version="1.0" encoding="UTF-8"?>
<element>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee
http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
version="3.1">
<servlet>
<servlet-name>InsertServlet</servlet-name>
<servlet-class>com.worklog.InsertServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>InsertServlet</servlet-name>
<url-pattern>/insert</url-pattern>
</servlet-mapping>
</web-app>
</element>
I was having the same issue. I was developing a mvc based REST API where there was no explicit html configuration or files. The API was using Swagger to generate a user interface. The problem started when I introduced Swagger version "3.0.0". I reverted back to Swagger "2.9.2" This solved my problem.
<!-- Swagger -->
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger-ui</artifactId>
<version>2.9.2</version>
</dependency>
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-swagger2</artifactId>
<version>2.9.2</version>
</dependency>
Please check context root cannot be empty.
If you're using eclipse:
right click, select properties, then web project settings. Check the context root cannot be empty

WebSphere 7.0 won't run filter for root URL

I have a WAR file that defines a filter to run on all URLs:
<!DOCTYPE web-app PUBLIC
"-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
"http://java.sun.com/dtd/web-app_2_3.dtd">
...
<filter>
<filter-name>OurRedirectServletFilter</filter-name>
<filter-class>com.mycompany.RedirectServletFilter</filter-class>
</filter>
...
<filter-mapping>
<filter-name>OurRedirectServletFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
The filter is designed to perform some redirects from 'convenience' URLs to a corresponding 'actual' URL, but I don't think that's really relevant to the problem.
On WebSphere 7.0, this filter doesn't run for requests to the root URL, e.g. /ctxroot or /ctxroot/; instead I just get a 404 response. It does run for /ctxroot/blah, whether blah is a valid or invalid path.
I've tried adding additional filter mappings for URL patterns <url-pattern>/</url-pattern> and <url-pattern></url-pattern>, but I get the same behavior.
I've tested on base WAS 7.0.0.0, and with the latest fix pack applied, i.e. WAS 7.0.0.27.
The filter works as expected on WAS 8.5 and I'm pretty sure on WAS 8.0, as well as on every version of WebLogic, JBoss, and Tomcat that I've tried. This then seems to be a bug with WAS 7.0, but I'd still like to find a workaround. Anybody know of one?
I eventually looked at the body of the 404 error response and saw error code SRVE0190E, which led me to this helpful page. The issue is that filters aren't called by default for URLs that correspond to resources that don't exist (though I swear I tested that for a URL other than the context root, and my filter was called).
It's possible to configure WebSphere to call filters in this situation by setting a custom property as further described in the linked page:
com.ibm.ws.webcontainer.invokefilterscompatibility=true
I also found that for the case of the context root URL, setting a welcome-file entry in web.xml that maps to an existing resource causes the filter to be called:
<welcome-file-list>
<welcome-file>fakehome.html</welcome-file>
</welcome-file-list>

Websphere not using welcome-file-list after mapping *.html to a servlet

I am using IBM WebSphere (WAS) 7.0.0.19 to host a java-based web-app, and I needed to map the extension *.html to a particular servlet so that I could do some server-side scrubbing of user-supplied HTML files. (The server reads the file, augments it with some extra information, and serves up the modified content transparently to the person viewing the page.)
Unfortunately, when I did this, welcome-files stopped working. Previously, if I typed in the URL for a directory, the server would look for index.html and serve up that. Now, I'm just getting a 403 forbidden rule ("Forbidden - by rule."). The access logs don't show anything more--they simply state that directory indexing is forbidden by rule for the server, which is correct. I don't want the webserver to build a table of contents for directories with no index.html, but when there is an index.html, I want it to serve up that file.
My first thought was that it was trying to serve the index.html through my servlet, the servlet was failing to find the file (because the url lacked "index.html"), and therefore it thought there was no index.html. However, I put in some debug code and am quite confident that the servlet code is never getting run when I go simply to the directory itself.
I don't really care whether index.html is served through the servlet or not--in the case of this particular file, the servlet would just spit back the original file anyway. I just want index.html to be served by something.
Here is the relevant section of my web.xml
<servlet-mapping>
<servlet-name>PageScrubber</servlet-name>
<url-pattern>*.html</url-pattern>
</servlet-mapping>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
For what it's worth, index.htm and index.jsp were not working before the addition of the servlet mapping. Only index.html worked before. However, now none of them work.
I have used the same web.xml with two Oracle products: WebLogic (WLS) and Oracle Application Server (OAS) with no issues.
I am quite confident that it is just the addition of this scrubber servlet that has caused the problem, because removing that directive caused directory indexing to start working again.
I did find some notes about welcome-file-list not working when using an extended document root, and I tried setting com.ibm.ws.webcontainer.EnablePartialURLtoExtendedDocumentRoot to be true, but that did not seem to change anything.
I'm pretty much out of ideas. Does anyone out there have any thoughts as to why it's not finding my index.html? Thanks in advance!
Caveat: I am working out of memory here.
The Welcome files used to be served by File Serving Servlet (or something that sounds similar to that).
This information would be in the WebSphere extensions file.
I would take a step back and remove your pageScrubber and get the file serving Servlet to serve the welcome files and see that things are working before getting back to using the PageScrubber.
These are my initial thoughts.
HTH

Forwarding requests between contexts in Tomcat

I'd like to be able to do cross-context request forwarding in Tomcat with the Tuckey URLRewrite filter. For example, I'd like to be able to route an incoming request with an SEO-/user-friendly URL like http://example.com/group-elements/300245/some-descriptive-text, where "group-elements" isn't the name of a deployed application, to a URL mapped to a Java Spring controller method for application 'foo', like http://example.com/foo/app/group/300245/elements. I'm using Tomcat 7.0.27 and URLRewrite 3.2.0; I'm working with Java Spring 3.1 web applications.
The URLRewrite 3.20 documentation notes an optional 'context' attribute for the 'to' filter parameter element:
If your application server is configured to allow "cross context" communication then this attribute can be used to forward (and only forward, not redirect or other "to" types) requests to a named servlet context.
On Tomcat, for instance, the application contexts in the server configuration (server.xml or context.xml) need the option crossContext="true". For instance, the two applications mentioned before ("app" and "forum") have to be defined as:
<Context docBase="app" path="/app" reloadable="true" crossContext="true"/>
<Context docBase="forum" path="/forum" reloadable="true" crossContext="true"/>
Given that and the original discussion about the feature, the 'context' attribute seems to be what I'm looking for. However, I haven't been able to properly enable cross-context request forwarding.
Here's my 'Context' entry application 'foo' in conf/server.xml:
<Context docBase="foo" path="/foo" reloadable="true" crossContext="true"/>
I have my urlrewrite.xml file and web.xml file in webapps/ROOT/WEB-INF/. Here's what they look like:
urlrewrite.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
"http://tuckey.org/res/dtds/urlrewrite3.2.dtd">
<urlrewrite>
<rule>
<from>baz</from>
<!-- Note: this 'to' element's value has an error. See the edit at bottom of this post for corrected version. -->
<to context="foo">/foo/app/group/300245/elements</to>
</rule>
</urlrewrite>
web.xml:
<?xml version="1.0" encoding="ISO-8859-1"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_5.xsd" version="2.5">
<filter>
<filter-name>UrlRewriteFilter</filter-name>
<filter-class>org.tuckey.web.filters.urlrewrite.UrlRewriteFilter</filter-class>
<init-param>
<param-name>logLevel</param-name>
<param-value>WARN</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UrlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
The rule defined above in urlrewrite.xml is intentionally basic and hard-coded. In this case I'm simply trying to get the cross-context aspect of the rule working before developing the regular expressions in 'to' and 'from'.
When I request http://example.com/baz with that rule in place, Tomcat returns a 404 error saying "The requested resource (/baz) is not available." I've tried a few variations in the 'to' filter parameter, but nothing has worked yet. And I haven't been able to find any examples of how 'context' should be used.
Any ideas on how I could get this kind of cross-context request filtering to work? Is it even possible? I imagine I might be able to achieve what I'm trying to do by renaming foo.war to ROOT.war or changing the root application as mentioned here, but I'd like to try doing this via URLRewrite unless doing so is infeasible or a bad idea on its face.
If showing more of my configuration would help, please let me know. Thanks in advance for any input.
Edit:
Thanks to Christopher Schultz for the helpful answer. In my case, the problem was caused by two things: 1) not having a context.xml file in webapps/ROOT/META-INF, and 2) having an error in the 'to' element in the URL rewrite rule in webapps/ROOT/WEB-INF/urlrewrite.xml.
The fix involved putting a proper context.xml file in webapps/ROOT/META-INF. For reference for anyone else that encounters this problem, that file ended up looking like this:
webapps/ROOT/META-INF/context.xml
<?xml version='1.0' encoding='utf-8'?>
<Context docBase="ROOT" path="/" reloadable="true" crossContext="true" />
As Schultz mentions, it's only necessary for a context with crossContext="true" to be defined for the context implied in the 'from' element in a given URL rewrite rule (here, that's ROOT). It is not necessary to explicitly define a context for the application in the 'to' URL rewrite rule. In other words, you shouldn't need to manually create a context.xml file for that application -- so continuing the example above, you would not need to manually define and put a context.xml file into webapps/foo/META-INF/.
Schultz's answer reflects the recommendations for defining a context in the official Tomcat documentation: http://tomcat.apache.org/tomcat-7.0-doc/config/context.html#Defining_a_context.
The problem was also caused by the fact that the URL rewrite rule in my initial post had an error. The correct version should have been:
urlrewrite.xml:
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE urlrewrite PUBLIC "-//tuckey.org//DTD UrlRewrite 3.2//EN"
"http://tuckey.org/res/dtds/urlrewrite3.2.dtd">
<urlrewrite>
<rule>
<from>baz</from>
<!-- Note: the use of '/app' instead of '/foo/app/' below -->
<to context="foo">/app/group/300245/elements</to>
</rule>
</urlrewrite>
If your (real) webapp is deployed to /foo and you want to on-the-fly rewrite URLs like /group-elements/baz to forward (not redirect) to /foo/app/group/300245/elements, then you're going to have to deploy your rewrite filter to one of two places: /group-elements or /.
The above configuration appears to be deploying to ROOT (which is /) but then mapping the URL /baz to /foo/app/group/300245/elements. Instead, you probably want this:
<rule>
<from>/group-elements/baz</from>
<to context="foo">/foo/app/group/300245/elements</to>
</rule>
It looks like you were trying to hit http://example.com/baz which I would have expected to work. The last bit of magic is going to be making the ROOT context cross-context (note that your webapp does NOT need to be cross-context: only the urlrewrite one does). You can change the ROOT webapp to be cross-context by addint crossContext="true" to webapps/ROOT/META-INF/context.xml.
Finally, you should really stop putting <Context> elements in server.xml: leaving them in there basically means you need to restart Tomcat in order to change your webapp deployments.
After the comments I come do this possible conclusion:
I think you are mixing the concepts of a reverse proxy with cross-context. Cross-context is method to share data between two web-applications within the same application server. A reverse-proxy like 'Apache http' can rewrite a url to pass it to a certain server behind it, effectively hiding any unwanted parts or performing other operations like load-balancing.
The infrastructure would be: client --> reverse proxy --> application server

Resources