Managed Bean Per Page (JSF) - 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

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.

Split CDI bean in windowscope for separation of concerns

I have a JSF application with RichFaces 4.5.8, deltaspike for CDI beans, and EJBs which runs in an EAP 6.3. I have a page with two tables and several popupPanels. The page is backed by a CDI bean controller in WindowScope. By now the page becomes larger and larger, because the popupPanels have a lot of controls and actions.
The xhtml page is separated by composite components and ui:include's which works fine, but the CDI bean becomes larger an larger. I would like to move the action methods of the popupPanels into other CDI beans, but for me it sounds strange to have several windowScoped CDI beans in one page.
What would you do to split up the large CDI bean?
Best regards
#DarWhi's comment is correct - you may use as many WindosScoped beans in your page as you want, all of them will live only with one window. There is no restriction that you must use only single bean in the JSF page. You just need to give a name using #Named to all of such beans.
If you prefer to have only one WindowScoped bean per window, you may still separate your logic into multiple beans,. Just inject all child beans into the WindowScoped bean, and then reference actions in child beans using dot notation: #{viewScopedBean.childBean.action.
You may use variables to store references to childBeans and make your code in JSF shorter, see this answer.

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.

JSF Managed bean and managed property both necessary?

I'm new to JSF and was wondering:
If I have a controller that handles all the work for a given page and a bean that holds all the data for said page, is It necessary to have both the
#ManagedProperty(value="#{myBean}")
annotation on the controller and the
#ManagedBean(name="myBean")
#SessionScoped
annotations on the form bean?
Managed beans in JSF are used to store the state of a web page. The JSF implementation is responsible for creating and discarding the bean objects( hence the name managed bean).
For every class you write #ManagedBean, the bean object is created by the JSF implementation as and when it detects an usage of the bean with the name(you can either sepcify a bean name or leave it to JSF to use the default name-class name with the first character changed to lowercase). The object created is placed in a map of the specified scope. Each scope has a map that it uses to store bean objects which have that scope specified.
Now if you need the values of these beans in your controller, you have to inject it using the ManagedProperty annotation. Note that you would need to provide the controller with a setter method for the managedProperty.
So to answer your question, the managedBean annotation is required to tell the JSF implementation to manage the bean instance and store the values in the table specific to the session scope. And the ManagedProperty annotation is needed to use that bean stored in the current session so that you can access all of its values.
We use #ManagedBean annotation to register a java bean with a JSF framework. This is a replacement for a faces-config.xml <managed-bean> element. We typically do not use name attribute because it already defaults to a simple class name camel cased.
We use #RequestScope and other scope annotations to explicitly specify the scope we want via annotation. This is equivalent to specifying<managed-bean-scope> xml entry. If you don't specify the scope it will be defaulted to #NoneScoped.
We use #ManagedProperty and specify an EL-expression in its value attribute to use JSF-provided dependency injection engine for JSF artifacts like other managed beans with broader scopes and EL-defined variables like param. We do it in case we need the injected values in other JSF artifacts, most typically beans. The injected values are available in bean's #PostConstruct-annotated method. This is an alternative to <managed-property> xml entry.
To sum it up. Use #ManagedBean #RequestScoped to register a bean with JSF framework. Use #ManagedProperty inside this bean to be able to reference among others other JSF beans with the same or broader scopes in this bean. In case you don't need to reference other beans in the created bean you don't need to use the #ManagedProperty annotation as it's purely optional.

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.

Resources