A Simple Page Not Found (404) Filter – Part 1


Continue to  Part 2

Overview

This post is all about back to basics with Servlets and Web Servers. Our scenario is very simple.  Our user will request a given web page and if this is found then it will be returned. If it is not found, then the web page will be generated (if it should exist) and stored as the appropriate html page.  The filter will then return to the user the correct page content without returning an error or a redirect.

Part 1 – Requirement

Our task is to create a simple Filter that will test for a 404 error that has been returned from the Web Server and replace it with the content “Your page could not be found so I have generated this” and Success.

Create the Project

  • New
  • Maven Project
  • Next
  • maven-archetype-webapp
  • Group Id: com.skills421.examples.servlets
  • ArtifactId: Filter404
  • Finish

Edit the Pom

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.skills421.examples.servlets</groupId>
<artifactId>Filter404</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>Filter404 Maven Webapp</name>
<url>http://maven.apache.org</url>

<properties>
<servlet.version>3.1.0</servlet.version>
<junit.version>4.11</junit.version>
<httpclient.version>4.3.4</httpclient.version>
<java.version>1.6</java.version>
</properties>

<dependencies>
<!-- Javax Servlet -->
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>${servlet.version}</version>
<scope>provided</scope>
</dependency>

<!-- Http Components -->
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>${httpclient.version}</version>
<scope>provided</scope>
</dependency>

<!-- JUnit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
</dependencies>

<!-- build settings -->
<build>
<finalName>Filter404</finalName>

<plugins>

<!-- set the java version -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.0</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
</configuration>
</plugin>
</plugins>
</build>
</project>

Run Maven Update

  • Right-click Project
  • Maven
  • Update Project…

Add Folders

  • Right-click src/main
  • add folder java
  • add folder resources
  • resources
  • Right-click src
  • add folder test/java
  • add folder test/resources

Add Source Folders

  • Right-click project
  • new -> Source Folder
  • src/main/webapp
  • new -> Source Folder
  • src/test/resources
001-project

Your project should now look like this:

Run the Project on the Server

  • Right-click project
  • Run As -> Run on Server
  • Select your server (or the default VMware vFrabric server if you are using STS)
  • Finish

Navigate to Existing Page

002-pagefound

In the browser enter the following url http://localhost:8080/Filter404/index.jsp

Navigate to Non-Existent Page

003-notfound

In the browser enter the following url http://localhost:8080/Filter404/xxx.html

Create the Filter (first attempt)

We want to create a Filter that is going to intercept all incoming and outgoing requests and responses to and from the server and catch a 404 not found error and handle it. To start off, let’s create the PageNotFound filter and a TestResponseWrapper to double-check the calls on the Response object that will be made by the Web Server.

create PageNotFoundFilter.java

package com.skills421.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

import com.skills421.filter.wrapper.TestResponse;

/**
* Servlet Filter implementation class PageNotFoundFilter
*/
@WebFilter(filterName = "PageNotFoundFilter", urlPatterns = {"/*"})
public class PageNotFoundFilter implements Filter
{

/**
* Default constructor.
*/
public PageNotFoundFilter()
{
}

/**
* @see Filter#destroy()
*/
public void destroy()
{
}

/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
System.out.println("PageNotFound-Filter");

HttpServletResponse httpResponse = (HttpServletResponse) response;

TestResponse testResponse = new TestResponse(httpResponse);

System.out.println("*** PageNotFound-Filter - before chain ***");

chain.doFilter(request, testResponse);

System.out.println("*** PageNotFound-Filter - after chain ***");

System.out.println(testResponse.isCommitted());
System.out.println(testResponse.getStatus());

if (testResponse.getStatus() == HttpServletResponse.SC_NOT_FOUND)
{
System.out.println("Intercepted 404");

httpResponse.getWriter().write("404 Error Successfully Intercepted");
httpResponse.setStatus(HttpServletResponse.SC_OK);

System.out.format("testResponse: %s",testResponse);
}
}

/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException
{
}

}

Create TestResponse.java

package com.skills421.filter.wrapper;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import java.util.Locale;

