In transferring our enterprise application to Cuba, we are becoming increasingly aware of a need in the Middleware to know where a request has come from as well as being able to tell if certain logical checks or processes have already occurred. I have two questions:
From an Entity Listener, is it possible to determine if the request for the update/insert came from the UI layer, or from the rest services. We need to differentiate our logic depending on how the application is being accessed. (E.g. interfaces may need certain actions to take place but will need other actions to be ignored). We also have more advanced validation outside of Bean Validation that may need to be fired in different circumstances.
Is it possible to store off variables or data inside of a transaction from a service call to be accessible from inside of an Entity Listener? This would allow the logic in the listener a certain amount of awareness or state management about the circumstances or the environment in which the action has been invoked.
I believe #2 we can work around for the most part if there is no good solution, or perhaps we can create a general service that can do exactly what we need here. #1 though is something that we really need. We’d rather use our entity listeners for what they are intended for and not have to put all of our logic in controllers and custom web service calls to separate our concerns.
#2 is certainly possible using the EntityManagerContext class. You can get it inside a transaction via Persistence.getEntityManagerContext() and put/get any objects into its internal map of attributes. For example:
// in a service
try (Transaction tx = persistence.createTransaction()) {
// ...
persistence.getEntityManagerContext().setAttribute("myAttr", "myValue");
// ...
tx.commit();
}
// in an entity listener
String myAttr = persistence.getEntityManagerContext().getAttribute("myAttr");
#1 can be achieved differently if you add your own interceptor of service calls, like ServiceInterceptor defined in the platform. See cuba-spring.xml for how it is registered. In such interceptor you could set some ThreadLocal variable that could be analyzed in entity listeners later on. It is supposed in this case that services should be invoked only from clients and not from other services inside middleware.
For #1 We noticed that UserSession.GetClientInfo() doesn’t return anything when going through the rest services. It’s populated with client information when users are inputting through the Web front end. Is this something that we could use to easily identify rest service requests without having to create an interceptor? Thanks.
Using UserSession to determine the client is a good idea. But we cannot guarantee that getClientInfo() will always return null or empty string for REST users, because I’m afraid at some point we may decide to return something useful. So I would recommend using a custom session attribute: set it only in the web client after login and analyze on middleware. Session attributes are passed from clients to the middleware and replicated in the middleware cluster (if used).