(Quick Reference)

5.9 Archetypes - Reference Documentation

Authors: Andres Almiray

Version: 1.2.0

Table of Contents

5.9 Archetypes

While it's true that artifact templates can be provided by plugins it simply was not possible to configure how an application is created. Application Archetypes fill this gap by providing a hook into the application creation process. Archetypes can do the following:
  • provide new versions of existing templates, like Model, Controller and so forth
  • create new directories and files
  • most importantly perhaps, install a preset of plugins

So, if your company requires all applications to be built following the same template and basic behavior then you can create an archetype that enforces those constraints. Archetypes are simple zip files with an application descriptor and templates. Despite this, Griffon provides a few scripts that let you manage archetypes

Archetypes are installed per Griffon location under $USER_HOME/.griffon/<version>/archetypes. Archetypes are registered with an application's metadata when creating an application. You can either manually modify the value of 'app.archetype' to a known archetype name or specify an -archetype=<archetypeName> flag when creating a new application.

If no valid archetype is found then the default archetype will be used. Following is the default template for an application archetype

import griffon.util.Metadata

includeTargets << griffonScript('CreateMvc')

target(name: 'createApplicationProject', description: 'Creates a new application project', prehook: null, posthook: null) { createProjectWithDefaults() createMVC()

// to install plugins do the following // Metadata md = Metadata.getInstance(new File("${basedir}/application.properties")) // // for a single plugin // installPluginExternal md, pluginName, pluginVersion // ** pluginVersion is optional ** // // for multiple plugins where the latest version is preferred // installPluginsLatest md, [pluginName1, pluginName2] // // for multiple plugins with an specific version // installPlugins md, [pluginName1: pluginVersion1] } setDefaultTarget(createApplicationProject)

5.9.1 A Fancy Example

This section demonstrates how an archetype can be created and put to good use for building applications.

#1 Create the archetype

The first step is to create the archetype project and its descriptor, which can be done by executing the following command

griffon create-archetype fancy
cd fancy

#2 Tweak the archetype descriptor

Locate the archetype descriptor (application.groovy) and open it in your favorite editor, paste the following snippet

import griffon.util.Metadata

includeTargets << griffonScript('CreateMvc')

target(name: 'createApplicationProject', description: 'Creates a new application project', prehook: null, posthook: null) { createProjectWithDefaults()

argsMap.model = 'MainModel' argsMap.view = 'MainView' argsMap.controller = 'MainController' createMVC()

createArtifact( name: mvcFullQualifiedClassName, suffix: 'Actions', type: 'MainActions', path: 'griffon-app/views')

createArtifact( name: mvcFullQualifiedClassName, suffix: 'MenuBar', type: 'MainMenuBar', path: 'griffon-app/views')

createArtifact( name: mvcFullQualifiedClassName, suffix: 'StatusBar', type: 'MainStatusBar', path: 'griffon-app/views')

createArtifact( name: mvcFullQualifiedClassName, suffix: 'Content', type: 'MainContent', path: 'griffon-app/views')

Metadata md = Metadata.getInstance(new File("${basedir}/application.properties")) installPluginExternal md, 'miglayout' }

setDefaultTarget(createApplicationProject)

This archetype overrides the default templates for Model, View and Controller that will be used for the initial MVC group. It also creates 4 additional files inside griffon-app/views. Finally it installs the latest version of the MigLayout plugin.

#3 Create the artifact templates

According to the conventions laid out in the archetype descriptor there must exist a file under templates/artifacts that matches each one of the specified artifact types, in other words we need the following files

MainModel.groovy

@artifact.package@import groovy.beans.Bindable
import griffon.util.GriffonNameUtils

class @artifact.name@ { @Bindable String status

void mvcGroupInit(Map args) { status = "Welcome to ${GriffonNameUtils.capitalize(app.config.application.title)}" } }

MainController.groovy

@artifact.package@class @artifact.name@ {
    def model
    def view

// void mvcGroupInit(Map args) { // // this method is called after model and view are injected // }

// void mvcGroupDestroy() { // // this method is called when the group is destroyed // }

def newAction = { evt = null -> model.status = 'New action' }

def openAction = { evt = null -> model.status = 'Open action' }

def saveAction = { evt = null -> model.status = 'Save action' }

def saveAsAction = { evt = null -> model.status = 'Save As action' }

def aboutAction = { evt = null -> model.status = 'About action' }

def quitAction = { evt = null -> model.status = 'Quit action' }

def cutAction = { evt = null -> model.status = 'Cut action' }

def copyAction = { evt = null -> model.status = 'Copy action' }

def pasteAction = { evt = null -> model.status = 'Paste action' } }

MainView.groovy

@artifact.package@build(@artifact.name.plain@Actions)
application(title: GriffonNameUtils.capitalize(app.config.application.title),
    pack: true,
    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]) {
   menuBar(build(@artifact.name.plain@MenuBar))
   migLayout(layoutConstraints: 'fill')
   widget(build(@artifact.name.plain@Content), constraints: 'center, grow')
   widget(build(@artifact.name.plain@StatusBar), constraints: 'south, grow')
}

