This week's book giveaway is in the OCAJP 8 forum. We're giving away four copies of OCA Java SE 8 Programmer I Study Guide and have Edward Finegan & Robert Liguori on-line! See this thread for details.
I'm new to Java development and am coming from an ASP.NET background, so JSF seemed like a good platform to use. Templating makes sense and works more or less like ASP.NET master pages, but I'm having the hardest time getting my head around Composite Controls which I assumed were roughly equivilent to ASP.NET User Controls. I would like to pass them a data object, and have code tied to the control responsible for rendering it. This seems like a simple and common task, but I'm running into two major problems.
#1 I don't know where to store the logic for the custom control. I can put it in a Bean, but there doesn't seem to be a way to tie a Bean directly to an instance of a composite control. The best I can really do is @RequestScoped which ties it to the page request. But what if I want to have 20 copies of the control on the page, each with their own data objects to render? What's the proper way to tie code to the composite control?
#2 There doesn't seem to be any reasonable way to interact with the control from the code for my page. Say I want to pass my control a Customer object from the page to the composite control. How would I go about doing this? All I can really find is ways to pass simple types and Strings to the control from the pages .xhtml file, not from code. How do I get a reference to the controls bean from the code for my page?
Am I trying to use these composite controls in a way they're not designed for? Is there something else I should use instead (beside an include) for housing code to render an element of a page that is re-used? I'm sorry for the basic questions, none of the tutorials I can find seem to cover this.
It might be a little difficult to answer, but I'll see what I can do.
Some basic architectural considerations to start with, I think. In MVC, a Controller binds together a Model and a View, so that implies that you need a separate Controller instance for each of them. The code, of course, is sharable, just not the binding storage.
In JSF, one rarely codes Controllers. Most of the Controller code is in the FacesServlet and in tag implementation classes. There are several ways to implement composite controls in JSF, but the easy ones are actually just aggregations of simple controls operating under their individual controllers. That's how, for example, the Facelets compositing feature works. The harder way is to implement an actual tag definition of your own, which is nasty, complex, and subject to breakage between JSF releases. A variation of this is the Facelets tag implementation class, but it isn't quite as general-purpose as actual JSF tag implementations.
In any event, MVC as a theoretical framework does not store anything in controllers other than the locations of their Models and Views. Possibly some internal hints that optimize rendering and data transfer, but nothing of substance. This is fairly important, since it's possible - and sometimes essential - that a single Model be accessible via several different Views at the same time, each with its own Controller and therefore all of the stateful data needs to be in the Model where all Controllers have equal access to it.
That last fact is one reason why compositing definitions can work so effectively using the templating facilities.
As I said, in JSF, one rarely writes Controllers. However, when you have a composite template and the different model values interact, it's not uncommon to facilitate these interactions using Listeners. Listeners are more "controller-like" than they are actual controllers, and they must be used with care (and not as freely as a lot of JSF newbies think!), but when used properly, they can be very effective.
An IDE is no substitute for an Intelligent Developer.
Joined: Jul 08, 2012
Thanks for the reply Tim. I think I'm mostly following you, but if composite controls don't have controllers and I shouldn't get in the habit of using listeners on a regular basis, where should I store the logic to render sections of a page that are re-used frequently? The composite control itself is great for the basic layout, but you usually need to make a few decisions when rendering.
Well, there's a difference between using listeners judiciously and not using them at all. What I was referring to is the classic case where JSF newbies rush in and spawn massive quantities of code full of javax.faces this and javax.faces that when they should be using POJO techniques.
However, listeners are invoked when a page is submitted, not when it is rendered. And even then, most listeners won't get invoked unless the submitted form contains 100% valid data, since listeners don't trigger events, they listen to them (A lot of people don't seem to realize that).
So in JSF, all the rendering decisions need to have been made in the backing beans. Most of the rendering control in JSF is done by use of the "rendered=" attribute and/or selection of style classes using EL expressions.
Which brings up another point. EL is a very useful thing, but keep EL expressions as simple as possible. Given a choice between a complex EL expression and a simple one referencing a complex calculation in the backing bean, go with the backing bean. It's easier to debug by far and is more in keeping with how MVC is supposed to separate things.