Stateful bean doesn't keep state - java

I have a stateful bean:
#Stateful
public class ClientContext {
private Band band;
public Band getBand() {
return band;
}
public void setBand(Band band) {
this.band = band;
}
}
I have Arquillian test.
public class RequestTest extends Arquillian {
...
#Inject
private ClientContext context;
#Inject
private RequestProcessor processor;
#Test
public void test() {
context.setBand(new Band());
Assert.assertNotNull(context.getBand());
processor.doSomething();
}
}
And Processor code:
#Stateless
#LocalBean
public class RequestProcessor {
...
#Inject
private ClientContext context;
public void doSomething() {
System.out.println(context.getBand());
}
}
I expect RequestProcessor to print out the Band. But actually I get null every time. What can be wrong or may be I don't understand Stateful beans correctly?

You are answering the question yourself, the main basis about the stateful is the keep just one instance per injection, which will live as long the injecting bean does.
so in you need to share a state between beans, you could use a #SessionBean
To clarify, the #Stateful means one instance are going to be created for each place where you are injecting it, this is useful when you need to bind some actions and their state to ONE component, so, if you need to create some info and then share between other classes you need to pick how you want to share it:
#Singleton: There will be just one instance for the entire app.
#SessionScoped: There will by one instance per client.
#Stateless: Will create one if there is no other available, after it will be release for use of other clients
If you are managing views the you can use too:
#RequestScoped: Will create one instance for each request and then destroys it.
#ViewScoped: The bean will remain as long the client keep making updates within the same view

Related

Stateless Factory with EJB

I have a requirement to get pdf documents from my system. I'm using Apache Fop for this - and this library is using 2 files to generate pdf - xsl file with structure and styling and xml with data. So I'm getting xsl file from web resources, but now I need to generate xml with data from database. I tried this solution:
I have this interface:
public interface PrintableDocument {
Object getJaxBOjbect(Long personId);
}
That's one of the stateless bean to get object, I need 10 more beans like this to get different data for different documents.
#Stateless
#PrintableDocumentOneQualifier
public class PrintableDocumentOne implements PrintableDocument {
#Inject
private SomeRepository repository;
public Object getJaxBOjbect(Long personId) {
// Getting information from database
// formulating Object with data and returning it
}
}
So now I want to create Factory like this one:
#Stateless
#LocalBean
public class PrintableDocumentsFactory {
#Inject
#PrintableDocumentOneQualifier
private PrintableDocument printableDocumentOne;
#Inject
#PrintableDocumentTwoQualifier
private PrintableDocument printableDocumentTwo;
private Map<String, PrintableDocument> map = new HashMap<>();
#PostConstruct
public void init() {
map.put("one", printableDocumentOne);
map.put("two", printableDocumentTwo);
}
public PrintableDocument getPrintableDocument(String type) {
return map.get(type);
}
}
And on the service bean I want to use this factory:
#Stateless
#Local(DocumentService.class)
public class DocumentServiceBean {
#Inject
private PrintableDocumentsFactory factory;
public byte[] getPdf(InputStream xsl, Long id, String type) {
PrintableDocument printableDocument =
factory.getPrintableDocument(type);
Object jaxBOject = printableDocument.getJaxBObject(id);
//Use this object to get pdf and return it to web controller.
}
}
But now I'm getting null from getPrintableDocument from factory. I think the problem is that I need stateless beans, and they are getting picked back to EJB container, when getPrintableDocument method ends. So my question is: how can I manage this kind of situation?
EDIT 1: Missed PostConstruct annotation on init in Factory. Fixed that, still have the problem.
EDIT 2: If I will have #Singleton on my Factory will it hold just one by one instances of stateless PrintableDocument beans or it will return pooled instances instead? Because now I have to refill strategy holder map on factory when system will need another been to answer the request.
You could try to use #EJB instead of #Inject to inject the PrintableDocumentsFactory into your DocumentServiceBean.
Try adding a #PostConstruct annotation to PrintableDocumentsFactory.init() method. Currently the init method won't be called, so no get registered in the map.

Is there a way to re-inject / update injected bean fields?

