Showing posts with label groovy. Show all posts
Showing posts with label groovy. Show all posts

Thursday, November 05, 2009

Griffon Plugins and Addons

In this post, I'm going to talk a bit about Griffon plugins and addons--what they are, why they're useful, and how you can create your own.  As an example, I'll walk through the steps used to create the recently released Griffon Mail Plugin.

What are Plugins and Addons?

  • Plugins provide a mechanism to extend your Griffon application with new functionality at build-time.  They are commonly used to integrate external libraries, add new builders, and support testing tools.  The full list of Griffon plugins is available here.
  • Addons are a new feature in Griffon 0.2 that provide mechanism to extend your Griffon application with new functionality at run-time.  Addons can add items to builders, add MVC groups, and add/respond to runtime events.  An example of this is the Guice plugin, which also bundles an addon that starts up the Guice framework and injects services into your controllers as they are created.  Another example is the REST plugin which uses and addon to add new methods to controllers as they are created.
Plugins and Addons are conceptually very similar.  Both are about adding new functionality and you will often see plugins and addons on working hand in hand.

Creating your own Plugins and Addons
Creating your own Griffon plugins and addons is not too difficult.  We'll walk through the process by re-creating the Griffon mail plugin.  So without further ado, lets get started:

Step 1: Create the plugin
griffon create-plugin mail

Step 2: Edit the plugin metadata
cd mail
edit MailGriffonPlugin.groovy which Griffon created for you:
class MailGriffonPlugin {
    def version = 0.1
    def canBeGlobal = false
    def dependsOn = [:]

    // TODO Fill in your own info
    def author = "Josh Reed"
    def authorEmail = "jareed@andrill.org"
    def title = "Send email from your Griffon app"
    def description = 'Send email from your Griffon app'

    // URL to the plugin's documentation
    def documentation = "http://griffon.codehaus.org/Mail+Plugin"
}

Step 3: Add our plugin functionality
What you do here will depend on your plugin, but in this case we need to add the mail.jar file from the JavaMail API site to the plugins lib/ directory.  When the user installs our plugin, this jar file will be added to the application's classpath.

The JavaMail API requires a bit of work to send emails, so we'll also add a helper class that hides this code behind a single static method call.

Step 4: Package your plugin so you can test it
When you're done with your plugin, you will want to test it out.  To do this:
griffon package-plugin
This will compile your plugin and package it as a zip file called griffon-mail-0.1.zip.  You can then install this plugin in a regular Griffon application with a:
griffon install-plugin griffon-mail-0.1.zip

For the mail plugin, we can send an email by calling our helper class:
MailService.sendMail(mailhost: 'smtp.server.com', to: 'jareed@andrill.org'...)
from our controller or wherever.  This is OK but we can do one better by creating an Addon that injects the sendMail method into every controller.

Step 5: Creating an Addon
Head back to our plugin directory and issue a:
griffon create-addon mail
this will create a MailGriffonAddon.groovy file.
(Note: if you try this with 0.2 you may run into an error about 'createMVC'  This is a bug that has been fixed, but you can fix it yourself by editing your $GRIFFON_HOME/scripts/CreateAddon.groovy file.  The last line should say 'createAddon' instead of 'createMVC')

This is where we do our runtime magic:
import griffon.util.IGriffonApplication

class MailGriffonAddon {
    private IGriffonApplication application
 
    // add ourselves as a listener so we can respond to events
    def addonInit = { app ->
        application = app
        app.addApplicationEventListener(this)
    }
 
    // inject the 'sendMail' into our 
    def onNewInstance = { klass, type, instance ->
        def types = application.config.griffon?.mail?.injectInto ?: ["controller"]
        if (!types.contains(type)) return
        instance.metaClass.sendMail = { Map args -> MailService.sendMail(args)}
    }
}

With this done, we can: griffon package-plugin and install the plugin into our test app: griffon install-plugin griffon-mail-0.1.zip
With the addon in place, we can reference the sendMail() method directly on our controller.

Step 6: Release the plugin
If you have write access to the Griffon Subversion, you can release your plugin with a:
griffon release-plugin
If you don't have write access, ask on the griffon-dev list and someone can help you out.

I hope this demystifies the plugin and addon building process.

Wednesday, October 14, 2009

Multi-Document Griffon Applications

In this post we're going to build the skeleton of a multi-document (tabbed) Griffon application.  Tabbed interfaces are extremely common.  You're probably even viewing this in a web browser with a few open tabs as we speak. We'll be implementing the document-handling logic, so all you will need to do is add your own application-specific logic.

Let's dive in by creating a new Griffon application and creating a Document MVC group:
griffon create-app MultiDocumentExample
cd MultiDocumentExample
griffon create-mvc Document

In our application model, MultiDocumentExampleModel.groovy, we need to add some properties to keep track of open and active documents. We also need a separate 'state' class (more on that later):
import groovy.beans.Bindable

class MultiDocumentExampleModel {
    @Bindable Map activeDocument = null
    List openDocuments = []
    DocumentState state = new DocumentState()
}

@Bindable class DocumentState {
    boolean isDirty = false
}

Next up is the view: MultiDocumentExampleView.groovy. For this minimal example, we'll define some common actions and a tabbed pane for displaying the documents, but you can customize it to suit your application:
actions {
    action(
        id: 'newAction', 
        name:'New', 
        accelerator: shortcut('N'), 
        closure: controller.newAction
    )
    action(
        id: 'openAction', 
        name:'Open', 
        accelerator: shortcut('O'), 
        closure: controller.openAction
    )
    action(
        id: 'closeAction', 
        name:'Close', 
        accelerator: shortcut('W'), 
        closure: controller.closeAction, 
        enabled: bind { model.activeDocument != null }
    )
    action(
        id: 'saveAction', 
        name:'Save', 
        accelerator: shortcut('S'), 
        closure: controller.saveAction, 
        enabled: bind { model.state.isDirty }
    )
}

