org.apache.myfaces.application.jsp
Class JspViewHandlerImpl

java.lang.Object
  extended by javax.faces.application.ViewHandler
      extended by org.apache.myfaces.application.jsp.JspViewHandlerImpl

public class JspViewHandlerImpl
extends ViewHandler

Implementation of the ViewHandler interface that knows how to use JSP pages as the view templating mechanism.

This implementation works tightly together with the various JSP TagHandler classes to implement the behaviour mandated by the ViewHandler specification.

Rendering of a view is done in two parts: first a jsp-generated servlet is invoked to create or refresh a jsf component tree, then the component tree is walked to generate the output to send to the user.

The invoked servlet is the one generated from the jsp file which corresponds to the viewId of the view being rendered. As is normal for jsp, this servlet alternates between writing literal text to the response output stream and invoking "tag handler" classes representing the jsp tags that were present in the page. This servlet is not aware of JSF at all.

On the first visit to a view, when each JSF taghandler is invoked, the corresponding JSF component will not yet exist so it is created and added to the current view tree. Each JSF taghandler also marks itself as having "buffered body content", which means that after the start-tag is executed a temporary output stream is installed for the response. Any output generated by the jsp-servlet therefore gets written into a memory buffer rather than sent via the network socket to the sender of the request. When the end of the JSF tag is encountered, the JSF tag checks whether any such body text did exist, and if so it creates a transient f:verbatim component and inserts it into the component tree. The final result is that after this "first pass" a component tree exists which has all the JSF components in it, plus a bunch of auto-generated f:verbatim components that hold all plain text, or output generated by non-jsf jsp tags. Absolutely NO output has yet been sent to the real response stream.

On later visits to the same view, the component tree already exists (has been restored). However the "verbatim" components holding static text are not present as they were marked "transient" (not keeping them reduces the amount of memory required to "save state"). Note that these components are not needed for any phase prior to RENDER because they are not "input" components. When the jsp-generated servlet is executed, JSF taghandlers that are invoked will simply verify that a corresponding component already exists in the view-tree rather than creating a new one. However the "body buffering" occurs again, so that the appropriate transient verbatim components are once again created and inserted into the tree.

Regardless of whether the view is new or restored, the rendered output can now be generated simply by walking the component tree and invoking the encodeBegin/encodeChildren/encodeEnd methods on each component. The static components simply output their contained text.

Notes for JSF1.1 users: the new two-phase approach that uses "output buffering" to capture non-JSF output is rather like wrapping all non-jsf components in an invisible f:verbatim tag. Although that doesn't sound like a big change, it allows processing to occur in two passes rather than one. And that means that before any component is rendered the entire component tree already exists. This solves a number of JSF1.1 problems, including output-ordering problems between text and jsf components, and errors when using the "for" attribute of a label to reference a component later in the page. It does introduce a performance penalty; non-JSF-generated output now gets buffered rather than being streamed directly to the user.

Version:
$Revision: 693059 $ $Date: 2008-09-08 06:42:28 -0500 (Mon, 08 Sep 2008) $
Author:
Thomas Spiegl (latest modification by $Author: bommel $), Bruno Aranda

Field Summary
static String FORM_STATE_MARKER
           
static int FORM_STATE_MARKER_LEN
           
 
Fields inherited from class javax.faces.application.ViewHandler
CHARACTER_ENCODING_KEY, DEFAULT_SUFFIX, DEFAULT_SUFFIX_PARAM_NAME
 
Constructor Summary
JspViewHandlerImpl()
           
 
Method Summary
 Locale calculateLocale(FacesContext facesContext)
          Get the locales specified as acceptable by the original request, compare them to the locales supported by this Application and return the best match.
 String calculateRenderKitId(FacesContext facesContext)
           
 UIViewRoot createView(FacesContext facesContext, String viewId)
          Create a UIViewRoot object and return it; the returned object has no children.
 String getActionURL(FacesContext facesContext, String viewId)
          Return a string containing a webapp-relative URL that the user can invoke to render the specified view.
 String getResourceURL(FacesContext facesContext, String path)
           
