I know there's a lot of debate on using stateful vs stateless EJBs in web applications.
The shopping cart is the most common use case: Oracle's Java EE examples use it a lot in the official docs, too.
Here on stackoverflow I found many interesting answers like this The Shopping Cart dilemma in JavaEE which often say something like:
ok... SFSB are good in enterprise, complex scenarios, e.g. if you want to share them with other applications and make them available not only to JSF/web clients
but... if you're just developing your grandpa's e-commerce website, just stick to the HttpSession / SessionScoped cdi-managed bean, and write your business methods in SLSB, as they are more efficient, and so on...
However, because I'm still in a learning and discovery phase, I just want to give SFSB a try, by myself, trying to build a simple shopping cart.
I saw an interesting tutorial suggesting to store a JNDI-retrieved instance of the #Stateful shopping cart ejb interface in the HttpSession, the first time the web client needed it, then use it as usual, during the web session. In my JSF presentation layer, I suppose I would have a #SessionScoped #Named bean (let's call it ShopController), and, in its initialization, store one instance of the stateful ejb in an instance variable.
I wonder if it's possible to directly bind the #Stateful bean to the http session by annotating it with the #SessionScoped CDI annotation.
Will it work as described above? Will CDI create one SFSB for each web session?
#SessionScoped is for #Named beans and #Stateful is for #EJB beans. If I'm not wrong, you cannot annotate 1 bean with both. If you want to use #Stateful, just annotate your ShoppingCart bean with #EJB and #Local and then reference it in your ShopController. Something like this:
#Named
#SessionScoped
public class ShopController {
...
#EJB
private ShoppingCart cart;
...
// Getters and Setters
}
#Local
#Stateful
public class ShoppingCart {
...
}
Don't waste your time learning how to use SFSB for web applications. You will have scalability issues very soon. Why would you learn how to make an application that uses unnecessary server resources?
Even your managed beans shouldn't be SessionScoped. At most create only one very thin SessionScoped MB with small user data to track it and all others should be request, view scoped.
The answer to your question is yes, you can use CDI to bind SessionScoped MB to SFSB EJBs. But this is not a nice architecture for web applications.
Related
I am experimenting with Jakarta EE and Jakarta Faces (JSF).
I just made a CDI named session scoped bean (as JSF managedBean's are deprecated now),
and was wondering why one would use a stateful EJB when scoped beans (running in the CDI container) are available, it seems to me that any transactions can be done using a stateless bean injected into the CDI managed bean.
Any real-world use cases would be really helpful :).
For those wondering, my Managed/named bean looks like this:
import jakarta.ejb.EJB;
import jakarta.enterprise.context.SessionScoped;
import jakarta.inject.Named;
#Named("userBean")
#SessionScoped
public class UserSessionBean implements java.io.Serializable{
#EJB
TransactionBean bean; //can be used to persist user data
String username;
String password;
// Constructor, getters and setters
}
why one would use a stateful EJB when scoped beans (running in the CDI
container) are available
Practically speaking almost never. Stateful Enterprise Beans were never intended as (scoped) backing beans anyway, and even when EJB was still recommended to be used, the stateful variation had little usage in web applications.
Originally the stateful enterprise bean had more utility when using it as a remote component using CORBA/RMI (e.g., as a kind of binary Servlet).
There's a highly specialised and somewhat obscure use-case for them now when taking advantage of the extended persistence context in Jakarta Persistence (JPA). Somehow in over a decade we never managed to specify its behaviour for other beans than stateful session beans.
Is is possible to inject JSF Managed Bean into an EJB? I have injected JSF Managed Beans in to another JSF Managed Bean as a #ManagedProperty. But when I do the same to the EJB, I get a null point exception.
No, that's not possible. The #ManagedProperty works inside #ManagedBean classes (JSF managed beans) only. You can only use #EJB or #Inject to inject another EJB or a CDI managed bean (a #Named class).
However, it makes design technically no sense to inject a front-end class like a JSF or CDI managed bean in a business service class like an EJB. An EJB should be designed in such way that it can without changes be reused together a completely different front-end like JAX-RS webservice or even a plain vanilla servlet. An EJB should absolutely not have any javax.faces.* imports/dependencies (like as that it should not have any javax.ws.rs.* nor javax.servlet.* ones).
If you intend to pass data from the JSF managed bean to an EJB, then just pass it as method argument. Such data is usually in flavor of a JPA #Entity or at least an ID/keyword which returns an entity.
I have an #ApplicationScoped bean which I create a bunch of instances of. I then use those instances to create a JSF page with the data contained in the instances. I want the user to be able to modify those data (for thier use only, not stored), but not have it affect the view for other users who share access to the same bean. I'm considering creating a #SessionScoped version of the #ApplicationScoped bean for each new session, but am not sure what the best way to go about it is. Should I:
Extend the #ApplicationScoped bean and give it #SessionScoped, then in my constructor, grab all of the relvant data?
Not create a #SessionScoped version, but rather create a "user" version for each piece of data that the user can modify in the #ApplicationScoped bean?
Other ideas?
I have an #ApplicationScoped bean which I create a bunch of instances
of.
That's wrong , the real purpose of an #ApplicationScoped bean is to minimize data redundancy in the JVM's Heap memory. There should be only one instance at any time, that one instance is always accessible by any other scoped beans. As suggested by Luiggi Mendoza above, you can go for a #SessionScoped or #ViewScoped bean, depending on your use case.
But simply, never use an #ApplicationScoped bean if the data is not going to be shared or persisted.
I really recommend you to read this other question to improve your architecture design: Understanding JSF as a MVC framework
It seems you have started to code in the wrong sense. During design-phase of development, you should first think about #sessionscoped beans that your application will need (something as thinking in your users-needs). Then, you should thing about the #applicationscoped beans (like your global-application-needs).
It is really strange to build a #sessionscoped bean extending it from an #applicationscoped bean.
You should write a #sessionscoped with all the necessary data and initialize it with relevant data, as you said. You will still be able to access #applicationscoped method's. Anyway, try to minimize your access to #apllicationscoped beans, code into #sessionscoped bean as much as possible.
Regards,
Actually I'm new to JSF and Facelets and enterprise apps despite i've been working on it the last 4 months, anyway, i'm developing a web page which has a login, an user administrator and a documents administrator (it has more but it doesn't matter) and i have to manage the acces and the content of pages according to each user permissions. Reading about security i've found out many ways of doing a login, but i have made my own with Stateful Beans in order to maintain the users data in the application for using them later so i can restrict the content. the question is... is this the correct way to manage the content according to users restrictions?
if not, which is the best and securest way of doing it?
this is my Stateful Bean (i did not include the Getters and Setters)
#ManagedBean
#Stateful
public class HandlerLogin implements Serializable{
#EJB
private LoginMethodsLocal loginMethods;
private String loginNickname;
private String loginPassword;
private String userData[];
//[0]=Nickname
//[1]=Name
//[2]=User Type
private boolean loguedIn= false;
public void check(){
System.out.println(this.loginNombre);
System.out.println(this.loginContrasena);
this.userData= loginMethods.Login(this.loginNickname, this.loginPassword);
//the method loginMethods.Login() queries in the database looking for
//"this.loginNickname" and "this.loginPassword"
if (this.userData!=null){
this.loguedIn=true;
}
else{
this.loguedIn= false;
FacesContext.getCurrentInstance().addMessage("mensajesLogin", new FacesMessage("Error, User Does not Exist"));
}
}
public void closeSession(){
this.userData=null;
}
}
so my logic to manage the content and navigation is to check what kind of user is and depending on it determine how the acces and rendering is going to be
The #Stateful annotation does nothing in a JSF #ManagedBean. That annotation is only really been used when the class is by itself injected as #EJB in another managed bean or EJB and even then, a brand new and completely different instance with all properties set to default would have been created and used. So the #Stateful annotation definitely doesn't do what you think it does. Remove it, it makes no sense in this context.
Whether the remaining code is the correct way or not depends on the concrete functional requirements. There are many ways which are equally good and secure (assuming that you understand what code you actually are writing). The question is more: how many of the wheel do you want to reinvent yourself? The builtin container managed authentication leaves very little room for finegrained control, but if it is sufficient for you, then just make use of it instead of homebrewing the authentication yourself.
Going through the following related answers should give some good ideas:
Performing user authentication in Java EE / JSF using j_security_check
JSF: How control access and rights in JSF?
How to check if is user logged in?
How to properly use isUserInRole(role)
JSF request scoped bean keeps recreating new Stateful session beans on every request?
Implementing a simple Login screen using JSF and Spring and Hibernate. I have written the Service and Data Layer Beans in Spring and integrated them with Hibernate.
I defined a Sign Up (new User creation) screen with two fields user id, password in JSF and wired them to a Managed Bean. (Bean Name: Users) Here this bean is also the domain class.
Now on click of the create button in JSF view I need to call the Service Bean methods (which are spring beans). For this I see that I have two ways to do,
Write a method in Users managed bean that takes the given user, password and calls the spring service bean methods which in turn calls DAO bean methods for saving data in DB. But here my question is how far it is a good practise to write controller kind of method in Domain classes?
Second way is to define a new Managed Bean that has the Spring Service object as a property (Which is injected using spring+jsf integration) and a method to call the service bean methods.
Am I doing a correct design? Any thing wrong? Please suggest me for a better design.
Thanks
Dont make your domain class as jsf managed bean.
Generally what I follow is I encapsulate domain class and other UI supporting properties in a form bean(when scenario is complex else direct entity as a property in managed bean) and have it in managed bean.
Spring service is injected in managed bean and on action form bean/entity bean is passed to spring service for business/use case processing and persistence(dao/repository).
Template Code:
#ManagedBean
public class Bean{
private Entity entity;//or
private FormBean formBean;
#Inject private Service service;
public String doAction(){
//error processing from service layer and UI message handling
service.process(entity);//or
service.process(formBean);
return Navigation.Constant;
}
}
Managed bean purpose should be to collect view data and pass it to service for processing. If you make your domain/entity class as managed bean you will be coupling it with JSF library which is not good for reusability. As per design principle SRP(single responsibility principle), class should have one responsibility in that case it will have more and hence as mentioned above not good practice.
Point 2 as mentioned by you is better.
Hope this helps !!!!