Communication between two beans - jsf

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.

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.

Passing t:savestate bean to another bean

I've two JSF 1.1 pages that I'm currently working with. One of them is viewDevices.jsp and the other is vewDevicesPrint.jsp. They are both running under the view scope (using tomahawk savestate, that is). In viewDevices, it has a img that user can click on to go to the viewDevicesPrint.jsp. Like so:
<img src="redesign/images/printicon2.png" alt="print records" border="0" width="16" height="16" onClick="javascript:window.open('/viewDevicesPrint.jsf','_blank','height=500,width=900,menubar=yes, toolbar=yes,scrollbars=yes')"/>
When this img is clicked, I would like to pass the current instance of viewDevicesBean to the viewDevicesPrintBean. Is there a way to do this?
I've the following in faces-config.xml. In debug, viewDevicesPrintBean is getting a new instance of viewDevicesBean, instead of the current instance of it.
<managed-bean>
<managed-bean-name>viewDevicesPrintBean</managed-bean-name>
<managed-bean-class>com.arch.myaccount.jsf.ViewDevicesPrintBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>param_viewDevicesBean</property-name>
<value>#{viewDevicesBean}</value>
</managed-property>
</managed-bean>
<managed-bean>
<managed-bean-name>viewDevicesBean</managed-bean-name>
<managed-bean-class>com.arch.myaccount.jsf.ViewDevicesBean</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>param_flow</property-name>
<value>#{param.Flow}</value>
</managed-property>
</managed-bean>
A view scoped bean is tied to the current view. When you change the current view by navigating to a different view, then that different view would get a brand new instance of the view scoped bean. Note that it works also that way in JSF2.
Your best bet is to pass the desired data as request parameters in window.open() URL (escape them!), so that the print bean can get them as request parameters (via either managed property or ExternalContext). An alternative, especially if you've rather a lot of data, is to store the bean instance in the session scope under an unique and autogenerated key (e.g. java.util.UUID) and pass that key as request parameter so that the bean associated with the print page can obtain the data from the session scope by that key.

jsf send selectOneMenu value as direct request managed bean

I have a selectOneMenu that manages a relation between two Objects A and B.
Where A is fixed and B is selectable via the menu.
On form submit B is send to the bean for further processing (creating and saving relationship object AToB).
Not working case!
<h:selectOneMenu value=#{b}>
<!-- b items from bean -->
</h:selectOneMenu>
<h:commandButton action="#{bean.addBToSelA(b)}"/>
<managed-bean>
<description>B Entity Request Bean</description>
<managed-bean-name>b</managed-bean-name>
<managed-bean-class>B</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Working case!
But if the selectOneMenu value is a nested property of a different managed bean it works. (as example AToB)
<h:selectOneMenu value=#{aToB.b}>
<!-- b items from bean -->
</h:selectOneMenu>
<h:commandButton action="#{bean.addBToSelA(aToB.b)}"/>
<managed-bean>
<description>AToB Entity Request Bean</description>
<managed-bean-name>aToB</managed-bean-name>
<managed-bean-class>AToB</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
</managed-bean>
Note: It is enough if my "b" is just a property of a different request managed bean.
Can someone be so kind and explain why?
Because JSF has already created the bean instance beforehand. It won't be overridden with the model value if the instance already exist in the scope. Remove the <managed-bean> from faces-config.xml and it'll work just fine.
Unrelated to the concrete problem, you seem to be already using JSF 2.x. Why sticking to the old JSF 1.x style faces-config.xml configuration? Just use #ManagedBean annotation (on real backing bean classes only, of course).

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

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.

Managed Bean Per Page (JSF)

Is it possible to have a managed bean created only on some pages i.e. bean != null on page1.faces and bean == null on other pages?
No, it is not possible to limit the accessibility of a managed bean under JSF to an specific page. Just use it in those pages that, according to your desing, you consider appropiate.
It is common to have a JSF application that uses a given managed bean for some pages in particular, especially form beans. For example if you have a form used to create and/or update certain type of entities in your application, lets say a product definition, you will find yourself declaring code like the following:
<managed-bean>
<managed-bean-name>productForm</managed-bean-name>
<managed-bean-class>com.example.forms.ProductForm</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>someProperty</property-name>
<value>propertyValue</value>
</managed-property>
</managed-bean>
And then reusing it in your actual viewProduct.jsp like the following
Product Name: <h:inputText value="#{productForm.productName}" styleClass="someClass"/>
Managed beans are a core component in the JSF development process. There is much more to managed beans than just initializing certain properties and helping tie your presentation to your models.To gain a better understanding of the rationale and philosophy, including IoC, behind the use of managed beans see: http://www.oracle.com/technology/tech/java/newsletter/articles/jsf_pojo/index.html

Resources