What are the techniques to manage "session" or invocation context for Stateless EJBs during Remote calls? - session

I am writing an application that uses RMI to invoke EJBs. The EJBs are Stateless; the business requirements do not require conversational state with the client.
One of the parameters to the EJB method calls is a "User" object used to determine if the user associated with the call has permission to perform the action. We are not using container-managed auth-auth: the User object is just a POJO provided by the remote client.
I would like to make this User object globally available/injectable within the "session" or invocation context. I am aware that Stateless EJBs do not have a "session" in the EJB sense; what I mean by "session" is "the current invocation". For example, say we have only one remote EJB with two methods:
myStatelessEjb.add(Thing, User)
myStatelessEjb.update(Thing, User)
These methods call many more methods: there are other EJBs involved, Bean Validators, etc. Rather than passing-around the User object everywhere, I would like to make the User object globally available/injectable with the context of the current remote EJB invocation.
I could of course just pass around the User object or encapsulate it with "Thing", but I thought maybe it would be a better design to not "pollute" my objects and APIs with User since it's a cross-cutting concern.
Notes (for emphasis):
I am using RMI.
There is no HTTP session, because I am using RMI.
I am not using container-managed auth-auth.
I am using container-managed transactions.
Is there a standard technique suitable for this problem? e.g. Perhaps the remote client should invoke a Stateful EJB which will hold the User, or maybe ThreadLocal is appropriate, or maybe I can hook onto the container-managed transaction, or maybe there's already an applicable session/context I'm unaware of.

Easiest way would be to store the user in a #RequestScoped CDI bean and inject that as required:
#RequestScoped
public class RequestUser {
private User user;
//getter and setter for user
}
#Remote
#Statless
public class MyRemoteInterface {
#Inject
private RequestUser requestUser;
...
public void foo(User user, Bar bar) {
request.setUser(user);
...
}
}
#Stateless
public class OtherEJB() {
#Inject
private RequestUser user;
public void doBar(Bar bar) {
User user = user.getUser();
...
}
}
While #SessionScoped is useful for HTTP sessions only, #RequestScoped has broader applicability:
public #interface RequestScoped
Specifies that a bean is request scoped.
The request scope is active:
during the service() method of any servlet in the web application, during the doFilter() method of any servlet filter and when the
container calls any ServletRequestListener or AsyncListener,
during any Java EE web service invocation,
during any remote method invocation of any EJB, during any asynchronous method invocation of any EJB, during any call to an EJB
timeout method and during message delivery to any EJB message-driven
bean, and
during any message delivery to a MessageListener for a JMS topic or queue obtained from the Java EE component environment.

Related

Is it possible to invoke a MessageDrivenBean remotely directly through a #Remote interface?

I am currently learning the basics of EJB 2+. In the book Java EE 7 The Big Picture, it was mentioned:
Session beans are generally accessed through a remote interface (though, as we shall see, there are cases where a remote interface is not required), while message-driven beans have only a bean implementation class.
Based on the statement above, invoking a message-driven bean (MDB) just like invoking a remote session bean through a remote interface, whose server-side interface is done with #Remote annotation, seems to be impossible.
For instance, if there is a MDB on a remote EJB container:
#Remote
#MessageDriven(mappedName="jms/HelloQueue")
public class HelloMDB implements MessageListener {
public void onMessage(Message msg) {
//implementation
}
}
Question: can the MDB mentioned above be invoked at all by a remote client directly and programmatically .e.g. through JNDI?
No, an MDB cannot be invoked by a remote client directly as noted in this Java EE 7 tutorial from Oracle which states:
Client components do not locate message-driven beans and invoke methods directly on them.
If you want to invoke the MDB's onMessage then simply send a message to the destination where it's listening.

Spring service method validation

I have a service class which is annotated with #Validated.
In this class I have a method with an argument which is annotated with #Valid.
If the method is called from another class instance with an argument that is not valid an exception is thrown.
As expected an error of type ConstraintViolationException is thrown.
If I call this method from another service method (internal call) no validation is performed and an error arises in the body of the method.
This is not what I want. Apparently calls made from within are not validated.
Investigating the problem I found out that the method was not invoked using a Spring proxy bean.
I fixed the problem by retrieving the proxy from the (#Autowired) application context and invoke the method using the proxy:
((T) context.getBean(this.getClass()).myMethod(validatedArgument)
This is an ugly solution.
How can I configure Spring so that method calls made from within are validated?
There is a tricky way to autowire the service to itself.
#Service
public class MyService {
#Autowired
private MyService copy;
private void call() {
//myMethod(validatedArgument);
copy.myMethod(validatedArgument);
}
}
The way Spring handles aspects is such that they are only invoked when one instance sends a message to a different instance. There are some ways to overcome this, but in your case, the fact that you want to do it is probably revealing a design flaw.

Why is injecting a Stateful Session bean in JSF/ CDI managed beans is considered bad?

Pascal Thivent mentions here that -
If you are using SFSB, then you must avoid injecting them into classes
that are multithreaded in nature, such as Servlets and JSF managed
beans (you don't want it to be shared by all clients).
Moving swiftly on, BalusC also put forwards the same thing here-, but indirectly.
....use SFSB only when you want a real stateful session bean
Consider a Session Scoped Managed bean-
#SessionScoped
public class Bean{
#EJB
EjbBean ejbBean;
}
with
#Stateful
public class EjbBean{
}
But the above SessionScoped bean will be linked to one client only and as such will have state/ instance variables different from other session scoped bean. Subsequently, any stateful EJB bean will not be shared by other clients.
Please suggest on what the author implies when he says-
you don't want it to be shared by all clients
I do perfectly understand the difference b/w HttpSession & the session word in Stateless Session Bean.

EJB 3.0 , are thread safe?

Hy,
I am a newbie in EJB. Now I am studying the EJB 3.0 specification. If I have two different JSF managed beans like the next ones:
#ManagedBean
public class CocheBean {
#EJB
private ICochesService cochesService = null;
}
#ManagedBean
public class UsuarioBean {
#EJB
private ICochesService cochesService = null;
}
The injecteds implementations for cochesService are the same in both cases?, I mean, for each annotation, the ejb container gets back a new object or is the same object?
Why do they refer to EJBs as session beans? Are they session scoped? Do they exist till the session of a user expires?
Its said that you dont have to worry if the stateless EJB are thread safe because the container has a pool of different instances for each request but if they are stateless and there is no danger that multiple threads access to just one ejb, why the container creates a pool of them and not just one?
Using JSF managed beans, if this bean is request or session scoped and because we inject the ejbs in this beans, they cannot be called more than once per user or per request at the same time, right?
How to specify the transactional atributes to EJB bean methods, with JPA annotations?
Thanks
This depends - if ICochesService is stateless than each of them will have different object. If it's stateful or singleton than both beans will have the same object injected
Answer to both questions is no :) See the Oracle docs
Exactly
You can call as many beans as you want per each request.
See the Oracle tutorial for Java Transaction API.

Listening to when the user session is ended in a JSF managed bean

Is it possible to do something like this: When a user session starts I read a certain integral attribute from the database. As the user performs certain activities in this session, I update that variable(stored in session) & when the session ends, then I finally store that value to the DB.
My question is how do I identify using the JSF framework if the user session has ended & I should then store the value back to DB?
Apart from the HttpSessionListener, you can use a session scoped managed bean for this. You use #PostConstruct (or just the bean's constructor) and #PreDestroy annotations to hook on session creation and destroy
#ManagedBean
#SessionScoped
public class SessionManager {
#PostConstruct
public void sessionInitialized() {
// ...
}
#PreDestroy
public void sessionDestroyed() {
// ...
}
}
The only requirement is that this bean is referenced in a JSF page or as #ManagedProperty of any request scoped bean. Otherwise it won't get created. But in your case this should be no problem as you're apparently already using a session scoped managed bean, just adding a #PreDestroy method ought to be sufficient.
My question is how do I identify using
the JSF framework if the user session
has ended & I should then store the
value back to DB?
The JSF framework does not have a separate concept of a session; it uses the underlying session management features of the Servlet specification.
You would have to create a HttpSessionListener that provides hooks for you to capture the session creation and destruction events, where you can read the value and store it back into the DB.
HttpSessionListener, or if you need Dependency Injection for that save, you might use #PostConstruct & #PreDestroy. Remember that the session is destroyed when you call invalidate() or after session timeout, not when the user closes the browser. Why do you use Session Scope anyway, Conversation Scope might fit you better.

Resources