CaffeineCache is not refreshed immediately after put operation in Spring Boot application - spring-boot

I have a random issue with CaffeineCache in my Spring Boot application. The problem is with an integration test that makes next
find user
delete it
find it again
It seems that sometimes cache doesn't not refreshes on time before the second call of find that comes immediately after delete.
Here is a simplified signature of find method
#Cacheable(cacheNames = "name", key = "{#config.id, #userId}", unless = "#result == null")
public User find(SomeConfig config, String userId) {
// ...
}
And a simplified signature of delete
#Caching(put = {
#CachePut(cacheNames = "someOtherCache", key = "#userId.technicalId"),
#CachePut(cacheNames = "name", key = "{#config.id, #userId}")
})
public User delete(SomeConfig config, String userId) {
// ...
}
I suppose that after call delete cache is not updated immediately and that's why method find is not called the second time. It happens 1 times from 10.
Any ideas about fix?

Related

Cache Evict issue with #Cacheable parameterless method

I'm trying to implement Spring caching in a Spring Boot RESTful service. This is the caching code for the getAllBlogs() and getBlogById() methods.
#Cacheable(value="allblogcache")
#Override
public List<Blog> getAllBlogs() {
System.out.println("******* "+ blogRepository.findAll().toString());
return (List<Blog>) blogRepository.findAll();
}
#Cacheable(value="blogcache", key = "#blogId")
#Override
public Blog getBlogById(int blogId) {
Blog retrievedBlog = null;
retrievedBlog = blogRepository.findById(blogId).get();
return retrievedBlog;
}
In the saveBlog method I want to evict the cache and have used the following code.
#Caching(evict = {
#CacheEvict(value="allblogcache"),
#CacheEvict(value="blogcache", key = "#blog.blogId")
})
#Override
public Blog saveBlog(Blog blog) {
return blogRepository.save(blog);
}
On running, I did the following using Postman:
Saved two blogs. Both blogs are getting saved to the database.
called get All blogs. Both the saved blogs are returned.
Saved a new blog. Here I assume the cache has been evicted.
I called get All blogs. However, only two blogs are getting returned. This
means the blogs are returned from the old cache. It didn't get evicted by the
call to the third save.
The github repo is at https://github.com/ximanta/spring-cache
You need to add allEntries = true attribute if you're evicting caches without specifying a key (see docs).
In your case, it would be #CacheEvict(value="allblogcache", allEntries = true)
P.S. tested it and managed to make it work. PR: https://github.com/ximanta/spring-cache/pull/1
It throw exception because you use wrong key expression:
#Caching(evict = {
#CacheEvict(value="allblogcache"),
#CacheEvict(value="blogcache", key = "#blogId")
~~~~~~~~~~ => Refer to parameter blogId but not found
})
public Blog saveBlog(Blog blog)
The correct expression is:
#Caching(evict = {
#CacheEvict(value="allblogcache"),
#CacheEvict(value="blogcache", key = "#blog.id") // Assume that the property for blog ID is "id"
})
public Blog saveBlog(Blog blog)

Spring + Hibernate - when the transaction is really committed?

