/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
package javax.faces.application;
import javax.faces.component.
NamingContainer;
import javax.faces.component.
UIViewRoot;
import javax.faces.context.
FacesContext;
import javax.faces.context.
ResponseWriter;
import javax.faces.render.
RenderKit;
import javax.faces.render.
ResponseStateManager;
import java.io.
IOException;
/**
* <p>
* <strong class="changed_modified_2_0 changed_modified_2_1 changed_modified_2_2">StateManager</strong>
* directs the process of saving and
* restoring the view between requests. <span class="changed_added_2_0">An
* implementation
* of this class must be thread-safe.</span> The {@link StateManager}
* instance for an application is retrieved from the {@link Application}
* instance, and thus cannot know any details of the markup language
* created by the {@link RenderKit} being used to render a view. The
* {@link StateManager} utilizes a helper object ({@link
* ResponseStateManager}), that is provided by the {@link RenderKit}
* implementation and is therefore aware of the markup language
* details.</p>
*/
public abstract class
StateManager {
// ------------------------------------------------------ Manifest Constants
/**
* <p>The <code>ServletContext</code> init parameter consulted by
* the <code>StateManager</code> to tell where the state should be
* saved. Valid values are given as the values of the constants:
* {@link #STATE_SAVING_METHOD_CLIENT} or {@link
* #STATE_SAVING_METHOD_SERVER}.</p>
* <p/>
* <p>If this parameter is not specified, the default value is the
* value of the constant {@link #STATE_SAVING_METHOD_CLIENT}. </p>
*/
public static final
String STATE_SAVING_METHOD_PARAM_NAME =
"javax.faces.STATE_SAVING_METHOD";
/**
* <p class="changed_added_2_0">The <code>ServletContext</code> init
* parameter consulted by the runtime to determine if the partial
* state saving mechanism should be used.</p>
* <div class="changed_added_2_0">
* <p>If undefined, the runtime must determine the version level of
* the application.</p>
*
* <ul>
* <li><p>For applications versioned at 1.2 and under, the runtime
* must not use the partial state saving mechanism.</li><p>
* <li><p>For applications versioned at 2.0 and above, the runtime
* must use the partial state saving mechanism.</p></li>
* </ul>
* <p>If this parameter is defined, and the application is versioned
* at 1.2 and under, the runtime must not use the partial state
* saving mechanism. Otherwise, If this param is defined, and
* calling <code>toLowerCase().equals("true")</code> on a
* <code>String</code> representation of its value returns
* <code>true</code>, the runtime must use partial state mechanism.
* Otherwise the partial state saving mechanism must not be
* used.</p>
* </div>
*
* @since 2.0
*/
public static final
String PARTIAL_STATE_SAVING_PARAM_NAME =
"javax.faces.PARTIAL_STATE_SAVING";
/**
* <p class="changed_added_2_0">The runtime must interpret the value
* of this parameter as a comma separated list of view IDs, each of
* which must have their state saved using the state saving
* mechanism specified in JSF 1.2.</p>
*/
public static final
String FULL_STATE_SAVING_VIEW_IDS_PARAM_NAME =
"javax.faces.FULL_STATE_SAVING_VIEW_IDS";
/**
* <p class="changed_added_2_1">Marker within the
* <code>FacesContext</code> attributes map to indicate we are
* saving state. The implementation must set this marker into the
* map <b>before</b> starting the state saving traversal and the marker
* must be cleared, in a finally block, <b>after</b> the traversal is
* complete.</p>
*/
public static final
String IS_SAVING_STATE =
"javax.faces.IS_SAVING_STATE";
/**
* <p class="changed_added_2_1">Marker within the
* <code>FacesContext</code> attributes map to indicate we are
* marking initial state, so the <code>markInitialState()</code>
* method of iterating components such as {@link
* javax.faces.component.UIData} could recognize this fact and save
* the initial state of descendents.</p>
* @since 2.1
*/
public final static
String IS_BUILDING_INITIAL_STATE =
"javax.faces.IS_BUILDING_INITIAL_STATE";
/**
* <p class="changed_added_2_2">
* If this param is set, and calling toLowerCase().equals("true") on a
* String representation of its value returns true, and the
* javax.faces.STATE_SAVING_METHOD is set to "server" (as indicated
* below), the server state must be guaranteed to be Serializable such
* that the aggregate state implements java.io.Serializable. The intent
* of this parameter is to ensure that the act of writing out the state
* to an ObjectOutputStream would not throw a NotSerializableException,
* but the runtime is not required verify this before saving the state.
* </p>
*
* @since 2.2
*/
public static final
String SERIALIZE_SERVER_STATE_PARAM_NAME =
"javax.faces.SERIALIZE_SERVER_STATE";
/**
* <p>Constant value for the initialization parameter named by
* the <code>STATE_SAVING_METHOD_PARAM_NAME</code> that indicates
* state saving should take place on the client.</p>
*/
public static final
String STATE_SAVING_METHOD_CLIENT = "client";
/**
* <p>Constant value for the initialization parameter named by
* the <code>STATE_SAVING_METHOD_PARAM_NAME</code> that indicates
* state saving should take place on the server.</p>
*/
public static final
String STATE_SAVING_METHOD_SERVER = "server";
// ---------------------------------------------------- State Saving Methods
private static final
String IS_CALLED_FROM_API_CLASS =
"javax.faces.ensureOverriddenInvocation";
/**
* <p>Return the tree structure and component state information for the
* view contained in the specified {@link FacesContext} instance as an
* object of type <code>StateManager.SerializedView</code>. If there
* is no state information to be saved, return <code>null</code>
* instead.</p>
* <p/>
* <p>Components may opt out of being included in the serialized view
* by setting their <code>transient</code> property to <code>true</code>.
* This must cause the component itself, as well as all of that component's
* children and facets, to be omitted from the saved tree structure
* and component state information.</p>
* <p/>
* <p>This method must also enforce the rule that, for components with
* non-null <code>id</code>s, all components that are descendants of the
* same nearest {@link NamingContainer} must have unique identifiers.</p>
*
* @param context {@link FacesContext} for the current request
*
* @throws IllegalStateException if more than one component or
* facet within the same {@link NamingContainer} in this view has
* the same non-<code>null</code> component id
* @deprecated this has been replaced by {@link #saveView}. The
* default implementation calls <code>saveView</code> and inspects the
* return. If the return is an <code>Object []</code>, it casts the
* result to an <code>Object []</code> wrapping the first and second
* elements in an instance of {@link SerializedView}, which it then
* returns. Otherwise, it returns <code>null</code>
*/
public
SerializedView saveSerializedView(
FacesContext context) {
context.
getAttributes().
put(
IS_CALLED_FROM_API_CLASS,
Boolean.
TRUE);
Object stateObj = null;
try {
stateObj =
saveView(
context);
} finally {
context.
getAttributes().
remove(
IS_CALLED_FROM_API_CLASS);
}
SerializedView result = null;
if (null !=
stateObj) {
if (
stateObj instanceof
Object[]) {
Object []
state = (
Object[])
stateObj;
if (
state.length == 2) {
result = new
SerializedView(
state[0],
state[1]);
}
}
}
return
result;
}
/**
* <p><span class="changed_deleted_2_2">The functionality of this method
* is now handled by {@link javax.faces.view.StateManagementStrategy#saveView}.
* </span> Return an opaque <code>Object</code> containing sufficient
* information for this same instance to restore the state of the
* current {@link UIViewRoot} on a subsequent request. The returned
* object must implement <code>java.io.Serializable</code>. If there
* is no state information to be saved, return <code>null</code>
* instead.</p>
* <p/>
* <p>Components may opt out of being included in the serialized view
* by setting their <code>transient</code> property to <code>true</code>.
* This must cause the component itself, as well as all of that component's
* children and facets, to be omitted from the saved tree structure
* and component state information.</p>
* <p/>
* <p>This method must also enforce the rule that, for components with
* non-null <code>id</code>s, all components that are descendants of the
* same nearest {@link NamingContainer} must have unique identifiers.</p>
* <p/>
* <p>For backwards compatability with existing
* <code>StateManager</code> implementations, the default
* implementation of this method calls {@link #saveSerializedView}
* and creates and returns a two element <code>Object</code> array
* with element zero containing the <code>structure</code> property
* and element one containing the <code>state</code> property of the
* <code>SerializedView</code>.</p>
*
* @param context {@link FacesContext} for the current request
*
* @throws IllegalStateException if more than one component or
* facet within the same {@link NamingContainer} in this view has
* the same non-<code>null</code> component id
* @since 1.2
*/
@
Deprecated
public
Object saveView(
FacesContext context) {
Object stateArray[] = null;
if (!
context.
getAttributes().
containsKey(
IS_CALLED_FROM_API_CLASS)) {
SerializedView view =
saveSerializedView(
context);
if (null !=
view) {
stateArray = new
Object[]{
view.
getStructure(),
view.
getState()};
}
}
return
stateArray;
}
/**
* <p>Convenience method, which must be called by
* <code>saveSerializedView()</code>, to construct and return a
* <code>Serializable</code> object that represents the structure
* of the entire component tree (including children and facets)
* of this view.</p>
* <p/>
* <p>Components may opt-out of being included in the tree structure
* by setting their <code>transient</code> property to <code>true</code>.
* This must cause the component itself, as well as all of that component's
* children and facets, to be omitted from the saved tree structure
* information.</p>
*
* @param context {@link FacesContext} for the current request
*
* @deprecated the distinction between tree structure and component
* state is now an implementation detail. The default
* implementation returns <code>null</code>.
*/
protected
Object getTreeStructureToSave(
FacesContext context) {
return null;
}
/**
* <p>Convenience method, which must be called by
* <code>saveSerializedView()</code>, to construct and return a
* <code>Serializable</code> object that represents the state of
* all component properties, attributes, and attached objects, for
* the entire component tree (including children and facets)
* of this view.</p>
* <p/>
* <p>Components may opt-out of being included in the component state
* by setting their <code>transient</code> property to <code>true</code>.
* This must cause the component itself, as well as all of that component's
* children and facets, to be omitted from the saved component state
* information.</p>
*
* @param context {@link FacesContext} for the current request
*
* @deprecated the distinction between tree structure and component
* state is now an implementation detail. The default
* implementation returns <code>null</code>.
*/
protected
Object getComponentStateToSave(
FacesContext context) {
return null;
}
/**
* <p>Save the state represented in the specified state
* <code>Object</code> instance, in an implementation dependent
* manner.</p>
* <p/>
* <p>This method will typically simply delegate the actual
* writing to the <code>writeState()</code> method of the
* {@link ResponseStateManager} instance provided by the
* {@link RenderKit} being used to render this view. This
* method assumes that the caller has positioned the
* {@link ResponseWriter} at the correct position for the
* saved state to be written.</p>
* <p/>
* <p>For backwards compatability with existing
* <code>StateManager</code> implementations, the default
* implementation of this method checks if the argument is an
* instance of <code>Object []</code> of length greater than or
* equal to two. If so, it creates a <code>SerializedView</code>
* instance with the tree structure coming from element zero and
* the component state coming from element one and calls through to
* {@link
* #writeState(javax.faces.context.FacesContext,javax.faces.application.StateManager.SerializedView)}.
* If not, does nothing.</p>
*
* @param context {@link FacesContext} for the current request
* @param state the Serializable state to be written,
* as returned by {@link #saveSerializedView}
*
* @since 1.2
*/
public void
writeState(
FacesContext context,
Object state)
throws
IOException {
if (null !=
state &&
state.
getClass().
isArray() &&
state.
getClass().
getComponentType().
equals(
Object.class)) {
Object stateArray[] = (
Object[])
state;
if (2 ==
stateArray.length) {
SerializedView view = new
SerializedView(
stateArray[0],
stateArray[1]);
writeState(
context,
view);
}
}
}
/**
* <p>Save the state represented in the specified
* <code>SerializedView</code> isntance, in an implementation
* dependent manner.</p>
* <p/>
* <p>This method must consult the context initialization parameter
* named by the symbolic constant
* <code>StateManager.STATE_SAVING_METHOD_PARAM_NAME</code>
* to determine whether state should be saved on the client or the
* server. If not present, client side state saving is assumed.</p>
* <p/>
* <p>If the init parameter indicates that client side state
* saving should be used, this method must delegate the actual
* writing to the <code>writeState()</code> method of the
* {@link ResponseStateManager} instance provided by the
* {@link RenderKit} being used to render this view. This
* method assumes that the caller has positioned the
* {@link ResponseWriter} at the correct position for the
* saved state to be written.</p>
*
* @param context {@link FacesContext} for the current request
* @param state the serialized state to be written
*
* @deprecated This method has been replaced by {@link
* #writeState(javax.faces.context.FacesContext,java.lang.Object)}.
* The default implementation calls the non-deprecated variant
* of the method passing an <code>Object []</code> as the second
* argument, where the first element of the array is the return from
* <code>getStructure()</code> and the second is the return from
* <code>getState()</code> on the argument <code>state</code>.
*
*/
public void
writeState(
FacesContext context,
SerializedView state) throws
IOException {
if (
state != null) {
writeState(
context, new
Object[]{
state.
getStructure(),
state.
getState()});
}
}
// ------------------------------------------------- State Restoring Methods
/**
* <p><span class="changed_deleted_2_2">The functionality of this method
* is now handled by {@link javax.faces.view.StateManagementStrategy#restoreView}.
* </span> Restore the tree structure and the component state of the view
* for the specified <code>viewId</code>, in an implementation dependent
* manner, and return the restored {@link UIViewRoot}. If there is no
* saved state information available for this <code>viewId</code>,
* return <code>null</code> instead.</p>
* <p/>
* <p>This method must consult the context initialization parameter
* named by the symbolic constant
* <code>StateManager.STATE_SAVING_METHOD_PARAM_NAME</code>
* to determine whether state should be saved on the client or the
* server. If not present, client side state saving is assumed.</p>
* <p/>
* <p>If the init parameter indicates that client side state
* saving should be used, this method must call the
* <code>getTreeStructureToRestore()</code> and (if the previous method
* call returned a non-null value) <code>getComponentStateToRestore()</code>
* methods of the {@link ResponseStateManager} instance provided by the
* {@link RenderKit} responsible for this view.</p>
*
* @param context {@link FacesContext} for the current request
* @param viewId View identifier of the view to be restored
* @param renderKitId the renderKitId used to render this response.
* Must not be <code>null</code>.
*
* @throws IllegalArgumentException if <code>renderKitId</code>
* is <code>null</code>.
*/
@
Deprecated
public abstract
UIViewRoot restoreView(
FacesContext context,
String viewId,
String renderKitId);
/**
* <p>Convenience method, which must be called by
* <code>restoreView()</code>, to construct and return a {@link UIViewRoot}
* instance (populated with children and facets) representing the
* tree structure of the component tree being restored. If no saved
* state information is available, return <code>null</code> instead.</p>
*
* @param context {@link FacesContext} for the current request
* @param viewId View identifier of the view to be restored
* @param renderKitId the renderKitId used to render this response.
* Must not be <code>null</code>.
*
* @throws IllegalArgumentException if <code>renderKitId</code>
* is <code>null</code>.
* @deprecated the distinction between tree structure and component
* state is now an implementation detail. The default
* implementation returns <code>null</code>.
*/
protected
UIViewRoot restoreTreeStructure(
FacesContext context,
String viewId,
String renderKitId) {
return null;
}
/**
* <p>Convenience method, which must be called by
* <code>restoreView()</code>, to restore the attributes, properties,
* and attached objects of all components in the restored component tree.
* </p>
*
* @param context {@link FacesContext} for the current request
* @param viewRoot {@link UIViewRoot} returned by a previous call
* to <code>restoreTreeStructure()</code>
* @param renderKitId the renderKitId used to render this response.
* Must not be <code>null</code>.
*
* @throws IllegalArgumentException if <code>renderKitId</code>
* is <code>null</code>.
* @deprecated the distinction between tree structure and component
* state is now an implementation detail. The default
* implementation does nothing.
*/
protected void
restoreComponentState(
FacesContext context,
UIViewRoot viewRoot,
String renderKitId) {
}
private
Boolean savingStateInClient = null;
/**
* @return <code>true</code> if and only if the value of the
* <code>ServletContext</code> init parameter named by the value of
* the constant {@link #STATE_SAVING_METHOD_PARAM_NAME} is equal to
* the value of the constant {@link #STATE_SAVING_METHOD_CLIENT}.
* <code>false</code> otherwise.
*
* @throws NullPointerException if <code>context</code> is
* <code>null</code>.
*/
public boolean
isSavingStateInClient(
FacesContext context) {
if (null !=
savingStateInClient) {
return
savingStateInClient.
booleanValue();
}
savingStateInClient =
Boolean.
FALSE;
String saveStateParam =
context.
getExternalContext().
getInitParameter(
STATE_SAVING_METHOD_PARAM_NAME);
if (
saveStateParam != null &&
saveStateParam.
equalsIgnoreCase(
STATE_SAVING_METHOD_CLIENT)) {
savingStateInClient =
Boolean.
TRUE;
}
return
savingStateInClient.
booleanValue();
}
/**
* <p>Convenience struct for encapsulating tree structure and
* component state. This is necessary to allow the API to be
* flexible enough to work in JSP and non-JSP environments.</p>
*
* @deprecated This class was not marked <code>Serializable</code>
* in the 1.0 version of the spec. It was also not a static inner
* class, so it can't be made to be <code>Serializable</code>.
* Therefore, it is being deprecated in version 1.2 of the spec.
* The replacement is to use an implementation dependent
* <code>Object</code>.
*/
public class
SerializedView extends
Object {
private
Object structure = null;
private
Object state = null;
public
SerializedView(
Object newStructure,
Object newState) {
structure =
newStructure;
state =
newState;
}
public
Object getStructure() {
return
structure;
}
public
Object getState() {
return
state;
}
}
/**
* <p class="changed_added_2_0">
* Convenience method to return the view state as a <code>String</code> with
* no <code>RenderKit</code> specific markup.
*
* This default implementation of this method will call {@link #saveView(javax.faces.context.FacesContext)}
* and passing the result to and returning the resulting value from
* {@link ResponseStateManager#getViewState(javax.faces.context.FacesContext, Object)}.
* </p>
*
* @param context {@link FacesContext} for the current request
*
* @since 2.0
*/
public
String getViewState(
FacesContext context) {
Object state =
saveView(
context);
return
context.
getRenderKit().
getResponseStateManager().
getViewState(
context,
state);
}
}