Thursday, June 22, 2006

url-pattern matching

I'm writing an intercepting filter to use in a web application, and I wanted to do some pattern matching in the same vein as the Servlet spec specifies. Basically, this spec says that you can use the '*' as a wildcard character. For example, /context/*.do would match /context/servlet.do and /context/different.do and as I interpret it, /context/path/to/another/servlet.do

I set out to write a pattern matching algorithm to handle this, and this is what I came up with:


private boolean urlMatches(String uri, String urlPattern){
boolean hasWildCard = urlPattern.indexOf("*") > -1;
boolean firstPositionWildCard = urlPattern.indexOf("*") == 0;

// test to see if its the same
if(uri.equals(urlPattern)){
return true;
}else{
//patterns without wildcards must match exactly
if(!hasWildCard){
return false;
}
}
// If the pattern is an empty string,
// interpret it as "nothing", not "everything"
if(urlPattern.trim().length() == 0){
return false;
}
String[] parts = urlPattern.split("\\*");
for(int i = 0; i < parts.length; i++){
String part = parts[i].trim();
int index = uri.indexOf(part);
if(index < 0){
return false;
}else{
// The first time through, the index must be 0
// when there's not a wildcard char in the first position
if(i == 0 && index > 0 && !firstPositionWildCard){
return false;
}
uri = uri.substring(uri.indexOf(part)+part.length());
}
}
return true;
}


I haven't tested it for more than an afternoon, but I think it's pretty solid. This is of course written in Java, but the logic should be similar for just about any other language.

Sunday, May 21, 2006

10lb Paradigm Shift

At long last, my baby boy is born!

On May 14th at about 3 am Gideon Emerson entered our lives. This was both a full moon and mother's day. I had a feeling that he'd be born then. Weighing in at 9lb. 15oz. and 21 in. he's got a healthy start in this world. Now the fun begins as we help him grow into the person he is to become.

It's now been a week since Gideon came into the world, and as people say, life has changed. The top 3 that come to mind:

  1. I don't mind doing the dishes or laundry anymore. Shana actually has started to call me "Bubbles" because I'm wandering around the house with sudsy hands so often.
  2. I am tremendously focussed on accomplishing goals and less succeptible to the noise of life's distractions. What's important has become plainly clear. What's not important has become even more clear.
  3. I now know the meaning of life. Which is simply, to outwardly love others so much that you forget your own desires. Producing a child is a sure-fire way to do it.
The most dramatic change was on my life's perspective, and it happened at my very roots. I have completely shifted the paradigm from which I make decisions. Yes, this is quite a broad statement, a little bit cliche and very generalized, but it's true. Put simply, a week ago, I spent lots of my time thinking about what I could do for me and my own self interests. Now, my focus is on my family's interests. I still have my own personal interests, but they're now measured differently. Everything is measured with a different metric. It's relieving, strange, uncomfortable and lifting. The change I've heard so much about in the past 9 months is not so much the change in sleeping patterns, or the surprising amount of effort that it takes to feed everyone (all 3 of us are learning how to eat), nor is it how the money gets spent. The change is how I make decisions, not the decisions themselves. The paradigm shift is totally exciting.

When someone this cute arrives, how could the new metrics not be exciting?


Sunday, April 16, 2006

Data in the 3rd dimension

If there's an activity in computer programming that separates the men from the boys, it's recursion and hierarchies. Recursion is such a simple and elegant thing, but so mind-bending that it takes a while to feel comfortable with it. Functional recursion, a method which calls itself, is something that I find easy to understand. If a method is a request for an action, that action makes a request for itself. It's not so hard to follow. Recursion is a natural thing when you're talking about methods in a class.

However, recursion gets goofy is when you force it to go where it doesn't belong. That's right, I'm talking about relational databases. A table of data is inherently not a good structure for storing hierarchical data. Sure, it's easy enough to make a table join to itself. But, in order to pull out the data, you've got to know ahead of time how many joins to use. And with each subsequent join, performance degrades. That, and making the queries to get information about a tree of data can get nasty. Until now, I thought that this was the only means of organizing hierarchical data in a relational database. Fortunately, I was wrong.

