Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.ajax4jsf.framework.renderer.AjaxRendererUtils Maven / Gradle / Ivy
/**
* Licensed under the Common Development and Distribution License,
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.sun.com/cddl/
*
* 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.ajax4jsf.framework.renderer;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import javax.faces.application.ViewHandler;
import javax.faces.component.ActionSource;
import javax.faces.component.EditableValueHolder;
import javax.faces.component.NamingContainer;
import javax.faces.component.UIComponent;
import javax.faces.component.UIForm;
import javax.faces.component.UIParameter;
import javax.faces.component.UIViewRoot;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.servlet.http.HttpServletResponse;
import org.ajax4jsf.ajax.UILoadBundle;
import org.ajax4jsf.framework.ajax.AjaxComponent;
import org.ajax4jsf.framework.ajax.AjaxContainer;
import org.ajax4jsf.framework.ajax.AjaxContext;
import org.ajax4jsf.framework.ajax.AjaxRegionListener;
import org.ajax4jsf.framework.ajax.AjaxSupport;
import org.ajax4jsf.framework.ajax.AjaxViewRoot;
import org.ajax4jsf.framework.ajax.JavaScriptParameter;
import org.ajax4jsf.framework.renderer.RendererUtils.HTML;
import org.ajax4jsf.framework.util.javascript.JSFunction;
import org.ajax4jsf.framework.util.javascript.JSFunctionDefinition;
import org.ajax4jsf.framework.util.javascript.JSReference;
import org.ajax4jsf.framework.util.message.Messages;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
/**
* @author shura
*
* Some utilites for render AJAX components.
*/
public class AjaxRendererUtils {
/**
* Name Javasript function for submit AJAX request
*/
public static final String AJAX_FUNCTION_NAME = "A4J.AJAX.Submit";
/**
* Attribute for keep clientId of status component
*/
public static final String STATUS_ATTR_NAME = "status";
/**
* Attribute for keep JavaScript funtion name for call after complete
* request.
*/
public static final String ONCOMPLETE_ATTR_NAME = "oncomplete";
/**
* Attribute to keep
*/
public static final String LIMITTOLIST_ATTR_NAME = "limitToList";
private static Log log = LogFactory.getLog(AjaxRendererUtils.class);
public static final String AJAX_REGIONS_ATTRIBUTE = "reRender";
private static final Class OBJECT_ARRAY_CLASS = (new Object[0]).getClass();
public static final String SEQUENCE_PARAM = "jsf_sequence";
private static final String VALUE_ATTR = "value";
public static final String AJAX_AREAS_RENDERED = "org.ajax4jsf.areas.rendered";
private static final String AJAX_SINGLE_ATTR = "ajaxSingle";
public static final String AJAX_QUEUE_ATTR = "eventsQueue";
public static final String AJAX_DELAY_ATTR = "requestDelay";
private static final Object AJAX_ABORT_ATTR = "ignoreDupResponses";
/**
* Static class - protect constructor TODO - make as subclass of chameleon
* RendererUtils.
*
*/
private AjaxRendererUtils() {
}
/**
* Build JavaScript onclick event for given component
*
* @param uiComponent -
* component for build event
* @param facesContext
* @return StringBuffer
with Javascript code
*/
public static StringBuffer buildOnClick(UIComponent uiComponent,
FacesContext facesContext) {
return buildOnEvent(uiComponent, facesContext, HTML.onclick_ATTRIBUTE);
}
/**
* Build JavaScript event for component
*
* @param uiComponent -
* component for build event
* @param facesContext
* @param eventName -
* name of event
* @return StringBuffer
with Javascript code TODO - for
* key-based events build list of supported keys
*/
public static StringBuffer buildOnEvent(UIComponent uiComponent,
FacesContext facesContext, String eventName) {
StringBuffer onEvent = new StringBuffer();
if(null != eventName){
String commandOnEvent = (String) uiComponent.getAttributes().get(
eventName);
if (commandOnEvent != null) {
onEvent.append(commandOnEvent);
onEvent.append(';');
}
}
JSFunction ajaxFunction = buildAjaxFunction(uiComponent, facesContext);
// Create formal parameter for non-input elements ???
// Link Control pseudo-object
// Options map. Possible options for function call :
// control - name of form control for submit.
// name - name for link control \
// value - value of control. - possible replace by parameters ?
// single true/false - submit all form or only one control.
// affected - array of element's ID for update on responce.
// oncomplete - function for call after complete request.
// status - id of request status component.
// parameters - map of parameters name/value for append on request.
// TODO
// sync true/false - run script in sync mode.
// ..........
ajaxFunction.addParameter(buildEventOptions(facesContext, uiComponent));
// appendAjaxSubmitParameters(facesContext, uiComponent, onEvent);
ajaxFunction.appendScript(onEvent);
if (uiComponent instanceof AjaxSupport) {
AjaxSupport support = (AjaxSupport) uiComponent;
if (support.isDisableDefault()) {
onEvent.append("; return false;");
}
}
log.debug(Messages.getMessage(Messages.BUILD_ONCLICK_INFO, uiComponent
.getId(), onEvent.toString()));
return onEvent;
}
/**
* @param facesContext
* @param uiComponent
* @return
*/
public static Map buildEventOptions(FacesContext facesContext,
UIComponent uiComponent) {
String clientId = uiComponent.getClientId(facesContext);
Map componentAttributes = uiComponent.getAttributes();
Map options = new HashMap();
Map parameters = new HashMap();
// UIForm form = getNestingForm(uiComponent);
// "input" - if assigned to html input element.
boolean input = (uiComponent instanceof AjaxSupport && uiComponent
.getParent() instanceof EditableValueHolder)
|| uiComponent instanceof EditableValueHolder;
// Action component - button etc.
boolean action = (uiComponent instanceof AjaxSupport && uiComponent
.getParent() instanceof ActionSource)
|| uiComponent instanceof ActionSource;
// TODO - disable ( or not ? ) submission of action for disabled default
// ?
// if ( action && uiComponent instanceof AjaxSupport) {
// AjaxSupport support = (AjaxSupport) uiComponent;
// if (support.isDisableDefault()) {
// action = false;
// }
// }
boolean ajaxSingle = Boolean.TRUE.equals(componentAttributes
.get(AJAX_SINGLE_ATTR));
// For input components in single mode or without form submit input
// control )
if ( ajaxSingle && input) { // || action
// TODO - inside form, put reference :
// document.forms['form'].controls['control']
options.put("control", JSReference.THIS);
}
// Control value for submit
String controlName;
Object controlValue;
// TODO - make compatible with JSF RI/MyFaces ? use submittedValue ( if
// any ) for UIInput, converted value for ValueHolder.
controlName = clientId;
controlValue = clientId;
parameters.put(controlName, controlValue);
if (ajaxSingle) {
options.put("single", JSReference.TRUE);
}
// Setup action URL. For portlet environment, it will be different from page.
options.put("actionUrl", getActionUrl(facesContext));
// add child parameters
for (Iterator it = uiComponent.getChildren().iterator(); it.hasNext();) {
UIComponent child = (UIComponent) it.next();
if (child instanceof UIParameter) {
String name = ((UIParameter) child).getName();
Object value = ((UIParameter) child).getValue();
if (null == name) {
throw new IllegalArgumentException(Messages.getMessage(
Messages.UNNAMED_PARAMETER_ERROR, uiComponent
.getClientId(facesContext)));
}
boolean escape = true;
if (child instanceof JavaScriptParameter) {
JavaScriptParameter actionParam = (JavaScriptParameter) child;
escape = !actionParam.isNoEscape();
}
if (escape) {
parameters.put(name, value);
} else {
parameters.put(name, new JSReference(value.toString()));
// if(it.hasNext()){onEvent.append(',');};
// renderAjaxLinkParameter( name,
// value, onClick, jsForm, nestingForm);
}
}
}
if (!parameters.isEmpty()) {
options.put("parameters", parameters);
}
// parameter to render only current list of areas.
if (isAjaxLimitToList(uiComponent)) {
Set ajaxAreas = getAjaxAreas(uiComponent);
Set areasIds = new HashSet();
if (null != ajaxAreas) {
for (Iterator iter = ajaxAreas.iterator(); iter.hasNext();) {
String id = (String) iter.next();
UIComponent comp = uiComponent.findComponent(id);
if (null != comp) {
areasIds.add(comp.getClientId(facesContext));
} else {
areasIds.add(id);
}
}
}
options.put("affected", areasIds);
}
String oncomplete = getAjaxOncomplete(uiComponent);
if (null != oncomplete) {
JSFunctionDefinition function = new JSFunctionDefinition("request");
function.addParameter("event");
function.addParameter("data");
function.addToBody(oncomplete);
options.put("oncomplete", function);
}
String status = getAjaxStatus(uiComponent);
if (null != status) {
options.put("status", status);
}
String queue = (String) componentAttributes.get(AJAX_QUEUE_ATTR);
Integer requestDelay = (Integer) componentAttributes
.get(AJAX_DELAY_ATTR);
if (null != requestDelay && requestDelay.intValue() > 0) {
options.put(AJAX_DELAY_ATTR, requestDelay);
if (null == queue) {
queue = clientId;
}
}
Boolean ignoreDupResponses = (Boolean)componentAttributes.get(AJAX_ABORT_ATTR);
if(null != ignoreDupResponses && ignoreDupResponses.booleanValue()){
options.put(AJAX_ABORT_ATTR, JSReference.TRUE);
if (null == queue) {
queue = clientId;
}
}
if (null != queue) {
options.put(AJAX_QUEUE_ATTR, queue);
}
// request timeout.
Integer timeout = (Integer) componentAttributes.get("timeout");
if (null != timeout && timeout.intValue()>0) {
options.put("timeout", timeout);
}
// Encoding for requests
String encoding = (String) componentAttributes.get("encoding");
if (null != encoding) {
options.put("encoding", encoding);
}
return options;
}
/**
* Create call to Ajax Submit function with first two parameters
*
* @param uiComponent
* @param facesContext
* @param functionName
* TODO
* @return
*/
public static JSFunction buildAjaxFunction(UIComponent uiComponent,
FacesContext facesContext){
JSFunction ajaxFunction = buildAjaxFunction(uiComponent, facesContext, AJAX_FUNCTION_NAME);
// client-side script must have reference to event-enabled object.
ajaxFunction.addParameter(new JSReference("event"));
return ajaxFunction;
}
/**
* Create call to Ajax Submit function with first two parameters
*
* @param uiComponent
* @param facesContext
* @param functionName
* TODO
* @return
*/
public static JSFunction buildAjaxFunction(UIComponent uiComponent,
FacesContext facesContext, String functionName) {
JSFunction ajaxFunction = new JSFunction(functionName);
UIComponent nestingContainer = (UIComponent) findAjaxContainer(
facesContext, uiComponent);
ajaxFunction.addParameter(nestingContainer.getClientId(facesContext));
// build form name or ActionUrl for script
UIComponent nestingForm = getNestingForm(uiComponent);
if (null == nestingForm) {
ajaxFunction.addParameter(JSReference.NULL);
} else {
ajaxFunction.addParameter(nestingForm.getClientId(facesContext));
}
return ajaxFunction;
}
/**
* Append common parameters ( array of affected areas, status area id, on
* complete function ) to JavaScript event string.
*
* @param uiComponent
* @param onClick -
* buffer with JavaScript code eg... AJAX.Submit(form,this
*/
// public static void appendAjaxSubmitParameters(FacesContext facesContext,
// UIComponent uiComponent, StringBuffer onClick)
// {
// Set ajaxAreas = getAjaxAreas(uiComponent);
// onClick.append(',');
// // parameter to render only current list of areas.
// if (isAjaxLimitToList(uiComponent) && ajaxAreas != null &&
// ajaxAreas.size() > 0)
// {
// onClick.append('[');
// Iterator areas = ajaxAreas.iterator();
// boolean first = true;
// while (areas.hasNext())
// {
// String element = (String) areas.next();
// UIComponent component = uiComponent.findComponent(element);
// if (null != component)
// {
// if (!first)
// {
// onClick.append(',');
// }
// else
// {
// first = false;
// }
// onClick.append('\'');
// onClick.append(component.getClientId(facesContext));
// onClick.append('\'');
// }
// }
// onClick.append("]");
// }
// else
// {
// onClick.append("null");
// }
// // insert id of request status element.
// onClick.append(',');
// String status = getAjaxStatus(uiComponent);
// if (null != status)
// {
// onClick.append('\'').append(status).append('\'');
// }
// else
// {
// onClick.append("null");
// }
// // insert function name for call after completed request
// onClick.append(',');
// String oncomplete = getAjaxOncomplete(uiComponent);
// if (null != oncomplete)
// {
// onClick.append(oncomplete);
// }
// else
// {
// onClick.append("null");
// }
//
// }
/**
* Get list of clientId's for given component
*
* @param uiComponent
* @return List of areas Id's , updated by this component.
*/
public static Set getAjaxAreas(UIComponent uiComponent) {
Object areas;
if (uiComponent instanceof AjaxComponent) {
areas = ((AjaxComponent) uiComponent).getReRender();
} else {
areas = uiComponent.getAttributes().get(
AjaxRendererUtils.AJAX_REGIONS_ATTRIBUTE);
}
return asSet(areas);
}
/**
* Convert parameter ( Collection, List, array, String, comma-separated
* String ) to list of srings. TODO - when move to JDK 5, change to
* List<String>
*
* @param valueToSet -
* obect for convert to List.
* @return - list of strings.
*/
public static Set asSet(Object valueToSet) {
if (null != valueToSet) {
// Simplest case - set.
if (valueToSet instanceof Set) {
return (Set) valueToSet;
}
// Other collections.
else if (valueToSet instanceof Collection) {
return new HashSet((Collection) valueToSet);
}
// Array
else if (OBJECT_ARRAY_CLASS.isAssignableFrom(valueToSet.getClass())) {
return new HashSet(Arrays.asList((Object[]) valueToSet));
}
// Tokenize string.
else if (valueToSet instanceof String) {
String areasString = (String) valueToSet;
if (areasString.indexOf(",") > 0) {
return new HashSet(Arrays.asList(areasString.trim().split("(\\s)*,(\\s)*")));
} else {
Set areasSet = new HashSet(5);
areasSet.add(areasString.trim());
return areasSet;
}
}
}
return null;
}
/**
* Get status area Id for given component.
*
* @param component
* @return clientId of status area, or null
*/
public static String getAjaxStatus(UIComponent component) {
String statusId;
if (component instanceof AjaxComponent) {
statusId = ((AjaxComponent) component).getStatus();
} else {
statusId = (String) component.getAttributes().get(STATUS_ATTR_NAME);
}
if (null != statusId) {
UIComponent status = null;
UIComponent currentParent = component;
try {
// Check the naming container of the current
// component for component identified by
// 'forComponent'
while (currentParent != null) {
// If the current component is a NamingContainer,
// see if it contains what we're looking for.
status = currentParent.findComponent(statusId);
if (status != null)
break;
// if not, start checking further up in the view
currentParent = currentParent.getParent();
}
} catch (Exception e) {
// ignore - log the warning
}
if (null != status) {
statusId = status
.getClientId(FacesContext.getCurrentInstance());
} else {
log.warn(Messages.getMessage(
Messages.AJAX_STATUS_COMPONENT_NOT_FOWND_WARNING,
component.getId()));
}
}
return statusId;
}
/**
* Get function name for call on completed ajax request.
*
* @param component
* for wich calculate function name
* @return name of JavaScript function or null
*/
public static String getAjaxOncomplete(UIComponent component) {
if (component instanceof AjaxComponent) {
return ((AjaxComponent) component).getOncomplete();
}
return (String) component.getAttributes().get(ONCOMPLETE_ATTR_NAME);
}
/**
* Calculate, must be component render only given areas, or all sended from
* server.
*
* @param component
* @return true
if client must render ONLY given areas.
*/
public static boolean isAjaxLimitToList(UIComponent component) {
boolean result = false;
if (component instanceof AjaxComponent) {
result = ((AjaxComponent) component).isLimitToList();
} else {
try {
result = ((Boolean) component.getAttributes().get(
LIMITTOLIST_ATTR_NAME)).booleanValue();
} catch (NullPointerException e) {
// NullPointer - ignore ...
} catch (ClassCastException e1) {
// not Boolean - false ...
}
}
return result;
}
/**
* Replacement for buggy in MyFaces RendererUtils
*
* @param component
* @return
*/
public static String getAbsoluteId(UIComponent component) {
if (component == null)
throw new NullPointerException(Messages
.getMessage(Messages.COMPONENT_NULL_ERROR_2));
StringBuffer idBuf = new StringBuffer();
idBuf.append(component.getId());
UIComponent parent = component;
while ((parent = parent.getParent()) != null) {
if (parent instanceof NamingContainer) {
idBuf.insert(0, NamingContainer.SEPARATOR_CHAR);
idBuf.insert(0, parent.getId());
}
}
idBuf.insert(0, NamingContainer.SEPARATOR_CHAR);
log.debug(Messages.getMessage(Messages.CALCULATE_COMPONENT_ID_INFO,
component.getId(), idBuf.toString()));
return idBuf.toString();
}
/**
* Find nested form for given component
*
* @param component
* @return nested UIForm
component, or null
*/
public static UIComponent getNestingForm(UIComponent component) {
UIComponent parent = component;
// Search enclosed UIForm or ADF UIXForm component
while (parent != null
&& !(parent instanceof UIForm)
&& !("org.apache.myfaces.trinidad.Form".equals(parent
.getFamily()))
&& !("oracle.adf.Form".equals(parent
.getFamily()))) {
parent = parent.getParent();
}
return parent;
}
protected static String getActionUrl(FacesContext facesContext) {
ViewHandler viewHandler = facesContext.getApplication()
.getViewHandler();
String viewId = facesContext.getViewRoot().getViewId();
return facesContext.getExternalContext().encodeActionURL(
viewHandler.getActionURL(facesContext, viewId));
}
/**
* @param facesContext
* @param uiComponent
* @return
*/
public static org.ajax4jsf.framework.ajax.AjaxContainer findAjaxContainer(
FacesContext facesContext, UIComponent uiComponent) {
UIComponent parent = uiComponent.getParent();
while (parent != null
&& !(parent instanceof org.ajax4jsf.framework.ajax.AjaxContainer)) {
parent = parent.getParent();
}
org.ajax4jsf.framework.ajax.AjaxContainer nestingContainer = null;
if (parent != null) {
// link is nested inside a form
nestingContainer = (org.ajax4jsf.framework.ajax.AjaxContainer) parent;
} else if (facesContext.getViewRoot() instanceof AjaxViewRoot) {
nestingContainer = (AjaxContainer) facesContext.getViewRoot();
}
return nestingContainer;
}
public static AjaxContainer getSubmittedAjaxContainer(FacesContext context,
AjaxContainer container) {
UIViewRoot root = context.getViewRoot();
if (root instanceof AjaxViewRoot) {
AjaxViewRoot ajaxRoot = (AjaxViewRoot) root;
UIComponent submitted = ajaxRoot.getSubmittedRegion(context);
if (null == submitted) {
return ajaxRoot;
} else {
return (AjaxContainer) submitted;
}
} else {
return container;
}
}
/**
* For Myfaces, get current viev sequence.
*
* @param facescontext
* @return
*/
private static Integer getViewSequence(FacesContext facescontext) {
Map map = facescontext.getExternalContext().getRequestMap();
Integer sequence = (Integer) map.get(SEQUENCE_PARAM);
if (sequence == null) {
sequence = new Integer(1);
map.put(SEQUENCE_PARAM, sequence);
}
return sequence;
}
/**
* Encode rendered areas as special HTML tag ( span in current release )
*
* @param context
* @param component
* @throws IOException
*/
public static boolean encodeAreas(FacesContext context,
UIComponent component) throws IOException {
AjaxContainer ajax = getSubmittedAjaxContainer(context,
(AjaxContainer) component);
// Out only for current container
if (null != ajax) {
ExternalContext externalContext = context.getExternalContext();
Map requestMap = externalContext.getRequestMap();
if (ajax.isSubmitted()
&& (null == requestMap.get(AJAX_AREAS_RENDERED))) {
AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context);
Set rendered = ajaxContext.getAjaxRenderedAreas();
StringBuffer senderString = new StringBuffer();
// write special area for list of rendered elements. Client-side
// Java
// Script
// read this structure for update areas of DOM tree.
ResponseWriter out = context.getResponseWriter();
// Create element to keep list rendered aread ( in title
// attribute )
// More right will create special namespace for such
// information,
// but I want to keep simple html ( xhtml ) document - on case
// I have troubles with microsoft XMLHTTP validations.
out.startElement(
AjaxContainerRenderer.AJAX_RESULT_GROUP_TAG,
component);
out.writeAttribute(HTML.NAME_ATTRIBUTE,
AjaxContainerRenderer.AJAX_UPDATE_HEADER, null);
for (Iterator it = rendered.iterator(); it.hasNext();) {
String id = (String) it.next();
// out.startElement(AJAX_RESULT_TAG, component);
// out.writeText(id,null);
// out.endElement(AJAX_RESULT_TAG);
senderString.append(id);
if (it.hasNext()) {
senderString.append(',');
}
}
out.writeAttribute(
AjaxContainerRenderer.AJAX_RESULT_GROUP_ATTR,
senderString, null);
out.endElement(AjaxContainerRenderer.AJAX_RESULT_GROUP_TAG);
// For sequences and client-saved states.
out.startElement(AjaxContainerRenderer.AJAX_VIEW_STATE_TAG,
component);
out.writeAttribute(HTML.id_ATTRIBUTE,
AjaxContainerRenderer.AJAX_VIEW_STATE_ID, null);
writeState(context);
out.endElement(AjaxContainerRenderer.AJAX_VIEW_STATE_TAG);
// Write rendered flag to html
out.startElement(
AjaxContainerRenderer.AJAX_RESULT_GROUP_TAG,
component);
out.writeAttribute(HTML.id_ATTRIBUTE,
AjaxContainerRenderer.AJAX_FLAG_HEADER, null);
out.writeAttribute(HTML.NAME_ATTRIBUTE,
AjaxContainerRenderer.AJAX_FLAG_HEADER, null);
out.writeAttribute(
AjaxContainerRenderer.AJAX_RESULT_GROUP_ATTR,
"true", null);
out.endElement(AjaxContainerRenderer.AJAX_RESULT_GROUP_TAG);
// set response header with list of rendered ID's
Object response = externalContext.getResponse();
// Use reflection for send responce headers - we can get
// different responces classes
// for different environment ( portal, cocoon etc )
if (response instanceof HttpServletResponse) {
HttpServletResponse httpResponse = (HttpServletResponse) response;
httpResponse.setHeader(
AjaxContainerRenderer.AJAX_UPDATE_HEADER,
senderString.toString());
httpResponse.setHeader(
AjaxContainerRenderer.AJAX_FLAG_HEADER, "true");
} else {
try {
Method setHeadergMethod = response.getClass()
.getMethod(
"setHeader",
new Class[] { String.class,
String.class });
setHeadergMethod.invoke(response, new Object[] {
AjaxContainerRenderer.AJAX_UPDATE_HEADER,
senderString.toString() });
setHeadergMethod.invoke(response, new Object[] {
AjaxContainerRenderer.AJAX_FLAG_HEADER,
"true" });
} catch (Exception e) {
log
.error(Messages
.getMessage(Messages.DETECTING_ENCODING_DISABLED_ERROR));
log.error(Messages.getMessage(
Messages.OBTAIN_RESPONSE_SET_HEADER_ERROR, e));
}
}
Map responseDataMap = ajaxContext.getResponseDataMap();
// Put data to JavaScript handlers, inside elements.
for (Iterator dataIterator = responseDataMap.keySet().iterator(); dataIterator.hasNext();) {
Object dataKey = dataIterator.next();
out.startElement(HTML.SPAN_ELEM, component);
out.writeAttribute(HTML.id_ATTRIBUTE, dataKey, null);
out.write(responseDataMap.get(dataKey).toString());
out.endElement(HTML.SPAN_ELEM);
}
// For self-rendered case, we use own methods for replace stateKey by real value
// in XML filter.
// if(ajaxContext.isSelfRender()){
// saveViewState(context, out);
// }
requestMap.put(AJAX_AREAS_RENDERED, "true");
return true;
}
}
return false;
}
/**
* Write state saving markers to context, include MyFaces view sequence.
*
* @param context
* @throws IOException
*/
public static void writeState(FacesContext context) throws IOException {
if (!context.getApplication().getStateManager().isSavingStateInClient(
context)) {
ResponseWriter writer = context.getResponseWriter();
// MyFaces-specific view sequence attribute
writer.startElement(HTML.INPUT_ELEM, null);
writer.writeAttribute(HTML.TYPE_ATTR, HTML.INPUT_TYPE_HIDDEN, null);
writer.writeAttribute(HTML.NAME_ATTRIBUTE,
AjaxRendererUtils.SEQUENCE_PARAM, null);
writer.writeAttribute(HTML.value_ATTRIBUTE, AjaxRendererUtils
.getViewSequence(context), null);
writer.endElement(HTML.INPUT_ELEM);
}
context.getApplication().getViewHandler().writeState(context);
}
/**
* Encode declaration for AJAX response. Render <html><body>
*
* @param context
* @param component
* @throws IOException
*/
public static void encodeAjaxBegin(FacesContext context,
UIComponent component) throws IOException {
// AjaxContainer ajax = (AjaxContainer) component;
ResponseWriter out = context.getResponseWriter();
// DebugUtils.traceView("ViewRoot in AJAX Page encode begin");
out.startElement("html", component);
// TODO - html attributes. lang - from current locale ?
Locale locale = context.getViewRoot().getLocale();
out.writeAttribute(HTML.lang_ATTRIBUTE, locale.toString(), "lang");
out.startElement("body", component);
}
/**
* End encoding of AJAX response. Render tag with included areas and close
* </body></html>
*
* @param context
* @param component
* @throws IOException
*/
public static void encodeAjaxEnd(FacesContext context, UIComponent component)
throws IOException {
// AjaxContainer ajax = (AjaxContainer) component;
ResponseWriter out = context.getResponseWriter();
// DebugUtils.traceView("ViewRoot in AJAX Page encode begin");
if (encodeAreas(context, component)) {
out.endElement("body");
out.endElement("html");
}
}
/**
* Detect AJAX status for request
*
* @param context
* @return
*/
public static boolean isAjaxRequest(FacesContext context) {
UIViewRoot root = context.getViewRoot();
if (root instanceof AjaxViewRoot) {
return ((AjaxViewRoot) root).isAjaxRequest();
} else {
return context.getExternalContext().getRequestParameterMap()
.containsKey(AjaxContainerRenderer.AJAX_PARAMETER_NAME);
}
}
/**
* Detect AJAX status for request
*
* @param context
* @return
*/
public static boolean isAjaxRequest() {
return isAjaxRequest(FacesContext.getCurrentInstance());
}
/**
* Add affected regions's ID to ajaxView component.
*
* @param component
* @param context
* TODO
*/
public static void addRegionsFromComponent(UIComponent component,
FacesContext context) {
// First step - find parent ajax view
Object ajaxRegions = getAjaxAreas(component);
// if (ajaxRegions == null){
// FacesContext context = FacesContext.getCurrentInstance();
// ajaxRegions = AjaxRendererUtils.getAbsoluteId(context,component);
// }
if (AjaxRegionListener.log.isDebugEnabled()) {
AjaxRegionListener.log.debug(Messages.getMessage(
Messages.INVOKE_AJAX_REGION_LISTENER, component.getId()));
}
addRegionByName(context, component, ajaxRegions);
}
/**
* @param context
* @param component
* @param ajaxRegions
*/
public static void addRegionByName(FacesContext context,
UIComponent component, Object ajaxRegions) {
// convert ID to absolute, if can be found relative to component ...
if (ajaxRegions != null) {
AjaxContainer view = getSubmittedAjaxContainer(context, null);
if (null != view) {
if (ajaxRegions instanceof Collection) {
Set areasToRender = view.getAjaxAreasToRender();
for (Iterator iter = ((Collection) ajaxRegions).iterator(); iter
.hasNext();) {
String id = iter.next().toString();
areasToRender.add(convertId(component, id));
}
// view.addAjaxAreas((Collection) ajaxRegions);
} else {
view.addAjaxArea(convertId(component, ajaxRegions
.toString()));
}
} else {
AjaxRegionListener.log
.warn(Messages
.getMessage(Messages.APPENDING_AJAX_REGION_TO_NON_AJAX_CONTAINER_WARNING));
}
}
}
/**
* Test for relative id of target components. Attempt convert to absolute.
* For use as argument for
* {@link UIComponent#findComponent(java.lang.String)}
*
* @param component
* @param id
* @return
*/
public static String convertId(UIComponent component, String id) {
if (id.charAt(0) == NamingContainer.SEPARATOR_CHAR) {
return id;
}
if(null!=component){
UIComponent target = component.findComponent(id);
if (null != target) {
return getAbsoluteId(target);
}
}
return id;
}
/**
* Find all instances of {@link UILoadBundle} in view tree and load bundles
* to request-scope map.
*
* @param context
* @throws IOException
*/
public static void loadBundles(FacesContext context) {
// TODO - performanse improove - don't seek by all components tree.
loadBundles(context, context.getViewRoot());
}
/**
* Recursive helper for {@link #loadBundles(FacesContext)}
*
* @param context
* @param component
* @throws IOException
*/
private static void loadBundles(FacesContext context, UIComponent component) {
// Iterate over cildrens
for (Iterator iter = component.getChildren().iterator(); iter.hasNext();) {
UIComponent child = (UIComponent) iter.next();
loadCildBundles(context, child);
}
// Iterate over facets
for (Iterator iter = component.getFacets().values().iterator(); iter
.hasNext();) {
UIComponent child = (UIComponent) iter.next();
loadCildBundles(context, child);
}
}
/**
* @param context
* @param child
*/
private static void loadCildBundles(FacesContext context, UIComponent child) {
if (child instanceof UILoadBundle) {
try {
child.encodeBegin(context);
} catch (IOException e) {
// DO nothing - really, LoadBundle don't can throw exceptions.
}
} else {
loadBundles(context, child);
}
}
}