I'm facing a singular problem...
I need to update an entity, but i don't know when it is really updated
My method is
#Override
#Transactional(isolation = Isolation.SERIALIZABLE)
public void lightOn(int idInterruttore) {
Interruttore interruttore = dao.findById(idInterruttore);
String inputPin = interruttore.getInputPin();
String pinName = interruttore.getRelePin();
GpioController gpio = interruttore.getGpio();
GpioPinDigitalOutput rele = gpio.provisionDigitalOutputPin(RaspiPin.getPinByName(pinName));
try {
DateTime date = new DateTime();
Date now = date.toDate();
int i = 1;
while (getInput(inputPin, gpio) != 1) {
if(i > 1){
logger.debug(String.format("Try n %s", i));
}
pushButton(rele);
Thread.sleep(1000);
i++;
}
dao.updateInterruttore(idInterruttore, now, true);
} catch (GpioPinExistsException | InterruptedException gpe) {
logger.error("GPIO già esistente", gpe);
} finally {
gpio.unprovisionPin(rele);
}
logger.debug(String.format("After the update status should be true and it's %s",
interruttore.isStato()));
}
updateInterruttore is (i used this form to be sure to call the commit after the update... I have the lock Option because multiple call can be done to this method but only the first must update
#Override
public void updateInterruttore(int idInterruttore, Date dateTime, boolean stato) {
Session session = getSession();
Transaction tx = session.beginTransaction();
String update = "update Interruttore i set i.dateTime = :dateTime, i.stato = :stato where idInterruttore = :idInterruttore";
session.createQuery(update).setTimestamp("dateTime", dateTime).setBoolean("stato", stato)
.setInteger("idInterruttore", idInterruttore).setLockOptions(LockOptions.UPGRADE).executeUpdate();
tx.commit();
}
}
Well... when I update the log says me:
After the update status should be true and it's false
This happens only the first time I call the method, the second time interruttore.isStato is correctly true.
Why this happens?
This happens because you're updating the database directly with the update statement. Hibernate does not update automatically an already loaded entity in this case. If you reload the entity after the call to dao.updateInterruttore you should get the updated data.
Two notes:
1) You are using a query to apply the update. In that case, Hibernate will no update the entity that is in the session. Unless you update the entity itself and call session.save(interruttore), then the entity will not be updated. (But the update shows up in the DB.) Furthermore, I don't understand why you just don't update the entity and save it via session.save().
2) You are annotating the service method with #Transactional. (Assuming that's Spring annotation) If you use JTA, your tx.commit() will have no effect. But once the method completes, your transaction is committed. (or rolled back if the method throws an exception) If you are not using JTA, then get rid of #Transactional and manage transaction in your DAO method, as you are doing. But that's considered bad practice.

Spring boot #CachePut, how it works

I'm trying to update values in spring cache, however #CachePut does not replace actual value, but put another value with the same key:
Cachename: noTimeCache:
Key: SYSTEM_STATUS, val: ON
Key: SYSTEM_STATUS, val: OFF
1.Why?
My cache service:
#CachePut(value = "noTimeCache", key = "#setting.getSetting().name()")
public String updateGlobalCacheValue(GlobalSettings setting) {
System.out.println("Setting: " + setting.getSetting().name() + ", val: " + setting.getValue());
return setting.getValue();
}
I know it's looks funny but i need to work with jpa repositories. Maybe someone have better solution.
2.Why can't I use function argument as #Cacheable key like this?
#Cacheable(value = "noTimeCache", key = "#setting.name()", unless = "#result == null")
#Query("SELECT gs.value FROM GlobalSettings gs WHERE gs.setting = ?1")
String getGlobalSettingValue(Settings setting);
It tells me setting is null.
3.Is the way to override #Repositository interface methods, for example save() to add annotation #Cacheable to them?
1-#CachePut does not replace actual value, but put another value :delete key = "#setting.name" in that way keygenarator will use the hashcode of GlobalSettings(verify if the hashcode is implemented correctly)and also verify if the name of the cache "noTimeCache" is not specified to other methods.
2-see this link http://docs.spring.io/spring/docs/current/spring-framework-reference/html/cache.html if the "setting" parameter is an attribute in GlobalSettings you can
change the SpEL expression #setting.getSetting().name() to #setting.setting.name
3-You can do the following if you are using java 6 (no idea if this is possible with java 7 or 8 ) :
public interface GlobalSettingsRepository extends JpaRepository<GlobalSettings, Long>{
#Override
#CacheEvict(value = {"noTimeCache"}, allEntries = true)
GlobalSettings save(GlobalSettings globalSettings);
}
Thanks for answers. It helps me solve problems.
#CachePut replace values, but there was a problem in keys. I use something like this:
#Cacheable(value = "globalSettings", unless = "#result == null")
#Query("SELECT gs.value FROM GlobalSettings gs WHERE gs.setting = ?1")
String getGlobalSettingValue(Settings setting);
Settings is enum and key for default is enum name, for example SYSTEM_STATUS.
and this:
#Cacheable(value = "globalSettings", key = "#setting.name()")
public String getGlobalSettingEnumValue(Settings setting) {
return Settings.valueOf(setting.name()).getDefaultValue();
}
will also save key as STSYEM_STATUS.
Key's was the same but cache interprets this like 2 different cache values, I don't know why.
U can't use variable name in repository class like #setting, it must be argument index like #p0, probably beacause of spring data use his own proxy classes.
This solve all my problems and now cache work properly.

