Starting a CDI conversation and injecting #ConversationScoped bean into stateless session bean - java

Similar questions have been asked, but don't quite address what I'm trying to do. We have an older Seam 2.x-based application with a batch job framework that we are converting to CDI. The job framework uses the Seam Contexts object to initiate a conversation. The job framework also loads a job-specific data holder (basically a Map) that can then be accessed, via the Seam Contexts object, by any service down the chain, including from SLSBs. Some of these services can update the Map, so that job state can change and be detected from record to record.
It looks like in CDI, the job will #Inject a CDI Conversation object, and manually begin/end the conversation. We would also define a new ConversationScoped bean that holds the Map (MapBean). What's not clear to me are two things:
First, the job needs to also #Inject the MapBean so that it can be loaded with job-specific data before the Conversation.begin() method is called. Would the container know to pass this instance to services down the call chain?
Related to that, according to this question Is it possible to #Inject a #RequestScoped bean into a #Stateless EJB? it should be possible to inject a ConservationScoped bean into a SLSB, but it seems a bit magical. If the SLSB is used by a different process (job, UI call, etc), does it get separate instance for each call?
Edits for clarification and a simplified class structure:
MapBean would need to be a ConversationScoped object, containing data for a specific instance/run of a job.
#ConversationScoped
public class MapBean implements Serializable {
private Map<String, Object> data;
// accessors
public Object getData(String key) {
return data.get(key);
}
public void setData(String key, Object value) {
data.put(key, value);
}
}
The job would be ConversationScoped:
#ConversationScoped
public class BatchJob {
#Inject private MapBean mapBean;
#Inject private Conversation conversation;
#Inject private JobProcessingBean jobProcessingBean;
public void runJob() {
try {
conversation.begin();
mapBean.setData("key", "value"); // is this MapBean instance now bound to the conversation?
jobProcessingBean.doWork();
} catch (Exception e) {
// catch something
} finally {
conversation.end();
}
}
}
The job might call a SLSB, and the current conversation-scoped instance of MapBean needs to be available:
#Stateless
public class JobProcessingBean {
#Inject private MapBean mapBean;
public void doWork() {
// when this is called, is "mapBean" the current conversation instance?
Object value = mapBean.getData("key");
}
}
Our job and SLSB framework is quite complex, the SLSB can call numerous other services or locally instantiated business logic classes, and each of these would need access to the conversation-scoped MapBean.

First, the job needs to also #Inject the MapBean so that it can be loaded with job-specific data before the Conversation.begin() method is called. Would the container know to pass this instance to services down the call chain?
Yes, since MapBean is #ConversationScoped it is tied to the call chain for the duration starting from conversation.begin() until conversation.end(). You can think of #ConversationScoped (and #RequestScoped and #SessionScoped) as instances in ThreadLocal - while there exists an instance of them for every thread, each instance is tied to that single thread.
Related to that, according to this question Is it possible to #Inject a #RequestScoped bean into a #Stateless EJB? it should be possible to inject a #ConservationScoped bean into a SLSB, but it seems a bit magical. If the SLSB is used by a different process (job, UI call, etc), does it get separate instance for each call?
It's not as magical as you think if you see that this pattern is the same as the one I explained above. The SLSB indeed gets a separate instance, but not just any instance, the one which belongs to the scope from which the SLSB was called.
In addition to the link you posted, see also this answer.
Iv'e tested a similar code to what you posted and it works as expected - the MapBean is the same one injected throughout the call. Just be careful with 2 things:
BatchJob is also #ConversationScoped but does not implement Serializable, which will not allow the bean to passivate.
data is not initialized, so you will get an NPE in runJob().

Without any code samples, I'll have to do some guessing, so let's see if I got you right.
Would the container know to pass this instance to services down the call chain?
If you mean to use the same instance elsewhere in the call, then this can be easily achieved by making the MapBean an #ApplicationScoped bean (or, alternatively, and EJB #Singleton).
it should be possible to inject a ConservationScoped bean into a SLSB, but it seems a bit magical.
Here I suppose that the reason why it seems magical is that SLSB is in terms of CDI a #Dependent bean. And as you probably know, CDI always creates new instance for dependent bean injection point. E.g. yes, you get a different SLS/Dependent bean instance for each call.
Perhaps some other scope would fit you better here? Like #RequestScoped or #SessionScoped? Hard to tell without more details.

Related

Concurrent access and scaling of "non-managed" utility class