application(title: 'Multiple Document Example',
    size:[800,600], 
    //pack:true,
    //location:[50,50],
    locationByPlatform:true,
    iconImage: imageIcon('/griffon-icon-48x48.png').image,
    iconImages: [imageIcon('/griffon-icon-48x48.png').image,
        imageIcon('/griffon-icon-32x32.png').image,
        imageIcon('/griffon-icon-16x16.png').image],
    defaultCloseOperation: 0,
    windowClosing: { evt -> if (controller.canClose()) { app.shutdown() } }
) {
    menuBar(id: 'menuBar') {
        menu(text: 'File', mnemonic: 'F') {
            menuItem(newAction)
            menuItem(openAction)
            menuItem(closeAction)
            menuItem(saveAction)
        }
    }
 
    tabbedPane(id: 'documents', stateChanged: { evt -> 
        controller.activeDocumentChanged() 
    })
}

If you look close, you'll see I'm using the window closing trick I blogged awhile ago. The last piece of the puzzle is the controller: MultiDocumentExampleController.groovy. This is where we do the heavy lifting.
class MultiDocumentExampleController {
    int count = 0  // not strictly required
    def model
    def view

    void mvcGroupInit(Map args) {}

    void activeDocumentChanged() {
        // de-activate the existing active document
        if (model.activeDocument) { 
            model.activeDocument.controller.deactivate() 
        }

        // figure out the new active document
        int index = view.documents.selectedIndex
        model.activeDocument = index == -1 ? null : model.openDocuments[index]
        if (model.activeDocument) { 
            model.activeDocument.controller.activate(model.state) 
        }
    }
 
    boolean canClose() {
        return model.openDocuments.inject(true) { flag, doc -> 
            if (flag) flag &= doc.controller.close() }
    }

    def newAction = { evt = null ->
        // TODO: use an id that makes sense for your application, like a file name
        String id = "Document " + (count++) 
  
        def document = buildMVCGroup('Document', id, 
            tabs: view.documents, id: id, name: id /* TODO pass other args */)
        if (document.controller.open()) {
            model.openDocuments << document
            view.documents.addTab(document.model.name, document.view.root)
            view.documents.selectedIndex = view.documents.tabCount - 1
        } else {
            destroyMVCGroup(id)
        }
    }
 
    def openAction = { evt = null ->
        // TODO: pop up a open file dialog or whatever makes sense

        // TODO: use an id that makes sense for your application, like a file name
        String id = "Document" + (count++)

        // check to see if the document is already open
        def open = model.openDocuments.find { it.model.id == id }
        if (open) {
            view.documents.selectedIndex = model.openDocuments.indexOf(open)
        } else {
            def document = buildMVCGroup('Document', id, 
                tabs: view.documents, id: id, name: id /* TODO pass other args */)
            if (document.controller.open()) {
                model.openDocuments << document
                view.documents.addTab(document.model.name, document.view.root)
                view.documents.selectedIndex = view.documents.tabCount - 1
            } else {
                destroyMVCGroup(id)
            }
        }
    }
 
    def saveAction = { evt = null ->
        model.activeDocument.controller.save()
    }
 
    def closeAction = { evt = null ->
        if (model.activeDocument.controller.close()) {
            int index = model.openDocuments.indexOf(model.activeDocument)
            model.openDocuments.remove(index)
            view.documents.removeTabAt(index)
        }
    }
}

There's a fair amount of code but it's all pretty straightforward.  The only thing that warrants further discussion is activeDocumentChanged().  This method is called whenever the active tab in the tabbed pane is changed.  In it, we deactivate() the previously active document and then activate() the new document.  When activating, we pass in the state object I mentioned earlier.  The purpose of the state object is to allow us to use bindings that depend on the active document.  For example, we really only want the save action to be enabled when we have a document open and the document is dirty.  We can't bind directly to the active document's model because as soon as we open or switch to a new document, the binding is no longer correct.  We can, however, bind to the state object and then sync the document's state in the activate() method (or other methods).

The implementation of the Document MVC group is straightforward:
DocumentModel.groovy
import groovy.beans.Bindable

@Bindable class DocumentModel {
    String id
    String name = "Untitled"
    boolean isDirty = false
    DocumentState state
}

DocumentView.groovy
panel(id: 'root') {
    // TODO: put your view implementation here
    button(text: 'Mark Dirty', enabled: bind { !model.isDirty }, 
        actionPerformed: { controller.markDirty() })
    button(text: 'Mark Clean', enabled: bind { model.isDirty }, 
        actionPerformed: { controller.markClean() })
}


DocumentController.groovy
import javax.swing.JOptionPane

/**
 * A skeleton controller for a 'document'.
 */
class DocumentController {
    def model
    def view
    def tabs

    void mvcGroupInit(Map args) {
        tabs = args.tabs
    }

    /**
     * Called when the tab with this document gains focus.
     */
    void activate(state) {
        // save the state object so we can signal the 
        model.state = state
  
        // TODO: sync the model and document state
        state.isDirty = model.isDirty
    }
 
    /**
     * Called when the tab with this document loses focus.
     */
    void deactivate() {
        // forget the state object
        model.state = null
    }
 
    /**
     * Called when the document is initially opened.
     */
    boolean open() {
        // TODO: perform any opening tasks
        return true 
    }
 
    /**
     * Called when the document is closed.
     */
    boolean close() {
        if (model.isDirty) {
            switch (JOptionPane.showConfirmDialog(app.appFrames[0], 
                    "Save changes to '${model.name}'?", "Example", 
                    JOptionPane.YES_NO_CANCEL_OPTION)){
                case JOptionPane.YES_OPTION: return save()
                case JOptionPane.NO_OPTION: return true
                case JOptionPane.CANCEL_OPTION: return false
            }
        }
        return true
    }
 
    /**
     * Called when the document is saved.
     */
    boolean save() {
        // TODO: perform any saving tasks
        markClean()
        return true
    }
 