Grails tries to validate encoded password (Spring Security Core)

I spent hours on this problem without finding the solution. Other questions come close but none of the suggested solutions work for me.
I'm running on
- Grails 2.1.1 installed with
- Groovy 2.0.8 and
- Oracle Java v 1.6.0_45 (also tried with 1.7 already)
I added the Spring Security Core Plugin v 2.0-RC2.
I'm a Grails beginner and all I want to do is create a "Runner" with a password using my own password validator.
This is my Runner.groovy domain class (did not change very much from the default Spring Security User template apart from the renaming):
package de.muden.runnerbase
class Runner {
transient springSecurityService
String username
String password
boolean enabled = true
boolean accountExpired
boolean accountLocked
boolean passwordExpired
Date dateCreated
Profile profile
public static final int MIN_PASS_LENGTH = 6
public static final int MAX_PASS_LENGTH = 20
static transients = ['springSecurityService']
static constraints = {
username(size:3..20,unique:true)
password(nullable:false, blank:false, minSize:6, validator: { passwd, runner ->
return (passwd != runner.username && validatePasswordInplace(passwd))
})
dateCreated()
profile(nullable:true)
}
static mapping = {
profile lazy:false
runs sort:'dateCreated'
password column: '`password`'
}
Set<Role> getAuthorities() {
UserRole.findAllByUser(this).collect { it.role } as Set
}
def beforeInsert() {
encodePassword()
}
def beforeUpdate() {
if (isDirty('password')) {
encodePassword()
}
}
String toString() {
return "Runner '$username'"
}
protected void encodePassword() {
password = springSecurityService.encodePassword(password)
}
protected static boolean validatePasswordInplace(String passToValidate) {
println "VALIDATING PASS $passToValidate"
return passToValidate ==~ /([A-Za-z0-9äöüÄÖÜß.!\?_-]){$MIN_PASS_LENGTH,$MAX_PASS_LENGTH}/
}
static hasMany = [runs: Run, shoes: Shoe]
}
So the validator allows passwords between 6 and 20 characters long, upper and lower case letters, numbers and a few special characters.
Simple unit tests just testing this method work as expected.
Now a simple integration test:
void testValidRunner() {
Runner r = new Runner(username:'dummy',password:'foobar')
assertTrue r.validate() // OK
assertFalse r.hasErrors() // OK
assertNotNull r.save(flush:true,failOnError:true) // OK
Runner foundRunner = Runner.findByUsername("dummy")
assertNotNull foundRunner // fails, foundRunner = null
assertEquals('dummy',foundRunner.username)
}
And the console (with -echoOut) says:
VALIDATING PASS foobar
VALIDATING PASS $2a$10$Q5RYaDrCFFxdXEqYqV4J2OJWHzgOJZJ3wljqVK1jNP4Sqm6ZUOPam
It is obvious that the second validation fails. But why is grails validating the encoded password again? And why doesn't r.validate() complain? Where exactly does that second validation happen?
I have the feeling that I'm doing really basic user password encryption wrong here...
First I thought it had to do with the Spring Security fields "accountExpired" etc. being added and not in the constraints block. But when I remove the custom validator everything works fine.
Any help is appreciated :-)
Thanks,
Matt
Below is what I think is going on ...
The second validation happens when you call r.save
The beforeInsert method is calling the encodePassword method, which is encoding the PW to the long string $2a$10$Q5RYaDrCFFxdXEqYqV4J2OJWHzgOJZJ3wljqVK1jNP4Sqm6ZUOPam
That is the string that will be validated and saved in the DB not 'foobar'
I believe that your regex does not allow the dollar sign, which is part of the encoded string resulting in the failure.
I do not think that using constraints will work for what you want to do. You need to validate before it is encoded, so you probably need to add separate validation code (in the domain class or elsewhere) and validate the PW before assigning to the PW field and saving the object.

