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
- remoting plugins
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.
- inside a service can declare a property using “expose”, e.g. static expose = [‘xfire’] in the service
- 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
- basically you get back a list of arrays–each array contains the property of the Car object
- you aren’t getting back serialized Car objects, it’s returning WSClient type of ArrayOfWhatever
- 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
- if you do happen to have a service that DOES have state, need to worry about thread safety
- 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
- can add another entry to the expose property, e.g. static expose = [‘xfire’, ‘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
- “/calculateProduct/$n1/$n2” {
controller = ‘math’
action = ‘product’
} - can then call url http://localhost:8080/myapp/calculateProduct/7/4 and get 28 back
- can also specify different actions in url mapping based on the type of http request (get vs. post vs. put) and take different actions depending on the http request type
- “/calculateProduct/$n1/$n2” {
- 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