Whats the correct way to create multiple instances of managed beans in JSF 2.0 - jsf

If I want to create more than one instance of managed bean in JSF 2.0, under different names in the same scope, how should I proceed? Ideally, I want the equivilant to (for example):
#ManagedBeans({name="myManagedBean1",name="myManagedBean2"})
#RequestScoped
public class MyManagedBean {
}
Thanks ..

You can't. It technically also doesn't make much sense. You're probably looking for a solution in the wrong direction for the particular functional requirement.
Your best bet is to have a parent bean and have those "multiple beans" as children.
#ManagedBean
#RequestScoped
public class Parent {
private Child child1;
private Child child2;
// ...
}
so that you can access it by #{parent.child1} and #{parent.child2}. You can of course also use a List<Child> property or even Map<String, Child> instead to be more flexible.
With the faces-config.xml it's however possible to define multiple bean classes with a different name. Still then, I don't see how that's useful.

In your case you should make use of the faces-config.xml. Implment your bean without the ManagedBean and RequestScope annotation. So your bean will not become a managed bean per default. You can than instance as much managedBeans as you need with different names, different scopes and at lease differnent properties.
For example:
<managed-bean>
<managed-bean-name>MyManagedBean1</managed-bean-name>
<managed-bean-class>org.MyManagedBean</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
<managed-property>
<property-name>value1</property-name>
<property-class>int</property-class>
<value>5</value>
</managed-property>
<managed-property>
<property-name>value2</property-name>
<property-class>int</property-class>
<value>2</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>MyManagedBean2</managed-bean-name>
<managed-bean-class>org.MyManagedBean</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-property>
<property-name>value1</property-name>
<property-class>int</property-class>
<value>30</value>
</managed-property>
<managed-property>
<property-name>value2</property-name>
<property-class>java.lang.String</property-class>
<value>project</value>
</managed-property>
</managed-bean>
Don't think that descriptors are evil and annotations are the only way to implement your code.

One possibility is to make your class abstract and subclass it into as many named instances as you need, which you may leave empty. This will also help you separate future managed bean functionality which really only concerns one of the cases.
You will have to move the #ManagedBean (and scope) annotation to all the subclasses, regrettably, even though it is #Inherited. For the current version of Mojarra atleast, others I don't know.

Related

Use many beans from the same class, different scopes

I want to use a ManagedBean class, Users.java, to create 2 bean instances with different scopes. I tried to do this in 2 ways:
1.
Use ManagedBean and SessionScope annotations for Users (this creates a "users" with a session scope), and declare in faces-config.xml another MenagedBean from User, with request scope.
#ManagedBean
#Component
#SessionScoped
public class Users implements Serializable {...}
Note: "Component" is from Spring framework, this can be ignored for the moment.
In faces-config.xml:
<managed-bean>
<managed-bean-name>newUser</managed-bean-name>
<managed-bean-class>ro.telacad.model.Users</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
In login page I use "#{users.}" inside . For this case, the login works fine (is made with Spring Security). I created also a "Sign up" page, and there, I need the "Users" bean with request scope to create a new user in database, "#{newUser.}". I put a breakpoint inside a method, and when the application stopes there, all the attributes of this object are null, and the application throws a NullPointerException.
2.
Remove annotations "ManagedBean" and "SessionsScoped" from Users.java, and declare the 2 managed beans in faces-config.xml:
<managed-bean>
<managed-bean-name>currentUser</managed-bean-name>
<managed-bean-class>ro.telacad.model.Users</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>newUser</managed-bean-name>
<managed-bean-class>ro.telacad.model.Users</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Of course, this time I use in login page and in welcome page "#{currentUser.}". This time, the NullPointerException is thrown in both cases (login and sign up).
The file faces-config.xml is loaded. I tested this by creating a class TempBean.java with 1 attribute and 1 method, declaring a managed bean of this class in faces-config.xml and use this in a h:form. It worked.
I extended "Users" class, exactly like Selaron said in the comment. It works fine. But I think it is not a good idea to do this in a real application, but for the moment I don't have any better idea.

Communication between two beans

I have two region and two taskflow on a page. On first taskflow manage bean is on pageflow scope where in second taskflow its on backing bean scope. My requirement is I want to call method of one bean from econd bean and vice-versa.
For example: on first jsff if some action happen then it action will go to its bean and from there I need to call method of second bean and vice-versa.
How can I achieve this?
Since both task flow will be running at same time so I need to get running instance of bean so that I can get the current status/value UI components.
All you need to do is to inject the bean whose method you want to use in the other bean. In ADF there is an easy way to achieve this. You should have a file called adfc-config.xml inside your WEB-INF folder. If you open it's source, you'll notice that each bean is described inside the <managed-bean> tag. It will be something like:
<managed-bean id="__2">
<managed-bean-name>bean1</managed-bean-name>
<managed-bean-class>com.domain.Bean1</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
</managed-bean>
for each bean. You have to insert a <managed-property> tag inside with a reference of the bean you want to inject, just like this:
<managed-bean id="__2">
<managed-bean-name>bean1</managed-bean-name>
<managed-bean-class>com.domain.Bean1</managed-bean-class>
<managed-bean-scope>view</managed-bean-scope>
<managed-property>
<property-name>bean2</property-name>
<value>#{Bean2}</value>
</managed-property>
</managed-bean>
Also, inside the Bean1 class you have to create an instance variable of Bean2, and then you can use it to get its current state.

