Wednesday, December 24, 2008

New Features in Eclipse 3.5

In an attempt to attract younger developers, the next version of Eclipse is to include Unlockable Achievements:


Beta testers are encouraged to submit their own Achievement ideas. Suggestions include:

  • Anally Retentive: remove all warnings from your code. Yes, even those ones about serialVersionUID

  • Saintly Patience: use BigDecimal for more than 5 minutes without wishing for operator overloading in Java

  • Ant Fan: start an Ant build and watch it finish without visiting Slashdot in between
Update: this blog post was, of course, a joke. However it appears that 3 years later Microsoft has actually gone and done it!

Thursday, December 4, 2008

Better Than Free: Metawidget v0.65

There was a time, years ago, when just having a $0 price tag on a piece of software would have sparked people's interest. Nowadays, the success of Open Source has meant that free is not enough.

For a new software project to be noticed, it doesn't just have to be free: it has to be well documented, well tested, have plenty of working examples, an attractive Web site and high quality code. And even then the competition is fierce: developers are busy people, and have very limited time to evaluate new technologies.

So the big feature in the new release of Metawidget, aside from a number of upgrades and enhancements (such as Commons Validator support), is a Live Demo that lets you immediately get in and start playing and coding with Metawidget. I'm hoping it's a great way to let people try it without having to download, unzip and read through the usual distribution.

The Live Demo uses an enhanced version of the Groovy 1.6 Console Applet to give you a fully working Java-like scripting environment. Everything is set up for you just to click Run. You can then fiddle with the code, even import your own business model classes on to the CLASSPATH to see how Metawidget renders them.

You can find the Live Demo here:

http://metawidget.org/live-demo


Also, special thanks to Gerardo Diazcorujo and Ryan Cornia for their help testing this release. Your continued feedback is invaluable to us. Please let us know what you think.

Friday, October 31, 2008

A Unified Theory

I just had an interesting exchange with the guys from the OpenXava project. We discussed differences in our two approaches, as well as those of other UI generation projects, and what it would take to unify them all under a JSR one day. I think we're a long way from that day, primarily because UI generation isn't particularly 'mainstream' yet (at least, not in the sense of ORM). Still, it's often said in physics that even though we don't know what the Unified Theory is, we know something about what features it must have.

Can we say something similar about UI generation? I'll list here all those features I think are being explored, either by Metawidget, OpenXava or one of the other projects, and see if we can update this page over the years to form consensus.

Static or Runtime

Should the generation happen statically or at runtime? If runtime, how do you allow customisation? If statically, how do you allow re-running the generation when the domain model changes (without losing any customisations)?

Static: n/a
Runtime: Metawidget, Naked Objects, Woko

Modeling Language

Should the generator have its own modeling language, which developers use to describe the UI, or should it try and derive the UI automatically? Do modeling languages introduce error-prone duplication? Is automatic derivation too inflexible? Is there enough metadata to drive automatic derivation, or do we have to 'guess and fill in the gaps'?

Yes: n/a
No: Metawidget, Naked Objects, Woko

Production or Prototype

Should we expect UI generation to be able to be used in production applications, or only during a prototyping phase?

Prototype: n/a
Production: Metawidget, Naked Objects, Woko

Customisation

What sort of customisations of the generated UI are important? Graphics? Layouts? How should we facilitate them?

Pluggable: Metawidget, Woko
Search-based: Naked Objects

Bounds of Generation

Should we try to automatically generate the whole UI, or just pieces of it? Is generating the whole UI flexible enough? Is just generating pieces useful enough?

Whole UI: Naked Objects, Woko
Just pieces: Metawidget

Multiple Platforms

Is supporting multiple platforms (eg. desktop, web, mobile) important?

Yes: Naked Objects, Metawidget
No: Woko

Consistency

Given the same domain model, should we try and produce a consistent UI across all platforms? Does this risk a 'lowest common denominator'? Does tailoring uniquely to each platform introduce too much work for the developer?

Yes: n/a
No: Metawidget, Naked Objects

Diverse Architectures

Should the generator care about diverse architectures? Is mandating the technology stack of the application too restrictive? Or should we try to enforce 'good coding' that way? Does supporting multiple versions of everything introduce too much complexity? Is the ability to retrofit existing applications an important goal?

Yes: Metawidget
No: Naked Objects, Woko

Third Party Components

Should we support third-party UI components? What if they are not available on all platforms (eg. desktop, web)?

Support third-party: Metawidget
No explicit support: Naked Objects, Woko

Non-Domain Model Objects

Should we support modelling objects that are not strictly part of the domain? 'Solution space' objects, such as search screens that are user-centric (even role-centric) and not persisted to long-term storage?

Support non-domain model objects: Metawidget
No explicit support: Naked Objects




Convergence

Following conversations (some below, some in newer blog entries) with various parties, we note some convergence with future releases of products. Specifically:

Naked Objects: 4+ supports deriving metadata from different sources. Newer viewers may allow generating just pieces of the UI, and also modelling non-domain objects. Future versions want to support third-party components.

Woko: 2+ will allow more diverse architectures.

Tuesday, September 30, 2008

Generate User Interface Automatically: Metawidget v0.6

Version 0.6 of Metawidget, the tool that lets you generate user interfaces automatically, is now available. This release includes:
Special thanks to Rintcius Blok for his contributions to this release!

As always, the best place to start is the Reference Documentation:


Your continued feedback is invaluable to us. Please download it and let us know what you think.

Metawidget: Ready, Set, Action!

The new release of Metawidget furthers its philosophy of 'inspecting the existing back-end for as much information as possible' by going after actions.

So now, in addition to automatically generating and wiring up textboxes, checkboxes etc. based on the properties of your business model, it'll generate buttons based on the actions of your business model.

This support is all pluggable, of course. With this release we've included two plug-ins: one for JBoss jBPM and one for Swing AppFramework.

JBoss jBPM


If your back-end architecture uses JBoss jBPM to define pageflows...

<pageflow-definition name="newuser">
   <page name="contact">
      <transition name="prev" to="account" />
      <transition name="next" to="card" />
   </page>
</pageflow-definition>

...then you can now point a Metawidget at that pageflow...

<m:metawidget value="newuser.account"/>

...and it'll generate command buttons that are localized and wired up to the correct actions...


You can see this in action in the included DVD Store Example, which retrofits an existing Seam application to generate its input fields and command buttons automatically, reducing all that boilerplate code.

Swing AppFramework


If you're using the Swing AppFramework (JSR 296) to structure your Swing app...

@Action
public void save( ActionEvent event ) {
   mMetawidget.save();
}
...then you can now point a Metawidget at your business model, and it'll generate command buttons that are localized and wired up to the correct actions. You can see it in action in the included Car Demo.

You can further combine all this with the other pluggable inspectors, such as JexlInspector to easily and declaratively control your app's actions...

