External properties file in grails 3 - grails

I need read configuration from a external file properties in grails 3. In grails 2.x I link the file with:
grails.config.locations = ["classpath:config.properties"]
In the config.groovy, but this file do not exists in grails 3.
Have you any idea for solve?

Because Grails 3 is built on Spring Boot, you can use the Spring Boot mechanisms for externalized properties. Namely, using the spring.config.location command line parameter, or the SPRING_BOOT_LOCATION environment variable. Here's the Spring documentation page on it.
The example the documentation provides for the command line parameter is this:
$ java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
The way I have been using it is by setting an environment variable, like this:
export SPRING_CONFIG_LOCATION="/home/user/application-name/application.yml"
One of the nice features is that you can leave some properties in the properties file that is bundled in the app, but if there are some properties you do not want to include (such as passwords), those can be set specifically in the external config file.

Take a look at https://gist.github.com/reduardo7/d14ea1cd09108425e0f5ecc8d3d7fca0
External configuration in Grails 3
Working on Grails 3 I realized that I no longer can specify external configuration using the standard grails.config.locations property in Config.groovy file.
Reason is obvious! There is no Config.groovy now in Grails 3. Instead we now use application.yml to configure the properties. However, you can't specify the external configuration using this file too!
What the hack?
Now Grails 3 uses Spring's property source concept. To enable external config file to work we need to do something extra now.
Suppose I want to override some properties in application.yml file with my external configuration file.
E.g., from this:
dataSource:
username: sa
password:
driverClassName: "org.h2.Driver"
To this:
dataSource:
username: root
password: mysql
driverClassName: "com.mysql.jdbc.Driver"
First I need to place this file in application's root. E.g., I've following structure of my Grails 3 application with external configuration file app-config.yml in place:
[human#machine tmp]$ tree -L 1 myapp
myapp
├── app-config.yml // <---- external configuration file!
├── build.gradle
├── gradle
├── gradle.properties
├── gradlew
├── gradlew.bat
├── grails-app
└── src
Now, to enable reading this file just add following:
To your build.gradle file
bootRun {
// local.config.location is just a random name. You can use yours.
jvmArgs = ['-Dlocal.config.location=app-config.yml']
}
To your Application.groovy file
package com.mycompany
import grails.boot.GrailsApp
import grails.boot.config.GrailsAutoConfiguration
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean
import org.springframework.context.EnvironmentAware
import org.springframework.core.env.Environment
import org.springframework.core.env.PropertiesPropertySource
import org.springframework.core.io.FileSystemResource
import org.springframework.core.io.Resource
class Application extends GrailsAutoConfiguration implements EnvironmentAware {
public final static String LOCAL_CONFIG_LOCATION = "local.config.location"
static void main(String[] args) {
GrailsApp.run(Application, args)
}
#Override
void setEnvironment(Environment environment) {
String configPath = System.properties[LOCAL_CONFIG_LOCATION]
if (!configPath) {
throw new RuntimeException("Local configuration location variable is required: " + LOCAL_CONFIG_LOCATION)
}
File configFile = new File(configPath)
if (!configFile.exists()) {
throw new RuntimeException("Configuration file is required: " + configPath)
}
Resource resourceConfig = new FileSystemResource(configPath)
YamlPropertiesFactoryBean ypfb = new YamlPropertiesFactoryBean()
ypfb.setResources([resourceConfig] as Resource[])
ypfb.afterPropertiesSet()
Properties properties = ypfb.getObject()
environment.propertySources.addFirst(new PropertiesPropertySource(LOCAL_CONFIG_LOCATION, properties))
}
}
Notice that Application class implements EnvironmentAware Interface and overrides its setEnvironment(Environment environment):void method.
Now this is all what you need to re-enable external config file in Grails 3 application.
Code and guidance is taken from following links with little modification:
http://grails.1312388.n4.nabble.com/Grails-3-External-config-td4658823.html
https://groups.google.com/forum/#!topic/grails-dev-discuss/_5VtFz4SpDY
Source: https://gist.github.com/ManvendraSK/8b166b47514ca817d36e

I am having the same problem to read the properties file from external location in Grails 3. I found this plugin which helpme to read the properties from external location. It has feature to read .yml, .groovy files as well.
Follow the steps mentioned in the documentation and it will work.
The steps are like:
Add dependency in build.gradle:
dependencies {compile 'org.grails.plugins:external-config:1.2.2'}
Add this in application.yml grails:
config:
locations:
- file:///opt/abc/application.yml
Create file at external location. In my case /opt/abc/application.yml.
Build the application and run.

You can use
def cfg = new ConfigSlurper.parse(getClass().classLoader.getResource('path/myExternalConfigfile.groovy'))

When running from a .jar file, I found that Spring Boot looks at the current directory for an application.yml file.
java -jar app-0.3.jar
In the current directory, I created an application.yml file with one line:
org.xyz.app.title: 'XYZZY'
I also used this file to specify the database and other such info.

Seems like there is no externalised config out of the box: http://grails.1312388.n4.nabble.com/Grails-3-External-config-td4658823.html

Related

What should be the logger.rolling name in log4j2.properties when we have multiple packages?

I have created multiple packages in my maven project and I'm using Junit and Cucumber. I was using log4j before and now I want to migrate it to log4j2. I just searched for the log4j2 properties file format and found the below configurations in the file:
logger.rolling.name = com.example.my.app
logger.rolling.level = debug
logger.rolling.additivity = false
logger.rolling.appenderRef.rolling.ref = RollingFile
What package should I give in the logger.rolling.name when I have multiple packages in my project?
You can use the Root logger as the catch all for packages you don't want to specify and then create loggers for any prefixes you do want. For example, if you have classes in the following packages - com.example.my.app, com.example.your.stuff, com.example.my.stuff - you can configure loggers for each of them or if you configure a logger for com.example.my then but the app and stuff packages will use that. If you configure a logger for com.example then all three packages would use that (unless you have a logger that is a better match).

What classspath is used for executing Grails' application.groovy

What classspath is used for compiling/executing Grails' application.groovy?
In my application.groovy, I instantiate a custom class (contained in a dependency's jar) and assign it to one of the config properties, like so:
environments {
production {
configProperty = new com.example.CustomClass()
I recently upgraded my application from Grails 3.1.5 to 3.2.2, and now this no longer works.
I receive an error like the following when I try to run grails run-app:
Error occurred running Grails CLI: startup failed:
script14788250424471597489853.groovy: 43: unable to resolve class com.example.CustomClass
# line 43, column 33.
configProperty = new com.example.CustomClass()
(Notice that the code is in the production block, but I'm running in development (run-app). That makes me think it's the compilation of this script that is failing.)
So I'm guessing I just need to add my dependency (that contains the CustomClass) to the appropriate classpath, but I'm not sure which one.
I'm using gradle, and have the following in my build.gradle file, to pull in the dependency containing CustomClass:
buildscript {
dependencies {
classpath "com.example:custom-module:1.1"
// ...
dependencies {
compile group: 'com.example', name: 'custom-module', version:'1.1'
}
The grails-app/conf/application.groovy file shouldn't reference application classes because it is read before compilation. If you wish to reference application classes in configuration please use grails-app/conf/runtime.groovy

How to import 'org.apache.log4j.jdbcplus.JDBCAppender' jar to Grails project?

I'm trying to use a custom jdbcappender in my Grails project. I downloaded the jar, added it in the lib folder and refresh the dependencies. When i used the custom appender got this error:
No such property: URL for class: org.apache.log4j.jdbcplus.JDBCAppender
In this code:
appender new org.apache.log4j.jdbcplus.JDBCAppender(
name: "stacktrace",
URL: "jdbc:postgresql://localhost:5432/test",
user: "test",
password: "test",
dbclass: "org.postgresql.Driver",
sql: "INSERT INTO audit VALUES('#MSG#','#THROWABLE#');"
)
Is the error in the jar import or in the appender configuration?
Best Regards,
André Cruz.
org.apache.log4j.jdbc.JDBCAppender (which is the standard JDBCAppender class in the Log4j jar) has a setURL method, but you're using org.apache.log4j.jdbcplus.JDBCAppender which has a setUrl method, so that line should be
url: "jdbc:postgresql://localhost:5432/test",

drools DRL classpath resource

I have a grails app with an XMLSolverFactory, loading it's XML configuration file from ./myapp/grails-app/conf/ with the code below. It cannot find the DRL file from the same path though. How can I get an XML configured Solver to find a classpath .DRL resource if it's running in a container?
def InputStream stream = this.getClass().classLoader.getResourceAsStream("nurseRosteringSolverConfig.xml")
solverFactory.configure(stream);
The configuration XML snippet
<scoreDrl>nurseRosteringScoreRules.drl</scoreDrl>
throws the error
scoreDrl (nurseRosteringScoreRules.drl) does not exist as a classpath resource
The getClass() code might prefix the package of your class.
Suppose your class file is in package org.foo.bar and your nurseRosteringScoreRules.drl is also in that package, then you 'd write:
<scoreDrl>/org/foo/bar/nurseRosteringScoreRules.drl</scoreDrl>

Struts2 example, not inserting records in mysql database because connection object is getting null

This Code is working fine with simple application so the drivers are fine.
so why the connection object is not able to initialise with drivers.
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.Statement;
import com.opensymphony.xwork2.ActionSupport;
public class Insert extends ActionSupport {
public String execute() throws Exception, SQLException {
String sql = "";
String url = "jdbc:mysql://localhost:3306/test";
//String dbName = "test";
String driverName = "org.gjt.mm.mysql.Driver";
String userName = "root";
String password = "root";
Connection con=null;
Statement stmt=null;
try {
Class.forName(driverName).newInstance();
con = DriverManager.getConnection(url, userName, password);
stmt = con.createStatement();
} catch (Exception e) {
System.out.println(e.getMessage());
}
}
What does the exception say? A NullPointerException on createStatement?
In any case, has the class been loaded; is the class on the classpath (i.e. the MySQL jar on the classpath?)
Check the object returned from Class.forName() to check whether the class has been found.
After your comment it is clear that you have a classpath problem. The mysql jar is not on the classpath. I assume you are talking about a web app deliverable (war file), as changing the build path in eclipse is trivial.
In a web application deployed in, for example, tomcat you can look into <webapp-name>/WEB-INF/lib. The file WEB-INF/lib/mysql-connector-java-5.0.5.jar, or something similar, should be there.
If you have a war file (not yet deployed) you can extract it using the command line tool "jar", or get a file listing from it. If you do (on a command line) jar tf | grep mysql the jarfile should be visible. If you use windows; WinRAR (and probably WinZip) can also open warfiles. In WEB-INF/lib a MySQL jar should be visible.
If you use maven to build your web app; don't forget to add a dependency to the mysql jar. If you use ant to build; don't forget to copy the mysql jar file into WEB-INF/lib before creating the war file.
Please note that currently the recommended driver to ask for is 'com.mysql.driver.Driver', and not 'org.gjt.mm.mysql.Driver'. You can try to load that Driver class in stead of the older driver; further; check whether this driver is actually in the mysql jar (jar tf mysq.jar | grep Driver or so). If the Driver is in the mysql jar and the mysql jar is on the classpath of the webapp (in WEB-INF/lib) and there is only one mysql jar there (version conflicts are no fun), and it still does not work I really don't know what could be wrong. I think I'd download the driver jar again from MySQL and try again.

Resources