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.

Tuesday, September 8, 2009

Mail.app is eating Bamboo

We upgraded Bamboo recently. The latest version sends out much smarter email summaries of build failures. Unfortunately, Mail.app eats the HTML so I get an email that has a subject and zero visible content...unless I go to View -> Message -> Best Alternative.

I have to hit a few button to tell Mail.app "You're HTML display is busted. Try something else"?! No other email client I've ever used has ever had trouble dealing with HTML, even horribly malformed HTML. Mail.app mostly seems to be able to handle HTML, but these corner cases are really annoying, especially when you have to deal with them on every message. I can't even set this property on a folder or a smart folder. That's really bad design.

Here's how you get Mail.app to fix itself--also terrible design. Open up terminal and type:

defaults write com.apple.mail PreferPlainText -bool FALSE

Yikes.

Tip 'o the hat to this post.

Tuesday, September 1, 2009

Kettlebells are kicking my butt

Baby number two is due in about 6 months. When we were at T-minus 6 months for our first child, I was in great shape. I swam about 50 laps of crawl 5 days a week at the most amazing pool at MIT's Z center. Best shape of my life.

Then our daughter arrived, I never slept, and I ate junk food to keep myself sane for the better part of the first two years of her life. After the first year, I got mono, which knocked me on my ass for about 6 straight months. I packed on some pounds and am now generally a pretty huge weakling. I strain muscles really easily now that I have so little muscle mass. The latest episode involved straining my wrist while unloading a lawn mower to hack my out-of-control-overgrown lawn. The lawn had gotten so overgrown that our little manual push mower wasn't so much cutting grass as combing it, so I had to borrow a friend's power mower. The previous strain involved carrying some luggage into the house after vacation.

These little indignities are getting to be more than just embarrassing. What to do?

I called my SEAL buddy to ask him for his advice on how to get back some functional strength in some simple workouts. His advice:

1. Install pullup bar in a well traveled area of the house. Do pullups (or in my case, attempt pullup) whenever you pass by.

A few notes on this: you can't just put the pullup bar in the basement. It has to be front and center, in a part of the house you visit often during the regular course of the day. If installing the pullup bar doesn't elicit gasps of horror from your spouse because of how the pullup bar's presence ruins the aesthetic of the room, you haven't put the bar in the right place. You want the pullup bar in the most obtrusive spot possible. In my case, it's in the pantry door frame. The lure of the pantry is irresistible: it contains cookies, chocolate, and the coffee grinder. I'm in there at dozen times a day, which means I'm trying pullups a dozen times a day.

I was amazed at how many people report nearly killing themselves doing pullups on improperly installed pullup bars. It's pretty simple: screw it into solid, load bearing wood framing, like a door frame.

2. Get a book by Pavel Tsatsouline and start doing kettlebell workouts with a 25 pound kettlebell.

A few notes on the kettlebell: No way in hell could I handle a 25 pound kettlebell. If I dropped it, I'd either crush my toes, the cat, shatter the floor, or sustain numerous strains at the very least. I picked up a lady's 10 pound bell to start with, just to make sure I could get the technique right before moving up to real man weight. Kettlebell workouts--even with light weights--are killer. Just you try 5 or 10 Turkish getups. You will be huffing and puffing in no time, and as Pavel says for many of his workouts, "Bring a puke bag."

The results, after just 10 days or so, are striking. I find myself with more energy. My arms are well toned--heck, I even have deltoids. Me--deltoids! When I used to lift weights at the gym years ago, I ended up with weird arms--big biceps, smaller triceps, and no shoulders. It's hard to do well-balanced weight lifting workouts what with all the goofy Nautilus equipment, but with a few simple kettlebell moves, you'll be amazed how your body changes.

I've also been amazed at how kettlebells develop real functional strength. Traditional weight lifting isolates your muscles and gives you the ability to lift weights in a particular way. For example, curling 50 pound dumbells makes you really good at...curling 50 pound dumbells. But day-to-day life doesn't present you with the opportunity to bench press something in order to accomplish anything of practical value.

Carrying a squirming two year old up steep stairs with one hand while dragging a 50 pound bag of concrete requires full body functional strength, not just huge biceps. The balance involved in these sorts of tasks is important, as is your body's ability to shift loads around. I find kettlebells are very good at building what I'll call "practical" strength. Ditto for the pullup bar.