1

I'm using JSP/Servlet to build web-site. The problem is, when I reload the page many times IllegalStateException is thrown or the same data occurs variable times in the page(why, no javascript anyway?).

This is the Page.class that calls implemented view method.

public abstract class Page extends Action {
protected String bodyViewPath = "body.jsp";

protected String layoutPath = "index.jsp";

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    // TODO Auto-generated method stub
    request = req;
    response = resp;
    try{
        view();
    }catch(Exception e) {
        throw new RuntimeException(e);
    }
}
protected void forward() throws Exception {
    String base = "/WEB-INF/";
    request.setAttribute("bodyViewPath", base +"/views/" + bodyViewPath);
    request.getRequestDispatcher(base + layoutPath).include(request, response);
}}

AdminPage.class:

public class AdminPage extends Page {

protected List<String> parameters;

@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    try{
        request = req;
        response = resp;
        if(getSession().getAttribute("user") == null) {
            redirect("/admin/login");
            return;
        }

        parseParameters();
        if(parameters.size() == 0) {
            redirect("/admin/index");
            return;
        }
        getTargetInstance().doGet(request, response);
    }catch(Exception e) {
        throw new RuntimeException(e);
    }

}

@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
        throws ServletException, IOException {
    try{
        request = req;
        response = resp;
        parseParameters();
        if(getSession().getAttribute("user") == null) {
            redirect("/admin/login");
            return;
        }

        if(parameters.size() == 0) {
            throw new RuntimeException("Not allowed");
        }
        getTargetInstance().doPost(request, response);
    }catch(Exception e) {
        throw new RuntimeException(e);
    }
}

protected void parseParameters() {
    String requestURI = request.getRequestURI().substring(1);
    parameters = new ArrayList<String>();
    List<String> params = Arrays.asList(requestURI.split("/"));
    if(params.size() > 2) {
        for(int i = 2; i < params.size(); i++) {
            parameters.add(params.get(i));
        }
    }
}

protected Action getTargetInstance() throws Exception {
    String actionName = parameters.get(0).substring(0,1).toUpperCase() + parameters.get(0).substring(1).toLowerCase();
    Class<Action> clazz = (Class<Action>) Class.forName("servlet.admin." + actionName);
    return clazz.newInstance();
}
}

This is the main Index, page that extends Page.class, which I use to view the list of registered users.

package servlet.admin;
import java.util.List;
import core.Page;
import data.Users;

public class Index extends Page {
public Index() {
    bodyViewPath = "admin/index.jsp";
}

public void view() throws Exception {
    List<Users> users = (List<Users>) pm.newQuery(Users.class).execute();
    setRequestAttribute("users", users);
    setRequestAttribute("logout_url", request.getContextPath() + "/admin/logout");
    forward();
}}

This is the layout:

<%@taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ page language="java" contentType="text/html; charset=UTF-8"
pageEncoding="UTF-8"%>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>Insert title here</title>
</head>
<body>
<jsp:include page="${bodyViewPath}" />
</body>
</html>

This is the view file:

<%@include file="/WEB-INF/includes.jsp" %>
<h1>List of registered users</h1>
<div>
<a href="${logout_url}">Logout</a>
</div>
<table>
<tr>
<th>ID</th>
<th>Name</th>
<th>Surname</th>
</tr>
<c:forEach items="${users}" var="user">
<tr>
<td>${user.id}</td>
<td>${user.name}</td>
<td>${user.surname}</td>
</tr>
</c:forEach>
</table>

The exception:

HTTP Status 500 -

type Exception report

message

description The server encountered an internal error () that prevented it from fulfilling this request.

exception

java.lang.RuntimeException: java.lang.RuntimeException: java.lang.IllegalStateException: Cannot forward after response has been committed
core.AdminPage.doGet(AdminPage.java:38)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

root cause

java.lang.RuntimeException: java.lang.IllegalStateException: Cannot forward after response has been committed
core.Page.doGet(Page.java:23)
core.AdminPage.doGet(AdminPage.java:36)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

root cause

java.lang.IllegalStateException: Cannot forward after response has been committed
core.Page.forward(Page.java:43)
servlet.admin.Index.view(Index.java:17)
core.Page.doGet(Page.java:21)
core.AdminPage.doGet(AdminPage.java:36)
javax.servlet.http.HttpServlet.service(HttpServlet.java:621)
javax.servlet.http.HttpServlet.service(HttpServlet.java:722)

note The full stack trace of the root cause is available in the Apache Tomcat/7.0.5 logs.

Before asking when I searched, many people say this is because of the farward method of the RequestDispatcher. But here I am not printing anything before calling forward, since I am passing all the data to the view(bodyViewPath variable) and anyway, my forward method is called at the end of my view method.

Please, help me.

Sabyrzhan
  • 175
  • 2
  • 16

2 Answers2

2

I'm using JSP/Servlet to build web-site. The problem is, when I reload the page many times IllegalStateException is thrown

That's because you assigned HttpServletRequest and HttpServletResponse as instance variables of an application wide servlet instance which causes that they are not threadsafe.

protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
    // ...
    request = req; // Fail!
    response = resp; // Fail!
    // ...
}

If you fire multiple requests in a short time, then this way the chance is big that those variables get overridden by a completely different request while they are still busy processing.

In other words, you're just using servlets the wrong way and your whole MVC attempt is also very questionable. First learn how servlets works and then lookup the front controller pattern (but please use it for learning/hobbying purposes only and don't reinvent the wheel).

Community
  • 1
  • 1
BalusC
  • 1,082,665
  • 372
  • 3,610
  • 3,555
1

So, given this stacktrace:

...
core.Page.doGet(Page.java:21)
core.AdminPage.doGet(AdminPage.java:36)
...

and the fact that HttpServletResponse is committed in Page.doGet and not commited in AdminPage.doGet there must be something wrong with these lines of code:

    request = req;
    response = resp;
    if(getSession().getAttribute("user") == null) {
        redirect("/admin/login");
        return;
    }

    parseParameters();
    if(parameters.size() == 0) {
        redirect("/admin/index");
        return;
    }
    getTargetInstance().doGet(request, response);

You will need to investigate the exact location where your response is becoming committed, either by crude System.outing or by debugging your code.

Oleg Mikheev
  • 17,186
  • 14
  • 73
  • 95
  • OK, i temporarily solved it by checking response object if it is committed in doGet methods. But still checking the problem and see when after calling RequestDispatcher.forward the state is set to TRUE. – Sabyrzhan Dec 17 '11 at 21:44