/* | |
* 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 org.apache.myfaces.test.mock; | |
import java.io.ByteArrayInputStream; | |
import java.io.ByteArrayOutputStream; | |
import java.io.IOException; | |
import java.io.ObjectInputStream; | |
import java.io.ObjectOutputStream; | |
import javax.faces.FacesException; | |
import javax.faces.application.StateManager.SerializedView; | |
import javax.faces.context.FacesContext; | |
import javax.faces.context.ResponseWriter; | |
import javax.faces.render.RenderKitFactory; | |
import javax.faces.render.ResponseStateManager; | |
/** | |
* Mock class that encode view state in hex format | |
* | |
* @author Leonardo Uribe | |
* @since 1.0.0 | |
* | |
*/ | |
public class MockResponseStateManager extends ResponseStateManager | |
{ | |
// ------------------------------------------------------------ Constructors | |
// ------------------------------------------------------ Instance Variables | |
private static final int TREE_PARAM = 0; | |
private static final int STATE_PARAM = 1; | |
private static final int VIEWID_PARAM = 2; | |
private static final String ZIP_CHARSET = "ISO-8859-1"; | |
// ----------------------------------------------------- Mock Object Methods | |
// -------------------------------------------------- ResponseStateManager Methods | |
public Object getState(FacesContext facesContext, String viewId) | |
{ | |
Object[] savedState = getSavedState(facesContext); | |
if (savedState == null) | |
{ | |
return null; | |
} | |
return new Object[] { savedState[TREE_PARAM], savedState[STATE_PARAM] }; | |
} | |
public Object getTreeStructureToRestore(FacesContext facesContext, | |
String viewId) | |
{ | |
// Although this method won't be called anymore, | |
// it has been kept for backward compatibility. | |
Object[] savedState = getSavedState(facesContext); | |
if (savedState == null) | |
{ | |
return null; | |
} | |
return savedState[TREE_PARAM]; | |
} | |
public Object getComponentStateToRestore(FacesContext facesContext) | |
{ | |
// Although this method won't be called anymore, | |
// it has been kept for backward compatibility. | |
Object[] savedState = getSavedState(facesContext); | |
if (savedState == null) | |
{ | |
return null; | |
} | |
return savedState[STATE_PARAM]; | |
} | |
public boolean isPostback(FacesContext context) | |
{ | |
return context.getExternalContext().getRequestParameterMap() | |
.containsKey(ResponseStateManager.VIEW_STATE_PARAM); | |
} | |
public void writeState(FacesContext facescontext, | |
SerializedView serializedview) throws IOException | |
{ | |
ResponseWriter responseWriter = facescontext.getResponseWriter(); | |
Object[] savedState = new Object[3]; | |
if (facescontext.getApplication().getStateManager() | |
.isSavingStateInClient(facescontext)) | |
{ | |
Object treeStruct = serializedview.getStructure(); | |
Object compStates = serializedview.getState(); | |
if (treeStruct != null) | |
{ | |
savedState[TREE_PARAM] = treeStruct; | |
} | |
if (compStates != null) | |
{ | |
savedState[STATE_PARAM] = compStates; | |
} | |
} | |
else | |
{ | |
// write viewSequence | |
Object treeStruct = serializedview.getStructure(); | |
if (treeStruct != null) | |
{ | |
if (treeStruct instanceof String) | |
{ | |
savedState[TREE_PARAM] = treeStruct; | |
} | |
} | |
} | |
savedState[VIEWID_PARAM] = facescontext.getViewRoot().getViewId(); | |
// write the view state field | |
writeViewStateField(facescontext, responseWriter, savedState); | |
// renderKitId field | |
writeRenderKitIdField(facescontext, responseWriter); | |
} | |
private void writeViewStateField(FacesContext facesContext, | |
ResponseWriter responseWriter, Object savedState) | |
throws IOException | |
{ | |
String serializedState = construct(facesContext, savedState); | |
responseWriter.startElement("input", null); | |
responseWriter.writeAttribute("type", "hidden", null); | |
responseWriter.writeAttribute("name", VIEW_STATE_PARAM, null); | |
responseWriter.writeAttribute("value", serializedState, null); | |
responseWriter.endElement("input"); | |
} | |
private void writeRenderKitIdField(FacesContext facesContext, | |
ResponseWriter responseWriter) throws IOException | |
{ | |
String defaultRenderKitId = facesContext.getApplication() | |
.getDefaultRenderKitId(); | |
if (defaultRenderKitId != null | |
&& !RenderKitFactory.HTML_BASIC_RENDER_KIT | |
.equals(defaultRenderKitId)) | |
{ | |
responseWriter.startElement("input", null); | |
responseWriter.writeAttribute("type", "hidden", null); | |
responseWriter.writeAttribute("name", | |
ResponseStateManager.RENDER_KIT_ID_PARAM, null); | |
responseWriter.writeAttribute("value", defaultRenderKitId, null); | |
responseWriter.endElement("input"); | |
} | |
} | |
private String construct(FacesContext facesContext, Object savedState) | |
throws IOException | |
{ | |
byte[] bytes = null; | |
ByteArrayOutputStream baos = null; | |
ObjectOutputStream oos = null; | |
try | |
{ | |
baos = new ByteArrayOutputStream(); | |
oos = new ObjectOutputStream(baos); | |
oos.writeObject(savedState); | |
bytes = baos.toByteArray(); | |
} | |
finally | |
{ | |
if (oos != null) | |
{ | |
try | |
{ | |
oos.close(); | |
} | |
catch (IOException e) | |
{ | |
} | |
finally | |
{ | |
oos = null; | |
} | |
} | |
if (baos != null) | |
{ | |
try | |
{ | |
baos.close(); | |
} | |
catch (IOException e) | |
{ | |
} | |
finally | |
{ | |
baos = null; | |
} | |
} | |
} | |
return new String(new _Hex().encode(bytes), ZIP_CHARSET); | |
} | |
private Object reconstruct(FacesContext facesContext, String encodedState) | |
throws IOException | |
{ | |
byte[] bytes = encodedState.getBytes(ZIP_CHARSET); | |
try | |
{ | |
bytes = new _Hex().decode(bytes); | |
} | |
catch(Exception e) | |
{ | |
throw new IOException(e.getMessage()); | |
} | |
ByteArrayInputStream input = null; | |
ObjectInputStream s = null; | |
Object object = null; | |
try | |
{ | |
input = new ByteArrayInputStream(bytes); | |
s = new ObjectInputStream(input); | |
object = s.readObject(); | |
} | |
catch (ClassNotFoundException e) | |
{ | |
throw new IOException(e.getMessage()); | |
} | |
finally | |
{ | |
if (s != null) | |
{ | |
try | |
{ | |
s.close(); | |
} | |
catch (IOException e) | |
{ | |
} | |
finally | |
{ | |
s = null; | |
} | |
} | |
if (input != null) | |
{ | |
try | |
{ | |
input.close(); | |
} | |
catch (IOException e) | |
{ | |
} | |
finally | |
{ | |
input = null; | |
} | |
} | |
} | |
return object; | |
} | |
private Object[] getSavedState(FacesContext facesContext) | |
{ | |
Object encodedState = facesContext.getExternalContext() | |
.getRequestParameterMap().get(VIEW_STATE_PARAM); | |
if (encodedState == null || (((String) encodedState).length() == 0)) | |
{ | |
return null; | |
} | |
Object[] savedState = null; | |
try | |
{ | |
savedState = (Object[]) reconstruct(facesContext, | |
(String) encodedState); | |
} | |
catch (IOException e) | |
{ | |
facesContext.getExternalContext().log( | |
"Cannot reconstruct view state", e); | |
} | |
if (savedState == null) | |
{ | |
return null; | |
} | |
String restoredViewId = (String) savedState[VIEWID_PARAM]; | |
if (restoredViewId == null) | |
{ | |
return null; | |
} | |
return savedState; | |
} | |
public String getViewState(FacesContext facesContext, Object state) | |
{ | |
if (state == null) | |
{ | |
return null; | |
} | |
Object treeStruct = null; | |
Object compStates = null; | |
if (state instanceof SerializedView) | |
{ | |
SerializedView view = (SerializedView) state; | |
treeStruct = view.getStructure(); | |
compStates = view.getState(); | |
} | |
else if (state instanceof Object[]) | |
{ | |
Object[] structureAndState = (Object[]) state; | |
if (structureAndState.length == 2) | |
{ | |
treeStruct = structureAndState[0]; | |
compStates = structureAndState[1]; | |
} | |
else | |
{ | |
throw new FacesException( | |
"The state should be an array of Object[] of lenght 2"); | |
} | |
} | |
else | |
{ | |
throw new FacesException( | |
"The state should be an array of Object[] of lenght 2, or a SerializedView instance"); | |
} | |
Object[] savedState = new Object[3]; | |
if (facesContext.getApplication().getStateManager() | |
.isSavingStateInClient(facesContext)) | |
{ | |
if (treeStruct != null) | |
{ | |
savedState[TREE_PARAM] = treeStruct; | |
} | |
if (compStates != null) | |
{ | |
savedState[STATE_PARAM] = compStates; | |
} | |
} | |
else | |
{ | |
// write viewSequence | |
if (treeStruct != null) | |
{ | |
if (treeStruct instanceof String) | |
{ | |
savedState[TREE_PARAM] = treeStruct; | |
} | |
} | |
} | |
savedState[VIEWID_PARAM] = facesContext.getViewRoot().getViewId(); | |
try | |
{ | |
return construct(facesContext, savedState); | |
} | |
catch (IOException e) | |
{ | |
throw new RuntimeException(e); | |
} | |
} | |
} |