Split CDI bean in windowscope for separation of concerns - jsf

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.

Related

How ManagedBeans figure out to which facelet or xhtml file they belong?

In JSF, I wonder how a ManagedBean understands that it should be available to an xhtml or facelet ?
To bind component values and objects to managed bean properties or to reference managed bean methods from component tags, page authors should use the Expression Language syntax.
When user make request to the page that contains EL, that refers to specific manage bean, this bean will be instantiated by JSF framework (except managed beans that have attribute eager="true", that means that managed bean is created before it is requested for the first time).
So the fact is that managed bean will be instantiated by JSF container and works as a model for the appropriate UI Component so the Facelet will know about the Bean, not vice versa

Saving a Composite Component bean attribute in ViewScoped

I would like some technique/pattern advice on retaining each single bean I bind to my Composite Components.
I am adding composite components to a form pragmatically based on user actions, and when the user is finished I want to harvest the single bean behind each composite component they added. Ex: If user selects & adds 4 composite components, that's one bean for each, so when the user is finished I want the 4 beans with the user's entered values.
This seems a bit hairy in the JSF world, but I continue to dig through stackoverflow and experiment. I'm relatively new to JSF details, but having fun.
I've got the composite components loading, each being given a bean to be used as "cc.attrs.bean" and it properly adds the control to the form. Here is what I am currently doing and what I expected:
Load Composite Component
Instantiate its Bean
Save Bean reference in a separate list in a ViewScoped bean (my hook to the bean for later)
Give Bean to Composite Component (as an attribute)
Add Composite Component to form
...User interacts with form and Composite Components adding/editing values...
User finally pushes "Done" (now I need the modified beans).
Thought I could get all the user's values from the "separate list in a ViewScoped bean" from #3 above.
My preliminary experiments tell me that if I instantiate the bean, save the bean reference in a separate ViewScoped list then give the bean to the Composite Component, the bean I saved won't have the Composite Component's values. Between all the build/render phases it seems to lose the connection between the bean I saved and the bean the Composite Component is bound to.
I don't know if I should be following this path, or if I should use a FacesComponent event technique to intercept the bean attribute being passed along, or if I should be using filters, or maybe even magical pixie dust etc...
This seemed promising: I already wrap each of my user selectable Composite Components in a single common Wrapper Composite Component (lets me put a nice PrimeFaces collapsible panel frame around them). For example, I put "Composite Component A" into "Wrapper", then I add "Wrapper" to the form. If I passed the single bean as an attribute to both those Composite Components, I was hoping that the FacesComponent event "init" technique on the Wrapper could nicely capture the "real bound bean" in my separate list in the ViewScoped bean. In my attempts on this today I'm having trouble finding the right event type and getting access to the bean... and getting lots of strange errors (probably due to my lack of detailed understanding of the lifecycle).
Stack: Eclipse Mars, JSF 2.2, Mojarra 2.2, Tomcat 8.0

Avoid auto-instantiation of managed bean when injected as #ManagedProperty

I have a requestscoped bean which can receive its data from three different viewscoped beans (from 3 different pages). The beans are JSF Managed Beans.
When I use ManagedProperty in the request scoped for 3 different view scoped beans, it instantiates the view scoped beans which is what I do NOT want. I want to simply know from which bean it is being called from and then call a specific method (different) for each bean.
How can I check which bean is instantiated and in scope so I can call the correct bean's method?
Looks like it's pretty simple. I was reading one of Balus's posts. I simply used ManagedProperty(value="#{viewScope.managedBeanName}") . It did not instantiate. For the inscope, it gave me the created bean :). Happy

What is the default Managed Bean Scope in a JSF 2 application?

