Sharing components between views - how to improve my design? - jsf

I'm working on a JSF webapp which purpose is to wrap a command-line program.
One of its main functionality is the ability to share a session between users (eg. for courses purpose), so that when an input is sent to an instance of the application, the output sent to every subscriber for this session.
As a result of this design, the webapp is mainly composed of a view-scoped bean which will request a controller of the command-line application.
It has also been chosen to identify a session with the URL fragment (eg. mydomain/myapp/#SESSIONID), so that anyone using the URL with the same fragment will share inputs and outputs, using its own instance of the view-scoped bean but sharing the same controller
In order to push results to all subscribers, I'm using Primefaces Push. Results are primarily text that has to be appened to the webapp's terminal, but some commands lead to the programmatic creation of a JSF component.
In order to handle this, I just render these components to a string that I send to all subscribers.
Then, I realized that in order to handle ajax requests from components (and from every subscriber), the associated UIComponent needs to be added to the UIViewRoot in the context of (don't know how to express this) each view-scope bean.
As a matter of fact, I first tried to bind a "common container" (a UIForm) to a property of the view scoped bean, in which I would put the programmatically created components, but I obviously had to face the chicken/egg issue #BalusC talks about in his blog, because the component was added again on each ajax request. Setting javax.faces.PARTIAL_STATE_SAVING to false didn't help either (I'm using MyFaces 2.2.5)
So, as somewhat of a workaround, when the controller needs to create a new component, it basically adds the id of the component to the data pushed (in a HashMap converted to Json), and all subscribers will trigger (back) a remoteCommand to its own instance of the view-scoped bean, in order to update the "common container" from its own UIViewRoot.
This does work, but I don't like this way of doing it!
So:
would it be possible to handle this kind of sharing between view-scope beans (with the same name) which are stored in different HTTP sessions? I'm refering to this answer from #BalusC... maybe playing with javax.faces.ViewState - would it even be possible?
Is there a "magical" scope for my currently-view-scoped bean I could use?
Shall I rather use a completely different design?
Thanks!

If you want share data between all your application users you can use application scope.
If you still want to use view scope, you can connect your view scope with another application scope like this:
ApplicationView appView = BeanUtil.findBean("applicationView", FacesContext.getCurrentInstance());
import javax.faces.context.FacesContext;
public class BeanUtil {
#SuppressWarnings("unchecked")
public static <T> T findBean(String beanName, FacesContext context) {
return (T) context.getApplication().evaluateExpressionGet(context,
"#{" + beanName + "}", Object.class);
}
}

Related

How to update bean in database on a RequestScoped view?

First of all, sorry for my english. I have a RequestScoped ManagedBean in order to send parameters to other views, without getting the The scope of the object referenced by expression is shorter than the referring managed beans error. I also have in the same RequestScoped view a p:dataTable showing these beans objects, with an update button for each row, that retrieves this bean to another form in the same view to be update with new values.
The problem is, when I hit the submit button to record the new values, another record is created, instead of the older one being updated. Of course, because the bean is killed when the submit button is pressed (RequestScoped), creating a new bean and another record in the DB. How can I fix it in this scope?
I've seen some alternatives using #PostConstruct here, however I'm not entirely sure it would solve my specific problem.
EDIT:
After researching a bit more into this topic, I came to another doubt: I am using the same Bean in both views (in my case, ProjectBean), should I create a new Bean with RequestScoped annotation (something like ProjectIdBean), set the older one to ViewScoped (so I can reproduce updates naturally on my Database), and let this new Bean handle the requests for other views?
Submit button:
<p:commandButton value="Gravar" action="#{projetoBean.gravar}"
process="#form" update="#form :formTabelaProjetos:tabelaProjetos" />
'Gravar' method:
public void gravar() {
System.out.println("Gravando projeto " + this.projeto.getNome());
ProjetoDAO dao = new ProjetoDAO();
if (this.projeto.getId() == null) {
dao.adiciona(this.projeto);
projetosAtivos = this.getProjetosAtivos();
} else {
dao.atualiza(this.projeto);
}
this.projeto = new Projeto();
}
You can use request scoped backing bean for updating entities. The problem is, that the request life cycle ends when your page is rendered. So anything you loaded will get discarded. The submit creates another request, that will try to reload resources, but it is a different request than the previous one and for example request parameters often do not contain what the programmer expects. But this is what you found out already. There are two ways how to deal with the problem:
1) use simple getters and setters to set "String, Integer" and similar variables in your request scoped bean, that you use to reconstruct and modify the entity you want to update. It is not convenient for the programmer but request scoped beans save resources of your server.
2) change the scope of your backing bean. Session scope is not ideal, because it can stay in memory for a really long time. And you might realize you need to clean it up manually. Much better is ViewScoped bean as it allows you to work with the entities you loaded over several steps. It gets wiped out when the user leaves the page.
#javax.faces.bean.ViewScoped
#javax.faces.bean.ManagedBean
public class SomethingBean {
......
}

