Wednesday, September 30, 2009

Uh oh: Tomcat POST too large

After getting a bug report with the attached stack trace, I noticed an obscene amount of network traffic going in and out of my sandbox tomcat. That was my first clue that something had gone horribly wrong. The stack trace from production wasn't helpful at all:

java.lang.NullPointerException
org.apache.catalina.connector.Request.parseParameters(Request.java:2340)
org.apache.catalina.connector.Request.getParameterNames(Request.java:1038)
org.apache.catalina.connector.RequestFacade.getParameterNames(RequestFacade.java:359)
org.apache.tapestry.web.ServletWebRequest.getParameterNames(ServletWebRequest.java:59)
$WebRequest_123a5d0549e.getParameterNames($WebRequest_123a5d0549e.java)
$WebRequest_123a5d05457.getParameterNames($WebRequest_123a5d05457.java)
org.apache.tapestry.services.impl.RequestCycleFactoryImpl.extractParameters(RequestCycleFactoryImpl.java:110)
org.apache.tapestry.services.impl.RequestCycleFactoryImpl.newRequestCycle(RequestCycleFactoryImpl.java:79)
$RequestCycleFactory_123a5d05439.newRequestCycle($RequestCycleFactory_123a5d05439.java)
org.apache.tapestry.engine.AbstractEngine.service(AbstractEngine.java:224)
org.apache.tapestry.services.impl.InvokeEngineTerminator.service(InvokeEngineTerminator.java:60)
$WebRequestServicer_123a5d0548d.service($WebRequestServicer_123a5d0548d.java)
$WebRequestServicer_123a5d05489.service($WebRequestServicer_123a5d05489.java)
org.apache.tapestry.services.impl.WebRequestServicerPipelineBridge.service(WebRequestServicerPipelineBridge.java:56)
$ServletRequestServicer_123a5d0546f.service($ServletRequestServicer_123a5d0546f.java)
org.apache.tapestry.request.DecodedRequestInjector.service(DecodedRequestInjector.java:55)
$ServletRequestServicerFilter_123a5d0546b.service($ServletRequestServicerFilter_123a5d0546b.java)
$ServletRequestServicer_123a5d05471.service($ServletRequestServicer_123a5d05471.java)
org.apache.tapestry.multipart.MultipartDecoderFilter.service(MultipartDecoderFilter.java:52)
$ServletRequestServicerFilter_123a5d05469.service($ServletRequestServicerFilter_123a5d05469.java)
$ServletRequestServicer_123a5d05471.service($ServletRequestServicer_123a5d05471.java)
org.apache.tapestry.services.impl.SetupRequestEncoding.service(SetupRequestEncoding.java:53)
$ServletRequestServicerFilter_123a5d0546d.service($ServletRequestServicerFilter_123a5d0546d.java)
$ServletRequestServicer_123a5d05471.service($ServletRequestServicer_123a5d05471.java)
$ServletRequestServicer_123a5d05463.service($ServletRequestServicer_123a5d05463.java)
org.apache.tapestry.ApplicationServlet.doService(ApplicationServlet.java:123)
org.apache.tapestry.ApplicationServlet.doPost(ApplicationServlet.java:168)
javax.servlet.http.HttpServlet.service(HttpServlet.java:709)
javax.servlet.http.HttpServlet.service(HttpServlet.java:802)
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:112)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)


But the stack trace from the first time through the bug in my sandbox was revealing:

