Grails domain class properties from properties file - grails

In my grails application I want to read some values from properties file and set it to Grails Domain class static property at startup.
Example
Class A{
static myValues="1,2";
}
class B{
static myValues="2,3";
}
In the above example I have directly given the inputs..Instead of that I want to read it from one config.properties file which will have the following
A=1,2
B=2,3
Is it possible to do that in grails.Help me please.

If you put config.properties in grails-app/conf then it'll be in the classpath and this code in grails-app/conf/BootStrap.groovy will load the properties and set the values:
class BootStrap {
def init = { servletContext ->
def props = new Properties()
def cl = Thread.currentThread().contextClassLoader
props.load cl.getResourceAsStream('config.properties')
props.each { key, value ->
def clazz = Class.forName(key, true, cl)
clazz.myValues = value
}
}
}
Obviously you'll need to check that the properties file is available, that the classes, exist, etc.

Related

How to get values from properties file in grails?

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

Where to put a xsl file in Grails, and how to get the path

I need to pass my xsl and read file on the service to generate pdf. i always get an error meesage something like
Document is empty (something might be wrong with your XSLT stylesheet).. Stacktrace follows:
Message: Document is empty (something might be wrong with your XSLT stylesheet).
i also autowire the file on the bean resource.xml or resource.groovy
class MyClassHolder{
Resource template
}
//in my controller
class MyController{
method(){
File resource = classHolder.template.file
def reader = new FileReader(resource)
myservice.convert(reader)
}
}
Whenever I required to put some file and read content from that file I create a directory e.g. resources in the web-app directory and read content in service like:
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
class MyService {
def readFile() {
def servletContext = SCH.servletContext
def file = servletContext.getResource('/resources/example.xsl').getContent()
println "Content = ${file}"
}
}
If you put it in the web-app folder, and you are using Grails 2, you can use the Grails Resource Locator.
class MyService {
def grailsResourceLocator
def templateResource
#PostConstruct
init() {
templateResource = grailsResourceLocator.findResourceForURI('/resources/example.xsl')
}
def convert() {
// no need to pass in resource or filereader, can use file or inputStream
def templateFile = templateResource.file
def templateStream = templateResource.inputStream
}
}
class MyController {
MyService myService
method() {
myService.convert()
}
}
Handy tip: to mock this in Spock, use GroovyPageStaticResourceLoader
#TestFor(MyService)
class MyServiceSpec extends Specification {
def setup() {
service.grailsResourceLocator = Mock(GroovyPageStaticResourceLocator)
}
}

Cannot use grails g.link in domain class

I have static method in a domain class that returns a url. I need to build that url dynamically but g.link isn't working.
static Map options() {
// ...
def url = g.link( controller: "Foo", action: "bar" )
// ...
}
I get the following errors:
Apparent variable 'g' was found in a static scope but doesn't refer to a local variable, static field or class. Possible causes:
You attempted to reference a variable in the binding or an instance variable from a static context.
You misspelled a classname or statically imported field. Please check the spelling.
You attempted to use a method 'g' but left out brackets in a place not allowed by the grammar.
# line 17, column 19.
def url = g.link( controller: "Foo", action: "bar" )
^
1 error
Obviously my problem is that I am trying to access g from static context, so how do I get around this?
The g object is a taglib, which is not available inside a domain class like it would be in a controller. You can get at it through the grailsApplication as shown here: How To Call A Taglib As A Function In A Domain Class
A better way to do this in Grails 2+ is through the grailsLinkGenerator service, like so:
def grailsLinkGenerator
def someMethod() {
def url = grailsLinkGenerator.link(controller: 'foo', action: 'bar')
}
In both cases, you'll need to do some extra work to get grailsApplication/grailsLinkGenerator from a static context. The best way is probably to grab it off the domainClass property of your domain class:
def grailsApplication = new MyDomain().domainClass.grailsApplication
def grailsLinkGenerator = new MyDomain().domainClass.grailsApplication.mainContext.grailsLinkGenerator
If you're using Grails 2.x you can use the LinkGenerator API. Here's an example, I am re-using a domain class I was testing with earlier so ignore the non-url related functionality.
class Parent {
String pName
static hasMany = [children:Child]
static constraints = {
}
static transients = ['grailsLinkGenerator']
static Map options() {
def linkGen = ContextUtil.getLinkGenerator();
return ['url':linkGen.link(controller: 'test', action: 'index')]
}
}
Utility Class with Static Method
#Singleton
class ContextUtil implements ApplicationContextAware {
private ApplicationContext context
void setApplicationContext(ApplicationContext context) {
this.context = context
}
static LinkGenerator getLinkGenerator() {
getInstance().context.getBean("grailsLinkGenerator")
}
}
Bean Def for New Utility Bean
beans = {
contextUtil(ContextUtil) { bean ->
bean.factoryMethod = 'getInstance'
}
}
If you need the base URL, add absolute:true to the link call.

Grails: why would this service class be null?