Why FaceletViewHandlingStrategy.renderView force http session creation [duplicate]

I am running Mojarra 2.2.0.
<context-param>
<param-name>javax.faces.STATE_SAVING_METHOD</param-name>
<param-value>client</param-value>
</context-param>
The managed bean action method is-
public void action() {
HttpSession session = (HttpSession) FacesContext.getCurrentInstance()
.getExternalContext().getSession(false);
System.out.println(session.getId()); // not null for stateful views
}
For stateless views session.getId() throws NPE
For views which are not stateless-
Firing a GET request, there is JSESSIONID=340041C96D5AA446D761C3602F54A76D
I read it here that-
For client side state saving mechanism, JSF won't create the session
and will store the view state in a hidden input field with the name
javax.faces.ViewState in the form whenever necessary.
Further, it's mentioned here that
JSF will indeed autocreate the session because the JSF view state has
to be stored over there. If you set the JSF state saving method to
client instead of server, then it won't be stored in session and hence
no session needs to be created
I think the above line is a source for trouble for me.
If you set the JSF state saving method to client instead of server,
then it won't be stored in session // FULLY AGREED
and
hence no session needs to be created. // This confuses because for
client side saving mechanism, a session id gets generated by the
servlet container & hence there is a session associated with the
request.
In reference to the discussion which I had with BalusC in this question,
I created a HttpSessionListener-
#WebListener
public class MyHttpSessionListener implements HttpSessionListener {
public void sessionCreated(HttpSessionEvent event) {
Thread.dumpStack();
}
public void sessionDestroyed(HttpSessionEvent event) {
}
}
See below attached screenshots(these 2 screenshots are for version 2.0.3, there must have been an old bug due to which the session was getting created)-
Libraby (Mojarra 2.2.0)-
When does JSF creates a session
Eaiest way to naildown this is creating a HttpSessionListener, putting a debug breakpoint on sessionCreated() method and inspecting the call stack who needed to get the session for the first time (and thus implicitly needs to create it).
In below example you will see a chain of getSession() calls in the call stack. You will see that FaceletViewHandlingStrategy.renderView() method is the one calling it for the first time.
After you click on FaceletViewHandlingStrategy.renderView() line in debugger's call stack, you will get into its source code (Maven will load source code automatically, otherwise you need to manually attach it).
You see, when server side state saving is enabled and the view to render is not transient (stateless), then JSF will implicitly create the session, just to ensure it's created on time in order to save the view (if the session was created later, e.g. during render response phase, you would otherwise risk exceptions like this Adding <h:form> causes java.lang.IllegalStateException: Cannot create a session after the response has been committed).
You'll in the source code also immediately see that when the state saving method is set to client, or when the view is stateless as in <f:view transient="true">, then JSF won't anymore implicitly create the session. Older JSF versions may do that as you figured, but this is to be accounted as a bug and ought to be fixed in a newer version.
If you would like to ensure statelessness and avoid accidental/unforeseen session creation, then you could just throw new IllegalStateException() inside sessionCreated() method. When that happens, you just have to look in call stack who's responsible for creating the session and then fix/change the code to not do that anymore.
what does it puts in a session map?
Under the covers, ExternalContext#getSessionMap() delegates to HttpSession#setAttribute()/getAttribute()/removeAttribute(). You can listen on those methods using a HttpSessionAttributeListener.
In below example you will see that ViewScopeContextManager.getContextMap() line calls SessionMap#put() method in order to put something in the session map. When you unfold the event argument, you will see the session attribute name and value, which is com.sun.faces.application.view.activeViewContexts and an empty ConcurrentHashMap respectively.
Indeed, I was using a #Named #ViewScoped which was referenced by an value expression on the particular page (you see EL resolver and Weld resolver further down in call stack). When you click ViewScopeContextManager.getContextMap() line in call stack, you'll see that it was just preparing a map in session scope in order to store view scoped beans.
That's just one example. There are more things which could be stored in the session. Using a debugger this way and inspecting the associated source code will tell a lot about the Why.

