Notifying one bean from another in ICEFaces - jsf

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.

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.

Xpages, faces-config, managed beans, and scoped variables

I have some properties in my database that will rarely if ever change, but are used pervasively throughout. It seems that this might be something I could do with a managed bean?
<managed-bean>
<managed-bean-name>bu</managed-bean-name>
<managed-bean-class> </managed-bean-class>
<managed-bean-scope>application</managed-bean-scope> </managed-bean>
I want to end up with a list of values in applicationScope.bu.
Do I just write a simple java implementation? Is there an easier or better way?
Your faces-config, to properly implement a managed bean, should include a block like you've put in, but you are missing the <managed-bean-class> value. This is what class will be created in memory (in your case, applicationScope). If your bean class has methods to return the values you're looking for, you're good. I'm a fan of beans (managed or POJO) and use this approach for a few applications.
[Edit]
As Steve points out in his answer, your need for accessibility, and quantity, of your configuration may drive how you store those values. How you interface with them may be different, and I lean heavily towards managed bean use.
For small amounts of values that need to be store for a given application, I like to set those in XSP Properties, then I can reference those via XSPContext.getProperty('xsp.property.name');.
For more complex things, I tend to create a config document, which I use as analogous to a profile document, which I then load from / store to the values.
[/Edit]
If you're looking for a good place to start with managed beans, or a quick reference for sanity checking, I'd recommend checking out Per Henrik Lausten's blog post on the subject.
The short version is, to have a managed bean, you must have:
a Java class
built with private properties (values)
which are exposed by public getter/setter methods
implements Serializable (java.io.Serializable)
contains an argument-less constructor (must take no parameters to be built the first time; not to mean that it can't go find values elsewhere)
an entry in faces-config (much like you've outlined)
binding via
EL with #{beanName.propertyName} (EL uses camel cased property names, converting, so the getter method of getPropertyName() is notated in EL as first shown
SSJS with #{javascript:return beanName.getPropertyName()} (full method invocation
You can then use your managed bean's name (in your case "bu") in either Expression Language or SSJS blocks. In the EL binding, note that the properties use camel casing to be accessed; so a property of myProperty is exposed by getMyProperty but looks like #{bu.myProperty}. You can also use it in SSJS, by the full method name, such as #{javascript:return bu.getMyProperty();}
Example
Here's one I have in my demo app is for a data object. It's in viewScope so it lives with the life cycle of a given XPage.
faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean>
<managed-bean-name>gotHouse</managed-bean-name>
<managed-bean-scope>view</managed-bean-scope>
<managed-bean-class>com.westeros.model.HouseModel</managed-bean-class>
</managed-bean>
<!--AUTOGEN-START-BUILDER: Automatically generated by IBM Domino Designer. Do not modify.-->
<!--AUTOGEN-END-BUILDER: End of automatically generated section-->
</faces-config>
HouseModel.java
*I've modified this here for brevity as an example.
package com.westeros.model;
//...
public class HouseModel implements Serializable {
private static final long serialVersionUID = 1L;
private String name;
//...
public HouseModel(){}
public void load(String unid){
// do some load things from the doc's UNID
}
public void setName(String name){
this.name = name;
}
public String getName(){
return this.name;
}
//...
}
house.xsp (House XPage) *excerpted for brevity of example
<?xml version="1.0" encoding="UTF-8"?>
<xp:view
xmlns:xp="http://www.ibm.com/xsp/core">
<!-- truncating -->
<div
class="form-group">
<xp:label
for="name"
value="Name" />
<xp:inputText
id="name"
value="#{gotHouse.name}" />
</div>
<!-- truncating -->
</xp:view>
You can use managed properties of managed beans.
For example this little bean...
package ch.hasselba.xpages;
import java.io.Serializable;
#SuppressWarnings("serial")
public class MyBean implements Serializable {
private String dbName;
public void setDbName(String dbName) {
this.dbName = dbName;
}
public String getDbName() {
return dbName;
}
}
... can be initialized in the faces-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<faces-config>
<managed-bean>
<managed-bean-name>myBean</managed-bean-name>
<managed-bean-class>ch.hasselba.xpages.MyBean</managed-bean-class>
<managed-bean-scope>application</managed-bean-scope>
<managed-property>
<property-name>dbName</property-name>
<value>MyName</value>
<property-class>java.lang.String</property-class>
</managed-property>
</managed-bean>
</faces-config>
As soon you acccess the bean, the value is "there". F.e. a label on your XPage...
<xp:label
value="#{myBean.dbName}"
id="label1">
</xp:label>
... will be then displaying MyName.
Managed properties can contain other beans, and access runtime properties (f.e. request parameters) which makes them extremly powerful.
If I understand your question correctly, I don't think the properties of a managed bean would be where you would want to store application properties.
I would just stick them in application scope on the landing page of your application.

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).

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.

Passing data between managed components in JSF

Is it actually possible to pass any data between managed components in JSF? If yes, how to achieve this?
Could anyone provide any sample?
There are several ways. If the managed beans are related to each other, cleanest way would be injection. There are different ways depending on JSF version and whether CDI is available.
CDI
Just use #Inject.
#Named
#SessionScoped
public class Bean1 {
// ...
}
#Named
#RequestScoped
public class Bean2 {
#Inject
private Bean1 bean1; // No getter/setter needed.
}
Other way around can also, the scope doesn't matter because CDI injects under the covers a proxy.
JSF 2.x
Use #ManagedProperty.
#ManagedBean
#SessionScoped
public class Bean1 {
// ...
}
#ManagedBean
#RequestScoped
public class Bean2 {
#ManagedProperty("#{bean1}")
private Bean1 bean1; // Getter/setter required.
}
Other way around is not possible in this specific example because JSF injects the physical instance and not a proxy instance. You can only inject a bean of the same or broader scope into a bean of a particular scope.
JSF 1.x
Use <managed-property> in faces-config.xml.
public class Bean1 {
// ...
}
public class Bean2 {
private Bean1 bean1; // Getter/setter required.
}
<managed-bean>
<managed-bean-name>bean1</managed-bean-name>
<managed-bean-class>com.example.Bean1</managed-bean-class>
<managed-bean-scope>session</managed-bean-scope>
</managed-bean>
<managed-bean>
<managed-bean-name>bean2</managed-bean-name>
<managed-bean-class>com.example.Bean2</managed-bean-class>
<managed-bean-scope>request</managed-bean-scope>
<managed-property>
<property-name>bean1</property-name>
<value>#{bean1}</value>
</managed-property>
</managed-bean>
See also:
Backing beans (#ManagedBean) or CDI Beans (#Named)?
How to choose the right bean scope?
Get JSF managed bean by name in any Servlet related class
To add to BalusC's answer, if you are using a dependency-injection framework (spring, guice, etc.), or if using JSF 2.0, you can have one managed bean set into the other using just:
#Inject
private Bean2 bean2;
(or the appropriate annotation based on your DI framework)

Resources