java.lang.IllegalStateException: Post too large
org.apache.catalina.connector.Request.parseParameters(Request.java:2388)
org.apache.catalina.connector.Request.getParameterNames(Request.java:1047)
org.apache.catalina.connector.RequestFacade.getParameterNames(RequestFacade.java:369)
org.apache.tapestry.web.ServletWebRequest.getParameterNames(ServletWebRequest.java:59)
$WebRequest_124021108bc.getParameterNames($WebRequest_124021108bc.java)
$WebRequest_12402110874.getParameterNames($WebRequest_12402110874.java)
org.apache.tapestry.services.impl.RequestCycleFactoryImpl.extractParameters(RequestCycleFactoryImpl.java:110)
org.apache.tapestry.services.impl.RequestCycleFactoryImpl.newRequestCycle(RequestCycleFactoryImpl.java:79)
$RequestCycleFactory_12402110856.newRequestCycle($RequestCycleFactory_12402110856.java)
org.apache.tapestry.engine.AbstractEngine.service(AbstractEngine.java:224)
org.apache.tapestry.services.impl.InvokeEngineTerminator.service(InvokeEngineTerminator.java:60)
$WebRequestServicer_124021108aa.service($WebRequestServicer_124021108aa.java)
org.apache.tapestry.services.impl.DisableCachingFilter.service(DisableCachingFilter.java:48)
$WebRequestServicerFilter_124021108ac.service($WebRequestServicerFilter_124021108ac.java)
$WebRequestServicer_124021108ae.service($WebRequestServicer_124021108ae.java)
$WebRequestServicer_124021108a6.service($WebRequestServicer_124021108a6.java)
org.apache.tapestry.services.impl.WebRequestServicerPipelineBridge.service(WebRequestServicerPipelineBridge.java:56)
$ServletRequestServicer_1240211088c.service($ServletRequestServicer_1240211088c.java)
org.apache.tapestry.request.DecodedRequestInjector.service(DecodedRequestInjector.java:55)
$ServletRequestServicerFilter_12402110888.service($ServletRequestServicerFilter_12402110888.java)
$ServletRequestServicer_1240211088e.service($ServletRequestServicer_1240211088e.java)
org.apache.tapestry.multipart.MultipartDecoderFilter.service(MultipartDecoderFilter.java:52)
$ServletRequestServicerFilter_12402110886.service($ServletRequestServicerFilter_12402110886.java)
$ServletRequestServicer_1240211088e.service($ServletRequestServicer_1240211088e.java)
org.apache.tapestry.services.impl.SetupRequestEncoding.service(SetupRequestEncoding.java:53)
$ServletRequestServicerFilter_1240211088a.service($ServletRequestServicerFilter_1240211088a.java)
$ServletRequestServicer_1240211088e.service($ServletRequestServicer_1240211088e.java)
$ServletRequestServicer_12402110880.service($ServletRequestServicer_12402110880.java)
org.apache.tapestry.ApplicationServlet.doService(ApplicationServlet.java:123)
org.apache.tapestry.ApplicationServlet.doPost(ApplicationServlet.java:168)
javax.servlet.http.HttpServlet.service(HttpServlet.java:647)
javax.servlet.http.HttpServlet.service(HttpServlet.java:729)
org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter.doFilterInternal(OpenEntityManagerInViewFilter.java:112)
org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:76)


Subsequent runs through the app in my sandbox showed the production stack trace, which totally obscured the error. The lesson here: when you're trying to reproduce a bug, do it in the cleanest environment possible.

The real underlying problem was an extremely large chunk of data that was being persisted by Tapestry 4.0. The page code had pulled out an enormous list of Entities and crammed them into the POST. It should have just passed around some database keys or smaller objects more tailored to the UI.

The fast-and-cheap, sloppy, short-term workaround was to tell Tomcat to bump up its max post size. To do this, edit your tomcat's server.xml and set the post size to something larger, like 4Mb or 8Mb by adding this attribute: maxPostSize="8000000".

Saturday, September 26, 2009

Be a real man, dad. Sing.

When my daughter was 18 months old, we took a swim class. There was a pretty even mix of fathers and mothers, boys and girls. Everybody sang the silly songs you sing in toddler swim class. It was great fun.

At 24 months, we joined the slightly older swim class. Same mix of dads and moms, maybe slightly more dads. Maybe slightly more boys than girls.

Nobody sings. It's me and two mothers that seem to carry the group of 15-odd toddlers and their parents. What happened?

Does something happen to fathers of boys between 18 and 24 months that causes them to hesitate to do anything that might smack ever so slightly of being girly? I wedged myself between two non-singing dads and their 24 month old sons and proceeded to sing along with the instructor, hoping I might be able to pressure them into actually enjoying themselves. All I got were dirty looks. I imagined these dads were thinking to themselves, "Watch out for that dad, Johnny, he sings silly songs with his kids--he might be a homo." I'm fairly certain that just be singing along I have lost any hope of befriending these ManDads.

