001 package org.apache.myfaces.tobago.ajax.api;
002
003 /*
004 * Licensed to the Apache Software Foundation (ASF) under one or more
005 * contributor license agreements. See the NOTICE file distributed with
006 * this work for additional information regarding copyright ownership.
007 * The ASF licenses this file to You under the Apache License, Version 2.0
008 * (the "License"); you may not use this file except in compliance with
009 * the License. You may obtain a copy of the License at
010 *
011 * http://www.apache.org/licenses/LICENSE-2.0
012 *
013 * Unless required by applicable law or agreed to in writing, software
014 * distributed under the License is distributed on an "AS IS" BASIS,
015 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
016 * See the License for the specific language governing permissions and
017 * limitations under the License.
018 */
019
020 import org.apache.commons.logging.Log;
021 import org.apache.commons.logging.LogFactory;
022 import org.apache.myfaces.tobago.component.ComponentUtil;
023 import org.apache.myfaces.tobago.component.UIViewRoot;
024
025 import javax.faces.component.UIComponent;
026 import javax.faces.context.FacesContext;
027 import javax.faces.event.PhaseId;
028 import javax.faces.render.Renderer;
029 import java.io.IOException;
030 import java.util.HashMap;
031 import java.util.Iterator;
032 import java.util.Map;
033 import java.util.StringTokenizer;
034
035 public class AjaxUtils {
036
037 private static final Log LOG = LogFactory.getLog(AjaxUtils.class);
038
039 public static final String AJAX_COMPONENTS = AjaxUtils.class.getName() + ".AJAX_COMPONENTS";
040
041 public static boolean isAjaxRequest(FacesContext facesContext) {
042 return facesContext.getExternalContext().getRequestMap().containsKey(AJAX_COMPONENTS);
043 }
044
045 public static void checkParamValidity(FacesContext facesContext, UIComponent uiComponent, Class compClass) {
046 if (facesContext == null) {
047 throw new NullPointerException("facesContext may not be null");
048 }
049 if (uiComponent == null) {
050 throw new NullPointerException("uiComponent may not be null");
051 }
052 //if (compClass != null && !(compClass.isAssignableFrom(uiComponent.getClass())))
053 // why isAssignableFrom with additional getClass method call if isInstance does the same?
054 if (compClass != null && !(compClass.isInstance(uiComponent))) {
055 throw new IllegalArgumentException("uiComponent : "
056 + uiComponent.getClass().getName() + " is not instance of "
057 + compClass.getName() + " as it should be");
058 }
059 }
060
061 public static void encodeAjaxComponent(FacesContext facesContext, UIComponent component) throws IOException {
062 if (facesContext == null) {
063 throw new NullPointerException("facesContext");
064 }
065 if (!component.isRendered()) {
066 return;
067 }
068 Renderer renderer = ComponentUtil.getRenderer(facesContext, component);
069 if (renderer != null && renderer instanceof AjaxRenderer) {
070 ((AjaxRenderer) renderer).encodeAjax(facesContext, component);
071 }
072 }
073
074 public static void processAjax(FacesContext facesContext, UIComponent component)
075 throws IOException {
076 if (component instanceof AjaxComponent) {
077 ((AjaxComponent) component).processAjax(facesContext);
078 } else {
079 processAjaxOnChildren(facesContext, component);
080 }
081 }
082
083 public static void processActiveAjaxComponent(FacesContext facesContext,
084 UIComponent component)
085 throws IOException {
086
087 if (component instanceof AjaxComponent) {
088 final UIViewRoot viewRoot = (UIViewRoot) facesContext.getViewRoot();
089
090 // TODO: handle phaseListeners ??
091
092 if (!facesContext.getRenderResponse()) {
093 component.processValidators(facesContext);
094 viewRoot.broadcastEventsForPhase(facesContext, PhaseId.PROCESS_VALIDATIONS);
095 } else if (LOG.isDebugEnabled()) {
096 LOG.debug("Skipping validate");
097 }
098
099 if (!facesContext.getRenderResponse()) {
100 component.processUpdates(facesContext);
101 viewRoot.broadcastEventsForPhase(facesContext, PhaseId.UPDATE_MODEL_VALUES);
102 } else if (LOG.isDebugEnabled()) {
103 LOG.debug("Skipping updates");
104 }
105
106 if (!facesContext.getRenderResponse()) {
107 viewRoot.processApplication(facesContext);
108 } else if (LOG.isDebugEnabled()) {
109 LOG.debug("Skipping application");
110 }
111
112 ((AjaxComponent) component).encodeAjax(facesContext);
113 } else {
114 LOG.error("Can't process non AjaxComponent : \""
115 + component.getClientId(facesContext) + "\" = "
116 + component.getClass().getName());
117 }
118 }
119
120 public static void processAjaxOnChildren(FacesContext facesContext,
121 UIComponent component) throws IOException {
122
123 final Iterator<UIComponent> facetsAndChildren = component.getFacetsAndChildren();
124 while (facetsAndChildren.hasNext() && !facesContext.getResponseComplete()) {
125 AjaxUtils.processAjax(facesContext, facetsAndChildren.next());
126 }
127 }
128
129 public static Map<String, UIComponent> parseAndStoreComponents(FacesContext facesContext) {
130 Map parameterMap = facesContext.getExternalContext().getRequestParameterMap();
131 String ajaxComponentIds = (String) parameterMap.get(AjaxPhaseListener.AJAX_COMPONENT_ID);
132 if (ajaxComponentIds != null) {
133 if (LOG.isDebugEnabled()) {
134 LOG.debug("ajaxComponentIds = \"" + ajaxComponentIds + "\"");
135 }
136 StringTokenizer tokenizer = new StringTokenizer(ajaxComponentIds, ",");
137 Map<String, UIComponent> ajaxComponents = new HashMap<String, UIComponent>(tokenizer.countTokens());
138 //noinspection unchecked
139 facesContext.getExternalContext().getRequestMap().put(AJAX_COMPONENTS, ajaxComponents);
140 javax.faces.component.UIViewRoot viewRoot = facesContext.getViewRoot();
141 while (tokenizer.hasMoreTokens()) {
142 String ajaxId = tokenizer.nextToken();
143 UIComponent ajaxComponent = viewRoot.findComponent(ajaxId);
144 if (ajaxComponent != null) {
145 if (LOG.isDebugEnabled()) {
146 LOG.debug("ajaxComponent for \"" + ajaxId + "\" = \"" + ajaxComponent + "\"");
147 }
148 ajaxComponents.put(ajaxId, ajaxComponent);
149 }
150 }
151 return ajaxComponents;
152 }
153 return null;
154 }
155
156 public static Map<String, UIComponent> getAjaxComponents(FacesContext facesContext) {
157 //noinspection unchecked
158 return (Map<String, UIComponent>)
159 facesContext.getExternalContext().getRequestMap().get(AJAX_COMPONENTS);
160 }
161
162 public static void ensureDecoded(FacesContext facesContext, String clientId) {
163 ensureDecoded(facesContext, facesContext.getViewRoot().findComponent(clientId));
164 }
165
166 public static void ensureDecoded(FacesContext facesContext, UIComponent component) {
167 if (component == null) {
168 LOG.warn("Ignore AjaxComponent: null");
169 return;
170 }
171 Map<String, UIComponent> ajaxComponents = getAjaxComponents(facesContext);
172 if (ajaxComponents != null) {
173 for (UIComponent uiComponent : ajaxComponents.values()) {
174 // is component or a parent of it in the list?
175 UIComponent parent = component;
176 while (parent != null) {
177 if (component == uiComponent) {
178 // nothing to do, because it was already decoded (in the list)
179 return;
180 }
181 parent = parent.getParent();
182 }
183 }
184 component.processDecodes(facesContext);
185 }
186 }
187 }