3. 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 applicaiton to interact with a Grails backend.
4. 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
6. Griffon Founders
Danno Ferrin
http://shemnon.com/speling
Andres Almiray
http://jroller.com/aalmiray
James Williams
http://jameswilliams.be/blog
7. Common Complaints
about Swing
Its hard
Have to code too much
Code is complex
Not many Advanced GUI Components (Myth)
8. Start Small
• Swing and SwingX Builder
• GUI Components
• About Box
• Define and Process Actions
9. Builders
The Builder Pattern is a software design pattern. The
intention is to separate the construction of a
complex object from its representation so that the
same construction process can create different
representations.
Often, the Build Patter is used to build Products in
accordance to the Composite pattern.
Swing is a complex hierarchy, . . .
Source: Wikipedia
Sounds like an opportunity
10. GUI Builders
• SwingBuilder
Applies the Builder Pattern to the construction of Swing
“Makes Swing Groovy”
• SwingXBuilder
Extends SwingBuilder adding the SwingLabs Components
• JideBuilder
Extends SwingBuilder adding JIDE Components
• SWTBuilder
Applies the Builder Pattern to the construction of SWT
“Makes SWT Groovy”
11. Plugins
A plugin is a Griffon extension point. Conceptually, it
is similar to the plugins found in modern IDEs.
A plugin is a technique to encapsulate functionality
that can be reused across multiple applications.
Griffon’s plugin community has just begun but it is
growing fast.
See: >griffon list-plugins
http://grails.org/Plugins
http://www.grails.org/The+Plug-in+Developers+Guide
12. 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
13. 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 NOTE:
The Code included on the
next several pages has
been enhanced based
upon questions asked in
the session.
14. Controller
import javax.swing.JOptionPane
class Sample2Controller {
// these will be injected by Griffon
def model
def view
void mvcGroupInit(Map args) {
// this method is called after model and view are injected
}
def click = { evt = null ->
model.count++
}
def exit = { evt = null ->
System.exit(0)
}
def showAbout = { evt = null ->
JOptionPane.showMessageDialog(null,
'''This is the SimpleUI Application''')
}
}
20. Goal
Menu Bar
Tool Bar
Login Dialog
Content Area
Tips Dialog
Status Bar
21. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
22. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
23. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
24. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
25. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
26. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area Glazed Lists
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
27. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area Glazed Lists
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
28. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area Glazed Lists
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
29. Planning
• Menu Bar
• Tool Bar
• Status Bar
• About Box
• Tips
• Login Dialog
• Master / Detail Content Area Glazed Lists
•Table and Fields
• Wire it together with Actions
• Make calls to Web Services
33. Organization
Menu Bar
Controller View
Model
Griffon Framework
34. Organization
Menu Bar
Controller View
About Dialog
Model
Griffon Framework
35. Organization
Menu Bar
Controller View
About Dialog
Content Pane
Model
Griffon Framework
36. Organization
Menu Bar
Controller View
About Dialog
Content Pane
Model
Tool Bar
Griffon Framework
37. Organization
Menu Bar
Controller View
About Dialog
Content Pane
Model
Tool Bar
Status Bar
Griffon Framework
38. Organization
Menu Bar
Controller View
About Dialog
Content Pane
Model
Tool Bar
Services
Status Bar
Griffon Framework
39. Organization
Menu Bar
Controller View
About Dialog
Content Pane
Model
Tool Bar
Services
Status Bar
Http Utils
Get
Griffon Framework
Put
Post
Delete
40. Organization
Menu Bar
Controller View
About Dialog
Content Pane
Model
Tool Bar
Services
Status Bar
Http Utils
Get
Griffon Framework
Put
Post
Delete
Rest Controller
41. Interaction with
RESTful WebServices
SQL HTTP Grails
Action
Method Method Convention
Create INSERT PUT create
Read SELECT GET show
Update UPDATE POST update
Delete DELETE DELETE delete
Collect SELECT list
42. Loading Data
class GCollabTodoController {
...
void loadData() {
setStatus(quot;Loading Dataquot;)
busy
model.todos.clear()
model.todos.addAll (TodoService.list(appContext))
norm
setStatus(quot;Finished Loading Dataquot;)
}
class TodoService {
static String APP_URL = 'http://localhost:8080/collab-todo/json/todo'
static List list(appContext) {
def userContext = appContext.userContext
def get = new Get(url: APP_URL,
userName: userContext.userName,
password: userContext.password)
def todoJson = get.text
def str = JsonUtil.makeJSONStrict(todoJson)
def jsonarray = JSONSerializer.toJSON(str)
def todo
def outputList = []
jsonarray.each {
todo = JsonUtil.jsonToObject(it.toString(), Todo.class)
outputList.add todo
}
return outputList
}
50. class UserInfoController {
def index = { redirect(action:show,params:params) }
def show = {
def result = session.user
format(result)
}
def beforeInterceptor = {
def authHeader = request.getHeader(quot;Authorizationquot;)
if (authHeader) {
def tokens = authHeader.split(' ')
def user_password = tokens[1]
tokens = user_password.split(':')
def userid = tokens[0]
def password = tokens[1]
// At this point, the userid and password could be verified
// to make sure that the person making the request is authenticated
//
// << AUTHENTICATION LOGIC / CALL >>
//
// Put look up the user object and put it into session for use
// later by the controllers.
def user = User.findByUserName(userid)
if (user) {
session.user = user
} else {
session.user = null
}
}
}
private format(obj) {
def restType = (params.rest == quot;restquot;)?quot;XMLquot;:quot;JSONquot;
println obj.quot;encodeAs$restTypequot;()
render obj.quot;encodeAs$restTypequot;()
}
}
51. class UserInfoController {
def index = { redirect(action:show,params:params) }
def show = {
def result = session.user
format(result)
}
def beforeInterceptor = {
def authHeader = request.getHeader(quot;Authorizationquot;)
if (authHeader) {
def tokens = authHeader.split(' ')
def user_password = tokens[1]
tokens = user_password.split(':')
def userid = tokens[0]
def password = tokens[1]
// At this point, the userid and password could be verified
// to make sure that the person making the request is authenticated
//
// << AUTHENTICATION LOGIC / CALL >>
//
// Put look up the user object and put it into session for use
// later by the controllers.
def user = User.findByUserName(userid)
if (user) {
session.user = user
} else {
session.user = null
}
}
}
private format(obj) {
def restType = (params.rest == quot;restquot;)?quot;XMLquot;:quot;JSONquot;
println obj.quot;encodeAs$restTypequot;()
render obj.quot;encodeAs$restTypequot;()
}
}
59. Resources
• Introduction to Groovy
• Groovy Basics
• More Advanced Groovy
• Introduction to Grails
• Building the User Interface
• Building Domains and Services
• Security in Grails
• Web 2.0—Ajax and Friends
• Web Services
• Reporting
• Batch Processing
• Deploying and Upgrading
• Alternative Clients
62. Conclusion
Thank You for your time
• Blog:
http://jshingler.blogspot.com
• Email:
ShinglerJim@gmail.com
• LinkedIn:
http://www.linkedin.com/in/jimshingler
• Twitter:
http://www.twitter.com/jshingler