@UiAction
@UiJexlAttribute( name = HIDDEN, value = "${!this.readOnly}" )
public void edit() {
   ...
}

@UiAction
@UiJexlAttribute( name = HIDDEN, value = "${this.readOnly}" )
public void save() {
   ...
}

@UiAction
@UiJexlAttribute( name = HIDDEN, value = "${this.readOnly || this.newContact}" )
public void delete() {
   ...
}

@UiAction
@UiComesAfter( { "edit", "delete" } )
@UiJexlAttribute( name = "label", value = "Back", condition = "${this.readOnly}" )
public void cancel() {
   ...
}

This code is enough to generate:
  • an Edit button that, when clicked, disappears in favour of...

  • ...a Save button

  • a Delete button that only appears if it's not a new business object

  • a Cancel button, that says Back if the user has not edited anything yet

You can see it in action in the included Swing Address Book Example...


So now there are even more places Metawidget can inspect your existing back-end architecture and remove the need for you to write boilerplate code for your existing front-end framework!

Wednesday, August 27, 2008

Duplication in User Interfaces: 10 Questions


I'm trying to collect some data about the problem Metawidget is trying to solve. Please take a moment to complete this short survey. I'll post the results in a later blog.




Tuesday, August 26, 2008

On Duplication in User Interfaces

Abridged from Kennard, R., Edmonds, E. & Leaney, J. 2009, 2nd International Conference on Human System Interaction

A User Interface (UI) is, by definition, a human-usable abstraction of an underlying system. Yet this holistic view is often overlooked in the discussion of the mechanics of UI tools, which view the UI as being separate to other subsystems of an application. This separatist viewpoint forces the UI to respecify variables from the other subsystems, and any discrepancy between the versions in the UI and those in the subsystems can only lead to errors.

This blog entry explores a sample of mainstream subsystems in use by real world applications. The example subsystems are taken from the Java platform, being one of the dominant enterprise platforms in use today.

There are a large number of possible application architectures, and not all will use all subsystems. Some will use different implementations from different vendors, some will use new types of subsystems, some will use no equivalent subsystem. The important point is that wherever a subsystem is used the UI must be consistent with it or, as will be discussed, the application cannot be expected to function correctly.

Note that this sample is not limited to those subsystems that typically exist on the same application tier. In order to reduce the maximum amount of duplication, it is important to source information from wherever it can be found, including subsystems that may be located remotely from one another. For example, in a typical application stack the UI tier is restricted from inspecting the implementation of the database tier, and special considerations must be made in order to access it securely. However, the difficulty of extracting information is considered secondary to the goal of removing duplication.

Properties Subsystem
The JavaBean specification was introduced in version 1.1 of the Java platform to enable the declaration of publicly accessible properties. It is more a convention than a part of the language, as it relies on methods with a particular signature. For example, to declare a JavaBean 'Person' with two properties 'name' and 'age', a developer would write:

public class Person {
   private String mName;
   private int mAge;

   public String getName() {
      return mName;
   }
   public void setName(String name) {
      mName = name;
   }

   public int getAge() {
      return mAge;
   }
   public void setAge(int age) {
      mAge = age;
   }
}

Even within the boundaries of its own convention, the JavaBean syntax contains duplication. The methods getName and setName must both contain the word 'Name', and must both use a type of String. In most cases, this name and type will further be mirrored by the private member variable 'mName'.

Such levels of duplication may not appear onerous in a simple example. However, having to maintain two methods and one member variable for every property quickly becomes problematic as the number of properties scales up. For example, subtle bugs will occur if a developer copies and pastes methods like 'getName' and 'setName' and renames them to, say, 'getNotes' and 'setNotes' but forgets to also alter the 'mName' variable they operate on. Here, attempts to update 'notes' will actually result in updating 'name':

public class Person {
   private String mName;
   private String mNotes;
   ...
   public String getNotes() {
      return mName;
   }
   public void setNotes(String notes) {
      mName = notes;
   }
}

Worst still is that this bug, like most duplication related defects, is not able to be identified statically, such as at compile-time or during application startup. Rather, it will only be encountered at runtime and developers must rely on runtime testing to expose it.

This verbosity and unnecessary duplication is a frequent criticism of the JavaBean convention. Modern Integrated Development Environments (IDEs) such as Eclipse and NetBeans can statically generate the two methods based on the member variable, but cannot remove the need for the code altogether. Therefore even when the implementations are correct, having many lines of repetitive statements quickly overwhelms and obscures important code. For example, a 'set' method may contain a business rule but a developer can easily miss it in the noise:

public class Person {
   ...many get and set methods...
   public void setAge(int age) {
      if (age<0) throw new Exception("Negative age");
      mAge = age;
   }
}

In recognition of this problem of duplication, language-level support for properties is a proposed feature for the next iteration of the Java language In the meantime, other languages already provide such support. Groovy (a language which runs on the JVM and has a similar syntax but different features) supports properties. In Groovy, a developer would write:

class Person {
   String name;
   int age;
}

There is now no duplication. Both the name and the type only appear once for each property. Note this is quite different from simply declaring two public member variables, as properties have implicit methods that guard the setting and retrieval of their values. These implicit methods can be explicitly overridden to introduce finer-grained controls (such as a check for 'negative age') at any stage in the application's development, even after other code has already been written against the implicit methods. This 'implicit by default' approach is a significant improvement over the explicitness of JavaBeans because finer-grained controls will be the exception, not the rule.

Whether properties are specified using JavaBeans, Groovy, or some other mechanism, the important point is both the name and type are concretely specified by the properties subsystem. It is duplication to respecify them anywhere else.

Persistence Subsystem
Most business systems persist their data to long-term storage, such as a database. To continue the Person example from the previous section, the developer may define the following SQL schema to store a Person:

TABLE person (
   name varchar(30) NOT NULL,
   age int NOT NULL
);

The persistence subsystem contains new information compared to the properties subsystem. Strings in Java are immutable, so do not have any concept of 'maximum length'. They are also implicitly nullable. Conversely, from the SQL schema it can be seen that 'name' is actually limited to 30 characters and is not-nullable (eg. is a required field). Clearly, the properties subsystem alone is not sufficient to fully the describe the business model.

However, there is also duplication. The names and types of each property have already been defined by the properties subsystem. It would not lead to a functioning system if the persistence subsystem was inconsistent. An ideal solution would be to eliminate the duplicated information whilst retaining the new information. Such a solution is provided by Object Relational Mappers (ORM) - a notable one being Hibernate.

Hibernate allows the developer to specify mapping files to map properties to database schemas. These mapping files include the new information:

<hibernate-mapping>
   <class name="Person">
      <property name="name" length="30" not-null="true"/>
      <property name="age"/>
   </class>
</hibernate-mapping>

There is still duplication in that 'Person', 'name' and 'age' are respecified, but the duplication is at least able to be validated: if there is inconsistency between the properties and the mapping file, Hibernate will error during application startup. This is an important step in reducing the margin for error, even if it doesn't reduce the duplication itself.

