Java tutorial
/** * License Agreement. * * Rich Faces - Natural Ajax for Java Server Faces (JSF) * * Copyright (C) 2007 Exadel, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License version 2.1 as published by the Free Software Foundation. * * 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. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ package org.ajax4jsf.renderkit; 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.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.context.ExternalContext; import javax.faces.context.FacesContext; import javax.faces.context.ResponseWriter; import javax.servlet.http.HttpServletResponse; import org.ajax4jsf.Messages; import org.ajax4jsf.component.AjaxComponent; import org.ajax4jsf.component.AjaxContainer; import org.ajax4jsf.component.AjaxLoadBundleComponent; import org.ajax4jsf.component.AjaxSupport; import org.ajax4jsf.component.AjaxViewRoot; import org.ajax4jsf.component.JavaScriptParameter; import org.ajax4jsf.context.AjaxContext; import org.ajax4jsf.javascript.JSFunction; import org.ajax4jsf.javascript.JSFunctionDefinition; import org.ajax4jsf.javascript.JSReference; import org.ajax4jsf.renderkit.RendererUtils.HTML; import org.ajax4jsf.util.ServicesUtils; 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 function name for call after complete * request. */ public static final String ONCOMPLETE_ATTR_NAME = "oncomplete"; /** * Attribute for keep JavaScript function name for call after complete * request. */ public static final String ONCOMPLETE_CONTENT_ID = "org.ajax4jsf.oncomplete"; /** * Attribute for keep JavaScript function name for call before updating * DOM tree. */ public static final String ONBEFOREDOMUPDATE_ATTR_NAME = "onbeforedomupdate"; /** * 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"; /** * @since 3.3.0 */ public static final String AJAX_PROCESS_ATTRIBUTE = "process"; private static final Class<?> OBJECT_ARRAY_CLASS = (new Object[0]).getClass(); public static final String VALUE_ATTR = "value"; public static final String AJAX_AREAS_RENDERED = "org.ajax4jsf.areas.rendered"; public static final String AJAX_SINGLE_ATTR = "ajaxSingle"; public static final String AJAX_QUEUE_ATTR = "eventsQueue"; public static final String AJAX_DELAY_ATTR = "requestDelay"; public static final String AJAX_ABORT_ATTR = "ignoreDupResponses"; public static final String AJAX_SINGLE_PARAMETER_NAME = "ajaxSingle"; public static final String SIMILARITY_GROUPING_ID_ATTR = "similarityGroupingId"; /** * Static class - protect constructor * */ private AjaxRendererUtils() { } /** * Build JavaScript onclick event for given component * * @param uiComponent - * component for build event * @param facesContext * @return <code>StringBuffer</code> 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 <code>StringBuffer</code> with Javascript code */ 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. // .......... 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; } public static Map<String, Object> buildEventOptions(FacesContext facesContext, UIComponent component) { return buildEventOptions(facesContext, component, null); } /** * @param facesContext * @param uiComponent * @return */ public static Map<String, Object> buildEventOptions(FacesContext facesContext, UIComponent uiComponent, Map<String, Object> params) { String clientId = uiComponent.getClientId(facesContext); Map<String, Object> componentAttributes = uiComponent.getAttributes(); Map<String, Object> options = new HashMap<String, Object>(); Map<String, Object> parameters = new HashMap<String, Object>(); UIComponent targetComponent = (uiComponent instanceof AjaxSupport) ? uiComponent.getParent() : uiComponent; // UIForm form = getNestingForm(uiComponent); // "input" - if assigned to html input element. boolean input = targetComponent instanceof EditableValueHolder; // Action component - button etc. // boolean action = targetComponent instanceof ActionSource; boolean ajaxSingle = Boolean.TRUE.equals(componentAttributes.get(AJAX_SINGLE_ATTR)); // For input components in single mode or without form submit input // control ) if (ajaxSingle) { parameters.put(AJAX_SINGLE_PARAMETER_NAME, targetComponent.getClientId(facesContext)); // options.put("single", JSReference.TRUE); if (input) { 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); AjaxContext ajaxContext = AjaxContext.getCurrentInstance(facesContext); // Setup action URL. For portlet environment, it will be different from // page. options.put("actionUrl", ajaxContext.getAjaxActionURL(facesContext)); // Add application-wide Ajax parameters parameters.putAll(ajaxContext.getCommonAjaxParameters()); // add child parameters for (Iterator<UIComponent> it = uiComponent.getChildren().iterator(); it.hasNext();) { UIComponent child = 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) { if (value == null) { value = ""; } parameters.put(name, value); } else { parameters.put(name, new JSReference(value.toString())); // if(it.hasNext()){onEvent.append(',');}; // renderAjaxLinkParameter( name, // value, onClick, jsForm, nestingForm); } } } if (params != null) { parameters.putAll(params); } if (!parameters.isEmpty()) { options.put("parameters", parameters); } // parameter to render only current list of areas. // if (isAjaxLimitToList(uiComponent)) { // Set<? extends Object> ajaxAreas = getAjaxAreas(uiComponent); // Set<String> areasIds = new HashSet<String>(); // if (null != ajaxAreas) { // for (Iterator<? extends Object> iter = ajaxAreas.iterator(); iter.hasNext();) { // String id = (String) iter.next(); // UIComponent comp = RendererUtils.getInstance(). // findComponentFor(uiComponent, id); // if (null != comp) { // areasIds.add(comp.getClientId(facesContext)); // } else { // areasIds.add(id); // } // } // } // options.put("affected", areasIds); // } String oncomplete = getAjaxOncomplete(uiComponent); if (null != oncomplete) { options.put(ONCOMPLETE_ATTR_NAME, buildAjaxOncomplete(oncomplete)); } String beforeupdate = getAjaxOnBeforeDomUpdate(uiComponent); if (null != beforeupdate) { options.put(ONBEFOREDOMUPDATE_ATTR_NAME, buildAjaxOnBeforeDomUpdate(beforeupdate)); } String status = getAjaxStatus(uiComponent); if (null != status) { options.put("status", status); } String queue = (String) componentAttributes.get(AJAX_QUEUE_ATTR); String implicitQueue = null; Integer requestDelay = (Integer) componentAttributes.get(AJAX_DELAY_ATTR); if (null != requestDelay && requestDelay.intValue() > 0) { options.put(AJAX_DELAY_ATTR, requestDelay); if (null == queue) { implicitQueue = clientId; } } Boolean ignoreDupResponses = (Boolean) componentAttributes.get(AJAX_ABORT_ATTR); if (null != ignoreDupResponses && ignoreDupResponses.booleanValue()) { options.put(AJAX_ABORT_ATTR, JSReference.TRUE); if (null == queue) { implicitQueue = clientId; } } if (null != queue) { options.put(AJAX_QUEUE_ATTR, queue); } else if (implicitQueue != null) { options.put("implicitEventsQueue", clientId); } ExternalContext externalContext = facesContext.getExternalContext(); String namespace = externalContext.encodeNamespace(""); if (namespace != null && namespace.length() != 0) { options.put("namespace", namespace); } String similarityGroupingId = (String) componentAttributes.get(SIMILARITY_GROUPING_ID_ATTR); if (similarityGroupingId == null || similarityGroupingId.length() == 0) { similarityGroupingId = clientId; } else { similarityGroupingId = externalContext.encodeNamespace(similarityGroupingId); } options.put(SIMILARITY_GROUPING_ID_ATTR, similarityGroupingId); // 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 * @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 * @return */ public static JSFunction buildAjaxFunction(UIComponent uiComponent, FacesContext facesContext, String functionName) { JSFunction ajaxFunction = new JSFunction(functionName); UIComponent nestingContainer = (UIComponent) findAjaxContainer(facesContext, uiComponent); String clientId = nestingContainer.getClientId(facesContext); if (clientId != null) { ajaxFunction.addParameter(clientId); } else { // fix for myfaces 1.2.4 ajaxFunction.addParameter(JSReference.NULL); } // 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<String> 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); } /** * Returns set of areas to be processed as a result of this component action invocation * * @param component * @return set of IDs that should be processed as a * @since 3.3.0 */ public static Set<String> getAjaxAreasToProcess(UIComponent component) { Object areas; if (component instanceof AjaxComponent) { areas = ((AjaxComponent) component).getProcess(); } else { areas = component.getAttributes().get(AjaxRendererUtils.AJAX_PROCESS_ATTRIBUTE); } return asSet(areas); } /** * Convert parameter ( Collection, List, array, String, comma-separated * String ) to list of srings. * * @param valueToSet - * obect for convert to List. * @return - list of strings. */ @SuppressWarnings("unchecked") public static Set<String> asSet(Object valueToSet) { if (null != valueToSet) { // Simplest case - set. if (valueToSet instanceof Set) { return (Set<String>) valueToSet; } // Other collections. else if (valueToSet instanceof Collection) { return new HashSet<String>((Collection<String>) valueToSet); } // Array else if (OBJECT_ARRAY_CLASS.isAssignableFrom(valueToSet.getClass())) { return new HashSet<String>(Arrays.asList((String[]) valueToSet)); } // Tokenize string. else if (valueToSet instanceof String) { String areasString = (String) valueToSet; if (areasString.indexOf(",") > 0) { return new HashSet<String>(Arrays.asList(areasString.trim().split("(\\s)*,(\\s)*"))); } else { Set<String> areasSet = new HashSet<String>(5); areasSet.add(areasString.trim()); return areasSet; } } } return null; } /** * Get status area Id for given component. * * @param component * @return clientId of status area, or <code>null</code> */ 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 = RendererUtils.getInstance().findComponentFor(component, statusId); if (null != status) { statusId = status.getClientId(FacesContext.getCurrentInstance()); } else { log.warn(Messages.getMessage(Messages.AJAX_STATUS_COMPONENT_NOT_FOWND_WARNING, component.getId())); } } return statusId; } public static JSFunctionDefinition buildAjaxOncomplete(String body) { JSFunctionDefinition function = new JSFunctionDefinition("request", "event", "data"); function.addToBody(body); return function; } public static JSFunctionDefinition buildAjaxOnBeforeDomUpdate(String body) { JSFunctionDefinition function = new JSFunctionDefinition("request", "event", "data"); function.addToBody(body); return function; } /** * Get function name for call on completed ajax request. * * @param component * for wich calculate function name * @return name of JavaScript function or <code>null</code> */ public static String getAjaxOncomplete(UIComponent component) { if (component instanceof AjaxComponent) { return ((AjaxComponent) component).getOncomplete(); } return (String) component.getAttributes().get(ONCOMPLETE_ATTR_NAME); } /** * Get function name for call before update DOM. * * @param component * for wich calculate function name * @return name of JavaScript function or <code>null</code> */ public static String getAjaxOnBeforeDomUpdate(UIComponent component) { if (component instanceof AjaxComponent) { return ((AjaxComponent) component).getOnbeforedomupdate(); } return (String) component.getAttributes().get(ONBEFOREDOMUPDATE_ATTR_NAME); } /** * Calculate, must be component render only given areas, or all sended from * server. * * @param component * @return <code>true</code> 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 <code>RendererUtils</code> * * @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 <code>UIForm</code> component, or <code>null</code> */ 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 getAjaxActionUrl(FacesContext facesContext) { return AjaxContext.getCurrentInstance(facesContext).getAjaxActionURL(facesContext); } /** * @param facesContext * @param uiComponent * @return */ public static org.ajax4jsf.component.AjaxContainer findAjaxContainer(FacesContext facesContext, UIComponent uiComponent) { UIComponent parent = uiComponent.getParent(); while (parent != null && !(parent instanceof org.ajax4jsf.component.AjaxContainer)) { parent = parent.getParent(); } org.ajax4jsf.component.AjaxContainer nestingContainer = null; if (parent != null) { // link is nested inside a form nestingContainer = (org.ajax4jsf.component.AjaxContainer) parent; } else if (facesContext.getViewRoot() instanceof AjaxViewRoot) { nestingContainer = (AjaxContainer) facesContext.getViewRoot(); } return nestingContainer; } /** * Encode rendered areas as special HTML tag ( span in current release ) * * @param context * @param component * @throws IOException */ public static void encodeAreas(FacesContext context, UIComponent component) throws IOException { AjaxContext ajaxContext = AjaxContext.getCurrentInstance(context); ExternalContext externalContext = context.getExternalContext(); Map<String, Object> requestMap = externalContext.getRequestMap(); Set<String> 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 <span> 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<String> 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 <meta> 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<String, Object> responseDataMap = ajaxContext.getResponseDataMap(); // Get data serializer instance AJAXDataSerializer serializer = (AJAXDataSerializer) ServicesUtils .getServiceInstance(AJAXDataSerializer.SERVICE); // Put data to JavaScript handlers, inside <span> elements. for (Iterator<String> dataIterator = responseDataMap.keySet().iterator(); dataIterator.hasNext();) { Object dataKey = dataIterator.next(); out.startElement(HTML.SPAN_ELEM, component); out.writeAttribute(HTML.id_ATTRIBUTE, dataKey, null); String dataString = serializer.asString(responseDataMap.get(dataKey)); out.write(dataString); out.endElement(HTML.SPAN_ELEM); } // Include active 'oncomplete' function content : Object oncomplete = ajaxContext.getOncomplete(); if (null != oncomplete) { out.startElement(HTML.SPAN_ELEM, component); out.writeAttribute(HTML.id_ATTRIBUTE, ONCOMPLETE_CONTENT_ID, null); out.writeText(oncomplete, null); 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"); } /** * Write state saving markers to context, include MyFaces view sequence. * * @param context * @throws IOException */ public static void writeState(FacesContext context) throws IOException { 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); 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"); encodeAreas(context, component); out.endElement("body"); out.endElement("html"); } /** * 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<UIComponent> iter = component.getChildren().iterator(); iter.hasNext();) { UIComponent child = (UIComponent) iter.next(); loadCildBundles(context, child); } // Iterate over facets for (Iterator<UIComponent> 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 AjaxLoadBundleComponent) { try { child.encodeBegin(context); } catch (IOException e) { // DO nothing - really, LoadBundle don't can throw exceptions. } } else { loadBundles(context, child); } } /** * @param facesContext * @return */ public static boolean isAjaxRequest(FacesContext facesContext) { return AjaxContext.getCurrentInstance(facesContext).isAjaxRequest(); } /** * TODO: add deprecation * * @param facesContext * @param component * @param id */ public static void addRegionByName(FacesContext facesContext, UIComponent component, String id) { AjaxContext.getCurrentInstance(facesContext).addComponentToAjaxRender(component, id); } /** * @param facesContext * @param component * @param id */ public static void addRegionsFromComponent(UIComponent component, FacesContext facesContext) { AjaxContext.getCurrentInstance(facesContext).addRegionsFromComponent(component); } }