Exposing a configuration property via getter in a quartz job - grails

Relating to Accessing grails application config from a quartz job:
Apparently, DI doesn't happen prior to the creation of a job. I'm guessing this is the same with other grails artefacts (couldn't spot relevant documentation).
In my particular case, I was aiming to load a property from config and expose that property from the job class. In general though, it seems a valid use-case to me, that artefacts will load configuration, and then return those properties via API.
I'm wondering then, how could this be achieved when a class cannot rely on access to grailsApplication.config at construction.
Thanks

Try with:
import org.codehaus.groovy.grails.commons.ConfigurationHolder as CH
class MyJob {
def execute() {
def myConfigVar = CH.flatConfig.get('my.var.setup.in.config.groovy')
...
}
}
OR
import grails.util.Holders
class MyJob {
def execute() {
def myConfigVar = Holders.config.my.var.setup.in.config.groovy
...
}
}

Related

Using a shared library class from a custom step with Jenkins pipeline shared libraries

I am setting up a shared library for Jenkins pipelines and am trying to figure out how to import a class in the shared library into a custom step that I am writing.
Here's what the directory structure looks like:
src
--jenny
----util
------Versioning.groovy
vars
--calculateVersion.groovy
The Versioning.groovy file defines some static helper methods that do some stuff.
package jenny.util
class Versioner implements Serializable {
static bool checkForValidVersion(version) {
return true
}
}
I would like to call this method from the calculateVersion.groovy something like this:
def call(version) {
return jenny.util.Versioner.checkForValidVersion(version)
}
So that my declarative pipeline can call:
def valid = calculateVersion "1.0.0"
But I receive this error No such property: jenny for class: calculateReleaseVersions
Is it possible to reference the classes in the shared library from files in the vars to define custom steps and how is this done?
Yes it is possible. At least for us:
Just like in plain java (or groovy) we put an import statement into the groovy script in vars. In your case that would be something like:
import jenny.util.Versioner
def call(version) {
return Versioner.checkForValidVersion(version)
}
Another thing I just found: It looks like the file name of the class Versioner doesn't match the class name: Versioning.groovy. Could that be the issue?
If that doesn't work you propably want to upgrade your pipeline plugin version(s).

How to customize an existing Grails plugin functionality, modifying behavior of doWithSpring method

I am new to grails and while working with Spring Security LDAP plugin it was identified that it accepts the ldap server password in plain text only. The task in hand is to pass an encrypted password which is decrypted before it is consumed by the plugin during its initialization phase.
I have already searched for all possible blogs and stackoverflow questions but could not find a way to extend the main plugin class to simply override the doWithSpring() method so that i can simply add the required decryption logic for the Ldap server password. Any help here will be appreciated.
I have already seen and tried jasypt plugin but it also does not work well if the password is stored in some external file and not application yml. So I am looking for a solution to extend the Spring security plugin main class, add the required behavior and register the custom class.
EDIT
Adding the snippet from Grails LDAP Security plugin, which I am trying to override. So If i am successfully able to update the value of securityConfig object before the plugin loads, the purpose is solved.
Some snippet from the plugin:
def conf = SpringSecurityUtils.securityConfig
...
...
contextSource(DefaultSpringSecurityContextSource, conf.ldap.context.server) { // 'ldap://localhost:389'
authenticationSource = ref('ldapAuthenticationSource')
authenticationStrategy = ref('authenticationStrategy')
userDn = conf.ldap.context.managerDn // 'cn=admin,dc=example,dc=com'
**password = conf.ldap.context.managerPassword // 'secret'**
contextFactory = contextFactoryClass
dirObjectFactory = dirObjectFactoryClass
baseEnvironmentProperties = conf.ldap.context.baseEnvironmentProperties // none
cacheEnvironmentProperties = conf.ldap.context.cacheEnvironmentProperties // true
anonymousReadOnly = conf.ldap.context.anonymousReadOnly // false
referral = conf.ldap.context.referral // null
}
ldapAuthenticationSource(SimpleAuthenticationSource) {
principal = conf.ldap.context.managerDn // 'cn=admin,dc=example,dc=com'
**credentials = conf.ldap.context.managerPassword // 'secret'**
}
You don't need to override the doWithSpring() method in the existing plugin. You can provide your own plugin which loads after the one you want to affect and have your doWithSpring() add whatever you want to the context. If you add beans with the same name as the ones added by the other plugin, yours will replace the ones provided by the other plugin as long as you configure your plugin to load after the other one. Similarly, you could do the same think in resources.groovy of the app if you don't want to write a plugin for this.
You have other options too. You could write a bean post processor or bean definition post processor that affects the beans created by the other plugin. Depending on the particulars, that might be a better idea.
EDIT:
After seeing your comment below I created a simple example that shows how you might use a definition post processor. See the project at https://github.com/jeffbrown/postprocessordemo.
The interesting bits:
https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomeBean.groovy
package demo
class SomeBean {
String someValue
}
https://github.com/jeffbrown/postprocessordemo/blob/master/src/main/groovy/demo/SomePostProcessor.groovy
package demo
import org.springframework.beans.BeansException
import org.springframework.beans.MutablePropertyValues
import org.springframework.beans.PropertyValue
import org.springframework.beans.factory.config.BeanDefinition
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
import org.springframework.beans.factory.support.BeanDefinitionRegistry
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor
class SomePostProcessor implements BeanDefinitionRegistryPostProcessor{
#Override
void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition definition = registry.getBeanDefinition('someBean')
MutablePropertyValues values = definition.getPropertyValues()
PropertyValue value = values.getPropertyValue('someValue')
def originalValue = value.getValue()
// this is where you could do your decrypting...
values.addPropertyValue('someValue', "MODIFIED: ${originalValue}".toString())
}
#Override
void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
}
}
https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/conf/spring/resources.groovy
beans = {
someBean(demo.SomeBean) {
someValue = 'Some Value'
}
somePostProcessor demo.SomePostProcessor
}
https://github.com/jeffbrown/postprocessordemo/blob/master/grails-app/init/postprocessordemo/BootStrap.groovy
package postprocessordemo
import demo.SomeBean
class BootStrap {
SomeBean someBean
def init = { servletContext ->
log.info "The Value: ${someBean.someValue}"
}
def destroy = {
}
}
At application startup you will see log output that looks something like this...
2017-10-23 19:04:54.356 INFO --- [ main] postprocessordemo.BootStrap : The Value: MODIFIED: Some Value
The "MODIFIED" there is evidence that the bean definition post processor modified the property value in the bean. In my example I am simply prepending some text to the string. In your implementation you could decrypt a password or do whatever you want to do there.
I hope that helps.
After trying Jasypt plugin and BeanPostProcessor solutions unsuccessfully for my use case, I found below solution to work perfectly.
To describe again the problem statement here,
a) we had to keep the passwords in an encrypted format inside properties files
b) and given we were packaging as a war file so the properties must not be kept inside the war to allow automated deployment scripts update the encrypted passwords depending on the environment
Jasypt plugin was a perfect solution for the use case a), but it was not able to cover the b) scenario
Moreover, the Grails LDAP Security plugin was getting loaded quite early hence Bean Post processors were also not helping out here.
Solution:
Created a new class by implementing the interface SpringApplicationRunListener. Extended its methods and parsed the properties file using YamlPropertySourceLoader
Sample code:
YamlPropertySourceLoader loader = new YamlPropertySourceLoader();
PropertySource<?> applicationYamlPropertySource = loader.load(
"application.yml", new ClassPathResource("application.yml"),"default");
return applicationYamlPropertySource;
Once the properties were loaded inside the MapPropertySource object, parsed them for the encrypted values and applied the decryption logic.
This whole implementation was executed before any plugins were initialized during Grails bootup process solving the purpose.
Hope it will help others.

