Grails external configuration file - grails

I started working with an existing Grails project and this is the part of the config file (Config.groovy) that deals with external configuration files:
grails.config.locations = [];
def defaultConfigFile = "${basedir}/configs/BombayConfig.groovy"
def defaultDatasourceFile = "${basedir}/configs/BombayDataSource.groovy"
if(File.separator == "\\") {
defaultConfigFile = defaultConfigFile.replace('/', '\\')
defaultDatasourceFile = defaultDatasourceFile.replace('/', '\\')
}
String PROJECT_NAME = "BOMBAY"
String CONFIG_ENV = "${PROJECT_NAME}_CONFIG_LOCATION"
String DATASOURCE_ENV = "${PROJECT_NAME}_DATASOURCE_LOCATION"
def externalConfig = System.getenv(CONFIG_ENV)
def externalDataSource = System.getenv(DATASOURCE_ENV)
if (externalConfig && new File(externalConfig).isFile()) {
grails.config.locations << "file:" + externalConfig
}
else {
grails.config.locations << "file:" + defaultConfigFile
}
if (externalDataSource && new File(externalDataSource).isFile()) {
grails.config.locations << "file:" + externalDataSource
}
else {
grails.config.locations << "file:" + defaultDatasourceFile
}
I have some default files in configs folder, but in the server the files that are being used reside in:
/home/someusername/configuration/
which doesn't look like the default path, and there are no environment variables pointing to that path as the configuration suggests.
I also tried to look for a configs folder linked to the other configuration folder, but didn't find anything.
I'm lost here; how else can configuration files be specified to Grails?
Edit:
To clarify on things, the server is running and works, I just want to figure out how it's picking up the configuration files from the above specified path.

I think the intention is that you use the grails.config.locations[] entry. The following is commented out in my Config.groovy
// grails.config.locations = [ "classpath:${appName}-config.properties",
// "classpath:${appName}-config.groovy",
// "file:${userHome}/.grails/${appName}-config.properties",
// "file:${userHome}/.grails/${appName}-config.groovy"]
So can't you specify something like this:
grails.config.locations = [ "file:${userHome}/configuration" ]
to pickup the files in that folder?

if(File.separator == "\\") {
defaultConfigFile = defaultConfigFile.replace('/', '\\')
defaultDatasourceFile = defaultDatasourceFile.replace('/', '\\')
}
This will probably cause problems - grails.config.locations is a list of URLs, not native file paths, so you definitely do want forward, not backward slashes. Instead try something like
File defaultConfigFile = new File(basedir, "configs/BombayConfig.groovy")
// and the same for datasource
// ...
File externalConfig = System.getenv(CONFIG_ENV) ? new File(System.getenv(CONFIG_ENV)) : null
if (externalConfig?.isFile()) {
grails.config.locations << externalConfig.toURI().toString()
}
else {
grails.config.locations << defaultConfigFile.toURI().toString()
}

In case you are struggling with external configs and you
have specifies external configs like so in Config.groovy
grails.config.locations = []
if(System.properties["${appName}.config.location"]) {
grails.config.locations << "file:" + System.properties["${appName}.config.location"]
}
if(System.properties["${appName}.datasource.config.location"]) {
grails.config.locations << "file:" + System.properties["${appName}.datasource.config.location"]
}
and your set environment is something like this
export GRAILS_OPTS="$GRAILS_OPTS -DAppName.config.location=dev-config/Config.groovy"
export GRAILS_OPTS="$GRAILS_OPTS -DAppName.datasource.config.location=dev-config/DataSource.groovy"
and dev configs are not being picked up, then you need to look into your fork settings in BuildConfig.groovy and turn them off like so
grails.project.fork = [
test: false,
run: false,
]
This way, when application is forked, your system properties will not be lost.

Related

war specific configuration file