    /**
     * Marks this document as 'dirty'
     */
    void markDirty() {
        model.isDirty = true
        if (model.state) { model.state.isDirty = true }
        // TODO: update any other model/state properties
        setTitle(model.name + "*")
    }
 
    /**
     * Marks this document as 'clean'
     */
    void markClean() {
        model.isDirty = false
        if (model.state) { model.state.isDirty = false }
        // TODO: update any other model/state properties
        setTitle(model.name)
    }
 
    /**
     * Sets this document's tab title.
     */
    void setTitle(title) {
        int index = tabs.indexOfComponent(view.root)
        if (index != -1) {
            tabs.setTitleAt(index, title)
        }
    }
}

So there it is. You should be able to use this as a starting place for your next Griffon-based text editor, web browser, etc.  I'm personally using in PSICAT to manage the open diagrams:


I zipped up all of the code from this post and made it available for download.

Monday, October 12, 2009

Griffon Tip: Silly SwingBuilder Tricks

Here's two quick tips for working with radio buttons in SwingBuilder.  Radio buttons are created using SwingBuilder's radioButton() method.  To ensure only one is selected at a time, you must also associate them with a button group.   Ideally SwingBuilder would allow you to nest your radioButton()s inside a buttonGroup(), e.g.
buttonGroup() {
    // doesn't work
    radioButton(text: 'Option 1')
    radioButton(text: 'Option 2')
}

Unfortunately this doesn't work as buttonGroup() does not support nesting.  Marc Hedlund stumbled across this same issue and offers up one solution.  I like his solution but it means creating a separate variable to hold the button group.  I've found a bit nicer way to do it using Groovy's with keyword:
buttonGroup().with {
    add radioButton(text: 'Option 1')
    add radioButton(text: 'Option 2')
}

The advantage of this approach is that it conveys our intention better and we don't have to instance extra variables.

EDIT: the 'with' also passes in the created object so you could take it a step further and replace the add as well:
buttonGroup().with { group ->
    radioButton(text: 'Option 1', buttonGroup: group)
    radioButton(text: 'Option 2', buttonGroup: group)
}

As a bonus, here's how you can use mutual binding to keep a boolean in your model in sync with the radio buttons.  Let's say your model looks something like so:
class DemoModel {
    ...
    @Bindable boolean option1 = true
    ...
}

Using mutual binding, you can keep the model synced up without any explicit management code:
buttonGroup().with {
    add radioButton(text: 'Option 1', selected: bind(source: model, sourceProperty: 'option1', mutual:true))
    add radioButton(text: 'Option 2', selected: bind { !model.option1 })
}

Obviously this will only work for cases where you have an either-or choice.

Tuesday, October 06, 2009

Griffon Tip: MVC Groups Revisited

My last post about MVC groups caused a bit of confusion, so I thought I'd follow up with a bit of clarification and, as a bonus, I'll also throw in a new trick for working with MVC groups.

MVC Groups for Dialogs
The withMVC method I introduced in the previous post was meant to help manage the lifecycle of short-lived MVC groups, such as those used in simple dialogs.  In cases like this, the MVC group only has to exist for as long as the dialog is visible.  withMVC was very much inspired by File#withInputStream which handles opening and closing of the input stream like withMVC handles creating and destroying of the MVC group.  Below is a complete example of showing an MVC group as a dialog:

NewProjectWizardModel.groovy
@Bindable class NewProjectWizardModel {
    String name
    String filePath
}

NewProjectWizardView.groovy
panel(id:'options', layout: new MigLayout('fill'), border: etchedBorder()) { 
    // project name
    label('Name:')
    textField(text: bind(source: model, sourceProperty:'name', mutual:true), constraints: 'growx, span, wrap')
    
    // directory
    label('Directory:')
    textField(text: bind(source: model, sourceProperty:'filePath', mutual:true), constraints:'width min(200px), growx')
    button(action: browseAction, constraints: 'wrap')
}

NewProjectWizardController.groovy
class NewProjectWizardController {
    def model
    def view

    void mvcGroupInit(Map args) {}

    def actions = [
        browse': { evt = null ->
            def file = Dialogs.showSaveDirectoryDialog("New Project", null, app.appFrames[0])
            if (file) { 
                model.filePath = file.absolutePath
                if (!model.name) { model.name = file.name }
            }
        }
    ]

    def show() {
        if (Dialogs.showCustomDialog("Create New Project", view.options, app.appFrames[0])) {
            // perform some logic
        }
    }
}

Dialogs.showCustomDialog() just uses JOptionPane to show a custom dialog with a component from the view.  I can show this dialog in response to a menu option, a button click, or whatever with the snippet from last post:
withMVC('NewProjectWizard', 'newProject', [:]) { mvc ->
    def project = mvc.controller.show()
    if (project) {
        // do something
    }
}

Hopefully that's a bit more clear and shows how MVC groups can be used as dialogs.  Now let's look at another use of MVC groups: embedding them as components in other views.

Embedding MVC Groups in Views
MVC groups work well as dialogs but they can also be embedded directly in the views of other MVC groups.  This is useful because it allows you to create re-usable components that you can embed in your views as needed.  Embedding is relatively straightforward:
widget(id:'sidePanel', buildMVCGroup('Project', 'project').view.root)

We build the MVC group and grab a component from the view (in this case it was called 'root' but it could be any id).  If we need to access something in the group, we can reference it by id:
def model = app.models['id']
def view = app.views['id']
def controller = app.controllers['id']

Hopefully these tips help you use MVC groups a bit more effectively and bring a bit more modularity to your Griffon app.

Monday, October 05, 2009

Griffon Tip: MVC Groups

Recently I've been doing some refactoring of PSICAT to make better use of Griffon's MVC Groups.  I like MVC Groups because they provide self-contained building blocks that you can re-use throughout your application.  Below are a few tips that might be useful to others:

