Sweet Looking Headings with CSS

As I’ve been playing more with Safari lately, I’ve found that many good looking web sites add a bit of something extra for Safari. They use CSS to add a drop shadow to certain elements of the page. Take a look at this example from LightHouse (Firefox 2.0 on the left, Safari 3 on the right):

Firefox vs. Safari rendering of the CSS 'text-shadow'

From Word Up! Creating Dynamic Visual Presentations:

A drop shadow on your text helps set apart your words from their background thus making them easier on the eyes.

And you can see that in the example above. Adding the slight, but dark drop shadow to the white text on the blue color makes it more readable. It’s a nice touch that makes the UI feel like it has an extra set of polish. The CSS is simple enough:

text-shadow: 2px 2px #055B98;

While most mortals won’t get to enjoy the effect, you don’t develop just for mere mortals, do you? Kick your game up a notch.

HOWTO Restore Your SVN Trunk to a Previous Version

Sometimes you just need to admit that you’ve loused things up and you want to go back to the way you had them last Thursday. It takes courage to throw in the towel, but it also takes a reasonable understanding of how to do it quickly with your tool. Here’s the simple procedure I follow when I want my trunk restored to a previous version.

First, I have my repository laid out like this:

/myproject
   /tags
      /archive
   /branch
   /trunk

-1. Know which revision of trunk you want to restore. If you don’t, then this is all a worthless waste of time.

0. Also, make sure to talk to your team. You don’t want anyone trying to commit or update from trunk between steps 1 and 3. Also, they may have objections to your choice in step -1.

1. Backup you work in the /tags/archive area. I use this area for snapshots of my project that I want to name, and don’t want to see very often (I want to see project releases occasionally, so they just go in /tags). Make sure you choose a good name (good-name in the url below) for your archive tag.

svn cp http://url/for/my/trunk http://url/for/my/tags/archive/good-name -m "Save my messed up work."

2. Delete your trunk. Now we could have simply used mv instead of cp in our last command, but we’re paranoid and want to make sure that everything worked first.

svn rm http://url/for/my/trunk -m "Start over on trunk."

3. Restore the version of trunk that you want to use. In this example, we’re using revision 437 as the source of our new trunk.

svn cp -r 437 http://url/for/my/trunk http://url/for/my/trunk -m "Restore trunk to previous version."

There you have it, kids. Happy restoration.

DB connection problems? Try a logging datasource!

We’ve been grappling with a number of different problems with our app over the last week. We’ve made many improvements, including several changes to our Spring configs (which I may touch on another day), but we still had a problem where occasionally we ran out of database connections momentarily — no matter how many we had in the pool to start with.

So the other morning I got an itch to start coding while I was waiting for my carpool ride to show up. By the time I got to work, I had a rough draft of something I wanted to try out. It’s a simple logging DataSource. We converted our datasource to one driven by Spring a couple months ago, but we still have a combination of straight JDBC, an old custom in-house ORM tool, and Hibernate. Somewhere among them, we’ve got something occasionally misbehaving.

It’s a pretty simple concept. I decided to extend Spring’s DelegatingDatasourceProxy to make my LoggingDataSource. Configuration is just as simple as changing this:

<jee:jndi-lookup id=dataSourceTarget jndi-name=java:/MyJbossDS/>

to this:

<bean id=dataSource class=com.timshadel.util.LoggingDataSource>
    <property name=targetDataSource ref=dataSourceTarget/>
    <property name=filterPattern value=^(com.timshadel|com.example).*/>
</bean>

<jee:jndi-lookup id=dataSourceTarget jndi-name=java:/MyJbossDS/>

When you turn it on, you might see something like this:

[main] INFO  com.timshadel.util.LoggingDataSource  - Connection request stack trace, filtered by ‘^(com.timshadel|com.example).*’
        com.example.myapp.model.MyClass.determineSomethingImportant(MyClass.java:770)
        com.example.myapp.model.MyClass.updateStatusString(MyClass.java:674)
        com.example.myapp.model.MyClass.loadStatusInfo(MyClass.java:643)
        com.example.myapp.model.MyClass.reloadStatusInfo(MyClass.java:332)
        com.example.myapp.util.helper.LegacyHelper.run(LegacyHelper.java:440)
[main] ERROR com.timshadel.util.LoggingDataSource  - Connection request stack trace, filtered by ‘^(com.timshadel|com.example).*’
        CAUGHT EXCEPTION (java.sql.SQLException): Pretend there’s no more connections.
        com.example.myapp.model.MyClass.determineSomethingImportant(MyClass.java:770)
        com.example.myapp.model.MyClass.updateStatusString(MyClass.java:674)
        com.example.myapp.model.MyClass.loadStatusInfo(MyClass.java:643)
        com.example.myapp.model.MyClass.reloadStatusInfo(MyClass.java:332)
        com.example.myapp.util.helper.LegacyHelper.run(LegacyHelper.java:440)

All of the stacktrace lines have been removed except those that match your pattern. This is helpful to make sure you cut through a typical enterprise Java call stack to only show the calls your code is making. For us that was helpful as a poor man’s way to determine which pieces of our code were using connections frequently. One simple run turned up a few hotspots. If we need to dig in a bit more, perhaps we’ll throw together a simple Ruby script to count how often a given call stack shows up in the log.

Also note, that since this puts the info out to Log4j, you can obviously pull this logging out to a completely separate file, set a different threshold, or use any of the other standard Log4j features to capture this information in a way that’s useful to you.

Finally, please remember that I pulled lots of this together while riding to work. It’s not really meant to be used for anything serious. Please expect warts and problems, but hopefully it’s enough to help get you goin’.