access configuration/property files from src/groovy

I have a file under src/groovy and I have some properties that are in my Config.groovy and in external property file too. Normally if one want access properties its possible to use grailsApplication .configuration.property.name expression. I want to be able to access all those properties from this file that is under src/groovy directory. What I've tried so far
import grails.util.Holders
class ForkedTomcatCustomizer {
def application
void customize(Tomcat tomcat) {
println Holders.grailsApplication.config.property.name
}
}
gave me NPE saying that grailsAppliction is null
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class ForkedTomcatCustomizer {
def application
void customize(Tomcat tomcat) {
def ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT)
def grailsAppliction = ctx.grailsApplication.getObject()
println grailsAppliction.config.property.name
}
}
the same - NPE because grailsAppliction is null
Is it possible to handle this situation somehow? Thank you!
Use the below and see if it works
println Holders.config.property.name
You don't need grailsApplication when using Holders.
The examples below are probably a little more complex than what you need, but they show how to get a configuration property at build time. I use them to merge two configuration files, but you might not need to do that.
This method returns a config property when called here at the CompileEnd event.
You could define a similar method in your app's _Events.groovy file that calls your own configuration holder class.
import org.codehaus.groovy.grails.commons.ConfigurationHolder;
class KeyAndSecret{
public static String consumerKey = ConfigurationHolder.config.consumerKey;
public static String consumerSecret = ConfigurationHolder.config.consumerSecret;
}
Try like this

