I've got a strange issue when trying to cache a method call on a 'repository' object in Grails (2.1.5). This repository, a plain groovy object in src/groovy, combines data from two data sources and returns a 'Seller' object.
def aDatabaseHelper
def bDatabaseHelper
#Cacheable('seller_do_get')
public Seller get(id){
....
//do stuff with aDatabaseHelper and bDatabaseHelper
return seller
}
The SellerRepository is defined in resources.groovy
aDatabaseHelper (ADatabaseHelper ){
aDataSource = ref("dataSource_a")
}
...
sellerRepository(SellerRepository){
aDatabaseHelper = aDatabaseHelper
bDatabaseHelper = bDatabaseHelper
}
And we've got ehcahce plugin (1.0.0) installed and working fine for other objects/methods.
The above for some reason doesn't cache it - it goes inside the get method each time. I created a 'BlaRepository' which takes in the same dependencies and has a getBla(id) method and it is getting cached just fine.
Does someone has a clue what's going on here? Which silly mistake am I making?
Seems like it should work, but could be a bug. Create a small test app that demonstrates the problem and run grails bug-report and attach it to a JIRA at http://jira.grails.org/browse/GPCACHEEHCACHE and I'll take a look.
Related
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.
I am using Grails 2.2.1, and I have a custom dataSource injected into the service so that I can execute some SQL queries.
Upon first execution, there is a dataSource, but on each subsequent call, the reference to the dataSource has become null.
class ReportService {
def dataSource_myds
Object[] reportRecords(int a) {
String query = "SELECT ..."
Object[] resultSet;
Sql sql = new Sql(dataSource_myds)
// ^ Here the NullPointerException is thrown
// But it always works at the first execution
sql.eachRow(query, [a]) {
...
resultSet += result
}
return resultSet
}
}
class ReportController {
ReportService reportService
def report = {
...
Object[] resultSet1 = reportService.reportRecords(1)
...
Object[] resultSet2 = reportService.reportRecords(2)
// ^ java.lang.NullPointerException : Must specify a non-null Connection
...
}
}
Has anyone ever seen this before, and if so, how can I avoid this?
Here is my DataSource.groovy
environments {
development {
dataSource_myds {
url = "jdbc:oracle:thin:#..."
driverClassName = "oracle.jdbc.driver.OracleDriver"
username = "..."
password = "..."
}
}
}
Try, to use resources.groovy way as well. This will also give you option for environment basis datasource.
Explained well on the link given below:
Grails 2 multiple dynamic datasources in services
Thanks
Solved avoiding 2 subsequent calls to the service. It seems the framework nulls the service connection after the first call from the controller.
James Kleeh's comment solved it for me - grails clean and then restart the app.
I had a similar issue and I got it fixed. Firstly, make sure your Service class is in the grails-app/services folder. Secondly, you need to make sure you get the object of the service class using the injection mechanism and not by using the constructor. I had my service class in the right folder but I was trying to create the instance of the service class as MyService.instance in my controller and having the issue of null dataSource/connection. Then I tried def myService in my controller instead of MyService.instance and it worked. Hope this helps. Thanks
Updated post:
In a Controller if I do this:
def obj = new Test(name:"lol")
obj.save(flush:true)
obj.name = "lol2"
//a singleton service with nothing to do with obj
testService.dostuff()
/*
"obj" gets persisted to the database right here
even before the next println
*/
println "done"
Can anyone please explain me why is this happening with Grails 1.3.7 and not with Grails 2? What is the reason?
I know I could use discard() and basically restructure the code but I am interested in what and why is happening behind the scenes. Thanks!
Old post:
I have a test Grails application. I have one domain class test.Test:
package test
class Test {
String name
static constraints = {}
}
Also I have a service test.TestService:
package test
class TestService {
static scope = "singleton"
static transactional = true
def dostuff() {
println "test service was called"
}
}
And one controller test.TestController:
package test
class TestController {
def testService
def index = {
def obj = new Test(name:"lol")
obj.save(flush:true)
obj.name = "lol2"
testService.dostuff()
println "done"
}
}
So what I do:
Create a domain object
Change one of it's properties
Call a singleton service method
What I would expect:
Nothing gets persisted to the db unless I call obj.save()
What happens instead:
Right after the service call Grails will do an update query to the database.
I have tried the following configuration from this url: http://grails.1312388.n4.nabble.com/Turn-off-autosave-in-gorm-td1378113.html
hibernate.flush.mode="manual"
But it didn't help.
I have tested it with Grails 1.3.7, Grails 2.0.3 does not have this issue.
Could anyone please give me a bit more information on what is exactly going on? It seems like the current session has to be terminated because of the service call and because the object is dirty it is getting automatically persisted to the database after the service call. What I don't understand that even with the manual flush mode configuration in Hibernate does not help.
Thanks in advance!
I'm not sure what about that thread you linked to made you think it would work. They all said it wouldn't work, the ticket created has been closed as won't fix. The solution here is to use discard() as the thread stated.
I'm working through the book Grails: A Quick-Start Guide and have come upon a problem. The book has me install the Blurb plugin, which seems to work, but states that we will be using it as if it were a domain class and using it a pre-existing controller. The code that I am to add to the controller looks like this
def blurb = Blurb.findByName("custom_${event.id}" )
if (!blurb){
blurb = new Blurb(name:"custom_${event.id}" , content:"" ).save()
}
When I do this I receive the same error in the IDE and the run output
'unable to resolve class Blurb' and I am directed specifically to this line blurb = new Blurb(name:"custom_${event.id}" , content:"" ).save()
Can anyone tell me what might be going wrong? I'm assuming the plugin is installed properly because if I try to access it's controller/action directly 'http://localhost:8080/TekDays/blurb/create' the plugin's provided view renders properly.
Thanks!
--
For reference I am using STS / Grails 1.3.7
Update 2011.05.12 7:45AM CST
I've attached a screenshot showing my project from the STS interface to show how my project is laid out in the event that it is package related as Burt indicated. The issue though is I'm not sure how do to the import statement so perhaps that screenshot will help.
Here is the current code in the Dashboard Controller.
package tekdays
class DashboardController {
...
}
I've tried adding the following lines per Burt's suggestion, but I obviously don't have it right
package tekdays
package my.package <--unexpected token: package
class DashboardController {
I tried changing out my with tekdays and default and both yield the same result.
Am I doing that wrong?
Thanks!
The Blurb class is in the default package, so if your controller is in a package you'll need to use a Groovy trick to access it:
package my.package
import Blurb as Blurb
class MyController {
def action = {
def blurb = Blurb.findByName("custom_${event.id}" )
if (!blurb) {
blurb = new Blurb(name:"custom_${event.id}" , content:"" ).save()
}
}
}
OK, I'm trying to set a property on a type I'm registering with SM.
Here's the code from the registry in one of my components. This
registry is being added during the configuration from a console app.
When I try to access the EndorsementSpecs property of the instance
AutoMandatoryEndorsementAggregator object, I get the 202. What's
interesting is that I can call
GetAllInstances>() from my
console app and it resolves just fine. Is there something about
accessing this code from within OnCreation that is causing the 202? I
can see everything I expect in WhatDoIHave(). I've also tried a TypeInterceptor with the same results.
//register all open generics
cfg.ConnectImplementationsToTypesClosing(typeof
(MandatoryEndorsementSpecBase<>));
ForSingletonOf<IMandatoryEndorsementAggregator<AutoPolicy>>()
.Use<AutoMandatoryEndorsementAggregator>()
.OnCreation((context, x) =>
{
var specs =
context.GetAllInstances<MandatoryEndorsementSpecBase<AutoPolicy>>();
x.EndorsementSpecs = specs;
})
;
Sorry to deflect your real questions, but are you just trying to inject all instances of MandatoryEndorsementSpecBase into AutoMandatoryEndorsementAggregatory?
If so, you can probably get away with just making it a constructor parameter so that they are all automatically injected.
public AutoMandatoryEndorsementAggregatory(MandatoryEndorsementSpecBase<AutoPolicy>[] endorsementSpecs){
EndorsementSpecs = endorsementSpecs;
}