It takes a real man to sing "Wheels on the Bus" and "Pop Goes the Weasel" in his swim trunks while surrounded by slightly more muscular men. (That said, I am very proud of the fact that I can now do all of 3 pull-ups and 3 chin-ups). I resisted singing with my daughter until I realized just how powerful a drug it is for her. Although my instinct tells me that the best hope for solving problems involving screaming infants and toddlers at 2:00 AM is to slam my face through a plaster wall, a far better thing to do is sing some silly song. Once I embraced this fact, life got a lot better.

My guess is that if my first kid were a boy, I'd fit in just great with the ManDads. I'd refuse sing-a-longs. I wouldn't hug my kids very much or say things like "I love you" to my children as often as I do. Maybe I would have caved and smashed my fists through the wall with some frequency in response to middle-of-the-night scream fests. But having a girl first has definitely softened me up, and it'll be interesting to see how ManDads react to me when I sing silly songs with my yet-to-be-born 2 year old son. I'm guessing they'll just figure I'm a pussy.

Friday, September 25, 2009

Quick visual diff on a Mac? FileMerge.

Thank you, stackoverflow.com. I have enjoyed reading Jeff Atwood's posts about stackoverflow, but I've always been a bit dubious. I googled "mac diff" just now and a link to stackoverflow came up as the top hit, directing me to use FileMerge. Perfect.

I needed to do a diff on some dog assembly AGP files to make sure I hadn't totally mangled the dog genome. FileMerge was perfect for the job!

Wednesday, September 23, 2009

Disabling screen saver password protection in Windows XP


I use a Mac. I run Parallels to run Windows. My Mac turns on its password-protected screensaver after about 30 minutes. My virtual PC turns its on after about 15 minutes. So I ended up having to enter my password fairly often. This was a real nuisance. I thought I couldn't change this because my IT group had locked the option out of the display properties, which seems odd because I have administrative rights on the VM.

But then I discovered that I could solve the problem by tweaking the registry:

HK_CURRENT_USER -> Software -> Policies -> Microsoft -> Windows -> Control Panel -> Desktop

Set ScreenSaverIsSecure = 0.

Sunday, September 20, 2009

Great pegboard hooks

For about a year, we've been using pegboard to hold our pots and pans a la Julia Child. We haven't been using very stable hooks. Sometimes you go to grab a pan and the hook ends up on the floor. I installed the pegboard when I was sleep deprived from having a baby and in the doldrums of a 6 month case of mono. In other words, I wasn't very with it, so the hooks I got for the pegboard didn't work out so well.

Then I got some of these amazing pegboard hooks at Amazon. Problem solved. You screw them in a bit and they're rock solid. You can unscrew them very easily if you need to.

Amazing Mexican in Arlington

Zocalo, in Arlington on Broadway just east of the center, is amazingly yummy. We went there for lunch. Best fajitas and enchiladas I've ever had. Not overly cheesy, greasy stuff. Good, fresh ingredients, well balanced.

On the other hand, Ixtapa, just over the Lexington border, is a much better place to plow through a few drinks in the company of your (young) children. Great spicy cheese dip most of the time, but not entirely consistent.

Ixtapa is almost as good as Los Loros in Atlanta. Cheap, cheesy Mexican. Entirely different category from Zocalo.

Friday, September 18, 2009

Debugging Unit Tests in Maven2 (mvn)

Recently I got fouled up by this issue in Intellij's IDEA. Basically IDEA loads up the Spring context one way, maven another. IDEA's trying to be helpful by doing this, but it's causing me headache. Instead of running and debugging my unit tests in IDEA, I had to resort to launching mvn on the command line and attaching a remote debugger to it via IDEA. How do you do this? Comme ca:

mvn -Dmaven.surefire.debug="-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=62905 -Xnoagent -Djava.compiler=NONE" -Dtest=YourTestClass test


Then create a remote debugging session in IDEA for port 62905.

It's pretty tedious because you have to fire up mvn, then wait for it to wait, and then start the debugging session from IDEA.

While you're at it, you might want to set -Dhibernate.show_sql=true and change your log4j.properties to include log4j.logger.org.hibernate.SQL=DEBUG, SQL_APPENDER to see what Hibernate is sending to the database.