Showing posts with label java. Show all posts
Showing posts with label java. Show all posts

Wednesday, September 26, 2007

Logging request and response headers in Tomcat

What's the best way to dump out request or response headers in Tomcat?

Before rolling up your own solution, take a look at the valve component that Tomcat supports. In particular, the aptly named RequestDumperValve will log all the request and response headers in Tomcat. To enable the valve, just go to your server.xml file in the /conf directory and uncomment this line:

<Valve className="org.apache.catalina.valves.RequestDumperValve"/>

Then restart your server and the headers will appear in your log file.

Monday, September 17, 2007

spring initbinder example that registers custom editor

One of the nice features in Spring is the automatic databinding that occurs if you use one of the subclasses of BaseCommandController such as AbstractCommandController or SimpleFormController. By automatic databinding, I mean Spring initializing your command object based on the request parameters. The magic behind this feature is Spring's builtin property editors which do things like convert strings to integers. Sooner or later, however, you'll run into a situation where you need to do some custom databinding by registering your own PropertyEditor through the initBinder() method.

Suppose this is my command class:


class FootballPlayer {

static enum POSITION {RB, WR, QB, DB, LB}



POSITION _position;



public POSITION getPosition() {

return _position;

}



public void setPosition(POSITION position) {

_position = position;

}

}




So if my request parameter is ?positon=rb and I want my command class to have the correct enum set, do the following:
First, create a custom property editor.

class FootBallPlayerEditor extends PropertyEditorSupport {

public String getAsText() {

FootballPlayer editor = (FootballPlayer) getValue();

return editor.getPosition().name();

}



public void setAsText(final String text) {

setValue(FootballPlayer.POSITION.valueOf(text));

}

}



then override initBinder

protected void initBinder(HttpServletRequest request,

ServletRequestDataBinder binder) {

binder.registerCustomEditor(FootballPlayer.POSITION.class, new FootBallPlayerEditor());

}



And you're all set.

Friday, September 14, 2007

Composite Comparator - Fun with generics and varargs

A couple of new features in Java 5 are the additions of generics and varargs. We use generics a lot when returning a list from our DAOs but I've never had to implement a method that accepted varargs until I implemented this parent reviews page.

This is a typical page where a user may sort by date or by rating. Another feature is that a principal's review for a school always comes first. So the sorting is like so:

  1. By Principal, then date descending
  2. By Principal, then date ascending
  3. By Principal, then rating, then descending

First thing I needed to do was create a couple of comparators. I used the static final comparator approach that that Josh Block talks about in Effective Java. I'll demonstrate with a baseball class. The nice thing about the composite comparator is that now I can create a comparator based on hr,rbi, and anything else I wanted to add later like sb, runs, etc.

Example:
public class BaseBallPlayer {

   private int _rbi;

   private int _hr;



   public BaseBallPlayer(int rbi, int hr) {

       _rbi = rbi;

       _hr = hr;

   }



   public static final Comparator HR_COMPARATOR = new Comparator<BaseBallPlayer>() {

       public int compare(BaseBallPlayer o1, BaseBallPlayer o2) {

           return o1.getRbi() - o2.getRbi();

       }

   };



   public static final Comparator RBI_COMPARATOR = new Comparator<BaseBallPlayer>() {

       public int compare(BaseBallPlayer o1, BaseBallPlayer o2) {

           return o1.getHr() - o2.getHr();

       }

   };



   public int getHr() {

       return _hr;

   }



   public int getRbi() {

       return _rbi;

   }

}

public class GenericComparator {

   public static <T>Comparator<T> createComparator(final Comparator<T>... c) {

       return new Comparator<T>() {

           public int compare(T r1, T r2) {

               int result = 0;

               for (Comparator<T> comp : c) {

                   result = comp.compare(r1, r2);

                   if (result != 0) {

                       break;

                   }

               }

               return result;

           }

       };

   }

}

   Comparator<BaseBallPlayer> HR_RBI_COMPARATOR = GenericComparator.<BaseBallPlayer>createComparator(

                   BaseBallPlayer.HR_COMPARATOR, BaseBallPlayer.RBI_COMPARATOR);

Wednesday, July 12, 2006

ResourceBundle bungle

Updated 7/13: used google pages as my online wysiwyg to generate valid html for xml files

We use SpringMVC and use the built-in validator support. I had a problem parsing in a parameter for an error message.

my applicationcontext contained:

<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource"> <property name="basename"> <value>app</value> </property> </bean>

the line in my resource bundle,app.property, was:
error_key=What's up, {0}?
the validator call was:
errors.reject(errorcode, new Object[] {"doc"}, defaultMessage);

