Setting a global map in Grails - caching

I am building a Grails web app, I created a map in BootStrap and placed it in servletContext in order to make it available to my application from anywhere. On average this map should hold about 1000 entries with String keys and Date value.
I was wondering if that can impact my application performance and there is a better place to keep this map ? I want this map to work as a caching mechanism. I wanna put a unique Key in it and a date, and be able to retrieve that date object from anywhere such as within a controller, or service class by passing the key. I was thinking of using a caching mechanism to do that but haven't find one that can do this form. I appreciate it if anyone can suggest any plugin for Grails that can achieve this.
P.S: Is it possible to do this with Cache Plugin : http://grails-plugins.github.io/grails-cache/docs/manual/guide/usage.html#annotations

You could use a Service for this task. Service is a singleton, so it will be alive all the time. And it's much easier to access from other parts of app. To prepare data on application startup, you can implements InitializingBean.
Foe example:
class MyCacheService implements InitializingBean {
Map cache
void afterPropertiesSet() {
cache = [
a: 1,
b: 2,
// .....
]
}
}

About making the Map cache thread-safe, we can use ConcurrentReaderHashMap cache so that does mostly-concurrent reading, but exclusive writing. That way everyone can read it from the service but not everyone can write to it or modify it at the same time.
It is possible to use Synchronized block on the methods such as addToCache so that not two controllers can write at the same time, but for getFromCache we don't need that.
Sample code for ConcurrentReaderHashMap

Related

Camunda DelegateExecution Event

I am new to Camunda.I am trying to trigger a event in spring boot application when I perform manual action like retry from Camunda BPM UI.
For that I am using Eventlistner.
#EventListener Public void onExecutionEvent(DelegateEvent executionDelegate){ // printing executionDelegate here }
I need the information present in executionDelegate object.But on printing it is giving me hash value.
Do anybody have complete object information as there are lot of class and interfaces in this Class.It would you be helpful if i am able to get a sample of complete object I information.
Thanks in advance.
The hash value is the default result of the "toString()" method which every class in java implements by default (by extending "Object").
The fact that you see a hash value means, that the DelegateEvent does not overwrite this method in way you maybe used to.
So the question is: what do you want to know from the delegateExecution? MOst often, you will be interested in the process variables ... you can just print out the result of the "getVariables()" method ...
If you want to learn more about the class and its values, put a break point in your eventListener method, start spring boot in debug mode and use the inspect/evaluate code feature of whatever IDE you use to just play around and get familiar.

Serializing element into custom Hybris CacheRegion