Given this grossly simplified rendition of the setup:
package net.myexample.plugin
class MyExampleService {
Map doMunge(Map m) {
// do stuff to 'm'
return m
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.plugin
class MyTagLib {
static namespace = 'p'
def myExampleService
def tag = { attrs, body ->
def m = doMungeAndFilter(attrs.remove('m'))
out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
}
Map doMungeAndFilter(def m) {
def mm = myExampleService.doMunge(m)
// do stuff to 'm'
return mm
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.app
import net.myexample.plugin.MyExampleService
class MyExampleService extends net.myexample.plugin.MyExampleService {
def doMunge(def m) {
def mm = super.doMunge(m)
// do more stuff to 'mm'
return mm
}
}
/****************************** BREAK: NEXT FILE ******************************/
package net.myexample.app
import net.myexample.plugin.MyTagLib
class MyTagLib extends net.myexample.plugin.MyTagLib {
static namespace = 'a'
def myExampleService
def tag = { attrs, body ->
def m = doMungeAndFilter(attrs.remove('m'))
out << g.render(template: '/template', plugin: 'my-example-plugin', model: m)
}
Map doMungeAndFilter(def m) {
def mm = super.doMungeAndFilter(m)
// do more stuff to 'mm'
return mm
}
}
/**
* But we get an exception that cites that it cannot call 'doMunge' on a null
* object -- which could only be 'myExampleService'
*/
Why would the service appear to be null when the method on the app's taglib calls its superclass (the taglib on the plugin), which in turn calls the method on the service?
The best theory I could come up with is that the service is not actually being instantiated in the app's taglib class because there are no explicit references to it aside from the def. I presume that this is the case because if I move all the logic from service class's method into the taglib's method, it works as expected.
(For the sake of painting a complete picture: MyExampleService.doMunge is called in other places, whereas the subsequent filtering (in MyTagLib.doMungeAndFilter) is only needed for the taglib.)
Alternatively: if I move doMungeAndFilter into another service class, creating the base version in the plugin and extending it in the app, that works fine. Which I suppose is an acceptable conclusion, though it feels like bloat to create another service class just to support the taglib like that.
Thoughts? Tips? Glaring errors or omissions?
Remove the def myExampleService from the subclass taglib. A property like that in Groovy compiles to a private field plus a public getter and setter, so in the superclass taglib you have implicitly
private Object myExampleService;
public void setMyExampleService(Object svc) {
this.myExampleService = svc;
}
// getter similar
When you declare myExampleService again in the subclass the subclass gets its own private field (with the same name) and the setter gets overridden to store the supplied value in this subclass field instead of the superclass one. Spring calls the setter to inject the service, so the end result is that the superclass private myExampleService never gets set, hence the null pointer exception when trying to call myExampleService.doMunge in the superclass.
The subclass has access to the superclass property via the inherited getter and setter so it doesn't need to re-declare it.
This is just a quick guess, but is you taglib class file located under /grails-app/taglib, or somewhere in your /src directory? I've noticed I can't get services to inject (automatically, at least) into classes located outside the /grails-app folder.

Grails - access static config object in codec class

I am currently updating my Grails project in order not to use the deprecated ConfigurationHolder class.
This goes fine in most cases, but I am facing trouble in my custom codec classes, where I have been using the following approach until now:
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
class MyCodec {
static boolean myStaticConfigProperty=CH.config.myStaticConfigProperty
static encode = { something ->
if(myStaticConfigProperty)
...
}
}
Direct injection using
def grailsApplication
does not work in this case since this will be injected as a non-static object.
Instead I have tried to use the approach suggested in this post getting-grails-2-0-0m1-config-info-in-domain-object-and-static-scope, but I cannot make it work even after injecting the grailsApplication object into my codec metaclasses in the bootstrap:
class BootStrap {
def grailsApplication
def init = { servletContext ->
for (cc in grailsApplication.codecClasses) {
cc.clazz.metaClass.getGrailsApplication = { -> grailsApplication }
cc.clazz.metaClass.static.getGrailsApplication = { -> grailsApplication }
}
}
}
Could anyone suggest an approach that will allow me to access the config object in a static way inside codec classes?
I'd suggest something like this completely untested code:
class MyCodec {
static def grailsConfig
static boolean myStaticConfigProperty = grailsConfig.myStaticConfigProperty
static encode = { something ->
if(myStaticConfigProperty)
...
}
}
class BootStrap {
def grailsApplication
def init = { servletContext ->
for (cc in grailsApplication.codecClasses) {
cc.grailsConfig = grailsApplication.config
}
}
}
If all of your codec classes just need the same one configuration property, you could skip injecting the grailsApplication and/or the config object entirely, and just set the one static property from BootStrap.
it works for me in grails 2.2.3
import grails.util.Holders as holders;
class MyFileCodec {
static encode = {file ->
def configPath= holders.grailsApplication.config.share.contextPath
return "${configPath}/${file.name}"
}
}
grails.util.Holders has been introduced since grails 2.0, it's the way to access config object.

Resources