Grails 2.4 Command objects nullable constraint and dependency injection

we are preparing for Grails 2.4 upgrade. One of the issues we face is that
most of the command object unit tests fails because of injected properties, like
services, are required to be not null during validation.
Is there any suggested way how to test this? Should we mock all properties although some are not needed for test? or is there a way to do this differently?
After my question is answered by Jeff, I share links with more information about new functionalities:
doWithSpring and doWithConfig are shortly described in What's new in 2.4: http://grails.org/doc/latest/guide/introduction.html#whatsNew24 in Unit Testing improvements section
There is also a JIRA issue with example: https://jira.grails.org/browse/GRAILS-11003
Most unit tests don't want or need the application context all spun up and populated. Unit tests can add whatever they want (or nothing) to the application context. In recent versions of Grails you can do something like this...
A controller and command object:
// grails-app/controllers/demo/DemoController.groovy
package demo
class DemoController {
def processName(SomeCommand co) {
render co.someValue
}
}
class SomeCommand {
String name
def helperService
def getSomeValue() {
helperService.processValue(name)
}
}
A service:
// grails-app/services/demo/HelperService
package demo
class HelperService {
def processValue(String originalValue) {
"__${originalValue}__"
}
}
A unit test:
// grails-app/test/unit/demo/DemoControllerSpec.groovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(DemoController)
class DemoControllerSpec extends Specification {
def doWithSpring = {
helperService HelperService
}
void 'process name'() {
when:
params.name = 'Jeff'
controller.processName()
then:
response.contentAsString == '__Jeff__'
}
}
That test will pass with Grails 2.4.2.
I hope that helps.

Grails Dependency Injection Problem

I am having problems when using dependency injection with Services in Grails.
class ExampleService{
def example2Service
def example3Service
def method1(){
def result = example2Service.method2()
}
}
class ExampleService{
def example3Service
def method2(){
def result = example3Service.method3()
return result
}
}
class Example3Service{
def method3(){
return true
}
}
Basically in Example2Service, I am getting a Null Pointer Exception when trying to call method3 in Example3Service.
I would appreciate any help than anybody can give me with this issue
thanks
Dependency Injection needs to be initialized. (The same applies to other kinds of runtime meta programming, like augmenting Domain classes with their save() and validate() methods.)
A Grails application will be initialized when
being run from the grails run-app command
being run after having been deployed to a web server
being run from the grails test-app command (integration tests, only; unit tests do not trigger initialization).
Involved classes are not initialized when
executing a single Groovy file (i.e., by using groovy, groovysh, or groovyConsole)
or when executing a unit test.
The following as an integration test should work:
class Test2ServiceTests extends GroovyTestCase {
def test2Service
void testMethod2() {
assert test2Service.method2() == true
}
}

Resources