Hello,
Martin and I discussed the existing state of the AJAX
functionality in MyFaces. We came up with some
suggestions for improvement. Below is a brief
discussion of how AJAX requests are handled in
MyFaces, which may be useful to some, followed by our
comments.
Every component that has Ajax functionality is
expected to implement the following interface:
public interface AjaxComponent
{
void encodeAjax(FacesContext context) throws
IOException;
void decodeAjax(FacesContext context);
}
As can be expected, 'decodeAjax' is reponsible for
parsing the request and updating the component, and
'encodeAjax' generates the response to the browser.
A specialised phase-listener is registered on the
'Apply Request Values' phase. The functionality of
this class is implemented in the 'beforePhase' method.
The phase listener searches the input parameters for a
parameter called 'affectedAjaxComponent'. If found,
then the value of this parameter is the component id
of the component that generated the AJAX request. If
this parameter is not found, the phase listener exits.
The phase listener finds the component and calls the
methods 'encodeAjax and decodeAjax.
If the parameter 'updateOnly' is found, then only
encodeAjax is called.
(This is incorrect. As mentioned previously, updates
to the component are done in the 'decodeAjax' method.
I think this should be renamed to 'encodeOnly').
If 'decodeAjax' is called, then the Phase Listener
also calls the method
'facesContext.getViewRoot().processApplication(facesContext)',
which executes any actions or actionListeners that may
have been registered in the method 'decodeAjax'.
String updateOnly = (String)
facesContext.getExternalContext().getRequestParameterMap().get("updateOnly");
if(updateOnly == null)
{
// then decode
decodeAjax(ajaxComponent, facesContext);
facesContext.getViewRoot().processApplication(facesContext);
}
encodeAjax(ajaxComponent, facesContext);
If server-side state-saving is configured, then the
state of the view is saved.
context.responseComplete is called.
Here are some of the inputs we came up with:
1. There are too many special cases in the Phase
Listener code:
if (component instanceof SuggestAjax) //do something
if (component instanceof HtmlCommandButtonAjax) ....
if (ajaxComponent instanceof UIComponentPerspective)
...
In our opinion, all this logic should be moved into
their respective components. The phase listener should
not be aware of these distinctions.
2. The responsibility for rendering the response
should lie entirely with the component. The current
code does something like this:
out.print("<?xml version=\"1.0\"?>\n");
out.print("<response>\n");
((AjaxComponent) component).encodeAjax(context);
out.print("</response>");
Due to this approach, the component-writer has 2
disadvantages:
a. He is forced to render an xml response. Other
options are ruled out.
b. If he wants to use an XML API (say, JDOM) to render
the response, he is contrained, as the root element
'response' has already been rendered in the output
stream.
3. The existing component(s) ? that still use
Prototype library should be converted to use Dojo.
Obviously the existing components will have to be
altered concurrently with the changes in the Phase
Listener, so that they continue working. Anyone have a
suggestion for the best way to go forward?
Regards,
Sharath
__________________________________________________
Do You Yahoo!?
Tired of spam? Yahoo! Mail has the best spam protection around
http://mail.yahoo.com