I would like to run different versions of my Grails (2.3.5) app at the same time in the same tomcat using different DBs.
At the moment I am having an external configuration file where I specify my DB configurations.
The filename is hardcoded:
<tomcat-home>/conf/sc.conf
"sc.war" is the name of my war-file. As I now want/need to run multiple versions I would like to make the name of the conf file variable.
<tomcat-home>/conf/<warfilename>.conf
Is there a way to get the war-file-name at runtime?
I am open for other ways to solve my problem. Thanks for your help.
You just need to give applicationBaseDir path into external config file
applicationBaseDir = ""
println "Bootstrapping application"
println ">>>>>>>>Environment >>>>>"+GrailsUtil.environment
Environment.executeForCurrentEnvironment {
development {
println "Keeping applicationBaseDir "+grailsApplication.config.applicationBaseDir+" as is."
}
production {
//Following code finds your project path and set applicationBaseDir
Process findPresentWorkingDirectory = "pwd".execute()
def pwd = findPresentWorkingDirectory.text
def pwdTokens = pwd.tokenize("/")
pwdTokens.pop()
applicationBaseDir = pwdTokens.join("/")
println ">>>> applicationBaseDir "+applicationBaseDir
applicationBaseDir = "/"+applicationBaseDir+"/webapps/applicationDir/"
println 'grailsApplication.config.applicationBaseDir '+applicationBaseDir
}
}
Or you directly set applicationBaseDir in external config file
applicationBaseDir = "/home/tomcat/webapps/applicationDir/"
Now, to refer specific external config file add into your project file Config.groovy file following code
environments {
development {
String codeSystemClassFilePath = AnyDomainClassNameFromYourApplication.class.getProtectionDomain().getCodeSource().getLocation().getPath()
// Here AnyDomainClassNameFromYourApplication change to your application domain class name e.g.I have domain class Student then I replace it with Student
def arrayWithLastValueAsProjectName = codeSystemClassFilePath.split('/target/classes/')[0].split('/')
String projectName = arrayWithLastValueAsProjectName[arrayWithLastValueAsProjectName.size()-1]
println "App name in dev==>"+projectName
grails.logging.jul.usebridge = true
grails.config.locations = [
"file:${userHome}/grails/${projectName}.groovy"
]
grails.assets.storagePath = ""
}
production {
String codeSystemClassFilePath = AnyDomainClassNameFromYourApplication.class.getProtectionDomain().getCodeSource().getLocation().getPath()
def arrayWithLastValueAsProjectName = codeSystemClassFilePath.split('/WEB-INF/classes/')[0].split('/')
String projectName = arrayWithLastValueAsProjectName[arrayWithLastValueAsProjectName.size()-1]
println "App name in production==>"+projectName
grails.logging.jul.usebridge = false
grails.config.locations = [
"file:${userHome}/grails/${projectName}.groovy"
]
}
}
//here grails/ is my default folder use to store exernal-config-files
I hope this helps you!

How to access a file system folder in Grails

I uploaded some documents into an uploadFolder C:/upload config path
environments {
development {
uploadFolder = "C:/upload/"
}
production {
uploadFolder = "C:/upload/"
}
test {
uploadFolder = "C:/Users/"
}
}
and I store it in the controller
documentInstance.fullPath = grailsApplication.config.uploadFolder + documentInstance.filename
How do I access the documents in the C:/upload/ file in Grails ?
There's no difference in how you access files in Grails then how you do it in a normal web application. If your paths are absolute paths you can do like this
def path = grailsApplication.config.uploadFolder + documentInstance.filename
File file = new File(path)
or to list all the documents in upload folder
Folder dir = new File(grailsApplication.config.uploadFolder)
dir.eachFile() {File file -> doSomething..}

Grails config file returning empty object instead of string

I am trying to read a string in from an external config file, but am for some reason only getting an empty object. Here is the config file (DirectoryConfig.groovy)
directory {
logDirectory = "c:\\opt\\tomcat\\logs\\"
}
And the code that retrieves the directory (from a controller):
String dirName = grailsApplication.config.directory.logDirectory
File directory = new File(dirName)
For some reason, dirName always ends up being "{}", and as a result the file cannot be read. What am I doing wrong here?
Creating DirectoryConfig.groovy in your grails-app/conf/ directory will not work by convention.
You should consider implementing solution that is recommended for externalizing Grails configuration - delivering .groovy or .properties files from classpath or filesystem. Take a look at commented code in Config.groovy:
// grails.config.locations = [ "classpath:${appName}-config.properties",
// "classpath:${appName}-config.groovy",
// "file:${userHome}/.grails/${appName}-config.properties",
// "file:${userHome}/.grails/${appName}-config.groovy"]
It's very common way to provide configuration files that depend on runtime property:
// if (System.properties["${appName}.config.location"]) {
// grails.config.locations << "file:" + System.properties["${appName}.config.location"]
// }
I often use something like this (it's part of the Config.groovy file):
grails.config.locations = []
grails.project.config.type = "classpath"
grails.project.config.extension = "groovy"
environments {
development {
grails.project.config.file = "development-config.${grails.project.config.extension}"
}
test {
grails.project.config.file = "test-config.${grails.project.config.extension}"
}
}
if (System.properties["grails.config.type"]) {
grails.project.config.type = System.properties["grails.config.type"]
}
if (System.properties["grails.config.file"]) {
grails.project.config.file = System.properties["grails.config.file"]
}
grails.config.locations << "${grails.project.config.type}:${grails.project.config.file}"
By default it assumes that there is e.g. development-config.groovy file in the classpath, but I can simply change it by setting -Dgrails.config.file=/etc/development.properties -Dgrails.config.type=file in Java runtime so it uses /etc/development.properties file instead of the default one.
If you would like to run your example in the simplest way, you will have to do:
1) put your DirectoryConfig.groovy in the classpath source e.g. src/java (attention: it wont work if you put your file in src/groovy)
2) define in your Config.groovy:
grails.config.locations = [
"classpath:DirectoryConfig.groovy"
]
3) re-run your application. grailsApplication.config.directory.logDirectory should now return the value you expect.
For more information about externalizing configuration go to http://grails.org/doc/latest/guide/conf.html#configExternalized

