Archive

Archive for August, 2006

IDEA 6 Run/Debug Madness

August 20th, 2006

I’ve been testing the latest beta of IDEA 6. If I used Struts or GWT I’d be more excited about it, but the features I use haven’t been enhanced much and there isn’t much else to make me upgrade. However, I ran into a strange setting change in 6 that doesn’t make much sense.

In 5.x, I could import a build.xml file and select which tasks I want to run before I run or debug an application, such as Tomcat or Jetty:
idea6_rundebug2.jpg

This popup is still available in IDEA 6 but it doesn’t seem to have any effect. In the ‘Edit Configuration’ window, you have to again tell IDEA to execute the task, even though you’ve already done so in the first window:

idea6_rundebug.jpg

Nothing like making you do something twice to ensure you really want to do it…

nick Entry

Creating and Validating Struts DynaForms with XDoclet

August 9th, 2006

The XDoclet Struts module supports creating and validating DynaForms through the use of a handful of XDoclet JavaDoc tags. It’s pretty simple, but some explanation is required to take full advantage of this feature. This short tutorial is mostly code, without much description of the various XDoclet tags you’ll see here. For a detailed description, please refer to the XDoclet site.

Let’s start out by looking at two separate classes, Person and Address. Person is shown first:


/**
* @struts.dynaform name="personForm"
* type="org.apache.struts.validator.DynaValidatorActionForm"
* validate="true"
*/
public class Person {
private Long id;
private String name;
private String notes;
private Address address;
public void setId(Long id) { this.id = id; }
public Long getId() { return this.id; }
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="person.name"
*/
public void setName(String name) { this.name = name; }
/**
* @struts.dynaform-field
*/
public String getName() { return this.name; }
/**
* @struts.validator
*/
public void setAddress(Address address) { this.address = address; }
/**
* @struts.dynaform-field
*/
public Address getAddress() { return this.address; }
/**
* @struts.validator type="maxlength"
* @struts.validator-args arg0resource="person.notes"
* @struts.validator-args arg1value="${var:maxlength}"
* @struts.validator-var name="maxlength" value="4000"
*/
public void setNotes(String notes) { this.notes = notes; }
/**
* @struts.dynaform-field
*/
public String getNotes() { return this.notes; }
}

As you can see, Person is pretty simple - just a few properties and some comments. The associated Address class is shown below:


public class Address {
private String line1;
private String line2;
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line1"
*/
public void setLine1(String line1) { this.line1 = line1; }
public String getLine1() { return this.line1; }
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line2"
*/
public void setLine2(String line2) { this.line2 = line2; }
public String getLine2() { return this.line2; }
}

Now that we have our two classes, let’s go over the various tags and what each one does, starting with the Person class.


