I have an application. Each user corresponds to the entity "Client". During the session, the user works with his entity.
I have JAX-RS + EJB application. I want this entity to be visible and used in all services, as a singleton. I want to achieve it using CDI.
First, the user login to the application. After login, I want to get its entity from the base and assign it to a singleton, but I didn't succeed. I tried the @Singleton
annotations (javax.inject
), @SessionScoped
and @ApplicationScoped
.
How can I do it?
//Entity
@Entity
@SessionScope //or @Singlton/@ApplicationScope
class Client { fields }
//login service
@Inject
Client client;
//After login I want to assign an entity from db[cleintEntity]
//to entity which is available everywhere[client]
client = clientEntity;
I want to do this:
//some ejb
@Inject
Client client;
//use entity
I don't want to transmit a link to the instance throughout the application, but I want it to be available everywhere using CDI.
Or do I need to create a separate ClientDAO
, which will be my singleton?
Based on your comment, you must use the @SessionScope
. The @Singleton
and @ApplicationScope
could be used if you wanted to have a single instance for all your users.
To solve your problem:
You want to instantiate the Client
when user logs in. So when you're in the login service, this object is not instantiated yet, so you can't @Inject
it into your login service and you should remember to remove the @Inject
annotation.
You need to use the @Produces
annotation. This annotation is used when you want to have control on the way your class is getting instantiated. When CDI container wants to find an implementation of the Client
class, if it finds a method that returns Client
and has @Produces
annotation, it calls that method instead of just instantiating the Client
itself. You should do your login business, then create an instance of Client
and store it in your login service as a member variable. Then add a method in this class which returns that client object and annotate the method with @Produces
. The final structure of your login service would be something like this:
@SessionScope
public class LoginService {
private Client client;
public void login(String username, String password) {
// implement login business
// if login is successful
client = clientEntity;
}
@Produces
@SessionScope
public Client clientProducer() {
return this.client;
}
}
You can also put the @Produces
annotation on top of a field. In such cases, the CDI container will use the value stored on that field instead of calling a method.
@SessionScope
public class LoginService {
@Produces
@SessionScope
private Client client;
public void login(String username, String password) {
// implement login business
// if login is successful
client = clientEntity;
}
}
Of course this should be considered as a sort of pseudocode. I don't know about all the details of your business. Maybe the way you're implementing the logic is completely wrong ;). But to solve this specific problem, the @Produces
should work.