Tonight I set out to figure out how else I might be able to represent a hierarchical data set in a relational database. To my delight, I found an answer that I like. Nested sets can be used to store hierarchical data. Although, it's slightly confusing, especially when you talk about adding and deleting new nodes, and double especially confusing when you start thinking about sorting those nodes. I've got an idea for a project where this kind of stuff is going to be essential. I'm excited to find that someone has done the research to figure out the right way to do this stuff.

Tuesday, April 04, 2006

Crib with a built in legacy


I have the good fortune of being the son of a talented and very generous carpenter. My Dad built a gorgeous crib for my soon-to-be-son. Shana and I are so excited about it!



As my father tells me, it's constructed out of wood from trees that his father cut down. After it was cut down, my grandfather had it rough sawn and stored it in the rafters of the barn. My dad actually remembers playing on top of the stack of timber when he was a child. I'm happy to say that at least one more Rank child will have the opportunity to play amidst the same wood.








Sunday, April 02, 2006

What do I know?

That's a rhetorical question, of course.

I had a thought this past week that I wanted to share with you all. To me it's quite a powerful thing to keep in mind when I'm communicating with others. It's simply this

It is better to have an informed opinion than to have the answer.

An informed opinion allows you to improve upon it. As an opinion becomes more informed, the sharper its focus becomes. Having the answer can leave you blind sided by something you didn't see. This has happened to me time and again. I'm just now seeing it from this perspective.

I'm finding that if I want to make my conversations with others productive, it's better to have beliefs, founded in good evidence and experience, than it is to have cast an answer in concrete. Such answers can bring you to your knees when you find out that the evidence out there doesn't support your beliefs. However, if you take the position that you're only doing your best to inform your beliefs, so that you can make the right decisions, life is better. People will actually want to talk to you because you are open to communicating ideas back and forth.

It may be simple, but it's helpful to me to know this:

I only know what I believe, and I only believe what I have good reason to believe. And from my experience, I've good reason to believe that I can be certain about nothing. Take that paradox and munch on it for a while.

Wednesday, March 08, 2006

You ain't seen nothin' yet

Here's the little one in utero. This photo was taken about 2 weeks ago. Now, we've got about 8 weeks to go. We've just boxed up a bunch of books to make room for a crib. We're taking Bradley classes in our attempt to have a natural child birth. We practice relaxation techniques regularly. We even do exercises together. And yes, we've been reading lots and lots and lots.

 Posted by Picasa

Sunday, January 15, 2006

What is the time when the clock reads 0000-00-00 00:00:00?

Understanding Zero time sounds like something you might find in a zen koan. Apparently, JDBC doesn't get it. For the past couple of days, I didn't either. But now, I've reached Hibernate nirvana; at least for a moment.

I've been working on getting a very basic resultset back when using Hibernate. The table I'm using has a couple of datetime fields, and by default, they are filled with zero time, such as 0000-00-00 00:00:00 in the format YY-MM-DD HH:mm:SS. I had lots of trouble pulling out the results, as a result. I'd get the following error:

Value '0000-00-00' can not be represented as java.sql.Timestamp

This only happens when I have existing data in my database with a "null" date. When the dates are good, the error doesn't appear.

Assuming that I don't have control over the entry of a null date in the database, I tried resolving the issue in a couple of ways. First I tried to resolve it by adjusting the hibernate mapping. I changed the "type" attribute of the property to be a timestamp, but that didn't work.

