Going to append the part of text file during grails _Install task - grails

I'm wiring grails plugin. During _Install I would like to append the part of my plugin'sConfig.groovy. The block I'd like to cut and append starts with
// **** PLUGINSTART
and ends with
// **** PLUGINEND
Curently I'm using ant.copy and completely replace the Config.groovy with my plugin's Config.groovy. How to append only this part?

Have a look at Externalized Configuration, particularly the line:
"This can be useful in situations where the config is either coming from a plugin or some other part of your application. A typical use
for this is re-using configuration provided by plugins across multiple
applications."

Related

Add logging to an external pluggable script

As described in Can't call one closure from another, I am using a pluggable script from within a Grails app.
Unfortunately, I've found that I can't use log4j from within these scripts. I am forced to use println.
I tried using
import org.apache.commons.logging.LogFactory
def Log log = LogFactory.getLog(getClass())
but I got no output. When I print out the result of the call to getClass(), I get something like
myscript$_run_closure5
So I'm thinking the issue is that there is no configuration in my Grails Config.groovy file for this class.
Is there a way for me to programmatically add these pluggable scripts to the log4j configuration? Keep in mind that I do not know in advance what the names of the scripts are, so this has to happen at runtime.
Consider the following code:
import org.apache.log4j.Logger
// ...
Logger log = Logger.getLogger('MyPlugin')
new File( grailsApplication.config.externalFiles ).eachFile { file ->
Binding binding = new Binding()
binding.variables.log = log
GroovyShell shell = new GroovyShell(binding)
shell.evaluate(file)
strategies.put( binding.variables.key, binding.variables )
}
Explanation:
It is not obligatory to pass class name to getLogger, it can be actually any string. You just need to make sure that this string is matched in log4j.properties of the main program.
You pass once created log to plugin scripts via binding variable "log". Then plugin scripts can access it simply as log.info('test123')
My personal recommendation would be to use logback instead of log4j. Both libraries were developed by the same guy and it is stated that logback supersedes log4j.

Share config between two grails apps that share a common plugin

We will have two apps that both need to use the same services/utilities/code/configuration.
We are using grailsApplication.config.* to configure things like URLs to external services. These are different depending on whether the app is running in dev/test/qa/staging/prod, so we have used the environments section in Config.groovy. We'll need the same URLs/environments configured for both applications.
In order to avoid duplication, we are trying to build a plugin that will hold all the shared stuff. This works for services and such, but Grails plugins do not include Config.groovy, resources.groovy so all the URL configuration and such can't be put in Config.groovy in the plugin.
Is there a nice way to put that configuration in a single place and have it available for both apps?
Perhaps we could put it in some place in the plugin and "import" it into the Config.groovy of both apps?
The grails.config.locations definition for external configuration files can include java.lang.Class objects to load configuration from pre-compiled Groovy scripts, as well as file: or classpath: URLs to parse Groovy or .properties files at runtime. So you should be able to create a configuration file in the plugin under src/groovy
{plugin}/src/groovy/com/example/CommonConfiguration.groovy
package com.example
environments {
production {
...
}
development {
...
}
}
and then in the applications' Config.groovy files include this class in grails.config.locations
grails.config.locations = [com.example.CommonConfiguration]
However this does mean that when the plugin's CommonConfiguration and the host app's Config.groovy both specify a value for the same property, the plugin would win. To redress the balance, you'd need to put a second external in grails.config.locations (which could be another Class or a URL)
grails.config.locations = [com.example.CommonConfiguration,
"file:app-config.groovy"]
and put app configuration in there (as later externals override earlier ones).
Given that you want to embed the configuration within the plugin you will need to make your plugin smart enough to read it's own configuration and merge that into the containing applications config. The following is based on Grails 1.3.7. The configuration holder may have changed since then (2.0 did a lot of house cleaning) but I am sure you can figure that part out. This example assumes that there is a configuration file called grails-app/conf/MyPluginConfig.groovy inside your plugin.
Inside your /MyPlugin.groovy you will add this merge of your configuration in the doWithSpring closure.
def doWithSpring = {
// get the current application configuration
def currentConfig = org.codehaus.groovy.grails.commons.ConfigurationHolder.config
GroovyClassLoader classLoader = new GroovyClassLoader(getClass().classLoader)
// get the plugin configuration
def pluginConfig = new ConfigSlurper(grails.util.GrailsUtil.environment).parse(classLoader.loadClass('MyPluginConfig'))
// merge the configurations
pluginConfig.merge(currentConfig)
// set the application configuration to the merged configuration
org.codehaus.groovy.grails.commons.ConfigurationHolder.config = pluginConfig
}
That's it in a nutshell. Hope this helps.
Also, take note that you can still override the values in your containing application because of the way the merge is done. The application configuration is merged into the plugin configuration. If the containing application defines something it will override the plugins value.

