Friday, February 22, 2013

Cannot call sendRedirect() after the response has been committed

So for the past few months I've noticed the following error on one page in our system: Cannot call sendRedirect() after the response has been committed
Nothing on that page that deals with the request or response has changed in the past few months and the error was only happening on my dev machine, our test and production servers worked fine, so I thought it was just my machine. The other day a colleague mentioned they were also getting the error. So we started looking into it. The java code in the page seemed fine, so for a while we were stumped. He realized that over the past few months lots of html code was put before the sendRedirect. So we moved the redirect to happen before the HTML code and our problem went away. Which reminded me, I've read somewhere that you can't have any HTML tags on a JSP page before the sendRedirect call because those tags are written to the response as they are hit, which effectively commits the response to that page making it impossible to forward to another page.

Lessons learned: Don't use a JSP page as a servlet or you will have weird bugs that only make sense when you view the generated code; don't forget HTML on a JSP commits the response.

Wednesday, January 9, 2013

Cookie fun

Yesterday I ran into a problem while testing where my machine wasn't getting the correct localized strings for the french language. After lots of debugging we found that the localization is dependent on a locale set in a cookie that every user is supposed to have which wasn't getting created on my machine. Looking at the code we couldn't see any reason why it wasn't working on my machine but was working on another developer's machine. After some more debugging we found that when the cookie is created it's domain is explicitly set. Since I was accessing the site from my local machine the domain I was using didn't match the domain of the cookie. So, I modified my hosts file so that localhost mapped to the same domain as the cookie, and now all the localized strings work correctly, because the cookie is created and the locale is stored in it.

Tuesday, January 8, 2013

Page encoding issues

Today I got a bug assigned to me that had to do with how data was being sent in post requests. On the page a user could enter text in several fields, if they entered ŽŒŸ І€ƒaniežœš and submitted it everything on the page and subsequent pages worked fine. If however the user used these characters: ëïéâäîü they would be converted to question marks. My dilemma is that only a month ago I made a whole bunch of changes to get that first set of characters to work and I didn't want to make all the same changes again to get the new set to work. I thought (more like prayed) it had to be something simple like page encoding. Long story short I fixed the problem with about 10 lines of code. I made sure each JSP that was getting hit though the submit process had it's character set and page encoding set to UTF-8. Then in each function in the servlet I made sure to set the characterEncoding on the request before it was ever used and on the response right before it was redirected or written to. That fixed the issue for me. No more question marks and no need to make lots of convoluted changes.

For future reference one team memeber suggested I try the character encoding CP1252, which made progress but didn't fix everything. Also there is a chance I didn't try it on every page before finding a page in the process I forgot about.

Another team member suggested I do the following:
new String(theTextToConvert.getBytes("Windows-1252"), "ISO-8859-1")
That also seemed to make progress but still didn't work fully and I would have had to make about 500 changes in several files instead of just 10 in two files.

Wednesday, December 12, 2012

PowerMock no last call on a mock available

Seems like every other time I write unit tests with PowerMock I run into this error "IllegalStateException: no last call on a mock available" What it should read is "Hey! You forgot to include in the PrepareForTest attribute a class that is used statically and was mocked with the MockStatic function"
At least that's always the reason I see that error.

Feel free to let me know if there are other reasons it pops up.


Wednesday, December 5, 2012

Race Condition

I have this weird problem where two separate users upload a picture to my web service and user1 see's user2's error messages. Reviewing the code nothing sticks out to me, so I would like to ask what is wrong with this code and why was it creating this condition where errors for user2 would be visible to user1?