After some more research, I realized that a custom UserType might be the answer. I came to that decision after reading this post about the using dates in hibernate. I also read a bit about more date and time issues in the hibernate forums. After going through these discussions, and coming to the understanding that my problems related to the odd date in my database, Things pointed to the custom UserType. I didn't know much about them, but I do know that there's a method specified in the interface named nullSafeGet and that sounds a LOT like what I needed. My strategy was to implement the UserType interface and create a custom class to use as a type in my mapping. Then, when a "0000-00-00 00:00:00" value is retrieved from a DATETIME typed column in the database, I'd simply return null instead of the beginning-of-time value.

I tried this out a moment ago, using a UserType class for Timestamp-like fields, which I found again, on the Hibernate forums. However, by the time the code execution could reach the nullSafeGet method of the class I was using, the error had already been thrown. So, apparently the answer to resolving zero dates does NOT lie in creating a custom UserType for Hibernate. So what's the answer?

The answer is so simple, that I nearly tipped over in my chair when I read it. Interestingly enough, I found the beginning of the trail to the answer in a RadRails forums post. This post points out that all I need to do is add an argument to the JDBC URL. All of the arguments for the JDBC URL for MySQL using the Connector/J driver are here. Specifically, the following argument handles the odd dates

zeroDateTimeBehavior=converToNull

So, a full JDBC URL for connecting to a database that might have zero dates would look like this:

jdbc:mysql://myhost/mydatabase?zeroDateTimeBehavior=convertToNull

There you have it. The solution turned out not to be Hibernate related at all, but rather, JDBC related.

Sunday, January 01, 2006

I WAS missing something!

I'm glad, and a bit embarrassed that I was so hasty to point a finger at the Struts folks. It turns out that they have a simple solution for resubmitting a form post. And it's exactly what I was hoping for; redirection.

In the action-mapping, and action only needs a forward with a redirect="true" attribute. Such as:


<action name="login" ...>
<forward name="loginSuccess" redirect="true" path="/path/showsomething.do"/>
</action>


My faith is restored in this framework, and I promise to do my homework a bit more before I decide to point fingers and spew forth my expert opinions :-)

Struts re-submits form posts? Am I missing something?

I just finished my first bona fide Struts application, and I'm a bit perplexed. I find an inherent problem with the design, and I'm trying to figure out if I missed something.

The problem is that the framework doesn't protect against form re-submission. The Struts framework seems to use a forward instead of a redirect after a form is successfully submitted and validated. If you do this and hit the refresh button on your browser, you'll see the problem. The form re-submits. This is a basic web development problem, and the ramifications are severe. If a form is resubmitted, a user can add as many records to a database as they hit the refresh button, make numerous purchases of the identical set of products, add the exact product to a shopping cart numerous times, etc. I'm surprised that this problem exists in such a widely used framework!

This problem is an obvious one, and I'm SURE that someone else has figured out an elegant solution to it. So I'm not about to give up on the framework altogether. However, I'm beginning to be skeptical of it. And I'm not the only one.

In my opinion, the solution involves a different workflow. Struts uses a Post -> Forward workflow. For successful form submissions, a Post -> Redirect -> Get (PRG) workflow is much better. Struts does provide support for tokens to see if a form is submitted more than once, but in my opinion, tokens aren't the way to solve the problem. Not only does it leave the server open to tampering, it also poses usability problems for the user.

Now, I don't claim to be any sort of expert in Struts matters. I just know that forwarding and allowing a form to be resubmitted is dead wrong, even if tokens can help check to see of a form is being resubmitted. In my simple understanding of Struts and ActionForwards, I do have an idea for a solution. Seeing an ActionMapping in the struts-config.xml, where there's a form, there's a <forward>. When the form is successfully validated without any errors, the ActionServlet should send the HttpResponse.redirect() instead of the HttpResponse.forward(), which I am assuming is what happens.

So, first, I think I'll look a little deeper into what other people have done to solve this problem,. If I can't find anything that seems to work, I'm going to subclass the ActionServlet as PRGActionServlet, and make it redirect to an ActionForward instead of forward. And MAYBE I'll add support for a different XML element called <redirect>. I don't know, but I'll report back with what I decide to do.