Canonical way to obtain CDI managed bean instance: BeanManager#getReference() vs Context#get()

I figured that there are two general ways to obtain an auto-created CDI managed bean instance via BeanManager when having solely a Bean<T> to start with (which is created based on Class<T>):
By BeanManager#getReference(), which is more often shown in
snippets:
Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class));
TestBean testBean1 = (TestBean) beanManager.getReference(bean, bean.getBeanClass(), beanManager.createCreationalContext(bean));
By Context#get(), which is less often shown in snippets:
Bean<TestBean> bean = (Bean<TestBean>) beanManager.resolve(beanManager.getBeans(TestBean.class));
TestBean testBean2 = beanManager.getContext(bean.getScope()).get(bean, beanManager.createCreationalContext(bean));
In effects, they do ultimately exactly the same thing: returning a proxied reference to the current CDI managed bean instance and auto-creates the bean instance if it doesn't already exist in the scope.
But they do it a bit differently: the BeanManager#getReference() always creates a whole new proxy instance, while the Context#get() reuses an existing proxy instance if already created before. This is evident when the above code is executed in an action method of an existing TestBean instance:
System.out.println(testBean1 == testBean2); // false
System.out.println(testBean1 == this); // false
System.out.println(testBean2 == this); // true
The javadoc of Context#get() is very explicit in this:
Return an existing instance of certain contextual type or create a new instance by calling Contextual.create(CreationalContext) and return the new instance.
while the javadoc of BeanManager#getReference() is not explicit enough on this:
Obtains a contextual reference for a certain bean and a certain bean type of the bean.
This got me confused. When do you use the one or the other? For the both ways you need a Bean<T> instance anyway, from which the bean class and bean scope is readily available which is required as additional argument. I can't imagine why they would need to be supplied externally in this specific case.
I can imagine that Context#get() is more memory efficient as it doesn't unnecessarily create another proxy instance referring the very same underlying bean instance, but just finds and reuses an existing proxy instance.
This puts me to the following question: when exactly is the BeanManager#getReference() more useful than Context#get()? It's more often shown in snippets and more often recommended as solution, but it only unnecessarily creates a new proxy even when one already exists.
beanManager#getReference gives you a new instance of a client proxy but the client proxy will forward method calls to the current contextual instance of a particular context.
Once you obtain the proxy and keep it and the method calls will be invoked on the current instance (e.g. current request).
It is also useful if the contextual instance is not serializable - the client proxy will be and will reconnect after you deserialize it.
BeanManager#getContext obtains the target instance without a client proxy. You may still see a Weld's proxy in the class name but that is an enhanced subclass that provides interception and decoration. If the bean is not intercepted nor decorated this will be a plain instance of the given bean.
Usually (1) is more suitable unless you have a special use-case where you need to access the target instance directly (e.g. to access its fields).
Or in other words
1) BeanManager#getReference will return a 'Contextual Reference', with a normal scoping proxy for the bean.
If a bean have with #SessionScoped as
#SessionScoped User user;
Then the contextual reference user will 'point' to the respective User instance (the 'Contextual Instance') of the current session for each invocation.
Two different invocations to user.getName() from two different web browsers will give you different answers.
2) Context#get() will return a the internal 'Contextual Instance' without the normal scoping proxy.This is usually nothing a user should call himself. If you get the User user for "Bob" that way and store it in an #ApplicationScoped bean or in a static variable,
then it will always remain to be the user "Bob" - even for web requests from other browsers! You will get a direct, non-proxied instance.
I have a Singleton that I was using the getReference() method to get the reference to. Even though the singleton was already initialized, the proxy created through getReference() called the #PostConstruct each time getReference() was used.
#Startup
#ApplicationScoped
#Singleton
#PostConstruct
private void initialize() {}
By switching to the getContext().get() method, the unnecessary #PostConstruct proxy calls are no longer made.
This was very helpful when integrating CDI with javafx, the thing was that I needed a reference to the right scoped object cause and not the proxy of the dependent scope...
I used a producer method to get a javaFX Node that gets injected into the controler like so:
#Inject
#ApplicationScoped
#FXMLFile("javafx/wares.fxml")
#FXMLController(WaresController.class)
Parent wares;
but when using the BeanManager#getReference() the proxy I get back "eats" all the values that are set by the FXMLLoader, the getContext.get() way solved it.
Thnx for this