A next generation ORM is the Java Persistence Architecture (JPA) standard. JPA achieves the goal of removing duplication entirely, whilst at the same time preserving the new information, by using metadata annotations on the properties:

public class Person {
   ...
   @Column(length=30,nullable=false)
   public String getName() {
      return mName;
   }

The important point is that persistence subsystems have evolved from SQL, through iterative generations of ORMs, to standardization - with a specific goal of removing duplication. A similar evolution and standardization for UIs would be highly beneficial. It might be though of as Object Interface Mapping (OIM).

Validation Subsystem
Persistence subsystems generally fail poorly when presented with invalid data, returning error messages that are not suitable for end-user consumption. Therefore it is desirable to pre-validate the data and, if necessary, return more meaningful messages.
Early validation subsystems, such as the Apache Commons Validator, use XML files to specify validation rules:

<form name="person">
   <field property="age" depends="intRange">
    <var>
       <var-name>min</var-name>
       <var-value>0</var-value>
       <var-name>max</var-name>
       <var-value>150</var-value>
    </var>
   </field>
</form>

As with the Hibernate mapping file in the previous section, it is evident these validation files contain both duplication ('age') and new information (minimum and maximum values). Again, it is desirable to remove the duplication whilst retaining the new information.

Next generation validation subsystems such as Hibernate Validator achieve this, again using metadata annotations on the properties:

public class Person {
   ...
   @Min(0) @Max(150)
   public String getName() {
      return mName;
}

Standardization efforts around future validation subsystems are ongoing. They allow the developer to define sophisticated scenarios including partial validation and interrelated validation between properties. For example, two properties could be mutually exclusive. If such properties were represented in a UI, filling in one may disable the other.

XML Serialization Subsystem
If the UI is the user interface to an application, XML messaging could be thought of as the machine interface. From this perspective, it shares the same problem of duplication. For example, a Web service request to load a Person may return the following XML:

<person age="30">
   <name>John Doe</name>
</person>

The 'age' attribute and the 'name' element must be consistent with those defined in the property, persistence and validation subsystems, else those systems will fail.

Modern solutions eliminate this duplication whilst retaining the extra information necessary to format the XML. For example, the Java API for XML Binding (JAXB) uses metadata annotations on the properties:

@XmlRootElement
public class Person {
   ...
   public String getName() {
      return mName;
   }
   @XmlAttribute
   public int getAge() {
      return mAge;
   }
}

The 'Person' class has metadata that declares it as an XML root element. The 'age' property has metadata that declares it as an XML attribute.

Internationalization Subsystem
In order to internationalize and localize an application, all human-readable text is generally factored into an internationalization subsystem. For example, the Java platform defines ResourceBundles of key/value pairs:

Resource-en-AU.properties
name=Name
age=Age
Resources-it-IT.properties
name=Nome
age=Eta

Internationalization is seldom used during the prototyping phase, but is an important subsystem once in production. It is mentioned here as it is one of the subsystems referred to later.

Business Process Modeling Subsystem
In a similar vein to validation subsystems, BPM subsystems externalize and formalize the business rules of an application. For example, using JBoss jBPM a developer can specify the valid actions available when editing a Person:

<page name="editPerson">
   <transition name="save" to="personSaved"/>
   <transition name="delete" to="personDeleted"/>
</page>

Generally it is these actions, and only these actions, that should be presented to the user in the UI.

Unit Test Subsystem
We conclude with a counter example of duplication. A unit test subsystem is separate from, but closely related, to an application and generally embodies a significant amount of duplication. This is intentional, and is used as a form of independent verification.

For example, a unit test may test the 'Name' property appears on a given UI screen. This 'Name' property must be specified within both the application and separately within the test subsystem so that, in the event of a regression, there is a mismatch and the test fails. If the test shared the declaration of the 'Name' property with the application, both the test and the application would regress together and the error would go unnoticed.

It is instructive to note that, in this case where duplication is a useful feature, it is useful only because duplication encourages brittleness between subsystems. Failure in the face of change is desirable for regression tests. It is not desirable for the rest of an application. Despite not being a desirable trait, the cumulative effect of the subsystems explored here is a high level of duplication and brittleness with the UI. We demonstrate this next.

Impact of Duplication
To appreciate the cumulative effect of the sample subsystems, we'll now explore constructing a hypothetical UI using a conventional UI builder or modeling language and demonstrates how much of that work is, in fact, duplication from other subsystems.


To construct the simple UI shown above, the developer must first drag (in a UI builder) or declare (in a modeling language) the labels for each of the 5 fields. The text on the labels must be semantically consistent with those defined in the properties subsystem. It would not lead to a functional system if, for example, the UI labeled a field 'Notes' which the property subsystem considered to be 'Name'. There may be slight differences - such as using a different language or more explanatory wording in the UI - but these would generally be handled by the internationalization subsystem as described in the previous section.

Second, the developer would choose appropriate UI widgets for each field. There is some flexibility here, but only a little. It would not lead to a functional system if, for example, a date picker widget was used for the 'Age' field. Similarly, the widget for the read-only 'Retired' field (which displays 'Yes' or 'No' based on age and gender) can never be an input widget. Whilst it is important to preserve the flexibility (for example, a UI may choose to represent the 'Name' field as two fields 'Firstname' and 'Surname') it is also important to realise, rather like the JavaBean and Groovy example discussed previously, that it is the exception not the rule.

Third, the developer would apply constraints to each widget. These constraints must match those imposed in the other subsystems. The 'Name' textbox must be limited in the maximum amount of text it accepts to the same length declared in the persistence subsystem (this is different to its visual length, which may be shorter than the maximum and scroll as the user types). The 'Age' slider must have the same minimum and maximum values as declared in the validation subsystem. The 'Gender' dropdown must only contain valid values as defined by, say, an enum.

Fourth, the developer would designate certain fields as required fields, and label them appropriately. For example, the 'Name' field is labeled with a star. These must correspond with the persistence subsystem. It would not lead to a functional system if the UI allowed a field to be optional that the database considered not nullable.

Finally, the developer would choose appropriate command buttons. These must correspond to the subsystem that handles the action, and must be named consistently. It would not lead to a functional system if, for example, the Save button executed the Delete action. In addition, a subsystem such as a BPM would already define whether a button is applicable in a given context. For example, the Delete button may not be considered valid when entering a new Person.


As shown in the table above, it can be seen there are over twenty 'points of duplication' with other subsystems for only a simple UI screen with 5 fields. Scaled up to real world applications with dozens of screens and hundreds of fields, such duplication goes from being unnecessary to being a significant potential for application errors. Worst still is that these errors can rarely be identified statically, such as at compile-time or during application startup. The developer must rely on runtime testing to expose them.

By exploring ways to remove duplication it is possible to not only reduce such errors, but to create more robust UIs. This is because developers may choose to simply omit the duplication rather than risk it becoming inconsistent over time. For example, a developer may not specify the maximum text length on the 'Name' field at all, in the hope the validation subsystem will catch any overflows.

Not all applications will use property, validation, persistence and BPM subsystems. Some will use no equivalent subsystem, some will use new types of subsystem. Wherever a subsystem is used, however, the UI must be consistent with it or, as this hypothetical example demonstrates, only defects can result: there is no usefulness to the duplication.

Tuesday, July 29, 2008

Death by Annotations

Every so often I read how 'we're all going to be drowning in annotations' or how someone's 'annotations are exploding' and consequently how 'OMG annotations suck'. I'd agree it's a problem. But, seeing as how Metawidget is probably going to make it worse, not better, I thought I should offer a balanced view.

Here's the basic problem. Here's a piece of Real Code, from one of my production systems, that uses JPA, JAXB, Hibernate extensions and Metawidget:

@OneToMany( cascade = CascadeType.ALL )
@JoinColumn( name = "survey_id" )
@IndexColumn( name = "number", base = 1 )
@Cascade( org.hibernate.annotations.CascadeType.DELETE_ORPHAN )
@UiComesAfter( "dateExtension" )
@XmlElementWrapper
@XmlElement( name = "question" )
public List getQuestions()
{
   return mQuestions;
}

A lot of people are going to look at that, think it looks really messy, and turn off. And I agree - it does look really messy. But it's important to consider what we've gained here, and what the alternative is:
  • it's less code, and more typesafe, than 4 separate XML configuration files

  • the metadata is closer to the thing the metadata is referring to

  • whilst it may seem like a lot of annotations for little actual code (the bit in bold), that's backward thinking: annotations are code, albeit declarative code. And it's a lot less code to write something declaratively than procedurally
So whilst I don't necessarily think annotations are as good as life can get, I do think they're better than anything we ever had before. The challenge now is how do we make them better?

Sunday, July 20, 2008

JEXL: An Expression Language (EL) for Swing?

In response to this forum posting, the next release of Metawidget (v0.6) adds support for Commons JEXL.

This lets environments that don't have an Expression Language (EL) of their own (environments like Swing, GWT etc) wire components together more easily. So, for example you can do:

class Person {
   public boolean retired;

   @JexlAttribute( name="hidden", value="${!this.retired}" )
   public Date retirementDate;
}

And the 'retirement date' field will only appear if the 'retired' checkbox is checked.

To enable JEXL support, you just need to add a JexlInspector into your CompositeInspector.

Thursday, July 10, 2008

Metawidget and Rebinding

One of the cool features of Metawidget is automatic binding between the business model and the UI, using whatever technologies the underlying platform supports (such as BeansBinding).

Up until now, however, there has been a bit of a 'gotcha' with this.

For Metawidgets that don't use automatic binding, the general approach is to call setToInspect and then setValue to populate the generated UI from business model values. This technique has an implicit side effect: the values can also be repopulated as many times as you like with new source objects, without re-calling setToInspect. This allows the Metawidget to be generated once and reused many times, mitigating the performance cost of generation.

For Metawidgets that do use automatic binding, however, setValue is never used. Setting new values requires re-calling setToInspect (and re-running generation) for every new source object.

To avoid this the new release of Metawidget supports a second, lightweight version of setToInspect called rebind. This function is only relevant when using automatic binding. Using rebind, a Metawidget can update the values in its generated widgets without re-running generation. This allows the Metawidget to be generated once and reused many times.

The downside of rebind is that the rebound source object must have exactly the same set of field names as the original object, else the call will fail. It becomes the responsibility of the caller to ensure this consistency.

For an example of rebinding, see the GWT Address Book sample application.

Metawidget: Javassist versus @UiComesAfter

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically PropertyStyles are now set as object instances, not as classes. Please download the latest documentation from http://metawidget.org

There's been some feedback that having to annotate your business model with @UiComesAfter like this...

public class Person {
   public String name;

   @UiComesAfter( "name" )
   public int age;

   @UiComesAfter( "age" )
   public boolean retired;
}

...to order the UI fields is a bit annoying. I agree. The problem is the Java classfile specification doesn't maintain the original declaration order of methods and fields, so we can't extract this information from reflection.

Of course, Metawidget can extract it from other places instead, such as hibernate-config.xml or metawidget-metadata.xml files, where available - but failing that you have to provide the ordering information somehow.

Well, thanks to an idea by those guys from the Tapestry team, there is now another option: JavassistPropertyStyle.

If you have Javassist available in your environment, the new JavassistPropertyStyle can use Javassist to extract debug information from the Java classfile and order the fields according to source code line number! No more @UiComesAfter! You use it like this:

<propertyTypeInspector xmlns="java:org.metawidget.inspector.propertytype"
   config="org.metawidget.inspector.impl.BasePropertyInspectorConfig">
   <propertyStyle>
      org.metawidget.inspector.impl.propertystyle.javassist.JavassistPropertyStyle
   </propertyStyle>

</propertyTypeInspector>

There are downsides. First, if you accidentally recompile your business model without debug information (like, say, when you go from development to production) all your fields will quietly unorder themselves. To protect from this, JavassistPropertyStyle fails early and fails hard if there is no debug information.

Second, JavassistPropertyStyle uses the following sorting algorithm:
  • superclass public fields come first, sorted by name

  • superclass methods come next, sorted by getter line number (or, if no getter, setter line number)

  • public fields come next, sorted by name

  • methods come last, sorted by getter line number (or, if no getter, setter line number)
This algorithm is less flexible than @UiComesAfter, which can interleave superclass and subclass properties. However, it is possible to use both @UiComesAfter and JavassistPropertyStyle together to get the best of both worlds!

Runtime UI Generator: Metawidget v0.55

Version 0.55 of Metawidget, the runtime UI generator, is now available. This release includes:

Many thanks to Tom Bee for all his help testing this release!

As always, the best place to start is the Reference Documentation:


Your continued feedback is invaluable to us. Please download it and let us know what you think.

Wednesday, July 2, 2008

Metawidget and Filtering Properties

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically PropertyStyles are now set as object instances, not classes. Please download the latest documentation from http://metawidget.org

I was recently asked whether Metawidget can filter out properties during its inspection process. You may want to do this if, for example, your business classes all extend a common base class that has framework-specific properties that are not 'real' business model properties.

The answer is yes! Metawidget is very flexible in what it does (and does not) inspect.

Whilst you could roll your own ProperyTypeInspector, the convenience implementation BasePropertyTypeInspector - which all annotation-based inspectors extend - already supports pluggable PropertyStyles. The PropertyStyle interface allows fine-grained control over what is considered a 'property'. We use this for both Groovy support, and also StrutsActionFormPropertyStyle:

public class StrutsActionFormPropertyStyle extends JavaBeanPropertyStyle {

   protected String[] getExcludeNames() {
      return new String[] { "servlet", "servletWrapper", "multipartRequestHandler" };
   }
}

Here, we can see StrutsActionFormPropertyStyle excludes, for example, the property 'servletWrapper' which is a method defined by the Struts ActionForm base class (ActionForm.getServletWrapper).

We can also exclude based on subtype. From GroovyProperty:

   protected Class[] getExcludeTypes() {
      return new Class[] { Class.class, MetaClass.class };
   }

To filter your own base classes:

Step 1: Define a PropertyStyle

In most cases, it's easiest to extend JavaBeanPropertyStyle (see StrutsActionFormPropertyStyle above)

Step 2: Tell the Inspectors to use the PropertyStyle

If you're using inspector-config.xml:

<propertyTypeInspector xmlns="java:org.metawidget.inspector.propertytype"
   config="org.metawidget.inspector.impl.BasePropertyInspectorConfig">
   <propertyStyle>
      org.metawidget.inspector.impl.propertystyle.struts.StrutsActionFormPropertyStyle
   </propertyStyle>

</propertyTypeInspector>

If you're setting your Inspector programmatically:

BasePropertyInspectorConfig config = new BasePropertyInspectorConfig();
config.setPropertyStyle( StrutsActionFormPropertyStyle.class );
metawidget.setInspector( new PropertyTypeInspector( config ) );

And that's it!

Tuesday, June 24, 2008

Metawidget and Tooltips

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically you should now use a WidgetProcessor to call .setToolTipText. Please download the latest documentation from http://metawidget.org

I was recently asked whether Metawidget could 'add an annotation for field/methods to describe a field in the UI with a tooltip'. Here's how to add that:

Step 1: Write the Annotation

You can basically copy @UiLabel:

package com.myapp;

import java.lang.annotation.*;

@Retention( RetentionPolicy.RUNTIME )
@Target( { ElementType.FIELD, ElementType.METHOD } )
public @interface UiDescription {
   String value();
}

Step 2: Write an Inspector for the Annotation

Most of the work is done for you by BasePropertyInspector:

package com.myapp;

import java.util.*;
import org.metawidget.inspector.impl.*;
import org.metawidget.util.*;

public class DescriptionInspector extends BasePropertyInspector {
   public DescriptionInspector() {
      this( new BasePropertyInspectorConfig() );
   }

   public DescriptionInspector( BasePropertyInspectorConfig config ) {
      super( config );
   }

   @Override
   protected Map<String, String> inspect( Property property, Object toInspect )
      throws Exception {
      Map<String, String> attributes = CollectionUtils.newHashMap();
      UiDescription description = property.getAnnotation( UiDescription.class );

      if ( description != null )
         attributes.put( "description", description.value() );


      return attributes;
   }
}

Step 3: Extend the Metawidget to understand the Inspector

For this example, I'll extend SwingMetawidget:

package com.myapp;

import java.util.Map;
import javax.swing.JComponent;
import org.metawidget.swing.SwingMetawidget;

public class DescriptiveSwingMetawidget extends SwingMetawidget {
   @Override
   protected JComponent buildActiveWidget( Map attributes )
      throws Exception {
      JComponent component = super.buildActiveWidget( attributes );

      if ( component == null )
         return null;

      component.setToolTipText( attributes.get( "description" ));
      return component;
   }
}

Step 4: Annotate the Business Object

We're done! To test it, first annotate the business object. We'll reuse the business object from the Metawidget tutorial:

package com.myapp;

public class Person {
   @UiDescription( "The name of the person" )
   public String name;

   @UiDescription( "The age of the person" )
   public int age;

   @UiDescription( "Whether the person is retired" )
   public boolean retired;
}

Step 5: Use the Business Object

Now use the business object. Again, we'll reuse the Main class from the Metawidget tutorial:

package com.myapp;

import javax.swing.JFrame;

import org.metawidget.inspector.composite.*;
import org.metawidget.inspector.propertytype.*;

public class Main {
   public static void main( String[] args ) {
      DescriptiveSwingMetawidget metawidget = new DescriptiveSwingMetawidget();
      CompositeInspectorConfig config = new CompositeInspectorConfig();
      config.setInspectors( new PropertyTypeInspector(), new DescriptionInspector() );
      metawidget.setInspector( new CompositeInspector( config ) );
      metawidget.setToInspect( new Person() );

      JFrame frame = new JFrame();
      frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
      frame.getContentPane().add( metawidget );
      frame.setSize( 400, 210 );
      frame.setVisible( true );
   }
}

Run it! You'll see the usual Swing tutorial app, but this time with tooltips on all the fields.

Of course, this simple example has its problems. Most notably, you'd probably want some localization on the descriptions. Both @UiLabel and @UiSection do this, but that's for another blog!

Sunday, June 22, 2008

GWT and Metawidget Part 4: Over to you

A recent Metawidget bug report has highlighted I need better documentation around how to build your own GWT app. I will be putting this in the next release, but for now please note:
  • when building your app, you need both metawidget.jar and metawidget-gwt-client.jar in your compiler CLASSPATH
  • when deploying your app, you need metawidget.jar in your WEB-INF/lib and a reference to GwtRemoteInspectorImpl in your web.xml
  • you can see this in action in addressbook-gwt.war in the binary distribution
  • you may also find the example-gwt-addressbook Ant task in the source distribution's build.xml useful

Thanks to the anonymous bug reporter for highlighting this lack of documentation!

Friday, June 20, 2008

Metawidget and Resource Bundles

I was recently asked if I could 'give an example of how to get translated labels (from a resource bundle) in the JSF version' of Metawidget.

You can see a working example of this in the addressbook-faces.war included in the download (with tutorial here), but in this blog entry I'll focus specifically on translated labels.

Metawidget generates labels for widgets based on...
  • the uncamel-cased version of the property name (eg. 'Date of birth' for 'dateOfBirth')

  • the exact text specified in the @UiLabel annotation (or label XML attribute)

...if a resource bundle is specified, it also tries...
  • a bundle key based on the camel-cased version of the text specified in @UiLabel or label (eg. 'dateOfBirth' for 'Date of birth')

  • a bundle key based on the property name

That's a lot of combinations, I know! But the idea is you can develop your app first without a bundle, and Metawidget will use sensible defaults. Then you can add a bundle later and Metawidget will automatically adapt to using it.

To add a bundle, you can either add one globally in faces-config.xml...

<application>
   <message-bundle>com.myapp.Resources</message-bundle>
</application>

...or on the page...

<f:loadBundle basename="com.myapp.Resources" var="bundle"/>
   ...
<m:metawidget value="#{myBusinessObject}" bundle="#{bundle}"/>

...and that's it! The other supported Metawidgets (for Android, GWT, JSP, Spring, Struts, Swing, etc.) all do localization in a similar fashion, following the conventions of their particular platform.

Thursday, June 19, 2008

Metawidget and Name/Value Pairs

I was recently asked whether Metawidget 'covered the scenario where my object contains a list of properties (name/value pairs) stored in a collection'?

The answer is yes! Metawidget can read properties from almost any source. You don't need a physical Class. Metawidget can even combine properties from multiple sources (using CompositeInspector). With respect to name/value pairs in a collection:

Step 1: Write an Inspector

Write an Inspector suited to your particular architecture. Here's an example:

package com.myapp;

import static org.metawidget.inspector.InspectionResultConstants.*;
import java.util.Map;
import org.metawidget.inspector.iface.*;
import org.metawidget.util.*;
import org.w3c.dom.*;

public class MapInspector implements Inspector {
   private Map<String, Map<String, Class<?>>> mObjectProperties = CollectionUtils.newHashMap();

   public MapInspector() {
      // Some dummy data
      Map<String, Class<?>> personProperties = CollectionUtils.newLinkedHashMap();
      personProperties.put( "name", String.class );
      personProperties.put( "age", int.class );
      personProperties.put( "retired", boolean.class );

      mObjectProperties.put( "person", personProperties );
   }

   public String inspect( Object toInspect, String type, String... names )
      throws InspectorException {
      Map<String, Class<?>> properties = mObjectProperties.get( type );

      if ( properties == null )
         return null;

      try {
         Document document = XmlUtils.newDocument();
         Element elementRoot = document.createElementNS( NAMESPACE, ROOT );
         document.appendChild( elementRoot );

         Element elementEntity = document.createElementNS( NAMESPACE, ENTITY );
         elementEntity.setAttribute( TYPE, type );
         elementRoot.appendChild( elementEntity );

         for ( Map.Entry<String, Class<?>> entry : properties.entrySet() ) {
            Element element = document.createElementNS( NAMESPACE, PROPERTY );
            element.setAttribute( NAME, entry.getKey() );
            element.setAttribute( TYPE, entry.getValue().getName() );
            elementEntity.appendChild( element );
         }

         return XmlUtils.documentToString( document, false );
      }
      catch ( Exception e ) {
         throw InspectorException.newException( e );
      }
   }
}

Step 2: Use the Inspector

You can try MapInspector by updating the code from the Metawidget tutorial:

package com.myapp;

import javax.swing.*;
import org.metawidget.swing.SwingMetawidget;

public class Main {

   public static void main( String[] args ) {
      SwingMetawidget metawidget = new SwingMetawidget();
      metawidget.setInspector( new MapInspector() );
      metawidget.setPath( "person" );


      JFrame frame = new JFrame( "Metawidget Tutorial" );
      frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
      frame.getContentPane().add( metawidget );
      frame.setSize( 400, 210 );
      frame.setVisible( true );
   }
}

Running this will give you a UI driven by name/value pairs in a collection. And because Metawidget decouples its Inspectors from its Metawidgets, it can be equally applied to Spring, Struts, JSF, JSP, GWT, Android etc. for free!

Step 3: Change your Inspector

Of course, your particular take on name/value pairs may be different.

For example, you may not be storing the class in the 'value', you might be storing an Object instead. In that case you'll need to either use Object.getClass() as the type, or just return no type (in which case Metawidget will choose a textbox widget). Equally, you may be storing more than just the value - you may be storing whether the field is required, its maximum length etc. You'll need to add these as extra attributes to the XML elements you create.

Finally, you may want to think about how you're going from a Map to a piece of XML, and whether you can optimize that process. For example, where is the Map coming from? Wherever it is, can you have the Inspector get it from there directly?

Wednesday, June 18, 2008

Metawidget and SwingX

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically you should now use a WidgetBuilder to add support for third-party components. Please download the latest documentation from http://metawidget.org

There's been a bit of interest in whether Metawidget can use SwingX components instead of standard Swing ones. The answer is yes! Metawidget makes it easy to support third-party component libraries. Here's how:

Step 1: Derive your own SwingXMetawidget

Subclass SwingMetawidget and override its buildActiveWidget method to select SwingX components. For example:

package com.myapp.metawidget.swingx;

import static org.metawidget.inspector.InspectionResultConstants.*;
import java.awt.*;
import javax.swing.JComponent;
import org.jdesktop.swingx.JXDatePicker;
import org.metawidget.util.ClassUtils;

public class SwingXMetawidget extends SwingMetawidget {

   public JComponent buildActiveWidget( Map<String, String> attributes )
      throws Exception {

         String type = attributes.get( TYPE );

         if ( type != null ) {
            Class<?> clazz = ClassUtils.niceForName( type );

            // Use SwingX JXDatePicker
            if ( Date.class.isAssignableFrom( clazz ) )
                  return new JXDatePicker();

      }

      // Not for SwingX
      return super.buildActiveWidget( attributes );
   }

   protected String getValueProperty( Component component ) {
      if ( component instanceof JXDatePicker )
         return "date";


      return super.getValueProperty( component );
   }
}

That's it! You'll get all the other Metawidget benefits (like layouts, internationalization, etc.) for free. Note that overriding getValueProperty is optional, but necessary if you want automatic two-way data binding between the JXDatePicker and your business objects.

Step 2: Use SwingXMetawidget in your Application

To try it, download the Metawidget source and update the Swing Address Book example's ContactDialog to say...

final SwingMetawidget metawidget = new SwingXMetawidget();

...(on about line 135). Run the example, double click on Homer Simpson and you'll see the SwingX JXDatePicker component used for the 'Date of Birth' field (previously it was just a JTextField, because vanilla Swing doesn't have a Date picker):

Tuesday, June 17, 2008

GWT and Metawidget Part 3: Binding

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically bindings are now set using .addWidgetProcessor. Please download the latest documentation from http://metawidget.org

The latest release of Metawidget adds supports for Google Web Toolkit (GWT) 1.5. This series of blogs explores the challenges that had to be overcome to acheive this.

Two Way Binding

Almost all Web frameworks support some form of automatic two-way binding between Web pages and domain objects. Some supply sophisticated expression languages (Java Server Faces), others straight property name mapping (Struts), but most supply something.

Except GWT.

To be fair, Google are planning to add this feature in an upcoming release - but it's not there in 1.5 just yet. One of the main stumbling blocks is that most binding implementations use reflection, and JavaScript doesn't support reflection.

As an interim solution, Metawidget supplies SimpleBinding. Metawidget's binding implementations are pluggable, so we can swap in 'real' GWT binding one day, but for now SimpleBinding gets you most of the way: a simple two-way binding, including converters.

But! How do we solve the reflection problem?

As with the last blog entry, Generators are our friend. SimpleBinding uses SimpleBindingAdapters, and comes with a SimpleBindingAdapterGenerator that can generate SimpleBindingAdapters automatically for your business classes.

A SimpleBindingAdapter is capable of 'reflecting' every property (and even sub-property) of a business class by pre-generating code that automatically traverses getters and calls setters. In effect, it statically generates codes that looks like this:

if ( "address".equals( property[0] )) {
   Address address = contact.getAddress();
   if ( property.length == 1 ) return address;

   // Address properties

   if ( "street".equals( property[1] )) {
      if ( property.length > 2 )
         throw new RuntimeException( "Cannot reflect into property 'street." + property[2] + "'" );
      return address.getStreet();
   }

To stop the tree of possible properties getting too large, it restricts itself to only classes within the same package or sub-package.

To use SimpleBinding in your code, add the following to your application-name.gwt.xml file:

<generate-with class="org.metawidget.gwt.generator.binding.simple.SimpleBindingAdapterGenerator">
   <when-type-assignable class="org.metawidget.example.shared.addressbook.model.Contact"/>
</generate-with>

...and in your application code add...

metawidget.setBindingClass( SimpleBinding.class );
SimpleBindingAdapter<Contact> adapter = (SimpleBindingAdapter<Contact>) GWT.create( Contact.class );
SimpleBinding.registerAdapter( Contact.class, adapter );

How does this work in practice? See for yourself! The Metawidget download includes a pre-built sample application, addressbook-gwt.war, that showcases a GwtMetawidget using two-way bindings in the UI. It's covered in detail in the reference guide.

GWT and Metawidget Part 2: Pluggability

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically Layouts are now set as an object instance, not as a class. Please download the latest documentation from http://metawidget.org

The latest release of Metawidget adds supports for Google Web Toolkit (GWT) 1.5. This series of blogs explores the challenges that had to be overcome to acheive this.

Pluggability

Pluggability is everywhere in Metawidget: pluggable inspectors, pluggable layout managers, pluggable binding implementations, etc. etc. The usual way this is acheived is through code like...

metawidget.setLayoutClass( TableLayout.class );

...which, somewhere behind the scenes, ends up calling...

layoutClass.newInstance();

GWT, however, is a very different kind of Web framework: it compiles Java to JavaScript, and JavaScript doesn't support newInstance.

But! Using GwtMetawidget, you can plug in different implementations by calling setLayout (and also setBinding, setInspector, etc.)! How is this possible?

GWT supplies a powerful concept called Generators. With a bit of work, you can use Generators to do all sorts of things, including scanning a project's available classes and generating fragments of code that be inserted at runtime.

For example, you can scan all the classes that implement Layout, and then generate a function that says:

if ( givenClass.equals( TableLayout.class )) return new TableLayout();

What's really great is you can push all this into the framework (in our case, Metawidget) so that it becomes 'magic' to the application code.

How does this work in practice? See for yourself! The Metawidget download includes a pre-built sample application, addressbook-gwt.war, that showcases a GwtMetawidget using pluggable bindings at runtime to generate the UI. It's covered in detail in the reference guide.

GWT and Metawidget Part 1: Reflection and Inspecting Annotations

The latest release of Metawidget adds supports for Google Web Toolkit (GWT) 1.5. This series of blogs explores the challenges that had to be overcome to acheive this.

Reflection and Inspecting Annotations

Whilst Metawidget does not require reflection and annotations (eg. you can just use XmlInspector), it's certainly a lot more powerful with them. By using reflection and inspecting the existing annotations on your business objects (you know, the JPA ones, the Hibernate Validator ones, etc.), Metawidget can automatically generate accurate UIs.

However, GWT is a very different kind of Web framework because it pre-compiles Java code to JavaScript. Java and JavaScript have similarities, but two areas they differ greatly is that JavaScript has no support for reflection or annotations.

But! Using GwtMetawidget, you can take your business object, reflect and inspect it, and generate your UI! How is this possible?

Well, GwtMetawidget showcases the power of Metawidget's separate Inspector/renderer architecture. Metawidget comes with a range of different inspectors targeting different aspects of back-end architectures (JPA annotations, Hibernate Validator annotations, JavaBean getters/setters etc). Each Inspector returns a piece of XML, and you can use CompositeInspector to compile them all together into one.

Because of this approach, inspection can be performed anywhere and the result passed somewhere else for rendering:

The process becomes:

  • instantiate the business object on the client-side as normal (ie. as JavaScript)
  • give your business object to GwtMetawidget (a client-side, JavaScript GWT Widget)
  • GwtMetawidget uses AJAX to pass the business object to the server
  • the server, using Java, runs all the Inspectors (including reflection and annotations)
  • the server returns the inspection results as an XML document
  • GwtMetawidget uses JavaScript to render the HTML widgets

How does this work in practice? See for yourself! The Metawidget download includes a pre-built sample application, addressbook-gwt.war, that showcases a GwtMetawidget using reflection and inspecting annotations at runtime to generate the UI. It's covered in detail in the reference guide.

Monday, June 16, 2008

Metawidget gets Groovy

Update: the APIs shown in this blog entry have changed slightly in newer releases of Metawidget. Specifically <propertystyle> now takes a PropertyStyle instance, not a class name. Please download the latest documentation from http://metawidget.org

The latest release of Metawidget adds supports for Groovy. This means Metawidget's Inspectors can now inspect GroovyBean properties for types and annotations.

GroovyBean properties are similar to JavaBean's getters/setters. Indeed, at compile time, GroovyBean properties try to 'look' like JavaBean properties by automatically generating a private member variable and a public getter/setter.

So, if your Groovy code says this...

class Booking {
   @NotNull
   String creditCard;
}

...at compile-time Groovy generates this:

class Booking {
   @NotNull
   private String mCreditCard;

   public String getCreditCard() {
      return mCreditCard;
   }

   public void setCreditCard(String creditCard) {
      mCreditCard = creditCard;
   }
}

Notice, however, that the annotation stays on the private member variable - it does not get applied to the getter. There are good reasons for this, but it means Metawidget's native JavaBeanPropertyStyle cannot be used to find those annotations.

So, instead, Metawidget now has a pluggable GroovyPropertyStyle that understands Groovy properties natively. To use it, you just need to update your inspector-config.xml...

<propertytypeinspector xmlns="java:org.metawidget.inspector.propertytype"
   config="org.metawidget.inspector.impl.BasePropertyInspectorConfig">
   <propertystyle>org.metawidget.inspector.impl.propertystyle.groovy.GroovyPropertyStyle</propertystyle>
</propertytypeinspector>

How does this work in practice? See for yourself! The Metawidget download includes a Seam Groovy Booking sample application, that showcases using Metawidget with Groovy. It's covered in detail in the reference guide.

Declarative User Interface Generator: Metawidget v0.5

Version 0.5 of Metawidget, the declarative user interface generator, is now available. This release includes:

To accomodate this, there have been some minor API changes:

  • JavaBeanInspector is now called PropertyTypeInspector
  • All classes that were called AbstractXXX are now named BaseXXX

All of the examples have been updated to the new API. As always, the best place to start is the Reference Documentation:

http://metawidget.org/doc/reference/en/pdf/metawidget.pdf

Your continued feedback is invaluable to us. Please download it and let us know what you think.

Sunday, June 15, 2008

Bulletproof Backups with the ReadyNAS Duo

Update: I wrote up my findings, four years on, in this new blog post!

I just invested in a ReadyNAS Duo, which is a mean-looking little device:


It's small (smaller than a shoebox), quiet (about as loud as a fridge), got terabytes of storage and can run autonomously doing all kinds of things (FTPing files, hosting web sites, downloading BitTorrents, etc.).

It's so flexible infact, there seems to be a lot of confusion on the forums around which strategy to adopt to make best use of it. So I thought I'd write this quick blog on how I use it as a really good backup device.

Step 1: Don't Use It

Well, don't use it as your main hard disk drive (HDD) anyway. It's tempting to try and move all your important files onto it, so that if your PC dies you can just hook up a different PC and off you go. But networks are much, much slower than local HDDs and it just isn't practical. Even e-mail programs run sluggishly if you're serving their EXE over the network.

Instead, get a good mirroring program like MirrorFolder, and have it mirror your HDD to the ReadyNAS frequently (even in real-time, if you like).

Step 2: Rely on it

Expect your PC to fail. Create a separate partition on your local HDD and call it something distant from C: (like N:). Then move all your important programs to it and configure them to be running off N: drive. This can be a tedious process, but once it's done your entire environment is relative to N:, which means as (and when) your PC fails, you can hook up another PC, map drive N: to the ReadyNAS and be up and running again nearly instantly.

Of course, it'll be slow (see Step 1), so ultimately you'll want to copy everything back to the 'mirrored partition' model on that new PC, but if your old PC dies and you need to continue working immediately for, say, the rest of the day it should suffice.

Step 3: Trick the software

Oddly, the ReadyNas Duo's weak spot is its backup software. You can't do weekly backups, or monthly backups, you can't filter out file types etc. etc.

Most suggestions on the forums are to work around this using some 'real' backup software instead, but that's silly because then it ties up your PC again while doing the backup. Instead:
  1. configure MirrorFolder (or equivalent) to only mirror the files you want to backup
  2. configure the ReadyNAS' built-in backup software to copy everything from the mirror into the backup share (this bit doesn't involve your PC, so you can run it overnight)
  3. set up different backup jobs, one for each day of the week, that backs up the mirror to different folders each day. You now have a rolling seven day backup
  4. create another backup job that, on Saturday, takes Sunday's backup and copies it to yet another folder (called, say 'Last Sunday')
  5. create yet another backup job that, on Friday, takes 'Last Sunday's backup and copies it to yet another folder (called, say 'Sunday Before Last'). Keep doing this so that you get monthly backups

Step 4: Trust nothing

Of course, even though your ReadyNAS is a secure backup of your PC, if you lose both at the same time you're still screwed. I'd recommend keeping the ReadyNAS in a separate part of the house to your PC, so that it's not lost in the event of a localized fire. But if the entire house burns to the ground, that's no help. Some of the forum backup strategies say 'buy another NAS' but there's a much nicer way:

The ReadyNAS Duo has 'swappable RAID', whereby you can swap one of the HDDs and the ReadyNAS will resync it. This feature is meant for when one of the HDDs is about to fail.

But you can also use it for off-site backups!

Invest in a third HDD and NAS drive tray (yes, you buy them separately if you hunt about a bit - the ones for the ReadyNAS NV+ are compatible). Then, on a weekly/monthly basis, swap one of the drives. Because you buy a third tray, you can leave the HDD screwed into the tray, so swapping takes very little time.Take the HDD you took out and keep it off-site. Now, even if your house burns down, you're covered!

Update - I've been advised there are problems with this style of swapping:

  1. Apparently both the SATA connectors on the drives and the ones inside the ReadyNAS are quite fragile, and likely to break with repeated swapping.
  2. If the drive is being written to as you swap it, those files might not be written correctly. Best to power the ReadyNAS down before doing the swap.

Instead, you can buy a USB enclosure for your extra HDD and backup over USB. Two things to note with this approach:

  1. If your USB enclosure is anything like mine, you have to unscrew it to put the HDD in. When you do this, you get to see just how flimsy the SATA connectors are!
  2. This is not a good solution if you have a serious amount of data. Re-syncing a 500GB HDD with RAID-X takes about an hour. With USB it'd take days.

Saturday, June 14, 2008

Awesome Sequence Diagram Generator

Just a quick blog about this great tool...

...it makes generating sequence diagrams a breeze, and is completely free! You just type your sequence in as text (no fiddly dragging and dropping and aligning) and it works out what the equivalent sequence diagram should look like. Impressive!
I'll be using this for the next release of Metawidget.

Friday, May 30, 2008

GWT Dictionary and Unit Tests

Much like Firing onClickListeners in GWT Unit Tests, unit testing a GWT Dictionary is possible, but it is neither:
  • intuitive

  • documented anywhere at all (that I could find)

The problem is...

Dictionary.getDictionary( "bundle" );

...requires a JavaScript-level variable bundle to be declared on your 'host HTML page'. When the GWT application is running normally, the 'host HTML page' is the index.html page. However, when running unit tests, there is no host HTML page, so where to define that JavaScript-level variable?

The answer is in those tricky JSNI methods again. Just do...

public class MyTest extends GWTTestCase {

      public void testSomething() {
         prepareBundle();
         ...your tests here...
      }

      ...your other tests here...

      native void prepareBundle() {
      /*-{
         $wnd["bundle"] = {
            "dateOfBirth": "Date of Birth",
            "surname": "Surname"
         };
      }-*/;

...and use the special $wnd variable to initialize a JavaScript variable bundle prior to running your tests.

Hope that helps somebody. This is going to be in the upcoming release of Metawidget.

Friday, May 16, 2008

Firing onClickListeners in GWT Unit Tests

Firing event handlers, such as onClickListener, from GWT Unit Tests is possible, but it is neither:
  • intuitive
  • well documented
You can't just do...

myButton.click();

...because that clicks the button without firing any listeners. Instead, within your GWTTestCase-derived unit test, put a method like this:

private native void fireClickListeners( FocusWidget w )
/*-{
  w.@com.google.gwt.user.client.ui.FocusWidget::fireClickListeners()();
}-*/;

It looks funny I know. Make sure you:
  • include the native keyword, which the GWT compiler understands to mean JavaScript Native Interface (JSNI), rather than Java Native Interface (JNI)

  • include the starting and ending comment delimiters, because the code inside the function is actually JavaScript code, which
    means nothing to the Java compiler

You can then call this method just as you would a normal method:

fireClickListeners( myButton );

Hope that helps somebody. I'm using this in the upcoming release of Metawidget.