View Javadoc
1   /*
2    * $Id$
3    *
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  package org.apache.struts.faces.util;
23  
24  
25  import java.lang.reflect.InvocationTargetException;
26  import java.util.Locale;
27  
28  import org.apache.commons.beanutils.MethodUtils;
29  import org.apache.struts.Globals;
30  import org.apache.struts.action.ActionMapping;
31  import org.apache.struts.action.ActionMessages;
32  import org.apache.struts.action.ActionServlet;
33  import org.apache.struts.config.ModuleConfig;
34  import org.apache.struts.faces.Constants;
35  import org.apache.struts.util.MessageResources;
36  
37  import jakarta.faces.FacesException;
38  import jakarta.faces.context.ExternalContext;
39  import jakarta.faces.context.FacesContext;
40  import jakarta.faces.event.ActionEvent;
41  import jakarta.servlet.http.HttpServletRequest;
42  
43  
44  /**
45   * Context bean providing accessors for the Struts related request,
46   * session, and application scope objects related to this request. Note
47   * that this bean's methods will trigger exceptions unless there is a
48   * {@code FacesContext} instance for this request.
49   */
50  public class StrutsContext {
51  
52  
53      // ------------------------------------------------------ Instance Variables
54  
55  
56      /**
57       * The {@code FacesContext} for the current request.
58       */
59      private final FacesContext fcontext;
60  
61      /**
62       * The {@code ExternalContext} for the current request.
63       */
64      private final ExternalContext econtext;
65  
66  
67      // ------------------------------------------------------ Constructors
68  
69  
70      /**
71       * Creates a new instance with
72       * {@link FacesContext#getCurrentInstance()}.
73       */
74      public StrutsContext() {
75          this(FacesContext.getCurrentInstance());
76      }
77  
78      /**
79       * Create a new instance with give {@code FacesContext}.
80       *
81       * @param facesContext The give {@code FacesContext}
82       */
83      public StrutsContext(FacesContext facesContext) {
84          this.fcontext = facesContext;
85          this.econtext = facesContext.getExternalContext();
86      }
87  
88  
89      // ---------------------------------------------------------- Public Methods
90  
91  
92      /**
93       * Return the {@code ActionEvent} for the current request
94       * (if any).
95       */
96      public ActionEvent getActionEvent() {
97          return Utils.getMapValue(ActionEvent.class, econtext.getRequestMap(),
98                  Constants.ACTION_EVENT_KEY);
99      }
100 
101     /**
102      * Return the {@code ActionMapping} for the current
103      * request (if any).
104      */
105     public ActionMapping getActionMapping() {
106         return Utils.getMapValue(ActionMapping.class, econtext.getRequestMap(),
107                 Globals.MAPPING_KEY);
108     }
109 
110     /**
111      * Return the {@code ActionMessages} instance containing
112      * application error messages for this request (if any).
113      */
114     public ActionMessages getActionMessages() {
115         return Utils.getMapValue(ActionMessages.class, econtext.getRequestMap(),
116                 Globals.MESSAGE_KEY);
117     }
118 
119     /**
120      * Return the {@code ActionServlet} instance for this
121      * web application.
122      */
123     public ActionServlet getActionServlet() {
124         return Utils.getMapValue(ActionServlet.class, econtext.getApplicationMap(),
125                 Globals.ACTION_SERVLET_KEY);
126     }
127 
128     /**
129      * Return {@code true} if a Boolean true value has been stored
130      * in the request attribute indicating that this request has been
131      * cancelled.
132      */
133     public boolean isCancelled() {
134         final Object value = econtext.getRequestMap().get(Globals.CANCEL_KEY);
135         if (value instanceof Boolean) {
136             return (Boolean) value;
137         } else {
138             return false;
139         }
140     }
141 
142     /**
143      * Return the exception that caused one of the Struts custom tags
144      * to report a JspException (if any).
145      */
146     public Throwable getException() {
147         return Utils.getMapValue(Throwable.class, econtext.getRequestMap(),
148                 Globals.EXCEPTION_KEY);
149     }
150 
151     /**
152      * Return the {@code ExternalContext} for the current request.
153      */
154     public ExternalContext getExternalContext() {
155         return econtext;
156     }
157 
158     /**
159      * Return the {@code FacesContext} for the current request.
160      */
161     public FacesContext getFacesContext() {
162         return fcontext;
163     }
164 
165     /**
166      * Return the {@code Locale} stored in the current user's
167      * session (if any) for Struts based localization.
168      */
169     public Locale getLocale() {
170         Locale locale = null;
171         if (econtext.getSession(false) != null) {
172             locale = Utils.getMapValue(Locale.class, econtext.getSessionMap(),
173                     Globals.LOCALE_KEY);
174         }
175 
176         if (locale == null) {
177             locale = econtext.getRequestLocale();
178         }
179 
180         return locale;
181     }
182 
183     /**
184      * Return the {@code MessageResources} instance for the
185      * application module that is processing this request
186      * (if any).
187      */
188     public MessageResources getMessageResources() {
189         return Utils.getMapValue(MessageResources.class, econtext.getRequestMap(),
190                 Globals.MESSAGES_KEY);
191     }
192 
193     /**
194      * Return the {@code ModuleConfig} for the application module
195      * to which this request has been assigned (if any).
196      *
197      * @return the {@code ModuleConfig} for the application module
198      *
199      * @throws IllegalArgumentException if no {@code ModuleConfig}
200      *     can be found
201      */
202     public ModuleConfig getModuleConfig() {
203         return getModuleConfig(econtext);
204     }
205 
206     /**
207      * Return the {@code ModuleConfig} for the application module
208      * to which this request has been assigned (if any).
209      *
210      * @param facesContext The given {@code FacesContext}
211      *
212      * @return the {@code ModuleConfig} for the application module
213      *
214      * @throws IllegalArgumentException if no {@code ModuleConfig}
215      *     can be found
216      */
217     public static ModuleConfig getModuleConfig(FacesContext facesContext) {
218         return getModuleConfig(facesContext.getExternalContext());
219     }
220 
221     /**
222      * Return the {@code ModuleConfig} for the application module
223      * to which this request has been assigned (if any).
224      *
225      * @param externalContext The given {@code ExternalContext}
226      *
227      * @return the {@code ModuleConfig} for the application module
228      *
229      * @throws IllegalArgumentException if no {@code ModuleConfig}
230      *     can be found
231      */
232     public static ModuleConfig getModuleConfig(ExternalContext externalContext) {
233         ModuleConfig moduleConfig = Utils.getMapValue(ModuleConfig.class,
234                 externalContext.getRequestMap(), Globals.MODULE_KEY);
235 
236         if (moduleConfig == null) {
237             moduleConfig = Utils.getMapValue(ModuleConfig.class,
238                     externalContext.getApplicationMap(), Globals.MODULE_KEY);
239         }
240 
241         if (moduleConfig == null) {
242             throw new IllegalArgumentException("Cannot find module configuration");
243         }
244 
245         return moduleConfig;
246     }
247 
248     /**
249      * Return the absolute URI to be rendered as the value of the
250      * {@code href} attribute.
251      *
252      * @param context {@code FacesContext} for the current request
253      *
254      * @throws IllegalArgumentException Request is neither
255      *     {@code HttpServletRequest} nor {@code PortletRequest}.
256      */
257     public static String uri(FacesContext context) {
258         final StringBuilder sb = new StringBuilder();
259 
260         final ExternalContext externalContext = context.getExternalContext();
261         if (StrutsContext.isServletRequest(externalContext)) {
262             servletUri(sb, externalContext);
263         } else if (StrutsContext.isPortletRequest(externalContext)) {
264             portletUri(sb, externalContext);
265         } else {
266             throw new IllegalArgumentException
267                     ("Request is neither HttpServletRequest nor PortletRequest");
268         }
269 
270         return sb.append(context.getViewRoot().getViewId()).toString();
271     }
272 
273     /**
274      * Appends an absolute URI for the current request suitable for use
275      * in a portlet environment.
276      *
277      * <p>NOTE: Implementation must not require portlet API classes to
278      * be present, so use reflection as needed.</p>
279      *
280      * @param context {@code FacesContext} for the current request
281      */
282     private static void portletUri(StringBuilder sb, ExternalContext context) {
283         final Object request = context.getRequest();
284         try {
285             final String scheme = (String)
286                     MethodUtils.invokeMethod(request, "getScheme", null);
287 
288             final String serverName = (String)
289                     MethodUtils.invokeMethod(request, "getServerName", null);
290 
291             final int serverPort = (Integer)
292                     MethodUtils.invokeMethod(request, "getServerPort", null);
293 
294             final String contextPath = (String)
295                     MethodUtils.invokeMethod(request, "getContextPath", null);
296 
297             buildUri(sb, scheme, serverName, serverPort, contextPath);
298         } catch (InvocationTargetException e) {
299             throw new FacesException(e.getTargetException());
300         } catch (Exception e) {
301             throw new FacesException(e);
302         }
303     }
304 
305     /**
306      * Return {@code true} if this is a portlet request instance.
307      *
308      * <p>NOTE: Implementation must not require portlet API classes to be
309      * present.</p>
310      *
311      * @param context {@code FacesContext} for the current request
312      */
313     private static boolean isPortletRequest(ExternalContext context) {
314         final Object request = context.getRequest();
315         for (Class<?> clazz = request.getClass(); clazz != null; clazz = clazz.getSuperclass()) {
316             Class<?> interfaces[] = clazz.getInterfaces();
317             if (interfaces == null) {
318                 continue;
319             }
320 
321             // Does this class implement PortletRequest?
322             for (Class<?> inter : interfaces) {
323                 if ("javax.portlet.PortletRequest".equals(inter.getName()) ||
324                     "jakarta.portlet.PortletRequest".equals(inter.getName())) {
325                     return true;
326                 }
327             }
328         }
329 
330         return false;
331     }
332 
333     /**
334      * Appends an absolute URI for the current request suitable for use
335      * in a servlet environment.
336      *
337      * @param context {@code FacesContext} for the current request
338      */
339     private static void servletUri(StringBuilder sb, ExternalContext context) {
340         final HttpServletRequest request = (HttpServletRequest)
341             context.getRequest();
342 
343         buildUri(sb, request.getScheme(), request.getServerName(),
344                 request.getServerPort(), request.getContextPath());
345     }
346 
347     /**
348      * Return {@code true} if this is a servlet request instance.
349      *
350      * @param context {@code FacesContext} for the current request
351      */
352     private static boolean isServletRequest(ExternalContext context) {
353         Object request = context.getRequest();
354         return request instanceof HttpServletRequest;
355     }
356 
357     /**
358      * Appends a URI into the given StringBuilder from the
359      * given parameters.
360      *
361      * @param sb The given {@Code StringBuilder} where the URI is
362      *     append.
363      * @param scheme The name of the scheme used to make this
364      *     request.
365      * @param serverName The host name of the server to which the
366      *     request was sent.
367      * @param serverPort The port number to which the request was
368      *     sent.
369      * @param contextPath The portion of the request URI that
370      *     indicates the context of the request.
371      */
372     private static void buildUri(final StringBuilder sb, final String scheme, final String serverName, final int serverPort, final String contextPath) {
373         sb.append(scheme)
374           .append("://")
375           .append(serverName);
376 
377         if ("http".equals(scheme) && serverPort == 80) {
378         } else if ("https".equals(scheme) && (serverPort == 443)) {
379         } else {
380             sb.append(':')
381               .append(serverPort);
382         }
383 
384         sb.append(contextPath);
385     }
386 }