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    }