blob: 85dfbf4cad8214c66e0a10df2baa751125c84a3c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package javax.faces.application;
import javax.faces.FacesException;
import javax.faces.context.ExternalContext;
import org.apache.myfaces.buildtools.maven2.plugin.builder.annotation.JSFWebConfigParam;
import java.io.UnsupportedEncodingException;
import java.util.Locale;
/**
* A ViewHandler manages the component-tree-creation and component-tree-rendering parts
* of a request lifecycle (ie "create view", "restore view" and "render response").
* <p>
* A ViewHandler is responsible for generating the component tree when a new view is
* requested; see method "createView".
* <p>
* When the user performs a "postback", ie activates a UICommand component within a view,
* then the ViewHandler is responsible for recreating a view tree identical to the one
* used previously to render that view; see method "restoreView".
* <p>
* And the ViewHandler is also responsible for rendering the final output to be sent to the
* user by invoking the rendering methods on components; see method "renderView".
* <p>
* This class also isolates callers from the underlying request/response system. In particular,
* this class does not explicitly depend upon the javax.servlet apis. This allows JSF to be
* used on servers that do not implement the servlet API (for example, plain CGI).
* <p>
* Examples:
* <ul>
* <li>A JSP ViewHandler exists for using "jsp" pages as the presentation technology.
* This class then works together with a taghandler class and a jsp servlet class to
* implement the methods on this abstract class definition.
* <li>A Facelets ViewHandler instead uses an xml file to define the components and
* non-component data that make up a specific view.
* </ul>
* Of course there is no reason why the "template" needs to be a textual file. A view could
* be generated based on data in a database, or many other mechanisms.
* <p>
* This class is expected to be invoked via the concrete implementation of
* {@link javax.faces.lifecycle.Lifecycle}.
* <p>
* For the official specification for this class, see
* <a href="http://java.sun.com/javaee/javaserverfaces/1.2/docs/api/index.html">JSF Specification</a>.
*
* @author Manfred Geiler (latest modification by $Author$)
* @version $Revision$ $Date$
*/
public abstract class ViewHandler
{
public static final String CHARACTER_ENCODING_KEY = "javax.faces.request.charset";
/**
* Indicate the default suffix to derive the file URI if extension mapping is used.
*/
@JSFWebConfigParam(defaultValue=".jsp", since="1.1")
public static final String DEFAULT_SUFFIX_PARAM_NAME = "javax.faces.DEFAULT_SUFFIX";
public static final String DEFAULT_SUFFIX = ".jsp";
/**
* @since JSF 1.2
*/
public String calculateCharacterEncoding(javax.faces.context.FacesContext context)
{
String _encoding = null;
ExternalContext externalContext = context.getExternalContext();
String _contentType = (String) externalContext.getRequestHeaderMap().get("Content-Type");
int _indexOf = _contentType == null ? -1 :_contentType.indexOf("charset");
if(_indexOf != -1)
{
String _tempEnc =_contentType.substring(_indexOf); //charset=UTF-8
_encoding = _tempEnc.substring(_tempEnc.indexOf("=")+1); //UTF-8
if (_encoding.length() == 0)
{
_encoding = null;
}
}
if (_encoding == null)
{
boolean _sessionAvailable = externalContext.getSession(false) != null;
if(_sessionAvailable)
{
Object _sessionParam = externalContext.getSessionMap().get(CHARACTER_ENCODING_KEY);
if (_sessionParam != null)
{
_encoding = _sessionParam.toString();
}
}
}
return _encoding;
}
/**
* Return the Locale object that should be used when rendering this view to the
* current user.
* <p>
* Some request protocols allow an application user to specify what locale they prefer
* the response to be in. For example, HTTP requests can specify the "accept-language"
* header.
* <p>
* Method {@link javax.faces.application.Application#getSupportedLocales()} defines
* what locales this JSF application is capable of supporting.
* <p>
* This method should match such sources of data up and return the Locale object that
* is the best choice for rendering the current application to the current user.
*/
public abstract Locale calculateLocale(javax.faces.context.FacesContext context);
/**
* Return the id of an available render-kit that should be used to map the JSF
* components into user presentation.
* <p>
* The render-kit selected (eg html, xhtml, pdf, xul, ...) may depend upon the user,
* properties associated with the request, etc.
*/
public abstract String calculateRenderKitId(javax.faces.context.FacesContext context);
/**
* Build a root node for a component tree.
* <p>
* When a request is received, this method is called if restoreView returns null,
* ie this is not a "postback". In this case, a root node is created and then renderView
* is invoked. It is the responsibility of the renderView method to build the full
* component tree (ie populate the UIViewRoot with descendant nodes).
* <p>
* This method is also invoked when navigation occurs from one view to another, where
* the viewId passed is the id of the new view to be displayed. Again it is the responsibility
* of renderView to then populate the viewroot with descendants.
* <p>
* The locale and renderKit settings are inherited from the current UIViewRoot that is
* configured before this method is called. That means of course that they do NOT
* get set for GET requests, including navigation that has the redirect flag set.
*/
public abstract javax.faces.component.UIViewRoot createView(javax.faces.context.FacesContext context,
String viewId);
/**
* Return a URL that a remote system can invoke in order to access the specified view.
* <p>
* Note that the URL a user enters and the viewId which is invoked can be
* different. The simplest difference is a change in suffix (eg url "foo.jsf"
* references view "foo.jsp").
*/
public abstract String getActionURL(javax.faces.context.FacesContext context,
String viewId);
/**
* Return a URL that a remote system can invoke in order to access the specified resource.
* <p>
* When path starts with a slash, it is relative to the webapp root. Otherwise it is
* relative to the value returned by getActionURL.
*/
public abstract String getResourceURL(javax.faces.context.FacesContext context,
String path);
/**
* Method must be called by the JSF impl at the beginning of Phase <i>Restore View</i> of the JSF
* lifecycle.
*
* @since JSF 1.2
*/
public void initView(javax.faces.context.FacesContext context) throws FacesException
{
String _encoding = this.calculateCharacterEncoding(context);
if(_encoding != null)
{
try
{
context.getExternalContext().setRequestCharacterEncoding(_encoding);
}
catch(UnsupportedEncodingException uee)
{
throw new FacesException(uee);
}
}
}
/**
* Combine the output of all the components in the viewToRender with data from the
* original view template (if any) and write the result to context.externalContext.response.
* <p>
* Component output is generated by invoking the encodeBegin, encodeChildren (optional)
* and encodeEnd methods on relevant components in the specified view. How this is
* interleaved with the non-component content of the view template (if any) is left
* to the ViewHandler implementation.
* <p>
* The actual type of the Response object depends upon the concrete implementation of
* this class. It will almost certainly be an OutputStream of some sort, but may be
* specific to the particular request/response system in use.
* <p>
* If the view cannot be rendered (eg due to an error in a component) then a FacesException
* is thrown.
* <p>
* Note that if a "postback" has occurred but no navigation to a different view, then
* the viewToRender will be fully populated with components already. However on direct
* access to a new view, or when navigation has occurred, the viewToRender will just
* contain an empty UIViewRoot object that must be populated with components from
* the "view template".
*/
public abstract void renderView(javax.faces.context.FacesContext context,
javax.faces.component.UIViewRoot viewToRender)
throws java.io.IOException,
FacesException;
/**
* Handle a "postback" request by recreating the component tree that was most recently
* presented to the user for the specified view.
* <p>
* When the user performs a "postback" of a view that has previously been created, ie
* is updating the state of an existing view tree, then the view handler must recreate
* a view tree identical to the one used previously to render that view to the user,
* so that the data received from the user can be compared to the old state and the
* correct "changes" detected (well, actually only those components that respond to
* input are actually needed before the render phase).
* <p>
* The components in this tree will then be given the opportunity to examine new input
* data provided by the user, and react in the appropriate manner for that component,
* as specified for the JSF lifecycle.
* <p>
* Much of the work required by this method <i>must</i> be delegated to an instance
* of StateManager.
* <p>
* If there is no record of the current user having been sent the specified view
* (ie no saved state information available), then NULL should be returned.
* <p>
* Note that input data provided by the user may also be used to determine exactly
* how to restore this view. In the case of "client side state", information
* about the components to be restored will be available here. Even for
* "server side state", user input may include an indicator that is used to
* select among a number of different saved states available for this viewId and
* this user.
* <p>
* Note that data received from users is inherently untrustworthy; care should be
* taken to validate this information appropriately.
* <p>
* See writeState for more details.
*/
public abstract javax.faces.component.UIViewRoot restoreView(javax.faces.context.FacesContext context,
String viewId);
/**
* Write sufficient information to context.externalContext.response in order to
* be able to restore this view if the user performs a "postback" using that
* rendered response.
* <p>
* For "client side state saving", sufficient information about the view
* state should be written to allow a "restore view" operation to succeed
* later. This does not necessarily mean storing <i>all</i> data about the
* current view; only data that cannot be recreated from the "template" for
* this view needs to be saved.
* <p>
* For "server side state saving", this method may write out nothing. Alternately
* it may write out a "state identifier" to identify which of multiple saved
* user states for a particular view should be selected (or just verify that the
* saved state does indeed correspond to the expected one).
*/
public abstract void writeState(javax.faces.context.FacesContext context)
throws java.io.IOException;
}