Last updated by 5 years ago

Page: Unified configuration refactor, Version:0

Unified configuration refactor

Objective

There is a requirement for provided pre-init configuration settings that can be picked up by plugins during load time. There are also a number of other disparate configuration points in Grails 0.5.5 that should be rationalized before the 1.0 release:

  • DataSources - are classes needlessly, and hence require a file per environment
  • Bootstrap - currently does not provide per-environment support out of the box, and does not provide a means to configure spring beans or metaclasses etc
  • resources.xml - ugly XML that should be handled akin to doWithSpring in plugins, as per previous comment on Bootstrap
There has also been a previous proposal to reorganize conf/ into per-environment directories. This is probably overkill, especially with the requirement for "common" configuration also that is always executed.

Proposal

The crux of it is quite simple:

  1. Favour a environment-aware DSLs over per-environment class files.
  2. Use script files instead of classes where performance will not be an issue (scripts perform poorly in a multithreaded environment so are unsuitable for supply closures to EMCs for example)
  3. Supply doWithXXX functionality for application bootstrapping in the same way it is done for plugins

Property configuration file

Here properties are defined that are accessible to plugins and the application, and spring beans, based on current environment.

// Top-level assignments apply to all environments
grails.webflow.stateless = true

env { development { resources.URL = "http://localhost:8088" smtp { mail.host = 'smtp.myisp.com' mail.auth.user = 'server' } }

production { resources.URL = "http://localhost:80/resources" smtp.mail.host = 'localhost' } }

Datasource configuration file

Replacing XXXXDataSource.groovy we have single file DataSource.groovy:

// Applies to all envs
pooling = true

env { dev { dbCreate = "create-drop" // one of 'create', 'create-drop','update' url = "jdbc:hsqldb:mem:devDB" driverClassName = "org.hsqldb.jdbcDriver" username = "sa" password = "" }

production { dbCreate = "update" // one of 'create', 'create-drop','update' url = "jdbc:mysql://localhost/appDB" driverClassName = "com.mysql.jdbc.Driver" username = "admin" password = "secret" } }

Bootstrap

ApplicationBootstrap will remain a class, as it may affect metaclasses and hence performance is a consideration.

Q: How to factor environments in here? Should 'env' not be used here too, for consistency?

class ApplicationBootstrap {
    def init = { ServletContext sc ->
       dev {
          …
       }
       production {
          …
       }
    }
    def destroy = { 
    }
    def doWithSpring = { 
       dev {
          …
       }
       production {
          …
       }
    }
    def doWithApplicationContext = { 
    }
}

Two-phase configuration

Configuration will occur in two phases, first the config will be built-up into an evaluatable "config" object which can be inspected by plugins:

if(!config.dataSource?.driverClassName) // configure default driver

Finally after plug-in initialisation configuration values will be set on bean definitions in a similar way to PropertyOverrideConfigurator

Related Issues

http://jira.codehaus.org/browse/GRAILS-729 http://jira.codehaus.org/browse/GRAILS-289