I have some beans (of multiple types, CDI, #Stateless and #Singleton beans). Some of their fields shall get injected from database values.
public class MyBean {
#Inject
#DbConfigValue(MyConfig.HOST)
String host;
}
So I added a custom #Qualifier (DbConfigValue) used by a Producer. The producer reads and caches config values from a database and injects them into the beans.
#Singleton
#Lock(LockType.READ)
public class Configuration {
#Produces
#Dependent
#DbConfigValue
public String getDbConfigValue(InjectionPoint point) {
// get key for the config-value from qualifier-annotation of the injected field
String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
// i have read+cached database config values in #PostConstruct before
return cachedConfigValues.get(key);
}
}
This works well for initial injection / bean construction. Some web tutorials out there are suggesting this approach.
Now, I think it is reasonable to assume that config values, if stored in DB, might change at runtime. So, whenever an admin changes a database config value, I currently do fire a CDI-event.
Question: is there any way to re-inject values into fields of already-initialized bean-instances? Or is injection always related to instance-creation only?
E.g. I had s.th. similar to this in mind:
public class MyEventListener {
#Inject
BeanManager beanManager;
#Asynchronous
public void onDbConfigValueChangedEvent (#Observes(during = TransactionPhase.AFTER_SUCCESS) DbConfigValueChangedEvent event) {
try {
// could be filtered by custom qualifier:
Set<Bean<?>> beans = beanManager.getBeans(Object.class,new AnnotationLiteral<Any>() {});
for (Bean<?> bean : beans) {
Set<InjectionPoint> points = bean.getInjectionPoints();
// What now? javax.enterprise.inject.spi.Bean is the
// bean-representation only.
// Can I somehow resolve the actual bean-instances here?
// Then update Field via Reflection?
}
}
catch(Exception e){
// ...
}
}
}
I also considered DeltaSpike which has some methods for injection-control. However, I did only find methods to inject into new bean instances, or even with new- or null-CreationalContexts (beans not CDI-managed afterwards)
Please note: I am aware that I can solve this specific use-case by injecting the configuration and explicitly getting the current values on each request like this:
public class MyBean {
#Inject
Configuration config;
public void someMethod(){
String host = config.getConfig(MyConfig.HOST);
// ...
}
}
However, I am wondering about the question in general: is there any support for re-injection? Or if not, do the specs (CDI or Java EE) forbid it?
Depending on how fast/slow your db is, this may be expensive. You could probably leverage some cacheing mechanism in the producer method.
Leverage on Instance injection mechanims, which lazily loads the actual injected bean.
Your Producer (Probably leveraging on some of cache to avoid db calls all the tome)
#Singleton
#Lock(LockType.READ)
public class Configuration {
#Produces
#RequestScoped //May fail if not in a request-context, but for ejb-calls, it is guaranteed to work as CDI has EJB Request Context
#DbConfigValue
public String getDbConfigValue(InjectionPoint point) {
// get key for the config-value from qualifier-annotation of the injected field
String key = point.getAnnotated().getAnnotation(DbConfigValue.class).value();
// i have read+cached database config values in #PostConstruct before
return cachedConfigValues.get(key);
}
}
And the injection points:
#SessionScoped
public class MyBean {
#Inject
#DbConfigValue(MyConfig.HOST)
private Instance<String> host;
public void doSomething() {
String myHost = host.get(); // of course will throw exception if value is failing. It will be resolved with every request.
}
}

Performance: Utility class vs. CDI bean

I want to externalize commonly used applicationlogic into a "utility class" called Helper. The applicationlogic needs other CDI beans to work.
Two possibilities:
a)
#SessionScoped
class ControllerWithCdiBean {
#Inject
Helper helper;
public void doIt() {
Object result = helpder.calculate();
}
}
#RequestScoped
class Helper{
#Inject
Service anyService;
public Object calculate() {
return anyService.calc();
}
}
b)
#SessionScoped
class ControllerWithStaticCallsViaDeltaspike {
public void doIt() {
Object result = Helpder.calculate();
}
}
class Helper{
private static Service anyService = BeanProvider.getContextualReference(Service.class);
public static Object calculate() {
return anyService.calc();
}
What about performance? Are there any notable differences? Both solutions are possible for me, is one solutions better than the other?
One disadvantage:
Helpder gets initialized for every Request.
Mark your Helper class as #ApplicationScoped. With this, you will have a single instance per application context.
Still, if it's just an utility class, it shouldn't be a managed bean at all. I would instead mark it as final, define a private constructor and mark all the methods as static. This is because since it's an utility class, it doesn't need to maintain any state.

Handling private write methods on singleton EJBs

I have a singleton EJB whose business methods are all #Lock(READ). However, on special ocassions, some of them call a private method that persists stuff on a database. What's the best way to handle this situation? Should I:
Use #Lock(WRITE) for that private method even though it's not a business method? If so, is this a reliable behaviour?
Do the synchronization on the private method myself? If so, is it safe to synchronize over the EntityManager?
Do something completely different?
This only partially answers your question, but here goes.
You could put the private methods in a "private" businness interface and call them via the container like this:
TestEJB.java:
#Stateless
public class TestEJB implements PrivateIface, PublicIface {
SessionContext ctx;
public void doBusiness() {
PrivateIface businessObject = ctx.getBusinessObject(PrivateIface.class);
businessObject.doPrivateBusinness();
}
#SomeContainerAnnotation
public void doPrivateBusinness() {
}
}
#Local
interface PrivateIface {
void doPrivateBusinness();
}
PublicIface.java:
#Local
public interface PublicIface {
void doBusiness();
}

How to select between different CDI-bean implementations runtime

I have a messageListener which purpose is to start clients implementing the Client-interface. The different implementations of the Client-interface is not know at compile time.
The messageListener uses the Launcher-bean to start the clients. So my problem is I need to construct a Launcher-bean that has the selected implementation of the Client-interface injected into it. Im not sure how to do this, or should i approch the problem differently?
public class MyMessageConsumer implements MessageListener {
public void onMessage(Message message) {
String clientType = message.getClientType();
//Here i need to construct a launcher-bean, which has the correct Client-implementation injected
launcher.startClient(message);
}
}
public class Launcher {
#Inject
private Client client;
public void startClient(Message message) {
...
client.start(message);
}
}
edit: I realised that the tricky part is not finding the correct implementation, but that i need the Consumption of a message to happen as a new request. Is it possible to understand what im after?
What you want is a producer.
This way you separate the client of the contextual instance and the producer. So inject them into a producer and have it decide what to use.
For this to be transparent and to avoid ambiguous dependency you could produce a value with #Dynamic qualifier.
#Inject
#Dynamic
Foo foo;
..............................
#Produces
#Dynamic
public Foo getFoo() {
//find out what implementation to use and return it
Creating your own qualifier and producer is very simple to google.

Categories

Resources