My jspx file looked like this:

      <spring:hasbinderrors name="mycommand">
          <div class="error">
              <c:foreach var="error" items="${errors.allErrors}">
                  <li><spring:message arguments="${error.arguments}" code="${error.code}"></spring:message></li>
              </c:foreach>
          </div></spring:hasbinderrors>

I expected this to show up in my final output: What's up, doc? Instead, the parameter was never parsed in. It only displayed: What's up, {0}?

Like always, the answer was found in the javadocs. The parameter binding is backed by java.text.MessageFormat and what happens is that a single quote, ' , stops any binding. So to solve the problem, use two quotes '' to represent a single quote.

Thursday, July 06, 2006

fmt:formatNumber rounding behavior

I was helping a coworker with a rounding "bug" earlier today. On one of our jspx pages, we need to round some numbers up. But she ran into a strange problem because 200.5 rounded to 200 but 21.5 rounded to 22. She thought the problem was hibernate related but a couple of quick unit tests revealed the real culprit: jstl's fmt:formatNumber tag. It's actually not a bug at all because according to the javadocs, it relies on the following for rounding:

ROUND_HALF_EVEN

public static final int ROUND_HALF_EVEN
Rounding mode to round towards the "nearest neighbor" unless both neighbors are equidistant, in which case, round towards the even neighbor. Behaves as for ROUND_HALF_UP if the digit to the left of the discarded fraction is odd; behaves as for ROUND_HALF_DOWN if it's even. Note that this is the rounding mode that minimizes cumulative error when applied repeatedly over a sequence of calculations.

Unfortunately, there's no way to change the behavior to ROUND_HALF_UP which is what we wanted. I'll send a note to the jstl mailing list to see if anyone else would like this feature and if so submit a patch.

*Update Before I sent that email to the mailing list, I did more digging and discovered that fmt:formatNumber is backed by DecimalFormat. As of Java 5, DecimalFormat does not support specifying a rounding mode other than the default ROUND_HALF_EVEN. The good news is that setRoundingMode was introduced in Java 6 to solve this exact problem. The bad news is that it'll be a while before java 6 is out of beta and this change gets propogated down to fmt:formatNumber. So in the meantime, the best thing to do is write your own tag is you require a rounding mode other than ROUND_HALF_EVEN.

Wednesday, March 01, 2006

Idea 5.2 and subversion installed

I've finally gotten around to starting my XmlEditor project. I plan to create a swing app that validates an xml file against an xsd. I also plan to allow the app to allow editing of the file to fix errors. This project will introduce me to swing and also to the java nio classes. I'm not sure if it's necessary to use nio but it's something I've been meaning to learn/use for a loooong time so we'll see how it goes.

Before I start my project, I want to make sure I have a revision control system (as encouraged in the pragmatic programming series) on my machine so I downloaded and installed subversion. The new version of Idea has subversion support built in so I upgraded from 4.5 to 5.1. It was a breeze to import settings and existing projects. I chose subversion because I already know cvs and wanted to try something new. I've heard the branching system makes a lot more sense and is a lot faster but I doubt I'll need branches for this small project. It took me around 20 days to finally start this project so let's see when it's finally finished :)

Wednesday, December 28, 2005

Spring MVC RedirectView appends jsessionid

Back when I worked at Sun we used to have a shutdown period the last two weeks of the year. I'm not sure if they still have that policy but I wonder why all companies don't operate like that. This time of year most people are either on vacation or are in vacation mode while at work. In fact, most large projects are not considered or launched until the new year anyway.

I work at a pretty small shop and it's like that for us too. I had a day free before going on vacation so I volunteered to fix a couple of minor bugs. One of them dealt with removing a ;jsessionid=????? that was being appended to one of our links. If you're not familiar with what that is, it's basically tomcat's way of tracking sessions when a user does not have cookies enabled. Instead of storing it in a cookie, that string is passed around in the URL. But in order to see the jessionid string in the first place, it needs to be enabled somewhere in your code.

One method is using c:url tags in your jsp pages. Another is by using HttpServletResponse's encodeURL or encodeRedirectURL methods in your controller code. Usually it's a good idea to include these calls but in our webapp we do not store session data and that string was just adding extra noise since the page where it appeared is used as a launchpad to forward to a perl page.

My first intuition was to look for the c:out tag but no luck there so I searched for the encodeURL methods. Ack..no luck there either. Where could this be coming from? I then saw a call to spring mvc's RedirctView class so I figured it might be in there. The docs made no mention of jsessionid's so I looked at the source code. A ha...RedirectView actually calls encodeURL before the redirect so that was the culprit. Another one of the many benefits of open source...full source code view.

I described the problem to Andy and he showed me how to easily view a library's source code in IDEA. If you go to your preferences and then look at the libraries in your project, you can add an entry point to the src code on your local machine. The same goes for api's too. The best thing about it is that you can keep it in the zip file and IDEA will still find it.