/*
* OpenFaces - JSF Component Library 2.0
* Copyright (C) 2007-2012, TeamDev Ltd.
* licensing@openfaces.org
* Unless agreed in writing the contents of this file are subject to
* the GNU Lesser General Public License Version 2.1 (the "LGPL" License).
* This library is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* Please visit http://openfaces.org/licensing/ for more details.
*/
package org.openfaces.ajax;
import org.openfaces.ajax.plugins.AjaxPluginIncludes;
import org.openfaces.ajax.plugins.PluginsLoader;
import org.openfaces.component.OUIObjectIterator;
import org.openfaces.component.ajax.AjaxSettings;
import org.openfaces.component.ajax.DefaultSessionExpiration;
import org.openfaces.component.ajax.SilentSessionExpiration;
import org.openfaces.component.util.AjaxLoadBundleComponent;
import org.openfaces.org.json.JSONException;
import org.openfaces.org.json.JSONObject;
import org.openfaces.renderkit.AjaxPortionRenderer;
import org.openfaces.util.*;
import javax.faces.FacesException;
import javax.faces.FactoryFinder;
import javax.faces.application.StateManager;
import javax.faces.component.UIComponent;
import javax.faces.component.UIData;
import javax.faces.component.UIForm;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.event.AbortProcessingException;
import javax.faces.event.FacesEvent;
import javax.faces.event.PhaseId;
import javax.faces.render.RenderKit;
import javax.faces.render.RenderKitFactory;
import javax.faces.render.Renderer;
import javax.faces.render.ResponseStateManager;
import javax.portlet.ActionRequest;
import javax.portlet.RenderRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @author Eugene Goncharov
*/
public abstract class CommonAjaxViewRoot {
private static final String APPLICATION_SESSION_EXPIRATION_PARAM_NAME = "org.openfaces.ajax.sessionExpiration";
private static final String SILENT_SESSION_EXPIRATION_HANDLING = "silent";
private static final String DEFAULT_SESSION_EXPIRATION_HANDLING = "default";
private static final String PARAM_EXECUTE = "_of_execute";
public static final String PARAM_EXECUTE_RENDERED_COMPONENTS = "_of_executeRenderedComponents";
// a copy of org.apache.myfaces.shared_impl.renderkit.RendererUtils.SEQUENCE_PARAM
private static final String MYFACES_SEQUENCE_PARAM = "jsf_sequence";
public static final long MAX_PORTLET_PARALLEL_REQUEST_TIMEOUT = 20 * 1000;
private static final String VALUE_ATTR_STRING = "value=\"";
private static long tempIdCounter = 0;
private static final Pattern JS_VAR_PATTERN = Pattern.compile("\\bvar\\b");
private UIViewRoot viewRoot;
private List<FacesEvent> events;
protected CommonAjaxViewRoot(UIViewRoot viewRoot) {
this.viewRoot = viewRoot;
}
protected abstract void parentProcessDecodes(FacesContext context);
protected abstract void parentProcessValidators(FacesContext context);
protected abstract void parentProcessUpdates(FacesContext context);
protected abstract void parentProcessApplication(FacesContext context);
protected abstract void parentEncodeChildren(FacesContext context) throws IOException;
protected abstract int parentGetChildCount();
protected abstract List<UIComponent> parentGetChildren();
protected abstract Iterator<UIComponent> parentGetFacetsAndChildren();
public void processDecodes(FacesContext context, boolean specialSessionExpirationHandling) {
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
if (!AjaxUtil.isAjaxRequest(context) ||
(specialSessionExpirationHandling && requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING))) {
parentProcessDecodes(context);
return;
}
try {
// The try-catch block is required to handle errors and exceptions
// during the processing of the ajax request.
//
// The handling of errors and exceptions is done on each phase of JSF request life-cycle
// If the exception is caught here, the appropriate message is sent back to the client
// in ajax response
doProcessDecodes(context, this);
broadcastEvents(context, PhaseId.APPLY_REQUEST_VALUES);
} catch (RuntimeException e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
} catch (Error e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
}
}
public void processValidators(FacesContext context, boolean specialSessionExpirationHandling) {
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
if (!AjaxUtil.isAjaxRequest(context)
|| (specialSessionExpirationHandling && requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING))) {
parentProcessValidators(context);
return;
}
try {
// The try-catch block is required to handle errors and exceptions
// during the processing of the ajax request.
//
// The handling of errors and exceptions is done on each phase of JSF request life-cycle
// If the exception is caught here, the appropriate message is sent back to the client
// in ajax response
AjaxRequest.getInstance().resetValidationError();
doProcessValidators(context);
broadcastEvents(context, PhaseId.PROCESS_VALIDATIONS);
} catch (RuntimeException e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
} catch (Error e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
}
}
public void processUpdates(FacesContext context, boolean specialSessionExpirationHandling) {
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
if (!AjaxUtil.isAjaxRequest(context) ||
(specialSessionExpirationHandling && requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING))) {
parentProcessUpdates(context);
return;
}
try {
// The try-catch block is required to handle errors and exceptions
// during the processing of the ajax request.
//
// The handling of errors and exceptions is done on each phase of JSF request life-cycle
// If the exception is caught here, the appropriate message is sent back to the client
// in ajax response
AjaxRequest.getInstance().setValidationError(false);
doProcessUpdates(context);
broadcastEvents(context, PhaseId.UPDATE_MODEL_VALUES);
} catch (RuntimeException e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
} catch (Error e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
}
}
public void processApplication(FacesContext context, boolean specialSessionExpirationHandling) {
ExternalContext externalContext = context.getExternalContext();
Map<String, Object> requestMap = externalContext.getRequestMap();
if (!AjaxUtil.isAjaxRequest(context)
|| (specialSessionExpirationHandling && requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING))) {
parentProcessApplication(context);
RequestFacade request = RequestFacade.getInstance(externalContext.getRequest());
UtilPhaseListener.processAjaxExecutePhase(context, request, viewRoot);
return;
}
try {
// The try-catch block is required to handle errors and exceptions
// during the processing of the ajax request.
//
// The handling of errors and exceptions is done on each phase of JSF request life-cycle
// If the exception is caught here, the appropriate message is sent back to the client
// in ajax response
doProcessApplication(context);
broadcastEvents(context, PhaseId.INVOKE_APPLICATION);
} catch (RuntimeException e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
} catch (Error e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
}
}
public void encodeChildren(FacesContext context) throws IOException {
if (!AjaxUtil.isAjaxRequest(context)) {
parentEncodeChildren(context);
return;
}
try {
// The try-catch block is required to handle errors and exceptions
// during the processing of the ajax request.
//
// The handling of errors and exceptions is done on each phase of JSF request life-cycle
// If the exception is caught here, the appropriate message is sent back to the client
// in ajax response
doEncodeChildren(context);
} catch (RuntimeException e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
} catch (Error e) {
processExceptionDuringAjax(context, e);
if (e.getMessage() != null) {
Log.log(context, e.getMessage(), e);
}
}
}
private void doProcessDecodes(FacesContext context, Object objectInstanceForSynchronizeOn) {
ExternalContext externalContext = context.getExternalContext();
RequestFacade request = RequestFacade.getInstance(externalContext.getRequest());
Map<String, Object> requestMap = externalContext.getRequestMap();
if (requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING)) {
return;
}
ResponseFacade response = ResponseFacade.getInstance(externalContext.getResponse());
String componentId = request.getParameter(AjaxUtil.PARAM_RENDER);
String[] render = extractRender(request);
String[] execute = extractExecute(request);
boolean executeRenderedComponents = extractExecuteRenderedComponents(request);
if (response instanceof ResponseFacade.ActionResponseFacade || response instanceof ResponseFacade.ResourceResponseFacade) {
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
boolean shouldWaitForPreviousAjaxCompletion = true;
long timeBefore = System.currentTimeMillis();
do {
synchronized (objectInstanceForSynchronizeOn) {
long timeElapsed = System.currentTimeMillis() - timeBefore;
if (timeElapsed > MAX_PORTLET_PARALLEL_REQUEST_TIMEOUT) {
Log.log(context, "CommonAjaxViewRoot.doProcessDecodes: waiting for parallel ajax request timed out");
sessionMap.remove(AjaxUtil.AJAX_REQUEST_MARKER);
}
if (sessionMap.get(AjaxUtil.AJAX_REQUEST_MARKER) == null) {
sessionMap.put(AjaxUtil.AJAX_REQUEST_MARKER, request.getParameter(AjaxUtil.AJAX_REQUEST_MARKER));
sessionMap.put(AjaxUtil.PARAM_RENDER, componentId);
sessionMap.put(AjaxUtil.UPDATE_PORTIONS_SUFFIX, request.getParameter(AjaxUtil.UPDATE_PORTIONS_SUFFIX));
sessionMap.put(AjaxUtil.CUSTOM_JSON_PARAM, request.getParameter(AjaxUtil.CUSTOM_JSON_PARAM));
shouldWaitForPreviousAjaxCompletion = false;
} else
try {
Thread.sleep(50);
} catch (InterruptedException e) {
// previous ajax request completion should be waited for anyway...
}
}
} while (shouldWaitForPreviousAjaxCompletion);
}
UIViewRoot viewRoot = context.getViewRoot();
assertChildren(viewRoot);
UIComponent[] components = locateComponents(render, viewRoot, true, false);
if (!extractSkipExecute(request))
ajaxApplyRequestValues(context, components, viewRoot, execute, executeRenderedComponents);
if (Boolean.valueOf(request.getParameter(UtilPhaseListener.PARAM_IMMEDIATE))) {
doProcessApplication(context);
}
}
private void doProcessValidators(FacesContext context) {
ExternalContext externalContext = context.getExternalContext();
RequestFacade request = RequestFacade.getInstance(externalContext.getRequest());
Map<String, Object> requestMap = externalContext.getRequestMap();
if (requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING)) {
return;
}
String[] render = extractRender(request);
String[] execute = extractExecute(request);
boolean executeRenderedComponents = extractExecuteRenderedComponents(request);
UIViewRoot viewRoot = context.getViewRoot();
assertChildren(viewRoot);
UIComponent[] components = locateComponents(render, viewRoot, false, false);
if (!extractSkipExecute(request))
ajaxProcessValidations(context, components, viewRoot, execute, executeRenderedComponents);
}
private void doProcessUpdates(FacesContext context) {
ExternalContext externalContext = context.getExternalContext();
RequestFacade request = RequestFacade.getInstance(externalContext.getRequest());
Map<String, Object> requestMap = externalContext.getRequestMap();
if (requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING)) {
return;
}
String[] render = extractRender(request);
String[] execute = extractExecute(request);
boolean executeRenderedComponents = extractExecuteRenderedComponents(request);
UIViewRoot viewRoot = context.getViewRoot();
assertChildren(viewRoot);
UIComponent[] components = locateComponents(render, viewRoot, false, false);
if (!extractSkipExecute(request))
ajaxUpdateModelValues(context, components, viewRoot, execute, executeRenderedComponents);
}
private UIComponent[] locateComponents(String[] render, UIViewRoot viewRoot,
boolean preProcessDecodesOnTables,
boolean preRenderResponseOnTables) {
if (render == null) return new UIComponent[0];
UIComponent[] components = new UIComponent[render.length];
for (int i = 0; i < render.length; i++) {
String componentId = render[i];
components[i] = findComponentById(viewRoot, componentId, preProcessDecodesOnTables, preRenderResponseOnTables);
}
return components;
}
/**
* The "skip execute" parameter (which commands to skip all "execute" phases) is used by some partial Ajax requests
* to ensure that no components are being saved to the backing bean and only the required data is saved (e.g. during
* the automatic column resizing state saving with Ajax, where nothing except the resizing state itself should be
* saved during the Ajax request)
*/
private boolean extractSkipExecute(RequestFacade request) {
String value = request.getParameter("_of_skipExecute");
return "true".equals(value);
}
private boolean extractExecuteRenderedComponents(RequestFacade request) {
String value = request.getParameter(PARAM_EXECUTE_RENDERED_COMPONENTS);
return Rendering.isNullOrEmpty(value) || value.equalsIgnoreCase("true");
}
private String[] extractRender(RequestFacade request) {
String componentIds = request.getParameter(AjaxUtil.PARAM_RENDER);
assertComponentId(componentIds);
String[] render = !Rendering.isNullOrEmpty(componentIds) ? componentIds.split(";") : null;
return render;
}
private String[] extractExecute(RequestFacade request) {
String idsStr = request.getParameter(PARAM_EXECUTE);
String[] execute = !Rendering.isNullOrEmpty(idsStr) ? idsStr.split(";") : null;
return execute;
}
private void doProcessApplication(FacesContext context) {
ExternalContext externalContext = context.getExternalContext();
RequestFacade request = RequestFacade.getInstance(externalContext.getRequest());
Map<String, Object> requestMap = externalContext.getRequestMap();
if (requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING)) {
return;
}
String[] render = extractRender(request);
UIViewRoot viewRoot = context.getViewRoot();
assertChildren(viewRoot);
String actionComponentId = UtilPhaseListener.processAjaxExecutePhase(context, request, viewRoot);
// invoke application should be after notification listeners
Log.log(context, "invoke listener finished");
UIComponent[] components = locateComponents(render, viewRoot, false, false);
if (actionComponentId != null) {
// todo: if component is an iterator its rowIndex should be reset so that the following id check succeed (JSFC-1974)
// [DPikhulya Oct-15] it's possible that after moving ajax from AjaxRequestsPhaseListener there are no additional
// actions are required for this check to succeed, because of the added findComponentByPath above.
}
for (int i = 0; i < components.length; i++) {
UIComponent component = components[i];
String thisComponentId = render[i];
Class clazz = null;
try {
clazz = Class.forName("com.sun.facelets.component.UIRepeat");
} catch (ClassNotFoundException e) {
//do nothing - it's ok - not facelets environment
}
if (!component.getClientId(context).equals(thisComponentId) &&
!(component instanceof UIData || component instanceof OUIObjectIterator || (clazz != null && clazz.isInstance(component))))
throw new IllegalStateException("component.getClientId [" + component.getClientId(context) + "] " +
"is supposed to be equal to componentId [" + thisComponentId + "]");
}
}
protected void assertChildren(UIViewRoot viewRoot) {
if (viewRoot.getChildCount() == 0) {
throw new IllegalStateException("View should have been already restored.");
}
}
private void doEncodeChildren(FacesContext context) throws IOException {
ExternalContext externalContext = context.getExternalContext();
RequestFacade request = RequestFacade.getInstance(externalContext.getRequest());
Map<String, Object> requestMap = externalContext.getRequestMap();
if (requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING)) {
handleSessionExpirationOnEncodeChildren(context, request);
releaseSyncObject(context);
return;
}
if (AjaxUtil.isPortletRequest(context)) {
renderPortletsAjaxResponse(context);
releaseSyncObject(context);
return;
}
String[] render = extractRender(request);
UIViewRoot viewRoot = context.getViewRoot();
assertChildren(viewRoot);
loadBundles(context);
UIComponent[] components = locateComponents(render, viewRoot, false, true);
Object originalResponse = externalContext.getResponse();
ResponseFacade response = ResponseFacade.getInstance(originalResponse);
Integer sequence = getSequenceIdForMyFaces(context);
finishProcessAjaxRequest(context, request, response, components, sequence);
releaseSyncObject(context);
}
/**
* @param componentId it to be verified
* @throws IllegalStateException if the passed component id is {@code null}
*/
private void assertComponentId(String componentId) {
if (componentId == null)
throw new IllegalStateException("processAjaxRequest: " + AjaxUtil.PARAM_RENDER + " is null");
}
private void handleSessionExpirationOnEncodeChildren(FacesContext context, RequestFacade request) throws IOException {
ExternalContext externalContext = context.getExternalContext();
Object originalResponse = externalContext.getResponse();
if (originalResponse instanceof HttpServletResponse) {
ResponseWrapper response = new ResponseWrapper((HttpServletResponse) originalResponse);
response.setHeader(AjaxViewHandler.AJAX_EXPIRED_HEADER, AjaxViewHandler.AJAX_VIEW_EXPIRED);
}
UIViewRoot viewRoot = context.getViewRoot();
List<UIComponent> children = viewRoot.getChildren();
AjaxSettings ajaxSettings = null;
String[] componentIds = extractRender(request);
Map<String, Object> requestMap = externalContext.getRequestMap();
assertChildren(viewRoot);
UIComponent component = componentIds != null && componentIds.length > 0 ? findComponentById(viewRoot, componentIds[0], false, false) : null;
if (component != null && component.getChildCount() > 0) {
List<UIComponent> ajaxSubmittedComponentChildren = component.getChildren();
ajaxSettings = findAjaxSettings(ajaxSubmittedComponentChildren);
}
if (ajaxSettings == null) {
ajaxSettings = findPageAjaxSettings(children);
}
if (ajaxSettings == null) {
Map initParameterMap = externalContext.getInitParameterMap();
String sessionExpirationHandling = (initParameterMap != null)
? (String) initParameterMap.get(APPLICATION_SESSION_EXPIRATION_PARAM_NAME)
: null;
if (sessionExpirationHandling != null && sessionExpirationHandling.length() > 0) {
if (sessionExpirationHandling.equalsIgnoreCase(SILENT_SESSION_EXPIRATION_HANDLING)) {
ajaxSettings = createSilentSessionExpirationSettings();
} else if (sessionExpirationHandling.equalsIgnoreCase(DEFAULT_SESSION_EXPIRATION_HANDLING)) {
ajaxSettings = createDefaultSessionExpirationSettings(context);
}
} else {
ajaxSettings = createDefaultSessionExpirationSettings(context);
}
}
if (ajaxSettings != null) {
boolean isNonPortletRequest = !AjaxUtil.isPortletRequest(context);
AbstractResponseFacade responseFacade =
finishSessionExpirationAjaxResponse(context, request, new UIComponent[]{ajaxSettings},
isNonPortletRequest);
String sessionExpiredResponse = null;
if (responseFacade.getOutputStream() != null) {
ByteArrayOutputStream byteArrayOutputStream = (ByteArrayOutputStream) responseFacade.getOutputStream();
sessionExpiredResponse = byteArrayOutputStream.toString("UTF-8");
} else if (responseFacade.getWriter() != null) {
sessionExpiredResponse = responseFacade.getWriter().toString();
}
if (sessionExpiredResponse != null) {
requestMap.put(AjaxViewHandler.SESSION_EXPIRED_RESPONSE, sessionExpiredResponse);
}
}
}
private static void releaseSyncObject(FacesContext context) {
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
// TODO [sanders] (Apr 1, 2009, 5:09 AM): Can't we synchronize on something shorter?.. :)
// TODO [sanders] (Apr 1, 2009, 5:09 AM): Won't java.util.concurrent help?
RequestsSyncObject syncObject = (RequestsSyncObject) sessionMap.get(AjaxViewHandler.SESSION_SYNCHRONIZATION);
if (syncObject == null) {
// can be the case during debugging when session expires during a long debugging session
return;
}
//noinspection SynchronizationOnLocalVariableOrMethodParameter
synchronized (syncObject) {
syncObject.setAjaxRequestProcessing(false);
syncObject.notifyAll();
}
}
private AjaxSettings findAjaxSettings(List<UIComponent> children) {
AjaxSettings result = null;
for (Object iteratedChild : children) {
if (iteratedChild instanceof AjaxSettings) {
result = (AjaxSettings) iteratedChild;
return result;
}
UIComponent uiComponent = (UIComponent) iteratedChild;
if (uiComponent.getChildCount() > 0) {
result = findAjaxSettings(uiComponent.getChildren());
if (result != null) {
return result;
}
}
}
return result;
}
private AjaxSettings findPageAjaxSettings(List<UIComponent> children) {
AjaxSettings result = null;
for (Object iteratedChild : children) {
if (iteratedChild instanceof AjaxSettings && isPageSettings((AjaxSettings) iteratedChild)) {
result = (AjaxSettings) iteratedChild;
return result;
}
UIComponent uiComponent = (UIComponent) iteratedChild;
if (uiComponent.getChildCount() > 0) {
result = findPageAjaxSettings(uiComponent.getChildren());
if (result != null) {
return result;
}
}
}
return result;
}
public static void processExceptionDuringAjax(FacesContext context, Throwable exception) {
try {
ExternalContext externalContext = context.getExternalContext();
Map<String, Object> requestMap = externalContext.getRequestMap();
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
if (AjaxUtil.isPortletRequest(context) && externalContext.getRequest() instanceof RenderRequest) {
try {
if (!Environment.isRI()) {
finishProccessErrorUnderPortletsDuringAjax(context, exception);
} else if (sessionMap.containsKey(AjaxViewHandler.ERROR_OCCURRED_UNDER_PORTLETS)) {
finishProccessErrorUnderPortletsDuringAjax(context, exception);
}
} catch (IOException e) {
Log.log(context, "An attempt to process exception during ajax failed.IOException was thrown during processing.");
}
} else if (!(sessionMap.containsKey(AjaxViewHandler.ERROR_OCCURRED_UNDER_PORTLETS))
&& AjaxUtil.isPortletRequest(context)
&& externalContext.getRequest() instanceof ActionRequest) {
sessionMap.put(AjaxViewHandler.ERROR_OCCURRED_UNDER_PORTLETS, Boolean.TRUE);
sessionMap.put(AjaxViewHandler.ERROR_OBJECT_UNDER_PORTLETS, exception);
}
if (!requestMap.containsKey(AjaxViewHandler.ERROR_OCCURRED)) {
requestMap.put(AjaxViewHandler.ERROR_OCCURRED, Boolean.TRUE.toString());
requestMap.put(AjaxViewHandler.ERROR_MESSAGE_HEADER, exception.getClass().getName() + ": " + exception.getMessage());
requestMap.put(AjaxViewHandler.ERROR_CAUSE_MESSAGE_HEADER, exception.getCause());
}
} finally {
releaseSyncObject(context);
}
}
private boolean isPageSettings(AjaxSettings ajaxSettings) {
return (ajaxSettings.getParent() instanceof UIViewRoot || ajaxSettings.getParent() instanceof UIForm);
}
private AjaxSettings createSilentSessionExpirationSettings() {
AjaxSettings result = new AjaxSettings();
result.setSessionExpiration(new SilentSessionExpiration());
return result;
}
private AjaxSettings createDefaultSessionExpirationSettings(FacesContext context) {
AjaxSettings result = new AjaxSettings();
DefaultSessionExpiration dse = new DefaultSessionExpiration();
result.setSessionExpiration(dse);
return result;
}
public int getChildCount() {
int childCount = parentGetChildCount();
UIViewRoot delegate = ((WrappedAjaxRoot) viewRoot).getDelegate();
if (childCount == 0 && delegate != null) {
childCount = delegate.getChildCount();
}
return childCount;
}
public List<UIComponent> getChildren() {
List<UIComponent> children = parentGetChildren();
UIViewRoot delegate = ((WrappedAjaxRoot) viewRoot).getDelegate();
if (children == null || children.isEmpty() && delegate != null) {
List<UIComponent> delegateChildren = delegate.getChildren();
if (children == null) {
children = new ArrayList<UIComponent>();
}
children.addAll(delegateChildren);
}
return children;
}
public Iterator<UIComponent> getFacetsAndChildren() {
Iterator<UIComponent> facetsAndChildren = parentGetFacetsAndChildren();
UIViewRoot delegate = ((WrappedAjaxRoot) viewRoot).getDelegate();
if (facetsAndChildren == null || !facetsAndChildren.hasNext() && delegate != null) {
facetsAndChildren = delegate.getFacetsAndChildren();
}
return facetsAndChildren;
}
/**
* Find all instances of {@link org.openfaces.component.util.LoadBundle} in view tree and load bundles
* to request-scope map.
*/
private void loadBundles(FacesContext context) {
loadBundles(context, context.getViewRoot());
}
/**
* Recursive helper for {@link #loadBundles(FacesContext)}
*/
private void loadBundles(FacesContext context, UIComponent component) {
// Iterate over children
for (UIComponent child : component.getChildren()) {
loadChildBundles(context, child);
}
// Iterate over facets
for (UIComponent child : component.getFacets().values()) {
loadChildBundles(context, child);
}
}
private void loadChildBundles(FacesContext context, UIComponent child) {
if (child instanceof AjaxLoadBundleComponent) {
try {
child.encodeBegin(context);
} catch (IOException e) {
Log.log(context, "Exception while invoking LoadBundle", e);
}
} else {
loadBundles(context, child);
}
}
private void ajaxApplyRequestValues(FacesContext context,
UIComponent[] render,
UIViewRoot viewRoot,
String[] execute,
boolean executeRenderedComponents)
throws FacesException {
if (render != null && executeRenderedComponents) {
for (UIComponent component : render) {
Log.log(context, "start ajaxApplyRequestValues for " + component);
component.processDecodes(context);
Log.log(context, "finish ajaxApplyRequestValues for " + component);
}
}
if (execute != null) {
for (String submittedComponentId : execute) {
UIComponent submittedComponent = findComponentById(viewRoot, submittedComponentId);
Log.log(context, "start ajaxApplyRequestValues for " + submittedComponent);
submittedComponent.processDecodes(context);
Log.log(context, "finish ajaxApplyRequestValues for " + submittedComponent);
}
}
}
private void ajaxProcessValidations(FacesContext context,
UIComponent[] render,
UIViewRoot viewRoot,
String[] execute,
boolean executeRenderedComponents) throws FacesException {
if (render != null && executeRenderedComponents) {
for (UIComponent component : render) {
Log.log(context, "start ajaxProcessValidations for " + component);
component.processValidators(context);
Log.log(context, "finish ajaxProcessValidations for " + component);
}
}
if (execute != null) {
for (String submittedComponentId : execute) {
UIComponent submittedComponent = findComponentById(viewRoot, submittedComponentId);
Log.log(context, "start ajaxProcessValidations for " + submittedComponent);
submittedComponent.processValidators(context);
Log.log(context, "finish ajaxProcessValidations for " + submittedComponent);
}
}
}
private void ajaxUpdateModelValues(FacesContext context,
UIComponent[] render,
UIViewRoot viewRoot,
String[] execute,
boolean executeRenderedComponents)
throws FacesException {
if (render != null && executeRenderedComponents) {
for (UIComponent component : render) {
Log.log(context, "start ajaxUpdateModelValues for " + component);
component.processUpdates(context);
Log.log(context, "finish ajaxUpdateModelValues for " + component);
}
}
if (execute != null) {
for (String submittedComponentId : execute) {
UIComponent submittedComponent = findComponentById(viewRoot, submittedComponentId);
Log.log(context, "start ajaxUpdateModelValues for " + submittedComponent);
submittedComponent.processUpdates(context);
Log.log(context, "finish ajaxUpdateModelValues for " + submittedComponent);
}
}
}
private void renderPortletsAjaxResponse(FacesContext context) {
if (!AjaxUtil.isAjaxRequest(context)) {
throw new IllegalStateException("This method should be only invoked for portlet Ajax requests");
}
if (!AjaxUtil.isPortletRequest(context)) {
throw new IllegalStateException("This method should be only invoked for portlet Ajax requests");
}
Integer sequenceId = (Environment.isLiferay(context.getExternalContext().getRequestMap()))
? getSequenceIdForMyFaces(context)
: null;
Map sessionMap = context.getExternalContext().getSessionMap();
String componentId = (String) sessionMap.get(AjaxUtil.PARAM_RENDER);
if (componentId == null) {
Log.log(context, "CommonAjaxViewRoot.renderPortletsAjaxResponse: " + AjaxUtil.PARAM_RENDER + " == null");
// Can happen sometimes on simultaneous ajax requests in Portlets.
// Seems that there's no better way to handle it in Portlets 1.0
return;
}
String[] render = componentId.split(";");
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
requestMap.put(AjaxUtil.KEY_RENDERING_PORTLETS_AJAX_RESPONSE, Boolean.TRUE);
try {
UIViewRoot viewRoot = context.getViewRoot();
assertChildren(viewRoot);
// clear the style ids set just constructed on the "render" phase in order to avoid warning of repeated style rendering
Styles.getRenderedStyleElementsIds(context).clear();
loadBundles(context);
UIComponent[] components = new UIComponent[render.length];
for (int i = 0; i < render.length; i++) {
String component = render[i];
UIComponent findComponent = findComponentById(viewRoot, component);
if (findComponent == null) {
throw new IllegalStateException("Couldn't find component by client id: " + component);
}
components[i] = findComponent;
}
ExternalContext externalContext = context.getExternalContext();
RequestFacade request = RequestFacade.getInstance(externalContext.getRequest());
ResponseFacade response = ResponseFacade.getInstance(externalContext.getResponse());
try {
finishProcessAjaxRequest(context, request, response, components, sequenceId);
} catch (IOException e) {
throw new FacesException(e);
}
} finally {
if (!requestMap.containsKey(AjaxViewHandler.SESSION_EXPIRATION_PROCESSING)) {
clearPortletSessionParams(context);
}
requestMap.remove(AjaxUtil.KEY_RENDERING_PORTLETS_AJAX_RESPONSE);
}
}
private static void clearPortletSessionParams(FacesContext context) {
Map<String, Object> sessionMap = context.getExternalContext().getSessionMap();
synchronized (CommonAjaxViewRoot.class) {
sessionMap.remove(AjaxUtil.PARAM_RENDER);
sessionMap.remove(AjaxUtil.UPDATE_PORTIONS_SUFFIX);
sessionMap.remove(AjaxUtil.CUSTOM_JSON_PARAM);
sessionMap.remove(AjaxUtil.AJAX_REQUEST_MARKER);
}
}
private void finishProcessAjaxRequest(
FacesContext context,
RequestFacade request,
ResponseFacade response,
UIComponent[] components,
Integer sequence) throws IOException {
AjaxResponse ajaxResponse = ajaxRenderResponse(request, context, components);
AjaxSavedStateIdxHolder stateIdxHolder = ajaxSaveState(context, request, ajaxResponse, components, sequence);
ajaxResponse.setStateIdxHolder(stateIdxHolder);
ajaxResponse.write(response);
}
private AbstractResponseFacade finishSessionExpirationAjaxResponse(FacesContext context,
RequestFacade request,
UIComponent[] components,
boolean nonPortletAjaxRequest) throws IOException {
AjaxResponse ajaxResponse = null;
if (!nonPortletAjaxRequest) {
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
requestMap.put(AjaxUtil.KEY_RENDERING_PORTLETS_AJAX_RESPONSE, Boolean.TRUE);
try {
// clear the style ids set just constructed on the "render" phase in order to avoid warning of repeated style rendering
Styles.getRenderedStyleElementsIds(context).clear();
ajaxResponse = ajaxRenderResponse(request, context, components);
} finally {
clearPortletSessionParams(context);
requestMap.remove(AjaxUtil.KEY_RENDERING_PORTLETS_AJAX_RESPONSE);
}
} else {
ajaxResponse = ajaxRenderResponse(request, context, components);
}
ResponseFacade response = ResponseFacade.getInstance(context.getExternalContext().getResponse());
AbstractResponseFacade responseFacade = new ResponseAdapter(response);
ajaxResponse.setStateIdxHolder(new AjaxSavedStateIdxHolder());
if (!nonPortletAjaxRequest) {
ajaxResponse.setSessionExpired(Boolean.TRUE.toString());
ajaxResponse.setSessionExpiredLocation((String) context.getExternalContext().getRequestMap().get(AjaxViewHandler.LOCATION_HEADER));
ajaxResponse.write(response);
} else {
ajaxResponse.write(responseFacade);
}
return responseFacade;
}
// TODO [sanders] (Apr 1, 2009, 5:11 AM): Too long name
private static void finishProccessErrorUnderPortletsDuringAjax(FacesContext context, Throwable e) throws IOException {
AjaxResponse ajaxResponse = new AjaxResponse();
Map<String, Object> requestMap = context.getExternalContext().getRequestMap();
requestMap.put(AjaxUtil.KEY_RENDERING_PORTLETS_AJAX_RESPONSE, Boolean.TRUE);
ajaxResponse.setStateIdxHolder(new AjaxSavedStateIdxHolder());
try {
ajaxResponse.setException(e);
ajaxResponse.write(ResponseFacade.getInstance(context.getExternalContext().getResponse()));
} finally {
clearPortletSessionParams(context);
requestMap.remove(AjaxUtil.KEY_RENDERING_PORTLETS_AJAX_RESPONSE);
}
}
private void ajaxPrepareInitializationScripts(
FacesContext context, AjaxResponse ajaxResponse, List<String> foreignHeadScripts, StringBuilder initializationScripts) {
StringBuilder tempBuffer = new StringBuilder();
if (foreignHeadScripts != null) {
for (String script : foreignHeadScripts) {
StringInspector scriptInspector = new StringInspector(script);
boolean substituteDocumentWrite = scriptInspector.indexOfIgnoreCase("document.write") > -1;
if (substituteDocumentWrite) {
tempBuffer.append("O$.substituteDocumentWrite();\n"); // tricky workaround. see ajaxUtil.js for details
}
tempBuffer.append(script).append("\n");
if (substituteDocumentWrite) {
tempBuffer.append("O$.restoreDocumentWrite();\n"); // tricky workaround. see ajaxUtil.js for details
}
}
}
if (tempBuffer.length() > 0) {
initializationScripts.insert(0, tempBuffer.toString());
}
if (initializationScripts.length() > 0) {
String initScriptsStr = initializationScripts.toString();
initScriptsStr = initScriptsStr.replaceAll("<!--", "").replaceAll("//-->", "");
// create special node with runtime js library that contains all initialization scripts
String uniqueRTLibraryName = ResourceFilter.RUNTIME_INIT_LIBRARY_PATH + AjaxUtil.generateUniqueInitLibraryName();
String initLibraryUrl = Resources.applicationURL(context, uniqueRTLibraryName);
ajaxResponse.setInitLibraryName(initLibraryUrl);
context.getExternalContext().getSessionMap().put(uniqueRTLibraryName, initScriptsStr);
}
}
private AjaxResponse ajaxRenderResponse(
RequestFacade request,
FacesContext context,
UIComponent[] components
) throws IOException {
AjaxResponse ajaxResponse = new AjaxResponse();
// collect all initialization scripts to buffer to use them in runtime loaded js library
StringBuilder initializationScripts = new StringBuilder();
List<String> updatePortions = AjaxUtil.getAjaxPortionNames(context, request);
for (UIComponent component : components) {
Log.log(context, "ajaxRenderResponse start for component " + component);
try {
if (updatePortions.isEmpty()) {
renderSimpleUpdate(request, context, component, ajaxResponse, initializationScripts);
} else {
renderPortionUpdate(request, context, component, ajaxResponse, initializationScripts, updatePortions);
}
} catch (IOException e) {
throw new FacesException(e.getMessage(), e);
}
Log.log(context, "ajaxRenderResponse finish for component " + component);
}
AjaxRequest ajaxRequest = AjaxRequest.getInstance(context);
Set<String> additionalRender = ajaxRequest.getReloadedComponentIds();
UIViewRoot viewRoot = context.getViewRoot();
for (String componentId : additionalRender) {
UIComponent component = findComponentById(viewRoot, componentId, false, true);
renderSimpleUpdate(request, context, component, ajaxResponse, initializationScripts);
}
Object ajaxResult = ajaxRequest.getAjaxResult();
ajaxResponse.setAjaxResult(ajaxResult);
ajaxResponse.setValidationError(ajaxRequest.isValidationError());
AjaxPluginIncludes availableIncludes = PluginsLoader.getAvailableIncludes(context);
List<String> foreignHeadScripts = availableIncludes.getScripts();
ajaxPrepareInitializationScripts(context, ajaxResponse, foreignHeadScripts, initializationScripts);
//todo: find component with inheader styles declaration and add corresponding functionality to AjaxPlugin(s)
addJSLibraries(context, ajaxResponse);
List<String> jsLibraries = availableIncludes.getJsIncludes();
if (jsLibraries != null)
addForeignJSLibraries(ajaxResponse, jsLibraries);
addStyles(context, ajaxResponse, components);
List<String> cssFiles = availableIncludes.getCssIncludes();
if (cssFiles != null) {
addForeignCSSFiles(ajaxResponse, cssFiles);
}
if (AjaxUtil.isPortletRequest(context)) {
final List<UIForm> uiForms = Components.findChildrenWithClass(viewRoot, UIForm.class, false, true);
for (UIForm form : uiForms) {
AjaxSavedStateIdxHolder stateIdxHolder = ajaxResponse.getStateIdxHolder();
if (stateIdxHolder != null && !stateIdxHolder.getForms().contains(form)) {
stateIdxHolder.getForms().add(form);
}
}
}
return ajaxResponse;
}
private void renderPortionUpdate(
RequestFacade request,
FacesContext context,
UIComponent component,
AjaxResponse ajaxResponse,
StringBuilder initializationScripts,
List<String> updatePortions
) throws IOException {
RenderKitFactory factory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
RenderKit renderKit = factory.getRenderKit(context, context.getViewRoot().getRenderKitId());
Renderer renderer = renderKit.getRenderer(component.getFamily(), component.getRendererType());
JSONObject customJSONParam = AjaxUtil.getCustomJSONParam(context, request);
AjaxPortionRenderer ajaxComponentRenderer = (AjaxPortionRenderer) renderer;
for (String nextId : updatePortions) {
StringBuilder portionOutput;
JSONObject responseData;
StringWriter stringWriter = new StringWriter();
ResponseWriter originalWriter = substituteResponseWriter(context, request, stringWriter);
try {
responseData = ajaxComponentRenderer.encodeAjaxPortion(context, component, nextId, customJSONParam);
portionOutput = new StringBuilder(stringWriter.toString());
} catch (JSONException e) {
throw new RuntimeException(e);
} finally {
restoreWriter(context, originalWriter);
}
StringBuilder rawScriptsBuffer = new StringBuilder();
StringBuilder rtLibraryScriptsBuffer = new StringBuilder();
extractScripts(portionOutput, rawScriptsBuffer, rtLibraryScriptsBuffer);
if (rtLibraryScriptsBuffer.length() > 0) {
initializationScripts.append(rtLibraryScriptsBuffer).append("\n");
}
ajaxResponse.addPortion(nextId, portionOutput.toString(), rawScriptsBuffer.toString(), responseData);
}
}
private void renderSimpleUpdate(RequestFacade request, FacesContext context, UIComponent component, AjaxResponse ajaxResponse, StringBuilder initializationScripts) throws IOException {
StringWriter wrt = new StringWriter();
ResponseWriter originalWriter = substituteResponseWriter(context, request, wrt);
StringBuilder outputBuffer;
try {
component.encodeBegin(context);
component.encodeChildren(context);
component.encodeEnd(context);
outputBuffer = new StringBuilder(wrt.toString());
} finally {
restoreWriter(context, originalWriter);
}
StringBuilder rtLibraryScriptsBuffer = new StringBuilder();
StringBuilder rawScriptsBuffer = new StringBuilder();
extractScripts(outputBuffer, rawScriptsBuffer, rtLibraryScriptsBuffer);
if (rtLibraryScriptsBuffer.length() > 0) {
initializationScripts.append(rtLibraryScriptsBuffer).append("\n");
}
String output = outputBuffer.toString();
String clientId = component.getClientId(context);
ajaxResponse.addSimpleUpdate(clientId, output, rawScriptsBuffer.toString());
}
private void extractScripts(StringBuilder buffer,
StringBuilder rawScriptBuffer,
StringBuilder rtLibraryScriptBuffer) {
String scriptStart = "<script";
String scriptEnd = "/script>";
while (true) {
int fromIndex = buffer.indexOf(scriptStart);
if (fromIndex == -1)
break;
int toIndex = buffer.indexOf(scriptEnd, fromIndex);
if (toIndex == -1)
break;
toIndex += scriptEnd.length();
String rawScript = buffer.substring(fromIndex, toIndex);
String script = purifyScripts(rawScript);
Matcher matcher = JS_VAR_PATTERN.matcher(rawScript);
boolean varFound = matcher.find();
buffer.delete(fromIndex, toIndex);
if (varFound) {
rtLibraryScriptBuffer.append(script).append("\n");
} else {
rawScriptBuffer.append(rawScript);
}
}
}
private String purifyScripts(String script) {
StringBuffer result = new StringBuffer();
int startIdx = script.indexOf("<script");
int endIdx = script.indexOf("</script>");
if (startIdx == -1 || endIdx == -1) return script;
int endScriptInit = script.indexOf(">", startIdx + 1);
if (startIdx > 0) {
result.append(script.substring(0, startIdx));
result.append("\n");
script = script.substring(startIdx);
// re-read indexes
startIdx = script.indexOf("<script");
endIdx = script.indexOf("</script>");
if (startIdx != -1)
endScriptInit = script.indexOf(">", startIdx + 1);
}
if (endScriptInit == -1) return script;
while (startIdx > -1) {
result.append(script.substring(endScriptInit + 1, endIdx));
result.append("\n");
script = script.substring(endIdx + "</script>".length());
// re-read indexes
startIdx = script.indexOf("<script");
endIdx = script.indexOf("</script>");
if (startIdx > -1)
endScriptInit = script.indexOf(">", startIdx + 1);
}
if (script.length() > 0) {
result.append(script);
result.append("\n");
}
return result.toString();
}
private void addJSLibraries(FacesContext context, AjaxResponse ajaxResponse) {
List<String> libraries = (List<String>) context.getExternalContext().getRequestMap().get(Resources.HEADER_JS_LIBRARIES);
if (libraries == null) return;
for (String jsLibrary : libraries) {
ajaxResponse.addJsLibrary(jsLibrary);
}
}
/**
* Adds all JS libraries declarations retrieved from third-party JSF components libraries that are currently supported
* and returned by corresponding plugin.
*/
private void addForeignJSLibraries(AjaxResponse ajaxResponse, List<String> libraries) {
for (String library : libraries) {
ajaxResponse.addJsLibrary(library);
}
}
private void addStyles(FacesContext context, AjaxResponse ajaxResponse, UIComponent[] components) {
for (UIComponent component : components) {
List<String> styleClasses = Styles.getAllStyleClassesForComponent(context, component);
addStyleClasses(ajaxResponse, styleClasses);
Styles.markStylesRenderedForComponent(context, component);
}
}
private void addStyleClasses(AjaxResponse ajaxResponse, List<String> styleClasses) {
if (styleClasses == null) return;
for (String style : styleClasses) {
ajaxResponse.addStyle(style);
}
}
private void addForeignCSSFiles(AjaxResponse ajaxResponse, List<String> cssFiles) {
for (String cssFile : cssFiles) {
ajaxResponse.addCssFile(cssFile);
}
}
/**
* Save state for processed ajaxs request
*
* @return If there is server side state saving, return serializid view state. Otherwise, return null.
* Serialized view state is used for adjusting "com.sun.faces.VIEW" for RI faces implementation
*/
@SuppressWarnings({"deprecation"})
private AjaxSavedStateIdxHolder ajaxSaveState(
FacesContext context,
RequestFacade request,
AjaxResponse ajaxResponse,
UIComponent[] components, Integer sequence) throws IOException {
AjaxSavedStateIdxHolder savedStateStructure = new AjaxSavedStateIdxHolder();
StateManager stateManager = context.getApplication().getStateManager();
boolean savingStateInClient = stateManager.isSavingStateInClient(context);
if (savingStateInClient) {
StringWriter stringWriter = new StringWriter();
ResponseWriter originalWriter = substituteResponseWriter(context, request, stringWriter);
try {
for (UIComponent component : components) {
Object state = component.processSaveState(context);
String clientId = component.getClientId(context);
writeState(context, clientId, state);
String stateString = stringWriter.toString();
ajaxResponse.addComponentState(clientId, stateString);
}
} finally {
restoreWriter(context, originalWriter);
}
} else {
StateManager.SerializedView view = stateManager.saveSerializedView(context);
boolean myFaces = Environment.isMyFaces();
boolean richFaces = Environment.isRichFacesStateManager(stateManager);
boolean facelets = Environment.isFacelets(context);
if (myFaces && !richFaces && !facelets) {
obtainViewStateSequenceForMyFaces(context, request, sequence, savedStateStructure);
}
if (!myFaces && view != null) {
obtainViewStateSequence(context, request, view, savedStateStructure);
} else if (myFaces) {
if (richFaces && view != null) {
obtainViewStateSequence(context, request, view, savedStateStructure);
} else {
if (facelets) {
obtainViewStateSequenceForMyFaces(context, request, sequence, savedStateStructure);
}
}
}
if (view != null) {
savedStateStructure.setViewStructureId(view.getStructure());
}
}
return savedStateStructure;
}
private void obtainViewStateSequence(FacesContext context, RequestFacade request, StateManager.SerializedView view,
AjaxSavedStateIdxHolder stateIdxHolder) throws IOException {
StringWriter stringWriter = new StringWriter();
ResponseWriter originalWriter = substituteResponseWriter(context, request, stringWriter);
ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
responseStateManager.writeState(context, view);
restoreWriter(context, originalWriter);
String stateString = stringWriter.getBuffer().toString();
// This is necessarry to obtain valid state key for updating it on client side
parseStateString(stateString, stateIdxHolder);
}
private void obtainViewStateSequenceForMyFaces(FacesContext context, RequestFacade request, Integer sequence,
AjaxSavedStateIdxHolder stateIdxHolder)
throws IOException {
StringWriter stringWriter = new StringWriter();
ResponseWriter originalWriter = substituteResponseWriter(context, request, stringWriter);
if (!Environment.isFacelets(context)) {
context.getApplication().getViewHandler().writeState(context);
} else {
ResponseStateManager responseStateManager = context.getRenderKit().getResponseStateManager();
Object[] state = new Object[2];
state[0] = Integer.toString(sequence, Character.MAX_RADIX);
responseStateManager.writeState(context, state);
}
restoreWriter(context, originalWriter);
String stateString = stringWriter.getBuffer().toString();
// This is necessarry to obtain valid state key for updating it on client side
parseStateString(stateString, stateIdxHolder);
}
private void parseStateString(String stateString, AjaxSavedStateIdxHolder stateIdxHolder) {
if (stateString == null) {
return;
}
Pattern valuePattern = Pattern.compile("value=(\"([^\"]*\")|'[^']*')");
final Matcher matcher = valuePattern.matcher(stateString);
final boolean isValuePatternFound = matcher.find();
if (isValuePatternFound) {
int startIndex = matcher.start();
int endIndex = matcher.end();
String valueString = stateString.substring(startIndex, endIndex);
int firstIndex = VALUE_ATTR_STRING.length();
String viewStateString = valueString.substring(firstIndex, valueString.lastIndexOf("\""));
stateIdxHolder.setViewStateIdentifier(viewStateString);
} else {
throw new FacesException("Could not obtain view state identifier by state description string - : " + stateString);
}
}
private Integer getSequenceIdForMyFaces(FacesContext context) { // see JSFC-1516
ExternalContext externalContext = context.getExternalContext();
Object session = externalContext.getSession(false);
if (session == null)
return null;
Map<String, Object> sessionMap = externalContext.getSessionMap();
Integer sequence = (Integer) sessionMap.get(MYFACES_SEQUENCE_PARAM);
return sequence;
}
private UIComponent findComponentById(UIComponent parent, String id) {
return findComponentById(parent, id, false, false);
}
private UIComponent findComponentById(UIComponent parent,
String id,
boolean preProcessDecodesOnTables,
boolean preRenderResponseOnTables) {
return UtilPhaseListener.findComponentById(parent, id, preProcessDecodesOnTables, preRenderResponseOnTables, true);
}
private void writeState(FacesContext context, String clientId, Object state) throws IOException {
ResponseWriter writer = context.getResponseWriter();
String stateStr = AjaxUtil.objectToString(state);
String fieldName = AjaxUtil.getComponentStateFieldName(clientId);
Rendering.renderHiddenField(writer, fieldName, stateStr);
}
private ResponseWriter substituteResponseWriter(FacesContext context, RequestFacade request, Writer innerWriter) {
ResponseWriter newWriter;
ResponseWriter responseWriter = context.getResponseWriter();
if (responseWriter != null) {
newWriter = responseWriter.cloneWithWriter(innerWriter);
} else {
RenderKitFactory factory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY);
RenderKit renderKit = factory.getRenderKit(context, context.getViewRoot().getRenderKitId());
newWriter = renderKit.createResponseWriter(innerWriter, null, request.getCharacterEncoding());
}
context.setResponseWriter(newWriter);
return responseWriter;
}
private void restoreWriter(FacesContext context, ResponseWriter originalWriter) {
if (originalWriter != null)
context.setResponseWriter(originalWriter);
}
private void broadcastEvents(FacesContext context, PhaseId phaseId) {
if (events == null) return;
for (FacesEvent event : new ArrayList<FacesEvent>(events)) {
PhaseId eventPhaseId = event.getPhaseId();
if (eventPhaseId.compareTo(PhaseId.ANY_PHASE) != 0 && eventPhaseId.compareTo(phaseId) != 0)
continue;
events.remove(event);
UIComponent source = event.getComponent();
try {
source.broadcast(event);
} catch (AbortProcessingException e) {
break;
}
}
if (context.getRenderResponse() || context.getResponseComplete())
events = null;
}
public void queueEvent(FacesEvent event) {
if (event == null) throw new NullPointerException("event");
if (events == null) {
events = new ArrayList<FacesEvent>();
}
events.add(event);
}
}