Can't initialize Service in Grails Integration Test because of JNDI lookup - grails

I have a service that implements InitializingBean and DisposableBean
class MyService implements InitializingBean, DisposableBean {
static transactional = false
def grailsApplication
#Override
void afterPropertiesSet() {
System.setProperty("JMS_TIMEOUT", grailsApplication.config.JMS_TIMEOUT);
// code performing a JDNI lookup
}
}
enter code here
The system properties are used to initialize some other components in the service. I have added the configs in Config.groovy.
grails.config.locations = [ "file:${basedir}/grails-app/conf/myconfig.properties" ]
This works fine when running the application. However I'm writing an integration test in test/integration that injects the service.
class MyServiceIntegrationTests extends GrailsUnitTestCase {
def myService
void testMyService() {
}
}
When running the test I get a StackTrace with the folllowing root cause:
Caused by: javax.naming.NameNotFoundException: Name [ConnectionFactory] not bound; 0 bindings: []
at javax.naming.InitialContext.lookup(InitialContext.java:354)
at com.ubs.ecredit.common.jmsclient.DefaultConnector.<init>(DefaultConnector.java:36)
Seems that the Config could not be loaded or are different in the Integration Tests. Any idea how I can change the config or code, so that these properties are also set for my integration test, before the service is instantiated?
UPDATE:
It turned out the cause was not the configurations but a JDNI lookup and a bug in Grails.
See: http://jira.grails.org/browse/GRAILS-5726

${basedir} gets different paths in different environments. As an alternative, you can use PropertiesLoaderUtils.loadProperties to load your customized configurations:
import org.springframework.core.io.support.PropertiesLoaderUtils
import org.springframework.core.io.ClassPathResource
....
void afterPropertiesSet() {
def configProperties = PropertiesLoaderUtils.loadProperties(
new ClassPathResource("myconfig.properties"))
System.setProperty("JMS_TIMEOUT", configProperties.getProperty("JMS_TIMEOUT"))
....
}

It turned out the cause was a JNDI lookup used by a library method, I have not shown in afterPropertiesSet() in my Service, which can be seen in the StackTrace.
After doing some research I found that this was a bug in Grails: http://jira.grails.org/browse/GRAILS-5726
Adding the mentioned workaround, resolved the issue for now.

Related

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.

NullPointerException when calling service methode in a domain class methode

According to Grails it should be possible to use a service within a domain class. But when I run the following simple example, the grails run-app fails with a NullPointerException: "Cannot invoke method test() on null object"
To reproduce use the following code pieces:
Bootstrap.groovy:
class BootStrap {
def init = { servletContext ->
new Test().test()
}
def destroy = {
}
}
with the service:
#Transactional
class TestService {
def test() {
}
}
and the domain class:
class Test {
def testService
def test() {
testService.test()
}
}
This happens with Grails 3.2.9 and 3.3.0. Is this a Grails error or a GORM failure, not auto injecting the service into domain classes ?
SOLUTION:
For all wondering what the solution is (see answer from erichelgeson) using "static mapping = { autowire true }". But testing both solutions, I found that "static mapping ..." works in Grails 3.3.0 and in 3.2.9, hence setting it globally in application.yml did only work for Grails 3.2.9 but not in Grails 3.3.0 thou.
Recent versions of Grails (3.2.9+) have disabled autowire by default on domain classes for performance reasons. You can re-enable it:
per domain:
static mapping = {
autowire true
}
or globally in application.yml/groovy
grails.gorm.autowire = true
See more # http://gorm.grails.org/6.1.x/hibernate/manual/index.html
Section 1.2.9
You could reenable autowiring per the previous suggestion, but there are performance implications to your whole application for that. It may be worth it, if this is a common situation.
If this is a rare situation for you, you can also access a service as so, in a domain class:
Holders.applicationContext.serviceName.methodName()

grailsApplication autowiring to spock tests are always null

