More Related Content
Similar to GR8Conf 2009: Griffon by Jim Shingler (18)
GR8Conf 2009: Griffon by Jim Shingler
- 1. Introduction to
Creating a Griffon: Rich Client front-end to our
Twitter Clone
By Jim Shingler
© Jim Shingler
Wednesday, May 13, 2009 1
- 2. Abstract
Groovy 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.
© Jim Shingler
Wednesday, May 13, 2009 2
- 3. Introduction
My 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 Author
© Jim Shingler
Wednesday, May 13, 2009 3
- 4. Agenda
Griffon 101
•What is Griffon
•Installing Griffon
•0 -100 k/mph in 60 seconds
</xml>
•Plugins Overview
•Teaching the Griffon to count
(Binding and Threading)
•Readying Graeme’s Twitter Clone
Griffon 201
•Griffon Twitter Client
© Jim Shingler
Wednesday, May 13, 2009 4
- 5. 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
© Jim Shingler
Wednesday, May 13, 2009 5
- 6. 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
© Jim Shingler
Wednesday, May 13, 2009 6
- 7. DEMO
© Jim Shingler
Wednesday, May 13, 2009 7
- 8. Congratulations
you are a
Developer
© Jim Shingler
Wednesday, May 13, 2009 8
- 9. Don’t
forget to
update
your
resume.
Griffon
© Jim Shingler
Wednesday, May 13, 2009 9
- 10. App Structure
& Convention
A pretty standard application
structure, . . . you can pretty well
guess the purpose of the files and
directories.
© Jim Shingler
Wednesday, May 13, 2009 10
- 12. Plugins
© Jim Shingler
Wednesday, May 13, 2009 12
- 13. Start Small
• Swing and SwingX Builder
• GUI Components
• About Box
• Define and Process Actions
© Jim Shingler
Wednesday, May 13, 2009 13
- 14. 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
© Jim Shingler
Wednesday, May 13, 2009 14
- 15. Controller
import 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')
}
}
© Jim Shingler
Wednesday, May 13, 2009 15
- 16. Model
import groovy.beans.Bindable
Adds Property @Bindable
Change Support class CountingModel {
def count = 0
}
to the model
© Jim Shingler
Wednesday, May 13, 2009 16
- 17. View and Menu
View
application(title:'sample2', /*size:[320,480], */location:[200,200],
pack:true, locationByPlatform:false) {
// add content here
build(Actions) Loads and runs Actions and MenuBar scripts inline
build(MenuBar)
button(id:'clickButton', text:bind{ model.count }, action: clickAction)
}
Data Binding. Observe
the change in the model MenuBar Execute the “clickAction”
jxmenuBar {
menu(text: 'File', mnemonic: 'F') {
menuItem(exitAction) Use the action to define
} the menu item
glue()
menu(text: 'Help', mnemonic: 'H') {
menuItem(aboutAction)
}
}
© Jim Shingler
Wednesday, May 13, 2009 17
- 18. Actions
// create the actions
Closure to run when
action(id: 'clickAction', the action is
name: 'Click Me', executed
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'
)
© Jim Shingler
Wednesday, May 13, 2009 18
- 20. 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
© Jim Shingler
Wednesday, May 13, 2009 20
- 21. Griffon Threading
• Build the UI in the EDT
SwingBuilder.build { . . . }
• Long Running code outside the EDT
doOutside { . . . } Creates thread and runs closure
• code inside the EDT
edt { . . . } Do synchronously in EDT
doLater { . . . } Do asynchronously in EDT
© Jim Shingler
Wednesday, May 13, 2009 21
- 22. DEMO
© Jim Shingler
Wednesday, May 13, 2009 22
- 23. Model
import groovy.beans.Bindable
@Bindable
class CountingModel {
def count = 0
def countSlow = 0
def countConcurrent = 0
}
© Jim Shingler
Wednesday, May 13, 2009 23
- 24. View
application(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})
}
© Jim Shingler
Wednesday, May 13, 2009 24
- 25. Actions
// create the actions
action(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'
)
© Jim Shingler
Wednesday, May 13, 2009 25
- 26. Controller
import javax.swing.JOptionPane
class 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''')
}
}
© Jim Shingler
Wednesday, May 13, 2009 26
- 27. Twitter Clone
Enhancements
© Jim Shingler
Wednesday, May 13, 2009 27
- 28. Render Status XML
import 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)}
}
}
. . .
© Jim Shingler
Wednesday, May 13, 2009 28
- 29. 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 }
}
}
...
© Jim Shingler
Wednesday, May 13, 2009 29
- 30. 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]
}
© Jim Shingler
Wednesday, May 13, 2009 30
- 31. Acegi Basic
Authentication
grails-app/conf/SecurityConfig.groovy
security {
// see DefaultSecurityConfig.groovy for all settable/overridable properties
active = true
basicProcessingFilter = true
loginUserDomainClass = "Person"
authorityDomainClass = "Authority"
requestMapClass = "Requestmap"
}
© Jim Shingler
Wednesday, May 13, 2009 31
- 32. Acegi Basic
Authentication
grails-app/conf/spring/resources.groovy
beans = {
authenticationEntryPoint(org.springframework.security.ui.basicauth.
BasicProcessingFilterEntryPoint) {
realmName = 'Grails Realm'
}
twitterCache(org.springframework.cache.ehcache.EhCacheFactoryBean) {
timeToLive = 1200
}
}
© Jim Shingler
Wednesday, May 13, 2009 32
- 34. Requirements
• Login
• Display User Info
• Display Statuses (Tweets)
• Update Statuses(Tweets)
• Send My Own Status (Tweet)
© Jim Shingler
Wednesday, May 13, 2009 34
- 35. Overview
MVC Triad
MenuBar
Controller View
ToolBar
StatusBar
Model Tips
About
Twitter Service
</xml>
Twitter Clone
© Jim Shingler
Wednesday, May 13, 2009 35
- 36. Let’s get to
Work
© Jim Shingler
Wednesday, May 13, 2009 36
- 37. Login Refresh ToolBar
User Info
Statuses / Tweets
Update
Status
© Jim Shingler
Wednesday, May 13, 2009 37
- 46. The Code
http://github.com/jshingler/gr8conf_2009/tree/master
© Jim Shingler
Wednesday, May 13, 2009 46
- 47. Founders
Danno Ferrin
http://shemnon.com/speling
Andres Almiray
http://jroller.com/aalmiray
James Williams
http://jameswilliams.be/blog
© Jim Shingler
Wednesday, May 13, 2009 47
- 48. Resources
• Griffon
• griffon.codehause.org
• griffon-user@groovy.codehause.org
• Grails
• www.grails.org
Coming
• Books Soon
© Jim Shingler
Wednesday, May 13, 2009 48
- 49. 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.
© Jim Shingler
Wednesday, May 13, 2009 49
- 50. Conclusion
Thank You for your time
• Blog:
http://jshingler.blogspot.com
• Email:
ShinglerJim@gmail.com
• LinkedIn:
http://www.linkedin.com/in/jimshingler
• Twitter:
@jshingler
© Jim Shingler
Wednesday, May 13, 2009 50