import javax.servlet.ServletOutputStream;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class TestResponse extends HttpServletResponseWrapper
{
@Override
public void addCookie(Cookie cookie)
{
System.out.println("TestResponse.addCookie");

super.addCookie(cookie);
}

@Override
public boolean containsHeader(String name)
{
System.out.println("TestResponse.containsHeader");

return super.containsHeader(name);
}

@Override
public String encodeURL(String url)
{
System.out.println("TestResponse.encodeURL");

return super.encodeURL(url);
}

@Override
public String encodeRedirectURL(String url)
{
System.out.println("TestResponse.encodeRedirectURL");

return super.encodeRedirectURL(url);
}

@Override
public String encodeUrl(String url)
{
System.out.println("TestResponse.encodeUrl");

return super.encodeUrl(url);
}

@Override
public String encodeRedirectUrl(String url)
{
System.out.println("TestResponse.encodeRedirectUrl");

return super.encodeRedirectUrl(url);
}

@Override
public void sendError(int sc, String msg) throws IOException
{
System.out.println("TestResponse.sendError");

super.sendError(sc, msg);
}

@Override
public void sendError(int sc) throws IOException
{
System.out.println("TestResponse.sendError");

super.sendError(sc);
}

@Override
public void sendRedirect(String location) throws IOException
{
System.out.println("TestResponse.sendRedirect");

super.sendRedirect(location);
}

@Override
public void setDateHeader(String name, long date)
{
System.out.println("TestResponse.setDateHeader");

super.setDateHeader(name, date);
}

@Override
public void addDateHeader(String name, long date)
{
System.out.println("TestResponse.addDateHeader");

super.addDateHeader(name, date);
}

@Override
public void setHeader(String name, String value)
{
System.out.println("TestResponse.setHeader");

super.setHeader(name, value);
}

@Override
public void addHeader(String name, String value)
{
System.out.println("TestResponse.addHeader");

super.addHeader(name, value);
}

@Override
public void setIntHeader(String name, int value)
{
System.out.println("TestResponse.setIntHeader");

super.setIntHeader(name, value);
}

@Override
public void addIntHeader(String name, int value)
{
System.out.println("TestResponse.addIntHeader");

super.addIntHeader(name, value);
}

@Override
public void setStatus(int sc)
{
System.out.println("TestResponse.setStatus");

super.setStatus(sc);
}

@Override
public void setStatus(int sc, String sm)
{
System.out.println("TestResponse.setStatus");

super.setStatus(sc, sm);
}

@Override
public int getStatus()
{
System.out.println("TestResponse.getStatus");

return super.getStatus();
}

@Override
public String getHeader(String name)
{
System.out.println("TestResponse.getHeader");

return super.getHeader(name);
}

@Override
public Collection getHeaders(String name)
{
System.out.println("TestResponse.getHeaders");

return super.getHeaders(name);
}

@Override
public Collection getHeaderNames()
{
System.out.println("TestResponse.getHeaderNames");

return super.getHeaderNames();
}

@Override
public ServletResponse getResponse()
{
System.out.println("TestResponse.getResponse");

return super.getResponse();
}

@Override
public void setResponse(ServletResponse response)
{
System.out.println("TestResponse.setResponse");

super.setResponse(response);
}

@Override
public void setCharacterEncoding(String charset)
{
System.out.println("TestResponse.setCharacterEncoding");

super.setCharacterEncoding(charset);
}

@Override
public String getCharacterEncoding()
{
System.out.println("TestResponse.getCharacterEncoding");

return super.getCharacterEncoding();
}

@Override
public ServletOutputStream getOutputStream() throws IOException
{
System.out.println("TestResponse.getOutputStream");

return super.getOutputStream();
}

@Override
public PrintWriter getWriter() throws IOException
{
System.out.println("TestResponse.getWriter");

return super.getWriter();
}

@Override
public void setContentLength(int len)
{
System.out.println("TestResponse.setContentLength");

super.setContentLength(len);
}

@Override
public void setContentLengthLong(long len)
{
System.out.println("TestResponse.setContentLengthLong");

super.setContentLengthLong(len);
}

@Override
public void setContentType(String type)
{
System.out.println("TestResponse.setContentType");

super.setContentType(type);
}

@Override
public String getContentType()
{
System.out.println("TestResponse.getContentType");

return super.getContentType();
}

@Override
public void setBufferSize(int size)
{
System.out.println("TestResponse.setBufferSize");

super.setBufferSize(size);
}

@Override
public int getBufferSize()
{
System.out.println("TestResponse.getBufferSize");

return super.getBufferSize();
}

@Override
public void flushBuffer() throws IOException
{
System.out.println("TestResponse.flushBuffer");

super.flushBuffer();
}

@Override
public boolean isCommitted()
{
System.out.println("TestResponse.isCommitted");

return super.isCommitted();
}

@Override
public void reset()
{
System.out.println("TestResponse.reset");

super.reset();
}

@Override
public void resetBuffer()
{
System.out.println("TestResponse.resetBuffer");

super.resetBuffer();
}

@Override
public void setLocale(Locale loc)
{
System.out.println("TestResponse.setLocale");

super.setLocale(loc);
}

@Override
public Locale getLocale()
{
System.out.println("TestResponse.getLocale");

return super.getLocale();
}

@Override
public boolean isWrapperFor(ServletResponse wrapped)
{
System.out.println("TestResponse.isWrapperFor");

return super.isWrapperFor(wrapped);
}

@Override
public boolean isWrapperFor(Class<?> wrappedType)
{
System.out.println("TestResponse.isWrapperFor");

return super.isWrapperFor(wrappedType);
}

public TestResponse(HttpServletResponse response)
{
super(response);

System.out.println("TestResponse()");

}

}

