+ All Categories
Home > Technology > Griffon In Front Grails In Back

Griffon In Front Grails In Back

Date post: 17-May-2015
Category:
Upload: jim-shingler
View: 14,377 times
Download: 0 times
Share this document with a friend
Popular Tags:
62
Griffon in Front Grails in Back Leveraging Grails with Griffon
Transcript
Page 1: Griffon In Front Grails In Back

Griffon in FrontGrails in Back

Leveraging Grails with Griffon

Page 2: Griffon In Front Grails In Back

Griffon in FrontGrails in Back

Leveraging Grails with Griffon

Page 3: Griffon In Front Grails In Back

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 applicaiton to interact with a Grails backend.

Page 4: Griffon In Front Grails In Back

IntroductionMy name is Jim Shingler

Chief Technical Architect

President of Genuine Solutions

Beginning Groovy and GrailsCo-Author

FallME (Inversion of Control for JavaME)Co-Founder

Page 5: Griffon In Front Grails In Back

Griffon Founders

Page 6: Griffon In Front Grails In Back

Griffon Founders

Danno Ferrinhttp://shemnon.com/speling

Andres Almirayhttp://jroller.com/aalmiray

James Williamshttp://jameswilliams.be/blog

Page 7: Griffon In Front Grails In Back

Common Complaints about Swing

Its hardHave to code too muchCode is complexNot many Advanced GUI Components (Myth)

Page 8: Griffon In Front Grails In Back

Start Small

• Swing and SwingX Builder

• GUI Components

• About Box

• Define and Process Actions

Page 9: Griffon In Front Grails In Back

BuildersThe 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.

Source: Wikipedia Swing is a complex hierarchy, . . . Sounds like an opportunity

Page 10: Griffon In Front Grails In Back

GUI Builders• SwingBuilder

Applies the Builder Pattern to the construction of Swing “Makes Swing Groovy”

• SwingXBuilderExtends SwingBuilder adding the SwingLabs Components

• JideBuilderExtends SwingBuilder adding JIDE Components

• SWTBuilderApplies the Builder Pattern to the construction of SWT“Makes SWT Groovy”

Page 11: Griffon In Front Grails In Back

PluginsA 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/Pluginshttp://www.grails.org/The+Plug-in+Developers+Guide

Page 12: Griffon In Front Grails In Back

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

Page 13: Griffon In Front Grails In Back

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.

