001: /*
002: * @author <a href="mailto:novotny@gridsphere.org">Jason Novotny</a>
003: * @version $Id: ActionResponseImpl.java 6385 2007-10-25 14:02:26Z wehrens $
004: */
005: package org.gridsphere.portlet.impl;
006:
007: import javax.portlet.*;
008: import javax.servlet.http.HttpServletRequest;
009: import javax.servlet.http.HttpServletResponse;
010: import java.util.*;
011:
012: /**
013: * The <CODE>ActionResponse</CODE> interface represents the portlet
014: * response to an action request.
015: * It extends the <CODE>PortletResponse</CODE> interface to provide specific
016: * action response functionality to portlets.<br>
017: * The portlet container creates an <CODE>ActionResponse</CODE> object and
018: * passes it as argument to the portlet's <CODE>processAction</CODE> method.
019: *
020: * @see ActionRequest
021: * @see PortletResponse
022: */
023: public class ActionResponseImpl extends PortletResponseImpl implements
024: ActionResponse {
025:
026: /**
027: * Is it still allowed to invoke the method sendRedirect() ?
028: */
029: boolean isRedirectAllowed = true;
030:
031: private boolean redirected = false;
032: private String redirectLocation = null;
033: protected Map<String, String[]> renderParams = null;
034:
035: /**
036: * Constructs an instance of SportletResponse using an
037: * <code>HttpServletResponse</code> as a proxy
038: *
039: * @param req the <code>HttpServletRequest</code>
040: * @param res the <code>HttpServletResponse</code>
041: */
042: public ActionResponseImpl(HttpServletRequest req,
043: HttpServletResponse res) {
044: super (req, res);
045: renderParams = new HashMap<String, String[]>();
046: }
047:
048: /**
049: * Sets the window state of a portlet to the given window state.
050: * <p/>
051: * Possible values are the standard window states and any custom
052: * window states supported by the portal and the portlet.
053: * Standard window states are:
054: * <ul>
055: * <li>MINIMIZED
056: * <li>NORMAL
057: * <li>MAXIMIZED
058: * </ul>
059: *
060: * @param windowState the new portlet window state
061: * @throws WindowStateException if the portlet cannot switch to the specified window state.
062: * To avoid this exception the portlet can check the allowed
063: * window states with <code>Request.isWindowStateAllowed()</code>.
064: * @throws IllegalStateException if the method is invoked after <code>sendRedirect</code> has been called.
065: * @see WindowState
066: */
067: public void setWindowState(WindowState windowState)
068: throws WindowStateException, IllegalStateException {
069: if (redirected) {
070: throw new IllegalStateException(
071: "cannot invoke setWindowState after sendRedirect has been called");
072: }
073: PortalContext portalContext = (PortalContext) req
074: .getAttribute(SportletProperties.PORTAL_CONTEXT);
075: if (portalContext != null) {
076: Enumeration e = portalContext.getSupportedWindowStates();
077: boolean found = false;
078: while (e.hasMoreElements() && (!found)) {
079: WindowState s = (WindowState) e.nextElement();
080: if (s.toString().equalsIgnoreCase(
081: windowState.toString())) {
082: found = true;
083: }
084: }
085: if (!found)
086: throw new WindowStateException(
087: "Unsupported window state!", windowState);
088: } else {
089: throw new IllegalStateException("No PortalContext found!");
090: }
091:
092: isRedirectAllowed = false;
093:
094: req
095: .setAttribute(SportletProperties.PORTLET_WINDOW,
096: windowState);
097: }
098:
099: /**
100: * Sets the portlet mode of a portlet to the given portlet mode.
101: * <p/>
102: * Possible values are the standard portlet modes and any custom
103: * portlet modes supported by the portal and the portlet. Portlets
104: * must declare in the deployment descriptor the portlet modes they
105: * support for each markup type.
106: * Standard portlet modes are:
107: * <ul>
108: * <li>EDIT
109: * <li>HELP
110: * <li>VIEW
111: * </ul>
112: * <p/>
113: * Note: The portlet may still be called in a different window
114: * state in the next render call, depending on the portlet container / portal.
115: *
116: * @param portletMode the new portlet mode
117: * @throws PortletModeException if the portlet cannot switch to this portlet mode,
118: * because the portlet or portal does not support it for this markup,
119: * or the current user is not allowed to switch to this portlet mode.
120: * To avoid this exception the portlet can check the allowed
121: * portlet modes with <code>Request.isPortletModeAllowed()</code>.
122: * @throws IllegalStateException if the method is invoked after <code>sendRedirect</code> has been called.
123: */
124: public void setPortletMode(PortletMode portletMode)
125: throws PortletModeException {
126:
127: if (redirected) {
128: throw new IllegalStateException(
129: "it is not allowed to invoke setPortletMode after sendRedirect has been called");
130: }
131: Set allowedModes = (Set) req
132: .getAttribute(SportletProperties.ALLOWED_MODES);
133: if (allowedModes != null) {
134: if (!allowedModes.contains(portletMode.toString()))
135: throw new PortletModeException(
136: "Unsupported portlet mode!", portletMode);
137: req.setAttribute(SportletProperties.PORTLET_MODE,
138: portletMode);
139: } else {
140: throw new IllegalStateException(
141: "No list of supported modes has been provided!");
142: }
143: isRedirectAllowed = false;
144: }
145:
146: /**
147: * Instructs the portlet container to send a redirect response
148: * to the client using the specified redirect location URL.
149: * <p/>
150: * This method only accepts an absolute URL (e.g.
151: * <code>http://my.co/myportal/mywebap/myfolder/myresource.gif</code>)
152: * or a full path URI (e.g. <code>/myportal/mywebap/myfolder/myresource.gif</code>).
153: * If required,
154: * the portlet container may encode the given URL before the
155: * redirection is issued to the client.
156: * <p/>
157: * The sendRedirect method can not be invoked after any of the
158: * following methods of the ActionResponse interface has been called:
159: * <ul>
160: * <li>setPortletMode
161: * <li>setWindowState
162: * <li>setRenderParameter
163: * <li>setRenderParameters
164: * </ul>
165: *
166: * @throws IllegalStateException if the method is invoked after any of above mentioned methods of
167: * the ActionResponse interface has been called.
168: * @param location the redirect location URL
169: * @exception java.io.IOException if an input or output exception occurs.
170: * @exception IllegalArgumentException if a relative path URL is given
171: */
172: public void sendRedirect(String location)
173: throws java.io.IOException {
174: // TODO needs work
175: if (isRedirectAllowed) {
176: if (location != null) {
177: HttpServletResponse res = (HttpServletResponse) super
178: .getResponse();
179: if (location.indexOf("/") == -1)
180: throw new IllegalArgumentException(
181: "Must be an absolute URL or full path URI");
182: if (location.indexOf("://") != -1) {
183: // provider.setAbsoluteURL(location);
184: } else {
185: // provider.setFullPath(location);
186: }
187: location = res.encodeRedirectURL(location.toString());
188: redirectLocation = location;
189: redirected = true;
190: req.setAttribute(SportletProperties.RESPONSE_COMMITTED,
191: "true");
192: // Don't do actual redirect this will be done by PortletServlet
193: // res.sendRedirect(location);
194: }
195: } else {
196: throw new IllegalStateException(
197: "Can't invoke sendRedirect() after certain methods have been called");
198: }
199: }
200:
201: /**
202: * Sets a parameter map for the render request.
203: * <p/>
204: * All previously set render parameters are cleared.
205: * <p/>
206: * These parameters will be accessible in all
207: * sub-sequent render calls via the
208: * <code>PortletRequest.getParameter</code> call until
209: * a new request is targeted to the portlet.
210: * <p/>
211: * The given parameters do not need to be encoded
212: * prior to calling this method.
213: *
214: * @param parameters Map containing parameter names for
215: * the render phase as
216: * keys and parameter values as map
217: * values. The keys in the parameter
218: * map must be of type String. The values
219: * in the parameter map must be of type
220: * String array (<code>String[]</code>).
221: * @throws IllegalStateException if the method is invoked after <code>sendRedirect</code> has been called.
222: * @exception IllegalArgumentException if parameters is <code>null</code>, if
223: * any of the key/values in the Map are <code>null</code>,
224: * if any of the keys is not a String, or if any of
225: * the values is not a String array.
226: */
227: public void setRenderParameters(java.util.Map parameters) {
228: if (redirected) {
229: throw new IllegalStateException(
230: "Can't invoke setRenderParameters() after sendRedirect() has been called");
231: }
232: if (parameters == null) {
233: throw new IllegalArgumentException(
234: "Render parameters must not be null.");
235: }
236: Map<String, String[]> params = new HashMap<String, String[]>();
237: for (Object obj : parameters.keySet()) {
238: if (!(obj instanceof String))
239: throw new IllegalArgumentException(
240: "Key must not be null and of type java.lang.String.");
241: String key = (String) obj;
242:
243: Object vals = parameters.get(key);
244:
245: if (!(vals instanceof String[]))
246: throw new IllegalArgumentException(
247: "Value must not be null and of type java.lang.String[].");
248: String newkey = SportletProperties.RENDER_PARAM_PREFIX
249: + key;
250: params.put(newkey, (String[]) vals);
251: }
252: renderParams.clear();
253: renderParams.putAll(params);
254: isRedirectAllowed = false;
255: }
256:
257: /**
258: * Sets a String parameter for the render request.
259: * <p/>
260: * These parameters will be accessible in all
261: * sub-sequent render calls via the
262: * <code>PortletRequest.getParameter</code> call until
263: * a request is targeted to the portlet.
264: * <p/>
265: * This method replaces all parameters with the given key.
266: * <p/>
267: * The given parameter do not need to be encoded
268: * prior to calling this method.
269: *
270: * @param key key of the render parameter
271: * @param value value of the render parameter
272: * @throws IllegalStateException if the method is invoked after <code>sendRedirect</code> has been called.
273: * @exception IllegalArgumentException if key or value are <code>null</code>.
274: */
275: public void setRenderParameter(String key, String value) {
276: if (redirected) {
277: throw new IllegalStateException(
278: "Can't invoke setRenderParameter() after sendRedirect() has been called");
279: }
280: if ((key == null) || (value == null)) {
281: throw new IllegalArgumentException(
282: "Render parameter key or value must not be null.");
283: }
284: renderParams.put(SportletProperties.RENDER_PARAM_PREFIX + key,
285: new String[] { value });
286: isRedirectAllowed = false;
287: }
288:
289: /**
290: * Sets a String array parameter for the render request.
291: * <p/>
292: * These parameters will be accessible in all
293: * sub-sequent render calls via the
294: * <code>PortletRequest.getParameter</code> call until
295: * a request is targeted to the portlet.
296: * <p/>
297: * This method replaces all parameters with the given key.
298: * <p/>
299: * The given parameter do not need to be encoded
300: * prior to calling this method.
301: *
302: * @param key key of the render parameter
303: * @param values values of the render parameter
304: * @throws IllegalStateException if the method is invoked after <code>sendRedirect</code> has been called.
305: * @exception IllegalArgumentException if key or value are <code>null</code>.
306: */
307: public void setRenderParameter(String key, String[] values) {
308: if (redirected) {
309: throw new IllegalStateException(
310: "Can't invoke setRenderParameter() after sendRedirect() has been called");
311: }
312: if (key == null || values == null || values.length == 0) {
313: throw new IllegalArgumentException(
314: "Render parameter key or value must not be null or values be an empty array.");
315: }
316: renderParams.put(SportletProperties.RENDER_PARAM_PREFIX + key,
317: values);
318: isRedirectAllowed = false;
319: }
320:
321: public Map getRenderParameters() {
322: return renderParams;
323: }
324:
325: public String getRedirectLocation() {
326: return redirectLocation;
327: }
328:
329: }
|