JSF passing view parameters by reference - when object must be instantiated

Let's say I've got a register page & a register confirm page. I enter user
details into the register page, navigate to the register confirm page where
I can return back to the register page if there are any mistakes.
I'm going to use view parameters to make the registration data available
from the register page to the confirm page, and vice versa.
Supposing there are 20 items of data to be moving from page to page, that's
a lot of view parameters and a lot of setPropertyActionListeners, especially
as all the data is going to end up nicely packaged in a User object.
So what I want to do is input the data on the register page into the
properties of a User record and send a reference to it to the register
confirm page. What gave me an idea was seeing the BalusC WeakHashMap
converter. This is a JSF converter which has a static weak hash map and
generates a uuid as the value for a map entry and the object reference as
the key. So by specifying this as a converter for f:viewParam you send
the uuid in the query string.
This works fine. The issue I have is that on the register page I have to
get an instance of a User class with new. Then I can do:
<h:inputText value="#{bean.user.firstname}"/>
(etc...), and pass the user instance as a view parameter. It works fine from
the register to the confirm page. The issue is that when I perform the
reverse, sending the user reference back to the register page from the
confirm page I absolutely cannot prevent the register page backing bean
from re-instantiating the user object, after the setter has been called
as a result of the view parameter.
So the converter does it's job and retrieves the User object from the
hash map, calls setUser() in the backing bean, and then I see the
constructor for the User class firing.
I've tried calling new User() from the bean constructor, in #PostConstruct,
in a preRenderView (also checking if an ajax request), but nothing I try
prevents the work of the view parameter from getting wiped out if new is
involved. I'm sure there's a simple solution but I just can't see it right
now.
I'd be grateful for any suggestions for how to solve this problem.
The issue I have is that on the register page I have to get an instance of a User class with new.
So what code is initially creating this new User instance then? If you do this in the preRenderView handler, then you can simply check for null, can't you?
If the view parameter and converter haven't done their job, user would still be null and you create a new instance. The bean constructor and #PostConstruct won't do you any good here, since they both run before the view parameter does its thing, but the preRenderView event is guaranteed to run after it.
#ManagedBean
public class Bean {
private User user;
public void onPreRenderView() {
if (user == null) {
user = new User();
}
}
}
(Something to additionally consider is that the conversation scope already does exactly what you're trying to do here. This is part of CDI not JSF, but if you're running in a Java EE 6 Web Profile compliant AS (JBoss AS 6 or 7, Glassfish V3, Resin 4, ...) you already have it. Otherwise it's just an extra jar.)
After several attempts over more than a year to find a solid long term solution
to this problem, at last! I've found one. The solution comes in the form of the
Apache Myfaces CDI extensions project, aka Myfaces CODI.
This provides additional scopes such as the #ViewAccessScoped which ensures that
if a bean is referenced by a page then it is available for that page. Also
provided is support for conversation groups. In the scenario where I want to
pass an object reference from a register page to a register confirm page, the
confirm page can just access the registerView bean directly on the next request.
Alternatively you can #Inject one bean into another and access it on the next
request, or use f:setPropertyActionListener from the source page.
Myfaces CODI works fine with Mojarra and also with ajaxified component libraries
such as primefaces. The concept is similar to what is provided by Jboss Seam,
though I've found the additional scope support to be better thought out and I've
tested this on glassfish 3.1.1 with no problems.
If you're using #ManagedBean and scope annotations from the javax.faces.bean
package in your code, codi intercepts these annotations and uses it's own
CDI based versions, so you can convert to CDI simply by adding codi as a
dependency to your project and not changing any code.
For me this is like moving from black and white TV to colour TV, I wish I'd
found this stuff sooner.
CODI documentation

Scalability and Thread Safety of Application Scoped ManagedBean Methods

During testing a weakness was exposed in how our app builds f:selectItems lists, specifically, entering really long names on some of our entities screws page alignment by making really wide selects.
Many of these selectItem lists are duplicated in multiple views and backing beans, so I'd like to consolidate their creation.
We already have an application scoped bean that provides List<SelectItem> for enums, and my initial thought was to place them there.
I have some questions, though. We're using jsf 1.2 (if that matters)
1) My understanding is that application scoped beans are singleton simply because a single instance is instantiated and placed in session context. They are not like EJB3 singletons in that only one thread can access any method, so multiple requests won't block trying to access different methods. Is that correct?
2) I suspect each method would have to be synchronized to prevent multiple threads calling the same method from clobbering each other. Is that the case even if the only class member accessed in the method is a threadsafe stateless #EJB?
Following is an implementation of one of them that would be used in 20 views. The implementations for 10 other entities would be similar. Also, the appropriate converters are registered.
public synchronized List<SelectItem> getAccountSelect(){
List<Account> list = new ArrayList<Account>(pemEJB.list(Account.class));
Collections.sort(list, new AccountByActiveByName());
List<SelectItem> result=new ArrayList<SelectItem>(list.size());
for(Account row : list){
result.add(new SelectItem(row,
StringUtil.prefixTruncate(row.getName(), MAX_ACCT_LENGTH, row.isActive())));
}
return result;
}
Any advice appreciated
If it's really mandatory to do the data loading in a getter instead of in the constructor/postconstruct, then there's definitely no point of making it an application scoped bean. Just make it a request scoped one where you do the data loading job in the constructor/postconstruct.
In the jsf applications I work on we load almost all of our reference data (values for selectOneMenues primarily) in Application scope beans and we set up the values in the Constructor of those beans. The data is then available to other managed beans and views via getters but is globalized and centralized for the application. Since the values are only read via getters there is no need for synchronization.
We then expose the beans as mbeans through jmx with a reload method so that they can be updated as needed. The reload method(s) are synchronized so as to block during the short reloads.
In your example above it seems like you could just return a Collection of selectItems so as long as the values are setup in advance you can use this method and still serve multiple threads just fine:
public List<SelectItem> getAccountSelectItems() {
return this.accountSelectItems;
}
Just add this private member to your bean:
private List<SelectItem> accountSelectItems;
and set it up in the constructor:
public AccountBean() {
List<Account> list = new ArrayList<Account>(pemEJB.list(Account.class));
Collections.sort(list, new AccountByActiveByName());
this.accountSelectItems = new ArrayList<SelectItem>(list.size());
for(Account row : list) {
this.accountSelectItems.add(new SelectItem(row, StringUtil.prefixTruncate(row.getName(), MAX_ACCT_LENGTH, row.isActive())));
}
}
If on the other hand this is data that is constantly changing and needs to be updated you might be better off just loading it per session or per request, though you can reload it periodically in application scope using Quartz or some other timer to keep the data reads from your data source down if real time is not an essential requirement for this data in your app. If you are reloading the data then you will want to synchronize those operations if you're using application scope.

Resources