Creating MVC Groups
MVC Groups are created with the 'griffon create-mvc ' command.  This creates the appropriate files in the griffon-app directory structure and registers the MVC Group in Application.groovy.

When you want to use the new MVC group in your application, you have two ways to instantiate it: createMVCGroup and buildMVCGroup.  Both methods instantiate the MVC group but differ in the ordering of parameters passed to them and in what they return:
  1. List[model, view, controller] createMVCGroup(type, id, paramMap)
  2. Map['model': model, 'view':view, 'controller':controller, ...] buildMVCGroup(paramMap, type, id)
So if I had created an MVC group: 'griffon create-mvc Diagram', I could instantiate it in my application with either:
def list = createMVCGroup('Diagram', 'diagram1', [:])
or
def map = buildMVCGroup([:], 'Diagram', 'diagram1')


I was initially a bit confused as to why the parameters map was moved to the first argument for buildMVCGroup but then I remembered that Groovy lets you pass named parameters to a method and collects them all as a map.  This allows some nice syntactic sugar when creating an MVC group:
def map = buildMVCGroup('Diagram', 'diagram1', name: 'The Diagram', format: 'jpeg')


The other nifty thing is that Griffon automagically sets parameters passed when creating an MVC group to properties on the model (if applicable).  In the example above, if I had a name and a format properties on my model, they would be set to the values I passed instead of me having to explicitly set them in mvcGroupInit.


Destroying MVC Groups
While probably not critical, it's good practice to dispose of your MVC groups when you're done working with them.  You can do this by calling destroyMVCGroup with the id you passed when creating the group.  I find myself using many short-lived MVC groups.  To ensure I disposed of things properly, I whipped up a little method that simplifies things:
def withMVC(String type, String id, Map params, Closure closure) {
    closure(buildMVCGroup(params, type, id))
    destroyMVCGroup(id)
}
NOTE: you could do the same trick of moving the map to the first argument if you wanted to be able to pass 'loose' named parameters to the method.

You would call it in your code like so:
withMVC('NewSectionDialog', 'newSection', [ project: model.project ]) { mvc ->
    def section = mvc.controller.show()
    if (section) { model.projectSections << section }
}
This creates the MVC group, hands it to the closure you pass, and then destroys the group when done.

MVC groups are a nice feature of Griffon that let you create re-usable building blocks within your application.  Hopefully this tip helps you use them more effectively.

Wednesday, September 09, 2009

Griffon Tip: Mac Look and Feel on Snow Leopard

If you upgraded your Mac to Snow Leopard recently, you may have noticed that your Griffon apps no longer look the same as they used to on Leopard.  Aside from a few color differences, the biggest giveaway will be that your app no longer uses the standard top menubar.  Fortunately there is a simple fix if you want to use the more native look and feel.  Change your griffon-app/lifecycle/Initialize.groovy file to include the 'mac' look and feel first:
import groovy.swing.SwingBuilder
import griffon.util.GriffonPlatformHelper

GriffonPlatformHelper.tweakForNativePlatform(app)
SwingBuilder.lookAndFeel('mac', 'nimbus', 'gtk', ['metal', [boldFonts: false]])

The crux of the problem is SwingBuilder tries various L&Fs in the order you specify them and stops when it finds one that works.  Nimbus is the L&F for Java 6 but previous versions of Mac OS X shipped with Java 5.  So SwingBuilder would try Nimbus and it would fail then it would try the Mac look and feel which would work.  Snow Leopard ships with Java 6 so when SwingBuilder tried Nimbus, it worked and it never tried to set the Mac L&F.

EDIT: This will be the default behavior in the upcoming Griffon 0.2 release.  So you will only need this fix if you have Griffon apps from pre-0.2 days.

Tuesday, September 01, 2009

Griffon Tip: Intercepting Window Closing Events

When building an editor of sorts, it is often useful to intercept the window closing event so that you can prompt the user to save if the editor has unsaved changes.  To do this in Griffon, we first need to change the defaultCloseOperation and define a windowClosing event handler on our application node in the view:

application(title:'Editor', size:[800,600], locationByPlatform: true,
    defaultCloseOperation: WindowConstants.DO_NOTHING_ON_CLOSE, 
    windowClosing: { evt -> 
        // check if the editor needs saving
    }) {
// the rest of your view code here
}

If we run our application now, we should notice that...the windowClosing event handler never runs.  Turns out that there's one more step--we need to tell Griffon that we want to explicitly handle shutting down the application.  We do this by setting autoShutdown=false in griffon-app/conf/Application.groovy Once this is set, we should notice that our windowClosing event handler runs.  Since Griffon is no longer responsible for automatically shutting down our application, we must make sure to call app.shutdown() somewhere in our closing logic or the user won't be able to exit the app.

Saturday, August 15, 2009

Are Groovy Stacktraces a Showstopper?

I've been part of an interesting debate on the merits of Groovy via Twitter this week. I'm reproducing it here because I think it's an interesting take on what potential users feel are make or break issues for a language, and to give others who may not have seen it the chance to weigh in without the 140 character limit. :)

(Sorry in advance. Reproducing a Twitter convo in a blog is kind of hideous)

[@philswenson] if you want to know why groovy sucks, click here: http://pastie.org/583115
[@joshareed] @philswenson It took me a second to diagnose your problem. Did you want Groovy to say: "Hey joker, actually import the classes you're using"
[@joshareed] @philswenson Apparently Ruby has some magical mind-reading interpreter/compiler that saves you from yourself?