Groovy Script - Logback configuration unawaited behaviour

I want to use Logback as my logging framework within Grails. therefore I set up everything in place to work but my implementation fails on the configuration file itself. the reason is, as I guess, somewhere whithin the scoping of Groovy Script but I'm not able to figure it out...
if I define my String properties without any identifier which I want to use later I get a warning that it may not be accessed. For example:
LOG_DIR = 'c:/temp/myproject/logs/'
BACKUP_DIR = LOG_DIR + 'backup/'
appender('F_MAIN', RollingFileAppender) {
file = LOG_DIR + 'test.log'
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = BACKUP_DIR + 'test.%d{yyyy-MM-dd}.%i.log.zip'
// .... and so on
}
}
I get the following error message from Logback, which I'm pretty sure is indicating that both LOG_DIR and BACKUP_DIR can not be reached:
13:33:32,036 |-ERROR in ch.qos.logback.classic.gaffer.AppenderDelegate#6fd00b - Appender [F_MAIN] of type [ch.qos.logback.core.rolling.RollingFileAppender] has no appplicable [LOG_DIR] property
13:33:32,068 |-ERROR in ch.qos.logback.classic.gaffer.ComponentDelegate#788ac3 - Component of type [ch.qos.logback.core.rolling.FixedWindowRollingPolicy] has no appplicable [BACKUP_DIR] property
I also tried the following approach by declaring both variables with the #Field tag, but it still does not work:
#Field String LOG_DIR = 'c:/temp/myproject/logs/'
#Field String BACKUP_DIR = LOG_DIR + 'backup/'
appender('F_MAIN', RollingFileAppender) {
file = LOG_DIR + 'test.log'
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = BACKUP_DIR + 'test.%d{yyyy-MM-dd}.%i.log.zip'
// .... and so on
}
}
what am I doing wrong here?
oh my!
after searching and a lot of trial/error I found the solution and it was so close and definitely seems obvious now: I had to declare both variables with def, so now they are visible throughout the whole script ;)
For example, this is working code:
def LOG_DIR = 'c:/temp/myproject/logs/'
def BACKUP_DIR = LOG_DIR + 'backup/'
appender('F_MAIN', RollingFileAppender) {
file = LOG_DIR + 'test.log'
rollingPolicy(FixedWindowRollingPolicy) {
fileNamePattern = BACKUP_DIR + 'test.%d{yyyy-MM-dd}.%i.log.zip'
// .... and so on
}
}
now, I'm also able to use a function like this within my script:
def createFilename(String directory, String name, boolean isBackupFile) {
String filename = ''
if(isBackupFile) {
filename = "${directory}backup/MyProject-${name}.%d{yyyy-MM-dd}.%i.log.zip"
} else {
filename = "${directory}MyProject-${name}.log"
}
return filename
}
def fileAppenderLog = createFilename(LOG_DIR, 'output', false)
def fileAppenderLogBackup = createFilename(LOG_DIR, 'output', true)
appender('F_MAIN', RollingFileAppender) {
file = fileAppenderLog
rollingPoliciy(FixedWindowRollingPolicy) {
fileNamePattern = fileAppenderLogBackup
// .... and so on
}
}
which is pretty useful, I think :), especially if you want to declare a bunch of different logfiles and even if you want to declare temporary logfiles which are created when Logback is rescanning this file ...

Get the ServletContext in Config.groovy (or how to get the real path of the current context)

The question is in the title - how to obtain the ServletContext in Config.groovy. The purpose is to get the real (absolute) path of the current context.
It's not possible to get the ServletContext there.
It is possible to get the absolute path via an ugly workaround:
def path = getClass().getProtectionDomain().getCodeSource().getLocation()
.getFile().replace(getClass().getSimpleName() + ".class", "").substring(1);
(the substring(1) removes an unnecessary leading slash)
I did this in Config.groovy:
def path = getClass().getProtectionDomain().getCodeSource().getLocation().getFile().replace("/WEB-INF/classes/" + getClass().getSimpleName() + ".class", "").substring(1);
path = path.substring(path.lastIndexOf("/") + 1)
println "path: $path ${path}"
def env = System.getenv()
if (!env['ISP_CONFIG']) {
System.err.println 'Environment variable EXTERNAL_CONFIG_DIR is not set.'
} else {
grails.config.locations = [
"file:${env['EXTERNAL_CONFIG_DIR']}/grails/${path}/grails-config.groovy",
"file:${env['EXTERNAL_CONFIG_DIR']}/grails/${path}/DataSource.groovy"
]
}

Resources