Spring boot #Cacheble with Ehcache - java

I'm using Spring boot with Ehcache for caching some data in the application.
The application is a rest service that caches some data that has high usage.
The code in our controllers looks like:
#Cacheable("CategoryModels")
#GetMapping("/category/{companyId}")
public List<CategoryViewModel> getAllCategories(#PathVariable(value = "companyId", required = true) long companyId,
#RequestHeader("user") String user) {
//custom code here
}
Now in some situations the users are getting different data sets back from the server. Can someone explain this in the above situation?
If data is changed in the database I refresh the cache and the program will auto update the updated data to the
For refreshing the cache I use a custom written method:
Cache categoryCache = (Cache) manager.getCache("CategoryModels").getNativeCache();
categoryCache.removeAll();
categoryController.getAllCategories(company.getCompanyId(), null);
I have the same behavior on other caches that are used and refreshed on the same way the above cache is used.

You should try to parametrize your cache definition with :
#Cacheable(value="CategoryModels", key="{ #root.methodName, #companyId, #user.id }")

It may be a couple of things. First off the default key resolver that spring provides does not consider anything but the names of the parameters. The cleanest way to fix this kid to write your own key revolver that considers both class and method, without this it could be possible to get back data from a completely different method that happens to share the same parameter list.

Related

Limit requests per t in Spring Boot

I am writing a REST service in spring boot and I've come across a problem I can't solve. Been googling for hours but most examples seem to bee way too complicated for me because I'm new to Spring Boot.
Let's assume a user can save an object into my database:
#RequestMapping(value = "/person", method = RequestMethod.GET)
public void saveName (#RequestParam String name){
personRepository.save(new Person(name));
}
Now I have been trying to find a way so an anonymous user can only make a limited amount of entries per minute.
You need to use Spring Security for this problem. You can check if the user is anonymous through isAnonymous() annotation and to limit it you can use a table to capture the attempts. Since you are new to Spring Boot. It's better to brush up on Spring Security as it gives you a fine-grained control over it.
If you do not want spring security, then, the same approach applies, use a table to capture unauthenticated user attempts. Also, there is a default session id, you could make use of this instead of going through the hassle of getting Ip addresses.
Even though the client is not an authenticated user, it still has its own session, so you can store in the session how many entries he has added. Don't store an interger but a collection of times, so you can remove the old ones if they are older than a minute.

RedisCacheManager Not Updating keyspace_misses

I’m using the spring-boot spring-data-redis 1.8.9.RELEASE RedisCacheManager implementation of CacheManager for caching. One metric that I want visibility into is the cache hit/miss ratio. To get that, I’m extracting the keyspace_hits and keyspace_misses exposed via the redis server which can also be viewed via the redis_cli with INFO STATS. The problem is that RedisCacheManager never registers cache misses, i.e. keyspace_misses never increments even if there is a cache "miss".
Debugging the code, I see that spring-data-redis actually checks to see if the key EXISTS in redis before retrieving it. I see the sense with this approach however when EXISTS is executed against the redis server, it does not register a cache miss.
Is there any way to use RedisCacheManager and register cache misses? I know I can use other redis objects to accomplish this but I was wondering if it could be done with the standard CacheManager implementation?
Edit
The ideal solution won't add a great deal of overhead and I am unable to edit the configuration of the redis server.
Code that RedisCacheManager uses when retrieving an element from cache. Notice Boolean exists:
public RedisCacheElement get(final RedisCacheKey cacheKey) {
Assert.notNull(cacheKey, "CacheKey must not be null!");
Boolean exists = (Boolean)this.redisOperations.execute(new RedisCallback<Boolean>() {
public Boolean doInRedis(RedisConnection connection) throws DataAccessException {
return connection.exists(cacheKey.getKeyBytes());
}
});
return !exists ? null : new RedisCacheElement(cacheKey, this.fromStoreValue(this.lookup(cacheKey)));
}
The above code will execute these commands on redis viewable via MONITOR on a cache miss. Notice again that EXISTS is executed as per the code:
After the above commands are executed, keyspace_misses is not incremented even though there was a cache miss:
The code mentioned in the question is part of RedisCache provided by Spring.
Extend and Create a custom implementation of RedisCache class to override the behavior of "get" method to suit your need.
Extend RedisCacheManager to override the method "createRedisCache" to use your custom RedisCache that you created in first step instead of default cache.