Spock tests injects null to grailsApplication,as i tried autowiring both to grails service and to domain objects(spec)
code(AttackSpec.groovy)
package core
import grails.test.mixin.TestFor
import grails.test.mixin.TestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import spock.lang.Specification
/**
* See the API for {#link grails.test.mixin.domain.DomainClassUnitTestMixin} for usage instructions
*/
#TestMixin(GrailsUnitTestMixin)
#TestFor(Attack)
class AttackSpec extends Specification {
def grailsApplication
def setup() {
Attack attack = new Attack();
println 'app '+grailsApplication.toString()
}
def cleanup() {
}
void "test something"() {
setup:
println 'app '+grailsApplication.toString()
}
}
output
log4j:WARN No appenders could be found for logger (org.codehaus.groovy.grails.commons.DefaultGrailsApplication).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
appnull
appnull
SLF4J: Class path contains multiple SLF4J bindings.
SLF4J: Found binding in [jar:file:/C:/ops/grails-2.4.4/dist/grails-plugin-log4j-2.4.4.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: Found binding in [jar:file:/C:/ops/grails-2.4.4/lib/org.slf4j/slf4j-simple/jars/slf4j-simple-1.7.5.jar!/org/slf4j/impl/StaticLoggerBinder.class]
SLF4J: See http://www.slf4j.org/codes.html#multiple_bindings for an explanation.
SLF4J: Actual binding is of type [org.slf4j.impl.GrailsSlf4jLoggerFactory]
I have tried using explicit #Autowired annotation and Static Typing,yet it's always the same. it seems like I have to inflate the grails application somewhere?
It sounds like you want to be running an integration test and not a unit test. Move your class under the integrations test folder and you may need to eliminate your test class annotations because I think those are only for unit testing.
What is the point of injecting grailsApplication in a unit test?. If you want to set a config, because your class under test: Attack reads a value of the grails application, then you can mock the grailsApplication as following:
def 'test whatever you want to'() {
def attack = new Attack()
attack.grailsApplication = [config: [my: [setting: "myValue"]]] // if attack uses grailsApplication.config.my.setting internally
when:
def setting = attack.getMySetting()
then:
setting == "myValue"
}
Or you could use a real Mock if you want to track access to it.
If you really want to use the grails environment to test, that access of the values on the framework (for whatever reason that might be) is correct executed, you should use an integration test. Subclassing IntegrationSpec from Spock will inject the grailsApplication into your test, so you can set the real thing in your Attack class.

Grails - How to inject bean defined in resources.groovy in integration test

I have 1 bean defined in resources.groovy
cachedbean(serviceImpl) {
}
In service I am using it this way
MyService{
static transactional = false
def cachedbean
myMeth(){
cachedbean.get("cacheKey")
}
}
This works fine but when I try to test it with integration test, I get nullpointer exception on 'get'
cachedbean.get("cacheKey").
How does it work?
Instead of "new"-ing up the service instance, if you let Grails auto wire the service bean into your integration test class it should be auto wired.
class MyServiceTests extends GroovyTestCase {
def myService
void testSomething () {
// myService should already be wired up
}
}
It's unclear if you did or not based on your sample code, but you need to fully-qualify out the package and class name for "serviceImpl" in your resources.groovy unless you explicitly import the package.
You may need to add inside the scope of your declaration in resources.groovy the line bean.autowire = "byName"

Override Grails service bean definition with plugin

I want to override a service implementation by just installing a plugin - when the plugin is installed I want the plugin-version of the service to be used and when the plugin is uninstalled I want the default version of the service to be used.
To prevent wasting time, I'll explain my problem using code. I have a "common plugin" that is shared by my main application and my "custom plugin" with the following:
public interface SimpleService {
void doProcessing();
}
I then have a "main application" that contains the following
Default implementation of service interface:
public DefaultSimpleService implements SimpleService {
void doProcessing() {
// ...
}
resource.groovy:
simpleService(DefaultSimpleService) { bean ->
bean.autowire = 'byName'
}
Controller that uses the service:
class SimpleController {
def simpleService
def index() {
simpleService.doProcessing()
}
}
So far so good. What I now want to do is to replace the implementation of SimpleService interface with a new one by just installing a plugin. I do not want to change any configuration within my application.
I have a plugin with a new implementation of the service:
public CustomSimpleService implements SimpleService {
void doProcessing() {
// ...
}
}
My first attempt was to register the custom service bean in the plugins "doWithSpring" section, but it is always overridden by the main application. Fair enough since it seems like plugins are always loaded before main application beans is registered (?)
My second attempt was to register the custom bean in "doWithApplicationContext" inside my CustomServiceGrailsPlugin.groovy:
def doWithApplicationContext = { applicationContext ->
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext.getBeanFactory()
beanFactory.registerBeanDefinition("simpleService", BeanDefinitionBuilder.rootBeanDefinition(CustomSimpleService.class.getName()).getBeanDefinition())
}
This actually works partially - When the plugin is loaded the plugins implementation of SimpleService is used, and if the plugin is uninstalled the main applications implementation of SimpleService is used. But there was a side issue: autowiring of beans is not working inside the plugin implementation that was "manually" registered...
Then I started to look at BeanPostProcessors but from what I read it looked like it wouldn't solve my problem.
So how do I solve my problem?
Regards
Tobbe
I think that your best bet is to check if the plugin is installed and don't declare the service in the application if so.
You can check the plugins installed with: org.codehaus.groovy.grails.plugins.PluginManagerHolder.pluginManager.allPlugins
And you can use this in the resources.groovy
boolean containsPlugin(String pluginName) {
def names = org.codehaus.groovy.grails.plugins.PluginManagerHolder.pluginManager.allPlugins.collect { it -> return it.name }
return(pluginName in names)
}
beans = {
if(!containsPlugin("thePlugin")) {
println "Installation not contains plugin, defining bean!"
myService(...)
}
}

Resources