MainActions.groovy

@artifact.package@import groovy.ui.Console

actions { action( id: 'newAction', name: 'New', closure: controller.newAction, mnemonic: 'N', accelerator: shortcut('N'), smallIcon: imageIcon(resource:"icons/page.png", class: Console), shortDescription: 'New' ) action( id: 'openAction', name: 'Open...', closure: controller.openAction, mnemonic: 'O', accelerator: shortcut('O'), smallIcon: imageIcon(resource:"icons/folder_page.png", class: Console), shortDescription: 'Open' ) action( id: 'quitAction', name: 'Quit', closure: controller.quitAction, mnemonic: 'Q', accelerator: shortcut('Q'), ) action( id: 'aboutAction', name: 'About', closure: controller.aboutAction, mnemonic: 'B', accelerator: shortcut('B') )

action( id: 'saveAction', name: 'Save', closure: controller.saveAction, mnemonic: 'S', accelerator: shortcut('S'), smallIcon: imageIcon(resource:"icons/disk.png", class: Console), shortDescription: 'Save' ) action( id: 'saveAsAction', name: 'Save as...', closure: controller.saveAsAction, accelerator: shortcut('shift S') )

action(id: 'cutAction', name: 'Cut', closure: controller.cutAction, mnemonic: 'T', accelerator: shortcut('X'), smallIcon: imageIcon(resource:"icons/cut.png", class: Console), shortDescription: 'Cut' ) action(id: 'copyAction', name: 'Copy', closure: controller.copyAction, mnemonic: 'C', accelerator: shortcut('C'), smallIcon: imageIcon(resource:"icons/page_copy.png", class: Console), shortDescription: 'Copy' ) action(id: 'pasteAction', name: 'Paste', closure: controller.pasteAction, mnemonic: 'P', accelerator: shortcut('V'), smallIcon: imageIcon(resource:"icons/page_paste.png", class: Console), shortDescription: 'Paste' ) }

MainMenuBar.groovy

@artifact.package@import static griffon.util.GriffonApplicationUtils.*

menuBar = menuBar { menu(text: 'File', mnemonic: 'F') { menuItem(newAction) menuItem(openAction) separator() menuItem(saveAction) menuItem(saveAsAction) if( !isMacOSX ) { separator() menuItem(quitAction) } }

menu(text: 'Edit', mnemonic: 'E') { menuItem(cutAction) menuItem(copyAction) menuItem(pasteAction) }

if(!isMacOSX) { glue() menu(text: 'Help', mnemonic: 'H') { menuItem(aboutAction) } } }

MainContent.groovy

@artifact.package@label('Main content')

MainStatusBar.groovy

@artifact.package@label(id: 'status', text: bind { model.status })

#4 Package and install the archetype

This step is easily done with a pair of command invocations

griffon package-archetype
griffon install-archetype target/package/griffon-fancy-0.1.zip

#5 Use the archetype

Now that the archetype has been installed all that is left is put it to good use, like this

griffon create-app sample --archetype=fancy

This command should generate the following files in the application directory

  • griffon-app
    • controllers
      • sample
        • SampleController
    • models
      • sample
        • sampleModel
    • views
      • sample
        • SampleActions
        • SampleContent
        • SampleMenuBar
        • SampleStatusBar
        • SampleView

If you inspect the application.properties file you'll notice that the miglayout plugin has been installed too.

Archetypes can be versioned, installed and released in the same way plugins are.