Filtering Page Found – the output

Now let’s run the project on the server and navigate to the following page: http://localhost:8080/Filter404/index.jsp

The output we see is as follows:

PageNotFound-Filter
TestResponse()
*** PageNotFound-Filter - before chain ***
TestResponse.setContentType
TestResponse.getWriter
*** PageNotFound-Filter - after chain ***
TestResponse.isCommitted
false
TestResponse.getStatus
200
TestResponse.getStatus

The methods that the WebServer calls on the Response Wrapper for a page that exists are as follows:

  • setContentType
  • getWriter
  • getStatus

Note that the response is NOT committed

Filtering Page Not Found – the output

Now let’s run the project on the server and navigate to the following page: Now let’s run the project on the server and navigate to the following page: http://localhost:8080/Filter404/xxx.html

The output we see is as follows:

PageNotFound-Filter
TestResponse()
*** PageNotFound-Filter - before chain ***
TestResponse.sendError
*** PageNotFound-Filter - after chain ***
TestResponse.isCommitted
true
TestResponse.getStatus
404
TestResponse.getStatus
Intercepted 404
testResponse: com.skills421.filter.wrapper.TestResponse@18879c56

The methods that the WebServer calls on the Response Wrapper for a page that does NOT exist are as follows:

  • sendError
  • getStatus

Note that the response IS committed for a page not found error (404)

Create our PageNotFoundResponse

Create PageNotFoundResponse.java

package com.skills421.filter.wrapper;

import java.io.IOException;

import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;

public class PageNotFoundResponse extends HttpServletResponseWrapper
{

public PageNotFoundResponse(HttpServletResponse response)
{
super(response);
}

@Override
public void sendError(int sc,String msg) throws IOException
{
this.setStatus(sc);
}
}

Modify PageFilter

Modify PageFilter.java

package com.skills421.filter;

import java.io.IOException;

import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;

import com.skills421.filter.wrapper.PageNotFoundResponse;

/**
* Servlet Filter implementation class PageNotFoundFilter
*/
@WebFilter(filterName = "PageNotFoundFilter", urlPatterns = {"/*"})
public class PageNotFoundFilter implements Filter
{

/**
* Default constructor.
*/
public PageNotFoundFilter()
{
}

/**
* @see Filter#destroy()
*/
public void destroy()
{
}

/**
* @see Filter#doFilter(ServletRequest, ServletResponse, FilterChain)
*/
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException
{
HttpServletResponse httpResponse = (HttpServletResponse) response;

PageNotFoundResponse pageNotFoundResponse = new PageNotFoundResponse(httpResponse);

chain.doFilter(request, pageNotFoundResponse);

if (pageNotFoundResponse.getStatus() == HttpServletResponse.SC_NOT_FOUND)
{
httpResponse.getWriter().write("404 Error Successfully Intercepted");
httpResponse.setStatus(HttpServletResponse.SC_OK);
}
}

/**
* @see Filter#init(FilterConfig)
*/
public void init(FilterConfig fConfig) throws ServletException
{
}

}

Run the Code

Now, let’s run the code on the server and we can see the following output:

002-pagefound
004-404handled

http://localhost:8080/Filter404/index.jsp http://localhost:8080/Filter404/xxx.html We have successfully created the code to intercept a 404 Page Not Found error message from the Server and replace the page with a success status and our custom content.

Part 2 – Generating Page Content

Continue to  Part 2

Download the Source

The source for this example can be downloaded from Github at https://github.com/skills421Training/Filter404/tree/Part-1

Advertisement

One comment

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s