Grails is an automagical RAD web application framework in the style of Ruby on Rails. Grails uses Groovy as its main language. You could also substitute it with Java, but that would be less fun. As an example I made a small web application for financial data.
Installation
In Mac Ports this command installs Grails
1 | sudo port install grails |
to be exact it installs version 1.3.2 Just this week version 1.3.3 was released. You still need to put Grails in your path
1 2 | export GRAILS_HOME=/opt/local/share/java/grails export PATH=$PATH:$GRAILS_HOME/bin |
Creating the app
Grails lets you generate code and configuration files from the command line or if you are a wimp you can use an IDE instead. This command generates the application
1 2 | grails create-app finance
cd finance |
You can already run the application,
1 | grails run-app |
but of course, there is not much to see yet.
Grails MVC
Grails reinvents MVC and provides scripts for it. Here is how we can create a controller
1 2 3 4 5 6 7 8 9 10 11 12 | grails create-controller finance Resolving dependencies... Dependencies resolved in 1439ms. Running script /opt/local/share/java/grails/scripts/CreateController.groovy Environment set to development [mkdir] Created dir: ... finance/grails-app/controllers/finance Created Controller for Finance [mkdir] Created dir: ... finance/grails-app/views/finance [groovyc] Compiling 1 source file to /Users/ivanidris/Projects/grails/finance/target/classes [mkdir] Created dir: ... finance/test/unit/finance Created Tests for Finance |
Grails generates some tests for the lazy Agile developer and a controller
1 2 3 4 5 | package finance class FinanceController { def index = { } } |
Now we can create some entity model classes or as Grails calls them domain classes
1 | grails create-domain-class datasource |
The datasource class will store information for the financial data sources. They will all be free, of course, since this is a home project.
1 2 3 4 5 6 7 8 9 | package finance class Datasource { String name String description static constraints = { } } |
Tweaking
In grails-app/conf/DataSource.groovy you can find configuration settings for different environments such as test, development and production. I changed the development settings so that the database will be persisted to a file for now. Every time Grails notices a change in the code the server is restarted. I changed the dbCreate parameter otherwise with the initial value of create-drop the database would have been dropped.
1 2 3 4 5 6 | development { dataSource { dbCreate = "update" // one of 'create', 'create-drop','update' url = "jdbc:hsqldb:file:devDB;shutdown=true" } } |
Scaffolding feature
Scaffolding gives you basic CRUD screens for your domain classes. I noticed a feature, when I setup scaffolding for Datasource in the main controller.
1 2 3 4 5 6 | package finance class FinanceController { def scaffold = Datasource def index = { } } |
The following stack trace was produced
ERROR view.ScaffoldingViewResolver - Error generating scaffolded view [/finance/index]: /opt/local/share/java/grails/src/grails/templates/scaffolding/index.gsp (No such file or directory) java.io.FileNotFoundException: /opt/local/share/java/grails/src/grails/templates/scaffolding/index.gsp (No such file or directory) at java.io.FileInputStream.open(Native Method) at java.io.FileInputStream.(FileInputStream.java:106) at java.lang.Thread.run(Thread.java:637)
The error message although correct was not very helpful. The fix was to change the controller to this
1 2 3 4 5 | package finance class FinanceController { def scaffold = Datasource } |
Constraints
You can define constraints for your domain classes. For instance, here name is required to be not null or blank. There are a few other possible constraints, such as defining a field to be an email address or URL.
1 2 3 4 5 6 7 8 9 10 11 12 | package finance class Datasource { String name String description Date added = new Date() static constraints = { name(blank:false) description(maxSize:255) } } |
More commands
At a certain point you will want to make a WAR
1 2 3 | grails war Done creating WAR ... finance/target/finance-0.1.war |
Also you might be interested in how many files and lines of code were written
1 2 3 4 5 6 7 8 9 10 11 | grails stats +----------------------+-------+-------+ | Name | Files | LOC | +----------------------+-------+-------+ | Controllers | 1 | 4 | | Domain Classes | 1 | 10 | | Unit Tests | 2 | 24 | +----------------------+-------+-------+ | Totals | 4 | 38 | +----------------------+-------+-------+ |
Not bad for a few minutes work. Strange that the configuration files and views are not listed.
Instrument type
Now it’s time to get serious about the domain model. Well not production type serious, more secret home weekend project type serious :). First let’s define InstrumentType. Every instrument would have a type, unless of course the type is unknown. The 1:1 relation description is set in belongsTo. The type is set to be unique. It is recommended to have a toString implementation, otherwise Grails will display the classname and record id by default in the UI.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package finance class InstrumentType { static belongsTo = Instrument String type String description static constraints = { type(unique:true, blank:false) } String toString() { "${type}" } } |
Instrument
The amazing thing about the financial industry, is that, there are no real identification standards. You would think, that for such a multi billion type business, some general scheme would exist. Each data vendor has their own symbology so for the same instrument we would have different records. One for each data source.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | package finance class Instrument { String name String symbol InstrumentType instrumentType Date added = new Date() Datasource source static constraints = { name(unique:true, blank:false) symbol(unique:true, blank:false) source(blank:false) } static mapping = { instrumentType lazy:false } static hasMany = [ contains:Instrument, values:FieldValue] String toString() { "${name} ${symbol} ${source}" } } |
We can have the instrument type be lazy fetched or in this case eagerly. hasMany here indicates that an instrument can contain other instruments and could have many values.
Field
A field could be an attribute that does not change a lot or a price. It might be useful to have a field type domain class as well, but I decided to keep things simple for now.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | package finance class Field { String name String description static constraints = { name(blank:false) } static hasMany = [ values : FieldValue ] String toString() { "${name}" } } |
FieldValue
Value is a keyword I think, just like values is a SQL keyword. Value is not allowed by groovyc
Apparent variable 'Value' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes: [groovyc] You attempted to reference a variable in the binding or an instance variable from a static context. [groovyc] You misspelled a classname or statically imported field. Please check the spelling. [groovyc] You attempted to use a method 'Value' but left out brackets in a place not allowed by the grammar. [groovyc] @ line 11, column 33. [groovyc] static hasMany = [ values : Value ] [groovyc] ^ [groovyc] [groovyc] 1 error
For the field values we need a proper timestamp. java.util.Date is not good enough for that so we will need Jodatime. Fortunately Grails has a whole plugin ecosystem, including a Jodatime plugin that we can install.
1 2 3 | grails install-plugin joda-time grails install-joda-time-gorm-mappings grails install-joda-time-templates |
The value is stored as a String. This is not type safe, so it would have been better to have a value table for each data type.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | package finance import org.joda.time.* import org.joda.time.contrib.hibernate.* class FieldValue { String val DateTime timestamp static constraints = { val(blank:false) timestamp(blank:false) } static belongsTo = [Instrument, Field] String toString() { "${val} ${timestamp}" } } |
Final scaffolding
Now we need to run
1 2 3 4 5 | grails create-controller Datasource grails create-controller Field grails create-controller FieldValue grails create-controller Instrument grails create-controller InstrumentType |
to create a controller for each domain class. Then put def scaffold = true in each controller to have Grails create basic CRUD functionality.
Conclusion
Grails is really easy to use and definitely more fun than the Java alternatives. Whenever I have time, I will retrieve some data and populate the database with some values. The next step would be to do some analysis on the data.
Found your website very informative, as a financial wealth management company your articles have proven to be very good, thank you.
Ive already been following on from the web site for a thirty day period approximately and have picked up a huge amount of data and also cherished the strategy you have organised your web site. I will be looking to work my own very personal blog site even so. I do think it’s also general and I must consentrate on quite a lot of scaled-down subjects. Being as much as possible to any or all folks is not everything it’s broke up to be.