Friday, December 7, 2007

JSP vs Facelets

One of the saddening aspects of JSF is the rendering of HTML along with JSF components in JSP pages.
For example


<div><div>Some Header</div>
<ul>
<li><h:outputText value="list item 1">
</h:outputText></li><li><h:outputText value="list item 2">
</h:outputText></li></ul>


will actually render as


list item 1list item 2
Some Header
<ul><li>
</li><li>
</li></ul>


Alright now the problem is that the HTML is written out right away and the JSF components are rendered at a different time.

Another situation is when you have HTML before or after a JSF Component.


<h:panelGroup>
<p>some markup</p>
<h:outputText value="some text"/>
<p>some more markup</p>
</h:panelGroup>


will render as


some text
some markup
some more markup


Now if you ask me since the default view is JSP for JSF they should have taken this into account.

They should key off the include of JSF tags in a page to parse the JSP differently.
Instead of rendering it like they do they should gather the HTML and attach it to the view in a verbatim component or some other kind of ui output component in the appropriate place in the JSF component tree. This should be possible because everything should be enclosed in a <f:view> tag.

Either that or you have the custom jsf tags be body aware which I assume they are and output the html prior to rendering their component/child component and then render html after the component.

I'm not sure which way is best or where this would take place but it seems very doable.

Now some people say Facelets is the answer and dump JSP all together.
I agree this is a way to fix it but this doesn't let you reuse any JSP tags that are non-JSF.
In the real world there are lots of JSP tags that are not JSF that still need to be reusable.
Also there was a reason for JSP pages in the first place and I'm not sure facelets fully fills that gap.

The real answer should be to fix JSP complation, JSP Rendering, or JSF tags where ever this should take place.

Whoever was responsible for the JSF spec should have seen to this in the first 1.0 release.

Sunday, August 12, 2007

Tiles Killed Convention - Facelets Templating

I recently went to a developers conference and listened to a rapid application development with JSF session by David Geary. I found the session very helpful and informative but something keeps bothering me every time somebody talks about templating as he did with Facelets.

Every time I hear about templating I think it should be easier and more reuseable. I started out developing Struts applications which use Tiles. I then moved on to JSF and Tiles. The nice thing about Tiles is "it works". Sometimes just working is not enough and a little convention goes a long ways.

Recently I've been thinking about the convention over configuration mentality that RoR uses. Also I've come upon a great templating package called Sitemesh. What I love about Sitemesh is you can define a decorator and decorate multiple pages by a matching URL pattern. This is a GREAT idea. Using Tiles I've always had to create a definition for every page in a Tiles definition file, a JSP that inserts the definition, and the page that actually has the content. Well that's three files for each page of content the user sees. Now the problem I have with this is the Tiles definition for the page and the tiles insert JSP is basically repeated for every page. Sure you can define a base Tiles definition and extend it but it tends to be mostly repetitive. You can also define your tiles definition in the JSP page which is just as messy and repetitive.

Let me get back to Facelets. Facelets is a wonderful idea to use the html view and bind to components. The problem is when you get to the templating part it goes back to the Tiles mentality again. You have a page which defines a composition and a page which contains the content. The page with the composition is repeated for every content page and in most cases the exact same composition definition. This is where the convention of Sitemesh is nice and could come in handy. It would be nice if you could define a Facelets composition for a URL path and apply it to all pages in a directory. That's a heck of a start for reuse and convention over configuration. Then you can just configure the exceptions to the case which should be rare.
Sidenote: You can use JSF components in a Sitemesh decorator (http://jira.opensymphony.com/browse/SIM-201).
There are a couple of positive benefits to applying templates based on a URL path that are a side effect. I've been on too many projects where everything is thrown into the base directory of a web application or relatively few directories. This gets out of hand quickly and not good structure. There are also security packages like Acegi that will apply security based on the URL path. So if you have your files in an appropriate file structure it should be easy to find pages, apply templates, and apply security.

(If you don't think it can be done check this out: http://jira.opensymphony.com/browse/SIM-223)

This brings up another annoyance of JSF. JSF has no notion of subdirectories built in. With Struts you could define config files for each URL path and then you didn't need to put the subdirectory paths for the JSP pages in a configuration file. JSF should add this in and promote appropriate directory structure.

As a closing note if you're doing something multiple times and not much changes maybe you should refactor it out. If you are doing this in programming maybe you would extract the commonalities out into a method passing in the parameters and then the method can be reused. In the case of a templating package you should refactor the configuration out of the JSP page or Faclets xhtml view and move it into the URL path with a configuring Servlet or Filter.

Thursday, August 9, 2007

Optimistic Locking in Rails with Active Record for Free...almost

Like other persistence frameworks, ActiveRecord helps us with concurrency issues. This is actually fairly simple, but in general the documentation I have found on this subject has been poor. I will try to sum this up very quickly.

1) Add lock_version

For each table where concurrency is a concern a lock_version column must be added; Rails is then supposed to perform some magic behind the scenes...

In your migration this should look as follows.
table_name.column :lock_version, :integer, :default=>0

Alternatively, if you already have a versioning column in your database you can inform rails of your column by adding the line "set_locking_column 'your_versioning_column_name'" to the associated model class.

2) Catch StaleObjectError

Now that you have added the lock_version column you get concurrency for free. Whenever an attempt occurs to save over the same record version an ActiveRecord::StaleObjectError will be raised.

So now you can update your controllers to catch StaleObjectErrors and handle these however you wish...

This would look something like this.

def some_updating_method(an_object)
an_object.update_attributes(params[:an_object])
rescue ActiveRecord::StaleObjectError => e
flash[:notice] = "This record changed while you were editing it. Please try again."
#maybe perform a redirect here...
end

3) But Wait! Update methods aren't actually passed objects that's too much overhead!

How observant you are. This is where most of the example tend to fall short. In fact, try implementing your update method exactly like Recipe 3.18 from the Rails Cookbook and see what happens...

Generally an update method actually looks more like this.

def update
my_object = MyObject.find(params[id])
my_object.update_attributes(params[:my_object])
end

While this will stop to users from updating at the exact same time this isn't exactly what we want in many cases. More often than not we want to prevent two users from editing over each other without knowing.

This is easily fixed with the following...

def edit
my_object = MyObject.find(params[id])
session[lock_version] = my_object.lock_version
# whatever we want edit to do
# ...
# ...
# call update...
end

Now we update update (har har) to detect the concurrency issue...

def update
if my_object.lock_version != session[:lock_version]
raise ActiveRecord::StaleObjectError
end
my_object = MyObject.find(params[id])
my_object.update_attributes(params[:my_object])
rescue ActiveRecord::StaleObjectError => e
flash[:notice] = "This record changed while you were editing it. Please try again."
#maybe perform a redirect here...
end

Hopefully this helps someone out. If you have a better/cleaner way of doing this, let me know.

Thursday, August 2, 2007

Drop all tables in MySQL

From time to time I would like to be able to drop all of the tables in my MySQL database without actually dropping the database. This can be painful if there are many tables in the database. Recently I came across this little nugget that simplifies the process.

mysqldump -u[username] -p[password] --add-drop-table --no-data [database] | grep ^DROP | mysql -u[username] -p[password] [database]

Voila! All your tables are gone!