initial JSF1.1 bean after request parameters are set

I need to perform some initialization of a JSF1.1 bean after all URL request parameters are set. Is there a good way to do so? For example, if the manage-bean is setup in faces-config like below, I need to perform some initialization after all there param (Param1, 2, 3) are set.
<managed-bean>
<managed-bean-name>someBean</managed-bean-name>
<managed-bean-class>com.arch.SomeBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>param1</property-name>
<value>#{param.param1}</value>
</managed-property>
<managed-property>
<property-name>param2</property-name>
<value>#{param.param2}</value>
</managed-property>
<managed-property>
<property-name>param3</property-name>
<value>#{param.param3}</value>
</managed-property>
</managed-bean>
Normally, you would use a #PostConstruct annotated method for this, but the support for #PostConstruct is only available since JSF 1.2.
Your best bet is to lazily execute it in the setter method of the managed property. E.g.
public void setParam3(String param3) {
boolean wasNull = this.param3 == null;
this.param3 = param3;
if (wasNull) {
init();
}
}
See also:
Communication in JSF - Passing GET parameters to backing bean
Alternatively, just upgrade to JSF 1.2. JSF 1.1 is fully forward compatible with JSF 1.2 without any changes in the code (expect of code where in you're incorrectly assuming a JSF 1.1 specific bug to be correct behavior).

How many Beans should be enough?

I'm a undergrad Student at a German University.
I have a team Programming Course .. where we have to use JavaEE/JSF to make a social networking site .. like LinkedIn.
Anyway my group has created a lot of beans. Which IMHO is too much .
<?xml version='1.0' encoding='UTF-8'?>
<!-- =========== FULL CONFIGURATION FILE ================================== -->
<faces-config version="1.2"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-facesconfig_1_2.xsd">
<managed-bean>
<managed-bean-name>SessionBean1</managed-bean-name>
<managed-bean-class>egispartnerprofile.SessionBean1</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>ApplicationBean1</managed-bean-name>
<managed-bean-class>egispartnerprofile.ApplicationBean1</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>RequestBean1</managed-bean-name>
<managed-bean-class>egispartnerprofile.RequestBean1</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>Hauptseite</managed-bean-name>
<managed-bean-class>egispartnerprofile.Hauptseite</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>PasswordVergessen</managed-bean-name>
<managed-bean-class>egispartnerprofile.PasswordVergessen</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>registery</managed-bean-name>
<managed-bean-class>egispartnerprofile.registery</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>Page1</managed-bean-name>
<managed-bean-class>egispartnerprofile.Page1</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<validator>
<validator-id>login.EmailValidator</validator-id>
<validator-class>Login.EmailValidator</validator-class>
</validator>
<managed-bean>
<managed-bean-name>Bewertung</managed-bean-name>
<managed-bean-class>group52.infoholders.Bewertung</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>Mitarbeiter</managed-bean-name>
<managed-bean-class>group52.infoholders.Mitarbeiter</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>Nachrichten</managed-bean-name>
<managed-bean-class>group52.infoholders.Nachrichten</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>Benutrzer</managed-bean-name>
<managed-bean-class>group52.infoholders.Benutzer</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>view$MainPage</managed-bean-name>
<managed-bean-class>egispartnerprofile.view.MainPage</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>view$NavigationBar</managed-bean-name>
<managed-bean-class>egispartnerprofile.view.NavigationBar</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>view$PartnerProfilePage</managed-bean-name>
<managed-bean-class>egispartnerprofile.view.PartnerProfilePage</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>view$PartnerProfileChange</managed-bean-name>
<managed-bean-class>egispartnerprofile.view.PartnerProfileChange</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>view$ProfilePage</managed-bean-name>
<managed-bean-class>egispartnerprofile.view.ProfilePage</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<navigation-rule>
<from-view-id>/Page1.jsp</from-view-id>
<navigation-case>
<from-outcome>case1</from-outcome>
<to-view-id>/view/MainPage.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<navigation-rule>
<from-view-id>/view/MainPage.jsp</from-view-id>
<navigation-case>
<from-outcome>case1</from-outcome>
<to-view-id>/view/ProfilePage.jsp</to-view-id>
</navigation-case>
</navigation-rule>
<managed-bean>
<managed-bean-name>view$ProfileChange</managed-bean-name>
<managed-bean-class>egispartnerprofile.view.ProfileChange</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
</faces-config>
Actually :
Ever Site is a Bean
We have 3 Application Beans
I just use 1 Session Bean
I think they missunderstood the purpose of Beans.(did they? or am I wrong ?!)
How can i make them clear ... that 1 Session Bean is ( or could be) enough?
It doesn't look like there are too many beans, but of course it depends on what the beans do and how they are used. The "one bean per view" rule is quite common and there is usually nothing wrong with this. Of course, if you can write some beans that are more general and can be used on many/all views, you should certainly do this, just try to keep their purpose clear and focused on a single task.
The fact that most of your beans are request-scoped is good. Only beans which have to keep some state during the whole duration of a user session should be put into session scope (hence the name). This also keeps the per session memory consumption low. Application scope is usually used for beans that have to be created once and are used by all users of your site. Like global variables/singletons, you should use them sparingly.
But about your idea that one session bean is enough: There is no general rule how many beans have to be in which scope. Design and develop the beans and then decide in which scope they need to be. As I said, it's very likely to have the number of beans in session scope lower than the number of beans in request scope, but if a bean has to be in session scope to work properly, you shouldn't be afraid of it.
Don't try to squeeze everything into a single session bean, just because you want to have only one bean in session scope. This would be called a God Object, which is an anti-pattern.
So for example, you have some user information (e.g. full name, status, role...) stored in a database, which you want to display on all pages when a user is logged in (like the grey bar at the top here on SO). This would be something you could implement as a session-scoped bean which is used on all of your pages (or better yet, in some header which is included on every page). This bean would be created as soon as the user logs on and fetches the information just once from the database.
In an online store, another session scoped bean could be used for storing the shopping basket of the user. Yet another session scoped bean could be used for managing a separate shopping list...
Apart from that, I would like to comment on the naming rules/style you and your team uses:
You should decide on one language (preferrably English) and stick to it, so no class/method/variable names like "PasswordVergessen"
Every class/method/variable should have a descriptive and self explaning name, so don't use somthing like "ApplicationBean1"
Try to organize your faces-config into blocks (separate navigation rules from bean definitions, etc.)
I would say that simon has answered very aptly to your question and leaves little ground to cover up. In addition to all the said things; I would just say that focus should be on OO design as that should really control the number of beans and not a rudimentary figure in head.
A tightly coupled 3 bean code is as bad as a code containing 2000 beans with no real purpose. It's the design that must guide you.
I may deviate from point; but if you'd really like to see how your beans should be controlled then read "The Thoughtworks Anthalogy" chapter "Object Calisthenics" essay written by Jeff Bay. The simple rules for programming is (Some of them even unbelieveable) :)
1. Use only one level of indentation per method
2. Don't use the else keyword
3. Wrap all primitives and String
4. Use only one dot per line
5. Don't abbreviate
6. Keep entities small
7. Don't use any classes with more than 2 instance variables
8. Use first class collection
9. Don't use any getter setter properties. (I know it won't work JSF way)
But with these rules you'll be posed with some real challenges. But you'll see that even though number of beans is huge, you have perfectly well designed code. :)
In short, I agree that you should move away from anti-pattern but most of the time one session bean is enough and it's good to have all beans with request scope. Number of beans is immaterial as long as you have well designed and flexible code.
Cheers.

