SlideShare uma empresa Scribd logo
1 de 62
Baixar para ler offline
Griffon in Front
 Grails in Back
 Leveraging Grails with Griffon
Griffon in Front
 Grails in Back
 Leveraging Grails with Griffon
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.
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 Founders
Griffon Founders

   Danno Ferrin
   http://shemnon.com/speling

   Andres Almiray
   http://jroller.com/aalmiray

   James Williams
   http://jameswilliams.be/blog
Common Complaints
   about Swing
Its hard
Have to code too much
Code is complex
Not many Advanced GUI Components (Myth)
Start Small
• Swing and SwingX Builder
• GUI Components
• About Box
• Define and Process Actions
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
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”
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
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
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.
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''')
    }
}
Model
import groovy.beans.Bindable

@Bindable
class Sample2Model {
    def count = 0
}
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)
                       }
                   }
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'
         )
Goal
Goal
 Menu Bar
  Tool Bar




Content Area




 Status Bar
Goal
 Menu Bar
  Tool Bar
Login Dialog


Content Area




 Tips Dialog




 Status Bar
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
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
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
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
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
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
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
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
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
Organization
             MVC Triad
Controller               View



                Model
Organization
             MVC Triad
Controller                View



                Model




                        Griffon Framework
Organization
Controller              View



              Model




                      Griffon Framework
Organization
                                     Menu Bar
Controller              View



              Model




                      Griffon Framework
Organization
                                     Menu Bar
Controller              View
                                    About Dialog


              Model




                      Griffon Framework
Organization
                                     Menu Bar
Controller              View
                                    About Dialog

                                    Content Pane
              Model




                      Griffon Framework
Organization
                                     Menu Bar
Controller              View
                                    About Dialog

                                    Content Pane
              Model
                                      Tool Bar




                      Griffon Framework
Organization
                                     Menu Bar
Controller              View
                                    About Dialog

                                    Content Pane
              Model
                                      Tool Bar

                                     Status Bar




                      Griffon Framework
Organization
                                     Menu Bar
Controller              View
                                    About Dialog

                                    Content Pane
              Model
                                      Tool Bar
 Services
                                     Status Bar




                      Griffon Framework
Organization
                                     Menu Bar
Controller              View
                                    About Dialog

                                    Content Pane
              Model
                                      Tool Bar
 Services
                                     Status Bar


Http Utils
   Get

                      Griffon Framework
   Put
  Post
 Delete
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
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
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
                                }
Let’s Look at the Code
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 = quot;GETquot;
             conn.doOutput = true

            if (userName && password) {
                conn.setRequestProperty(quot;Authorizationquot;, quot;Basic ${userName}:${password}quot;)
            }

            def content
            if (conn.responseCode == conn.HTTP_OK) {
                 response = conn.content.text
            } else {
            response = quot;URL: quot; + this.toString() + quot;nquot; +
                 quot;RESPONSE CODE: quot; + conn.responseCode
                 throw new ResourceException(response)
             }
            conn.disconnect()
            return response
        } catch (Exception e) {
            println quot;Caught Exception ${e}quot;
            throw new ResourceException(e)
        }
    }

   String toString(){
        return url + quot;?quot; + queryString.toString()
   }
Save Todo
void saveTodo(event) {
     fillSelectedTodoFromView()

    def todo = selectedTodo()

     if(shouldBeSaved(todo)) {
         execWithExceptionHandling {
              TodoService.save(appContext, todo)
             loadData()
         }
    } else {
        JOptionPane.showMessageDialog(frame,
           quot;If this had been a completed application the Todo would have been updated:quot;)
    }
}

private boolean shouldBeSaved(todo) {
    if (todo.id == quot;quot; || !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
    }
}
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(quot;namequot;, todo.name)
        put.queryString.add(quot;priorityquot;, todo.priority)
        put.queryString.add(quot;statusquot;, todo.status)
        put.queryString.add(quot;notequot;, todo.note)
        put.queryString.add(quot;owner.idquot;, userContext.id)
        put.queryString.addDate(quot;createdDatequot;, todo.createdDate)

        def putResponse = put.text
    }
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(quot;PUTquot; )
         conn.setRequestProperty(quot;Content-Typequot; , contentType)
         conn.doOutput = true
         conn.doInput = true

         if (userName && password) {
            conn.setRequestProperty(quot;Authorizationquot;, quot;Basic ${userName}:${password}quot;)
         }

         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 = quot;URL: quot; + this.toString() + quot;nquot; +
              quot;RESPONSE CODE: quot; + responseCode
         }
    conn.disconnect()
    return response
    }

    String toString(){
          return url + quot;?quot; + queryString.toString()
     }
}
RESTFul WebServices
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;()
    }

}
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;()
    }

}
Other Griffon Apps
http://github.com/jshingler/gcollabtodo/tree/master
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
Resources
• Griffon
  • griffon.codehause.org
  • griffon-user@groovy.codehause.org
• Grails
  • www.grails.org
                                        Coming
• Books                                  Soon
Resources
• SwingLabs
  • swinglabs.org
• MigLayout
  • miglayout.org
• GlazedLists
  • publicobject.com/glazedlists
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

Mais conteúdo relacionado

Semelhante a Griffon In Front Grails In Back

SAP WEBDYNPRO ABAP TRAINING
SAP WEBDYNPRO ABAP TRAININGSAP WEBDYNPRO ABAP TRAINING
SAP WEBDYNPRO ABAP TRAININGSanthosh Sap
 
Leveraging the Ribbon API and Dialog Framework
Leveraging the Ribbon API and Dialog FrameworkLeveraging the Ribbon API and Dialog Framework
Leveraging the Ribbon API and Dialog FrameworkCory Peters
 
JavaOne 2009 BOF-5189 Griffon In Depth
JavaOne 2009 BOF-5189 Griffon In DepthJavaOne 2009 BOF-5189 Griffon In Depth
JavaOne 2009 BOF-5189 Griffon In DepthDanno Ferrin
 
Accessibility: A Journey to Accessible Rich Components
Accessibility: A Journey to Accessible Rich ComponentsAccessibility: A Journey to Accessible Rich Components
Accessibility: A Journey to Accessible Rich ComponentsAchievers Tech
 
Windows Presentation Foundation
Windows Presentation FoundationWindows Presentation Foundation
Windows Presentation FoundationTran Ngoc Son
 
Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3
Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3
Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3Doris Chen
 
Cake php concept to deployment
Cake php concept to deploymentCake php concept to deployment
Cake php concept to deploymentilsanbao
 
Cake php 1 3 concept to deployment presentation
Cake php 1 3 concept to deployment presentationCake php 1 3 concept to deployment presentation
Cake php 1 3 concept to deployment presentationlaminbarrow
 
Beyond the Basics, Debugging with Firebug and Web Inspector
Beyond the Basics, Debugging with Firebug and Web InspectorBeyond the Basics, Debugging with Firebug and Web Inspector
Beyond the Basics, Debugging with Firebug and Web InspectorSteven Roussey
 
Django Developer Certification
Django Developer CertificationDjango Developer Certification
Django Developer CertificationVskills
 
Asp.Net MVC Framework Design Pattern
Asp.Net MVC Framework Design PatternAsp.Net MVC Framework Design Pattern
Asp.Net MVC Framework Design Patternmaddinapudi
 
SAP Inside Track 2010 - Thomas Jung Intro to WDA
SAP Inside Track 2010 - Thomas Jung Intro to WDASAP Inside Track 2010 - Thomas Jung Intro to WDA
SAP Inside Track 2010 - Thomas Jung Intro to WDAsjohannes
 
JavaScript and DOM Pattern Implementation
JavaScript and DOM Pattern ImplementationJavaScript and DOM Pattern Implementation
JavaScript and DOM Pattern Implementationdavejohnson
 
Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016Sergey Polischook
 
Zend con 2016 bdd with behat for beginners
Zend con 2016   bdd with behat for beginnersZend con 2016   bdd with behat for beginners
Zend con 2016 bdd with behat for beginnersAdam Englander
 
The Google App Engine Oil Framework
The Google App Engine Oil FrameworkThe Google App Engine Oil Framework
The Google App Engine Oil FrameworkEric ShangKuan
 
MOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentMOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentanistar sung
 

Semelhante a Griffon In Front Grails In Back (20)

Sap webdynpro abap training
Sap webdynpro abap trainingSap webdynpro abap training
Sap webdynpro abap training
 
SAP WEBDYNPRO ABAP TRAINING
SAP WEBDYNPRO ABAP TRAININGSAP WEBDYNPRO ABAP TRAINING
SAP WEBDYNPRO ABAP TRAINING
 
Leveraging the Ribbon API and Dialog Framework
Leveraging the Ribbon API and Dialog FrameworkLeveraging the Ribbon API and Dialog Framework
Leveraging the Ribbon API and Dialog Framework
 
JavaOne 2009 BOF-5189 Griffon In Depth
JavaOne 2009 BOF-5189 Griffon In DepthJavaOne 2009 BOF-5189 Griffon In Depth
JavaOne 2009 BOF-5189 Griffon In Depth
 
Accessibility: A Journey to Accessible Rich Components
Accessibility: A Journey to Accessible Rich ComponentsAccessibility: A Journey to Accessible Rich Components
Accessibility: A Journey to Accessible Rich Components
 
Windows Presentation Foundation
Windows Presentation FoundationWindows Presentation Foundation
Windows Presentation Foundation
 
Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3
Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3
Building Beautiful and Interactive Metro apps with JavaScript, HTML5 & CSS3
 
Cake php concept to deployment
Cake php concept to deploymentCake php concept to deployment
Cake php concept to deployment
 
Cake php 1 3 concept to deployment presentation
Cake php 1 3 concept to deployment presentationCake php 1 3 concept to deployment presentation
Cake php 1 3 concept to deployment presentation
 
Beyond the Basics, Debugging with Firebug and Web Inspector
Beyond the Basics, Debugging with Firebug and Web InspectorBeyond the Basics, Debugging with Firebug and Web Inspector
Beyond the Basics, Debugging with Firebug and Web Inspector
 
Django Developer Certification
Django Developer CertificationDjango Developer Certification
Django Developer Certification
 
Asp.Net Mvc Dev Days09
Asp.Net Mvc Dev Days09Asp.Net Mvc Dev Days09
Asp.Net Mvc Dev Days09
 
Asp.Net MVC Framework Design Pattern
Asp.Net MVC Framework Design PatternAsp.Net MVC Framework Design Pattern
Asp.Net MVC Framework Design Pattern
 
SAP Inside Track 2010 - Thomas Jung Intro to WDA
SAP Inside Track 2010 - Thomas Jung Intro to WDASAP Inside Track 2010 - Thomas Jung Intro to WDA
SAP Inside Track 2010 - Thomas Jung Intro to WDA
 
JavaScript and DOM Pattern Implementation
JavaScript and DOM Pattern ImplementationJavaScript and DOM Pattern Implementation
JavaScript and DOM Pattern Implementation
 
Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016Behat internals for advanced usage. Symfony Camp 2016
Behat internals for advanced usage. Symfony Camp 2016
 
Zend con 2016 bdd with behat for beginners
Zend con 2016   bdd with behat for beginnersZend con 2016   bdd with behat for beginners
Zend con 2016 bdd with behat for beginners
 
Appengine Nljug
Appengine NljugAppengine Nljug
Appengine Nljug
 
The Google App Engine Oil Framework
The Google App Engine Oil FrameworkThe Google App Engine Oil Framework
The Google App Engine Oil Framework
 
MOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app developmentMOPCON 2014 - Best software architecture in app development
MOPCON 2014 - Best software architecture in app development
 

Mais de Jim Shingler

HIPAA Solutions on Cloud Foundry
HIPAA Solutions on Cloud FoundryHIPAA Solutions on Cloud Foundry
HIPAA Solutions on Cloud FoundryJim Shingler
 
DevOps is a Journey, Not an Event
DevOps is a Journey, Not an EventDevOps is a Journey, Not an Event
DevOps is a Journey, Not an EventJim Shingler
 
Personal Healthcare IOT on PCF using Spring
Personal Healthcare IOT on PCF using SpringPersonal Healthcare IOT on PCF using Spring
Personal Healthcare IOT on PCF using SpringJim Shingler
 
S1 2GX 2011 - Content Management with a Custom CMS
S1 2GX 2011 - Content Management with a Custom CMS S1 2GX 2011 - Content Management with a Custom CMS
S1 2GX 2011 - Content Management with a Custom CMS Jim Shingler
 
S1 2GX 2011 - Using Grails on a public facing Fortune 500 website
S1 2GX 2011 - Using Grails on a public facing  Fortune 500 website S1 2GX 2011 - Using Grails on a public facing  Fortune 500 website
S1 2GX 2011 - Using Grails on a public facing Fortune 500 website Jim Shingler
 
Gg Code Mash2009 20090106
Gg Code Mash2009 20090106Gg Code Mash2009 20090106
Gg Code Mash2009 20090106Jim Shingler
 

Mais de Jim Shingler (6)

HIPAA Solutions on Cloud Foundry
HIPAA Solutions on Cloud FoundryHIPAA Solutions on Cloud Foundry
HIPAA Solutions on Cloud Foundry
 
DevOps is a Journey, Not an Event
DevOps is a Journey, Not an EventDevOps is a Journey, Not an Event
DevOps is a Journey, Not an Event
 
Personal Healthcare IOT on PCF using Spring
Personal Healthcare IOT on PCF using SpringPersonal Healthcare IOT on PCF using Spring
Personal Healthcare IOT on PCF using Spring
 
S1 2GX 2011 - Content Management with a Custom CMS
S1 2GX 2011 - Content Management with a Custom CMS S1 2GX 2011 - Content Management with a Custom CMS
S1 2GX 2011 - Content Management with a Custom CMS
 
S1 2GX 2011 - Using Grails on a public facing Fortune 500 website
S1 2GX 2011 - Using Grails on a public facing  Fortune 500 website S1 2GX 2011 - Using Grails on a public facing  Fortune 500 website
S1 2GX 2011 - Using Grails on a public facing Fortune 500 website
 
Gg Code Mash2009 20090106
Gg Code Mash2009 20090106Gg Code Mash2009 20090106
Gg Code Mash2009 20090106
 

Último

Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 3652toLead Limited
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfAddepto
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024BookNet Canada
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsSergiu Bodiu
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyAlfredo García Lavilla
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesZilliz
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brandgvaughan
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfRankYa
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsMark Billinghurst
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsMemoori
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxNavinnSomaal
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clashcharlottematthew16
 

Último (20)

Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365Ensuring Technical Readiness For Copilot in Microsoft 365
Ensuring Technical Readiness For Copilot in Microsoft 365
 
Gen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdfGen AI in Business - Global Trends Report 2024.pdf
Gen AI in Business - Global Trends Report 2024.pdf
 
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC CataList - Tech Forum 2024
 
DevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platformsDevEX - reference for building teams, processes, and platforms
DevEX - reference for building teams, processes, and platforms
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
Commit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easyCommit 2024 - Secret Management made easy
Commit 2024 - Secret Management made easy
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Vector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector DatabasesVector Databases 101 - An introduction to the world of Vector Databases
Vector Databases 101 - An introduction to the world of Vector Databases
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
WordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your BrandWordPress Websites for Engineers: Elevate Your Brand
WordPress Websites for Engineers: Elevate Your Brand
 
Search Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdfSearch Engine Optimization SEO PDF for 2024.pdf
Search Engine Optimization SEO PDF for 2024.pdf
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Human Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR SystemsHuman Factors of XR: Using Human Factors to Design XR Systems
Human Factors of XR: Using Human Factors to Design XR Systems
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
AI as an Interface for Commercial Buildings
AI as an Interface for Commercial BuildingsAI as an Interface for Commercial Buildings
AI as an Interface for Commercial Buildings
 
SAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptxSAP Build Work Zone - Overview L2-L3.pptx
SAP Build Work Zone - Overview L2-L3.pptx
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Powerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time ClashPowerpoint exploring the locations used in television show Time Clash
Powerpoint exploring the locations used in television show Time Clash
 
DMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special EditionDMCC Future of Trade Web3 - Special Edition
DMCC Future of Trade Web3 - Special Edition
 

Griffon In Front Grails In Back

  • 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
  • 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''') } }
  • 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(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 }
  • 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 = quot;GETquot; conn.doOutput = true if (userName && password) { conn.setRequestProperty(quot;Authorizationquot;, quot;Basic ${userName}:${password}quot;) } def content if (conn.responseCode == conn.HTTP_OK) { response = conn.content.text } else { response = quot;URL: quot; + this.toString() + quot;nquot; + quot;RESPONSE CODE: quot; + conn.responseCode throw new ResourceException(response) } conn.disconnect() return response } catch (Exception e) { println quot;Caught Exception ${e}quot; throw new ResourceException(e) } } String toString(){ return url + quot;?quot; + 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, quot;If this had been a completed application the Todo would have been updated:quot;) } } private boolean shouldBeSaved(todo) { if (todo.id == quot;quot; || !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(quot;namequot;, todo.name) put.queryString.add(quot;priorityquot;, todo.priority) put.queryString.add(quot;statusquot;, todo.status) put.queryString.add(quot;notequot;, todo.note) put.queryString.add(quot;owner.idquot;, userContext.id) put.queryString.addDate(quot;createdDatequot;, 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(quot;PUTquot; ) conn.setRequestProperty(quot;Content-Typequot; , contentType) conn.doOutput = true conn.doInput = true if (userName && password) { conn.setRequestProperty(quot;Authorizationquot;, quot;Basic ${userName}:${password}quot;) } 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 = quot;URL: quot; + this.toString() + quot;nquot; + quot;RESPONSE CODE: quot; + responseCode } conn.disconnect() return response } String toString(){ return url + quot;?quot; + queryString.toString() } }
  • 48.
  • 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;() } }
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 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
  • 60. Resources • Griffon • griffon.codehause.org • griffon-user@groovy.codehause.org • Grails • www.grails.org Coming • Books Soon
  • 61. Resources • SwingLabs • swinglabs.org • MigLayout • miglayout.org • GlazedLists • publicobject.com/glazedlists
  • 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