0

I have the following design. When a client makes a request to the server, the server creates a state that holds all sorts of info. There are various stateless and stateful beans which need to read and write to this state. Refer to this unprofessional diagram:

enter image description here

The ComputationCycle class is where the processing starts and works by phases. During each phase it calls upon other Manager classes (which behave like utility classes) to help in the computation (diagram shows only for 1 phase). The state is being read and written to both from the CC class and the managers, both are stateless.

State holds Employee, Department and Car classes (in some irrelevant data structure) which are stateful. These classes can also call the Manager classes. This is done by a simple @Inject Manager1. The same way CC uses managers.

My problem is how to access the stateful state (and its contained classes) from the stateless classes (and from the Car, Department and Employee classes too, although I think solving one will solve the other). I can't inject a stateful bean into a stateless bean. So after the client makes a request and the computation cycle starts, how do I access the state related to this request?

One solution is to pass the state to every method in the stateless classes, but this is really cumbersome and bloaty because all methods will have an "idiotic" State argument everywhere.

How can I make this design work the way I want it to?

Mark
  • 2,167
  • 4
  • 32
  • 64
  • Maybe I am misleading your design, but injecting a `@Stateful` into a `@Stateless` is not the correct way. You will end up with unpredictable results. As other has pointed out, you can probably get a better results with a `@Singleton`. – Leonardo Jul 26 '17 at 15:24
  • @Leonardo covener answered that I can do it this way. Is he wrong? – Mark Jul 26 '17 at 15:51
  • There are many resources on the web stating that it is a wrong approach. Here is a stack overflow question answering your doubt: [access existing instance stateful inside stateless, java ee 6](https://stackoverflow.com/questions/9384368/access-existing-instance-stateful-inside-stateless-java-ee-6/9384670#9384670) – Leonardo Jul 26 '17 at 15:56
  • @Leonardo I pointed that out too in his answer comments. he suggested that the `@Inject` instead of `@EJB` along with `@RequestScoped` should work. Also, this is ee7. Do you disagree with his answer? – Mark Jul 26 '17 at 18:49

2 Answers2

4

I can't inject a stateful bean into a stateless bean.

You can absolutely inject dependencies this way.

If the stateful bean is @RequestScoped, any call into the stateless bean on that thread that hits a CDI injected contextual reference (iow proxy) will find its way to the right instance of the stateful bean.

As long as you use CDI, you don't need to trouble yourself with trying to stash things away in your own threadlocals.

covener
  • 17,402
  • 2
  • 31
  • 45
  • That's good news but I read [this](https://stackoverflow.com/questions/11437206/java-ee-6-how-to-call-stateful-session-bean-from-stateless-session-bean?rq=1) Q&A. Is it wrong? – Mark Jul 22 '17 at 16:08
  • It's referring to older EE injection and stateless/stateful as in EJBs. So, I think it's at least wrong in your context. Unfortunately I'm not using EE day to day so I can't quickly verify or demonstrate it in a sample. But it seems fundamental to me that this is perfectly fine to have beans reach into a long-lived scope. – covener Jul 22 '17 at 16:13
  • if your stateless were like singletons, here is a related q https://stackoverflow.com/questions/35624313/injecting-requestscoped-cdi-bean-into-applicationscoped-cdi-bean-via-producer-cl – covener Jul 22 '17 at 16:14
  • I don't think my stateless should be singletons because the whole point of making them stateless is that any of the instances in the pool can answer any call so it's better for performance. If i made them singletons i would have to wait for it to be released each time. I think that's how it works. – Mark Jul 22 '17 at 16:21
  • Ah i also see what you mean about the versions - they are using `@EJB` instead of `@Inject`. Didn't know there is such a big difference. – Mark Jul 22 '17 at 16:24
  • @Mark you can add @Lock(READ) to your relevant singleton methods to serve clients concurrently. – Leonardo Jul 26 '17 at 15:52
  • You were right, I can inject with `@RequestScoped` (tried without and it failed, `@SessionScope` also worked but is less suitable for my case). It does give an odd error though: https://stackoverflow.com/questions/45601299/unexpected-invocation-state-0-error-in-wildfly – Mark Aug 09 '17 at 22:04
1

Buyer beware, ThreadLocal will possibly do what you're wanting, along with a static accessor. However, this class is prone to causing memory leaks if you are not extremely careful to remove each entry at the end of the request. In addition, you seem to be using EJB; I assume they are all in the same JRE. I use ThreadLocal quite a bit in similar situations, and I've had no problems. I use SerletContextListener's to null the static reference to the ThreadLocal when the context shuts down, although that has been problematic on some older Web app servers, so I make sure the ThreadLocal exists before attempting to use it.

EJB can "talk" to each other across servers. It sounds local all your EJB are running in the same context.

Create a class that holds your state.

Extend ThreadLocal--you can do this anonymously--and override initialValue() to return a new instance of your class.

Create a utility class to hold the ThreadLocal as a static field. Don't make it final Create static fetch and remove methods that call ThreadLocal.get() and remove(). Create a static destroy() method that is called when your context shuts down--see ServletContextListener.

Steve11235
  • 2,849
  • 1
  • 17
  • 18
  • What do you mean by "the same JRE"? This is a WAR running in JBoss. Requests come in using JAX-RS which spawns a thread on which all of the above happens. Indeed the State is unique per such a thread so ThreadLocal seems right. Can you explain or show how I would use it? – Mark Jul 22 '17 at 02:33