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 }