(This training video and many others are available at Marakana.com).
Don’t have 90 minutes? Let me save you some time.
Here’s the gist of it.
Brown’s goal is to start from scratch and create a Twitter clone. He wants to do something more exciting than typical Grails demos that merely set up a simple CRUD application.
He mentions that several “cool technologies” will come into play, including JMS, search, cache with Gemfire, and Spring Security. Of these, only the plugins for Spring Security and for search receive significant attention in the video.
Setting up the app:
Point #1: the command grails create-app <apptitle> creates a full application infrastructure following a convention to which all Grails applications adhere. Directories include /lib, /scripts, /src, /test, /web-app, and /grails-app, and the latter encompasses /conf, /controllers, /domain, /i18n, /services, /taglib, /utils, and /views.
Main idea: You never have to wonder how a Grails app is organized.
Point #2: Grails enjoys a large plugin ecosystem. The command grails install-plugin spring-security-core installs a plugin that contributes a LoginController, a LogoutController, and support (in the Config.groovy file) for mapping security URIs such as ‘/login/**’ and ‘/logout/**’ to security policies such as IS_AUTHENTICATED_ANONYMOUSLY (which allows universal access). The plugin also contributes additional commands, such as s2-quickstart.
Main idea: You can get a lot of mileage out of a plugin.
Point #3: the command grails s2-quickstart org.mydomain.myprojectpath Person Authority creates the two specified classes in the specified package and seeds those classes with the members and methods required to support security aspects. Brown manually adds a display friendly realName variable, since the plugin only seeds userName.
Main idea: Acegi-style security on the cheap is at your fingertips.
Point #4: the class BootStrap.groovy in /grails-app/conf includes init and destroy methods.
Main idea: Using the init method to seed the in-memory database (HSQLDB) with dummy data is a good way to facilitate testing and rapid prototyping.
Point #5: the class Config.groovy contains the default security mappings contributed by the security plugin.
Main idea: Map the ‘/status/**’ URI to the IS_AUTHENTICATED_FULLY policy to enforce authentication. Any unauthorized user attempting to view a display of statuses will be redirected to the login page.
Running and tweaking the app:
Point #6: the command grails run-app will build the app, start the embedded Tomcat instance, and launch the app in that instance.
Main idea: Painless, instant gratification is yours.
Point #7: since the goal is to create and display Twitter-style Status messages, a persistent Status domain object will be needed. The command grails create-domain-class Status will create a domain entity in the /grails-app/domain directory. Brown adds the members message, author, and dateCreated.
Main idea: Simply existing in the /domain directory is sufficient for a class to be persisted to the database (via GORM, the Grails adaptation of Hibernate). No annotations or XML mappings are required.
Point #8: the command grails create-controller <fully-qualified-path-to>.Status creates a controller for the Status entity. If a view exists that matches the name of the action in a controller, binding is automatic.
Main idea: Grails exploits “convention over configuration” to achieve a lot of automagical wiring.
Point #9: Brown creates index.gsp in /view/status, and uses the <g:formRemote> tag (provided with Grails) to create an ajax form. He also adds an updateStatus action to the controller, and includes a reference to “params.message” there that the view can consume via an expression.
Main idea: A map of all request parameters, called params, is always available to the controller and view.
Point #10: Brown invokes the save() method on a Status instance, even though no such method has been declared.
Main idea: Through inversion of control, save() and get() methods are always available to domain classes; they’re added (with other GORM stuff) at runtime thanks to Groovy’s support for this.
Point #11: Simply declare a variable called springSecurityService to perform database authentication using a line such as Person.get(springSecurityService.principal.id) with the bean provided by the security plugin.
Main idea: For all Grails artifacts, “autowire-by-name” is in effect. Declare a property with a name that matches the name of a bean, and that bean will be injected into that property before the code executes.
Point #12: dateCreated is a special property.
Main idea: If a property called dateCreated of type java.util.Date exists in a domain class, GORM will automagically initialize that property to now() when persisting.
Making the app look like a tweetfeed:
Point #13: Brown writes a currentUserTimeline method that employs a criteria API to query for the last N Statuses. Status.withCriteria() takes a block of code to generate the query
Main idea: The file /conf/DataSource.groovy contains db config info, and GORM’s criteria api takes care of the SQL.
Point #14: To display each item in a returned collection of Status objects, the <g:render> tag references a _messages template.
Main idea: To define a gsp fragment as a template eligible for inclusion, simply start the filename with an underscore.
Main idea: Easy peasy.
Point #16: The goal is not merely to view a list of one’s own statuses (already achieved), but also to view statuses from those whom one follows. So, to the Person class, add static hasMany = [followed:Person] to express that bag of people a given person follows. Then, status from each member of that collection may also be queried.
Main idea: Use hasMany to achieve this relationship. (Using belongsTo=Person would ensure cascading deletes.)
Point #17: You can’t follow someone until you find someone to follow. The command grails install-plugin searchable contributes a controller called Searchable, so that simply declaring static searchable = [only: "realName"] renders the Person searchable by the value of realName.
Main idea: Cool.
Point #18: Brown adds a follow() action to the Status controller. It adds the followed Person to the follower’s hasMany of followed Persons. Brown also extends the currentUserTimeline() with a criterion to query either the current user’s Statuses or those of the folks he follows.
Main idea: We’re done.
Manual coding entailed only about 54 lines in Status controller and perhaps 30 lines in the Person object.
Reference: The Gist of It: Build Twitter with Grails in 90 Minutes from our JCG partner David Byron at the Intermediate Java Blog.