If I have a stateful class that requires a utility-like stateless class to perform an operation on it. These stateful classes are kept in a list in a container (stateful) class. This is what I would do with plain Java:
class Container {
List<Stateful> sfList;
}
class Stateful {
List<String> list;
void someMethod() {
list.add("SF");
Stateless.foo(this);
}
class Stateless {
public static void foo(Stateful sf) {
sf.getList().add("SL");
}
}
and inside main this is the procedure:
Stateful sf = new Stateful();
sfList.add(sf);
sf.someMethod();
Now with JavaEE CDI I would do:
class StatefulBean {
List<String> list;
#Inject
StatelessBean slsb;
void someMethod() {
list.add("SF");
slsb.add(this);
}
#Stateless
class StatelessBean {
public void add(StatefulBean sfsb) {
sfsb.add("SL");
}
}
In this case all StatefulBean could access a shared pool of StatelessBean with no concurrency issues and it will scale properly with requests.
However, since Stateful is not a managed bean I can't inject into it and so I used the utility class instead. Also I'm creating Stateful with a constructor so I can't inject into it the stateless bean (I will get a NPE using it).
My questions are:
Are there concurrency and scalabilty differences between the stateless injection approach (provided it would work) and the utility class approach?
How can I make the EE injection approach work?
Are there concurrency and scalabilty differences between the stateless injection approach (provided it would work) and the utility class approach?
Yes there are, primarily around the loss of management. The way you're instantiating Stateful on every invocation of the method, there's no pooling involved. This is going to lead to you creating more instances than you probably need.
Another loss is on the scalability side. Where the container will manage the passivation and activation of your stateful bean in a distributed environment, the manual approach will see to it that you manage your own activation and passivation.
Since Stateful is not a managed bean..
Incorrect. According to the CDI Spec, any java class that meets the listed criteria (in your case, a default no-arg constructor) is a managed bean. That means that you could #Inject StatelessBean into Stateless and the container would oblige. To allow this level of management, you'll need to set bean-discovery-mode=all in your beans.xml.
Even with the (apparently needless) circular reference, normal Java concurrency rules apply: as long as the state that you're manipulating is not static or in a static class, you're threadsafe. Each threaded call to that static method still operates on a separate stack, so no problems there.
How can I make the EE injection approach work?
If you need on-demand instantiation of Stateless(or any other bean really), use the CDI Instance to programmatically obtain a managed instance of any class you want. You can now add something like this to Container:
#Inject #Dependent Instance<Stateful> stateful;
#PostConstruct
public void createStateless(){
//instantiate sfList;
sfList.add(stateful.get()); //execute as many times as you need
}

Injecting stateful bean into stateless

I have read that #Stateful bean (SFSB) should be never injected into #Stateless bean (SLSB). But what is the correct way to achieve the following?
#Stateless
public class FirstEJB
{
#EJB
private SecondEJB second;
public void businessMethod()
{
second.businessMethod1();
second.businessMethod2();
}
}
There is some state that should be persisted between second.businessMethod1() and second.businessMethod2(), so SecondEJB can't be stateless. There is also no easy way to merge businessMethod1() and businessMethod2() methods into single one, because SecondEJB can have more than 2 business methods and they can be called in defferent combinations.
Actually I have tried to make SecondEJB stateful and it seems to work, but it leads to memory leak. There is no SecondEJB methods marked with #Remove annotation, but I have tried #StatefulTimeout with no luck: a lot of SecondEJB instances created and not removed. Can someone explain why it leaks?
Just don't use injection. You can use JNDI lookup of the bean at the moment your buisnessMethod is called and SecondEJB instance will be method scoped variable instantiated on every method call.

When should scope annotation be used

What does the scope annotation in Java guice mean?
Could someone give an example to explain how it works?
I see examples like this:
#Singleton
class Log {
void log(String message) { ... }
}
But singleton has nothing to do with scope, right?
Thanks!!!
Scopes allow you to reuse instances: for the lifetime of an application (#Singleton), a session (#SessionScoped), or a request (#RequestScoped).
http://code.google.com/p/google-guice/wiki/Scopes
It means that if your class is annotated with Singleton there will be only one object instantiated from this class which will be injected every time you will use this kind of bind.
When you use #RequestScoped you get every time new object per request

SpringMVC #Scope session not creating threads

Say I have the following class...
#Controller
public class WebController {
#Autowired PersonService personService;
#RequestMapping(value = "/get", method = RequestMethod.GET)
#ResponseBody
#Scope("session")
public List<Player> getPerson(String personName) {
return playerService.getByName(personName);
}
}
Now this invokes the following service...
#Service("playerService")
public class PlayerServiceImpl implements PlayerService {
private List<Player> players;
#Override
#Transactional
public List<Player> getByName(final String name) {
if (players == null) {
players = getAll();
}
return getValidPlayers(name);
}
If I initially start my application, players is null, correctly, then when in the same session, I invoke this method again with a new value, players is no longer null, as you would expect. However, no new thread appears to be being created, if I open a new browser window (therefore creating a new session) and invoke this method, it still has the values from the previous session.
Why is #Scope("session") not creating a new thread in the thread pool?
I've specified <context:component-scan base-package="com." /> in my servlet-context as expected, everything works fine apart from the service methods are all acting as singletons rather than creating a new thread per session like say a Java EE container.
If players was marked as static I'd understand.
I've also tried marking my controller as #Scope("session") (as shown below) but this appears to have no impact either. What's the best way to make my Spring app create a new thread for a new session?
#Controller
#Scope("session")
public class PlayerController {
You are using #Scope annotation the wrong way.
Quoting the docs:
When used as a type-level annotation in conjunction with the Component annotation, indicates the name of a scope to use for instances of the annotated type.
When used as a method-level annotation in conjunction with the Bean annotation, indicates the name of a scope to use for the instance returned from the method.
So you can annotate either a spring component bean or a method that creates a bean if you're using java config. Java config is the only reason it even compiles (it wouldn't in pre 3.0 spring)
In your case that annotation is on a normal bean method where it doesn't mean anything.
Solving the right problem
It looks like you're trying to implement db cache by storing query results in a List<Player> players.
Don't do that. Use one of the prebuilt cache abstractions (spring has a very nice one) instead.
So where should #Scope go?
Annotating #Controller with #Scope("session") won't help as it will create session scoped controllers but the service they have injected is still a singleton.
Annotating only Service bean won't work either, cause #Controller is a singleton and it's dependencies are autowired on application startup.
Annotating both #Service and #Controller might work, but seems a bit heavy handed.
It's better to avoid state at all.
New threads are created for each request.
Your service has an instance variable (players) which is not threadsafe - it is shared by all threads. Any spring bean - including controllers and services are by default a singleton, you need to specify on the service annotation its scope.
#Service("playerService")
#Scope("session")
public class PlayerServiceImpl
But its best(simpler, easier to scale) to keep beans singletons and not rely on instance variables (unless they are also managed by spring/threadsafe/singletons).

EJB3 correlation ID

Now my colleagues work on logging subsystem and they want to bind separate operations, that was initiated from some business method. For example, if method from bean A calls to some method in bean B and then in bean C it will be great to know than business methods in bean B and bean C does some staff for method from bean A. Especially it will be great to know that methods from B and C done some unit of work for concrete call of bean A.
So, the question is how to tie this units of work into something total? Obviously, it is not beautiful to use method arguments for binding!
And also I think that it is time to ask another question, that is close enough to previous one. What if I want to propagate some context information from bean A to another beans, that are called from A? Something like security credentials and security principal? What can I do?
May be questions that I asked is some kind of bad practice?
Looks like a good use case for mdc, available in both Logback and Log4J. Essentially you are attaching some custom value to a thread and all logging messages comming from that thread can attach that value to the message.
I think the best way to implement this in EJB will be an interceptor:
public class MdcInterceptor {
#AroundInvoke
public Object addMdcValue(InvocationContext context) throws Exception {
MDC.put("cid", RandomStringUtils.randomAlphanumeric(16));
try {
return context.proceed();
} finaly {
MDC.remove("cid");
}
}
}
Now all you have to do is add:
%X{user}
to your logging pattern (logback.xml or log4j.xml).
See also
Logging user activity in web app
For general purpose context information you can use TransactionSynchronizationRegistry. It could look something like this:
#Stateless
public class MyBean {
#Resource
TransactionSynchronizationRegistry registry;
#AroundInvoke
public Object setEntryName(InvocationContext ic) throws Exception {
registry.putResource(NAME, "MyBean");
return ic.proceed();
}
}
#Stateless
public class MyBean2 {
#Resource
TransactionSynchronizationRegistry registry;
public void doJob() {
String entryName = (String)registry.getResource(NAME);
...
}
}
I believe it is usually implemented using ThreadLocal variables as normally each transaction maps to a sigle thread in application servers. So if TransactionSynchronizationRegistry is not implemented in your AS (like e.g. in JBoss 4.2.3) or you need lower level tool, you could use ThreadLocal variables directly.
BTW I guess that MDC utilities use the same thing under the covers.

Categories