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 import org.apache.myfaces.tobago.util.ResponseUtils; 025 026 import javax.faces.FactoryFinder; 027 import javax.faces.application.Application; 028 import javax.faces.application.ViewHandler; 029 import javax.faces.component.UIComponent; 030 import javax.faces.context.FacesContext; 031 import javax.faces.context.ResponseWriter; 032 import javax.faces.event.PhaseId; 033 import javax.faces.render.RenderKit; 034 import javax.faces.render.RenderKitFactory; 035 import javax.faces.render.Renderer; 036 import javax.servlet.ServletResponse; 037 import javax.servlet.http.HttpServletResponse; 038 import java.io.IOException; 039 import java.io.PrintWriter; 040 import java.util.HashMap; 041 import java.util.Iterator; 042 import java.util.Map; 043 import java.util.StringTokenizer; 044 045 public class AjaxUtils { 046 047 private static final Log LOG = LogFactory.getLog(AjaxUtils.class); 048 049 public static final String AJAX_COMPONENTS = AjaxUtils.class.getName() + ".AJAX_COMPONENTS"; 050 051 public static boolean isAjaxRequest(FacesContext facesContext) { 052 Map parameterMap = facesContext.getExternalContext().getRequestParameterMap(); 053 String ajaxComponentIds = (String) parameterMap.get(AjaxPhaseListener.AJAX_COMPONENT_ID); 054 return ajaxComponentIds != null; 055 } 056 057 public static void checkParamValidity(FacesContext facesContext, UIComponent uiComponent, Class compClass) { 058 if (facesContext == null) { 059 throw new NullPointerException("facesContext may not be null"); 060 } 061 if (uiComponent == null) { 062 throw new NullPointerException("uiComponent may not be null"); 063 } 064 //if (compClass != null && !(compClass.isAssignableFrom(uiComponent.getClass()))) 065 // why isAssignableFrom with additional getClass method call if isInstance does the same? 066 if (compClass != null && !(compClass.isInstance(uiComponent))) { 067 throw new IllegalArgumentException("uiComponent : " 068 + uiComponent.getClass().getName() + " is not instance of " 069 + compClass.getName() + " as it should be"); 070 } 071 } 072 073 public static void encodeAjaxComponent(FacesContext facesContext, UIComponent component) throws IOException { 074 if (facesContext == null) { 075 throw new NullPointerException("facesContext"); 076 } 077 if (!component.isRendered()) { 078 return; 079 } 080 Renderer renderer = ComponentUtil.getRenderer(facesContext, component); 081 if (renderer != null && renderer instanceof AjaxRenderer) { 082 ((AjaxRenderer) renderer).encodeAjax(facesContext, component); 083 } 084 } 085 086 public static void processAjax(FacesContext facesContext, UIComponent component) 087 throws IOException { 088 if (component instanceof AjaxComponent) { 089 ((AjaxComponent) component).processAjax(facesContext); 090 } else { 091 processAjaxOnChildren(facesContext, component); 092 } 093 } 094 095 public static void processActiveAjaxComponent(FacesContext facesContext, 096 UIComponent component) 097 throws IOException { 098 099 if (component instanceof AjaxComponent) { 100 final UIViewRoot viewRoot = (UIViewRoot) facesContext.getViewRoot(); 101 102 // TODO: handle phaseListeners ?? 103 104 if (!facesContext.getRenderResponse()) { 105 component.processValidators(facesContext); 106 viewRoot.broadcastEventsForPhase(facesContext, PhaseId.PROCESS_VALIDATIONS); 107 } else if (LOG.isDebugEnabled()) { 108 LOG.debug("Skipping validate"); 109 } 110 111 if (!facesContext.getRenderResponse()) { 112 component.processUpdates(facesContext); 113 viewRoot.broadcastEventsForPhase(facesContext, PhaseId.UPDATE_MODEL_VALUES); 114 } else if (LOG.isDebugEnabled()) { 115 LOG.debug("Skipping updates"); 116 } 117 118 if (!facesContext.getRenderResponse()) { 119 viewRoot.processApplication(facesContext); 120 } else if (LOG.isDebugEnabled()) { 121 LOG.debug("Skipping application"); 122 } 123 124 ((AjaxComponent) component).encodeAjax(facesContext); 125 } else { 126 LOG.error("Can't process non AjaxComponent : \"" 127 + component.getClientId(facesContext) + "\" = " 128 + component.getClass().getName()); 129 } 130 } 131 132 public static void processAjaxOnChildren(FacesContext facesContext, 133 UIComponent component) throws IOException { 134 135 final Iterator<UIComponent> facetsAndChildren = component.getFacetsAndChildren(); 136 while (facetsAndChildren.hasNext() && !facesContext.getResponseComplete()) { 137 AjaxUtils.processAjax(facesContext, facetsAndChildren.next()); 138 } 139 } 140 141 public static Map<String, UIComponent> parseAndStoreComponents(FacesContext facesContext) { 142 Map parameterMap = facesContext.getExternalContext().getRequestParameterMap(); 143 String ajaxComponentIds = (String) parameterMap.get(AjaxPhaseListener.AJAX_COMPONENT_ID); 144 if (ajaxComponentIds != null) { 145 if (LOG.isDebugEnabled()) { 146 LOG.debug("ajaxComponentIds = \"" + ajaxComponentIds + "\""); 147 } 148 StringTokenizer tokenizer = new StringTokenizer(ajaxComponentIds, ","); 149 Map<String, UIComponent> ajaxComponents = new HashMap<String, UIComponent>(tokenizer.countTokens()); 150 //noinspection unchecked 151 facesContext.getExternalContext().getRequestMap().put(AJAX_COMPONENTS, ajaxComponents); 152 javax.faces.component.UIViewRoot viewRoot = facesContext.getViewRoot(); 153 while (tokenizer.hasMoreTokens()) { 154 String ajaxId = tokenizer.nextToken(); 155 UIComponent ajaxComponent = viewRoot.findComponent(ajaxId); 156 if (ajaxComponent != null) { 157 if (LOG.isDebugEnabled()) { 158 LOG.debug("ajaxComponent for \"" + ajaxId + "\" = \"" + ajaxComponent + "\""); 159 } 160 ajaxComponents.put(ajaxId, ajaxComponent); 161 } 162 } 163 return ajaxComponents; 164 } 165 return null; 166 } 167 168 public static Map<String, UIComponent> getAjaxComponents(FacesContext facesContext) { 169 //noinspection unchecked 170 return (Map<String, UIComponent>) 171 facesContext.getExternalContext().getRequestMap().get(AJAX_COMPONENTS); 172 } 173 174 public static void ensureDecoded(FacesContext facesContext, String clientId) { 175 ensureDecoded(facesContext, facesContext.getViewRoot().findComponent(clientId)); 176 } 177 178 public static void ensureDecoded(FacesContext facesContext, UIComponent component) { 179 if (component == null) { 180 LOG.warn("Ignore AjaxComponent: null"); 181 return; 182 } 183 Map<String, UIComponent> ajaxComponents = getAjaxComponents(facesContext); 184 if (ajaxComponents != null) { 185 for (UIComponent uiComponent : ajaxComponents.values()) { 186 // is component or a parent of it in the list? 187 UIComponent parent = component; 188 while (parent != null) { 189 if (component == uiComponent) { 190 // nothing to do, because it was already decoded (in the list) 191 return; 192 } 193 parent = parent.getParent(); 194 } 195 } 196 component.processDecodes(facesContext); 197 } 198 } 199 200 public static boolean redirect(FacesContext facesContext, String url) throws IOException { 201 if (!isAjaxRequest(facesContext)) { 202 return false; 203 } 204 ResponseWriter writer = facesContext.getResponseWriter(); 205 if (writer == null) { 206 RenderKit renderKit = facesContext.getRenderKit(); 207 if (renderKit == null) { 208 RenderKitFactory renderFactory = (RenderKitFactory) FactoryFinder.getFactory(FactoryFinder.RENDER_KIT_FACTORY); 209 Application application = facesContext.getApplication(); 210 ViewHandler applicationViewHandler = application.getViewHandler(); 211 String renderKitId = applicationViewHandler.calculateRenderKitId(facesContext); 212 renderKit = renderFactory.getRenderKit(facesContext, renderKitId); 213 } 214 writer = renderKit.createResponseWriter(((HttpServletResponse) 215 facesContext.getExternalContext().getResponse()).getWriter(), null, null); 216 } 217 ResponseUtils.ensureNoCacheHeader(facesContext); 218 writer.startElement("redirect", null); 219 writer.writeAttribute("url", url, null); 220 writer.endElement("redirect"); 221 writer.flush(); 222 facesContext.responseComplete(); 223 return true; 224 } 225 226 public static void redirect(ServletResponse response, String url) throws IOException { 227 PrintWriter out = response.getWriter(); 228 out.print("<redirect url="); 229 out.print(url); 230 out.println("</redirect>"); 231 } 232 }