getting IllegalStateException within the doFilter method - java

When i create a servlet filter in Spring MVC, I am getting the following exception.
[javax.servlet.ServletException: java.lang.IllegalStateException: Cannot create a session after the response has been committed] with root cause
when i put the sysout i could understand that the exception occurs at the redirect line, but didn't understand why
can anyone please tell me some solution for this
SessionFilter.java
public class SessionFilter implements Filter {
private ArrayList<String> urlList;
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getServletPath();
boolean allowedRequest = false;
if(urlList.contains(url)) {
allowedRequest = true;
}
if (!allowedRequest) {
HttpSession session = request.getSession(false);
if (null == session) {
System.out.println("preparing for redirect");
response.sendRedirect("index.jsp");
}
}
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig config) throws ServletException {
System.out.println("entered init");
String urls = config.getInitParameter("avoid-urls");
StringTokenizer token = new StringTokenizer(urls, ",");
urlList = new ArrayList<String>();
while (token.hasMoreTokens()) {
urlList.add(token.nextToken());
}
}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>SpringMVCHibernate</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
<servlet>
<servlet-name>dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>dispatcher</servlet-name>
<url-pattern>*.do</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>1</session-timeout>
</session-config>
<filter>
<filter-name>SessionFilter</filter-name>
<filter-class>com.common.dao.SessionFilter</filter-class>
<init-param>
<param-name>avoid-urls</param-name>
<param-value>index.jsp</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>SessionFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
:
:
:

To simple and short Answer for your Question:
To avoid this , you should have a return statement , or avoid redirecting or forwarding request , or these kind of things should be done by the last filter in the filter chain.
For More Details Explanation you can read below :
This Exception occurs when you try to send response again when the response is already committed and flushed to user.
For Example :
Here in below example code ,first the request will be forwarded to index_test.jsp and response will be flushed to user , then the control will again come back to filter and try to send another response (redirect)to user , and it will fail.
Usually we check multiple conditions in filter and accordingly forward and redirect , if two conditions are met , then it will create a problem .
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
request.getRequestDispatcher("index_test.jsp").forward(request, response);
((HttpServletResponse)response).sendRedirect("new.jsp");
chain.doFilter(request, response);
}
Solution for your case :
To avoid this , you should have a return statement , or avoid redirecting or forwarding request , or these kind of things should be done by the last filter in the filter chain.
So you could change your code as :
public class SessionFilter implements Filter {
private ArrayList<String> urlList;
#Override
public void destroy() {
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getServletPath();
boolean allowedRequest = false;
if(urlList.contains(url)) {
allowedRequest = true;
}
if (!allowedRequest) {
HttpSession session = request.getSession(false);
if (null == session) {
System.out.println("preparing for redirect");
response.sendRedirect("index.jsp");
return;
}
}
chain.doFilter(req, res);
}
#Override
public void init(FilterConfig config) throws ServletException {
System.out.println("entered init");
String urls = config.getInitParameter("avoid-urls");
StringTokenizer token = new StringTokenizer(urls, ",");
urlList = new ArrayList<String>();
while (token.hasMoreTokens()) {
urlList.add(token.nextToken());
}
}

Its Obvious right :
System.out.println("preparing for redirect");
response.sendRedirect("index.jsp");
return;
We are have return after that statement.
So further execution wont happen so u are not getting exception.
See we cant involve both filtering and Redirect or Forward in same block it will give IllegalStateException because :
This Exception occurs when you try to send response again when the response is already committed and flushed to user

Related

How to update the response Content-Type after Servlet processing is done using ServeletFilter

I tried to change the ServletResponse Content-Type using ServletFilter. But, the servelet (in my content, AxisServlet) updates that Content-Type when chain.doFilter() calls. But other Response Headers are correctly updated.
I tried setting response headers after doFilter is called. At that time no response header was updated.
Does anyone know a way to update the Content-Type of the ServletResponse after Servelt is completed?
Code :
public class HeaderFilter implements Filter {
private HashMap<String,String> rsCustomHeaders = new HashMap<String,String>();
public void init(FilterConfig config) throws ServletException {
Enumeration<String> initParameterNames = config.getInitParameterNames();
while (initParameterNames.hasMoreElements()) {
String initParameterName = initParameterNames.nextElement();
rsCustomHeaders.put(initParameterName, config.getInitParameter(initParameterName));
}
System.out.println("init().rsCustomHeaders : " + rsCustomHeaders);
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
for (Map.Entry<String, String> rsCustomHeaderEntry : rsCustomHeaders.entrySet()) {
httpServletResponse.addHeader(rsCustomHeaderEntry.getKey(), rsCustomHeaderEntry.getValue());
}
System.out.println("doFilter().encoding :Set Response Headers Done");
chain.doFilter(httpServletRequest, httpServletResponse);
System.out.println("doFilter().HeaderFilter is Done!!!");
}
public void destroy() {
System.out.println("destroy(). : Destroy is called!");
}
}
web.xml
<filter>
<filter-name>HeaderFilter</filter-name>
<filter-class>filters.HeaderFilter</filter-class>
<init-param>
<param-name>content-type</param-name>
<param-value>application/xml; charset=utf-8</param-value>
</init-param>
<init-param>
<param-name>Content_type</param-name>
<param-value>text/xml; charset=utf-8</param-value>
</init-param>
<init-param>
<param-name>rq_content-type</param-name>
<param-value>text/xml; charset=utf-8</param-value>
</init-param>
<init-param>
<param-name>Header-X</param-name>
<param-value>Value-X</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>HeaderFilter</filter-name>
<url-pattern>/services/GradeThreeMath</url-pattern>
</filter-mapping>
Set content type on the original response.
Use HttpServletResponseWrapper with overridden setContentType to wrap response that is passed to child.doFilter. Overridden setContentType should just ignore any attempts to change content type.
The code snippet:
// Setting content type
httpServletResponse.setContentType("you-content-type");
chain.doFilter(httpServletRequest, new HttpServletResponseWrapper(httpServletResponse) {
#Override
public void setContentType(final String type) {
// Ignore any further attempts to change content type
}
});

communicating between php and servlet applications

I am creating a web servlet , which is presently accessed by php , using :
$payload = file_get_contents('http://localhost:8080/HelloWorldServlet/index?name=Joe&age=24');
This calls a HelloWorldServlet web application running on my tomcat server
with a url pattern for /index.
The doGet() is invoked for the servlet. The doGet() method writes the data in json, as response..
My question is how do I send back the json to php , just to display it?
Also, the php application is running on port 8888.
Here is the code for doGet:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
//GsonBuilder builder = new ();
GsonBuilder builder = new GsonBuilder();
Gson gson = builder.create();
response.setContentType("application/json; charset=UTF-8");
String key = request.getParameter("name");
String value = request.getParameter("age");
String jsonString = gson.toJson(new Tuple(key, value)).toString();
request.setAttribute("data", jsonString);
//response.sendRedirect("localhost:8888/MYPHPAPPLICATION/testcall.php");
try {
getServletConfig().getServletContext().getRequestDispatcher(
"/display.jsp").forward(request,response);
} catch (ServletException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Also, I created a filter for changing the request when it tried to forward to a php page.
But it didn't work as expected.
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws ServletException, IOException {
HttpServletRequest request = (HttpServletRequest) req;
String requestURI = request.getRequestURI();
if (requestURI.contains("display.jsp"))
{
String toReplace = "localhost:8888/MYPHPAPPLICATION/testcall.php";
req.getRequestDispatcher(toReplace).forward(req, res);
} else
chain.doFilter(req, res);
}
This is my web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" id="WebApp_ID" version="2.5">
<display-name>HelloWorldServlet</display-name>
<servlet>
<description></description>
<servlet-name>HelloWorldServlet2</servlet-name>
<servlet-class>com.srccodes.example.HelloWorld</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>HelloWorldServlet2</servlet-name>
<url-pattern>/index</url-pattern>
</servlet-mapping>
<filter>
<filter-name>urlRewriteFilter</filter-name>
<filter-class>com.srccodes.example.UrlRewriteFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>urlRewriteFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
</web-app>
Just write it to the response body and return immediately.
#Override
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// ...
String jsonString = gson.toJson(new Tuple(key, value)).toString();
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(jsonString);
}
You don't need JSP for this. It's primarily designed to act as a template for HTML output.

my servlet mapping spoil my filter

In my program any url in the form of /Controller/* is redirected by my servlet mapping to Controller class.
I tried to add a filter for authantication, if user is not logged in and path is not /Controller/RegForm it's redirecting to /Controller/RegForm.
Problem is because my servlet mapping redirects to /Controller, filter always gets the /Controller as path.
How can I use both filter and the servlet mapping ?
This is my web.xml:
<filter>
<filter-name>AuthFilter</filter-name>
<filter-class>AuthFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>AuthFilter</filter-name>
<url-pattern>/Controller/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>Controller</servlet-name>
<servlet-class>Controller</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>Controller</servlet-name>
<url-pattern>/Controller/*</url-pattern>
</servlet-mapping>
<session-config>
<session-timeout>
30
</session-timeout>
</session-config>
my filter:
#WebFilter("/Controller/*")
public class AuthFilter implements Filter {
#Override
public void init(FilterConfig config) throws ServletException {
// If you have any <init-param> in web.xml, then you could get them
// here by config.getInitParameter("name") and assign it as field.
}
#Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
HttpSession session = request.getSession(false);
String path = ((HttpServletRequest) request).getServletPath();
if ((session != null && session.getAttribute("student") != null )||(excludeFromFilter(path))) {
chain.doFilter(req, res); // Log
}
else {
response.sendRedirect("/registration-war/Controller/RegForm"); // No logged-in user found, so redirect to login page.
}
}
private boolean excludeFromFilter(String path) {
if (path.equals("/Controller/RegForm")) {
return true; // add more page to exclude here
} else {
return false;
}
}
You use HttpServletRequest.getServletPath() which returns the servlet URL which is (according to your servlet mapping) "/Controller".
You want the path info not the servlet path:
Returns any extra path information associated with the URL the client sent when it made this request. The extra path information follows the servlet path but precedes the query string and will start with a "/" character.
So for example this will return "/RegForm" if your user requests the /Controller/RegForm page.
String pathInfo = HttpServletRequest.getPathInfo();

IE10 document mode at the java side

Is there any way of getting to know IE document mode on the java servlet. Apparently, I tried to get browser information using "User-Agent" string, but i am unable to get document mode from this.
To get the document mode of IE, use below Servlet class.
Code:
public class DocumentModeOfIE extends HttpServlet {
private String documentMode;
public void init(ServletConfig config) throws ServletException {
}
public void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
PrintWriter out = resp.getWriter();
resp.setContentType("text/html");
documentMode = req.getHeader("X-UA-Compatible");
out.println(documentMode);
}
public void destroy() {
}
}
==============To Set the IE document mode to particular standard mode (i.e IE 7 0r IE8)==============
Code :
Using filter....
Filter Class:
public class UserAgentCompatibleFilter implements javax.servlet.Filter {
private Logger log = Logger.getLogger("UserAgentCompatibleFilter");
private String compatibilityMode;
public void destroy() {
}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
if (compatibilityMode != null) {
HttpServletResponse res = (HttpServletResponse) resp;
res.addHeader("X-UA-Compatible", compatibilityMode);
}
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {
compatibilityMode = config.getInitParameter("compatibilityMode");
if (compatibilityMode == null) {
log.warn("No CompatibilityMode set for UserAgentCompatibleFilter, thus disabling it");
}
}
}
web.xml :
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
version="2.5">
<!-- filter component start -->
<filter>
<filter-name>UserAgentCompatibleFilter</filter-name>
<filter-class>com.standardandpoors.ata.web.UserAgentCompatibleFilter</filter-class>
<init-param>
<param-name>compatibilityMode</param-name>
<param-value>IE=8</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>UserAgentCompatibleFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- filter component end -->
I hope this will help u most......

J2EE filter : login page unable to load the css or any images

I have already visited Java FilterImplementation for session checking link, which says about Spring security. I did not get the help i need.
After applying filter login.jsp is unable to load CSS and images.
I am trying simple example providing filter in web.xml and applying the filter on pages other than login.jsp.
Web.xml file is :
<filter>
<filter-name>struts2</filter-name>
<filter-class>
org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
</filter-class>
</filter>
<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>AuthenticationFilter2</filter-name>
<filter-class>filter.AuthorizationFilter2</filter-class>
<init-param>
<param-name>avoid-urls</param-name>
<param-value>login.jsp</param-value>
</init-param>`
<filter>
And the filter class is :
private ArrayList<String> urlList;
public void destroy() {
// TODO Auto-generated method stub
System.out.println("authorization filter2 destroy method....");
}
public void doFilter(ServletRequest req, ServletResponse res,
FilterChain chain) throws IOException, ServletException {
System.out.println("authorization filter2 doFilter method....");
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response = (HttpServletResponse) res;
String url = request.getServletPath();
System.out.println("ppp:"+request.getRequestURL());
System.out.println("url is :"+url);
boolean allowedRequest = false;
System.out.println("url list is :"+urlList);
if(urlList.contains(url.substring(1))) {
allowedRequest = true;
}
System.out.println("request allowed....."+allowedRequest);
if (!allowedRequest) {
Map session = ActionContext.getContext().getSession();
/*HttpSession session = request.getSession(false);*/
/* if (null == session) {
response.sendRedirect("login.jsp");
}*/
System.out.println("session contains login :"+session.containsKey("login"));
if(!session.containsKey("login")){
response.sendRedirect("login.jsp");
}
}
chain.doFilter(req, res);
}
public void init(FilterConfig config) throws ServletException {
System.out.println("authorization filter2 init method....");
String urls = config.getInitParameter("avoid-urls");
StringTokenizer token = new StringTokenizer(urls, ",");
urlList = new ArrayList<String>();
while (token.hasMoreTokens()) {
urlList.add(token.nextToken());
}
}
Login page contains css and images as per the requirement.
Please help me out. Thank you.
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
String uri = ((HttpServletRequest)request).getRequestURI();
#SuppressWarnings("rawtypes")
Map session = ActionContext.getContext().getSession();
if ( uri.indexOf("/css") > 0){
chain.doFilter(request, response);
}
else if( uri.indexOf("/images") > 0){
chain.doFilter(request, response);
}
else if( uri.indexOf("/js") > 0){
chain.doFilter(request, response);
}
else if (session.containsKey("login")) {
chain.doFilter(request, response);
}
else {
((HttpServletResponse)response).sendRedirect(((HttpServletRequest)request).getContextPath() + "/login?authentication=failed");
}
}
put this block of code in your action class , it works.
Thank you all.
Your CSS files and images used on logjn.jsp page have to be excluded from your filter

Categories

Resources