Access an existing stateful instance inside stateless, java ee 6

Is it possible to access a session with a bean state inside a dumb bean?

My problem is that I have a bean session called User, and I want to access the user information inside the idle bean ...

I try like this:

Ejb Side:

@Stateless public class OfferManagerBean implements OfferManagerLocal, OfferManager { @Resource private SessionContext context; @EJB private ro.project.ejb.interfaces.User user; public String getUsername() { user = (ro.project.ejb.interfaces.User) context.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User"); return user.getUsername(); } 

Client side

  User user = (User) ctx.lookup("java:global/project/projectEJB/User!ro.project.ejb.interfaces.User"); user.setUsername("Alex"); OfferManager offerManager = (OfferManager) ctx.lookup("java:global/project/projectEJB/OfferManagerBean!ro.project.ejb.interfaces.OfferManager"); assertEquals(offerManager.getUsername(), "Alex"); 

The result of this test case: java.lang.AssertionError: expected:<null> but was:<Alex>

it fails .. It seems that as I request a stateful bean, it returns me a new instance ...

  • I know why this is not working. Because my test fails: P. I get a new instance.
  • I want to check certain registered user permissions in EJB because I donโ€™t want to count on the client side, because I can make a mistake there, or I will tell other developers about creating a graphical interface for my project.
  • I do not want to use Java EE Security beucause. I do not know how to login in an RCP application.
  • My main question is: how do I access a bean session (same client) inside EJB .. is this possible? And How?

I ask for almost the same thing this guy asks: The concept of a reusable rmi ejb call login session

I want to do this, but not with JAAS ...

Thank you in advance

+4
source share
4 answers

You should never introduce @Stateful bean (SFSB) in @Stateless bean (SLSB). The SFSB lives as long as its client lives (the client is the instance into which the SFSB is inserted, which in this case is the SLSB itself). SLSBs, however, intend to be stateless, and most containers have them in the pool. Therefore, whenever an SLSB returns to the pool after use, it will be reused elsewhere, but it contains the same SFSB instance as when the SLSB was first created! This can lead to undesirable results.

In addition, every time you get SFSB from JNDI, you will get a brand instance that is not like SLSBs that are not used elsewhere. An SFSB client is the current instance of the client class in which you have SFSB from JNDI. You must save this instance yourself and reuse the same instance until you complete the transaction on it. One way is to store it in an HTTP session on its own or in the bean session-controlled bean of your MVC environment.

The functional requirement is not entirely clear to me, so itโ€™s hard to give a suitable answer on how to solve your specific problem, but I get the impression that you really need to store the user in an HTTP session and not in SFSB. The most common novice user error regarding beans session it is that they misinterpret the โ€œsessionโ€ in the EJB context as an HTTP session.

See also this answer to a question of the same type for a more detailed explanation: Does the malicious JSF bean request keep a new session recreated based on the state of beans for each request? According to your background, you are familiar with JSF, so this answer should be clear.

+10
source

In the general case, you can access a specific existing session with a state of bean inside an idle bean. It can be specified, for example, as an argument to a business method of a session without a bean state.

But what you are trying cannot work. The reason is that both dependent injections (@EJB) and lookup (ctx.lookup ...) are guaranteed to call newInstance and, as a result, you will have a new instance.

This is explained in the specification in the following words:

A bean session when life begins, when a client receives a link to a session with a check of the state of the bean through an injection or JNDI lookup dependency, or when the client calls the create method on the bean session's home interface. This calls the container to call newInstance in the bean session class to create a new session bean.

+3
source

In case others are not clear enough: you are doing it wrong!;)

I agree that this can be confusing, but the only session in the beans beans is stored in the bean proxy that you get from the InititalContext.

The various beans that you get from this context do not use a shared session. In EJB, beans are not stored in an EJB session, but they are this session.

In other words, InitialContext (ctx in your code) is NOT the EJB equivalent for HttpSession.

The worst part is that in your code the user is an EJB bean. It is not right.

The user is a noun in your application. They are represented by JPA entities or simple "normal" java beans. EJBs are designed to implement verbs in your application: Services, DAO, Repositories, etc.

It is assumed that the state in the beans state session will contain model data during the business process (for caching, locking, redundancy, etc.). In no case should this state be model data.

My advice: let your current "design" go. Do not try to fix it, do not try to justify it. Let it, delete your code, do not look back. Read some good books about EJB, and then get started.

Good luck

+2
source

I do not check if you are doing the right / wrong use of SFSB and SLSB. But below is the answer to your problem

Option 1: From your servlet, do a JNDI lookup for SFSB. It should be once. Save the returned SFSB link to HttpSession. When you call the SLSB method, which needs an SFSB instance to store user data, pass this SFSB reference object as a parameter to the SLSB method. Then access it from the SLSB method and save the user data.

The problem with Option-1: you bind your persistence mechanism (SFSB) to your user interface (since you store it in HttpSession and pass it). Tomorrow, if you want to switch to another storage mechanism, like a cache, you will need to rework a lot. Again, if you want to expose your SLSB method as a WebService, you cannot do this because you cannot xml-ize the reference to the SFSB object. In short, a bad option.

Option-2: have a static hash file in some class in the business layer. Suppose you have unique transaction attributes for each transaction, something like an identifier. When you start a transaction, create an SFSB from your business layer, save its link in a static hash map with identifier as a key. When you call the SLSB service method, skip this identifier (I assume that each transaction may have a unique identifier). From the SLSB method, use the identifier to search for the SFSB link stored in the static hash map. Use it for storage. In this case, your interface and SFSB are not connected. Tomorrow, if you want to strengthen the persistence mechanism, you can do this without affecting customers, as your changes will be limited within the BC level.

+1
source

Source: https://habr.com/ru/post/1397664/


All Articles