Page 14: Griffon In Front Grails In Back

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''') }}

Page 15: Griffon In Front Grails In Back

Model

import groovy.beans.Bindable

@Bindableclass Sample2Model { def count = 0}

Page 16: Griffon In Front Grails In Back

Viewapplication(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

Page 17: Griffon In Front Grails In Back

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' )

Page 18: Griffon In Front Grails In Back

Goal

Page 19: Griffon In Front Grails In Back

GoalMenu Bar

Tool Bar

Content Area

Status Bar

Page 20: Griffon In Front Grails In Back

GoalMenu Bar

Tool Bar

Content Area

Status Bar

Tips Dialog

Login Dialog

Page 21: Griffon In Front Grails In Back

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

Page 22: Griffon In Front Grails In Back

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

Page 23: Griffon In Front Grails In Back

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

Page 24: Griffon In Front Grails In Back

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

Page 25: Griffon In Front Grails In Back

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

Page 26: Griffon In Front Grails In Back

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

Glazed Lists

Page 27: Griffon In Front Grails In Back

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

Glazed Lists

Page 28: Griffon In Front Grails In Back

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

Glazed Lists

Page 29: Griffon In Front Grails In Back

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

Glazed Lists

Page 30: Griffon In Front Grails In Back

OrganizationController View

Model

MVC Triad

Page 31: Griffon In Front Grails In Back

OrganizationController View

Model

MVC Triad

Griffon Framework

Page 32: Griffon In Front Grails In Back

OrganizationController View

Model

Griffon Framework

Page 33: Griffon In Front Grails In Back

OrganizationController View

Menu Bar

Model

Griffon Framework

Page 34: Griffon In Front Grails In Back

OrganizationController View

Menu Bar

About Dialog

Model

Griffon Framework

Page 35: Griffon In Front Grails In Back

OrganizationController View

Menu Bar

Content Pane

About Dialog

Model

Griffon Framework

Page 36: Griffon In Front Grails In Back

OrganizationController View

Menu Bar

Content Pane

Tool Bar

About Dialog

Model

Griffon Framework

Page 37: Griffon In Front Grails In Back

OrganizationController View

Menu Bar

Content Pane

Tool Bar

Status Bar

About Dialog

Model

Griffon Framework

Page 38: Griffon In Front Grails In Back

OrganizationController View

Menu Bar

Content Pane

Tool Bar

Status Bar

About Dialog

Model

Griffon Framework

Services

Page 39: Griffon In Front Grails In Back

OrganizationController

Http UtilsGetPutPost

Delete

ViewMenu Bar

Content Pane

Tool Bar

Status Bar

About Dialog

Model

Griffon Framework

Services

Page 40: Griffon In Front Grails In Back

OrganizationController

Http UtilsGetPutPost

Delete

Rest Controller

ViewMenu Bar

Content Pane

Tool Bar

Status Bar

About Dialog

Model

Griffon Framework

Services

Page 41: Griffon In Front Grails In Back

Interaction with RESTful WebServicesAction SQL

MethodHTTP

MethodGrails

Convention

Create INSERT PUT create

Read SELECT GET show

Update UPDATE POST update

Delete DELETE DELETE delete

Collect SELECT list

Page 42: Griffon In Front Grails In Back

Loading Data class GCollabTodoController { . . .

void loadData() { setStatus("Loading Data") busy model.todos.clear() model.todos.addAll (TodoService.list(appContext))

norm setStatus("Finished Loading Data") }

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 }

Page 43: Griffon In Front Grails In Back

Let’s Look at the Code

Page 44: Griffon In Front Grails In Back

package http.utils

class Get{ String url QueryString queryString = new QueryString() String text def userName def password String getText() try { def response def conn = new URL(toString()).openConnection() conn.requestMethod = "GET" conn.doOutput = true

if (userName && password) { conn.setRequestProperty("Authorization", "Basic ${userName}:${password}") } def content if (conn.responseCode == conn.HTTP_OK) { response = conn.content.text } else { response = "URL: " + this.toString() + "\n" + "RESPONSE CODE: " + conn.responseCode throw new ResourceException(response) } conn.disconnect() return response } catch (Exception e) { println "Caught Exception ${e}" throw new ResourceException(e) } } String toString(){ return url + "?" + queryString.toString() }}

Get (HttpUtils)

Page 45: Griffon In Front Grails In Back

Save Todo void saveTodo(event) { fillSelectedTodoFromView() def todo = selectedTodo()

if(shouldBeSaved(todo)) { execWithExceptionHandling { TodoService.save(appContext, todo) loadData() } } else { JOptionPane.showMessageDialog(frame, "If this had been a completed application the Todo would have been updated:") } } private boolean shouldBeSaved(todo) { if (todo.id == "" || !todo.id ) { return true } return false } private void fillSelectedTodoFromView() { selectedTodo().with { name = view.nameTextField?.text priority = view.priorityComboBox?.selectedItem selectedTodo().status = view.statusComboBox?.selectedItem completedDate = view.completedDateField?.date createdDate = view.createDateField?.date dueDate = view.dueDateField?.date note = view.noteTextField?.text } }

Page 46: Griffon In Front Grails In Back

Service Savestatic void save(appContext, todo) { def userContext = appContext.userContext def put = new Put(url: APP_URL, userName: userContext.userName, password: userContext.password) put.queryString.add("name", todo.name) put.queryString.add("priority", todo.priority) put.queryString.add("status", todo.status) put.queryString.add("note", todo.note) put.queryString.add("owner.id", userContext.id) put.queryString.addDate("createdDate", todo.createdDate) def putResponse = put.text }

Page 47: Griffon In Front Grails In Back

package http.utilsclass Put{ String url QueryString queryString = new QueryString() String content String contentType String text def userName def password String getText(){ def conn = new URL(url).openConnection() conn.setRequestMethod("PUT" ) conn.setRequestProperty("Content-Type" , contentType) conn.doOutput = true conn.doInput = true if (userName && password) { conn.setRequestProperty("Authorization", "Basic ${userName}:${password}") } conn.outputStream.withWriter { out -> out.write(queryString.toString()) out.flush() out.close() } def response if (conn.HTTP_OK == conn?.responseCode) { response = conn.content.text } else { response = "URL: " + this.toString() + "\n" + "RESPONSE CODE: " + responseCode } conn.disconnect() return response } String toString(){ return url + "?" + queryString.toString() }}

Put (HttpUtils)

Page 48: Griffon In Front Grails In Back
Page 49: Griffon In Front Grails In Back

RESTFul WebServices

Page 50: Griffon In Front Grails In Back

class UserInfoController { def index = { redirect(action:show,params:params) }

def show = { def result = session.user format(result) }

def beforeInterceptor = {

def authHeader = request.getHeader("Authorization") 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 == "rest")?"XML":"JSON" println obj."encodeAs$restType"() render obj."encodeAs$restType"() }

}

Page 51: Griffon In Front Grails In Back

class UserInfoController { def index = { redirect(action:show,params:params) }

def show = { def result = session.user format(result) }

def beforeInterceptor = {

def authHeader = request.getHeader("Authorization") 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 == "rest")?"XML":"JSON" println obj."encodeAs$restType"() render obj."encodeAs$restType"() }

}

Page 52: Griffon In Front Grails In Back

Other Griffon Apps

Page 53: Griffon In Front Grails In Back
Page 54: Griffon In Front Grails In Back
Page 55: Griffon In Front Grails In Back
Page 56: Griffon In Front Grails In Back
Page 57: Griffon In Front Grails In Back
Page 59: Griffon In Front Grails In Back

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

Page 60: Griffon In Front Grails In Back

Resources• Griffon

• griffon.codehause.org• [email protected]

• Grails• www.grails.org

• BooksComing

Soon

Page 61: Griffon In Front Grails In Back

Resources• SwingLabs

• swinglabs.org• MigLayout

• miglayout.org• GlazedLists

• publicobject.com/glazedlists

Page 62: Griffon In Front Grails In Back

Conclusion

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

• Email: [email protected]

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

• Twitter: http://www.twitter.com/jshingler

Thank You for your time


Recommended