Normally the default scope is the Request scope. I ve tried to delete the scope annotation and expected the bean to have a request bean scopped behaviour (by returning a submitted value on a previous page, I remember i've tried this the past and it worked fine) but i got nothing on the expression language wired to it.
So what is the default scope and why it's not the same behaviour?!
Depends on who's managing the bean.
If it's JSF via #ManagedBean, then it defaults to #RequestScoped, as mentioned in the javadoc:
If the scope annotations are omitted, the bean must be handled as if the RequestScoped annotation is present
If it's CDI via #Named, then it defaults to #Dependent, as mentioned in Weld documentation:
Finally, CDI features the so-called dependent pseudo-scope. This is the default scope for a bean which does not explicitly declare a scope type.
The effect is that the bean instance is newly created on every single EL expression. So, imagine a login form with two input fields referring a bean property and a command button referring a bean action, thus with in total three EL expressions, then effectively three instances will be created. One with the username set, one with the password set and one on which the action is invoked. In effects, this behaves the same as JSF #NoneScoped. This confirms the symptoms you're seeing.
If it's Spring via #Component, then it defaults to #Scope("singleton"), as mentioned in javadoc:
Default: "singleton"
In effects, this behaves the same as JSF #ApplicationScoped and CDI #ApplicationScoped.
Netbeans has got nothing to do with it. It's just an editing tool like notepad but then with 1000+ extra features.
See also:
what is none scope bean and when to use it?
How to choose the right bean scope?

Are #ManagedBeans obsolete in JavaEE6 because of #Named in CDI/Weld?

Because of CDI (and its implementation Weld), every POJO in JEE6 can be annotated with #Named, which makes the POJO accessible to the view.
Does that mean that ManagedBeans are completely obsolete now?
Or did I miss something where #ManagedBean still makes sense?
In short, #ManagedBean makes sense for applications that use JSF but do not use JSR 299 (whatever the reason is). Below a longer explanation from Gavin King:
Re: Comparisons to #ManagedBean annotations in JSF2?:
While looking through the Weld examples, and the older WebBeans
documentation, it looks like a
competitor to the new #ManagedBean JSF
2.0 annotations. Is there any information on when we'd want to use
one over the other?
It's a good question, and I'm not
really in full agreement with the
answers that have been posted so far.
The new EE Managed Beans specification
defines a base component model for
Java EE, together with a very basic
set of container services (#Resource,
#PostConstruct, #PreDestroy).
The idea is that other specifications
(beginning with EJB, CDI, JSF and the
new Java Interceptors spec) build upon
this base component model and layer
additional services, for example
transaction management, typesafe
dependency injection, interceptors. So
at this level, the managed beans, CDI,
interceptors and EJB specifications
all work hand-in-hand and are highly
complementary.
Now, the Managed Beans specification
is quite open-ended with respect to
identifying exactly which classes are
managed beans. It does provide the
#ManagedBean annotation as one
mechanism, but it also allows other
specifications to define different
mechanisms. So, for example:
The EJB specification says that a class obeying certain programming
restrictions with a #Stateless or
#Stateful annotation deployed in an
EJB jar is a managed bean.
The CDI specification says that any class with an appropriate constructor
deployed in a "bean deployment
archive" is a managed bean.
Given that EJB and CDI provide
arguably more convenient ways to
identify a managed bean, you might
wonder precisely what #ManagedBean is
needed for. The answer, as alluded to
by Dan, is that if you have CDI
available in your environment (for
example, if you are using EE6), then
#ManagedBean is just not really
needed. #ManagedBean is really there
for use by people who are using JSF2
without CDI.
OTOH, if you do annotate a bean
#ManagedBean, and you do have CDI in
your environment, you can still use
CDI to inject stuff into your bean.
It's just that the #ManagedBean
annotation is not required in this
case.
To summarize, if you do have CDI
available to you, it provides a far
superior programming model to the
#ManagedBean/#ManagedProperty model
that JSF2 inherits from JSF1. So
superior, in fact, that the EE 6 web
profile does not require support for
#ManagedProperty etc. The idea being
that you should just use CDI instead.
You have a choice. Either use the #ManagedBean from JSF2 to bind beans into your forms, or use the #Named annotation from CDI. If you plan on only doing JSF, you can stick to #ManagedBean, but if you want to integrate with EJB's, or make use of CDI's #ConversationScoped, then go the CDI route.
Personally I feel the next version of JSF should deprecate the #ManagedBean, and standardize on CDI. The duality is confusing to newcomers.
CDI has no view scope, because it doesn't have the notion of a view, so if you need that scope, CDI in its pure form can't do it. View scope basically means request scope + being AJAX-ready. It's not a JSF view, like a page named xyz.xhtml, even though you see JSF <f:viewParam> and the likes. A frequent use case with view-scoped beans is how to get GET parameters into a such a bean. Also read this.
Note that CDI rather lives at the EJB/service layer than the JSF/presentation layer. This blog has a nice overview.
As such #ManagedBean cannot be fully replaced by CDI, again if you're using #ViewScoped beans - at least not without extending CDI or using the Seam 3 Faces module. Using view-scoped beans is almost always going to happen when using AJAXed JSF 2-based GUI toolkits like RichFaces, PrimeFaces, IceFaces etc.
Mixing annotations from the wrong Java EE 6 packages can get you in trouble unexpectedly, again when using RichFaces or a similar API:
#javax.faces.bean.ManagedBean
#javax.faces.bean.[Jsf]Scoped
are for components used solely at the presentation layer, here by RichFaces, PrimeFaces, etc. Some rich components seem to have problems with CDI-annotated and JSF-annotated helper beans. If you get strange behavior from your beans (or beans that seem to do nothing) the wrong mix of annotations might be the cause.
Mixing JSF and CDI, like
#javax.inject.Named
#javax.faces.bean.[Jsf]Scoped
is possible and works in most cases when referenced from JSF pages, however there are some little-known issues/drawbacks, e.g. when using a JSF scope which CDI doesn't have:
Also the combination #Named #ViewScoped won't work as intended. The JSF-specific #ViewScoped works in combination with JSF-specific #ManagedBean only. Your CDI-specific #Named will behave like #RequestScoped this way. Either use #ManagedBean instead of #Named or use CDI-specific #ConversationScoped instead of #ViewScoped.
Then
#javax.inject.Named
#javax.faces.bean.[Cdi]Scoped
can be used for CDI beans directly referenced from your JSF pages AFAIK. I haven't had any problems with the above combinations so far, so you could consider #ManagedBean obsolete here.
What's left is the service layer, here mostly transactional EJB service beans declared as
#javax.ejb.*
mostly #javax.ejb.Stateless. You can even annotate and use EJBs directly from JSF pages - though I'm not sure if this design is desirable. To reference (inject) any components annotated with #javax.ejb.*, e.g. #Stateless, prefer #Inject over #EJB as described here. (Probably an ancestor of this answer...)
Finally, a very nice overview of Java EE 6 annotations can be found here:
http://www.physics.usyd.edu.au/~rennie/javaEEReferenceSheet.html
Note: the above info is not from an expert, but simply my own take/sight from a newcomers perspective on this ridiculously confusing Java EE 6 annotations spaghetti. More insight has yet to be developed. I hope this answer can endure to be a general, practical answer to this confusion - even though it has gone a little overboard in the context of the original question.
As i Just read in the Weld Reference (p. 12), #ManagedBean is now superflous:
You can explicitly declare a managed
bean by annotating the bean class
#ManagedBean, but in CDI you don't
need to. According to the
specification, the CDI container
treats any class that satisfies the
following conditions as a managed
bean:
It is not a non-static inner class. It is a concrete class, or is
annotated #Decorator.
It is not annotated with an EJB component-defining annotation or
declared as an EJB bean class in
ejb-jar.xml.
It does not implement javax.enterprise.inject.spi.Extension.
It has an appropriate constructor—either:
the class has a constructor with no parameters, or
the class declares a constructor annotated #Inject.

Resources