PrepareResponse().AsActionResult() throws unsupported exception DotNetOpenAuth CTP

Currently I'm developing an OAuth2 authorization server using DotNetOpenAuth CTP version. My authorization server is in asp.net MVC3, and it's based on the sample provided by the library. Everything works fine until the app reaches the point where the user authorizes the consumer client.
There's an action inside my OAuth controller which takes care of the authorization process, and is very similar to the equivalent action in the sample:
[Authorize, HttpPost, ValidateAntiForgeryToken]
public ActionResult AuthorizeResponse(bool isApproved)
{
var pendingRequest = this.authorizationServer.ReadAuthorizationRequest();
if (pendingRequest == null)
{
throw new HttpException((int)HttpStatusCode.BadRequest, "Missing authorization request.");
}
IDirectedProtocolMessage response;
if (isApproved)
{
var client = MvcApplication.DataContext.Clients.First(c => c.ClientIdentifier == pendingRequest.ClientIdentifier);
client.ClientAuthorizations.Add(
new ClientAuthorization
{
Scope = OAuthUtilities.JoinScopes(pendingRequest.Scope),
User = MvcApplication.LoggedInUser,
CreatedOn = DateTime.UtcNow,
});
MvcApplication.DataContext.SaveChanges();
response = this.authorizationServer.PrepareApproveAuthorizationRequest(pendingRequest, User.Identity.Name);
}
else
{
response = this.authorizationServer.PrepareRejectAuthorizationRequest(pendingRequest);
}
return this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
}
Everytime the program reaches this line:
this.authorizationServer.Channel.PrepareResponse(response).AsActionResult();
The system throws an exception which I have researched with no success. The exception is the following:
Only parameterless constructors and initializers are supported in LINQ to Entities.
The stack trace: http://pastebin.com/TibCax2t
The only thing I've done differently from the sample is that I used entity framework's code first approach, an I think the sample was done using a designer which autogenerated the entities.
Thank you in advance.
If you started from the example, the problem Andrew is talking about stays in DatabaseKeyNonceStore.cs. The exception is raised by one on these two methods:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc());
return matches.FirstOrDefault();
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
return from key in MvcApplication.DataContext.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc()));
}
I've resolved moving initializations outside of the query:
public CryptoKey GetKey(string bucket, string handle) {
// It is critical that this lookup be case-sensitive, which can only be configured at the database.
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket && key.Handle == handle
select key;
var match = matches.FirstOrDefault();
CryptoKey ck = new CryptoKey(match.Secret, match.ExpiresUtc.AsUtc());
return ck;
}
public IEnumerable<KeyValuePair<string, CryptoKey>> GetKeys(string bucket) {
var matches = from key in db.SymmetricCryptoKeys
where key.Bucket == bucket
orderby key.ExpiresUtc descending
select key;
List<KeyValuePair<string, CryptoKey>> en = new List<KeyValuePair<string, CryptoKey>>();
foreach (var key in matches)
en.Add(new KeyValuePair<string, CryptoKey>(key.Handle, new CryptoKey(key.Secret, key.ExpiresUtc.AsUtc())));
return en.AsEnumerable<KeyValuePair<string,CryptoKey>>();
}
I'm not sure that this is the best way, but it works!
It looks like your ICryptoKeyStore implementation may be attempting to store CryptoKey directly, but it's not a class that is compatible with the Entity framework (due to not have a public default constructor). Instead, define your own entity class for storing the data in CryptoKey and your ICryptoKeyStore is responsible to transition between the two data types for persistence and retrieval.

Resources