001: package org.apache.velocity.tools.struts;
002:
003: /*
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021:
022: import java.util.Locale;
023: import java.util.Iterator;
024:
025: import javax.servlet.ServletContext;
026: import javax.servlet.http.HttpServletRequest;
027: import javax.servlet.http.HttpSession;
028:
029: import org.apache.struts.Globals;
030: import org.apache.struts.action.ActionForm;
031: import org.apache.struts.action.ActionMessage;
032: import org.apache.struts.action.ActionMessages;
033: import org.apache.struts.config.ModuleConfig;
034: import org.apache.struts.config.ForwardConfig;
035: import org.apache.struts.config.ActionConfig;
036: import org.apache.struts.util.MessageResources;
037: import org.apache.struts.util.RequestUtils;
038: import org.apache.struts.taglib.TagUtils;
039: import org.apache.struts.util.ModuleUtils;
040:
041: /**
042: * <p>A utility class to expose the Struts shared
043: * resources. All methods are static.</p>
044: *
045: * <p>This class is provided for use by Velocity view tools
046: * that need access to Struts resources. By having all Struts-
047: * specific code in this utility class, maintenance is simplified
048: * and reuse fostered.</p>
049: *
050: * <p>It is the aim, that sooner or later the functionality in
051: * this class is integrated into Struts itself. See
052: * <a href="http://nagoya.apache.org/bugzilla/show_bug.cgi?id=16814">Bug #16814</a>
053: * for more on that.</p>
054: *
055: * @author <a href="mailto:marinoj@centrum.is">Marino A. Jonsson</a>
056: * @author Nathan Bubna
057: * @author <a href="mailto:sidler@teamup.com">Gabe Sidler</a>
058: * based on code by <a href="mailto:ted@husted.org">Ted Husted</a>
059: *
060: * @version $Id: StrutsUtils.java 479724 2006-11-27 18:49:37Z nbubna $
061: */
062: public class StrutsUtils {
063:
064: /****************** Struts ServletContext Resources ****************/
065:
066: /**
067: * Returns the message resources for this application or <code>null</code>
068: * if not found.
069: *
070: * @param app the servlet context
071: * @since VelocityTools 1.1
072: */
073: public static MessageResources getMessageResources(
074: HttpServletRequest request, ServletContext app) {
075: /* Identify the current module */
076: ModuleConfig moduleConfig = ModuleUtils.getInstance()
077: .getModuleConfig(request, app);
078: return (MessageResources) app.getAttribute(Globals.MESSAGES_KEY
079: + moduleConfig.getPrefix());
080: }
081:
082: /**
083: * Returns the message resources with the specified bundle name for this application
084: * or <code>null</code> if not found.
085: *
086: * @param app the servlet context
087: * @param bundle The bundle name to look for. If this is <code>null</code>, the
088: * default bundle name is used.
089: * @since VelocityTools 1.1
090: */
091: public static MessageResources getMessageResources(
092: HttpServletRequest request, ServletContext app,
093: String bundle) {
094: MessageResources resources = null;
095:
096: /* Identify the current module */
097: ModuleConfig moduleConfig = ModuleUtils.getInstance()
098: .getModuleConfig(request, app);
099:
100: if (bundle == null) {
101: bundle = Globals.MESSAGES_KEY;
102: }
103:
104: // First check request scope
105: resources = (MessageResources) request.getAttribute(bundle
106: + moduleConfig.getPrefix());
107:
108: if (resources == null) {
109: resources = (MessageResources) app.getAttribute(bundle
110: + moduleConfig.getPrefix());
111: }
112:
113: return resources;
114: }
115:
116: /**
117: * Select the module to which the specified request belongs, and
118: * add return the corresponding ModuleConfig.
119: *
120: * @param urlPath The requested URL
121: * @param app The ServletContext for this web application
122: * @return The ModuleConfig for the given URL path
123: * @since VelocityTools 1.1
124: */
125: public static ModuleConfig selectModule(String urlPath,
126: ServletContext app) {
127: /* Match against the list of sub-application prefixes */
128: String prefix = ModuleUtils.getInstance().getModuleName(
129: urlPath, app);
130:
131: /* Expose the resources for this sub-application */
132: ModuleConfig config = (ModuleConfig) app
133: .getAttribute(Globals.MODULE_KEY + prefix);
134:
135: return config;
136: }
137:
138: /********************** Struts Session Resources ******************/
139:
140: /**
141: * Returns the <code>java.util.Locale</code> for the user. If a
142: * locale object is not found in the user's session, the system
143: * default locale is returned.
144: *
145: * @param request the servlet request
146: * @param session the HTTP session
147: */
148: public static Locale getLocale(HttpServletRequest request,
149: HttpSession session) {
150: Locale locale = null;
151:
152: if (session != null) {
153: locale = (Locale) session.getAttribute(Globals.LOCALE_KEY);
154: }
155: if (locale == null) {
156: locale = request.getLocale();
157: }
158: return locale;
159: }
160:
161: /**
162: * Returns the transaction token stored in this session or
163: * <code>null</code> if not used.
164: *
165: * @param session the HTTP session
166: */
167: public static String getToken(HttpSession session) {
168: if (session == null) {
169: return null;
170: }
171: return (String) session
172: .getAttribute(Globals.TRANSACTION_TOKEN_KEY);
173: }
174:
175: /*********************** Struts Request Resources ****************/
176:
177: /**
178: * Returns the Struts errors for this request or <code>null</code>
179: * if none exist. Since VelocityTools 1.2, this will also check
180: * the session (if there is one) for errors if there are no errors
181: * in the request.
182: *
183: * @param request the servlet request
184: * @since VelocityTools 1.1
185: */
186: public static ActionMessages getErrors(HttpServletRequest request) {
187: ActionMessages errors = (ActionMessages) request
188: .getAttribute(Globals.ERROR_KEY);
189: if (errors == null || errors.isEmpty()) {
190: // then check the session
191: HttpSession session = request.getSession(false);
192: if (session != null) {
193: errors = (ActionMessages) session
194: .getAttribute(Globals.ERROR_KEY);
195: }
196: }
197: return errors;
198: }
199:
200: /**
201: * Returns the Struts messages for this request or <code>null</code>
202: * if none exist. Since VelocityTools 1.2, this will also check
203: * the session (if there is one) for messages if there are no messages
204: * in the request.
205: *
206: * @param request the servlet request
207: * @since VelocityTools 1.1
208: */
209: public static ActionMessages getMessages(HttpServletRequest request) {
210: ActionMessages messages = (ActionMessages) request
211: .getAttribute(Globals.MESSAGE_KEY);
212: if (messages == null || messages.isEmpty()) {
213: // then check the session
214: HttpSession session = request.getSession(false);
215: if (session != null) {
216: messages = (ActionMessages) session
217: .getAttribute(Globals.MESSAGE_KEY);
218: }
219: }
220: return messages;
221: }
222:
223: /**
224: * Returns the <code>ActionForm</code> bean associated with
225: * this request of <code>null</code> if none exists.
226: *
227: * @param request the servlet request
228: * @param session the HTTP session
229: */
230: public static ActionForm getActionForm(HttpServletRequest request,
231: HttpSession session) {
232: /* Is there a mapping associated with this request? */
233: ActionConfig mapping = (ActionConfig) request
234: .getAttribute(Globals.MAPPING_KEY);
235: if (mapping == null) {
236: return null;
237: }
238:
239: /* Is there a form bean associated with this mapping? */
240: String attribute = mapping.getAttribute();
241: if (attribute == null) {
242: return null;
243: }
244:
245: /* Look up the existing form bean */
246: if ("request".equals(mapping.getScope())) {
247: return (ActionForm) request.getAttribute(attribute);
248: }
249: if (session != null) {
250: return (ActionForm) session.getAttribute(attribute);
251: }
252: return null;
253: }
254:
255: /**
256: * Returns the ActionForm name associated with
257: * this request of <code>null</code> if none exists.
258: *
259: * @param request the servlet request
260: * @param session the HTTP session
261: */
262: public static String getActionFormName(HttpServletRequest request,
263: HttpSession session) {
264: /* Is there a mapping associated with this request? */
265: ActionConfig mapping = (ActionConfig) request
266: .getAttribute(Globals.MAPPING_KEY);
267: if (mapping == null) {
268: return null;
269: }
270:
271: return mapping.getAttribute();
272: }
273:
274: /*************************** Utilities *************************/
275:
276: /**
277: * Return the form action converted into an action mapping path. The
278: * value of the <code>action</code> property is manipulated as follows in
279: * computing the name of the requested mapping:
280: * <ul>
281: * <li>Any filename extension is removed (on the theory that extension
282: * mapping is being used to select the controller servlet).</li>
283: * <li>If the resulting value does not start with a slash, then a
284: * slash is prepended.</li>
285: * </ul>
286: */
287: public static String getActionMappingName(String action) {
288:
289: String value = action;
290: int question = action.indexOf("?");
291: if (question >= 0) {
292: value = value.substring(0, question);
293: }
294:
295: int slash = value.lastIndexOf("/");
296: int period = value.lastIndexOf(".");
297: if ((period >= 0) && (period > slash)) {
298: value = value.substring(0, period);
299: }
300:
301: return value.startsWith("/") ? value : ("/" + value);
302: }
303:
304: /**
305: * Returns the form action converted into a server-relative URI
306: * reference.
307: *
308: * @param application the servlet context
309: * @param request the servlet request
310: * @param action the name of an action as per struts-config.xml
311: */
312: public static String getActionMappingURL(
313: ServletContext application, HttpServletRequest request,
314: String action) {
315: StringBuffer value = new StringBuffer(request.getContextPath());
316: ModuleConfig config = (ModuleConfig) request
317: .getAttribute(Globals.MODULE_KEY);
318: if (config != null) {
319: value.append(config.getPrefix());
320: }
321:
322: /* Use our servlet mapping, if one is specified */
323: String servletMapping = (String) application
324: .getAttribute(Globals.SERVLET_KEY);
325:
326: if (servletMapping != null) {
327: String queryString = null;
328: int question = action.indexOf("?");
329:
330: if (question >= 0) {
331: queryString = action.substring(question);
332: }
333:
334: String actionMapping = TagUtils.getInstance()
335: .getActionMappingName(action);
336:
337: if (servletMapping.startsWith("*.")) {
338: value.append(actionMapping);
339: value.append(servletMapping.substring(1));
340: } else if (servletMapping.endsWith("/*")) {
341: value.append(servletMapping.substring(0, servletMapping
342: .length() - 2));
343: value.append(actionMapping);
344: }
345:
346: if (queryString != null) {
347: value.append(queryString);
348: }
349: } else {
350: /* Otherwise, assume extension mapping is in use and extension is
351: * already included in the action property */
352: if (!action.startsWith("/")) {
353: value.append("/");
354: }
355: value.append(action);
356: }
357:
358: /* Return the completed value */
359: return value.toString();
360: }
361:
362: /**
363: * Returns the action forward name converted into a server-relative URI
364: * reference.
365: *
366: * @param app the servlet context
367: * @param request the servlet request
368: * @param forward the name of a forward as per struts-config.xml
369: */
370: public static String getForwardURL(HttpServletRequest request,
371: ServletContext app, String forward) {
372: ModuleConfig moduleConfig = ModuleUtils.getInstance()
373: .getModuleConfig(request, app);
374: //TODO? beware of null module config if ActionServlet isn't init'ed?
375: ForwardConfig fc = moduleConfig.findForwardConfig(forward);
376: if (fc == null) {
377: return null;
378: }
379:
380: StringBuffer url = new StringBuffer();
381: if (fc.getPath().startsWith("/")) {
382: url.append(request.getContextPath());
383: url.append(RequestUtils.forwardURL(request, fc,
384: moduleConfig));
385: } else {
386: url.append(fc.getPath());
387: }
388: return url.toString();
389: }
390:
391: /**
392: * Returns a formatted error message. The error message is assembled from
393: * the following three pieces: First, value of message resource
394: * "errors.header" is prepended. Then, the list of error messages is
395: * rendered. Finally, the value of message resource "errors.footer"
396: * is appended.
397: *
398: * @param property the category of errors to markup and return
399: * @param request the servlet request
400: * @param session the HTTP session
401: * @param application the servlet context
402: *
403: * @return The formatted error message. If no error messages are queued,
404: * an empty string is returned.
405: */
406: public static String errorMarkup(String property,
407: HttpServletRequest request, HttpSession session,
408: ServletContext application) {
409: return errorMarkup(property, null, request, session,
410: application);
411: }
412:
413: /**
414: * Returns a formatted error message. The error message is assembled from
415: * the following three pieces: First, value of message resource
416: * "errors.header" is prepended. Then, the list of error messages is
417: * rendered. Finally, the value of message resource "errors.footer"
418: * is appended.
419: *
420: * @param property the category of errors to markup and return
421: * @param bundle the message resource bundle to use
422: * @param request the servlet request
423: * @param session the HTTP session
424: * @param application the servlet context
425: * @since VelocityTools 1.1
426: * @return The formatted error message. If no error messages are queued,
427: * an empty string is returned.
428: */
429: public static String errorMarkup(String property, String bundle,
430: HttpServletRequest request, HttpSession session,
431: ServletContext application) {
432: ActionMessages errors = getErrors(request);
433: if (errors == null) {
434: return "";
435: }
436:
437: /* fetch the error messages */
438: Iterator reports = null;
439: if (property == null) {
440: reports = errors.get();
441: } else {
442: reports = errors.get(property);
443: }
444:
445: if (!reports.hasNext()) {
446: return "";
447: }
448:
449: /* Render the error messages appropriately if errors have been queued */
450: StringBuffer results = new StringBuffer();
451: String header = null;
452: String footer = null;
453: String prefix = null;
454: String suffix = null;
455: Locale locale = getLocale(request, session);
456:
457: MessageResources resources = getMessageResources(request,
458: application, bundle);
459: if (resources != null) {
460: header = resources.getMessage(locale, "errors.header");
461: footer = resources.getMessage(locale, "errors.footer");
462: prefix = resources.getMessage(locale, "errors.prefix");
463: suffix = resources.getMessage(locale, "errors.suffix");
464: }
465: if (header == null) {
466: header = "errors.header";
467: }
468: if (footer == null) {
469: footer = "errors.footer";
470: }
471: /* prefix or suffix are optional, be quiet if they're missing */
472: if (prefix == null) {
473: prefix = "";
474: }
475: if (suffix == null) {
476: suffix = "";
477: }
478:
479: results.append(header);
480: results.append("\r\n");
481:
482: String message;
483: while (reports.hasNext()) {
484: message = null;
485: ActionMessage report = (ActionMessage) reports.next();
486: if (resources != null && report.isResource()) {
487: message = resources.getMessage(locale, report.getKey(),
488: report.getValues());
489: }
490:
491: results.append(prefix);
492:
493: if (message != null) {
494: results.append(message);
495: } else {
496: results.append(report.getKey());
497: }
498:
499: results.append(suffix);
500: results.append("\r\n");
501: }
502:
503: results.append(footer);
504: results.append("\r\n");
505:
506: /* return result */
507: return results.toString();
508: }
509:
510: }
|