How can I use Hibernate/JPA to tell the DB who the user is before inserts/updates/deletes?

Summary (details below):
I'd like to make a stored proc call before any entities are saved/updated/deleted using a Spring/JPA stack.
Boring details:
We have an Oracle/JPA(Hibernate)/Spring MVC (with Spring Data repos) application that is set up to use triggers to record history of some tables into a set of history tables (one history table per table we want audited). Each of these entities has a modifiedByUser being set via a class that extends EmptyInterceptor on update or insert. When the trigger archives any insert or update, it can easily see who made the change using this column (we're interested in which application user, not database user). The problem is that for deletes, we won't get the last modified information from the SQL that is executed because it's just a plain delete from x where y.
To solve this, we'd like to execute a stored procedure to tell the database which app user is logged in before executing any operation. The audit trigger would then look at this value when a delete happens and use it to record who executed the delete.
Is there any way to intercept the begin transaction or some other way to execute SQL or a stored procedure to tell the db what user is executing the inserts/updates/deletes that are about to happen in the transaction before the rest of the operations happen?
I'm light on details about how the database side will work but can get more if necessary. The gist is that the stored proc will create a context that will hold session variables and the trigger will query that context on delete to get the user ID.
From the database end, there is some discussion on this here:
https://docs.oracle.com/cd/B19306_01/network.102/b14266/apdvprxy.htm#i1010372
Many applications use session pooling to set up a number of sessions
to be reused by multiple application users. Users authenticate
themselves to a middle-tier application, which uses a single identity
to log in to the database and maintains all the user connections. In
this model, application users are users who are authenticated to the
middle tier of an application, but who are not known to the
database.....in these situations, the application typically connects
as a single database user and all actions are taken as that user.
Because all user sessions are created as the same user, this security
model makes it very difficult to achieve data separation for each
user. These applications can use the CLIENT_IDENTIFIER attribute to
preserve the real application user identity through to the database.
From the Spring/JPA side of things see section 8.2 at the below:
http://docs.spring.io/spring-data/jdbc/docs/current/reference/html/orcl.connection.html
There are times when you want to prepare the database connection in
certain ways that aren't easily supported using standard connection
properties. One example would be to set certain session properties in
the SYS_CONTEXT like MODULE or CLIENT_IDENTIFIER. This chapter
explains how to use a ConnectionPreparer to accomplish this. The
example will set the CLIENT_IDENTIFIER.
The example given in the Spring docs uses XML config. If you are using Java config then it looks like:
#Component
#Aspect
public class ClientIdentifierConnectionPreparer implements ConnectionPreparer
{
#AfterReturning(pointcut = "execution(* *.getConnection(..))", returning = "connection")
public Connection prepare(Connection connection) throws SQLException
{
String webAppUser = //from Spring Security Context or wherever;
CallableStatement cs = connection.prepareCall(
"{ call DBMS_SESSION.SET_IDENTIFIER(?) }");
cs.setString(1, webAppUser);
cs.execute();
cs.close();
return connection;
}
}
Enable AspectJ via a Configuration class:
#Configuration
#EnableAspectJAutoProxy
public class SomeConfigurationClass
{
}
Note that while this is hidden away in a section specific to Spring's Oracle extensions it seems to me that there is nothing in section 8.2 (unlike 8.1) that is Oracle specific (other than the Statement executed) and the general approach should be feasible with any Database simply by specifying the relevant procedure call or SQL:
Postgres for example as the following so I don't see why anyone using Postgres couldn't use this approach with the below:
https://www.postgresql.org/docs/8.4/static/sql-set-role.html
Unless your stored procedure does more than what you described, the cleaner solution is to use Envers (Entity Versioning). Hibernate can automatically store the versions of an entity in a separate table and keep track of all the CRUD operations for you, and you don't have to worry about failed transactions since this will all happen within the same session.
As for keeping track who made the change, add a new colulmn (updatedBy) and just get the login ID of the user from Security Principal (e.g. Spring Security User)
Also check out #CreationTimestamp and #UpdateTimestamp.
I think what you are looking for is a TransactionalEvent:
#Service
public class TransactionalListenerService{
#Autowired
SessionFactory sessionFactory;
#TransactionalEventListener(phase = TransactionPhase.BEFORE_COMMIT)
public void handleEntityCreationEvent(CreationEvent<Entity> creationEvent) {
// use sessionFactory to run a stored procedure
}
}
Registering a regular event listener is done via the #EventListener
annotation. If you need to bind it to the transaction use
#TransactionalEventListener. When you do so, the listener will be
bound to the commit phase of the transaction by default.
Then in your transactional services you register the event where necessary:
#Service
public class MyTransactionalService{
#Autowired
private ApplicationEventPublisher applicationEventPublisher;
#Transactional
public void insertEntityMethod(Entity entity){
// insert
// Publish event after insert operation
applicationEventPublisher.publishEvent(new CreationEvent(this, entity));
// more processing
}
}
This can work also outside the boundaries of a trasaction if you have the requirement:
If no transaction is running, the listener is not invoked at all since
we can’t honor the required semantics. It is however possible to
override that behaviour by setting the fallbackExecution attribute of
the annotation to true.

Spring boot response caching

I was trying to understand the caching that happens at the client side.
Unfortunately I am unable to find any resources that can help me out.
I have employee model objects which are fairly small in size.
Once a use a GET request to obtain an employee object, I want it to be cached at the client side
Now when the request comes again to obtain the same employee, I want to see if the actual object has been modified, if not, then serve from the client cache else return the modified object also adding it to the cache.
I am using Spring boot to create a REST endpoint.
What I have been able to figure out is that cache-control would be used some how, but I am not sure how the objects would be added here in spring.
Any help here is much appreciated!!!!
Thanks,
Amar
HTTP caching is not an easy topic. There are different ways to do it, and you should probably start by familiarizing yourself with the mechanisms, this seems to be a good starting resource: HTTP caching
Then, you will probably identify some common usage patterns you will want to reuse. One way to do that is to create custom annotations and write an interceptor that reacts on them.
For example, you could write such an annotation:
#Inherited
#Retention(RUNTIME)
#Target({METHOD, TYPE})
public #interface CacheFor {
long amount();
TimeUnit unit() default TimeUnit.SECONDS;
}
and use it on controller methods like this:
#CacheFor(amount=10, unit = MINUTES)
#RequestMapping(bla bla)
public FooBar serveMyData(){
// code here
}
and in your interceptor, you will need to look at the handler method, check whether it has this annotation, and if it does, set the appropriate headers.

