Thursday, July 22, 2010
Griffon Validation Plugin 0.5 Released
- Download Griffon 0.9 from http://griffon.codehaus.org/Download
- Run "griffon upgrade" under your application folder
Other than the core upgrade, another somewhat important change in this release is now Validation plugin officially depends on i18n plugin, so once you upgrade to v0.5 Griffon will automatically install i18n (currently 0.2) into your application if its not already installed yet. And as usual please feel free to contact me for any bugs or feature requests.
Labels: griffon, plugin, release note, validation
Tuesday, June 22, 2010
Griffon Validation Plugin 0.4 Release
1. @Validatable AST Transformation
In the previous version user can enhance regular Groovy class in their Griffon application manually using:
ValidationEnhancer.enhance(object)
With 0.4 release now this manual process can be replace by the convenient @Validatable annotation thanks to Groovy AST transformation. Any class now annotated with @Validatable will be automatically synthesized with validation capability.
import net.sourceforge.gvalidation.annotation.Validatable
@Validatable
class AnnotatedModel {
String id
String email = " "
static constraints = {
id(nullable: false)
email(email: true)
}
}
Other than the fact that annotated class is enhanced during build-time instead of run-time as for the models and manually enhanced objects, they behave identically from user's point-of-view.
2. Bindable errors
In this release the dynamic errors field in models and Validatable objects has been enhanced to be Bindable, hence standard SwingBuilder binding can be utilized to tie errors automatically to a component. This is particularly handy when building error notification component to display error message for the user. For example with this new capability now you can simple bind the error to the build-in ErrorMessagePanel without manually synchronizing it after each validation.
container(new ErrorMessagePanel(messageSource),
id: 'errorMessagePanel', constraints: NORTH,
errors: bind(source: model, 'errors'))
3. beforeValidation callback
Inspired by Rails before_validation callback, now GValidation provides a similar pre-validation callback to give model developer a chance to manipulate data right before validation. Here is an example how this kind of callback can be used:
class ServerModel {
@Bindable String serverName
@Bindable int port
@Bindable String stringForm
def beforeValidation = {
setStringForm "${serverName}:${port}"
}
….
}
For more information please check out the GValidation Wiki Page. As usual your feedback and comment are always welcome.
Labels: griffon, plugin, release, validation
Wednesday, June 02, 2010
How to support custom artifact type in Griffon plugin
Step 1 - Handle your artifact
To support a new artifact type you have to tell the Griffon core about the artifact type first. You can achieve this by implementing your own ArtifactHandler, for most of the common cases extending from ArtifactHandlerAdapter will be enough otherwise you can implement the interface manually. Here is what it looks like for the Constraint artifact type:
class ConstraintArtifactHandler extends ArtifactHandlerAdapter {
public static final String TYPE = "constraint"
public static final String TRAILING = "Constraint"
ConstraintArtifactHandler() {
super(TYPE)
}
}
Step 2 - Register your artifact
As shown above, if you have experience working with Grails artefact support, you will notice the handler implementation is almost identical in Griffon, however things starting to differ from this point forward. Now you have the handler implemented, next thing is to register it with Griffon core. This is best achieved during initialization phase in your addon. Open the [PluginName]GriffonAddon.groovy file add the following callback if its not already there:
def addonInit = {app ->
....
app.artifactManager.registerArtifactHandler(new ConstraintArtifactHandler())
....
}
Step 3 - Find your artifacts
Now we have the new artifact type registered, next step is to tell Griffon where to find the artifacts. Ever wonder how Griffon knows to look under griffon-app/models for model classes? This is what we are going to do in this step. This is also where Griffon custom artifact support truly differs from Grails. Instead of handling it at run-time, Griffon chooses to handle this at build time, so to achieve this you need to tap into the Griffon event model. Open the _Events.groovy script and implement the following event listener:
eventCollectArtifacts = { artifactsInfo ->
if(!artifactsInfo.find{ it.type == 'constraint' }) {
artifactsInfo << [type: 'constraint', path: 'constraints', suffix: 'Constraint']
}
}
This event listener will tell Griffon to look for anything under griffon-app/constraints folder with suffix 'Constraint' and register them as constraint artifacts.
Step 4 - Measure your artifacts
Now we pretty much have the basic bolts and nuts in place, its time to make our newly found artifact type to be more integrated with Griffon as any other first class artifact types do. One of the nice feature of Griffon is the stats command, it gives you an instant overview of how big your app is in terms of how many files and Line of Code per type including artifacts. Won't it be nice to have it also display the metrics about our own custom artifacts? fortunately its actually pretty easy to achieve in Griffon, similar to the previous step we will add another listener to the _Events script.
eventStatsStart = { pathToInfo ->
if(!pathToInfo.find{ it.path == 'constraints'} ) {
pathToInfo << [name: 'Constraints', path: 'constraints', filetype:['.groovy','.java']]
}
}
Griffon event model is a very powerful concept, usually when I am not sure how to do something funky in Griffon this is the first place I look.
Step 5 - Automate your artifacts
One of big selling point of the next generation Rails-like RIA framework is the ability to create any artifact simply by using one of the built-in command, for example grails create-controller or griffon create-mvc. To make our new artifact type a true first-class citizen of Griffon, of course we need all the bells and whistles. To add a new command to Griffon, you need to create a new Groovy script under scripts folder:
CreateConstraint.groovy
target('default': "Creates a new constraint") {
depends(checkVersion, parseArguments)
promptForName(type: "Constraint")
def name = argsMap["params"][0]
createArtifact(name: name, suffix: "Constraint", type: "Constraint", path: "griffon-app/constraints")
createUnitTest(name: name, suffix: "Constraint")
}
Like other convention-over-configuration framework, Griffon relies heavily on simple naming conventions, so in the script make sure you naming everything consistent to avoid unnecessary complexity. This script will create artifact for the type of Constriant and related unit test case, as you can see it will be a simple matter to create integration test case if need be.
Now with the command in place, you can finally provide the template for the new artifact being created. Again naming convention is being used to determine where to find template file, for our example the template file should be placed under src/templates/artifacts and named Constraint.groovy:
@artifact.package@class @artifact.name@ {
def validate(propertyValue, bean, parameter) {
// insert your custom constraint logic
}
}
Phew, now finally we are done. This is a long post and as you can see a lot of plumbing; this is exactly why currently there are some discussion going on within Griffon dev mail list to provide declaration based custom artifact support either using Grails style or Groovy AST transformation, so stay tuned for future updates on this topic.
I also need to thank Andres Almiray for pointing me to the right direction when I first started looking into this topic.
Labels: addon, custom artifact, griffon, plugin
Wednesday, May 26, 2010
Griffon Validation Plugin 0.3 Release
1.Custom Constraint Support
This is probably the biggest improvement introduced in this release. Inspired by Grails' Custom Constraint plugin, once upgraded GValidation will introduce a new type of artifact to your Griffon application - Constraint.
In previous version GValidation allows you to define a custom validator using a closure just like in Grails:
// Simple custom validator
even( validator: {
return (it % 2) == 0
})
However this kind of closure based simple validator is hard to reuse therefore you will have to rewrite them every single time, a major inconvenience and a violation of the DRY principle. In version 0.3 now you can create a top level reusable custom constraint by using the following script:
griffon create-constraint [package].[constraint-name]A Groovy class will be created under griffon-app/constraints folder to allow you to define your custom validation logic, a typical custom constraint looks like this:
class MagicConstraint {
/**
* Generated message
*
* @param propertyValue value of the property to be validated
* @param bean object owner of the property
* @param parameter configuration parameter for the constraint
* @return true if validation passes otherwise false
*/
def validate(propertyValue, bean, parameter) {
if (!parameter)
return true
return propertyValue == 42
}
}
Once created a custom constraint pretty much behaves exactly like a built-in constraint, you can easily invoke them in your model by following the simple naming convention, with the above example you can apply the constraint on any field in your model by using the following declaration:
class DemoModel{
….
@Bindable int magicNumber
static constraints = {
….
magicNumber(magic: true)
….
}
2. Selective ValidationOriginally proposed by Andres Almiray, GValidation now offers capability to perform validation on only a selected number of fields in the model instead of all. Here is a typical single field validation usage scenario:
model.validate('name')
...
if(model.hasErrors()){
// notify user
...
}
You can also perform selective validation on a list of fields:model.validate(['name', 'email'])3. Default Catch-All Error Message Code
...
if(model.hasErrors()){
// notify user
...
}
This is a minor enhancement however a great time saver for someone who has to perform a large number of validation in their app. In previous version validation plugin only generates model specific error message code:
[modelclass].[field].[validator].messageNow for every built-in and custom validator the plugin will also generate a default error message code additionally:
default.[validator].message
You can retrieve the error code and default error code from the Error object using the following fields respectively:
error.errorCode
error.defaultErrorCode
For a complete guide on the plugin, please check out the Wiki page.
Labels: griffon, plugin, validation
Monday, April 19, 2010
Quote of the Day
Most teams purporting to be doing agile software development are not applying the level of technical rigor necessary to succeed at it. Most "agile" team have actually only adopted Scrum's project-management practice and have failed to effectively adopt "the hard disciplines" like test-driven development, refactoring, pair programming, simple design, and continuous integration.
Friday, April 16, 2010
Use controller action via listeners in Griffon view (Updated)
In Griffon view you can supply a predefined action to a component such as JButton to invoke a controller action in a breeze. The following code snippet demonstrate how it is done in Griffon:
actions {
action(id: "quitAction",
name: messageSource.getMessage('menuItem.exit.caption'),
mnemonic: "x",
closure: controller.quit)
}
...
menuBar {
menu(messageSource.getMessage('menu.file.caption')) {
menuItem(quitAction)
}
}
...
From Andres Almiray:
The main difference between all examples is that the first assigns an instance of javax.swing.Action to the node's value. The builder knows that it can configure a button/menuItem/etc out of an Action so it does it.
When it comes to listener and event handling, one would expect a similar pattern applies; for example according to Swing builder documentation mousePressed event exists on JComponent level so one would hope the following code can bind a controller action to an mousePressed event.
actions {
action(id: "nodeSelectionAction",
closure: controller.selectNode)
}
list(id:'nodeList', model: model.serverListModel, eventPressed: nodeSelectionAction)
From Andres Almiray:
The second example does not work because it attempts to assign an instance of javax.swing.Action as the value of the menuPressed property, which has to be a MouseListener. That's why it breaks (although the error text may be misleading).
Unfortunately you will get No such property: mousePressed for class: javax.swing.JList error message. Instead the correct way to do this is by using the closure instead of an Action since mousePressed expects a listener. Groovy closure declared here will be converted to a listener automatically:
From Andres Almiray:
list(id:'nodeList', model: model.serverListModel, mousePressed: controller.selectNode)
The third example works because it assigns a closure as the value of the mousePressed property. Groovy will generate under the covers a proxy of a MouseListener that uses that closure as the implementation of said proxy's mousePressed method.
Hope this post will save some investigation time for someone who is new to Griffon and Swing builder.
Go Griffon!
Labels: griffon, groovy, swing, swing builder
Tuesday, April 06, 2010
GValidation 0.2 release
Apache Commons Lang 2.5
Apache Commons Validator 1.3.1
Jakarta ORO 2.0.8
To upgrade your application to the new plugin version please uninstall validation plugin first:
griffon uninstall-plugin validation
griffon install-plugin validation
I have also updated the Wiki with a quick tutorial showing how validation can be utilized in a simple but somewhat telling example. The same tutorial demo application binary can also be downloaded from the project files page.
Labels: griffon, plugin, release, validation

