gr8conf 2009: griffon by jim shingler
DESCRIPTION
Jim Shingler presents an introduction to the Griffon Swing MVC framework.TRANSCRIPT
© 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• [email protected]•Grails•www.grails.org•Books Coming
Soon
48Wednesday, May 13, 2009
© Jim Shingler
Resources•[email protected] is a medium volume list
useful for those interested in ongoing developments• [email protected] is a high volume list
that logs commits and issues•[email protected] 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: [email protected]
• LinkedIn: http://www.linkedin.com/in/jimshingler
• Twitter: @jshingler
Thank You for your time
50Wednesday, May 13, 2009