[@philswenson] @joshareed why the extra 500 lines of crap? in java or jruby that stacktrace would have been 1/50 the size. that's my point
[@joshareed] @philswenson re: Java guess that's the trade off for Groovy dynamics. Ruby's (http://bit.ly/IagLJ) is not any better [Note: Nambu mangled the original link]

[@philswenson] @joshareed Ruby's stack dump = 67 lines. Groovy's = 222 lines. Not as different as I said, but still...
[@joshareed] @philswenson # of lines doesn't matter when you see the cause of the prob in the first 10 lines, does it? You don't have to keep reading...
[@joshareed] @philswenson and was the 67 vs 222 equivalent programs in each? I'd be interested in comparing the source of each

[@philswenson] @joshareed this was a case where the cause was obvious (it usually isn't). isn't groovy in large part about succinctness over java?
[@joshareed] @philswenson how much time do you spend looking at stacktraces that this is hang up for you? Write a 3 line .findAll{} to filter traces
[@joshareed] @philswenson and if you want to stick with stacktrace length as your argument then you won't be plain old Java traces with JRuby

From my perspective, this isn't a JRuby vs Groovy debate even though both languages were brought up in the conversation. Both are two different ways to skin a cat but they ultimately get you to the same place. Which you choose to use is more a matter of personal preference than the actual merits of the language.

What I'm more interested in is how important/serious is the stacktrace issue that Phil Swenson argues? I've been writing Groovy for a couple years now and can't remember (off the top of my head) a stacktrace from Groovy that was so confusing I couldn't figure out the problem. I'm sure there are some, especially when you start getting deep into the Groovy innards, but I'm guessing that's also the case with other languages on the JVM, like JRuby.

All dynamic languages built on the JVM introduce a certain level of indirection (by necessity), so are Groovy's stacktraces that much more hideous than JRuby's? What qualifies as hideous? I think length is a naive measure because the cause of the problem is likely to show up in the first dozen lines. Who cares if it goes on for another 200 lines? Length is also easily manipulated. You could write a simple findAll closure that sanitizes the stacktrace by removing all the lines that start with 'sun.reflect' or 'org.codehaus.groovy.runtime'. I have never once run into a problem that could be tracked to one of those lines in the stacktrace. So now does that make Groovy better than JRuby because the stacktrace is shorter?

I'm sure this is just a case of me being used to seeing Groovy stacktraces, so I'm used to feel of them and can quickly hone in on the cause of the problem. Likewise I'm sure Phil is used to [J]Ruby errors which probably look much different than Groovy's. I say probably because the two example put forth didn't look all that dissimilar IMO but were not from the same problem so it was an apples to oranges comparison.

Anyways, how important are stacktraces when making the decision to use a particular language? Are they important enough to declare one language's superiority over another? Are they worth focusing on to improve Groovy's ease-of-use?

Thursday, July 02, 2009

Griffon Action Patterns

I've been working on a decent-sized Griffon app recently and hit upon a pattern for managing actions that I thought might be useful to others. I began by following SwingPad's lead and declaring my actions separate (PSICATActions.groovy) from my view (PSICATView.groovy):

actions {
action(id: 'exitAction', name: 'Exit', closure: controller.exit)
action(id: 'openAction', name: 'Open', closure: controller.open)
...
}


which I import into my view:

// build actions
build(PSICATActions)

application(title:'PSICAT', size:[800,600], locationByPlatform: true, layout: new MigLayout('fill')) {
...
}


This is nice because it keeps all of your action definitions in one place and doesn't clutter your view code with them. When implementing the actions, the common pattern seems to define closures on your controller:

class PSICATController {
def model
def view

void mvcGroupInit(Map args) {
...
}

def exit = { evt = null ->
...
}

def open = { evt = null ->
...
}
}


This is fine but when you start getting many actions your controller becomes cluttered and it is difficult to tell what is an action implementation and what is regular controller logic. You also have to be careful with naming:

actions {
action(id: 'exitAction', name: 'Exit', closure: controller.exit)
action(id: 'openAction', name: 'Open', closure: controller.open)
action(id: 'newAction', name: 'New', closure: controller.new) // ERROR
}


We are forced to break with our naming convention because 'new' is a reserved keyword. To combat the clutter and avoid naming issues, I've taken to declaring my action implementations in a map on the controller:

class PSICATController {
def model
def view

void mvcGroupInit(Map args) {
...
}

def actions = [
'exit': { evt = null -> ... },
'open': { evt = null -> ... },
'new': { evt = null -> ... } // no issues here
]
}


Using the map makes it easy to tell what is an action and what is not, and linking the action definitions to the implementations becomes elegant and intuitive:

actions {
action(id: 'exitAction', name: 'Exit', closure: controller.actions['exit'])
action(id: 'openAction', name: 'Open', closure: controller.actions['open'])
action(id: 'newAction', name: 'New', closure: controller.actions['new'])
}


So far I have been pretty happy with this approach. What do other Griffon developers out there think?

Thursday, June 26, 2008

Mercurial Push from IntelliJ

I've been using IntelliJ on a recent project because of its Groovy and Mercurial support. The Mercurial support worked quite well except for pushing changes to a remote repository over ssh. A quick look at the Version Control Console revealed that things were getting hung up on: remote: ssh_askpass: exec(/usr/libexec/ssh-askpass): No such file or directory. After confirming that there was no ssh-askpass on my Mac OS X Leopard system, I turned to Google. After a few misses, I stumbled across Joe Mocker's blog post about VNC tunneled through SSH on OS X. Embedded in that post is this shell/AppleScript:

#! /bin/sh

#
# An SSH_ASKPASS command for MacOS X
#
# Author: Joseph Mocker, Sun Microsystems

#
# To use this script:
# setenv SSH_ASKPASS "macos-askpass"
# setenv DISPLAY ":0"
#

TITLE=${MACOS_ASKPASS_TITLE:-"SSH"}

DIALOG="display dialog \"$@\" default answer \"\" with title \"$TITLE\""
DIALOG="$DIALOG with icon caution with hidden answer"

result=`osascript -e 'tell application "Finder"' -e "activate" \
-e "$DIALOG" -e 'end tell'`

if [ "$result" = "" ]; then
exit 1
else
echo "$result" | sed -e 's/^text returned://' -e 's/, button returned:.*$//'
exit 0
fi


I dropped this code into a script at /usr/libexec/ssh-askpass and now when I push from IntelliJ:

Ugly, but it works. Now I just wish that the IntelliJ Mercurial plugin would consult the .hg/hgrc file for the remote repository or at least remember the value I type in when I pushed the last time, so I don't have to type in some long ssh://user@host.org/path/to/the/repo every time.

Tuesday, June 10, 2008

GraphicsBuilder Update

Just a quick update to my previous post about GraphicsBuilder. All of the issues I had in Step #4 have been fixed, so you should no longer have to modify the pom.xml file or manually install Batik 1.7 jars. The only remaining issue is the requirement on Java 1.6, but Andres recently posted that the next version of GraphicsBuilder will not require Java 1.6.

Thursday, May 22, 2008

Units DSL in Groovy

A while back I saw Guillaume Laforge's article about building a Groovy DSL for unit manipulations. I recently needed to implement something similar in a project, so I decided to take Guillaume's code and update it a bit. I wanted a nice way to package it up so I could quickly enable unit manipulation support on a particular class. I also added a pair of methods to make things more flexible. Here's my UnitDSL.groovy:

package org.psicat.model

import org.jscience.physics.amount.*
import javax.measure.unit.*

/**
* A helper class for setting up the Units DSL
*/
class UnitDSL {
private static boolean isEnabled = false;
private UnitDSL() { /* singleton */ }

/**
* Initialize the Units DSL.
*/
static enable() {
// only initialize once
if (isEnabled) return

// mark ourselves as initialized
isEnabled = true

// enable inheritance on EMC
ExpandoMetaClass.enableGlobally()

// transform number properties into an mount of a given unit represented by the property
Number.metaClass.getProperty = { String symbol -> Amount.valueOf(delegate, Unit.valueOf(symbol)) }

// define opeartor overloading, as JScience doesn\'t use the same operation names as Groovy
Amount.metaClass.static.valueOf = { Number number, String unit -> Amount.valueOf(number, Unit.valueOf(unit)) }
Amount.metaClass.multiply = { Number factor -> delegate.times(factor) }
Number.metaClass.multiply = { Amount amount -> amount.times(delegate) }
Number.metaClass.div = { Amount amount -> amount.inverse().times(delegate) }
Amount.metaClass.div = { Number factor -> delegate.divide(factor) }
Amount.metaClass.div = { Amount factor -> delegate.divide(factor) }
Amount.metaClass.power = { Number factor -> delegate.pow(factor) }
Amount.metaClass.negative = { -> delegate.opposite() }

// for unit conversions
Amount.metaClass.to = { Amount amount -> delegate.to(amount.unit) }
Amount.metaClass.to = { String unit -> delegate.to(Unit.valueOf(unit)) }
}

/**
* Add Units support to the specified class.
*/
static addUnitSupport(clazz) {
clazz.metaClass.setProperty = { String name, value ->
def metaProperty = clazz.metaClass.getMetaProperty(name)
if (metaProperty) {
if (metaProperty.type == Amount.class && value instanceof String) {
metaProperty.setProperty(delegate, Amount.valueOf(value))
} else {
metaProperty.setProperty(delegate, value)
}
}
}
}

/**
* Remove Units support from the specified class.
*/
static removeUnitSupport(clazz) {
GroovySystem.metaClassRegistry.removeMetaClass(clazz)
}
}


To enable the DSL, you have to call UnitDSL.enable(). This adds a few methods to the metaclasses on Number and Amount. The majority of the code in enable() is a straight cut and paste job from Guillaume's article.

I did add two methods. The first:

Amount.metaClass.static.valueOf = { Number number, String unit -> Amount.valueOf(number, Unit.valueOf(unit)) }


allows you to create an Amount using a Number and a String, e.g. Amount.valueOf(1.5, "cm").

The other new method:

Amount.metaClass.to = { String unit -> delegate.to(Unit.valueOf(unit)) }

allows conversions with the unit specified as a String, e.g. 1.5.m.to("cm")

The final enhancement I added was to create a addUnitSupport(clazz) method. This method overrides the setProperty() method of the passed class to support setting Amount properties as strings. All assignments in the following scenario are valid:

class Foo {
Amount bar
}

// test
UnitDSL.enable()
UnitDSL.addUnitSupport(Foo)

def foo = new Foo()
foo.bar = Amount.valueOf(3, SI.METER)
foo.bar = Amount.valueOf(3, "m")
foo.bar = Amount.valueOf("3m")
foo.bar = 3.m
foo.bar = "3m"


To use this code, you'll have to grab the latest JScience release.

Monday, May 12, 2008

Open Participation in SimpleIssue

When I started writing the simple issue tracker it was with the goal of learning more about Grails and coming away with a generally useful project. I decided to blog it because I was hoping my insights might be useful to the community. The response has been awesome, with lots of encouragement and lots of great ideas.

It strikes me that I can probably learn more from the community than just working away on my own. So if you want to fix something I screwed up or you have ideas for new features or you just want to experiment, drop me a line and I'll add you to the SimpleIssue project out at Google Code. Mike Hugo has already pointed out my embarrassing lack of tests and has offered to lend a hand. This is great news for me because testing has never been my strong suit. It will give me an opportunity to study how it's done.

SimpleIssue is a nights and weekends project for me, so I don't expect any particular level of participation. If you've got ideas and want to contribute, then all the better for us.

Sunday, May 11, 2008

Writing a Simple Issue Tracker in Grails, Part 2

This is the long overdue follow up to my Writing a Simple Issue Tracker in Grails post. In this post I'll be detailing how to add security with the JSecurity plugin.

So let's dive right in and work on securing our application. I opted to use the JSecurity plugin for no other reason than I've used the Acegi plugin in the past and wanted to see how JSecurity compares. You could use the Acegi plugin with a similar process and results.

Following the JSecurity Quick Start guide, we'll begin by installing the plugin and running the quick start script:

grails install-plugin jsecurity
grails quick-start


The quick start script created a few domain classes as well as a controller for logging in and out. Now we need to setup an Administrator user and role to test things with. We'll just cut and paste the Administrator role setup right from the Quick Start guide into our Bootstrap.groovy file:

import org.jsecurity.crypto.hash.Sha1Hash

class BootStrap {

def init = {servletContext ->
// Administrator user and role.
def adminRole = new JsecRole(name: "Administrator").save()
def adminUser = new JsecUser(username: "admin", passwordHash: new Sha1Hash("admin").toHex()).save()
new JsecUserRoleRel(user: adminUser, role: adminRole).save()
}

def destroy = {
}
}


With the administrator user in place, we can start securing our controllers. JSecurity makes this drop dead simple by letting you specify rules in the conf/SecurityFilters.groovy file.

Before we dive in and start writing our rules, let's think about what we want users to be able to do. I'm going to keep things simple and have two classes of users: anonymous and administrators. However, you could easily create a third class of users, authenticated, that would have more permissions than the anonymous users but less than the administrators.

Administrators should be able to create, edit, and delete Projects, Components, and Issues. Additionally, Administrators should be able to access the admin controller.

Depending on how private you want your issue tracker, anonymous users might be able to list and show the Projects, Components, and Issues or they might not. They may also create new issues or they may not. To handle this, I'm going to create two new configuration parameters that control how secure the application is by adding the following lines to Config.groovy:

issue.secure.create = true
issue.secure.view = false


These configuration options will let us configure whether anonymous users can create issues (issue.secure.create = true) and whether anonymous users can view issues (issue.secure.view = false). In the above example, creating a new issue is secured (requires the user be logged in) but viewing is not.

Now that we have an idea of our security rules, let's codify them in the conf/SecurityFilters.groovy file:

import org.codehaus.groovy.grails.commons.ApplicationHolder

class SecurityFilters {
def filters = {

// secure the project controller
projectCreationAndEditing(controller: "project", action: "(create|edit|save|update|delete)") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure the component controller
componentCreationAndEditing(controller: "component", action: "(create|edit|save|update|delete)") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure issue editing
issueEditing(controller: "issue", action: "(edit|update|delete)") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure admin controller
admin(controller: "admin", action: "*") {
before = {
accessControl {
role("Administrator")
}
}
}

// secure creating issues if Config#issue.secure.create = true
if (ApplicationHolder.application.config?.issue?.secure?.create) {
issueCreation(controller: "issue", action: "(create|save)") {
before = {
accessControl {
role("Administrator")
}
}
}
}

// secure viewing issues if Config#issue.secure.view = true
if (ApplicationHolder.application.config?.issue?.secure?.view) {
issueBrowsing(controller: "issue", action: "(show|list)") {
before = {
accessControl {
role("Administrator")
}
}
}

componentBrowsing(controller: "component", action: "(show|list)") {
before = {
accessControl {
role("Administrator")
}
}
}

projectBrowsing(controller: "project", action: "(show|list)") {
before = {
accessControl {
role("Administrator")
}
}
}
}
}
}


So with that we should have a secured grails app. Obviously there are plenty of things we can improve. First off, there is no user management code. We'll probably want to generate a controller to allow new users to register as well as to allow Administrators to add new users. The views could be cleaned up quite a bit and we could add a custom logo. Finally there are numerous other options that folks have suggested, including saved searches, internationalization, etc.

I've gone ahead and created a new Google Code project with the code from this article. If you're interested in hacking on this code, let me know. In the next installment, which I promise won't take a month, I'll be adding search/filtering support via the Searchable plugin and creating an API so I can create new issues from external applications.

Cheers,
Josh

Sunday, April 13, 2008

Writing a Simple Issue Tracker in Grails, Part 1

My project for the weekend was to write a simple issue tracking webapp in Grails. I could have used something like Trac but that's overkill for my needs. I just wanted something simple where my users could report issues and request new features. I also wanted to add a few personal touches, which I'll show you along the way.

I'm going to assuming that you're not absolutely new to Grails and you've already got it installed and played around with it. If that's not the case, I suggest checking out Scott Davis's Mastering Grails series of articles. He's goes into far more detail than I do, so check them out.

Let's start by creating our project:
grails create-app simpleissue

First up is to define our domain models. We're going to keep it simple with just three models: Project, Component, and Issue. A Project has one or more Components, such as ui, documentation, etc. A Component is associated with a single Project and has zero or more Issues associated with it. The Issue object is associated with a Component and captures a bunch of information.

So let's lay down the code:
Project.groovy

class Project {
// relationships
static hasMany = [components: Component]

// fields
String name

String toString() {
return name
}

// constraints
static constraints = {
name()
components()
}
}

Component.groovy

class Component {
// relationships
static belongsTo = Project
static hasMany = [issues: Issue]

// fields
Project project
String name

// override for nice display
String toString() {
return "${project} - ${name}"
}

// constraints
static def constraints = {
name()
project()
issues()
}
}

Issue.groovy

class Issue {
// relationships
static belongsTo = Component

// fields
Component component
String type
String submitter
String description
String status = "New"
Integer bounty
Date dateCreated
Date lastUpdated

// constraints
static constraints = {
component()
type(inList: ["Defect", "Feature"])
submitter()
description(size: 0..5000)
status(inList: ["New", "Accepted", "Closed", "Won't Fix"])
bounty(range:0..12)
}
}


Most of the code is a pretty straightforward translation of our written description of the domain. You may, however, notice a few peculiar constraints. I've used a fair number of 'empty' constraints such as:

static def constraints = {
name()
project()
issues()
}

By default, Grails treats all fields in the domain class as required. I didn't want to change that, but I wanted to affect the order that the fields show up in a particular order in the web forms. By specifying the constraint, even if it is empty, it'll show up in that order in our forms. Of course, we could have customized the field order by hand directly in the view GSP code.

I also make use of the inList constraint to limit the fields to a specific set of values. Our views will be generated with an HTML select drop down containing the list of values we've specified.

Finally, we specify our issue description as being size:0..5000. This will ensure that there is plenty of space in the database for the description text. If we hadn't specified this, the description would have been generated as a varchar(255).

With our domain classes in place, we can create our controllers and views to test things out:

grails generate-all Project
grails generate-all Component
grails generate-all Issue
grails run-app

Fire up your browser and test things out by visiting http://localhost:8080/simpleissue:
and our issue creation form:

Looks pretty decent for 5 minutes of work. Poke around and test creating a project, component, and a few issues.

Customizing the Look

Now let's clean things up a bit and add some polish. The first thing I want to do is have the index page show the list of issues. We could copy and paste the code from the Issue List view or we can simply add a redirect to the top of our web-app/index.gsp file:

<% response.sendRedirect('issue/list') %>


The next thing I want to do is clean up the issue creation form. A few of the values, such as status, dateCreated, lastUpdated don't need to be specified in the form. We can go into grails-app/views/issue/create.gsp and remove those fields.

You may have noticed an odd field in the Issue domain class: bounty. You might have expected to see a field for priority on the issue. Instead, I chose to add a "beer bounty" field where the issue submitter could pledge a certain number of beers that I could redeem upon completion of the issue. This is, in my opinion, far superior to simply assigning low, medium, high priorities to issues.

As a final customization, I want to convert the number of beers into little beer mug icons to make it easy to see the important issues to fix. We'll do this by first copying the repeat example tag from the Dynamic Tag Libraries page of the documentation:
grails create-tag-lib Misc
This will create a grails-app/taglib/MiscTagLib.groovy file which we can add:

class MiscTagLib {
def repeat = {attrs, body ->
def i = Integer.valueOf(attrs["times"])
def current = 0
i.times {
out << body(++current)
}
}
}


And we'll call it in our grails-app/views/issue/list.gsp:

<g:repeat times="${issue.bounty}">
<img src="${createLinkTo(dir:'images', file:'beer.gif')}" alt="${issue.bounty} beers"/>
</g:repeat>


Here's a look at the final output:
In part 2, we're going to add in some security to prevent arbitrary user's from editing and deleting issues. We'll also add in searching/filtering support with the Searchable plugin.

Cheers.

Sunday, April 06, 2008

Pluggable Service Implementations in Grails

This weekend I was working on a StorageService service in Grails. The service takes a file, stores it somewhere, and then returns the URL where the file can be retrieved from. I can envision having multiple implementations of this service: one that simply puts the file in a directory for something like Tomcat/Apache/Nginx to serve up, one that puts the contents of the file into a database blob and has a controller that retrieves it from the database and serves it up, and one that stores the file on Amazon S3.

I wanted to be able to easily specify which implementation to use without having to refactor my code and I wanted to be able to configure the implementation based upon the environment. For development and integration testing, it would be easiest to test with a simple File-based service. When I actually rolled it out to production, I would likely want to use something more scalable like Amazon's S3.

I didn't know how (if?) Grails handled this situation, so I decided to write my own. I drew inspiration from Shawn Harstock's post about Fun with Grails Configuration Files for managing service configuration in the various environments.

The first thing I did was create a stub service, StorageService:

import org.codehaus.groovy.grails.commons.ApplicationHolder

class StorageService {
boolean transactional = true
boolean initialized = false
def provider = null

String store(File file) {
// initialize our provider
if (!initialized) {
initializeProvider()
}

// use our provider or log the error
if (provider == null) {
// log the error
return null
} else {
return provider.store(file)
}
}

def initializeProvider() {
initialized = true;

// get our provider name
def prefix = ApplicationHolder.application.config?.storage?.provider
if (prefix == null) {
prefix = "Default"
} else {
def index = prefix.lastIndexOf('.')
if (index == -1) {
prefix = prefix[0].toUpperCase() + prefix[1..-1]
} else {
prefix = prefix[0..index] + prefix[index+1].toUpperCase() + prefix[(index+2)..-1]
}
}

// try creating the provider
provider = Class.forName("${prefix}StorageProvider")?.newInstance()
}
}

The service looks up and loads the storage provider class based on a configuration parameter. For example, my Config.groovy file might look like this:

...
environments {
development {
storage {
provider="file"
}
}
test {
storage {
provider="org.andrill.mock"
}
}
production {
storage {
provider="s3"
}
}

}
...


In development, the StorageService would try to load the class FileStorageProvider and delegate calls to it. In testing, it would try to load the class org.andrill.MockStorageProvider and delegate calls to it. And finally, in production it would try to use the S3StorageProvider.

My controllers don't need to know which provider implementation, they just declare a
StorageService storageService field, which Spring auto-wires for them, and go. It works like a charm.

So my only question is, did I just re-invent the wheel? Does Grails already have a mechanism for handling this? If not, how would you accomplish the task?

Update: Check out David Hernández's explanation of how to do this with Spring. No icky, ClassForName needed. Nice work, David!

Cheers.

Monday, March 31, 2008

Back from Boston

I made it back from Boston. The trip was fun but I did not get as much done as I would have at home. Things are looking to be pretty busy this week as I scramble to get caught up. The wedding is in a few weeks. 10 days on the beach in the Bahamas. That thought is what's getting me through the work and stress.

In other news, I'm starting a new project in my spare time. I'm going to keep things under wraps for a bit as I don't have a solid time frame. However, one thing I will mention is that it's going to be a webapp and it's going to contain a social component. I'm hoping the development will yield a series of useful Groovy/Grails blog posts.

I'd also really like to pull together a generic "web 2.0 template" project in Grails. Something that would pull together plugins for security and contain User, Profile, Role-type domain classes, controllers, and views. Ideally you should be able to use it to bootstrap a generic Web 2.0 site with all of the user registration and profile management taken care of. Then you can start adding your specific domain classes to make the site useful.