/**
* @struts.dynaform name="personForm"
* type="org.apache.struts.validator.DynaValidatorActionForm"
* validate="true"
*/
public class Person {

The class-level XDoclet tags define that a DynaValidatorActionForm should be created in the struts-config.xml file, with a name of “personForm” and a type of “org.apache.struts.validator.DynaValidatorActionForm”. You can substitute your own type here if you want to subclass one of the ActionForm classes. If you want to also generate the validation rules for your DynaForm, you have to include the ‘validate=”true”‘ attribute. This attribute just aids processing by the XDoclet templates; it’s not included in the output files. After the class-level comments, we have the various method-level comments. We’ll start with the name attribute in the Person class.


/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="person.name"
*/
public void setName(String name) { this.name = name; }
/**
* @struts.dynaform-field
*/
public String getName() { return this.name; }

The above code is a simple setter and getter pair. What makes this attribute interesting are the comments that generate the valication rules and the form property. Starting with the setter, we can see that the name property is required when the user submits the DynaForm. If the name property is omitted, the “person.name” value is retrieved from the resource bundle. It’s probably best to look at the generated portion of the validation.xml file to understand what’s going on here:


<form name="personForm">
<field
property="name"
depends="required">
<arg0
key="person.name"
/>
</field>
...
</form>

As you can see, it’s pretty simple to define the validation rules use XDoclet tags. Of course, we also need to define our form fields. The getter method has the relevant XDoclet tag to create a form-property element in our struts-config.xml. As shown, the struts.dynaform-field tag will just create the following XML snippet:


<form-property name="name" type="java.lang.String"/>

The name and type attributes are taken from the method. Of course, we don’t have to use the defaults. We can specify a different name and type if we want, as well as define multiple form fields in the getter. For example:


/**
* @struts.dynaform-field
* name="firstName"
* type="java.lang.String"
* @struts.dynaform-field
* name="lastName"
* type="java.lang.String"
*/
public String getName() { return this.name; }

This feature is handy when you need to add additional form fields, but don’t need to define additional object attributes. Let’s look at what our complete form definition for the struts-config.xml would look like:


<form-bean name="personForm" type="org.apache.struts.validator.DynaValidatorActionForm">
<form-property name="name" type="java.lang.String"/>
<form-property name="address" type="example.Address"/>
<form-property name="notes" type="java.lang.String"/>
</form-bean>

What about that Address class? We haven’t talked about it yet. We’re not concerned about creating a DynaForm representation of it, although we could rather easily. Instead, the personForm will just have an instance of the Address class and will access it as a nested bean. We’re more concerned about validating the properties of the Address class when the user submits a personForm. Let’s revisit the Address property in the Person class:


/**
* @struts.validator
*/
public void setAddress(Address address) { this.address = address; }
/**
* @struts.dynaform-field
*/
public Address getAddress() { return this.address; }

You can see that the setter for the Address only has a simple struts.validator tag. That tells the XDoclet template to look in the Address class for all of the validation definitions:


/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line1"
*/
public void setLine1(String line1) { this.line1 = line1; }
...
/**
* @struts.validator type="required"
* @struts.validator-args arg0resource="address.line2"
*/
public void setLine2(String line2) { this.line2 = line2; }

The XDoclet template follows the struts.validator rule in the Person class to the Address class and includes whatever it finds there. The final result of these rules is the following validation.xml snippet for the personForm:


<form name="personForm">
<field
property="name"
depends="required">
<arg0
key="person.name"
/>
</field>

<field
property="notes"
depends="maxlength">
<arg0
key="person.notes"
/>
<arg1
key="${var:maxlength}"
resource="false"
/>
<var>
<var-name>maxlength</var-name>
<var-value>4000</var-value>
</var>
</field>

<field
property="address.line1"
depends="required">
<arg0
key="address.line1"
/>
</field>

<field
property="address.line2"
depends="required">
<arg0
key="address.line2"
/>
</field>
</form>

Next, we need to look at the Ant tasks to generate these files. An annotated XML snippet is shown below.


<target name="xdoclet-web">
<taskdef classname="xdoclet.modules.web.WebDocletTask" classpathref="project.class.path" name="webdoclet"/>
<webdoclet destDir="etc/web" excludedTags="@author,@version,@todo" mergeDir="etc/merge">
<fileset dir="src">
<include name="**/*.java"/>
</fileset>

<!-- The strutsconfigxml element generates the struts-config.xml file. -->
<strutsconfigxml destDir="etc/web" mergeDir="etc/merge" version="1.1"/>

<!-- By including this element, the validation.xml file will be
generated based on your struts.validation tags. -->
<strutsdynaformvalidationxml/>

</webdoclet>
</target>

That’s all there is to creating and validating your DynaForm with XDoclet. A future revision to this tutorial will include a method to override the validation rules defined in an associated objects.

nick Articles

TiArmor by Vix

August 3rd, 2006

Note: I wasn’t compensated for this post.

My Powerbook is coming up on its 2nd anniversary. Other than a prematurely failed drive, it’s been a great machine. One shortcoming has been the lack of any texture in the areas to the right and left of the trackpad - where your hands would normally rest. The heat coupled with long hours coding and writing can lead to sweaty hands, which nobody wants.

Luckily, Vix Inc. has released TiArmor, a thin film applied to the notebook case that provides a subtle texture and protection to the case. Available in clear and grey, the TiArmor works extremely well. I’ve been using it for about a week and it makes long coding sessions more bearable.

What’s the downside? So far I haven’t found any. You’ll need to take your time when installing them to ensure all of the air bubbles are removed. I wasn’t patient enough and ended up with some trapped air. However, patience has never been one of my strong points.

nick Entry

Using WordPress As a CMS

August 3rd, 2006

Frequent readers will notice that I’ve recently redone my company’s website. When I made the decision to reimplement the site, I decided that I needed some form of a CMS to make updating content easier. Applications like Joomla or whatever is available for Java just seemed like overkill. I had been using WordPress for blogging for a while and was quite happy with it, so it seemed natural that I’d try to use it as my site’s CMS. But first, I needed a theme.

I found the theme on OSWD, and I managed to convert it into a WordPress theme with little trouble. (The image seen on the various pages is mine, taken during a rare vacation to Downeast Maine.) Converting a well-structured theme into something usable by WordPress is surprisingly easy and much like any other web project when you receive the design and need to cut it up for the application.

The index page for the site needed to be different than the content based pages. My intention was to display a text blurb along with two lists of links, one for recent articles and another for news. The links would link to category-specific posts. To do this, I just needed to edit the index.php file to display titles from two blog post categories. The text blurb is hardcoded, but it would be easy to have the text included from a specific post.

After the index page, the rest of the site was trivial to implement. Static pages like Contact and About were pages instead of posts, and I used the wp-contactform plugin to allow visitors to contact us.

Next, I decided that I wanted to include Google Adsense ads into the site, but only for blog posts and articles. WordPress allows you to create , which is what I created for my blog post categories. You’re looking at one now, in fact.

I’m not a PHP programmer, but WordPress is very well documented, which made this process very easy. If you need a simple, flexible CMS, WordPress could be the way to go.

nick Entry

OmniPlan Unleashed into the Wild

August 2nd, 2006

Being a user of both OmniGraffle and OmniOutliner, I was looking forward to Omni’s next application: OmniPlan. Although it’s an early beta, I had high hopes for OmniPlan, especially given the comparatively high $150 license fee.

Starting it up, the first thing I noticed is how pretty the interface is. Unfortunately, that doesn’t serve to make the interface easier to use. One thing I don’t want to do is fight with the application - I just expect it to work and get out of my way. That didn’t seem to be the case with OmniPlan. I spent most of my time fighting with elements and trying to navigate the interface.

I hope things improve with this product. The other Omni Group products I use are excellent, OmniPlan currently doesn’t warrant anything close to $150/license.

nick Entry