How to get values from properties file please? and where should I put the file ?
Thank you
EDIT : I'm using grails 3.1.5 And I'm trying to get properties from a job class (quartz)
Either keep your properties directly in Config.groovy file.
Or you can create a .properties file to keep properties and add this file in Config.groovy
grails.config.locations = [ "classpath:grails-app-config.properties"]
and access it anywhere in application using
grailsApplication.config."propertyName"
We have a trait like this:
/**
* Load config from config locations given by property grails.config.locations.
* Based on http://grails.1312388.n4.nabble.com/Grails-3-External-config-td4658823.html
*/
trait ExternalConfigurationLoader implements EnvironmentAware {
#Override
void setEnvironment(Environment environment) {
loadExternalConfigLocations(environment)
}
void loadExternalConfigLocations(Environment environment) {
if (environment) {
def configLocations = findConfigLocationsFromApplicationGroovy()
DefaultResourceLocator resourceLocator = new DefaultResourceLocator()
for (String configLocation in configLocations) {
loadConfigLocation(configLocation, grails.util.Environment.current.name, environment, resourceLocator)
}
}
}
List<String> findConfigLocationsFromApplicationGroovy() {
def applicationGroovy = this.getClass().classLoader.getResource('application.groovy')
if (applicationGroovy) {
def applicationConfiguration = new ConfigSlurper(grails.util.Environment.current.name).parse(applicationGroovy)
return applicationConfiguration.grails.config.locations
}
[]
}
void loadConfigLocation(String configLocation, String currentEnvironmentName, Environment environment, ResourceLocator resourceLocator) {
def configurationResource = resourceLocator.findResourceForURI(configLocation)
if (configurationResource) {
log.debug "External config '$configLocation' found. Loading."
def configSlurper = new ConfigSlurper(currentEnvironmentName)
def config = configSlurper.parse(configurationResource.getURL())
environment.propertySources.addFirst(new MapPropertySource(configLocation, config))
} else {
log.debug "External config '$configLocation' not found."
}
}
}
Then we can add this trait to Application.groovy:
class Application extends GrailsAutoConfiguration implements ExternalConfigurationLoader {
and configure external config files in application.groovy:
grails.config.locations = ["classpath:myapp-config.groovy", "file:dev-config.groovy"]
If using Tomcat, you can then put myapp-config.groovy in Tomcats lib folder.
Note: this variant only supports external config files of type .groovy but you can extend it to support .yml or .properties if you prefer that. Also note that this example has some issues with overriding values from environment block in application.yml, so if you plan to override dataSource you will need to move the default configuration of dataSource from application.yml to application.groovy first.
There is also a plugin in the making that is adding similar support for grails.config.locations. See https://github.com/sbglasius/external-config
I am working on a small grails application. I would like to create a install wizard for the application giving the user the ability to configure data connection settings via a web interface. Is there a way to stall the data connection and configure the datasource while the application is running? I would like to do this while maintaining the ability to leverage GORM/Hibernate for all domain objects. Restarting/reloading the application after configuring the datasource would be ok.
In Config.groovy file add 1 more entry for value of grails.config.locations
in result you will have something like this
grails.config.locations = ["file:${userHome}/.grails/global-config.groovy",
"classpath:${appName}-config.properties",
"classpath:${appName}-config.groovy",
"file:${userHome}/.grails/${appName}-config.properties",
"file:${userHome}/.grails/${appName}-config.groovy",
"file:${userHome}/.grails/${appName}-MyDbconfig.groovy"]
In you application after user enters DB connection parameters write it to file
"file:${userHome}/.grails/${appName}-MyDbconfig.groovy"
in corresponding format. Like follwoing
dataSource{
url = '...'
username = '...'
password = '...'
properties {
...
}
}
save file and restart application.
Since you say the user should be able to configure the datasource via web interface then you should ask for configuration params since maxActive, maxIdle, etc... Once you have all the params you store anywhere you want.
Inside your Grails application:
// grails-app/conf/BootStrap.groovy
import utils.DataSourceConfigurator
class BootStrap {
def init = { servletContext ->
DataSourceConfigurator.configure(servletContext)
}
}
Like this you say to your application that once its ready to run it needs to configure the DataSource first.
package utils
import org.codehaus.groovy.grails.commons.ApplicationAttributes
import org.codehaus.groovy.grails.web.json.JSONObject
class DataSourceConfigurator {
private static JSONObject getDSConfig() {
JSONObject conf = new JSONObject()
// Go find the configuration wherever you stored it from the web interface, parse it and return it.
return conf
}
public static final configure = { servletContext ->
if(!servletContext) {
// Invalid servlet context
return
}
def context = servletContext.getAttribute(ApplicationAttributes.APPLICATION_CONTEXT)
def ds = context?.dataSourceUnproxied
if(!ds) {
// There is no datasource available to configure.
return
}
JSONObject config = getDSConfig()
if(!config) {
// No previous configuration saved from web interface.
return
}
ds.setInitialSize(config.initialSize)
ds.setMaxWait(config.maxWait)
ds.setMaxActive(config.maxActive)
ds.setMinIdle(config.minIdle)
ds.setMaxIdle(config.maxIdle)
....
// There are many other variables to configure. Check them by yourself.
}
}
For more information you could check the documentation regarding DataSource configuration: http://docs.grails.org/latest/guide/conf.html#transactionAwareDataSourceProxy
So essentially I'm trying to get my project up and running on AppFog. The datasource information is stored in an enviornment variable, which is essentially JSON. My goal is to take this data and set my datasource config from it.
Here is what I have tried:
Code to set the datasource config which is a method in a POGO. The POGO is instantiated and the method called at the beginning of DataSource.groovy:
import appfog.ParseDataSource
new ParseDataSource().setConfig()
dataSource {
...
}
class ParseDataSource {
void setConfig() {
String env = java.lang.System.getenv("VCAP_SERVICES")
if (env) {
def config = JSON.parse(env)
config = config["mysql-5.1"][0].credentials
grailsApplication.config.environments.production.dataSource.username = config.username
grailsApplication.config.environments.production.dataSource.password = config.password
grailsApplication.config.environments.production.dataSource.url = "jdbc:mysql://" + config.host + ":" + config.port + "/" + config.name
}
}
}
The problem is that grailsApplication is always null. I've tried registering a spring bean in resources.groovy:
beans = {
parseDataSource(appfog.ParseDataSource) {
grailsApplication = ref('grailsApplication')
}
}
class ParseDataSource {
def grailsAPplication
...
}
I've also tried getting it via Holders:
GrailsApplication grailsApplication = Holders.grailsApplication
Either way it is null so I'm not doing something right. Any ideas?
I think you are making this overly complex. Overwriting the grails config object while still in the process of building it would cause an order of operations issue that would make the code very fragile.
Simply setting the values directly seems more straightforward:
Datasource.groovy:
def configJson = JSON.parse(java.lang.System.getenv("VCAP_SERVICES"))
def mysqlConfig = configJson["mysql-5.1"][0].credentials
dataSource = {
production = {
username = mysqlConfig.username
// etc.
}
}
If you wanted to keep parsing in its own class for clarity's sake, make the values properties and read them in the dataSource block rather than trying to put them in the grails config object:
config parsing:
class EnvironmentConfigParser {
String username
String password
String url
EnvironmentConfigParser() {
def configJson = JSON.parse(java.lang.System.getenv("VCAP_SERVICES"))
def mysqlConfig = configJson["mysql-5.1"][0].credentials
username = mysqlConfig.username
password = mysqlConfig.password
url = "jdbc:mysql://${mysqlConfig.host}:${mysqlConfig.port}/${mysqlConfig.name}"
}
}
in Datasource.groovy:
def parser = new EnvironmentConfigParser()
dataSource = {
production = {
username = parser.username
// etc
}
}
You should be able to access grailsApplication the way you have injected in resources.groovy provided you are injecting the bean parseDataSource somewhere in your application in any artefact.
In your special case you need the bean to be available in datasource.groovy. You were instantiating the POGO which will not help you injecting grailsApplication to the POGO. On the other hand, you cannot actually inject the POGO to datasource.groovy like
def parseDataSource
because it(datasource) is a config object during bootstrap.
The best way remains will be to metaClass the pogo at BootStrap and make grailsApplication available to it. Burt has shown it here exactly that way.
I was also thinking whether BeanPostProcessor can be useful in this case but I am not sure whether config per environment will be achieved. But you can give it a try if it helps in achieving your business need. It generally goes like:
//src/groovy
import org.springframework.beans.factory.config.BeanPostProcessor
class DatasourcePostProcessor implements BeanPostProcessor{
def parseDataSource
#Override
Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean
}
#Override
Object postProcessAfterInitialization(Object bean, String beanName) {
if(beanName == 'dataSource') {
//Set values to dataSource bean as required
parseDataSource.setConfig(bean)
}
return bean
}
}
//resources.groovy
parseDataSource(ParseDataSource){
grailsApplication = ref('grailsApplication')
}
datasourcePostProcessor(DatasourcePostProcessor){
parseDataSource = ref('parseDataSource')
}
Is there any way I can override the value of dateCreated field in my domain class without turning off auto timestamping?
I need to test controller and I have to provide specific domain objects with specific creation date but GORM seems to override values I provide.
Edit
My classes look like this:
class Message {
String content
String title
User author
Date dateCreated
Date lastUpdated
static hasMany = [comments : Comment]
static constraints = {
content blank: false
author nullable: false
title nullable: false, blank: false
}
static mapping = {
tablePerHierarchy false
tablePerSubclass true
content type: "text"
sort dateCreated: 'desc'
}
}
class BlogMessage extends Message{
static belongsTo = [blog : Blog]
static constraints = {
blog nullable: false
}
}
I'm using console to shorten things up. The problem which I encountered with Victor's approach is, when I write:
Date someValidDate = new Date() - (20*365)
BlogMessage.metaClass.setDateCreated = {
Date d ->
delegate.#dateCreated = someValidDate
}
I get following exception:
groovy.lang.MissingFieldException: No such field: dateCreated for class: pl.net.yuri.league.blog.BlogMessage
When I tried
Message.metaClass.setDateCreated = {
Date d ->
delegate.#dateCreated = someValidDate
}
Script goes well, but unfortunately dateCreated is not being altered.
I was having a similar issue, and was able to overwrite dateCreated for my domain (in a Quartz Job test, so no #TestFor annotation on the Spec, Grails 2.1.0) by
Using the BuildTestData plugin (which we use regularly anyway, it is fantastic)
Double-tapping the domain instance with save(flush:true)
For reference, my test:
import grails.buildtestdata.mixin.Build
import spock.lang.Specification
import groovy.time.TimeCategory
#Build([MyDomain])
class MyJobSpec extends Specification {
MyJob job
def setup() {
job = new MyJob()
}
void "test execute fires my service"() {
given: 'mock service'
MyService myService = Mock()
job.myService = myService
and: 'the domains required to fire the job'
Date fortyMinutesAgo
use(TimeCategory) {
fortyMinutesAgo = 40.minutes.ago
}
MyDomain myDomain = MyDomain.build(stringProperty: 'value')
myDomain.save(flush: true) // save once, let it write dateCreated as it pleases
myDomain.dateCreated = fortyMinutesAgo
myDomain.save(flush: true) // on the double tap we can now persist dateCreated changes
when: 'job is executed'
job.execute()
then: 'my service should be called'
1 * myService.someMethod()
}
}
Getting a hold of the ClosureEventListener allows you to temporarily disable grails timestamping.
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes
import org.codehaus.groovy.grails.commons.spring.GrailsWebApplicationContext
import org.codehaus.groovy.grails.orm.hibernate.cfg.GrailsAnnotationConfiguration
import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventTriggeringInterceptor
import org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventListener
class FluxCapacitorController {
def backToFuture = {
changeTimestamping(new Message(), false)
Message m = new Message()
m.dateCreated = new Date("11/5/1955")
m.save(failOnError: true)
changeTimestamping(new Message(), true)
}
private void changeTimestamping(Object domainObjectInstance, boolean shouldTimestamp) {
GrailsWebApplicationContext applicationContext = servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
GrailsAnnotationConfiguration configuration = applicationContext.getBean("&sessionFactory").configuration
ClosureEventTriggeringInterceptor interceptor = configuration.getEventListeners().saveOrUpdateEventListeners[0]
ClosureEventListener listener = interceptor.findEventListener(domainObjectInstance)
listener.shouldTimestamp = shouldTimestamp
}
}
There may be an easier way to get the applicationContext or Hibernate configuration but that worked for me when running the app. It does not work in an integration test, if anyone figures out how to do that let me know.
Update
For Grails 2 use eventTriggeringInterceptor
private void changeTimestamping(Object domainObjectInstance, boolean shouldTimestamp) {
GrailsWebApplicationContext applicationContext = servletContext.getAttribute(GrailsApplicationAttributes.APPLICATION_CONTEXT)
ClosureEventTriggeringInterceptor closureInterceptor = applicationContext.getBean("eventTriggeringInterceptor")
HibernateDatastore datastore = closureInterceptor.datastores.values().iterator().next()
EventTriggeringInterceptor interceptor = datastore.getEventTriggeringInterceptor()
ClosureEventListener listener = interceptor.findEventListener(domainObjectInstance)
listener.shouldTimestamp = shouldTimestamp
}
I got this working by simply setting the field. The trick was to do that after the domain object has been saved first. I assume that the dateCreated timestamp is set on save and not on object creation.
Something along these lines
class Message {
String content
Date dateCreated
}
// ... and in test class
def yesterday = new Date() - 1
def m = new Message( content: 'hello world' )
m.save( flush: true )
m.dateCreated = yesterday
m.save( flush: true )
Using Grails 2.3.6
As of Grails 3 and GORM 6 you can tap into AutoTimestampEventListener to execute a Runnable that temporarily ignores all or select timestamps.
The following is a small snippet I use in my integration tests where this is necessary:
void executeWithoutTimestamps(Class domainClass, Closure closure){
ApplicationContext applicationContext = Holders.findApplicationContext()
HibernateDatastore mainBean = applicationContext.getBean(HibernateDatastore)
AutoTimestampEventListener listener = mainBean.getAutoTimestampEventListener()
listener.withoutTimestamps(domainClass, closure)
}
Then in your case you could do the following:
executeWithoutTimestamps(BlogMessage, {
Date someValidDate = new Date() - (20*365)
BlogMessage message = new BlogMessage()
message.dateCreated = someValidDate
message.save(flush: true)
})
I'm using something like this for an initial import/migration.
Taking gabe's post as a starter (which didn't work for me Grails 2.0), and looking at the old source code for ClosureEventTriggeringInterceptor in Grails 1.3.7, I came up with this:
class BootStrap {
private void changeTimestamping(Object domainObjectInstance, boolean shouldTimestamp) {
Mapping m = GrailsDomainBinder.getMapping(domainObjectInstance.getClass())
m.autoTimestamp = shouldTimestamp
}
def init = { servletContext ->
changeTimestamping(new Message(), false)
def fooMessage = new Message()
fooMessage.dateCreated = new Date("11/5/1955")
fooMessage.lastUpdated = new Date()
fooMessage.save(failOnError, true)
changeTimestamping(new Message(), true)
}
}
You can try to disable it by setting autoTimestamp = false in the domain class mapping. I doubt about global overriding because the value is taken directly from System.currentTimeMillis() (I'm looking at org.codehaus.groovy.grails.orm.hibernate.support.ClosureEventListener.java).
So I can only suggest that you override a setter for dateCreated field in your class, and assign your own value. Maybe even metaclass access will work, like
Date stubDateCreated
...
myDomainClass.metaClass.setDateCreated =
{ Date d -> delegate.#dateCreated = stubDateCreated }
I couldn't get the above techniques to work, the call to GrailsDomainBinder.getMapping always returned null???
However...
You can use the fixtures plugin to set the dateCreated property on a domain instance
The initial loading will not do it...
fixture {
// saves to db, but date is set as current date :(
tryDate( SomeDomain, dateCreated: Date.parse( 'yyyy-MM-dd', '2011-12-25') )
}
but if you follow up with a post handler
post {
// updates the date in the database :D
tryDate.dateCreated = Date.parse( 'yyyy-MM-dd', '2011-12-01')
}
Relevant part of the fixtures docs here
AFAIK fixtures don't work for unit testing, although the plugin authors may add unit testing support in the future.
A simpler solution is to use a SQL query in your integration test to set it as you please after you initialize your object with the other values you want.
YourDomainClass.executeUpdate(
"""UPDATE YourDomainClass SET dateCreated = :date
WHERE yourColumn = :something""",
[date:yourDate, something: yourThing])
As of grails 2.5.1, getMapping() method of GrailsDomainBinder class is not static,non of the above method works as is. However, #Volt0's method works with minor tweaking. Since all of us are trying to do so to make our tests working, instead of placing it in BootStrap, I placed it in actual integration test. Here is my tweak to Volt0's method:
def disableAutoTimestamp(Class domainClass) {
Mapping mapping = new GrailsDomainBinder().getMapping(domainClass)
mapping.autoTimestamp = false
}
def enableAutoTimestamp(Class domainClass) {
Mapping mapping = new GrailsDomainBinder().getMapping(domainClass)
mapping.autoTimestamp = true
}
And simply call these methods in tests like
disableAutoTimestamp(Domain.class)
//Your DB calls
enableAutoTimestamp(Domain.class)
The above code can also be placed in src directory and can be called in tests however I placed this in actual test as there was only one class in my app where I needed this.
The easy solution is to add a mapping:
static mapping = {
cache true
autoTimestamp false
}
Given this UrlMapping:
"/foo/$foobar" {
controller = "foo"
action = "foo"
constraints {
}
}
Combined with this controller:
class FooController {
def foo = {
def foobar = params.foobar
println "foobar=" + foobar
}
}
And with these requests:
http://localhost:8080/app/foo/example.com give the output "foobar=example"
http://localhost:8080/app/foo/examplecom give the output "foobar=examplecom"
It seems like Grails cuts the "foobar" parameter at the first dot ("."). Is this intentional? Is there a work-around if I want to use parameters containing dots in my URL mappings?
This can be solved by setting ...
grails.mime.file.extensions = false
... in Config.groovy.
It seems like Grails is trying to do some MIME magic behind the scene based on the file name suffix.
Updated: Some additional info from the Grails JIRA.
This is the offending code in UrlMappingsFilter.java:
if(WebUtils.areFileExtensionsEnabled()) {
String format = WebUtils.getFormatFromURI(uri);
if(format!=null) {
MimeType[] configuredMimes = MimeType.getConfiguredMimeTypes();
// only remove the file extension if its one of the configured mimes in Config.groovy
for (MimeType configuredMime : configuredMimes) {
if (configuredMime.getExtension().equals(format)) {
request.setAttribute(GrailsApplicationAttributes.CONTENT_FORMAT, format);
uri = uri.substring(0, (uri.length() - format.length() - 1));
break;
}
}
}
}
WebUtils.areFileExtensionsEnabled() returns the value of the "grails.mime.file.extensions" setting configured in Config.groovy.