001: /*
002: * Copyright 2002-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016:
017: package org.springframework.web.portlet.util;
018:
019: import java.io.File;
020: import java.io.FileNotFoundException;
021: import java.util.Enumeration;
022: import java.util.HashMap;
023: import java.util.Iterator;
024: import java.util.Map;
025: import java.util.TreeMap;
026:
027: import javax.portlet.ActionRequest;
028: import javax.portlet.ActionResponse;
029: import javax.portlet.PortletContext;
030: import javax.portlet.PortletRequest;
031: import javax.portlet.PortletSession;
032:
033: import org.springframework.util.Assert;
034: import org.springframework.web.util.WebUtils;
035:
036: /**
037: * Miscellaneous utilities for portlet applications.
038: * Used by various framework classes.
039: *
040: * @author Juergen Hoeller
041: * @author William G. Thompson, Jr.
042: * @author John A. Lewis
043: * @since 2.0
044: */
045: public abstract class PortletUtils {
046:
047: /**
048: * Return the temporary directory for the current web application,
049: * as provided by the portlet container.
050: * @param portletContext the portlet context of the web application
051: * @return the File representing the temporary directory
052: * @throws IllegalArgumentException if the supplied <code>portletContext</code> is <code>null</code>
053: */
054: public static File getTempDir(PortletContext portletContext) {
055: Assert.notNull(portletContext,
056: "PortletContext must not be null");
057: return (File) portletContext
058: .getAttribute(WebUtils.TEMP_DIR_CONTEXT_ATTRIBUTE);
059: }
060:
061: /**
062: * Return the real path of the given path within the web application,
063: * as provided by the portlet container.
064: * <p>Prepends a slash if the path does not already start with a slash,
065: * and throws a {@link java.io.FileNotFoundException} if the path cannot
066: * be resolved to a resource (in contrast to
067: * {@link javax.portlet.PortletContext#getRealPath PortletContext's <code>getRealPath</code>},
068: * which simply returns <code>null</code>).
069: * @param portletContext the portlet context of the web application
070: * @param path the relative path within the web application
071: * @return the corresponding real path
072: * @throws FileNotFoundException if the path cannot be resolved to a resource
073: * @throws IllegalArgumentException if the supplied <code>portletContext</code> is <code>null</code>
074: * @throws NullPointerException if the supplied <code>path</code> is <code>null</code>
075: * @see javax.portlet.PortletContext#getRealPath
076: */
077: public static String getRealPath(PortletContext portletContext,
078: String path) throws FileNotFoundException {
079: Assert.notNull(portletContext,
080: "PortletContext must not be null");
081: // Interpret location as relative to the web application root directory.
082: if (!path.startsWith("/")) {
083: path = "/" + path;
084: }
085: String realPath = portletContext.getRealPath(path);
086: if (realPath == null) {
087: throw new FileNotFoundException("PortletContext resource ["
088: + path
089: + "] cannot be resolved to absolute file path - "
090: + "web application archive not expanded?");
091: }
092: return realPath;
093: }
094:
095: /**
096: * Check the given request for a session attribute of the given name under the
097: * {@link javax.portlet.PortletSession#PORTLET_SCOPE}.
098: * Returns <code>null</code> if there is no session or if the session has no such attribute in that scope.
099: * Does not create a new session if none has existed before!
100: * @param request current portlet request
101: * @param name the name of the session attribute
102: * @return the value of the session attribute, or <code>null</code> if not found
103: * @throws IllegalArgumentException if the supplied <code>request</code> is <code>null</code>
104: */
105: public static Object getSessionAttribute(PortletRequest request,
106: String name) {
107: return getSessionAttribute(request, name,
108: PortletSession.PORTLET_SCOPE);
109: }
110:
111: /**
112: * Check the given request for a session attribute of the given name in the given scope.
113: * Returns <code>null</code> if there is no session or if the session has no such attribute in that scope.
114: * Does not create a new session if none has existed before!
115: * @param request current portlet request
116: * @param name the name of the session attribute
117: * @param scope session scope of this attribute
118: * @return the value of the session attribute, or <code>null</code> if not found
119: * @throws IllegalArgumentException if the supplied <code>request</code> is <code>null</code>
120: */
121: public static Object getSessionAttribute(PortletRequest request,
122: String name, int scope) {
123: Assert.notNull(request, "Request must not be null");
124: PortletSession session = request.getPortletSession(false);
125: return (session != null ? session.getAttribute(name, scope)
126: : null);
127: }
128:
129: /**
130: * Check the given request for a session attribute of the given name under the {@link javax.portlet.PortletSession#PORTLET_SCOPE}.
131: * Throws an exception if there is no session or if the session has no such attribute in that scope.
132: * Does not create a new session if none has existed before!
133: * @param request current portlet request
134: * @param name the name of the session attribute
135: * @return the value of the session attribute
136: * @throws IllegalStateException if the session attribute could not be found
137: * @throws IllegalArgumentException if the supplied <code>request</code> is <code>null</code>
138: */
139: public static Object getRequiredSessionAttribute(
140: PortletRequest request, String name)
141: throws IllegalStateException {
142: return getRequiredSessionAttribute(request, name,
143: PortletSession.PORTLET_SCOPE);
144: }
145:
146: /**
147: * Check the given request for a session attribute of the given name in the given scope.
148: * Throws an exception if there is no session or if the session has no such attribute in that scope.
149: * Does not create a new session if none has existed before!
150: * @param request current portlet request
151: * @param name the name of the session attribute
152: * @param scope session scope of this attribute
153: * @return the value of the session attribute
154: * @throws IllegalStateException if the session attribute could not be found
155: * @throws IllegalArgumentException if the supplied <code>request</code> is <code>null</code>
156: */
157: public static Object getRequiredSessionAttribute(
158: PortletRequest request, String name, int scope)
159: throws IllegalStateException {
160: Object attr = getSessionAttribute(request, name, scope);
161: if (attr == null) {
162: throw new IllegalStateException("No session attribute '"
163: + name + "' found");
164: }
165: return attr;
166: }
167:
168: /**
169: * Set the session attribute with the given name to the given value under the {@link javax.portlet.PortletSession#PORTLET_SCOPE}.
170: * Removes the session attribute if value is <code>null</code>, if a session existed at all.
171: * Does not create a new session if not necessary!
172: * @param request current portlet request
173: * @param name the name of the session attribute
174: * @param value the value of the session attribute
175: * @throws IllegalArgumentException if the supplied <code>request</code> is <code>null</code>
176: */
177: public static void setSessionAttribute(PortletRequest request,
178: String name, Object value) {
179: setSessionAttribute(request, name, value,
180: PortletSession.PORTLET_SCOPE);
181: }
182:
183: /**
184: * Set the session attribute with the given name to the given value in the given scope.
185: * Removes the session attribute if value is <code>null</code>, if a session existed at all.
186: * Does not create a new session if not necessary!
187: * @param request current portlet request
188: * @param name the name of the session attribute
189: * @param value the value of the session attribute
190: * @param scope session scope of this attribute
191: * @throws IllegalArgumentException if the supplied <code>request</code> is <code>null</code>
192: */
193: public static void setSessionAttribute(PortletRequest request,
194: String name, Object value, int scope) {
195: Assert.notNull(request, "Request must not be null");
196: if (value != null) {
197: request.getPortletSession()
198: .setAttribute(name, value, scope);
199: } else {
200: PortletSession session = request.getPortletSession(false);
201: if (session != null) {
202: session.removeAttribute(name, scope);
203: }
204: }
205: }
206:
207: /**
208: * Get the specified session attribute under the {@link javax.portlet.PortletSession#PORTLET_SCOPE},
209: * creating and setting a new attribute if no existing found. The given class
210: * needs to have a public no-arg constructor.
211: * Useful for on-demand state objects in a web tier, like shopping carts.
212: * @param session current portlet session
213: * @param name the name of the session attribute
214: * @param clazz the class to instantiate for a new attribute
215: * @return the value of the session attribute, newly created if not found
216: * @throws IllegalArgumentException if the session attribute could not be instantiated; or if the supplied <code>session</code> argument is <code>null</code>
217: */
218: public static Object getOrCreateSessionAttribute(
219: PortletSession session, String name, Class clazz)
220: throws IllegalArgumentException {
221: return getOrCreateSessionAttribute(session, name, clazz,
222: PortletSession.PORTLET_SCOPE);
223: }
224:
225: /**
226: * Get the specified session attribute in the given scope,
227: * creating and setting a new attribute if no existing found. The given class
228: * needs to have a public no-arg constructor.
229: * Useful for on-demand state objects in a web tier, like shopping carts.
230: * @param session current portlet session
231: * @param name the name of the session attribute
232: * @param clazz the class to instantiate for a new attribute
233: * @param scope the session scope of this attribute
234: * @return the value of the session attribute, newly created if not found
235: * @throws IllegalArgumentException if the session attribute could not be instantiated; or if the supplied <code>session</code> argument is <code>null</code>
236: */
237: public static Object getOrCreateSessionAttribute(
238: PortletSession session, String name, Class clazz, int scope)
239: throws IllegalArgumentException {
240: Assert.notNull(session, "Session must not be null");
241: Object sessionObject = session.getAttribute(name, scope);
242: if (sessionObject == null) {
243: Assert
244: .notNull(clazz,
245: "Class must not be null if attribute value is to be instantiated");
246: try {
247: sessionObject = clazz.newInstance();
248: } catch (InstantiationException ex) {
249: throw new IllegalArgumentException(
250: "Could not instantiate class ["
251: + clazz.getName()
252: + "] for session attribute '" + name
253: + "': " + ex.getMessage());
254: } catch (IllegalAccessException ex) {
255: throw new IllegalArgumentException(
256: "Could not access default constructor of class ["
257: + clazz.getName()
258: + "] for session attribute '" + name
259: + "': " + ex.getMessage());
260: }
261: session.setAttribute(name, sessionObject, scope);
262: }
263: return sessionObject;
264: }
265:
266: /**
267: * Return the best available mutex for the given session:
268: * that is, an object to synchronize on for the given session.
269: * <p>Returns the session mutex attribute if available; usually,
270: * this means that the
271: * {@link org.springframework.web.util.HttpSessionMutexListener}
272: * needs to be defined in <code>web.xml</code>. Falls back to the
273: * {@link javax.portlet.PortletSession} itself if no mutex attribute found.
274: * <p>The session mutex is guaranteed to be the same object during
275: * the entire lifetime of the session, available under the key defined
276: * by the {@link org.springframework.web.util.WebUtils#SESSION_MUTEX_ATTRIBUTE}
277: * constant. It serves as a safe reference to synchronize on for locking
278: * on the current session.
279: * <p>In many cases, the {@link javax.portlet.PortletSession} reference
280: * itself is a safe mutex as well, since it will always be the same
281: * object reference for the same active logical session. However, this is
282: * not guaranteed across different servlet containers; the only 100% safe
283: * way is a session mutex.
284: * @param session the HttpSession to find a mutex for
285: * @return the mutex object (never <code>null</code>)
286: * @see org.springframework.web.util.WebUtils#SESSION_MUTEX_ATTRIBUTE
287: * @see org.springframework.web.util.HttpSessionMutexListener
288: */
289: public static Object getSessionMutex(PortletSession session) {
290: Assert.notNull(session, "Session must not be null");
291: Object mutex = session
292: .getAttribute(WebUtils.SESSION_MUTEX_ATTRIBUTE);
293: if (mutex == null) {
294: mutex = session;
295: }
296: return mutex;
297: }
298:
299: /**
300: * Expose the given Map as request attributes, using the keys as attribute names
301: * and the values as corresponding attribute values. Keys must be Strings.
302: * @param request current portlet request
303: * @param attributes the attributes Map
304: * @throws IllegalArgumentException if an invalid key is found in the Map (i.e. the key is not a String); or if
305: * either of the supplied arguments is <code>null</code>
306: */
307: public static void exposeRequestAttributes(PortletRequest request,
308: Map attributes) throws IllegalArgumentException {
309: Assert.notNull(request, "Request must not be null");
310: Assert.notNull(attributes, "attributes Map must not be null");
311: Iterator it = attributes.entrySet().iterator();
312: while (it.hasNext()) {
313: Map.Entry entry = (Map.Entry) it.next();
314: if (!(entry.getKey() instanceof String)) {
315: throw new IllegalArgumentException(
316: "Invalid key ["
317: + entry.getKey()
318: + "] in attributes Map - only Strings allowed as attribute keys");
319: }
320: request.setAttribute((String) entry.getKey(), entry
321: .getValue());
322: }
323: }
324:
325: /**
326: * Check if a specific input type="submit" parameter was sent in the request,
327: * either via a button (directly with name) or via an image (name + ".x" or
328: * name + ".y").
329: * @param request current portlet request
330: * @param name name of the parameter
331: * @return if the parameter was sent
332: * @see org.springframework.web.util.WebUtils#SUBMIT_IMAGE_SUFFIXES
333: */
334: public static boolean hasSubmitParameter(PortletRequest request,
335: String name) {
336: return getSubmitParameter(request, name) != null;
337: }
338:
339: /**
340: * Return the full name of a specific input type="submit" parameter
341: * if it was sent in the request, either via a button (directly with name)
342: * or via an image (name + ".x" or name + ".y").
343: * @param request current portlet request
344: * @param name name of the parameter
345: * @return the actual parameter name with suffix if needed - null if not present
346: * @see org.springframework.web.util.WebUtils#SUBMIT_IMAGE_SUFFIXES
347: */
348: public static String getSubmitParameter(PortletRequest request,
349: String name) {
350: Assert.notNull(request, "Request must not be null");
351: if (request.getParameter(name) != null) {
352: return name;
353: }
354: for (int i = 0; i < WebUtils.SUBMIT_IMAGE_SUFFIXES.length; i++) {
355: String suffix = WebUtils.SUBMIT_IMAGE_SUFFIXES[i];
356: String parameter = name + suffix;
357: if (request.getParameter(parameter) != null) {
358: return parameter;
359: }
360: }
361: return null;
362: }
363:
364: /**
365: * Return a map containing all parameters with the given prefix.
366: * Maps single values to String and multiple values to String array.
367: * <p>For example, with a prefix of "spring_", "spring_param1" and
368: * "spring_param2" result in a Map with "param1" and "param2" as keys.
369: * <p>Similar to portlet
370: * {@link javax.portlet.PortletRequest#getParameterMap()},
371: * but more flexible.
372: * @param request portlet request in which to look for parameters
373: * @param prefix the beginning of parameter names
374: * (if this is <code>null</code> or the empty string, all parameters will match)
375: * @return map containing request parameters <b>without the prefix</b>,
376: * containing either a String or a String array as values
377: * @see javax.portlet.PortletRequest#getParameterNames
378: * @see javax.portlet.PortletRequest#getParameterValues
379: * @see javax.portlet.PortletRequest#getParameterMap
380: */
381: public static Map getParametersStartingWith(PortletRequest request,
382: String prefix) {
383: Assert.notNull(request, "Request must not be null");
384: Enumeration paramNames = request.getParameterNames();
385: Map params = new TreeMap();
386: if (prefix == null) {
387: prefix = "";
388: }
389: while (paramNames != null && paramNames.hasMoreElements()) {
390: String paramName = (String) paramNames.nextElement();
391: if ("".equals(prefix) || paramName.startsWith(prefix)) {
392: String unprefixed = paramName
393: .substring(prefix.length());
394: String[] values = request.getParameterValues(paramName);
395: if (values == null || values.length == 0) {
396: // Do nothing, no values found at all.
397: } else if (values.length > 1) {
398: params.put(unprefixed, values);
399: } else {
400: params.put(unprefixed, values[0]);
401: }
402: }
403: }
404: return params;
405: }
406:
407: /**
408: * Pass all the action request parameters to the render phase by putting them into
409: * the action response object. This may not be called when the action will call
410: * {@link javax.portlet.ActionResponse#sendRedirect sendRedirect}.
411: * @param request the current action request
412: * @param response the current action response
413: * @see javax.portlet.ActionResponse#setRenderParameter
414: */
415: public static void passAllParametersToRenderPhase(
416: ActionRequest request, ActionResponse response) {
417: try {
418: Enumeration en = request.getParameterNames();
419: while (en.hasMoreElements()) {
420: String param = (String) en.nextElement();
421: String values[] = request.getParameterValues(param);
422: response.setRenderParameter(param, values);
423: }
424: } catch (IllegalStateException ex) {
425: // Ignore in case sendRedirect was already set.
426: }
427: }
428:
429: /**
430: * Clear all the render parameters from the {@link javax.portlet.ActionResponse}.
431: * This may not be called when the action will call
432: * {@link ActionResponse#sendRedirect sendRedirect}.
433: * @param response the current action response
434: * @see ActionResponse#setRenderParameters
435: */
436: public static void clearAllRenderParameters(ActionResponse response) {
437: try {
438: response.setRenderParameters(new HashMap());
439: } catch (IllegalStateException ex) {
440: // Ignore in case sendRedirect was already set.
441: }
442: }
443:
444: }
|