GR8Conf 2009: Griffon by Jim Shingler

Post on 10-May-2015

1.934 views 0 download

Tags:

description

Jim Shingler presents an introduction to the Griffon Swing MVC framework.

Transcript of GR8Conf 2009: Griffon by Jim Shingler

© Jim Shingler

Introduction toCreating a Griffon: Rich Client front-end to our

Twitter Clone

By Jim Shingler

1Wednesday, May 13, 2009

© Jim Shingler

AbstractGroovy and Grails have given us the ability to leverage the strength of the Java Platform (and Eco System) and the productivity of “Convention over Configuration” to construct websites. But “What If” the User Interface requirements of the new application is best solved with the type of interaction a desktop application provides?

Griffon bring the same productivity gains to the desktop application that Grails brings to web applications. This session will use Griffon and popular open source libraries to build a desktop application to interact with a Grails backend.

2Wednesday, May 13, 2009

© Jim Shingler

IntroductionMy name is Jim Shingler

Chief Technical Architect

President of Genuine Solutions

Beginning Groovy and Grails Co-Author

FallME (Inversion of Control for JavaME) Co-Founder

Griffon Splash Plugin Author

Griffon gConfig Author

Griffon TM Bundle Author3Wednesday, May 13, 2009

© Jim Shingler

Agenda

</xml>

Griffon 101•What is Griffon•Installing Griffon•0 -100 k/mph in 60 seconds•Plugins Overview•Teaching the Griffon to count (Binding and Threading)•Readying Graeme’s Twitter Clone

Griffon 201•Griffon Twitter Client

4Wednesday, May 13, 2009

© Jim Shingler

Installing Griffon

1. Download Griffon

2. Unpack it (unix: /opt/local/share/ windows: /apps/griffon)

3. Set the GROOVY_HOME

4. Add it to your path, <GROOVY_HOME>/bin

5Wednesday, May 13, 2009

© Jim Shingler

0-100 k/mph in 60 Seconds

> griffon create-app small

Welcome to Griffon 0.1.0 - http://griffon.codehaus.org/

Licensed under Apache Standard License 2.0

Griffon home is set to: /opt/local/share/griffon-0.1.0

. . .

> griffon run-app

6Wednesday, May 13, 2009

© Jim Shingler

DEMO

7Wednesday, May 13, 2009

© Jim Shingler

Congratulations

Developer

you are a

8Wednesday, May 13, 2009

© Jim Shingler

Griffon

Don’t forget to update your

resume.

9Wednesday, May 13, 2009

© Jim Shingler

App Structure& Convention

A pretty standard application structure, . . . you can pretty well guess the purpose of the files and

directories.

10Wednesday, May 13, 2009

© Jim Shingler

Griffon Commands

11Wednesday, May 13, 2009

© Jim Shingler

Plugins

12Wednesday, May 13, 2009

© Jim Shingler

Start Small

• Swing and SwingX Builder

• GUI Components

• About Box

• Define and Process Actions

13Wednesday, May 13, 2009

© Jim Shingler

DEMO

• Create Count App• Add Button• Build and Initialize “Click Action”• Process the Click Action

• Install and Enable SwingXBuilder• Build and Initialize Menus• Build and Initialize “Menu Actions”• Process the Menu Actions

14Wednesday, May 13, 2009

© Jim Shingler

Controllerimport javax.swing.JOptionPane

class CountingController { // these will be injected by Griffon def model def view def builder

void mvcGroupInit(Map args) { // this method is called after model and view are injected } def click = { evt = null ->

model.count++ } def exit = { evt = null -> app.shutdown() }

def showAbout = { evt = null -> builder.optionPane().showMessageDialog(null, 'This is the Counting Application')

}}

15Wednesday, May 13, 2009

© Jim Shingler

Modelimport groovy.beans.Bindable

@Bindableclass CountingModel { def count = 0}

Adds Property Change Support

to the model

16Wednesday, May 13, 2009

© Jim Shingler

View and MenuView