Here is some simplified code to try and demonstrate the situation.

    public class SomeService {
       
        private static SomeService service;
        private SomeService() {
        }
       
        public static SomeService getInstance() {
            if(service == null) {
               service = new SomeService();
            }
        }
   
        public ErrorStatus doSomething(ErrorStatus es) {
           
            es = new ErrorStatus(es);
            // stuff happens that causes an error
            es.addMessage(new ErrorMessage("some error happened"));
            return es;
        }
       
        public ErrorStatus doSomethingElse(ErrorStatus es) {
           
            es = new ErrorStatus(es);
            // stuff happens that causes an error
            es.addMessage(new ErrorMessage("some different error happened"));
            return es;
        }
    }
   
    public class ErrorMessage {
        String message;

        //simple constructor, getters and setters, nothing interesting
    }
   
    public class ErrorStatus {
        int id;
        String status;
        List<ErrorMessage> messages;

        public ErrorStatus() {
             id = 0;
             status = "";
             messages = new ArrayList<>();
        }

        public ErrorStatus(ErrorStatus other) {
            id = other.getId();
            status = other.getStatus();
            messages = other.getMessages();
        }
       
        public void addMessage(ErrorMessage message) {
       
            //data checks
            messages.add(message);
        }
       
        //getters and setters
    }   
   
    public class UploadServlet extends HttpServlet {
       
        public doGet(request, response) {
           
            ErrorStatus es = new ErrorStatus();
            SomeService service = SomeService.getInstance();
           
            es = service.doSomething(es);
           
            es = service.doSomethingElse(es);
           
            printErrors(response.getWriter(), es);
           
        }
               
        public void printErrors(PrintWriter pw, ErrorStatus es) {
           
            for(int i = 0; i < es.getMessages().size(); i++) {
               
                pw.write(es.getMessages().get(i).getMessage());
            }
        }
    }

The two places in the code I think something weird could be happening is the copy constructor or the fact that the service is a singleton. Maybe I'm not copying the list correctly, or maybe the service being a singleton changes how the stack and heap are used, I'm really not sure. From my understanding of how the stack, heap, singletons and servlets work one users data would never be affected by another users data.
Also they only part of this that ever had problems was the list, the primitive data was always correct, only the list of errors was ever showing up for the wrong user.

I should note, I have solved the problem I just don't understand why it was a problem. The solution was to stop using the copy constructor and to just let the ErrorStatus object get modified in the doSomething and doSomethingElse methods. So the revised code would have a void return type for doSomething and would just call es.addMessage, also the copy constructor was deleted from ErrorStatus.

Any help understanding why this caused a race condition would be appreciated.

I'll update this post once I find the answer to why this was a problem.

Update 1/8/13:
So in my spare time I tried to reproduce the error programmatically, I wrote a multithreaded test program which would run the code thousands of times, unfortunately I couldn't reproduce the race condition. As I have more spare time I might try a few more things but I'm beginning to think there was something more going on that I didn't include when I simplified the process to post here.

Monday, November 5, 2012

Java's Jimi pro library

So a few months ago I was asked to add the ability to our web app to allow tiff files to be uploaded. I'm not familiar with all the caveates of images and the Java language but apparently there are a few formats that aren't allowed by default, one of them being TIFF. So I had to find an open source library to facilitate uploading TIFF images. I looked into a few and by far the easiest to use and incorporate into our app was JimiPro. It's one jar file and only one command for most cases. Simple enough. I included the jar and started using the Jimi.getImage method and got everything working just the way we needed.
Six months later.... Web Ops tells my boss they are noticing something very strange, the servers crash every few weeks because too many threads are running. So being the go to guy for all the strange issues I started looking into this. Luckily a thread dump gave us a starting point somewhere in the Jimi library. So I dove in and found that the getImage call in one of the three places I used it was creating a waiting thread that never got notified. With some direction from my boss I started looking into why only one of the three didn't work. Turns out when you use getImage you need to force it to recognize all the pixels were loaded and that it should stop. One easy way to do that is to create an ImageIcon and call getImage on it. So adding one simple line 'new ImageIcon(image).getImage()' solved my problem and got the waiting thread to stop waiting.

Gotta love those handy undocumented 'features' that cause your whole system to crash!

Friday, October 26, 2012

jQuery, ajax and click functions that don't work

So the issue today dealt with a page that uses jQuery to turn a selection box into a drop down multi select box. Check it out here it's a pretty nice plugin.
Anyway, I populate the page with my data, create the drop down and then when the drop down changes the page makes an Ajax request to reload the page with new data. The problem was that when the page reloaded the items in the drop down didn't work the same. each item consists of a label and a checkbox. The checkbox still worked fine the problem was that now if you clicked on the label it wouldn't select the checkbox. After some research I found there is a pretty common problem with Ajax and jQuery where the dynamically assigned functions stop working after an Ajax call. I set some break points in the javascript and verified that wasn't my problem, the functions to check the box when you click the label were still working. With some help from a co-worker we found that the plugin was creating a hidden div on the page and when I made the Ajax call that div was getting created a second, third fourth... time on the page. So a simple remove before making the Ajax call solved my problem and got the labels working again.