Notifying one bean from another in ICEFaces

I have an ICEFaces we application. One page has two beans that display different things on the page.
I want to be able to notify one bean when another bean changes something on the bean so that the first bean update its content on the page.
Is that possible in ICEFaces? if so how?
Thanks,
Tam
What you can do is to "inject" bean1 into bean2, so the bean2 will have access to any method present in bean1.
If you are using Spring, this can be easily done when defining the beans:
<bean id="bean1" class="foo.bar.Bean1"/>
<bean id="bean2" class="foo.bar.Bean2">
<property id="bean1" ref="bean1"/>
</bean>
and in Java code of bean2:
public class Bean2 {
private Bean1 bean1 = null;
// The setter will be used by Spring to inject Bean1 in Bean2...
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
...
public void someMethod() {
...
// Now, you can call the bean1 instance to update what you want...
bean1.updateSomething();
}
}
If you are not using Spring:
You can directly access the bean1 instance within bean2 code like that:
Bean1 bean1 = (Bean1) FacesContext.getCurrentInstance().getCurrentInstance()
.getExternalContext().getSessionMap().get("bean1");
As has already been noted, JSF can do simple injection as well. Something like this in your faces-config.xml file:
<managed-bean>
<managed-bean-name>bean1</managed-bean-name>
<managed-bean-class>org.icefaces.sample.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>bean2</managed-bean-name>
<managed-bean-class>org.icefaces.sample.Bean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>bean1</property-name>
<value>#{bean1}</value>
</managed-property>
</managed-bean>
As for updating the user interface when bean values change, that can be triggered through regular client interaction with the page. However, if you are doing a collaborative type application (where one user's change can update values that other user's can see), then ICEfaces has a feature called Ajax Push that you can use. Check their docs for more info.
I was going to post some examples of my own work, but the guys on the ICEFaces blog already have a really good blog post of their own. Take a look.

Resources