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