Properties in the database

I'd like to store properties in a database tables and have defaults for those properties set in Config.groovy. For example, I want to put a default email address into Config.groovy:
app.send.report.to = 'me#example.com'
and then be able to override this in a database table (key, value columns...).
Is there a plugin (or functionality inside grails) to do this?
There is Dynamic Config Plugin.
It stores config property in ConfigProperty domain and merges properties from Config.groovy and from database using:
grailsApplication.config.merge(configObject)
You may want to look at the plugin source code. If plugin does not work for you, you can implement something similar to this.
This approach is useful when you have UI for editing config properties.
Grails does not have functionality that I'm aware of to override configuration values from a database, but it shouldn't be that difficult to do. In your Config.groovy you could put the defaults, and then as part of your bootstrap process, you could generate a temporary config file that has the values from the database (a simple query and iteration over the results could be used to generate that temp file). Include that temp file as one of your grails config locations, and it will override any values that are in the Config.groovy
If your goal is to have a shared configuration file that is used by multiple grails apps, you might also look into using something like Zookeeper to manage the shared configuration, but that may be a bit overkill for a single config file.
Not quite what you're asking for, but depending on what you want to achieve the External Configuration Reload plugin might be of use. It helps you to override default properties (in runtime), but not by using the DB.

How to redirect println output from console to specified log file in grails using log4j (Config.groovy)

In my application I use println "Some text here ${var}" statements to send some "debug" info to the console. But I want to send data to the specified file.
Could it be done via configuration of Config.groovy file?
You can't. Log messages have to go through log4j for them to be handled by Grails and log4j.
What you could do is replace all instances of println in your code with log.debug; that should be a simple search and replace with your text editor or IDE.
If that isn't possible you could try to replace the global System.out object with a File-backed PrintStream object in BootStrap.groovy.
You should to use logger directly. It's easy, clean, documented and flexible.
http://grails.org/doc/latest/guide/single.html#logging

Grails g:link - include app name in resulting anchor href attribute

This GSP:
<g:link controller="book" action="show" id="5">Example</g:link>
results in this HTML:
Example
This is relative to the HTTP host. If your site is running at http://localhost:8080 that's fine.
During development, an app will more commonly be running at http://localhost:8080/appName.
In such cases, the above link will not work - it will result in an absolute URL of http://localhost:8080/book/show/5 instead of the required http://localhost:8080/appName/book/show/5
What changes are required of the above GSP for the app name to be present in the resulting anchor's href?
The configuration setting grails.app.context should be equal to the context where you want your application deployed. If it's not set, as in the default configuration, it defaults to your application name, like http://localhost:8080/appName. If you want to deploy your app in the root context (e.g. http://locahost:8080/), add this to your Config.groovy:
grails.app.context = "/"
If the context is properly set, the URLs generated by g:link tags will include the context before the controller name.
I found that the meta tag is very useful for getting information in GSP files.
For example, if you want your application name, you can get it like this:
<g:meta name="app.name"/>
You can get any property in your application.properties file like that.
And if you, like me, need to concatenate it to another value, here is my example. Remember that any tag can be used as a method without the g: namespace. For example:
<g:set var="help" value="http://localhost:8080/${meta(name:"app.name")}/help" />
Grails documentation about this is a little poor, but it is here.
For me the single best reason to use <g:link> is that it adds the context if there is one, or omits it if you're running at http://localhost:8080 or in prod at http://mycoolsite.com - it's trivial to just concatenate the parts together yourself otherwise.
The same goes for using g:resource with css, javascript, etc. - it lets you have one GSP that works regardless of what the context is (e.g. 'appName'), since it's resolved at runtime.
I think that is what grails.serverURL is for. You defined this config variable in the Config.groovy, check the configuration documentation for Grails for more details.
Hope this helps!
createLink tag includes your appname / context parameter automatically in the link.
Here is reference doc for it.

Resources