Griffon In Front Grails In Back

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    8 Favorites

    Griffon In Front Grails In Back - Presentation Transcript

    1. Griffon in Front Grails in Back Leveraging Grails with Griffon
    2. Griffon in Front Grails in Back Leveraging Grails with Griffon
    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
    5. Griffon Founders
    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''') } }
    15. Model import groovy.beans.Bindable @Bindable class Sample2Model { def count = 0 }
    16. View 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) } MenuBar jxmenuBar { menu(text: 'File', mnemonic: 'F') { menuItem(exitAction) } glue() menu(text: 'Help', mnemonic: 'H') { menuItem(aboutAction) } }
    17. Actions // create the actions action(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' )
    18. Goal
    19. Goal Menu Bar Tool Bar Content Area Status Bar
    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
    30. Organization MVC Triad Controller View Model
    31. Organization MVC Triad Controller View Model Griffon Framework
    32. Organization Controller View Model Griffon Framework
    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(\"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 }
    43. Let’s Look at the Code
    44. class Get{ String url QueryString queryString = new QueryString() String text Get (HttpUtils) 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() }
    45. 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 } }
    46. Service Save static 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 }
    47. package http.utils class Put{ String url QueryString queryString = new QueryString() String content Put (HttpUtils) 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() } }
    48. RESTFul WebServices
    49. 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\"() } }
    50. 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\"() } }
    51. Other Griffon Apps
    52. http://github.com/jshingler/gcollabtodo/tree/master
    53. 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
    54. Resources • Griffon • griffon.codehause.org • griffon-user@groovy.codehause.org • Grails • www.grails.org Coming • Books Soon
    55. Resources • SwingLabs • swinglabs.org • MigLayout • miglayout.org • GlazedLists • publicobject.com/glazedlists
    56. 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

    + jshinglerjshingler, 10 months ago

    custom

    3608 views, 8 favs, 1 embeds more stats

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 3608
      • 3550 on SlideShare
      • 58 from embeds
    • Comments 0
    • Favorites 8
    • Downloads 116
    Most viewed embeds
    • 58 views on http://www.grails66.com

    more

    All embeds
    • 58 views on http://www.grails66.com

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Categories