Info: using Hybris 5.7
I've being trying to write a custom CacheRegion in order to use Redis for this purpose (instead of the in memory solutions provided such as Maps or EHCache).
Following the instructions provided here didn't seem to be enought.
The point that I'm stuck is the moment to serialize the element object wich doesn't implement serializable so I can't get to serialize it into json or byte array or anything else (tried with Jackson, Kryo, FST and java default serializer).
The code is something as follow (skipping other parts):
...
#Override
public Object getWithLoader(CacheKey cacheKey, CacheValueLoader cacheValueLoader) throws CacheValueLoadException {
return Optional.ofNullable(get(cacheKey))
.orElseGet(() -> {
Object element = cacheValueLoader.load(cacheKey);
//Can't get to serialize *element* to store it
return element;
});
}
...
Debugging I found out that Object element is actualy an instance of GenericBMPBean$GenericItemEntityStateCacheUnit and it seems to contains a lot of things (except the actual data that I couldn't find, oddly).
Another thing that I didn't understand yet is the usage of the CacheKey.CacheUnitValueType wich seems to be ignored by the EhCache implementation. Even when it is NON_SERIALIZABLE it is stored into the EhCache.
So my question is: How should I manage to serialize this kind of data?
Plus question: what is the desired usage of the flag CacheUnitValueType ?
The main goal behind this is to decouple the cache from the application JVM and increase HA and scalability.
Thank you.
The point that I'm stuck is the moment to serialize the element object wich doesn't implement serializable so I can't get to serialize it.
An object which doesn't implement Serializable in hybris should not be serialized. You have to take care of what get cached.
It's stated in the documentation
It is not possible on entity and type system regions because of not serializable object nature.

What strategies exist for using Spring Cache on methods that take an array or collection parameter?

I want to use Spring's Cache abstraction to annotate methods as #Cacheable. However, some methods are designed to take an array or collection of parameters and return a collection. For example, consider this method to find entites:
public Collection<Entity> getEntities(Collection<Long> ids)
Semantically, I need to cache Entity objects individually (keyed by id), not based on the collection of IDs as a whole. Similar to what this question is asking about.
Simple Spring Memcached supports what I want, via its ReadThroughMultiCache, but I want to use Spring's abstraction in order to support easy changing of the cache store implementation (Guava, Coherence, Hazelcast, etc), not just memcached.
What strategies exist for caching this kind of method using Spring Cache?
Spring's Cache Abstraction does not support this behavior out-of-the-box. However, it does not mean it is not possible; it's just a bit more work to support the desired behavior.
I wrote a small example demonstrating how a developer might accomplish this. The example uses Spring's ConcurrentMapCacheManager to demonstrate the customizations. This example will need to be adapted to your desired caching provider (e.g. Hazelcast, Coherence, etc).
In short, you need to override the CacheManager implementation's method for "decorating" the Cache. This varies from implementation to implementation. In the ConcurrentMapCacheManager, the method is createConcurrentMapCache(name:String). In Spring Data GemFire, you would override the getCache(name:String) method to decorate the Cache returned. For Guava, it would be the createGuavaCache(name:String) in the GuavaCacheManager, and so on.
Then your custom, decorated Cache implementation (perhaps/ideally, delegating to the actual Cache impl, from this) would handle caching Collections of keys and corresponding values.
There are few limitations of this approach:
A cache miss is all or nothing; i.e. partial keys cached will be considered a miss if any single key is missing. Spring (OOTB) does not let you simultaneously return cache values and call the method for the diff. That would require some very extensive modifications to the Cache Abstraction that I would not recommend.
My implementation is just an example so I chose not to implement the Cache.putIfAbsent(key, value) operation (here).
While my implementation works, it could be made more robust.
Anyway, I hope it provides some insight in how to handle this situation properly.
The test class is self-contained (uses Spring JavaConfig) and can run without any extra dependencies (beyond Spring, JUnit and the JRE).
Cheers!
Worked for me. Here's a link to my answer.
https://stackoverflow.com/a/60992530/2891027
TL:DR
#Cacheable(cacheNames = "test", key = "#p0")
public List<String> getTestFunction(List<String> someIds) {
My example is with String but it also works with Integer and Long, and probably others.

Storing session data in controller

I'm new to Spring. I'm working on a MVC application that would works as follows:
1) user fills the form with data necessary to create the connection to some service
2) controller gets the data from input, create new object serviceManager and save this object e.g in some HashMap with serviceId
3) next time user wants to use this service, controller using serviceId reads data from HashMap.
So I simply need to store this HashMap throughout the whole session in my controller for future use. What would be the best way to accomplish that? Maybe creating serviceManager object each time and reading data from database is the proper solution? In my controller I'm already using #Autowired fields which perfectly serve the purpose, but they're defined in spring xml and I have to store the data dynamically.
Seems your requirement is kind of same with mine which I should keep the main data in the session and every time get the detail data from client and combine 2 kind of data to retrieve something from database. I just put the main part data in the session and then in the whole session that I can get it. I also try to use #SessionAttribute, but after tried dozens of time, I gave it up, it has a lots of problems. So if you can, I just recomment you to store the data in session, that's the samplest way.
I'm newish to spring myself, but as far as putting this in the session:
#Controller
#SessionAttributes({"myObject"})
public class MyController() {
...
#RequestMapping(value="/foo")
// Corrected as per Costi below
// public String someMethod(#PathVariable MyObject myObject) {
public String someMethod(#ModelAttribute MyObject myObject) {
...
}
}
#SessionAttributes will put a MyObject named myObject into the session, if it's not already there, and the #PathVariable pulls it down so you can use it in the method.
The curlys in session attributes aren't necessary for just one attribute, however, you can specify more than one, comma separated, when you use the array notation (which is to say: the curlys)

How to handle externally stored default values in Domain Class

I want to be able to set default values for some fields in my domain classes.
Till now I had a class which stored a Map of settings for my whole project, with a task in mind to move this map into a redis database.
The day has come and I moved all the data to redis and created a nice spring bean to get/set the values.
However...
it seems that default values are set on the domain class instance before bean is injected.
This kind of breaks the whole process.
Also... there's an issue with unit tests.
I've created a class which implements the same interface as the spring bean and holds test values. I wanted to inject it into domain classes, but this fails as well.
So right now I'm trying to find a good way to handle externally stored defauls values for my domain classes with ability to run unit tests.
Any thoughts?
There are a few different approaches you could take:
Introduce a separate bean with the default values so that those are supplied in the same way as they were before. In a separate higher level context or later on in application startup, you could then override the bean definition with the one that pulls from the database
Use a BeanPostProcessor or BeanFactoryPostProcessor to specify the default values, then use your new bean for retrieving new values
If neither of these answers is helpful, please post your setup and example code so I can get a clearer picture of what you're trying to do.
What I did in the end:
I've created a class which is connecting to Redis and gets me all the data I require.
For unit testing I've created a copy of this class, it implements the same interface but instead of getting the data from Redis it has a simple Map inside and get's the data from there. In the end it acts the same, but the data is stored internally. So in my unit tests I just inject this Unit test version of this class where appropriate.
Probably not the best solution there is but it worked for me for the last few months.

Resources