protected  ViewHandlerSupport getViewHandlerSupport()
           
 void renderView(FacesContext facesContext, UIViewRoot viewToRender)
          Generate output to the user by combining the data in the jsp-page specified by viewToRender with the existing JSF component tree (if any).
 UIViewRoot restoreView(FacesContext facesContext, String viewId)
          Just invoke StateManager.restoreView.
 void setViewHandlerSupport(ViewHandlerSupport viewHandlerSupport)
           
 void writeState(FacesContext facesContext)
          Writes a state marker that is replaced later by one or more hidden form inputs.
 
Methods inherited from class javax.faces.application.ViewHandler
calculateCharacterEncoding, initView
 
Methods inherited from class java.lang.Object
clone, equals, finalize, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait
 

Field Detail

FORM_STATE_MARKER

public static final String FORM_STATE_MARKER
See Also:
Constant Field Values

FORM_STATE_MARKER_LEN

public static final int FORM_STATE_MARKER_LEN
Constructor Detail

JspViewHandlerImpl

public JspViewHandlerImpl()
Method Detail

setViewHandlerSupport

public void setViewHandlerSupport(ViewHandlerSupport viewHandlerSupport)
Parameters:
viewHandlerSupport - the viewHandlerSupport to set

getViewHandlerSupport

protected ViewHandlerSupport getViewHandlerSupport()
Returns:
the viewHandlerSupport

calculateLocale

public Locale calculateLocale(FacesContext facesContext)
Get the locales specified as acceptable by the original request, compare them to the locales supported by this Application and return the best match.

Specified by:
calculateLocale in class ViewHandler

calculateRenderKitId

public String calculateRenderKitId(FacesContext facesContext)
Specified by:
calculateRenderKitId in class ViewHandler

createView

public UIViewRoot createView(FacesContext facesContext,
                             String viewId)
Create a UIViewRoot object and return it; the returned object has no children.

As required by the spec, the returned object inherits locale and renderkit settings from the viewRoot currently configured for the facesContext (if any). This means that on navigation from one view to another these settings are "inherited".

Specified by:
createView in class ViewHandler

getActionURL

public String getActionURL(FacesContext facesContext,
                           String viewId)
Return a string containing a webapp-relative URL that the user can invoke to render the specified view.

URLs and ViewIds are not quite the same; for example a url of "/foo.jsf" or "/faces/foo.jsp" may be needed to access the view "/foo.jsp".

This method simply delegates to ViewHandlerSupport.calculateActionURL.

Specified by:
getActionURL in class ViewHandler

getResourceURL

public String getResourceURL(FacesContext facesContext,
                             String path)
Specified by:
getResourceURL in class ViewHandler

renderView

public void renderView(FacesContext facesContext,
                       UIViewRoot viewToRender)
                throws IOException,
                       FacesException
Generate output to the user by combining the data in the jsp-page specified by viewToRender with the existing JSF component tree (if any).

As described in the class documentation, this first runs the jsp-generated servlet to create or enhance the JSF component tree - including verbatim nodes for any non-jsf data in that page.

The component tree is then walked to generate the appropriate output for each component.

Specified by:
renderView in class ViewHandler
Throws:
IOException
FacesException

restoreView

public UIViewRoot restoreView(FacesContext facesContext,
                              String viewId)
Just invoke StateManager.restoreView.

Specified by:
restoreView in class ViewHandler

writeState

public void writeState(FacesContext facesContext)
                throws IOException
Writes a state marker that is replaced later by one or more hidden form inputs.

The problem with html is that the only place to encode client-side state is in a hidden html input field. However when a form is submitted, only the fields within a particular form are sent; fields in other forms are not sent. Therefore the view tree state must be written into every form in the page. This method is therefore invoked at the end of every form.

Theoretically the state of a component tree will not change after rendering starts. Therefore it is possible to create a serialized representation of that state at the start of the rendering phase (or when first needed) and output it whenever needed as described above. However this is not currently implemented; instead the entire page being generated is buffered, and a "marker" string is output instead of the tree state. After the rendering pass is complete the component final tree state is computed and the buffer is then post-processed to replace the "marker" strings with the real data.

This method also supports "javascript viewstate". TODO: document this.

Specified by:
writeState in class ViewHandler
Parameters:
facesContext -
Throws:
IOException


Copyright © 2012 The Apache Software Foundation. All Rights Reserved.