Tuesday, April 22, 2008

Extending a Struts2 theme

"Oh, so that's what a theme is!" - I exclaimed in my mind when I finally found out why my jsp page didn't look as I expected. I had the theme="simple" set in my <form> tag, as I had blindly copied it from some tutorial long ago, but expected the page to render as if it had the xhtml theme applied.

Struts2 themes are the Fairy Godmother who may turn a plain looking form made out of Struts2 tags to a full-fledged table. Or in general - they may decorate any struts2 tag it with any html you wish, using Freemarker template engine.

For example, the xhtml theme puts the <s:form> tag into a table containing two columns: one holding labels, the other one holding inputs. Having a plain form like that: will result in generating the following html: It's the xhtml theme, too, who is responsible for rendering form validation errors next to the appropriate fields. Before I learned this, I had been experimenting furiously with my simple-themed form, wondering where my validation messages go!

Well, at least I've found them :). But setting my form's theme to xhtml wasn't really appealing to me. I'd have to rearrange it completely, as I have already designed it as a table. Still, I wanted the errors to appear next to the erroneous fields.

Encouraged by Mark Menard's great post, I decided to extend the Struts2's simple theme. Nah, just tweak it a little bit, to be honest.

So I started with downloading the original simple theme from Struts2's repository and copying it to my application under the name fieldError. In Maven2's directory tree, it went in src\main\resources\template\fieldError. I then replaced the text.ftl file with the one from xhtml theme - this is the template responsible for decorating <s:textarea> tag. If you look inside it you'll see all it does is "calling" three other templates - controlheader.ftl, text.ftl from the simple theme and controlfooter.ftl. These templates in turn extend other templates - and if you dig in, it becomes clear that all the error handling logic resides in controlheader-core.ftl. This is the fragment that interests us the most: Even if you're as much a Freemarker ignoramus as I am, it should be clear, that in the snippet there is a check if there are are errors and then - some kind of iteration. In each iteration there's a table row being rendered. I'm not into having any additional cells in my table, though - say, a html list would do. So here's what I replaced this fragment with: Just one more thing and we're done. When I tried to run the app at this point, I got a message from Freemarker who was confused as of where to look for the templates. So I had to inform him of that in my struts.xml file: The entire directory with simple theme also needs to be copied to the template directory so that Freemarker can include them:

src
  +main
    +resources
       +template
          +simple
          +fieldError
We can now start using the new template: And the result is following: Here's the entire template directory for you to download.

Monday, April 21, 2008

Struts2, uploading a null file and disappearing ActionMessages

There are two small errors I found in my Struts2 app today. Two little sneaky bastards, caused by my inattention, and perhaps insufficient documentation of Struts2. I'd like to post them both, in case it saves some other newbie's day.

The first one concerns the use of the FileUploadInterceptor. It's a really handy class that manages uploading a file from your webapp's form. It's a part of the defaultStack, so all you need to enable the file upload is one s:file tag on your jsp, and a bunch of getters/setters in your Action class, which will allow you to access the uploaded file, already residing on the server. It's all described in details on RoseIndia.

However, what I haven't found in any of the example code snippets, is checking whether the user has chosen a file at all. In the case of my application, uploading a company's logo is not mandatory - so I needed a test before loading the image, checking whether there's any file being uploaded. So what did I do? Let's see: the FileUploadInterceptor fills in three properties of my action:

Well, if the File pic references the actual file, I simply checked whether it was null: ...which didn't prove to be a good idea. pic just kept on containing a reference to a nonexistent temp file. At first I thought the params interceptor somehow "forgot" to set it to null, if a file had been transferred previously. However, this was not the case. Every time the filename was different, but it was there. What's the solution, then?

It seems that the other two properties aren't there without purpose. Apparently, FileUploadInterceptor works this way: every time it runs, it generates a file name and creates a File object for it, no matter if a file is actually being uploaded. That's a normal behavior. What I should have done is checking the String picFileName property, which is empty if there's nothing being sent, like this: That's it, worked like a charm. Still, I find it a little misleading and think the javadocs of FileUploadInterceptor lack a suitable warning.

The other mistake of mine was while setting the ActionMessages of my action which extends the Struts2's built-in ActionSupport. There it is, down in black and white:

getActionMessages public Collection getActionMessages() Description copied from interface: ValidationAware Get the Collection of Action-level messages for this action. Messages should not be added directly here, as implementations are free to return a new Collection or an Unmodifiable Collection.
...and so it does. Trying to do: resulted in my message "disappearing" in the always empty collection. Man, that felt creepy! ;) It's a pity I haven't noticed this method before: but there's no way I could blame the missing documentation this time - just me and my blondishness :)

Saturday, April 19, 2008

SyntaxHighlighter on Blogger

Ironically, my first reasonable post here is going to cover Blogspot itself.

When I decided to set up a blog, one of the few things I knew it should have was a nice syntax coloring script. The most powerful one I've seen so far is SyntaxHighlighter, which not only features coloring as such, but also displays the code in a neat, scrollable box with actual line numbering. Now that's a killer!

However, wiring SyntaxHighlighter to your Blogspot site does take some doing. Especially if you tend to thoughtlessly copy someone else's code :)

First of all, Blogspot doesn't allow link tag in your posts. Which is where I put it, having simply copied the sample code from the Usage page.

Luckily, if you go to Layout -> Edit HTML pane, you may edit your blog's template in an XML format. That's where you need to find the head section and insert the link to your css.

Right, the link. Our friends at Blogspot haven't provided for uploading any external files like scripts or CSS, so you either have to host them somewhere else or manually insert the CSS in the CSS section of the Blogger's template. I opted for the latter, courtesy of my dearest Bro.

To get SyntaxHighlighter to work, you still need to call some JavaScript functions as well as import a Flash file. I'm pretty unlikely to be blogging about my love life, rather programming issues, so I'll probably include some code on a regular basis. Having to paste those script lines every time I do it would be an overhead. (My brother deleting the linked scripts is a hazard, too). Thus placing as well the script includes in the template seems to be a good idea.

So you think we've got the syntax coloring configured? Surprise. If you insert some code to your blog, you'll find the <pre> or <textarea> contain one line only, with some nasty br tags in them. Bad, bad Blogger, converting all line breaks into br tags, even in Html mode! Fortunately there are two solutions to this. Either you disable the "Convert line breaks" option in Settings -> Formatting pane, or you can resort to "blogger mode", already implemented in SyntaxHighlighter. Well, thanks guys for pointing that out - nothing is obvious at 2 AM...

Just two more hints, in case you've stayed up late as I have:

1. The syntax of JavaScript doesn't involve any funny question marks. If you find any in your code, you've probably copied it from a Wiki along with the camel case escape characters.

2. If you want test the coloring on your Java code, include shBrushJava.js instead of the sample shBrushCSharp.js.

So, let's give it a try. These are the vital snippets from my template xml:



Let's see how this renders... ;)

PS. Oddly enough, the textarea containing code gets doubled on the main page, while all is as expected if you follow the entry's link. No clue why this happens. Any ideas?

Thursday, April 10, 2008

Test...

Which is, actually, a common misuse of the term 'test'.

HTML:

Java: