View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership.  The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License.  You may obtain a copy of the License at
9    *
10   *   http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing,
13   * software distributed under the License is distributed on an
14   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15   * KIND, either express or implied.  See the License for the
16   * specific language governing permissions and limitations
17   * under the License.
18   */
19  
20  package org.apache.myfaces.tobago.internal.ajax;
21  
22  
23  import org.apache.myfaces.tobago.ajax.AjaxUtils;
24  import org.apache.myfaces.tobago.internal.component.AbstractUIMessages;
25  import org.apache.myfaces.tobago.internal.util.ResponseUtils;
26  import org.apache.myfaces.tobago.internal.util.StringUtils;
27  import org.apache.myfaces.tobago.renderkit.RendererBase;
28  import org.apache.myfaces.tobago.util.ComponentUtils;
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  import javax.faces.component.UIComponent;
33  import javax.faces.component.UIPanel;
34  import javax.faces.context.ExternalContext;
35  import javax.faces.context.FacesContext;
36  import javax.servlet.http.HttpServletResponse;
37  import java.io.IOException;
38  import java.io.Writer;
39  import java.util.ArrayList;
40  import java.util.HashMap;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.StringTokenizer;
44  
45  public final class AjaxInternalUtils {
46  
47    private static final Logger LOG = LoggerFactory.getLogger(AjaxInternalUtils.class);
48  
49    public static final String AJAX_COMPONENTS = AjaxUtils.class.getName() + ".AJAX_COMPONENTS";
50  
51    private static final String TOBAGO_MESSAGES_CLIENT_IDS = "tobago.messages.clientIds";
52    public static final String TOBAGO_PARTIAL_IDS = "tobago::partialIds";
53  
54    private AjaxInternalUtils() {
55    }
56  
57    public static void checkParamValidity(
58        final FacesContext facesContext, final UIComponent uiComponent, final Class compClass) {
59      if (facesContext == null) {
60        throw new NullPointerException("facesContext may not be null");
61      }
62      if (uiComponent == null) {
63        throw new NullPointerException("uiComponent may not be null");
64      }
65      //if (compClass != null && !(compClass.isAssignableFrom(uiComponent.getClass())))
66      // why isAssignableFrom with additional getClass method call if isInstance does the same?
67      if (compClass != null && !(compClass.isInstance(uiComponent))) {
68        throw new IllegalArgumentException("uiComponent : "
69            + uiComponent.getClass().getName() + " is not instance of "
70            + compClass.getName() + " as it should be");
71      }
72    }
73  
74    public static void encodeAjaxComponent(final FacesContext facesContext, final UIComponent component)
75        throws IOException {
76      if (facesContext == null) {
77        throw new NullPointerException("facesContext");
78      }
79      if (!component.isRendered()) {
80        return;
81      }
82      final RendererBase renderer = ComponentUtils.getRenderer(facesContext, component);
83      if (renderer != null && renderer instanceof AjaxRenderer) {
84        ((AjaxRenderer) renderer).encodeAjax(facesContext, component);
85      }
86    }
87  
88    public static void setRenderAllComponents(final FacesContext facesContext) {
89      final Map<String, UIComponent> ajaxComponents = new HashMap<String, UIComponent>();
90      facesContext.getExternalContext().getRequestMap().put(AJAX_COMPONENTS, ajaxComponents);
91      final javax.faces.component.UIViewRoot viewRoot = facesContext.getViewRoot();
92      final UIComponent page = viewRoot.getChildren().get(0);
93      ajaxComponents.put(page.getClientId(facesContext), page);
94    }
95  
96    public static void storeMessagesClientIds(final FacesContext facesContext, final AbstractUIMessages messages) {
97      final Map attributes = facesContext.getAttributes();
98      final List<String> messageClientIds;
99      if (attributes.containsKey(TOBAGO_MESSAGES_CLIENT_IDS)) {
100       messageClientIds = (List<String>) attributes.get(TOBAGO_MESSAGES_CLIENT_IDS);
101     } else {
102       messageClientIds = new ArrayList<String>();
103       attributes.put(TOBAGO_MESSAGES_CLIENT_IDS, messageClientIds);
104     }
105     messageClientIds.add(messages.getClientId(facesContext));
106   }
107 
108   public static List<String> getMessagesClientIds(final FacesContext facesContext) {
109      return (List<String>) facesContext.getAttributes().get(TOBAGO_MESSAGES_CLIENT_IDS);
110   }
111 
112   public static List<String> getMessagesComponentIds(final FacesContext facesContext) {
113     final Map parameterMap = facesContext.getExternalContext().getRequestParameterMap();
114     final UIComponent component = facesContext.getViewRoot().getChildren().get(0);
115     final String clientId = component.getClientId(facesContext);
116     final String ids = (String) parameterMap.get(clientId + ComponentUtils.SUB_SEPARATOR + "messagesClientIds");
117     final List<String> list = new ArrayList<String>();
118     if (ids != null) {
119       final StringTokenizer tokenizer = new StringTokenizer(ids, ",");
120       while (tokenizer.hasMoreTokens()) {
121         final String id = tokenizer.nextToken();
122         list.add(id);
123       }
124     }
125     return list;
126 
127   }
128 
129   public static Map<String, UIComponent> parseAndStoreComponents(final FacesContext facesContext) {
130     final Map parameterMap = facesContext.getExternalContext().getRequestParameterMap();
131     final String ajaxComponentIds = (String) parameterMap.get(TOBAGO_PARTIAL_IDS);
132     if (ajaxComponentIds != null) {
133       if (LOG.isDebugEnabled()) {
134         LOG.debug("ajaxComponentIds = \"" + ajaxComponentIds + "\"");
135       }
136       final StringTokenizer tokenizer = new StringTokenizer(ajaxComponentIds, ",");
137       final Map<String, UIComponent> ajaxComponents = new HashMap<String, UIComponent>(tokenizer.countTokens());
138       //noinspection unchecked
139       facesContext.getExternalContext().getRequestMap().put(AJAX_COMPONENTS, ajaxComponents);
140       final javax.faces.component.UIViewRoot viewRoot = facesContext.getViewRoot();
141       while (tokenizer.hasMoreTokens()) {
142         final String ajaxId = tokenizer.nextToken();
143         final 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(final FacesContext facesContext) {
157     //noinspection unchecked
158     return (Map<String, UIComponent>)
159         facesContext.getExternalContext().getRequestMap().get(AJAX_COMPONENTS);
160   }
161 
162   public static void addAjaxComponent(final FacesContext facesContext, final UIComponent component) {
163     final Map<String, UIComponent> ajaxComponents =
164         (Map<String, UIComponent>) facesContext.getExternalContext().getRequestMap().get(AJAX_COMPONENTS);
165     if (ajaxComponents != null) {
166       if (!alreadyContained(component, ajaxComponents)) {
167         ajaxComponents.put(component.getClientId(facesContext), component);
168       }
169     }
170   }
171 
172   public static String encodeJavaScriptString(final String value) {
173     String result = StringUtils.replace(value, "\\", "\\\\");
174     result = StringUtils.replace(result, "\n", "\\n");
175     result = StringUtils.replace(result, "\r", "\\r");
176     return StringUtils.replace(result, "\"", "\\\"");
177   }
178 
179   public static boolean alreadyContained(final UIComponent component, final Map<String, UIComponent> ajaxComponents) {
180     for (final UIComponent uiComponent : ajaxComponents.values()) {
181       // is component or a parent of it in the list?
182       UIComponent parent = component;
183       while (parent != null) {
184         if (component == uiComponent) {
185           // nothing to do, because it was already decoded (in the list)
186           return true;
187         }
188         parent = parent.getParent();
189       }
190     }
191     return false;
192   }
193 
194   public static boolean addNextPossibleAjaxComponent(final FacesContext context, final String componentClientId) {
195     UIComponent component = ComponentUtils.findComponent(context.getViewRoot(), componentClientId);
196     component = component.getParent();
197     if (component instanceof UIPanel) {
198       addAjaxComponent(context, component);
199       return true;
200     } else {
201       LOG.error("Ignore adding ajax component (no instance of UIPanel) id: " + componentClientId + " component: "
202           + component);
203       return false;
204     }
205   }
206 
207   public static void ensureDecoded(final FacesContext facesContext, final String clientId) {
208     ensureDecoded(facesContext, facesContext.getViewRoot().findComponent(clientId));
209   }
210 
211   public static void ensureDecoded(final FacesContext facesContext, final UIComponent component) {
212     if (component == null) {
213       LOG.warn("Ignore AjaxComponent: null");
214       return;
215     }
216     final Map<String, UIComponent> ajaxComponents = getAjaxComponents(facesContext);
217     if (ajaxComponents != null) {
218       if (!alreadyContained(component, ajaxComponents)) {
219         component.processDecodes(facesContext);
220       }
221     }
222   }
223 
224   public static boolean redirect(final FacesContext facesContext, final String url) throws IOException {
225     if (!AjaxUtils.isAjaxRequest(facesContext)) {
226       return false;
227     }
228     redirect((HttpServletResponse) facesContext.getExternalContext().getResponse(), url);
229     facesContext.responseComplete();
230     return true;
231   }
232 
233   public static void redirect(final HttpServletResponse response, final String url) throws IOException {
234     final Writer writer = response.getWriter();
235     final String contentType = "application/json; charset=UTF-8";
236     ResponseUtils.ensureContentTypeHeader(response, contentType);
237     ResponseUtils.ensureNoCacheHeader(response);
238     redirectInternal(writer, url);
239   }
240 
241   private static void redirectInternal(final Writer writer, final String url) throws IOException {
242     writer.flush(); // is needed in some cases, e. g. TOBAGO-1094
243     writer.write("{\n  \"tobagoAjaxResponse\": true,\n");
244     writer.write("  \"responseCode\": 302,\n");
245     writer.write("  \"location\": \"");
246     writer.write(url);
247     writer.write("\"\n}\n");
248     writer.flush();
249   }
250 
251   public static void requestNavigationReload(FacesContext facesContext) throws IOException {
252     final ExternalContext externalContext = facesContext.getExternalContext();
253     final String pathPrefix = externalContext.getRequestContextPath() + externalContext.getRequestServletPath();
254     final HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();
255     final String contentType = "application/json; charset=UTF-8";
256     ResponseUtils.ensureContentTypeHeader(response, contentType);
257     ResponseUtils.ensureNoCacheHeader(response);
258     final Writer writer = response.getWriter();
259     writer.flush(); // is needed in some cases, e. g. TOBAGO-1094
260     writer.write("{\n  \"tobagoAjaxResponse\": true,\n");
261     writer.write("  \"responseCode\": " + AjaxResponseRenderer.CODE_RELOAD_REQUIRED + ",\n");
262     writer.write("  \"location\": \"");
263     writer.write(pathPrefix + facesContext.getViewRoot().getViewId());
264     writer.write("\"\n}\n");
265     writer.flush();
266     facesContext.responseComplete();
267   }
268 }