Play Framework 2.1: Overriding configuration file programmatically in Global settings

I'm working to develop a multi-tenant Play Framework 2.1 application. I intend to override the onRequest method of the GlobalSettings class to load and set a custom configuration based on the subdomain of the request. Problem is, I don't see how this would be possible in Play 2.x.
I can override system properties at the command line when starting the server, but how can I do this programmatically in Java code for each request?
The code would look something like this (I assume):
#Override
public play.mvc.Action onRequest(Request request, Method actionMethod) {
//Look up configuration settings in Cache based on request subdomain
//(i.e. Cache.get("subdomain.conf"))
//if not in cache:
//load appropriate configuration file for this subdomain (java.io.File)
//set new configuration from file for this request
//cache the configuration for future use in a new thread
//else
//set configuration from cache for this request
return super.onRequest(request, actionMethod);
}
}
Looking up the URL and getting/setting the cache is easy, but I cannot figure out how to SET a new configuration programmatically for Play Framework 2.1 and the documentation is a little light on things like this.
Any thoughts? Anyone know a better, more efficient way to do this?
So, in a sort of roundabout way, I created the basis for a multi-tenant Play application using a Scala Global. There may be a more efficient way to implement this using a filter, but I'm finding this seems to work so far. This does not appear to be as easily implemented in Java.
Instead of using the configuration file, I'm using the database. I assume it would be far more efficient to use a key-value cache, but this seems to work for now.
In Global.scala:
object Global extends GlobalSettings {
override def onRouteRequest(request: RequestHeader): Option[Handler] = {
if (request.session.get("site").isEmpty){
val id = models.Site.getSiteIDFromURL(request.host)
request.session.+("site" -> id)
}
super.onRouteRequest(request)
}
}
And then, obviously, you have to create a database model to query the site based on the request domain and/or the session value set in the request. If anyone knows a better way I'd love to hear it.

Categories

Resources