application(title:'sample2', /*size:[320,480], */location:[200,200], pack:true, locationByPlatform:false) { // add content here build(Actions) build(MenuBar) button(id:'clickButton', text:bind{ model.count }, action: clickAction)}

jxmenuBar { menu(text: 'File', mnemonic: 'F') { menuItem(exitAction) }

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

MenuBar

Loads and runs Actions and MenuBar scripts inline

Use the action to define the menu item

Data Binding. Observe the change in the model

Execute the “clickAction”

17Wednesday, May 13, 2009

© Jim Shingler

Actions// create the actionsaction(id: 'clickAction', name: 'Click Me', closure: controller.&click, shortDescription: 'Increment the Click Count' )

action(id: 'exitAction', name: 'Exit', closure: controller.exit, mnemonic: 'x', accelerator: 'F4', shortDescription: 'Exit SimpleUI' )

action(id: 'aboutAction', name: 'About', closure: controller.showAbout, mnemonic: 'A', accelerator: 'F1', shortDescription: 'Find out about SimpleUI' )

Closure to run when the action is

executed

18Wednesday, May 13, 2009

© Jim Shingler

Threading the GUI

It isn’t that bad

19Wednesday, May 13, 2009

© Jim Shingler

Rules of Thumb

• Painting and UI Operations need to be done in the EventDispatchThread (EDT)

• Everything else should be done outside the EDT

• Java 6 has SwingWorker, Java 5 has SwingLabs Swingworker

But that just isn’t Groovy enough for Griffon

20Wednesday, May 13, 2009

© Jim Shingler

Griffon Threading

• Build the UI in the EDTSwingBuilder.build { . . . }

• Long Running code outside the EDTdoOutside { . . . }

• code inside the EDTedt { . . . }doLater { . . . }

Creates thread and runs closure

Do synchronously in EDT

Do asynchronously in EDT

21Wednesday, May 13, 2009

© Jim Shingler

DEMO

22Wednesday, May 13, 2009

© Jim Shingler

Model

import groovy.beans.Bindable

@Bindableclass CountingModel { def count = 0 def countSlow = 0 def countConcurrent = 0}

23Wednesday, May 13, 2009

© Jim Shingler

Viewapplication(title:'counting', /*size:[320,480], location:[50,50],*/ pack:true, locationByPlatform:true) { build(Actions) build(MenuBar) gridLayout() button(id:'clickButton', text:bind {model.count}, action: clickAction) label(text:bind {model.count}) button(id:'slowClickButton', text:"Slow Click", action: slowClickAction) label(text:bind {model.countSlow}) button(id:'concurrentClickButton', text:"Concurrent Click", action: concurrentClickAction) label(text:bind {model.countConcurrent})}

24Wednesday, May 13, 2009

© Jim Shingler

Actions// create the actionsaction(id: 'clickAction', name: 'Click', closure: controller.&click, shortDescription: 'Increment the Click Count' )

action(id: 'clickActionSlow', name: 'Click Slow', closure: controller.&clickSlow, shortDescription: 'Increment the Click Count Slow' ) action(id: 'clickActionConcurrent', name: 'Click Concurrent', closure: controller.&clickConcurrent, shortDescription: 'Increment the Click Count Concurrent' )

action(id: 'exitAction', name: 'Exit', closure: controller.exit, mnemonic: 'x', accelerator: 'F4', shortDescription: 'Exit SimpleUI' )

action(id: 'aboutAction', name: 'About', closure: controller.showAbout, mnemonic: 'A', accelerator: 'F1', shortDescription: 'Find out about SimpleUI' )

25Wednesday, May 13, 2009

© Jim Shingler

Controllerimport javax.swing.JOptionPaneclass CountingController { // these will be injected by Griffon def model def view void mvcGroupInit(Map args) { } def click = { evt -> model.count++ } def clickSlow = { evt = null -> Thread.sleep(5000) model.countSlow++ } def clickConcurrent = { evt = null -> doOutside { Thread.sleep(5000) edt { // Sync model.countConcurrent++ } } } def exit = { evt = null -> System.exit(0) } def showAbout = { evt = null -> JOptionPane.showMessageDialog(null, '''This is the SimpleUI Application''') }}

26Wednesday, May 13, 2009

© Jim Shingler

Twitter Clone Enhancements

27Wednesday, May 13, 2009

© Jim Shingler

Render Status XMLimport grails.converters.*

class StatusController { def twitterCache def index = { def messages = twitterCache.get(principalInfo.username)?.value if(!messages) { messages = findStatusMessages() twitterCache.put new Element(principalInfo.username, messages) } def feedOutput = { . . . } withFormat { html([messages:messages]) xml { render messages as XML} rss { render(feedType:"rss", feedOutput)} } }. . .

28Wednesday, May 13, 2009

© Jim Shingler

Render Person XML import grails.converters.*

class PersonController {

. . .

def findByUsername = { def p = Person.findByUsername(params.username) withFormat { html person:p xml { render p as XML } } }

. . .

29Wednesday, May 13, 2009

© Jim Shingler

def show = { def person = Person.get(params.id) if (!person) { flash.message = "Person not found with id $params.id" redirect action: list return } List roleNames = [] for (role in person.authorities) { roleNames << role.authority } roleNames.sort { n1, n2 -> n1 <=> n2 } withFormat { html ( [person: person, roleNames: roleNames] ) xml { render person as XML } } // [person: person, roleNames: roleNames] }

30Wednesday, May 13, 2009

© Jim Shingler

Acegi Basic Authentication

grails-app/conf/SecurityConfig.groovysecurity {

// see DefaultSecurityConfig.groovy for all settable/overridable properties

active = true basicProcessingFilter = true

loginUserDomainClass = "Person" authorityDomainClass = "Authority" requestMapClass = "Requestmap"

}

31Wednesday, May 13, 2009

© Jim Shingler

Acegi Basic Authentication

beans = { authenticationEntryPoint(org.springframework.security.ui.basicauth. BasicProcessingFilterEntryPoint) { realmName = 'Grails Realm' } twitterCache(org.springframework.cache.ehcache.EhCacheFactoryBean) { timeToLive = 1200 } }

grails-app/conf/spring/resources.groovy

32Wednesday, May 13, 2009

© Jim Shingler

Griffon Twitter Clone Client

33Wednesday, May 13, 2009

© Jim Shingler

Requirements

• Login

• Display User Info

• Display Statuses (Tweets)

• Update Statuses(Tweets)

• Send My Own Status (Tweet)

34Wednesday, May 13, 2009

© Jim Shingler

Overview

Twitter Clone

Twitter Service

ViewController

Model

MenuBar

ToolBar

StatusBar

Tips

About

MVC Triad

</xml>

35Wednesday, May 13, 2009

© Jim Shingler

Let’s get to Work

36Wednesday, May 13, 2009

© Jim Shingler

ToolBar

User Info

Statuses / Tweets

RefreshLogin

Update Status

37Wednesday, May 13, 2009

© Jim Shingler

38Wednesday, May 13, 2009

© Jim Shingler

Other Griffon Apps

39Wednesday, May 13, 2009

© Jim Shingler

40Wednesday, May 13, 2009

© Jim Shingler

41Wednesday, May 13, 2009

© Jim Shingler

42Wednesday, May 13, 2009

© Jim Shingler

43Wednesday, May 13, 2009

© Jim Shingler

44Wednesday, May 13, 2009

© Jim Shingler

45Wednesday, May 13, 2009

© Jim Shingler

The Codehttp://github.com/jshingler/gr8conf_2009/tree/master

46Wednesday, May 13, 2009

© Jim Shingler

Founders

Danno Ferrinhttp://shemnon.com/speling

Andres Almirayhttp://jroller.com/aalmiray

James Williamshttp://jameswilliams.be/blog

47Wednesday, May 13, 2009

© Jim Shingler

Resources•Griffon• griffon.codehause.org• griffon-user@groovy.codehause.org•Grails•www.grails.org•Books Coming

Soon

48Wednesday, May 13, 2009

© Jim Shingler

Resources•dev@griffon.codehaus.org is a medium volume list

useful for those interested in ongoing developments• scm@griffon.codehaus.org is a high volume list

that logs commits and issues•user@griffon.codehaus.org is a high volume list is

for questions and general discussion about Griffon•You can find a great archive support at MarkMail,

http://griffon.markmail.org.

49Wednesday, May 13, 2009

© Jim Shingler

Conclusion

• Blog: http://jshingler.blogspot.com

• Email: ShinglerJim@gmail.com

• LinkedIn: http://www.linkedin.com/in/jimshingler

• Twitter: @jshingler

Thank You for your time

50Wednesday, May 13, 2009