Thursday, October 22, 2009

Session Notes - Grails Without a Browser

Presenter: Jeff Brown, SpringSource

  • grails typically thought of as a web framework (which it is), but there are significant applications built with grails that have no browser front-end at all
  • interesting work done at LinkedIn in this regard
    • talked about it in public at JavaOne last year
    • primary revenue generating app is a grails app (partner interaction, etc.)
      • this app has no browser front-end to it
      • built a business/service layer all in grails
      • have other applications that sit in front of this that aren't grails
  • lots of stuff in grails doesn't have anything to do with building web apps specifically
    • GORM
    • service layer
    • these make good sense in any application
  • can think of grails as a platform--similar to eclipse platform
    • eclipse IDE is what you think of, but the IDE is really just one app on top of the eclipse platform
    • e.g. substantial parts of grails are being used in griffon for building desktop apps
  • grails 0.4 was the first release that had the plugin system in it
    • interview soon after this release--jeff was asked what was coming up in the following year
    • hope was that they'd see a lot of development in the plugin space
    • turned out that there's a far more active and productive plugin community than they had hoped
    • shows the power of the plugin architecture in grails as well as grails as a platform in general
  • some plugins have nothing to do with an html ui
    • remoting plugins
      • exposes services to remote calls
      • can have the grails side interacting with GORM as per usual, but make these services available to RMI, SOAP, etc.
    • good REST support built right into the framework

Code Demo

  • simple app with Car domain class, CarService
  • services
    • transactional by default
    • instance of service class is automatically added to the spring application context
  • installing xfire SOAP plugin
    • inside a service can declare a property using "expose", e.g. static expose = ['xfire'] in the service
      • this will inspect services that have an expose property declared and make them available via xfire
    • also plugins for exposing as rmi, jms, etc.
  • after fire the app up can browse to http://localhost:8080/context/services to see a list of service WSDLs
    • xfire generated the wsdl automatically
    • can test with something like SOAP UI--UI tool to allow you to exercise web services
  • as you define other operations within the service, the WSDL gets regenerated as needed to expose the new methods
    • with xfire you do need to bounce the app for it to pick up the changes
  • creating a groovy script as a command-line client to the exposed service
    • create a groovyx.net.ws.WSClient, give it the URL to the WSDL, and can then call methods on the web service
    • WSClient is an external project (not core to groovy) so you do need to add it to your classpath
  • note that you don't have access to the Car class when you get back data from the web service
    • you aren't getting back serialized Car objects, it's returning WSClient type of ArrayOfWhatever
      • basically you get back a list of arrays--each array contains the property of the Car object
        • really JAXB elements that contain an xml representation of the car
  • note that by default all of your services are singletons (stateless)
    • if you do happen to have a service that DOES have state, need to worry about thread safety
      • can specify that the bean is scoped in any one of the valid spring scopes
  • controllers are not singletons since they have state--new controllers are created for every request
  • xfire may or may not support (need to check) not exposing specific methods within a service using something like webparam annotations
  • installing jmx plugin
    • can add another entry to the expose property, e.g. static expose = ['xfire', 'jmx']
      • still exposed as SOAP, but also available to jmx
  • creating simple math service
  • can create a griffon client to access the grails service
  • demoing creation of griffon app (results in a swing app)
    • showing two text input fields in swing app, click button to make call to grails service to add the two numbers together
    • actually clicking on the button calls a griffon controller, and the griffon controller makes the web service call to the grails service
      • creating an instance of groovy's WSClient in the griffon controller and calling the same way as from the command line client
  • now creating a RESTful interface to the math service
    • adding a MathController to the grails app with a "product" action to multiply two numbers
    • return from the controller is xml
    • showing calling this in the browser but of course this could be called from anything that can accept xml as the return format
  • now adding another component to the griffon application to do multiplication by calling the REST URL in the grails app
    • plugin for griffon to enable REST support
    • wind up with two buttons in the griffon app, one that makes a soap call, the other making a rest call
  • can use UrlMappings in a grails app to make things more RESTful
  • in controller you can specify the allowed HTTP request types that can be made to the controller by action, e.g. static allowedMethods = [delete:'POST'] would throw a 405 if any request type other than POST is made to the delete action
    • should never do anything destructive in response to a get request
    • if you write controllers from scratch the allowedMethods property is NOT there, and in most cases you'll want to add it
  • in RESTful services, the request will come to the controller since controllers in grails apps are what respond to requests
    • can put logic in services to get it out of your controller, but the REST response since it's based on HTTP request/response needs to be handled in the controller
    • controllers don't have to render a *view* specifically, they just have to provide a response
      • response can be html, xml, json, etc.
  • when you think about grails, building web apps is a huge part of what it's used for, but grails also handles "no browser" apps or multiple UI clients quite well
  • in the end your application is just responding to requests

Q&A

  • anyone working on a plugin so you can write an app that can render either a grails or griffon app?
    • nothing really going on in this specific area, but moving towards compatibility with grails and griffon plugins
    • in many cases you can do a search/replace on a grails plugin to replace "grails" with "griffon" and it'll work in griffon
  • has linkedin experienced any scalability issues?
    • linkedin app get hits really hard and is holding up very well
    • being on the jvm means you have great existing solutions for deployment, scalability, monitoring, etc.
      • can do things in other frameworks (e.g. rails, django) perhaps as quickly as with grails, but that's only one piece of the puzzle
  • what happens when an app and a plugin rely on different versions of the same jars?
    • no good solution for this at this point
    • after grails 1.2 is released, significant effort will be put into the plugin system--need to figure out what role OSGi will play in the future of grails
      • will grails apps and/or plugins turn into OSGi bundles? probably ponder this early next year
  • is GORM usable outside of Grails?
    • yes, and isn't difficult to do now
    • wiring between gorm and the rest of grails is pretty decoupled at this point
    • can use GORM in griffon, for example--drop the GORM jar in and annotate classes, and everything works
      • all the gorm dependencies are in 1 JAR now
    • when using GORM outside of grails you do need to create your own boostrapper or use annotations so GORM knows about your domain model
  • error handling with soap?
    • inside controller action if you get bad data you can render the soap response with the error
    • grails doesn't complicate or simplify any error handling with soap
    • anything you can do to specify timeouts, etc.?
      • rest client for griffon no, wsclient probably does
    • shouldn't assume when something goes wrong in groovy/grails that you always get an exception
      • in many cases grails fails silently, e.g. if you call save() and it fails, it doesn't throw an exception it just returns null
      • can now specify that save() throws an error if save fails
  • what about security with xfire and securing services?
    • can secure access to the webapp at the http level
    • don't know if xfire plugin has specific user/role based access
    • controllers in REST would hook into everything that grails already does--just an http request to the webapp

No comments: