Why my stateless session bean works as stateful? [duplicate] - java

This question already has an answer here:
#Inject stateless EJB contains data from previous request
(1 answer)
Closed 3 years ago.
I've wrote stateful session bean:
#Stateful
public class SessionBean {
List<Integer> list = new ArrayList<>();
public void addItem(int s) {
list.add(s);
}
public int getItemsCount() {
return list.size();
}
}
and use it in my servlet:
#WebServlet("/add")
public class AddServlet extends HttpServlet {
#Inject
SessionBean sessionBean;
#Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
int i = sessionBean.getItemsCount();
resp.getWriter().write(i + " ");
sessionBean.addItem(i + 1);
}
}
It works as expected, list saves the state and I can use it in next request.
But if I'd change #Stateful on #Stateless I expected not to store state of the bean, and get in each request clean list, but it always save the state of previous request and shows new number. So what is the difference between stateless and stateful? How to see it? As I see, they work the same.
I want to see example that will show something like - here we use stateful and it saves the state, and here we change on stateless and it works differently and not save the state. Please show me the differences.

But if I'd change #Stateful on #Stateless I expected not to store state of the bean, and get in each request clean list, but it always save the state of previous request and shows new number.
The Stateful vs. Stateless distinction is foremost declarative, not functional. If you declare a session bean to be stateless, then it is your responsibility to ensure that it does not actually retain any state between method invocations.
So what is the difference between stateless and stateful? How to see it? As I see, they work the same.
One of the more important differences is that if you declare a bean stateless then you afford the container the option of serving different requests with different bean instances. If it opted to do so then that could make a declared-stateless bean that in fact retains state appear not to retain state after all, at least to a limited extent. But the container is not required to do that, so if your stateless bean violates its contract by retaining state, then that will probably be visible to clients sooner or later.
There is more (rather a lot more, in fact -- read the specifications), but the most important thing is what I led off with. To put it another way, the correct declaration of a session bean as stateless vs. stateful is part of its developer's contract with the container in which it is deployed. A bean does not behave differently than its code demands just for being declared stateless.

Stateless session beans are not expected to carry any form of state, e.g. instance variables. Therefore, containers often maintain a pool of stateless beans so they can be reused by different clients.
The Oracle doc mentions the following about session beans: http://docs.oracle.com/javaee/5/tutorial/doc/bnbly.html
Clients may, however, change the state of instance variables in pooled stateless beans, and this state is held over to the next invocation of the pooled stateless bean.
This phenomenon is what you might be experiencing and why the list not empty.

Related

Java EE 7 - How start a transaction from inside a container?

I'm using a Java EE 7 + GlassFish and need to perform some operation against a number of JPA entities from a stateless bean.
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
///do some work against entity
}
}
}
This JobRunner bean is injected into the servlet and I invoke do() method from the web UI.
The issue is that all entities are being changed within one transaction so if one fails everything is rolled back what is not desirable. Is there a way to start and close a new transaction for each entity (i.e. for each iteration of the loop)?
I can write an external client and make a loop there calling a stateless bean for each entity but it's not something that completely works for me as I prefer to keep an app monolithic. Can I somehow manage transactions form inside a container?
Maybe JMS helps? If I implement a doer as message listener and will be sending a message for each entity, will it start a new transaction for each one?
#Stateless
public class JobRunner
{
public void do()
{
for (Entity entity:facade.findAll())
{
sendMessageToRealDoer(entity);
}
}
}
Create another bean, specifying #TransactionAttribute(TransactionAttributeType.REQUIRES_NEW), at method or bean level:
import javax.ejb.TransactionAttribute;
import javax.ejb.TransactionAttributeType;
#Stateless
public class JobWork {
#TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
public void doWork(Entity entity) {
// do what you would do in the loop with the Entity
// this runs in a new transaction
}
}
I wish I could tell you that you only need to annotate a method of the same bean (JobRunner) and simply call it. This is not possible (EDIT)without workarounds - check comment from Steve C(/EDIT) because when calling methods of this object in EJBs and CDI beans the interceptors do not get called. Transactions are implemented with interceptors in both cases.
Some notes:
If the total duration of the operations in the loop is expected to be long, you will get a timeout in the outer transaction, that is implicitly started for the JobRunner stateless EJB. You will want to take measure that no "outer" transaction is started.
Sending the data to a queue will work too; but queues will process them asynchronously, meaning that the execution will return to the servlet calling JobRunner.do() most probably before all items have been processed.

Guice Provider<EntityManager> vs EntityManager

I was trying to get simple webapp working with Guice and JPA on Jetty, using the persistence and servlet guice extensions.
I have written this Service implementation class:
public class PersonServiceImpl implements PersonService {
private EntityManager em;
#Inject
public PersonServiceImpl(EntityManager em) {
this.em = em;
}
#Override
#Transactional
public void savePerson(Person p) {
em.persist(p);
}
#Override
public Person findPerson(long id) {
return em.find(Person.class, id);
}
#Override
#Transactional
public void deletePerson(Person p) {
em.remove(p);
}
}
And this is my servlet (annotated with #Singleton):
#Inject
PersonService personService;
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
String name = req.getParameter("name");
String password = req.getParameter("password");
String email = req.getParameter("email");
int age = Integer.valueOf(req.getParameter("age"));
Person p = new Person();
p.setAge(age);
p.setName(name);
p.setEmail(email);
p.setPassword(password.toCharArray());
logger.info("saving person");
personService.savePerson(p);
logger.info("saved person");
logger.info("extracting person");
Person person = personService.findPerson(p.getId());
resp.getWriter().print("Hello " + person.getName());
}
When I run this it works, and I get the name sent to the client, but when I look at the log I see that there is no DML generated for the insertion and selection from postgresql does not return any results, which means it wasn't really persisted.
I debugged through the code and I saw that JpaLocalTxnInterceptor called txn.commit().
Then I made a change to PersonServiceImpl and used Provider<EntityManager> instead of just EntityManager and it worked as expected. Now I don't really understand why and it's probably because I don't really understand the idea behind Provider.
On the Guice wiki page it says:
Note that if you make MyService a #Singleton, then you should inject Provider instead.
However, my PersonServiceImpl is not a #Singleton so I am not sure why it applies, perhaps it's because of the Servlet?
I would really appreciate if you could clear this out for me.
You need Provider<EntityManager> because Guice's built-in persistence and servlet extensions expect EntityManager to be request-scoped. By injecting a request-scoped EntityManager from a service held in a singleton servlet, you're making a scope-widening injection, and Guice won't store data from a stale, mismatched EntityManager.
Providers
Provider is a one-method interface that exposes a get() method. If you inject a Provider<Foo> and then call get(), it will return an instance created the same way as if you had injected Foo directly. However, injecting the Provider allows you to control how many objects are created, and when they are created. This can be useful in a few cases:
only creating an instance if it's actually needed, especially if the creation takes lots of time or memory
creating two or more separate instances from within the same component
deferring creation to an initialization method or separate thread
mixing scopes, as described below
For binding of X, Provider<X>, or #Provides X, Guice will automatically allow you to inject either X or Provider<X> directly. You can use Providers without adjusting any of your bindings, and Providers work fine with binding annotations.
Scopes and scope-widening injections
Broadly speaking, scopes define the lifetime of the object. By default, Guice creates a new object for every injection; by marking an object #Singleton, you instruct Guice to inject the same instance for every injection. Guice's servlet extensions also support #RequestScoped and #SessionScoped injections, which cause the same object to be injected within one request (or session) consistently but for a new object to be injected for a different request (or session). Guice lets you define custom scopes as well, such as thread scope (one instance per thread, but the same instance across injections in the same thread).
#Singleton public class YourClass {
#Inject HttpServletRequest request; // BAD IDEA
}
What happens if you inject a request-scoped object directly from within a #Singleton component? When the singleton is created, it tries to inject the instance relevant to the current request. Note that there might not be a current request, but if there is one, the instance will be saved to a field in the singleton. As requests come and go, the singleton is never recreated, and the field is never reassigned--so after the very first request your component stops working properly.
Injecting a narrow-scope object (#RequestScoped) into a wide scope (#Singleton) is known as a scope-widening injection. Not all scope-widening injections show symptoms immediately, but all may introduce lingering bugs later.
How Providers help
PersonService isn't annotated with #Singleton, but because you're injecting and storing an instance in a #Singleton servlet, it might as well be a singleton itself. This means EntityManager also has singleton behavior, for the same reasons.
According to the page you quoted, EntityManager is meant to be short-lived, existing only for the session or request. This allows Guice to auto-commit the transaction when the session or request ends, but reusing the same EntityManager is likely preventing storage of data any time after the first. Switching to a Provider allows you to keep the scope narrow by creating a fresh EntityManager on every request.
(You could also make PersonService a Provider, which would also likely solve the problem, but I think it's better to observe Guice's best practices and keep EntityManager's scope explicitly narrow with a Provider.)

How to pass data from EJB Interceptor to Interceptor in Async EJB

I have 2 Stateless EJBs StatelessA and StatelessB, both of them have interceptors InterceptorA and InterceptorB respectively. Also, StatelessB has Asynchronous methods. Something like this:
#Stateless
#Interceptors(InterceptorA.class)
public class StatelessA{...
#Stateless
#Asynchronous
#Interceptors(InterceptorB.class)
public class StatelessB{...
When calling a method on StatelessA, it calls several StatelessB methods and returns a value.
I am trying to develop 2 interceptors to store the total time and the subtotal times of StatelessB calls, this is the objective of the interceptors.
I need to do it so InterceptorA can see the detail of InterceptorB data, so I store only a value in the DB, containing the total time (of SLSB A) and the subtotal times (of SLSB B).
I tried using a ThreadLocal variable (containing a list of times, something like long[]), which works fine if StatelessB is not asyncrhonous.
The problem is that when it is asynchronous, the variable is not available, since it is running in a different thread (AFAIK).
I also tried injecting EJBContext or using the InvocationContext, but none of them works.
Can someone point me out what other alternatives do I have?
Thanks in advance.
I was thinking this over and over, and arrived to a solution, which is using the security context to pass data.
The solution involves using the only data propagated in an asynchronous invocation, as specified in EJB 3.1:
4.5.4 Security Caller security principal propagates with an asynchronous method invocation. Caller security principal propagation
behaves exactly the same for asynchronous method invocations as it
does for synchronous session bean invocations.
In JBoss, one can access the security context and use a data map in it to pass the values from InterceptorA to InterceptorB, as follows:
In InterceptorA:
SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
securityContext.getData().put("interceptorAData",data);
In InterceptorB:
SecurityContext securityContext = SecurityContextAssociation.getSecurityContext();
securityContext.getData().get("interceptorAData");
I tested it and it works great in JBoss EAP 6.1.
This solution implies couplig the interceptor to the server implementation (JBoss AS), but the principle works for other servers.
The advantage is that it decouples the application logic from the interceptors, which was the first objective.
I appreciate any comments.
Would it work to store the information you need in an #Entity object and then use the #PersistenceContext annotation to inject an EntityManager into the beans to persist and find the data? Something like:
#PersistenceContext
EntityManager entityManager;
...
method() {
MyEntityTimer met = new MyEntityTimer(getCurrentTime(), id);
entityManager.persist(met);
}
...
elsewhere:
MyEntityTimer met = entityManager.find(MyEntityTimer.class, id);
and:
#Entity
#Table(name = "TABLE")
public class MyEntityTimer {
#Id
#Column(name = "ID")
private int id;
...
}
I'll answer my question with what I ended up doing.
The only way I found to pass a variable from interceptor A to interceptor B was adding a parameter to the EJBs A and B, something like this:
#Stateless
#Interceptors(InterceptorA.class)
public class StatelessA{
public void methodA(Object reserved, ...other params )
#Stateless
#Asynchronous
#Interceptors(InterceptorB.class)
public class StatelessB{
public void methodB(Object reserved, ...other params)
This way, when InterceptorA is called, I'll set the reserved parameter with the data I need to share with InterceptorB.
InterceptorB will access this variable with no issue getting it from the parameters.
The down side to this solution is that the dummy parameters are needed, coupling in some way the EJBs with the interceptors..

CDI and pooling

Does CDI allows pooling in some way?Because I thought this is a feature of EJB beans but Adam Bien says in this screencast that container chooses whether to create new instance of class through reflection or use the existing one. So if I have for example these two beans
#RequestScoped
public class RequestBean {
public void doIt() {
}
}
#SessionScoped
public class SessionBean {
#Inject
private RequestBean bean;
public void doSomething() {
bean.doIt();
}
}
the question is - is there always new instance of RequestBean created upon calling doSomething or does CDI container somehow manage instances in pool?
The first one is scoped to the request, so a new instance is created for each request. The second one is scoped to the session, so a new one is created for each session.
CDI doesn't pool and recycle the objects, because it has no idea if the objects are stateful or not, and you don't want, in a request, to get back the state that a bean had in a previous request. That would ruin the whole point of the request/session scope.
Unless beans are really costly to create (because they start a new connection or something like that), pooling them doesn't bring any advantage. Short-lived objects are very fast to create and garbage collect nowadays. And if the bean is really expensive to create, then it should probably be a singleton.

Possible to inject same stateful session bean instance into multiple other session beans?

Is it possible to make the container inject the same stateful session bean instance into multiple other stateful session beans?
Given the following classes:
#Stateful
public class StatefulTwoBean implements StatefulTwo {
#EJB
private StatefulOne statefulOne;
}
#Stateful
public class StatefulThreeBean implements StatefulThree {
#EJB
private StatefulOne statefulOne;
}
In the above example, StatefulTwoBean and StatefulThreeBean each get injected their own instance of StatefulOneBean.
Is it possible to make the container inject the same instance of StatefulOneBean into both StatefulTwoBean and StatefulThreeBean?
The problem is this - Stateful beans' isntances are allocated by differentiating the clients that call them. Glassfish (and perhaps others) don't propagate this difference on injected beans. The EJB specification, as far as I remember, isn't clear about this.
So your solution is to implement the differentiation yourself. How to achieve this. I'm not pretending this is the most beautiful solution, but it worked. - we did it by putting a Facade (an EJB itself) (I'm calling it a facade, although it does not entirely cover the facade pattern) in front of all our EJBs, with the following code:
public Object call(Object bean,
String methodName,
Object[] args,
Class[] parameterTypes,
UUID sessionId) throws Throwable {
//find the session
SessionContext sessionContext = SessionRegistry.getSession(sessionId);
//set it as current
SessionRegistry.setLocalSession(sessionContext);
.....
}
The important parameter is sessionId - this is something both the client and the server know about, and identifies the current seesion between them.
On the client we used a dynamic proxy to call this facade. So the calls look like this:
getBean(MyConcreteEJB.class).someMethod(), an the getBean method created the proxy, so that callers didn't have to know about the facade bean.
The SessionRegistry had
private static ThreadLocal<SessionContext> localSessionContext = new
ThreadLocal<SessionContext>();
And the SessionContext was simply a Map providing set(key, value) and get(key)
So now, instead of using #Stateful beans to store your state, you could use the SessionContext.
In EJB3.1 you can create your StatefulOne bean as singleton (using the #Singleton annotation) giving you the desired semantics. JBoss should already support this annotation (they've wrote the standard).

Categories

Resources