com.sun.jsftemplating.layout.LayoutViewHandler Maven / Gradle / Ivy
/*
* The contents of this file are subject to the terms
* of the Common Development and Distribution License
* (the License). You may not use this file except in
* compliance with the License.
*
* You can obtain a copy of the license at
* https://jsftemplating.dev.java.net/cddl1.html or
* jsftemplating/cddl1.txt.
* See the License for the specific language governing
* permissions and limitations under the License.
*
* When distributing Covered Code, include this CDDL
* Header Notice in each file and include the License file
* at jsftemplating/cddl1.txt.
* If applicable, add the following below the CDDL Header,
* with the fields enclosed by brackets [] replaced by
* you own identifying information:
* "Portions Copyrighted [year] [name of copyright owner]"
*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
*/
package com.sun.jsftemplating.layout;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.Stack;
import java.util.Set;
import java.util.HashSet;
import javax.faces.FactoryFinder;
import javax.faces.application.StateManager;
import javax.faces.application.ViewHandler;
import javax.faces.application.StateManager.SerializedView;
import javax.faces.component.UIComponent;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.sun.jsftemplating.el.PageSessionResolver;
import com.sun.jsftemplating.layout.descriptors.LayoutComponent;
import com.sun.jsftemplating.layout.descriptors.LayoutComposition;
import com.sun.jsftemplating.layout.descriptors.LayoutDefinition;
import com.sun.jsftemplating.layout.descriptors.LayoutElement;
import com.sun.jsftemplating.layout.descriptors.LayoutFacet;
import com.sun.jsftemplating.layout.descriptors.LayoutInsert;
import com.sun.jsftemplating.layout.descriptors.Resource;
import com.sun.jsftemplating.util.LayoutElementUtil;
import com.sun.jsftemplating.util.LogUtil;
import com.sun.jsftemplating.util.SimplePatternMatcher;
import com.sun.jsftemplating.util.TypeConversion;
import com.sun.jsftemplating.util.TypeConverter;
import com.sun.jsftemplating.util.UIComponentTypeConversion;
import com.sun.jsftemplating.util.fileStreamer.Context;
import com.sun.jsftemplating.util.fileStreamer.FacesStreamerContext;
import com.sun.jsftemplating.util.fileStreamer.FileStreamer;
// FIXME: Things to consider:
// FIXME: - What is necessary to support Portlets...
// FIXME: - Should I attempt to clean up old unused UIComponents?
// FIXME: - f:view supported setting locale, I should too...
/**
* This class provides a custom ViewHandler
that is able to
* create and populate a UIViewRoot
from a
* {@link LayoutDefinition}. This is often defined by an XML document,
* the default implementation's DTD is defined in
* layout.dtd
.
*
* Besides the default ViewHandler
behavior, this class is
* responsible for using the given viewId
as the
* {@link LayoutDefinition} key and setting it on the UIViewRoot that is
* created. It will obtain the {@link LayoutDefinition}, initialize the
* declared {@link Resource}s, and instantiate UIComponent
* tree using the {@link LayoutDefinition}'s declared
* {@link LayoutComponent} structure. During rendering, it delegates to
* the {@link LayoutDefinition}.
*
* @author Ken Paulsen ([email protected])
*/
public class LayoutViewHandler extends ViewHandler {
/**
* Constructor.
*
* @param oldViewHandler The old ViewHandler
.
*/
public LayoutViewHandler(ViewHandler oldViewHandler) {
_oldViewHandler = oldViewHandler;
// FIXME: Fire an initializtion event, work out how to listen for this event
// This is added here to ensure that if the ViewHandler is reloaded in
// a running application, that handlers, ct's, and resources will get
// re-read. Ryan added a feature which may introduce this code path.
LayoutDefinitionManager.clearGlobalComponentTypes(null);
LayoutDefinitionManager.clearGlobalHandlerDefinitions(null);
LayoutDefinitionManager.clearGlobalResources(null);
}
/**
* Initialize the view for the request processing lifecycle. It is
* called at the beginning of the Restore View phase.
public void initView(FacesContext context) throws FacesException {
// Not used yet... I left this here as a reminder that it is here
}
*/
/**
* This method is invoked when restoreView does not yield a
* UIViewRoot
(initial requests and new pages).
*
* This implementation should work with both
* {@link LayoutDefinition}-based pages as well as traditional
* JSP pages (or other frameworks).
*/
public UIViewRoot createView(FacesContext context, String viewId) {
//_time = new java.util.Date();
// Check to see if this is a resource request
String path = getResourcePath(viewId);
if (path != null) {
// Serve Resource
return serveResource(context, path);
}
// Check to see if jsftemplating should create the view
if(!this.isMappedView(viewId)) {
UIViewRoot viewRoot = _oldViewHandler.createView(context, viewId);
return viewRoot;
}
Locale locale = null;
String renderKitId = null;
// use the locale from the previous view if is was one which will be
// the case if this is called from NavigationHandler. There wouldn't be
// one for the initial case.
if (context.getViewRoot() != null) {
UIViewRoot oldViewRoot = context.getViewRoot();
LayoutDefinition oldLD = ViewRootUtil.getLayoutDefinition(oldViewRoot);
if ((oldLD != null) && oldViewRoot.getViewId().equals(viewId)) {
// If you navigate to the page you are already on, JSF will
// re-create the UIViewRoot of the current page. The initPage
// event needs to be reset so that it will re-execute itself.
oldLD.setInitPageExecuted(context, Boolean.FALSE);
}
locale = context.getViewRoot().getLocale();
renderKitId = context.getViewRoot().getRenderKitId();
}
// Create the ViewRoot
UIViewRoot viewRoot = _oldViewHandler.createView(context, viewId);
viewRoot.setViewId(viewId);
ViewRootUtil.setLayoutDefinitionKey(viewRoot, viewId);
// if there was no locale from the previous view, calculate the locale
// for this view.
if (locale == null) {
locale = calculateLocale(context);
}
viewRoot.setLocale(locale);
// set the renderkit
if (renderKitId == null) {
renderKitId = calculateRenderKitId(context);
}
viewRoot.setRenderKitId(renderKitId);
// Save the current viewRoot, temporarily set the new UIViewRoot so
// beforeCreate, afterCreate will function correctly
UIViewRoot currentViewRoot = context.getViewRoot();
// Set the View Root to the new viewRoot
// NOTE: This must happen after return _oldViewHandler.createView(...)
// NOTE2: However, we really want the UIViewRoot available during
// initPage events which are fired during
// getLayoutDefinition()... so we need to set this, then unset
// it if we go through _oldViewHandler.createView(...)
context.setViewRoot(viewRoot);
// Initialize Resources / Create Tree
LayoutDefinition def = null;
try {
def = ViewRootUtil.getLayoutDefinition(viewRoot);
} catch (LayoutDefinitionException ex) {
if (LogUtil.configEnabled()) {
LogUtil.config("JSFT0005", (Object) viewId);
if (LogUtil.finestEnabled()) {
LogUtil.finest(
"File (" + viewId + ") not found!", ex);
}
}
// Restore original ViewRoot, we set it prematurely
if (currentViewRoot != null) {
// FIXME: Talk to Ryan about restoring the ViewRoot to null!!
context.setViewRoot(currentViewRoot);
}
// FIXME: Provide better feedback when no .jsf & no .jsp
// FIXME: Difficult to tell at this stage if no .jsp is present
// Not found, delegate to old ViewHandler
return _oldViewHandler.createView(context, viewId);
} catch (RuntimeException ex) {
// Restore original ViewRoot, we set it prematurely
if (currentViewRoot != null) {
// FIXME: Talk to Ryan about restoring the ViewRoot to null!!
context.setViewRoot(currentViewRoot);
}
// Allow error to be thrown (this isn't the normal code path)
throw ex;
}
// We need to do this again b/c an initPage handler may have changed
// the viewRoot
viewRoot = context.getViewRoot();
// Check to make sure we found a LD and that the response isn't
// already finished (initPage could complete the response...
// i.e. during a redirect).
if ((def != null) && !context.getResponseComplete()) {
// Ensure that our Resources are available
Iterator it = def.getResources().iterator();
Resource resource = null;
while (it.hasNext()) {
resource = it.next();
// Just calling getResource() puts it in the Request scope
resource.getFactory().getResource(context, resource);
}
// Get the Tree and pre-walk it
if (LayoutDefinitionManager.isDebug(context)) {
// Make sure to reset all the client ids we're about to check
getClientIdMap(context).clear();
}
buildUIComponentTree(context, viewRoot, def);
}
// Restore the current UIViewRoot
if (currentViewRoot != null) {
context.setViewRoot(currentViewRoot);
}
// Return the populated UIViewRoot
return viewRoot;
}
/**
* Tests if the provided viewId
matches one of the
* configured view-mappings. If no view-mappings are defined, all
* viewId
s will match.
*
* @param viewId The viewId to be tested.
*
* @return true If the viewId matched or no view-mappings are defined,
* false otherwise.
* @since 1.2
*/
private boolean isMappedView(String viewId) {
if (this._viewMappings == null) {
String initParam = (String) FacesContext.getCurrentInstance().
getExternalContext().getInitParameterMap().get(VIEW_MAPPINGS);
this._viewMappings = SimplePatternMatcher.
parseMultiPatternString(initParam, ";");
}
if (this._viewMappings.isEmpty()) {
return true;
}
for (SimplePatternMatcher mapping : this._viewMappings) {
if (mapping.matches(viewId)) {
return true;
}
}
return false;
}
/**
* If this is a resource request, this method will handle the
* request.
*/
public static UIViewRoot serveResource(FacesContext context, String path) {
// Mark the response complete so no more processing occurs
context.responseComplete();
// Create dummy UIViewRoot
UIViewRoot root = new UIViewRoot();
root.setRenderKitId("dummy");
// Setup the FacesStreamerContext
Context fsContext = new FacesStreamerContext(context);
fsContext.setAttribute(Context.FILE_PATH, path);
// Get the HttpServletResponse
Object obj = context.getExternalContext().getResponse();
HttpServletResponse resp = null;
if (obj instanceof HttpServletResponse) {
resp = (HttpServletResponse) obj;
// We have an HttpServlet response, do some extra stuff...
// Check the last modified time to see if we need to serve the resource
long mod = fsContext.getContentSource().getLastModified(fsContext);
if (mod != -1) {
long ifModifiedSince = ((HttpServletRequest)
context.getExternalContext().getRequest()).
getDateHeader("If-Modified-Since");
// Round down to the nearest second for a proper compare
if (ifModifiedSince < (mod / 1000 * 1000)) {
// A ifModifiedSince of -1 will always be less
resp.setDateHeader("Last-Modified", mod);
} else {
// Set not modified header and complete response
resp.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
return root;
}
}
}
// Stream the content
try {
FileStreamer.getFileStreamer(context).streamContent(fsContext);
} catch (FileNotFoundException ex) {
if (LogUtil.infoEnabled()) {
LogUtil.info("JSFT0004", (Object) path);
}
if (resp != null) {
try {
((HttpServletResponse) resp).sendError(
HttpServletResponse.SC_NOT_FOUND);
} catch (IOException ioEx) {
// Ignore
}
}
} catch (IOException ex) {
if (LogUtil.infoEnabled()) {
LogUtil.info("JSFT0004", (Object) path);
if (LogUtil.fineEnabled()) {
LogUtil.fine(
"Resource (" + path + ") not available!", ex);
}
}
// FIXME: send 404?
}
// Return dummy UIViewRoot to avoid NPE
return root;
}
/**
* Returns the current encoding type.
*
* @param ctx The FacesContext
.
*/
public static String getEncoding(FacesContext ctx) {
// Sanity check
if (ctx == null) {
return null;
}
String encType = null;
UIViewRoot root = ctx.getViewRoot();
Map map = PageSessionResolver.getPageSession(ctx, root);
if (map != null) {
//check for page session
encType = (String) map.get(ENCODING_TYPE);
}
if ((encType == null) || encType.equals("")) {
//check for application level
encType = ctx.getExternalContext().getInitParameter(ENCODING_TYPE);
}
if ((encType == null) || encType.equals("")) {
ExternalContext extCtx = ctx.getExternalContext();
try {
ServletRequest request = (ServletRequest) extCtx.getRequest();
encType = request.getCharacterEncoding();
} catch (Exception ex) {
// FIXME: Portlet?
}
if ((encType == null) || encType.equals("")) {
//default encoding type
encType="UTF-8";
}
}
return encType;
}
/**
* This method checks the given viewId and returns a the path to the
* requested resource if it refers to a resource. Resources are
* things like JavaScript files, images, etc. Basically anything that
* is not a JSF page that you'd like to serve up via the FacesServlet.
* Serving resources this way allows you to bundle the resources in a
* jar file, this is useful if you want to package up part of an app
* (or a JSF component) in a single file.
*
* A request for a resource must be prefixed by the resource prefix,
* see @{link #getResourcePrefixes}. This prefix must also be mapped to
* the FacesServlet
in order for this class to handle the
* request.
*/
public String getResourcePath(String viewId) {
ExternalContext extCtx = FacesContext.getCurrentInstance().getExternalContext();
// FIXME: Portlet!
String servletPath = extCtx.getRequestServletPath();
Iterator it = getResourcePrefixes().iterator();
while (it.hasNext()) {
if (servletPath.equals(it.next())) {
return extCtx.getRequestPathInfo();
}
}
return null;
}
/**
* This method returns the prefix that a URL must contain in order to
* retrieve a "resource" through this ViewHandler
.
*
* The prefix itself does not manifest itself in the file system /
* classpath.
*
* If the prefix is not set, then an init parameter (see
* {@link #RESOURCE_PREFIX}) will be checked. If that is still not
* specified, then the {@link #DEFAULT_RESOURCE_PREFIX} will be
* used.
*/
public Set getResourcePrefixes() {
if (_resourcePrefix == null) {
HashSet set = new HashSet();
// Check to see if it's specified by a context param
// Get context parameter map (initParams in JSF are context params)
String initParam = (String) FacesContext.getCurrentInstance().
getExternalContext().getInitParameterMap().get(RESOURCE_PREFIX);
if (initParam != null) {
for(String token: initParam.split(",")) {
set.add(token.trim());
}
}
// Add default...
set.add(DEFAULT_RESOURCE_PREFIX);
_resourcePrefix = set;
}
return _resourcePrefix;
}
/**
* This method allows a user to set the resource prefix which will be
* checked to obtain a resource via this Viewhandler
.
* Currently, only 1 prefix is supported. The prefix itself does not
* manifest itself in the file system / classpath.
*/
public void setResourcePrefixes(Set prefix) {
_resourcePrefix = prefix;
}
/**
* This method iterates over the child {@link LayoutElement}s of the
* given elt
to create UIComponent
s for each
* {@link LayoutComponent}.
*
* @param context The FacesContext
.
* @param parent The parent UIComponent
of the
* UIComponent
to be found or created.
* @param elt The LayoutElement
driving everything.
*/
public static void buildUIComponentTree(FacesContext context, UIComponent parent, LayoutElement elt) {
// FIXME: Consider processing *ALL* LayoutElements so that and others
// FIXME: have meaning when inside other components.
Iterator it = elt.getChildLayoutElements().iterator();
LayoutElement childElt;
UIComponent child = null;
while (it.hasNext()) {
childElt = it.next();
if (childElt instanceof LayoutFacet) {
if (!((LayoutFacet) childElt).isRendered()) {
// The contents of this should be a single UIComponent
buildUIComponentTree(context, parent, childElt);
}
// NOTE: LayoutFacets that aren't JSF facets aren't
// NOTE: meaningful in this context
} else if (childElt instanceof LayoutComposition) {
LayoutComposition compo = ((LayoutComposition) childElt);
String template = compo.getTemplate();
if (template != null) {
// Add LayoutComposition to the stack
LayoutComposition.push(context, childElt);
try {
// Add the template here.
buildUIComponentTree(context, parent, LayoutDefinitionManager.getLayoutDefinition(
context, template));
} catch (LayoutDefinitionException ex) {
if (((LayoutComposition) childElt).isRequired()) {
throw ex;
}
}
// Remove the LayoutComposition from the stack
LayoutComposition.pop(context);
} else {
// In this case we don't have a template, so instead we
// render the body
buildUIComponentTree(context, parent, childElt);
}
} else if (childElt instanceof LayoutInsert) {
Stack stack =
LayoutComposition.getCompositionStack(context);
if (stack.empty()) {
// No template-client found...
// Is this supposed to do nothing? Or throw an exception?
throw new IllegalArgumentException(
"'ui:insert' encountered, however, no "
+ "'ui:composition' was used!");
}
// Get associated UIComposition
String insertName = ((LayoutInsert) childElt).getName();
if (insertName == null) {
// include everything
buildUIComponentTree(context, parent, stack.get(0));
} else {
// First resolve any EL in the insertName
insertName = "" + ((LayoutInsert) childElt).resolveValue(
context, parent, insertName);
// Search for specific LayoutDefine
LayoutElement def = LayoutInsert.findLayoutDefine(
context, parent, stack, insertName);
if (def == null) {
// Not found include the body-content of the insert
buildUIComponentTree(context, parent, childElt);
} else {
// Found, include the ui:define content
buildUIComponentTree(context, parent, def);
}
}
} else if (childElt instanceof LayoutComponent) {
// Calling getChild will add the child UIComponent to tree
child = ((LayoutComponent) childElt).
getChild(context, parent);
if (LayoutDefinitionManager.isDebug(context)) {
// To help developer avoid duplicate ids, we'll check the
// ids here.
Map idMap = getClientIdMap(context);
String id = child.getClientId(context);
if (idMap.containsKey(id)) {
throw new IllegalArgumentException("The clientId ("
+ id + ") appears more than once! Make sure you "
+ "have not included multiple times in the same "
+ "NamingContainer.");
}
idMap.put(id, id);
}
// Check for events
// NOTE: For now I am only supporting "action" and
// NOTE: "actionListener" event types. In the future it
// NOTE: may be desirable to support beforeEncode /
// NOTE: afterEncode as well. At this time, those events
// NOTE: are supported by the "Event" UIComponent. That
// NOTE: component can wrap non-layout-based components to
// NOTE: achieve this functionality (supporting that
// NOTE: functionality here will simply do the same thing
// NOTE: automatically).
// Recurse
buildUIComponentTree(context, child, childElt);
} else {
buildUIComponentTree(context, parent, childElt);
}
}
}
/**
* This method provides access to a Map
of clientIds
* that have been used in this page.
*/
private static Map getClientIdMap(FacesContext context) {
Map reqMap =
context.getExternalContext().getRequestMap();
Map idMap = (Map)
reqMap.get("__debugIdMap");
if (idMap == null) {
idMap = new HashMap();
reqMap.put("__debugIdMap", idMap);
}
return idMap;
}
/**
* This implementation relies on the default behavior to reconstruct
* the UIViewRoot.
*
* ...
*/
public UIViewRoot restoreView(FacesContext context, String viewId) {
//_time = new java.util.Date();
Map map = context.getExternalContext().getRequestMap();
if (map.get(RESTORE_VIEW_ID) == null) {
map.put(RESTORE_VIEW_ID, viewId);
} else {
// This request has already been processed, it must be a forward()
return createView(context, viewId);
}
// Perform default behavior...
UIViewRoot root = _oldViewHandler.restoreView(context, viewId);
// We can check for JSFT UIViewRoots by calling
// getLayoutDefinitionKey(root) as this will return null if not JSFT
if (root != null) {
String key = ViewRootUtil.getLayoutDefinitionKey(root);
if (key != null) {
// Set the View Root to the new viewRoot (needed for initPage)
// NOTE: See createView note about saving / restoring the
// NOTE: original UIViewRoot and issue with setting it to
// NOTE: (null). restoreView is less important b/c it is not
// NOTE: normally called by a developer or framework as
// NOTE: navigation rules will call createView. For this
// NOTE: reason, I am not resetting the UIViewRoot for now.
context.setViewRoot(root);
// Call getLayoutDefinition() to ensure initPage events are
// fired, only do this for JSFT ViewRoots. Its good to call
// this after restoreView as we need the UIViewRoot available
// during initPage events. Formerly this was done during the
// ApplyRequestValuesPhase, however, I no longer have a custom
// UIViewRoot to use for this purpose, so I will do it here,
// which should be just as good.
LayoutDefinition def = ViewRootUtil.getLayoutDefinition(key);
// While we're at it, we should call the LD decode() event so
// we can provide a page-level decode() functionality. This
// won't effect components in the page, or JSFT-based
// components.
def.decode(context, root);
}
}
// Return the UIViewRoot
return root;
}
/**
*
*/
public void renderView(FacesContext context, UIViewRoot viewToRender) throws IOException {
// Make sure we have a def
LayoutDefinition def = ViewRootUtil.getLayoutDefinition(viewToRender);
if (def == null) {
// PartialRequest or No def, fall back to default behavior
_oldViewHandler.renderView(context, viewToRender);
} else {
// Start document
if (!context.getPartialViewContext().isPartialRequest() || context.getPartialViewContext().isRenderAll()) {
ResponseWriter writer = setupResponseWriter(context);
writer.startDocument();
// Render content
def.encode(context, viewToRender);
// End document
writer.endDocument();
} else {
// NOTE: This "if" branch has been added to avoid the
// NOTE: start/endDocument calls being called 2x on PartialView
// NOTE: requests. JSF Issue #1307 has been filed to resolve
// NOTE: this correctly (assuming checking here is not
// NOTE: correct... which I do not feel that it is).
//
// Render content
def.encode(context, viewToRender);
}
}
//System.out.println("PROCESSING TIME: " + (new java.util.Date().getTime() - _time.getTime()));
}
private static void renderComponent(FacesContext context, UIComponent comp) throws IOException {
if (!comp.isRendered()) {
return;
}
comp.encodeBegin(context);
if (comp.getRendersChildren()) {
comp.encodeChildren(context);
} else {
UIComponent child = null;
Iterator it = comp.getChildren().iterator();
while (it.hasNext()) {
child = it.next();
renderComponent(context, child);
}
}
comp.encodeEnd(context);
}
/**
*
*/
private ResponseWriter setupResponseWriter(FacesContext context) throws IOException {
ResponseWriter writer = context.getResponseWriter();
if (writer != null) {
// It is already setup
return writer;
}
ExternalContext extCtx = context.getExternalContext();
// FIXME: Portlet?
ServletResponse response = (ServletResponse) extCtx.getResponse();
RenderKitFactory renderFactory = (RenderKitFactory)
FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
RenderKit renderKit =
renderFactory.getRenderKit(context,
context.getViewRoot().getRenderKitId());
// See if the user (page author) specified a ContentType...
String contentTypeList = null;
// FIXME: Provide a way for the user to specify this...
// FIXME: Test multiple browsers against this code!!
String userContentType = "text/html";
if((userContentType != null) && (userContentType.length() > 0)) {
// User picked this, use it...
response.setContentType(userContentType);
}
else {
// No explicit Content-type, find best match...
contentTypeList = (String) extCtx.getRequestHeaderMap().get("Accept");
if (contentTypeList == null) {
contentTypeList = "text/html;q=1.0";
}
}
String encType = getEncoding(context);
// Object encValue = extCtx.getSessionMap().get(
// ViewHandler.CHARACTER_ENCODING_KEY);
extCtx.getSessionMap().put(ViewHandler.CHARACTER_ENCODING_KEY,
encType);
// FIXME: use the external context to set the character encoding, it is supported
response.setCharacterEncoding(encType);
// FIXME: Portlet?
writer =
renderKit.createResponseWriter(
new OutputStreamWriter(response.getOutputStream(), encType),
contentTypeList, encType);
context.setResponseWriter(writer);
// Not setting the contentType here results in XHTML which formats differently
// than text/html in Mozilla.. even though the documentation claims this
// works, it doesn't (try viewing the Tree)
// response.setContentType("text/html");
// As far as I can tell JSF doesn't ever set the Content-type that it
// works so hard to calculate... This is the code we should be
// calling, however we can't do this yet
response.setContentType(writer.getContentType());
return writer;
}
/**
* Take any appropriate action to either immediately write out the
* current state information (by calling
* StateManager.writeState
, or noting where state
* information should later be written.
*
* @param context FacesContext
for the current request
*
* @exception IOException if an input/output error occurs
*/
public void writeState(FacesContext context) throws IOException {
// Check to see if we should delegate back to the legacy ViewHandler
UIViewRoot root = context.getViewRoot();
// FIXME: For now I am treating "@all" Ajax requests as normal requests...
// FIXME: Otherwise the view state is not written.
if ((root == null) || (context.getPartialViewContext().isPartialRequest() && !context.getPartialViewContext().isRenderAll())
|| (ViewRootUtil.getLayoutDefinition(root) == null)) {
// Use old behavior...
_oldViewHandler.writeState(context);
} else {
// b/c we pre-processed the ViewTree, we can just add it...
StateManager stateManager =
context.getApplication().getStateManager();
SerializedView view = stateManager.saveSerializedView(context);
// New versions of JSF 1.2 changed the contract so that state is
// always written (client and server state saving)
stateManager.writeState(context, view);
}
}
/**
* Return a URL suitable for rendering (after optional encoding
* performed by the encodeResourceURL()
method of
* ExternalContext that selects the specified web
* application resource. If the specified path starts with a slash,
* it must be treated as context relative; otherwise, it must be
* treated as relative to the action URL of the current view.
*
* @param context FacesContext
for the current request
* @param path Resource path to convert to a URL
*
* @exception IllegalArgumentException If viewId
is not
* valid for this ViewHandler
.
*/
public String getResourceURL(FacesContext context, String path) {
return _oldViewHandler.getResourceURL(context, path);
}
/**
* Return a URL suitable for rendering (after optional encoding
* performed by the encodeActionURL()
method of
* ExternalContext
that selects the specified view
* identifier.
*
* @param context FacesContext
for this request
* @param viewId View identifier of the desired view
*
* @exception IllegalArgumentException If viewId
is not
* valid for this ViewHandler
.
*/
public String getActionURL(FacesContext context, String viewId) {
return _oldViewHandler.getActionURL(context, viewId);
}
/**
* Returns an appropriate Locale
to use for this and
* subsequent requests for the current client.
*
* @param context FacesContext
for the current request
*
* @exception NullPointerException if context
is
* null
*/
public Locale calculateLocale(FacesContext context) {
return _oldViewHandler.calculateLocale(context);
}
/**
* Return an appropriate renderKitId
for this
* and subsequent requests from the current client.
*
* The default return value is
* javax.faces.render.RenderKitFactory.HTML_BASIC_RENDER_KIT
.
*
*
* @param context FacesContext
for the current request.
*/
public String calculateRenderKitId(FacesContext context) {
return _oldViewHandler.calculateRenderKitId(context);
}
/**
* This is the key that may be used to identify the clientId of the
* UIComponent that is to be updated via an Ajax request.
*/
public static final String AJAX_REQ_KEY = "ajaxReq";
public static final String RESTORE_VIEW_ID = "_resViewID";
/**
* This is the default prefix that must be included on all requests
* for resources.
*/
public static final String DEFAULT_RESOURCE_PREFIX = "/resource";
/**
* The name of the context-param
to set the resource
* prefix.
*/
public static final String RESOURCE_PREFIX =
"com.sun.jsftemplating.RESOURCE_PREFIX";
private Set _resourcePrefix = null;
//private transient java.util.Date _time = null;
private ViewHandler _oldViewHandler = null;
static final String AJAX_REQ_TARGET_KEY = "_ajaxReqTarget";
/**
* The name of the context-param
to set the view mappings
*/
// TODO: should these keys be added to a new Class f.e. com.sun.jsftemplating.Keys?
private static final String VIEW_MAPPINGS =
"com.sun.jsftemplating.VIEW_MAPPINGS";
/**
*
*/
private static final TypeConversion UICOMPONENT_TYPE_CONVERSION =
new UIComponentTypeConversion();
/*
* This is intended to initialize additional type conversions
* for the {@link TypeConverter}. These additional type conversions
* are typically specific to JSF or JSFTemplating. If you are
* reading this and want additional custom type conversions, bug
* Ken Paulsen to add an init event which will allow you to easily
* initialize your own type conversions.
*/
static {
// Add type conversions by class
TypeConverter.registerTypeConversion(null, UIComponent.class, UICOMPONENT_TYPE_CONVERSION);
// Add type conversions by class name
TypeConverter.registerTypeConversion(null, UIComponent.class.getName(), UICOMPONENT_TYPE_CONVERSION);
}
private Collection _viewMappings = null;
/**
* This key can be used to override the encoding type used in your
* application.
*/
public static final String ENCODING_TYPE="com.sun.jsftemplating.ENCODING";
}